diff options
Diffstat (limited to 'drivers/soc/imx/mu/mx8_mu.c')
-rw-r--r-- | drivers/soc/imx/mu/mx8_mu.c | 191 |
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); + +/**@}*/ + |