plat/arm: Add MHUv2 support to SCMI driver

Currently the SCMI driver supports MHUv1, but Arm platforms may have
varied versions of MHU driver, with MHUv2 controllers being in the
latest Arm platforms.

This patch updates the SCMI driver to support MHUv2, specifically that
the sender must send the wake-up to the receiver before initiating any
data transfer.

Also, the existing mhu driver files, css_mhu.c and css_mhu.h, have been
moved from the scpi directory to a new directory, css/drivers/mhu.

Change-Id: I9b46b492a3e1d9e26db12d83a9773958a8c8402f
Signed-off-by: Samarth Parikh <samarth.parikh@arm.com>
diff --git a/plat/arm/css/drivers/mhu/css_mhu.c b/plat/arm/css/drivers/mhu/css_mhu.c
new file mode 100644
index 0000000..30492a6
--- /dev/null
+++ b/plat/arm/css/drivers/mhu/css_mhu.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bakery_lock.h>
+#include <css_def.h>
+#include <mmio.h>
+#include <plat_arm.h>
+#include <platform_def.h>
+#include "css_mhu.h"
+
+/* SCP MHU secure channel registers */
+#define SCP_INTR_S_STAT		0x200
+#define SCP_INTR_S_SET		0x208
+#define SCP_INTR_S_CLEAR	0x210
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT		0x300
+#define CPU_INTR_S_SET		0x308
+#define CPU_INTR_S_CLEAR	0x310
+
+ARM_INSTANTIATE_LOCK;
+
+/* Weak definition may be overridden in specific CSS based platform */
+#pragma weak plat_arm_pwrc_setup
+
+
+/*
+ * Slot 31 is reserved because the MHU hardware uses this register bit to
+ * indicate a non-secure access attempt. The total number of available slots is
+ * therefore 31 [30:0].
+ */
+#define MHU_MAX_SLOT_ID		30
+
+void mhu_secure_message_start(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+
+	arm_lock_get();
+
+	/* Make sure any previous command has finished */
+	while (mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) &
+							(1 << slot_id))
+		;
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+	assert(!(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) &
+							(1 << slot_id)));
+
+	/* Send command to SCP */
+	mmio_write_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+	/* Wait for response from SCP */
+	uint32_t response;
+	while (!(response = mmio_read_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_STAT)))
+		;
+
+	return response;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+
+	/*
+	 * Clear any response we got by writing one in the relevant slot bit to
+	 * the CLEAR register
+	 */
+	mmio_write_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
+
+	arm_lock_release();
+}
+
+void mhu_secure_init(void)
+{
+	arm_lock_init();
+
+	/*
+	 * The STAT register resets to zero. Ensure it is in the expected state,
+	 * as a stale or garbage value would make us think it's a message we've
+	 * already sent.
+	 */
+	assert(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) == 0);
+}
+
+void plat_arm_pwrc_setup(void)
+{
+	mhu_secure_init();
+}
diff --git a/plat/arm/css/drivers/mhu/css_mhu.h b/plat/arm/css/drivers/mhu/css_mhu.h
new file mode 100644
index 0000000..0fb00c7
--- /dev/null
+++ b/plat/arm/css/drivers/mhu/css_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CSS_MHU_H__
+#define __CSS_MHU_H__
+
+#include <stdint.h>
+
+void mhu_secure_message_start(unsigned int slot_id);
+void mhu_secure_message_send(unsigned int slot_id);
+uint32_t mhu_secure_message_wait(void);
+void mhu_secure_message_end(unsigned int slot_id);
+
+void mhu_secure_init(void);
+
+#endif	/* __CSS_MHU_H__ */
diff --git a/plat/arm/css/drivers/mhu/css_mhu_doorbell.c b/plat/arm/css/drivers/mhu/css_mhu_doorbell.c
new file mode 100644
index 0000000..b9faf67
--- /dev/null
+++ b/plat/arm/css/drivers/mhu/css_mhu_doorbell.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <platform_def.h>
+#include "css_mhu_doorbell.h"
+#include "../scmi/scmi.h"
+
+void mhu_ring_doorbell(scmi_channel_plat_info_t *plat_info)
+{
+	MHU_RING_DOORBELL(plat_info->db_reg_addr,
+			plat_info->db_modify_mask,
+			plat_info->db_preserve_mask);
+	return;
+}
+
+void mhuv2_ring_doorbell(scmi_channel_plat_info_t *plat_info)
+{
+	/* wake receiver */
+	MHU_V2_ACCESS_REQUEST(MHUV2_BASE_ADDR);
+
+	/* wait for receiver to acknowledge its ready */
+	while (MHU_V2_IS_ACCESS_READY(MHUV2_BASE_ADDR) == 0)
+		;
+
+	MHU_RING_DOORBELL(plat_info->db_reg_addr,
+			plat_info->db_modify_mask,
+			plat_info->db_preserve_mask);
+
+	/* clear the access request for the recevier */
+	MHU_V2_CLEAR_REQUEST(MHUV2_BASE_ADDR);
+
+	return;
+}
diff --git a/plat/arm/css/drivers/mhu/css_mhu_doorbell.h b/plat/arm/css/drivers/mhu/css_mhu_doorbell.h
new file mode 100644
index 0000000..3c94536
--- /dev/null
+++ b/plat/arm/css/drivers/mhu/css_mhu_doorbell.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_MHU_DOORBELL_H
+#define CSS_MHU_DOORBELL_H
+
+#include <mmio.h>
+#include <stdint.h>
+
+/* MHUv2 Base Address */
+#define MHUV2_BASE_ADDR		PLAT_CSS_MHU_BASE
+
+/* MHUv2 Control Registers Offsets */
+#define MHU_V2_MSG_NO_CAP_OFFSET		0xF80
+#define MHU_V2_ACCESS_REQ_OFFSET		0xF88
+#define MHU_V2_ACCESS_READY_OFFSET		0xF8C
+
+#define SENDER_REG_STAT(CHANNEL)	(0x20 * (CHANNEL))
+#define SENDER_REG_SET(CHANNEL)		(0x20 * (CHANNEL)) + 0xC
+
+/* Helper macro to ring doorbell */
+#define MHU_RING_DOORBELL(addr, modify_mask, preserve_mask)	do {	\
+		uint32_t db = mmio_read_32(addr) & (preserve_mask);	\
+		mmio_write_32(addr, db | (modify_mask));		\
+	} while (0)
+
+#define MHU_V2_ACCESS_REQUEST(addr)	\
+	mmio_write_32((addr) + MHU_V2_ACCESS_REQ_OFFSET, 0x1)
+
+#define MHU_V2_CLEAR_REQUEST(addr)	\
+	mmio_write_32((addr) + MHU_V2_ACCESS_REQ_OFFSET, 0x0)
+
+#define MHU_V2_IS_ACCESS_READY(addr)	\
+	(mmio_read_32((addr) + MHU_V2_ACCESS_READY_OFFSET) & 0x1)
+
+struct scmi_channel_plat_info;
+void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info);
+void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info);
+
+#endif	/* CSS_MHU_DOORBELL_H */