summaryrefslogtreecommitdiff
path: root/drivers/irqchip/irq-ativic32.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 05:41:08 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 05:41:08 +0300
commitc9297d284126b80c9cfd72c690e0da531c99fc48 (patch)
treebec7ce343f2a37def4e99ec556deb3998dbeb041 /drivers/irqchip/irq-ativic32.c
parent17e3cd222af1c72a750cd83565bb8dfc7bc12335 (diff)
parent6fc61ee69433e7e0433cabd36f78bb5fb3b26524 (diff)
downloadlinux-c9297d284126b80c9cfd72c690e0da531c99fc48.tar.xz
Merge tag 'nds32-for-linus-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux
Pull nds32 architecture support from Greentime Hu: "This contains the core nds32 Linux port (including interrupt controller driver and timer driver), which has been through seven rounds of review on mailing list. It is able to boot to shell and passes most LTP-2017 testsuites in nds32 AE3XX platform: Total Tests: 1901 Total Skipped Tests: 618 Total Failures: 78" Reviewed-by: Arnd Bergmann <arnd@arndb.de> * tag 'nds32-for-linus-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux: (44 commits) nds32: To use the generic dump_stack() nds32: fix building failed if using elf toolchain. nios2: add ioremap_nocache declaration before include asm-generic/io.h. nds32: fix building failed if using older version gcc. dt-bindings: timer: Add andestech atcpit100 timer binding doc clocksource/drivers/atcpit100: VDSO support clocksource/drivers/atcpit100: Add andestech atcpit100 timer net: faraday add nds32 support. irqchip: Andestech Internal Vector Interrupt Controller driver dt-bindings: interrupt-controller: Andestech Internal Vector Interrupt Controller dt-bindings: nds32 SoC Bindings dt-bindings: nds32 L2 cache controller Bindings dt-bindings: nds32 CPU Bindings MAINTAINERS: Add nds32 nds32: Build infrastructure nds32: defconfig nds32: Miscellaneous header files nds32: Device tree support nds32: Generic timers support nds32: Loadable modules ...
Diffstat (limited to 'drivers/irqchip/irq-ativic32.c')
-rw-r--r--drivers/irqchip/irq-ativic32.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-ativic32.c b/drivers/irqchip/irq-ativic32.c
new file mode 100644
index 000000000000..f69a8588521c
--- /dev/null
+++ b/drivers/irqchip/irq-ativic32.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2005-2017 Andes Technology Corporation
+
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <nds32_intrinsic.h>
+
+static void ativic32_ack_irq(struct irq_data *data)
+{
+ __nds32__mtsr_dsb(BIT(data->hwirq), NDS32_SR_INT_PEND2);
+}
+
+static void ativic32_mask_irq(struct irq_data *data)
+{
+ unsigned long int_mask2 = __nds32__mfsr(NDS32_SR_INT_MASK2);
+ __nds32__mtsr_dsb(int_mask2 & (~(BIT(data->hwirq))), NDS32_SR_INT_MASK2);
+}
+
+static void ativic32_unmask_irq(struct irq_data *data)
+{
+ unsigned long int_mask2 = __nds32__mfsr(NDS32_SR_INT_MASK2);
+ __nds32__mtsr_dsb(int_mask2 | (BIT(data->hwirq)), NDS32_SR_INT_MASK2);
+}
+
+static struct irq_chip ativic32_chip = {
+ .name = "ativic32",
+ .irq_ack = ativic32_ack_irq,
+ .irq_mask = ativic32_mask_irq,
+ .irq_unmask = ativic32_unmask_irq,
+};
+
+static unsigned int __initdata nivic_map[6] = { 6, 2, 10, 16, 24, 32 };
+
+static struct irq_domain *root_domain;
+static int ativic32_irq_domain_map(struct irq_domain *id, unsigned int virq,
+ irq_hw_number_t hw)
+{
+
+ unsigned long int_trigger_type;
+ u32 type;
+ struct irq_data *irq_data;
+ int_trigger_type = __nds32__mfsr(NDS32_SR_INT_TRIGGER);
+ irq_data = irq_get_irq_data(virq);
+ if (!irq_data)
+ return -EINVAL;
+
+ if (int_trigger_type & (BIT(hw))) {
+ irq_set_chip_and_handler(virq, &ativic32_chip, handle_edge_irq);
+ type = IRQ_TYPE_EDGE_RISING;
+ } else {
+ irq_set_chip_and_handler(virq, &ativic32_chip, handle_level_irq);
+ type = IRQ_TYPE_LEVEL_HIGH;
+ }
+
+ irqd_set_trigger_type(irq_data, type);
+ return 0;
+}
+
+static struct irq_domain_ops ativic32_ops = {
+ .map = ativic32_irq_domain_map,
+ .xlate = irq_domain_xlate_onecell
+};
+
+static irq_hw_number_t get_intr_src(void)
+{
+ return ((__nds32__mfsr(NDS32_SR_ITYPE) & ITYPE_mskVECTOR) >> ITYPE_offVECTOR)
+ - NDS32_VECTOR_offINTERRUPT;
+}
+
+asmlinkage void asm_do_IRQ(struct pt_regs *regs)
+{
+ irq_hw_number_t hwirq = get_intr_src();
+ handle_domain_irq(root_domain, hwirq, regs);
+}
+
+int __init ativic32_init_irq(struct device_node *node, struct device_node *parent)
+{
+ unsigned long int_vec_base, nivic, nr_ints;
+
+ if (WARN(parent, "non-root ativic32 are not supported"))
+ return -EINVAL;
+
+ int_vec_base = __nds32__mfsr(NDS32_SR_IVB);
+
+ if (((int_vec_base & IVB_mskIVIC_VER) >> IVB_offIVIC_VER) == 0)
+ panic("Unable to use atcivic32 for this cpu.\n");
+
+ nivic = (int_vec_base & IVB_mskNIVIC) >> IVB_offNIVIC;
+ if (nivic >= ARRAY_SIZE(nivic_map))
+ panic("The number of input for ativic32 is not supported.\n");
+
+ nr_ints = nivic_map[nivic];
+
+ root_domain = irq_domain_add_linear(node, nr_ints,
+ &ativic32_ops, NULL);
+
+ if (!root_domain)
+ panic("%s: unable to create IRQ domain\n", node->full_name);
+
+ return 0;
+}
+IRQCHIP_DECLARE(ativic32, "andestech,ativic32", ativic32_init_irq);