diff mbox series

[U-Boot,04/41] imx8: add IPC communication support between ACore and SCU

Message ID 20180528122526.20597-5-peng.fan@nxp.com
State Superseded
Delegated to: Stefano Babic
Headers show
Series imx: add i.MX8QXP support | expand

Commit Message

Peng Fan May 28, 2018, 12:24 p.m. UTC
The IPC communication is based on Message Unit(MU) between ACore
and SCU.

Add the lowlevel MU initialization, message send/receive code.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 arch/arm/include/asm/arch-imx8/fsl_mu_hal.h |  54 +++++++++++++++
 arch/arm/include/asm/arch-imx8/sci/sci.h    |  39 +++++++++++
 arch/arm/mach-imx/imx8/Makefile             |   1 +
 arch/arm/mach-imx/imx8/fsl_mu_hal.c         |  28 ++++++++
 arch/arm/mach-imx/imx8/sci/ipc.c            | 100 ++++++++++++++++++++++++++++
 5 files changed, 222 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-imx8/fsl_mu_hal.h
 create mode 100644 arch/arm/include/asm/arch-imx8/sci/sci.h
 create mode 100644 arch/arm/mach-imx/imx8/fsl_mu_hal.c
 create mode 100644 arch/arm/mach-imx/imx8/sci/ipc.c
diff mbox series

Patch

diff --git a/arch/arm/include/asm/arch-imx8/fsl_mu_hal.h b/arch/arm/include/asm/arch-imx8/fsl_mu_hal.h
new file mode 100644
index 0000000000..a7b9518604
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8/fsl_mu_hal.h
@@ -0,0 +1,54 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ */
+
+#ifndef __FSL_MU_HAL_H__
+#define __FSL_MU_HAL_H__
+
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+struct mu_type {
+	u32 tr[4];
+	u32 rr[4];
+	u32 sr;
+	u32 cr;
+};
+
+#define MU_SR_GIP0_MASK	BIT(31)
+#define MU_SR_RF0_MASK	BIT(27)
+#define MU_SR_TE0_MASK	BIT(23)
+#define MU_CR_GIE0_MASK	BIT(31)
+#define MU_CR_RIE0_MASK	BIT(27)
+#define MU_CR_TIE0_MASK	BIT(23)
+#define MU_CR_GIR0_MASK	BIT(19)
+
+#define MU_CR_GIEn_MASK	0xF0000000u
+#define MU_CR_RIEn_MASK	0x0F000000u
+#define MU_CR_TIEn_MASK	0x00F00000u
+#define MU_CR_GIRn_MASK	0x000F0000u
+#define MU_CR_Fn_MASK	0x7u
+#define MU_CR_NMI_MASK	0x8u
+
+#define MU_CR_GIRn_NMI_MASK	(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)
+
+#define MU_TR_COUNT		4
+#define MU_RR_COUNT		4
+
+static inline void mu_hal_init(struct mu_type *base)
+{
+	/* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */
+	clrbits_le32(&base->cr, MU_CR_GIEn_MASK | MU_CR_RIEn_MASK |
+		     MU_CR_TIEn_MASK | MU_CR_GIRn_MASK | MU_CR_Fn_MASK);
+}
+
+static inline void mu_hal_enablerxfullint(struct mu_type *base, u32 index)
+{
+	clrsetbits_le32(&base->cr, MU_CR_GIRn_NMI_MASK,
+			MU_CR_RIE0_MASK >> index);
+}
+
+void mu_hal_sendmsg(struct mu_type *base, u32 regindex, u32 msg);
+void mu_hal_receivemsg(struct mu_type *base, u32 regindex, u32 *msg);
+#endif /* __FSL_MU_HAL_H__ */
diff --git a/arch/arm/include/asm/arch-imx8/sci/sci.h b/arch/arm/include/asm/arch-imx8/sci/sci.h
new file mode 100644
index 0000000000..589dba0653
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8/sci/sci.h
@@ -0,0 +1,39 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ */
+
+#ifndef _SC_SCI_H
+#define _SC_SCI_H
+
+/*!
+ * This type is used to declare a handle for an IPC communication
+ * channel. Its meaning is specific to the IPC implementation.
+ */
+typedef u64 sc_ipc_t;
+
+/*!
+ * This type is used to declare an ID for an IPC communication
+ * channel. Its meaning is specific to the IPC implementation.
+ */
+typedef u64 sc_ipc_id_t;
+
+#include <asm/arch/sci/types.h>
+#include <asm/arch/sci/ipc.h>
+#include <asm/arch/sci/svc/misc/api.h>
+#include <asm/arch/sci/svc/pad/api.h>
+#include <asm/arch/sci/svc/pm/api.h>
+#include <asm/arch/sci/svc/rm/api.h>
+#include <asm/arch/sci/svc/timer/api.h>
+
+#define MU_BASE_ADDR(id)	(0x5D1B0000U + (id * 0x10000))
+
+#define SC_IPC_AP_CH0		(MU_BASE_ADDR(0))
+#define SC_IPC_AP_CH1		(MU_BASE_ADDR(1))
+#define SC_IPC_AP_CH2		(MU_BASE_ADDR(2))
+#define SC_IPC_AP_CH3		(MU_BASE_ADDR(3))
+#define SC_IPC_AP_CH4		(MU_BASE_ADDR(4))
+
+#define SC_IPC_CH		SC_IPC_AP_CH1
+
+#endif
diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile
index cfb7e34653..8ae0518c16 100644
--- a/arch/arm/mach-imx/imx8/Makefile
+++ b/arch/arm/mach-imx/imx8/Makefile
@@ -4,6 +4,7 @@ 
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-y += fsl_mu_hal.o sci/ipc.o
 obj-y += sci/svc/misc/rpc_clnt.o
 obj-y += sci/svc/pad/rpc_clnt.o
 obj-y += sci/svc/pm/rpc_clnt.o
