summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2014-12-17 17:58:40 +0100
committerStefan Agner <stefan.agner@toradex.com>2014-12-17 18:38:46 +0100
commit6f0bbad6b805cf2014eec54531dbe4ddb4867a91 (patch)
tree111322498c811383e22463057b76b59cd2848434
parent4f10615fb1b80f0f959095c87c662089376d168c (diff)
ARM: imx: vf610: extend MSCM with CPU2CPU interrupt support
Extend the MSCM driver with CPU2CPU interrupt support. Those interrupts are mainly used for the external MCC kernel module which uses the functionality to pass messages to the secondary Cortex-M4 core. In Timesys version (at least up to 1.06), the interrupt handling was directly done in the MCC kernel module. However, because newer kernels use virtual interrupt numbers, it is not possible to use hardcoded hardware IRQ number by default. By requesting the interupts within the MSCM driver and exporting some helper functions.
-rw-r--r--arch/arm/mach-imx/mscm-vf610.c90
-rw-r--r--include/linux/vf610_mscm.h11
2 files changed, 97 insertions, 4 deletions
diff --git a/arch/arm/mach-imx/mscm-vf610.c b/arch/arm/mach-imx/mscm-vf610.c
index 6dc45b52b811..e36a7936b57e 100644
--- a/arch/arm/mach-imx/mscm-vf610.c
+++ b/arch/arm/mach-imx/mscm-vf610.c
@@ -11,25 +11,50 @@
#include <linux/cpu_pm.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/irqchip/arm-gic.h>
#include "common.h"
#define MSCM_CPxNUM 0x4
+
+#define MSCM_IRCP0IR 0x800
+#define MSCM_IRCP1IR 0x804
+#define MSCM_IRCPnIR(n) ((n) * 0x4 + MSCM_IRCP0IR)
+#define MSCM_IRCPnIR_INT(n) (0x1 << (n))
+#define MSCM_IRCPGIR 0x820
+
+#define MSCM_INTID_MASK 0x3
+#define MSCM_INTID(n) ((n) & MSCM_INTID_MASK)
+#define MSCM_CPUTL(n) (((n) == 0 ? 1 : 2) << 16)
+
#define MSCM_IRSPRC(n) (0x880 + 2 * (n))
#define MSCM_IRSPRC_CPEN_MASK 0x3
#define MSCM_IRSPRC_NUM 112
+#define MSCM_CPU2CPU_NUM 4
+
#define MSCM_IRQ_OFFSET 32
static void __iomem *mscm_base;
+struct device_node *mscm_node;
static u16 mscm_saved_irsprc[MSCM_IRSPRC_NUM];
static u16 cpu_id;
+struct mscm_cpu2cpu_irq_data {
+ int intid;
+ int irq;
+ irq_handler_t handler;
+ void *priv;
+};
+
+static struct mscm_cpu2cpu_irq_data cpu2cpu_irq_data[MSCM_CPU2CPU_NUM];
+
static int vf610_mscm_notifier(struct notifier_block *self, unsigned long cmd,
void *v)
{
@@ -112,12 +137,69 @@ static const struct irq_domain_ops routable_irq_domain_ops = {
.xlate = vf610_mscm_domain_xlate,
};
-void __init vf610_mscm_init(void)
+static irqreturn_t mscm_cpu2cpu_irq_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret;
+ struct mscm_cpu2cpu_irq_data *data = dev_id;
+
+
+ ret = data->handler(data->intid, data->priv);
+ if (ret == IRQ_HANDLED)
+ writel(MSCM_IRCPnIR_INT(data->intid), mscm_base + MSCM_IRCPnIR(cpu_id));
+
+ return ret;
+}
+
+int mscm_request_cpu2cpu_irq(unsigned int intid, irq_handler_t handler,
+ const char *name, void *priv)
+{
+ int irq;
+ struct mscm_cpu2cpu_irq_data *data;
+
+
+ if (intid >= MSCM_CPU2CPU_NUM)
+ return -EINVAL;
+
+ irq = of_irq_get(mscm_node, intid);
+ if (irq < 0)
+ return irq;
+
+ data = &cpu2cpu_irq_data[intid];
+ data->intid = intid;
+ data->irq = irq;
+ data->handler = handler;
+ data->priv = priv;
+
+ return request_irq(irq, mscm_cpu2cpu_irq_handler, 0, name, data);
+}
+EXPORT_SYMBOL(mscm_request_cpu2cpu_irq);
+
+void mscm_free_cpu2cpu_irq(unsigned int intid, void *priv)
{
- struct device_node *np;
+ struct mscm_cpu2cpu_irq_data *data;
- np = of_find_compatible_node(NULL, NULL, "fsl,vf610-mscm");
- mscm_base = of_iomap(np, 0);
+ if (intid >= MSCM_CPU2CPU_NUM)
+ return;
+
+ data = &cpu2cpu_irq_data[intid];
+
+ if (data->irq < 0)
+ return;
+
+ free_irq(data->irq, data);
+}
+EXPORT_SYMBOL(mscm_free_cpu2cpu_irq);
+
+void mscm_trigger_cpu2cpu_irq(unsigned int intid, int cpuid)
+{
+ writel(MSCM_INTID(intid) | MSCM_CPUTL(cpuid), mscm_base + MSCM_IRCPGIR);
+}
+EXPORT_SYMBOL(mscm_trigger_cpu2cpu_irq);
+
+void __init vf610_mscm_init(void)
+{
+ mscm_node = of_find_compatible_node(NULL, NULL, "fsl,vf610-mscm");
+ mscm_base = of_iomap(mscm_node, 0);
if (!mscm_base) {
WARN_ON(1);
diff --git a/include/linux/vf610_mscm.h b/include/linux/vf610_mscm.h
new file mode 100644
index 000000000000..881fbd772a95
--- /dev/null
+++ b/include/linux/vf610_mscm.h
@@ -0,0 +1,11 @@
+#ifndef __VF610_MSCM__
+#define __VF610_MSCM__
+
+#include <linux/interrupt.h>
+
+int mscm_request_cpu2cpu_irq(unsigned int intid, irq_handler_t handler,
+ const char *name, void *priv);
+void mscm_free_cpu2cpu_irq(unsigned int intid, void *priv);
+void mscm_trigger_cpu2cpu_irq(unsigned int intid, int cpuid);
+
+#endif /* __VF610_MSCM__ */