plat: marvell: Add support for Armada-37xx SoC platform

Add supprot for Marvell platforms based on Armada-37xx SoC.
This includes support for the official Armada-3720 modular
development board and EspressoBin community board.
The Armada-37xx SoC contains dual Cortex-A53 Application CPU,
single secure CPU (Cortex-M3) and the following interfaces:
- SATA 3.0
- USB 3.0 and USB 2.0
- PCIe
- SDIO (supports boot from eMMC)
- SPI
- UART
- I2c
- Gigabit Ethernet

Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
diff --git a/plat/marvell/a3700/common/dram_win.c b/plat/marvell/a3700/common/dram_win.c
new file mode 100644
index 0000000..fb236d8
--- /dev/null
+++ b/plat/marvell/a3700/common/dram_win.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <dram_win.h>
+#include <marvell_plat_priv.h>
+#include <mmio.h>
+#include <mvebu.h>
+#include <plat_marvell.h>
+#include <string.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]);
+}
+