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/a8k/common/plat_ble_setup.c b/plat/marvell/a8k/common/plat_ble_setup.c
new file mode 100644
index 0000000..0cd62cb
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_ble_setup.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+#include <ap_setup.h>
+#include <aro.h>
+#include <ccu.h>
+#include <cp110_setup.h>
+#include <debug.h>
+#include <io_win.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_EN_CTRL_REG			(MVEBU_AP_GEN_MGMT_BASE + 0x130)
+#define AVS_ENABLE_OFFSET		(0)
+#define AVS_SOFT_RESET_OFFSET		(2)
+#define AVS_LOW_VDD_LIMIT_OFFSET	(4)
+#define AVS_HIGH_VDD_LIMIT_OFFSET	(12)
+#define AVS_TARGET_DELTA_OFFSET		(21)
+#define AVS_VDD_LOW_LIMIT_MASK	        (0xFF << AVS_LOW_VDD_LIMIT_OFFSET)
+#define AVS_VDD_HIGH_LIMIT_MASK	        (0xFF << AVS_HIGH_VDD_LIMIT_OFFSET)
+/* 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))
+
+#define AVS_A3900_CLK_VALUE		((0x80 << 24) | \
+					 (0x2c2 << 13) | \
+					 (0x2c2 << 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)
+
+/* Notify bootloader on DRAM setup */
+#define AP807_CPU_ARO_0_CTRL_0		(MVEBU_RFU_BASE + 0x82A8)
+#define AP807_CPU_ARO_1_CTRL_0		(MVEBU_RFU_BASE + 0x8D00)
+
+/* 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)
+
+/*
+ * - 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]
+ * - 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
+
+#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_SVC4_OFFS		42		/* LD0[112:105] */
+#define EFUSE_AP_LD0_WP_MASK		0xFF
+
+#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS	4
+
+/* 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
+ ****************************************************************************
+ */
+static void ble_plat_avs_config(void)
+{
+	uint32_t reg_val, device_id;
+
+	/* Check which SoC is running and act accordingly */
+	if (ble_get_ap_type() == CHIP_ID_AP807) {
+		VERBOSE("AVS: Setting AP807 AVS CTRL to 0x%x\n",
+			AVS_A3900_CLK_VALUE);
+		mmio_write_32(AVS_EN_CTRL_REG, AVS_A3900_CLK_VALUE);
+		return;
+	}
+
+	/* 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:
+		/* Set the new AVS value - fix the default one on A80x0 */
+		mmio_write_32(AVS_EN_CTRL_REG, AVS_A8K_CLK_VALUE);
+		break;
+	case MVEBU_70X0_DEV_ID:
+	case MVEBU_70X0_CP115_DEV_ID:
+		/* Only fix AVS for CPU clocks lower than 1600MHz on A70x0 */
+		reg_val = mmio_read_32(MVEBU_AP_SAR_REG_BASE(
+						FREQ_MODE_AP_SAR_REG_NUM));
+		reg_val &= SAR_CLOCK_FREQ_MODE_MASK;
+		reg_val >>= SAR_CLOCK_FREQ_MODE_OFFSET;
+		if ((reg_val > CPU_1600_DDR_900_RCLK_900_2) &&
+		    (reg_val < CPU_DDR_RCLK_INVALID))
+			mmio_write_32(AVS_EN_CTRL_REG, AVS_A7K_LOW_CLK_VALUE);
+		break;
+	default:
+		ERROR("Unsupported Device ID 0x%x\n", device_id);
+	}
+}
+
+/****************************************************************************
+ * 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;
+	uint8_t  svc[4], perr[4], i, sw_ver;
+
+	/* Due to a bug in A3900 device_id skip SVC config
+	 * TODO: add SVC config once it is decided for a3900
+	 */
+	if (ble_get_ap_type() == CHIP_ID_AP807) {
+		NOTICE("SVC: SVC is not supported on AP807\n");
+		ble_plat_avs_config();
+		return;
+	}
+
+	/* 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);
+		ble_plat_avs_config();
+		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;
+	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]);
+
+	/* 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 {
+		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 */
+	avs_workpoint &= 0x7F;
+
+	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
+
+/* Switch to ARO from PLL in ap807 */
+static void aro_to_pll(void)
+{
+	unsigned int reg;
+
+	/* switch from ARO to PLL */
+	reg = mmio_read_32(AP807_CPU_ARO_0_CTRL_0);
+	reg |= AP807_CPU_ARO_SEL_PLL_MASK;
+	mmio_write_32(AP807_CPU_ARO_0_CTRL_0, reg);
+
+	reg = mmio_read_32(AP807_CPU_ARO_1_CTRL_0);
+	reg |= AP807_CPU_ARO_SEL_PLL_MASK;
+	mmio_write_32(AP807_CPU_ARO_1_CTRL_0, reg);
+
+	mdelay(1000);
+
+	/* disable ARO clk driver */
+	reg = mmio_read_32(AP807_CPU_ARO_0_CTRL_0);
+	reg |= (AP807_CPU_ARO_CLK_EN_MASK);
+	mmio_write_32(AP807_CPU_ARO_0_CTRL_0, reg);
+
+	reg = mmio_read_32(AP807_CPU_ARO_1_CTRL_0);
+	reg |= (AP807_CPU_ARO_CLK_EN_MASK);
+	mmio_write_32(AP807_CPU_ARO_1_CTRL_0, reg);
+}
+
+int ble_plat_setup(int *skip)
+{
+	int ret;
+
+	/* 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();
+
+	/* work with PLL clock driver in AP807 */
+	if (ble_get_ap_type() == CHIP_ID_AP807)
+		aro_to_pll();
+
+	/* 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;
+}