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