summaryrefslogtreecommitdiff
path: root/drivers/soc/imx/mu/mx8_mu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/imx/mu/mx8_mu.c')
-rw-r--r--drivers/soc/imx/mu/mx8_mu.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/soc/imx/mu/mx8_mu.c b/drivers/soc/imx/mu/mx8_mu.c
new file mode 100644
index 000000000000..87f6eae78d61
--- /dev/null
+++ b/drivers/soc/imx/mu/mx8_mu.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mx8_mu.h>
+#include <linux/of.h>
+
+static int version;
+
+/*!
+ * This function sets the Flag n of the MU.
+ */
+int32_t MU_SetFn(void __iomem *base, uint32_t Fn)
+{
+ uint32_t reg, offset;
+
+ reg = Fn & (~MU_CR_Fn_MASK1);
+ if (reg > 0)
+ return -EINVAL;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ /* Clear ABFn. */
+ reg &= ~MU_CR_Fn_MASK1;
+ reg |= Fn;
+ writel_relaxed(reg, base + offset);
+
+ return 0;
+}
+
+/*!
+ * This function reads the status from status register.
+ */
+uint32_t MU_ReadStatus(void __iomem *base)
+{
+ uint32_t reg, offset;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ASR_OFFSET1 : MU_ASR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+
+ return reg;
+}
+
+/*!
+ * This function enables specific RX full interrupt.
+ */
+void MU_EnableRxFullInt(void __iomem *base, uint32_t index)
+{
+ uint32_t reg, offset;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1);
+ reg |= MU_CR_RIE0_MASK1 >> index;
+ writel_relaxed(reg, base + offset);
+}
+EXPORT_SYMBOL(MU_EnableRxFullInt);
+
+/*!
+ * This function enables specific general purpose interrupt.
+ */
+void MU_EnableGeneralInt(void __iomem *base, uint32_t index)
+{
+ uint32_t reg, offset;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1);
+ reg |= MU_CR_GIE0_MASK1 >> index;
+ writel_relaxed(reg, base + offset);
+}
+
+/*
+ * Wait and send message to the other core.
+ */
+void MU_SendMessage(void __iomem *base, uint32_t regIndex, uint32_t msg)
+{
+ uint32_t mask = MU_SR_TE0_MASK1 >> regIndex;
+
+ if (unlikely(version == MU_VER_ID_V10)) {
+ /* Wait TX register to be empty. */
+ while (!(readl_relaxed(base + MU_V10_ASR_OFFSET1) & mask))
+ ;
+ writel_relaxed(msg, base + MU_V10_ATR0_OFFSET1
+ + (regIndex * 4));
+ } else {
+ /* Wait TX register to be empty. */
+ while (!(readl_relaxed(base + MU_ASR_OFFSET1) & mask))
+ ;
+ writel_relaxed(msg, base + MU_ATR0_OFFSET1 + (regIndex * 4));
+ }
+}
+
+/*
+ * Wait and send message to the other core with timeout mechanism.
+ */
+void MU_SendMessageTimeout(void __iomem *base, uint32_t regIndex, uint32_t msg,
+ uint32_t t)
+{
+ uint32_t mask = MU_SR_TE0_MASK1 >> regIndex;
+ uint32_t timeout = t;
+
+ if (unlikely(version == MU_VER_ID_V10)) {
+ /* Wait TX register to be empty. */
+ while (!(readl_relaxed(base + MU_V10_ASR_OFFSET1) & mask)) {
+ udelay(10);
+ if (timeout-- == 0)
+ return;
+ };
+
+ writel_relaxed(msg, base + MU_V10_ATR0_OFFSET1
+ + (regIndex * 4));
+ } else {
+ /* Wait TX register to be empty. */
+ while (!(readl_relaxed(base + MU_ASR_OFFSET1) & mask)) {
+ udelay(10);
+ if (timeout-- == 0)
+ return;
+ };
+
+ writel_relaxed(msg, base + MU_ATR0_OFFSET1 + (regIndex * 4));
+ }
+}
+EXPORT_SYMBOL(MU_SendMessageTimeout);
+
+/*
+ * Wait to receive message from the other core.
+ */
+void MU_ReceiveMsg(void __iomem *base, uint32_t regIndex, uint32_t *msg)
+{
+ uint32_t mask = MU_SR_RF0_MASK1 >> regIndex;
+
+ if (unlikely(version == MU_VER_ID_V10)) {
+ /* Wait RX register to be full. */
+ while (!(readl_relaxed(base + MU_V10_ASR_OFFSET1) & mask))
+ ;
+ *msg = readl_relaxed(base + MU_V10_ARR0_OFFSET1
+ + (regIndex * 4));
+ } else {
+ /* Wait RX register to be full. */
+ while (!(readl_relaxed(base + MU_ASR_OFFSET1) & mask))
+ ;
+ *msg = readl_relaxed(base + MU_ARR0_OFFSET1 + (regIndex * 4));
+ }
+}
+EXPORT_SYMBOL(MU_ReceiveMsg);
+
+
+
+void MU_Init(void __iomem *base)
+{
+ uint32_t reg, offset;
+
+ version = readl_relaxed(base) >> 16;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ /* Clear GIEn, TIEn, GIRn and ABFn. */
+ reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_TIEn_MASK1
+ | MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1 | MU_CR_Fn_MASK1);
+
+ /*
+ * i.MX6SX and i.MX7D have multi-core power management which need
+ * to use RIE interrupts.
+ */
+ if (!(of_machine_is_compatible("fsl,imx6sx") ||
+ of_machine_is_compatible("fsl,imx7d")))
+ reg &= ~MU_CR_RIEn_MASK1;
+
+ writel_relaxed(reg, base + offset);
+}
+EXPORT_SYMBOL(MU_Init);
+
+/**@}*/
+