mediatek: mt8183: add MTK SSPM driver

Add MTK SSPM driver.

Change-Id: I30dd9a95456b8c3c8d18fd22120824eec97634ee
diff --git a/plat/mediatek/mt8183/drivers/sspm/sspm.c b/plat/mediatek/mt8183/drivers/sspm/sspm.c
new file mode 100644
index 0000000..3917638
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/sspm/sspm.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <sspm.h>
+
+static void memcpy_to_sspm(uint32_t dst, uint32_t *src, uint32_t len)
+{
+	while (len--) {
+		mmio_write_32(dst, *src);
+		dst += sizeof(uint32_t);
+		src++;
+	}
+}
+
+static void memcpy_from_sspm(uint32_t *dst, uint32_t src, uint32_t len)
+{
+	while (len--) {
+		*dst = mmio_read_32(src);
+		dst++;
+		src += sizeof(uint32_t);
+	}
+}
+
+int sspm_mbox_read(uint32_t slot, uint32_t *data, uint32_t len)
+{
+	if (slot >= 32)	{
+		ERROR("%s:slot = %d\n", __func__, slot);
+		return -EINVAL;
+	}
+
+	if (data)
+		memcpy_from_sspm(data,
+				 MBOX3_BASE + slot * 4,
+				 len);
+
+	return 0;
+}
+
+int sspm_mbox_write(uint32_t slot, uint32_t *data, uint32_t len)
+{
+	if (slot >= 32) {
+		ERROR("%s:slot = %d\n", __func__, slot);
+		return -EINVAL;
+	}
+
+	if (data)
+		memcpy_to_sspm(MBOX3_BASE + slot * 4,
+			       data,
+			       len);
+
+	return 0;
+}
+
+static int sspm_ipi_check_ack(uint32_t id)
+{
+	int ret = 0;
+
+	if (id == IPI_ID_PLATFORM) {
+		if ((mmio_read_32(MBOX0_BASE + MBOX_IN_IRQ_OFS) & 0x1) == 0x1)
+			ret = -EINPROGRESS;
+	} else if (id == IPI_ID_SUSPEND) {
+		if ((mmio_read_32(MBOX1_BASE + MBOX_IN_IRQ_OFS) & 0x2) == 0x2)
+			ret = -EINPROGRESS;
+	} else {
+		ERROR("%s: id = %d\n", __func__, id);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int sspm_ipi_send_non_blocking(uint32_t id, uint32_t *data)
+{
+	int ret = 0;
+
+	ret = sspm_ipi_check_ack(id);
+	if (ret)
+		return ret;
+
+	if (id == IPI_ID_PLATFORM) {
+		memcpy_to_sspm(MBOX0_BASE + PINR_OFFSET_PLATFORM * 4,
+			       data,
+			       PINR_SIZE_PLATFORM);
+		dsb();
+		mmio_write_32(MBOX0_BASE + MBOX_OUT_IRQ_OFS, 0x1);
+	} else if (id == IPI_ID_SUSPEND) {
+		memcpy_to_sspm(MBOX1_BASE + PINR_OFFSET_SUSPEND * 4,
+			       data,
+			       PINR_SIZE_SUSPEND);
+		dsb();
+		mmio_write_32(MBOX1_BASE + MBOX_OUT_IRQ_OFS,
+			      0x2);
+	}
+
+	return 0;
+}
+
+int sspm_ipi_recv_non_blocking(uint32_t id, uint32_t *data, uint32_t len)
+{
+	int ret = 0;
+
+	ret = sspm_ipi_check_ack(id);
+	if (ret == -EINPROGRESS) {
+		if (id == IPI_ID_PLATFORM) {
+			memcpy_from_sspm(data,
+					 MBOX0_BASE + PINR_OFFSET_PLATFORM * 4,
+					 len);
+			dsb();
+			/* clear interrupt bit*/
+			mmio_write_32(MBOX0_BASE + MBOX_IN_IRQ_OFS,
+				      0x1);
+			ret = 0;
+		} else if (id == IPI_ID_SUSPEND) {
+			memcpy_from_sspm(data,
+					 MBOX1_BASE + PINR_OFFSET_SUSPEND * 4,
+					 len);
+			dsb();
+			/* clear interrupt bit*/
+			mmio_write_32(MBOX1_BASE + MBOX_IN_IRQ_OFS,
+				      0x2);
+			ret = 0;
+		}
+	} else if (ret == 0) {
+		ret = -EBUSY;
+	}
+
+	return ret;
+}
+
+int sspm_alive_show(void)
+{
+	uint32_t ipi_data, count;
+	int ret = 0;
+
+	count = 5;
+	ipi_data = 0xdead;
+
+	if (sspm_ipi_send_non_blocking(IPI_ID_PLATFORM, &ipi_data) != 0) {
+		ERROR("sspm init send fail! ret=%d\n", ret);
+		return -1;
+	}
+
+	while (sspm_ipi_recv_non_blocking(IPI_ID_PLATFORM,
+					  &ipi_data,
+					  sizeof(ipi_data))
+					  && count) {
+		mdelay(100);
+		count--;
+	}
+
+	return (ipi_data == 1) ? 0 : -1;
+}