plat: marvell: Add common ARMADA platform components

Add common Marvell ARMADA platform components.
This patch also includes common components for Marvell
ARMADA 8K platforms.

Change-Id: I42192fdc6525a42e46b3ac2ad63c83db9bcbfeaf
Signed-off-by: Hanna Hawa <hannah@marvell.com>
Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
diff --git a/plat/marvell/common/aarch64/marvell_common.c b/plat/marvell/common/aarch64/marvell_common.c
new file mode 100644
index 0000000..abc501a
--- /dev/null
+++ b/plat/marvell/common/aarch64/marvell_common.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <mmio.h>
+#include <plat_marvell.h>
+#include <platform_def.h>
+#include <xlat_tables.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..a3dc917
--- /dev/null
+++ b/plat/marvell/common/aarch64/marvell_helpers.S
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <cortex_a72.h>
+#include <marvell_def.h>
+#include <platform_def.h>
+#ifndef PLAT_a3700
+#include <ccu.h>
+#include <cache_llc.h>
+#endif
+
+	.weak	plat_marvell_calc_core_pos
+	.weak	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.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
+	b	console_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_MARVELL_CRASH_UART_BASE
+	b	console_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------------------------------
+	 * 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..981cfbe
--- /dev/null
+++ b/plat/marvell/common/marvell_bl1_setup.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <bl1.h>
+#include <bl1/bl1_private.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <plat_marvell.h>
+#include <sp805.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)
+{
+	const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
+
+	/* Initialize the console to provide early debug support */
+	console_init(PLAT_MARVELL_BOOT_UART_BASE,
+		     PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+		     MARVELL_CONSOLE_BAUDRATE);
+
+	/* 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;
+
+	/* Calculate how much RAM BL1 is using and how much remains free */
+	bl1_ram_layout.free_base = MARVELL_BL_RAM_BASE;
+	bl1_ram_layout.free_size = MARVELL_BL_RAM_SIZE;
+	reserve_mem(&bl1_ram_layout.free_base,
+		    &bl1_ram_layout.free_size,
+		    BL1_RAM_BASE,
+		    bl1_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..7c87ce3
--- /dev/null
+++ b/plat/marvell/common/marvell_bl2_setup.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <bl_common.h>
+#include <console.h>
+#include <marvell_def.h>
+#include <platform_def.h>
+#include <plat_marvell.h>
+#include <string.h>
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+
+/*****************************************************************************
+ * This structure represents the superset of information that is passed to
+ * BL31, e.g. while passing control to it from BL2, bl31_params
+ * and other platform specific parameters
+ *****************************************************************************
+ */
+typedef struct bl2_to_bl31_params_mem {
+	bl31_params_t bl31_params;
+	image_info_t bl31_image_info;
+	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;
+	entry_point_info_t bl31_ep_info;
+} bl2_to_bl31_params_mem_t;
+
+
+static bl2_to_bl31_params_mem_t bl31_params_mem;
+
+
+/* Weak definitions may be overridden in specific MARVELL standard platform */
+#pragma weak bl2_early_platform_setup
+#pragma weak bl2_platform_setup
+#pragma weak bl2_plat_arch_setup
+#pragma weak bl2_plat_sec_mem_layout
+#pragma weak bl2_plat_get_bl31_params
+#pragma weak bl2_plat_get_bl31_ep_info
+#pragma weak bl2_plat_flush_bl31_params
+#pragma weak bl2_plat_set_bl31_ep_info
+#pragma weak bl2_plat_get_scp_bl2_meminfo
+#pragma weak bl2_plat_get_bl32_meminfo
+#pragma weak bl2_plat_set_bl32_ep_info
+#pragma weak bl2_plat_get_bl33_meminfo
+#pragma weak bl2_plat_set_bl33_ep_info
+
+
+meminfo_t *bl2_plat_sec_mem_layout(void)
+{
+	return &bl2_tzram_layout;
+}
+
+/*****************************************************************************
+ * This function assigns a pointer to the memory that the platform has kept
+ * aside to pass platform specific and trusted firmware related information
+ * to BL31. This memory is allocated by allocating memory to
+ * bl2_to_bl31_params_mem_t structure which is a superset of all the
+ * structure whose information is passed to BL31
+ * NOTE: This function should be called only once and should be done
+ * before generating params to BL31
+ *****************************************************************************
+ */
+bl31_params_t *bl2_plat_get_bl31_params(void)
+{
+	bl31_params_t *bl2_to_bl31_params;
+
+	/*
+	 * Initialise the memory for all the arguments that needs to
+	 * be passed to BL31
+	 */
+	memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
+
+	/* Assign memory for TF related information */
+	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
+	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
+
+	/* Fill BL31 related information */
+	bl2_to_bl31_params->bl31_image_info = &bl31_params_mem.bl31_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+
+	/* Fill BL32 related information if it exists */
+#if BL32_BASE
+	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
+		VERSION_1, 0);
+	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+#endif
+
+	/* Fill BL33 related information */
+	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info,
+		PARAM_EP, VERSION_1, 0);
+
+	/* BL33 expects to receive the primary CPU MPID (through x0) */
+	bl2_to_bl31_params->bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
+
+	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+
+	return bl2_to_bl31_params;
+}
+
+/* Flush the TF params and the TF plat params */
+void bl2_plat_flush_bl31_params(void)
+{
+	flush_dcache_range((unsigned long)&bl31_params_mem,
+			sizeof(bl2_to_bl31_params_mem_t));
+}
+
+/*****************************************************************************
+ * This function returns a pointer to the shared memory that the platform
+ * has kept to point to entry point information of BL31 to BL2
+ *****************************************************************************
+ */
+struct entry_point_info *bl2_plat_get_bl31_ep_info(void)
+{
+#if DEBUG
+	bl31_params_mem.bl31_ep_info.args.arg1 = MARVELL_BL31_PLAT_PARAM_VAL;
+#endif
+
+	return &bl31_params_mem.bl31_ep_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 marvell_bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+	/* Initialize the console to provide early debug support */
+	console_init(PLAT_MARVELL_BOOT_UART_BASE,
+		     PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+		     MARVELL_CONSOLE_BAUDRATE);
+
+	/* 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_setup(meminfo_t *mem_layout)
+{
+	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();
+}
+
+/*****************************************************************************
+ * Populate the extents of memory available for loading SCP_BL2 (if used),
+ * i.e. anywhere in trusted RAM as long as it doesn't overwrite BL2.
+ *****************************************************************************
+ */
+void bl2_plat_get_scp_bl2_meminfo(meminfo_t *scp_bl2_meminfo)
+{
+	*scp_bl2_meminfo = bl2_tzram_layout;
+}
+
+/*****************************************************************************
+ * Before calling this function BL31 is loaded in memory and its entrypoint
+ * is set by load_image. This is a placeholder for the platform to change
+ * the entrypoint of BL31 and set SPSR and security state.
+ * On MARVELL std. platforms we only set the security state of the entrypoint
+ *****************************************************************************
+ */
+void bl2_plat_set_bl31_ep_info(image_info_t *bl31_image_info,
+			       entry_point_info_t *bl31_ep_info)
+{
+	SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE);
+	bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS);
+}
+
+/*****************************************************************************
+ * Populate the extents of memory available for loading BL32
+ *****************************************************************************
+ */
+#ifdef BL32_BASE
+void bl2_plat_get_bl32_meminfo(meminfo_t *bl32_meminfo)
+{
+	/*
+	 * Populate the extents of memory available for loading BL32.
+	 */
+	bl32_meminfo->total_base = BL32_BASE;
+	bl32_meminfo->free_base = BL32_BASE;
+	bl32_meminfo->total_size =
+			(TRUSTED_DRAM_BASE + TRUSTED_DRAM_SIZE) - BL32_BASE;
+	bl32_meminfo->free_size =
+			(TRUSTED_DRAM_BASE + TRUSTED_DRAM_SIZE) - BL32_BASE;
+}
+#endif
+
+/*****************************************************************************
+ * Before calling this function BL32 is loaded in memory and its entrypoint
+ * is set by load_image. This is a placeholder for the platform to change
+ * the entrypoint of BL32 and set SPSR and security state.
+ * On MARVELL std. platforms we only set the security state of the entrypoint
+ *****************************************************************************
+ */
+void bl2_plat_set_bl32_ep_info(image_info_t *bl32_image_info,
+			       entry_point_info_t *bl32_ep_info)
+{
+	SET_SECURITY_STATE(bl32_ep_info->h.attr, SECURE);
+	bl32_ep_info->spsr = marvell_get_spsr_for_bl32_entry();
+}
+
+/*****************************************************************************
+ * Before calling this function BL33 is loaded in memory and its entrypoint
+ * is set by load_image. This is a placeholder for the platform to change
+ * the entrypoint of BL33 and set SPSR and security state.
+ * On MARVELL std. platforms we only set the security state of the entrypoint
+ *****************************************************************************
+ */
+void bl2_plat_set_bl33_ep_info(image_info_t *image,
+			       entry_point_info_t *bl33_ep_info)
+{
+
+	SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE);
+	bl33_ep_info->spsr = marvell_get_spsr_for_bl33_entry();
+}
+
+/*****************************************************************************
+ * Populate the extents of memory available for loading BL33
+ *****************************************************************************
+ */
+void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo)
+{
+	bl33_meminfo->total_base = MARVELL_DRAM_BASE;
+	bl33_meminfo->total_size = MARVELL_DRAM_SIZE;
+	bl33_meminfo->free_base = MARVELL_DRAM_BASE;
+	bl33_meminfo->free_size = MARVELL_DRAM_SIZE;
+}
diff --git a/plat/marvell/common/marvell_bl31_setup.c b/plat/marvell/common/marvell_bl31_setup.c
new file mode 100644
index 0000000..a74816b
--- /dev/null
+++ b/plat/marvell/common/marvell_bl31_setup.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <console.h>
+#include <debug.h>
+#include <marvell_def.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+#include <platform.h>
+
+#ifdef USE_CCI
+#include <cci.h>
+#endif
+
+/*
+ * The next 3 constants identify the extents of the code, RO data region and the
+ * limit of the BL31 image.  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__, __RO_END__ & __BL31_END__ linker symbols
+ * refer to page-aligned addresses.
+ */
+#define BL31_END (unsigned long)(&__BL31_END__)
+
+/*
+ * 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_setup
+#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 & 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 marvell_bl31_early_platform_setup(bl31_params_t *from_bl2,
+				void *plat_params_from_bl2)
+{
+	/* Initialize the console to provide early debug support */
+	console_init(PLAT_MARVELL_BOOT_UART_BASE,
+		     PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+		     MARVELL_CONSOLE_BAUDRATE);
+
+#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
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	assert(from_bl2 != NULL);
+	assert(from_bl2->h.type == PARAM_BL31);
+	assert(from_bl2->h.version >= VERSION_1);
+	/*
+	 * 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);
+
+	/*
+	 * Copy BL32 (if populated by BL2) and BL33 entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	if (from_bl2->bl32_ep_info)
+		bl32_image_ep_info = *from_bl2->bl32_ep_info;
+	bl33_image_ep_info = *from_bl2->bl33_ep_info;
+#endif
+}
+
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+				void *plat_params_from_bl2)
+{
+	marvell_bl31_early_platform_setup(from_bl2, plat_params_from_bl2);
+
+#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)
+{
+	/* Initialize the runtime console */
+	console_init(PLAT_MARVELL_BL31_RUN_UART_BASE,
+		     PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ,
+		     MARVELL_CONSOLE_BAUDRATE);
+}
+
+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..2df4802
--- /dev/null
+++ b/plat/marvell/common/marvell_cci.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <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..3ee2f3d
--- /dev/null
+++ b/plat/marvell/common/marvell_common.mk
@@ -0,0 +1,67 @@
+# 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))
+
+PLAT_INCLUDES		+=	-I. -Iinclude/common/tbbr		\
+				-I$(MARVELL_PLAT_INCLUDE_BASE)/common	\
+				-I$(MARVELL_PLAT_INCLUDE_BASE)/common/aarch64
+
+
+PLAT_BL_COMMON_SOURCES  +=      lib/xlat_tables/xlat_tables_common.c			\
+				lib/xlat_tables/aarch64/xlat_tables.c			\
+				$(MARVELL_PLAT_BASE)/common/aarch64/marvell_common.c	\
+				$(MARVELL_PLAT_BASE)/common/aarch64/marvell_helpers.S
+
+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					\
+				$(MARVELL_PLAT_BASE)/common/marvell_bl2_setup.c		\
+				$(MARVELL_PLAT_BASE)/common/marvell_io_storage.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_ddr_info.c b/plat/marvell/common/marvell_ddr_info.c
new file mode 100644
index 0000000..68bff99
--- /dev/null
+++ b/plat/marvell/common/marvell_ddr_info.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <debug.h>
+#include <platform_def.h>
+#include <ddr_info.h>
+#include <mmio.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..ba8e409
--- /dev/null
+++ b/plat/marvell/common/marvell_gicv2.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <gicv2.h>
+#include <plat_marvell.h>
+#include <platform.h>
+#include <platform_def.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
+
+/*
+ * 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);
+}
+
+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_io_storage.c b/plat/marvell/common/marvell_io_storage.c
new file mode 100644
index 0000000..cb9ece2
--- /dev/null
+++ b/plat/marvell/common/marvell_io_storage.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <bl_common.h>		/* For ARRAY_SIZE */
+#include <debug.h>
+#include <firmware_image_package.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <platform_def.h>
+#include <string.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..2a75790
--- /dev/null
+++ b/plat/marvell/common/marvell_pm.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <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..ec293af
--- /dev/null
+++ b/plat/marvell/common/mrvl_sip_svc.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <ap_setup.h>
+#include <cache_llc.h>
+#include <debug.h>
+#include <marvell_plat_priv.h>
+#include <runtime_svc.h>
+#include <smcc.h>
+#include "comphy/phy-comphy-cp110.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 MAX_LANE_NR		6
+#define MVEBU_COMPHY_OFFSET	0x441000
+#define MVEBU_SD_OFFSET		0x120000
+
+/* 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)
+
+
+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)) {
+
+		/* some systems passes SD phys address instead of COMPHY phys
+		 * address - convert it
+		 */
+		if (x1 & MVEBU_SD_OFFSET)
+			x1 = (x1 & ~0xffffff) + MVEBU_COMPHY_OFFSET;
+
+		if ((x1 & 0xffffff) != MVEBU_COMPHY_OFFSET) {
+			ERROR("%s: Wrong smc (0x%x) address: %lx\n",
+			      __func__, smc_fid, x1);
+			SMC_RET1(handle, SMC_UNK);
+		}
+
+		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);
+		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:
+		/* x1:  ap_base_addr */
+		ret = mvebu_get_dram_size(x1);
+		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);
+
+	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..731c315
--- /dev/null
+++ b/plat/marvell/common/mss/mss_ipc_drv.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+#include <debug.h>
+#include <string.h>
+#include <mss_ipc_drv.h>
+#include <mmio.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..28eb907
--- /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 __PM_IPC_DRV_H
+#define __PM_IPC_DRV_H
+
+#include <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 /* __PM_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..efff59e
--- /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_PM_MEM_H
+#define __MSS_PM_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_PM_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..c04df72
--- /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..334fcfc
--- /dev/null
+++ b/plat/marvell/common/mss/mss_scp_bootloader.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <mmio.h>
+#include <arch_helpers.h> /* for cache maintanance operations */
+#include <platform_def.h>
+#include <delay_timer.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..67c387a
--- /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..dfc77c7
--- /dev/null
+++ b/plat/marvell/common/plat_delay_timer.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <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);
+}