intc: Add support for GRLIB IRQMP

This adds support for the GRLIB IRQMP interrupt controller commonly used
in LEON3/4/5 systems.

The driver supports the 15 SPARC interrupts and 16 extended interrupts.

Signed-off-by: Martin Åberg <martin.aberg@gaisler.com>
diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt
index 2b31302..e8bc013 100644
--- a/drivers/interrupt_controller/CMakeLists.txt
+++ b/drivers/interrupt_controller/CMakeLists.txt
@@ -17,3 +17,4 @@
 zephyr_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ      intc_vexriscv_litex.c)
 zephyr_sources_ifdef(CONFIG_SWERV_PIC               intc_swerv_pic.c)
 zephyr_sources_ifdef(CONFIG_NPCX_MIWU               intc_miwu.c)
+zephyr_sources_ifdef(CONFIG_LEON_IRQMP              intc_irqmp.c)
diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig
index ec3084c..6ab2084 100644
--- a/drivers/interrupt_controller/Kconfig
+++ b/drivers/interrupt_controller/Kconfig
@@ -39,6 +39,13 @@
 	help
 	  IRQ implementation for LiteX VexRiscv
 
+config LEON_IRQMP
+	bool "GRLIB IRQMP interrupt controller"
+	default y
+	depends on SOC_SPARC_LEON
+	help
+	  GRLIB IRQMP and IRQAMP
+
 source "drivers/interrupt_controller/Kconfig.multilevel"
 
 source "drivers/interrupt_controller/Kconfig.loapic"
diff --git a/drivers/interrupt_controller/intc_irqmp.c b/drivers/interrupt_controller/intc_irqmp.c
new file mode 100644
index 0000000..30faa4e
--- /dev/null
+++ b/drivers/interrupt_controller/intc_irqmp.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019-2020 Cobham Gaisler AB
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This is a driver for the GRLIB IRQMP interrupt controller common in LEON
+ * systems.
+ *
+ * Interrupt level 1..15 are SPARC interrupts. Interrupt level 16..31, if
+ * implemented in the interrupt controller, are IRQMP "extended interrupts".
+ *
+ * For more information about IRQMP, see the GRLIB IP Core User's Manual.
+ */
+
+#define DT_DRV_COMPAT gaisler_irqmp
+
+#include <kernel.h>
+#include <init.h>
+
+/*
+ * Register description for IRQMP and IRQAMP interrupt controllers
+ * IRQMP      - Multiprocessor Interrupt Controller
+ * IRQ(A)MP   - Multiprocessor Interrupt Controller with extended ASMP support
+ */
+#define IRQMP_NCPU_MAX 16
+struct irqmp_regs {
+	uint32_t ilevel;                                /* 0x00 */
+	uint32_t ipend;                                 /* 0x04 */
+	uint32_t iforce0;                               /* 0x08 */
+	uint32_t iclear;                                /* 0x0c */
+	uint32_t mpstat;                                /* 0x10 */
+	uint32_t brdlst;                                /* 0x14 */
+	uint32_t errstat;                               /* 0x18 */
+	uint32_t wdogctrl;                              /* 0x1c */
+	uint32_t asmpctrl;                              /* 0x20 */
+	uint32_t icselr[2];                             /* 0x24 */
+	uint32_t reserved2c;                            /* 0x2c */
+	uint32_t reserved30;                            /* 0x30 */
+	uint32_t reserved34;                            /* 0x34 */
+	uint32_t reserved38;                            /* 0x38 */
+	uint32_t reserved3c;                            /* 0x3c */
+	uint32_t pimask[IRQMP_NCPU_MAX];                /* 0x40 */
+	uint32_t piforce[IRQMP_NCPU_MAX];               /* 0x80 */
+	uint32_t pextack[IRQMP_NCPU_MAX];               /* 0xc0 */
+};
+
+#define IRQMP_PEXTACK_EID       (0x1f << 0)
+
+static volatile struct irqmp_regs *get_irqmp_regs(void)
+{
+	return (struct irqmp_regs *) DT_INST_REG_ADDR(0);
+}
+
+static int get_irqmp_eirq(void)
+{
+	return DT_INST_PROP(0, eirq);
+}
+
+void arch_irq_enable(unsigned int source)
+{
+	volatile struct irqmp_regs *regs = get_irqmp_regs();
+	volatile uint32_t *pimask = &regs->pimask[0];
+	const uint32_t setbit = (1U << source);
+	unsigned int key;
+
+	key = arch_irq_lock();
+	*pimask |= setbit;
+	arch_irq_unlock(key);
+}
+
+void arch_irq_disable(unsigned int source)
+{
+	volatile struct irqmp_regs *regs = get_irqmp_regs();
+	volatile uint32_t *pimask = &regs->pimask[0];
+	const uint32_t keepbits = ~(1U << source);
+	unsigned int key;
+
+	key = arch_irq_lock();
+	*pimask &= keepbits;
+	arch_irq_unlock(key);
+}
+
+int arch_irq_is_enabled(unsigned int source)
+{
+	volatile struct irqmp_regs *regs = get_irqmp_regs();
+	volatile uint32_t *pimask = &regs->pimask[0];
+
+	return !!(*pimask & (1U << source));
+}
+
+int z_sparc_int_get_source(int irl)
+{
+	volatile struct irqmp_regs *regs = get_irqmp_regs();
+	const int eirq = get_irqmp_eirq();
+	int source;
+
+	if ((eirq != 0) && (irl == eirq)) {
+		source = regs->pextack[0] & IRQMP_PEXTACK_EID;
+		if (source == 0) {
+			source = irl;
+		}
+	} else {
+		source = irl;
+	}
+
+	return source;
+}
+
+static int irqmp_init(const struct device *dev)
+{
+	ARG_UNUSED(dev);
+	volatile struct irqmp_regs *regs = get_irqmp_regs();
+
+	regs->ilevel = 0;
+	regs->ipend = 0;
+	regs->iforce0 = 0;
+	regs->pimask[0] = 0;
+	regs->piforce[0] = 0xfffe0000;
+
+	return 0;
+}
+
+SYS_INIT(irqmp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
diff --git a/dts/bindings/interrupt-controller/gaisler,irqmp.yaml b/dts/bindings/interrupt-controller/gaisler,irqmp.yaml
new file mode 100644
index 0000000..270431e
--- /dev/null
+++ b/dts/bindings/interrupt-controller/gaisler,irqmp.yaml
@@ -0,0 +1,23 @@
+# Copyright (c) 2020 Cobham Gaisler AB
+# SPDX-License-Identifier: Apache-2.0
+
+description: GRLIB Multiprocessor Interrupt Controller
+
+compatible: "gaisler,irqmp"
+
+include: [interrupt-controller.yaml, base.yaml]
+
+properties:
+    reg:
+      required: true
+
+    eirq:
+      type: int
+      default: 0
+      description: Extended interrupt number (or 0 for none)
+
+    "#interrupt-cells":
+      const: 1
+
+interrupt-cells:
+  - irq