diff --git a/arch/arm/mach-imx/imx8/fsl_mu_hal.c b/arch/arm/mach-imx/imx8/fsl_mu_hal.c
new file mode 100644
index 0000000000..87b8d5a355
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/fsl_mu_hal.c
@@ -0,0 +1,28 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <log.h>
+#include <asm/arch/fsl_mu_hal.h>
+
+void mu_hal_sendmsg(struct mu_type *base, u32 regindex, u32 msg)
+{
+	assert(regindex < MU_TR_COUNT);
+	u32 mask = MU_SR_TE0_MASK >> regindex;
+	/* Wait TX register to be empty. */
+	while (!(readl(&base->sr) & mask))
+		;
+	writel(msg, &base->tr[regindex]);
+}
+
+void mu_hal_receivemsg(struct mu_type *base, u32 regindex, u32 *msg)
+{
+	assert(regindex < MU_TR_COUNT);
+	u32 mask = MU_SR_RF0_MASK >> regindex;
+
+	/* Wait RX register to be full. */
+	while (!(readl(&base->sr) & mask))
+		;
+	*msg = readl(&base->rr[regindex]);
+}
diff --git a/arch/arm/mach-imx/imx8/sci/ipc.c b/arch/arm/mach-imx/imx8/sci/ipc.c
new file mode 100644
index 0000000000..7af10de027
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/sci/ipc.c
@@ -0,0 +1,100 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <asm/arch/fsl_mu_hal.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sci/ipc.h>
+#include <asm/arch/sci/rpc.h>
+
+void sc_ipc_read(sc_ipc_t ipc, void *data)
+{
+	struct mu_type *base = (struct mu_type *)ipc;
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *)data;
+	u8 count = 0;
+
+	/* Check parms */
+	if (!base || !msg)
+		return;
+
+	/* Read first word */
+	mu_hal_receivemsg(base, 0, (u32 *)msg);
+	count++;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG) {
+		*((u32 *)msg) = 0;
+		return;
+	}
+
+	/* Read remaining words */
+	while (count < msg->size) {
+		mu_hal_receivemsg(base, count % MU_RR_COUNT,
+				  &msg->DATA.u32[count - 1]);
+		count++;
+	}
+}
+
+void sc_ipc_write(sc_ipc_t ipc, void *data)
+{
+	struct mu_type *base = (struct mu_type *)ipc;
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *)data;
+	u8 count = 0;
+
+	/* Check parms */
+	if (!base || !msg)
+		return;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG)
+		return;
+
+	/* Write first word */
+	mu_hal_sendmsg(base, 0, *((u32 *)msg));
+	count++;
+
+	/* Write remaining words */
+	while (count < msg->size) {
+		mu_hal_sendmsg(base, count % MU_TR_COUNT,
+			       msg->DATA.u32[count - 1]);
+		count++;
+	}
+}
+
+void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, sc_bool_t no_resp)
+{
+	sc_ipc_write(ipc, msg);
+	if (!no_resp)
+		sc_ipc_read(ipc, msg);
+}
+
+sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id)
+{
+	struct mu_type *base = (struct mu_type *)id;
+	u32 i;
+
+	/* Get MU base associated with IPC channel */
+	if (!ipc || !base)
+		return SC_ERR_IPC;
+
+	/* Init MU */
+	mu_hal_init(base);
+
+	/* Enable all RX interrupts */
+	for (i = 0; i < MU_RR_COUNT; i++)
+		mu_hal_enablerxfullint(base, i);
+
+	/* Return MU address as handle */
+	*ipc = (sc_ipc_t)id;
+
+	return SC_ERR_NONE;
+}
+
+void sc_ipc_close(sc_ipc_t ipc)
+{
+	struct mu_type *base = (struct mu_type *)ipc;
+
+	if (base)
+		mu_hal_init(base);
+}