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/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;
+}