v4.19.13 snapshot.
diff --git a/arch/arm/mach-imx/avic.c b/arch/arm/mach-imx/avic.c
new file mode 100644
index 0000000..c0434a3
--- /dev/null
+++ b/arch/arm/mach-imx/avic.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <asm/mach/irq.h>
+#include <asm/exception.h>
+
+#include "common.h"
+#include "hardware.h"
+#include "irq-common.h"
+
+#define AVIC_INTCNTL		0x00	/* int control reg */
+#define AVIC_NIMASK		0x04	/* int mask reg */
+#define AVIC_INTENNUM		0x08	/* int enable number reg */
+#define AVIC_INTDISNUM		0x0C	/* int disable number reg */
+#define AVIC_INTENABLEH		0x10	/* int enable reg high */
+#define AVIC_INTENABLEL		0x14	/* int enable reg low */
+#define AVIC_INTTYPEH		0x18	/* int type reg high */
+#define AVIC_INTTYPEL		0x1C	/* int type reg low */
+#define AVIC_NIPRIORITY(x)	(0x20 + 4 * (7 - (x))) /* int priority */
+#define AVIC_NIVECSR		0x40	/* norm int vector/status */
+#define AVIC_FIVECSR		0x44	/* fast int vector/status */
+#define AVIC_INTSRCH		0x48	/* int source reg high */
+#define AVIC_INTSRCL		0x4C	/* int source reg low */
+#define AVIC_INTFRCH		0x50	/* int force reg high */
+#define AVIC_INTFRCL		0x54	/* int force reg low */
+#define AVIC_NIPNDH		0x58	/* norm int pending high */
+#define AVIC_NIPNDL		0x5C	/* norm int pending low */
+#define AVIC_FIPNDH		0x60	/* fast int pending high */
+#define AVIC_FIPNDL		0x64	/* fast int pending low */
+
+#define AVIC_NUM_IRQS 64
+
+/* low power interrupt mask registers */
+#define MX25_CCM_LPIMR0	0x68
+#define MX25_CCM_LPIMR1	0x6C
+
+static void __iomem *avic_base;
+static void __iomem *mx25_ccm_base;
+static struct irq_domain *domain;
+
+#ifdef CONFIG_FIQ
+static int avic_set_irq_fiq(unsigned int hwirq, unsigned int type)
+{
+	unsigned int irqt;
+
+	if (hwirq >= AVIC_NUM_IRQS)
+		return -EINVAL;
+
+	if (hwirq < AVIC_NUM_IRQS / 2) {
+		irqt = imx_readl(avic_base + AVIC_INTTYPEL) & ~(1 << hwirq);
+		imx_writel(irqt | (!!type << hwirq), avic_base + AVIC_INTTYPEL);
+	} else {
+		hwirq -= AVIC_NUM_IRQS / 2;
+		irqt = imx_readl(avic_base + AVIC_INTTYPEH) & ~(1 << hwirq);
+		imx_writel(irqt | (!!type << hwirq), avic_base + AVIC_INTTYPEH);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_FIQ */
+
+
+static struct mxc_extra_irq avic_extra_irq = {
+#ifdef CONFIG_FIQ
+	.set_irq_fiq = avic_set_irq_fiq,
+#endif
+};
+
+#ifdef CONFIG_PM
+static u32 avic_saved_mask_reg[2];
+
+static void avic_irq_suspend(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = gc->chip_types;
+	int idx = d->hwirq >> 5;
+
+	avic_saved_mask_reg[idx] = imx_readl(avic_base + ct->regs.mask);
+	imx_writel(gc->wake_active, avic_base + ct->regs.mask);
+
+	if (mx25_ccm_base) {
+		u8 offs = d->hwirq < AVIC_NUM_IRQS / 2 ?
+			MX25_CCM_LPIMR0 : MX25_CCM_LPIMR1;
+		/*
+		 * The interrupts which are still enabled will be used as wakeup
+		 * sources. Allow those interrupts in low-power mode.
+		 * The LPIMR registers use 0 to allow an interrupt, the AVIC
+		 * registers use 1.
+		 */
+		imx_writel(~gc->wake_active, mx25_ccm_base + offs);
+	}
+}
+
+static void avic_irq_resume(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = gc->chip_types;
+	int idx = d->hwirq >> 5;
+
+	imx_writel(avic_saved_mask_reg[idx], avic_base + ct->regs.mask);
+
+	if (mx25_ccm_base) {
+		u8 offs = d->hwirq < AVIC_NUM_IRQS / 2 ?
+			MX25_CCM_LPIMR0 : MX25_CCM_LPIMR1;
+
+		imx_writel(0xffffffff, mx25_ccm_base + offs);
+	}
+}
+
+#else
+#define avic_irq_suspend NULL
+#define avic_irq_resume NULL
+#endif
+
+static __init void avic_init_gc(int idx, unsigned int irq_start)
+{
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+
+	gc = irq_alloc_generic_chip("mxc-avic", 1, irq_start, avic_base,
+				    handle_level_irq);
+	gc->private = &avic_extra_irq;
+	gc->wake_enabled = IRQ_MSK(32);
+
+	ct = gc->chip_types;
+	ct->chip.irq_mask = irq_gc_mask_clr_bit;
+	ct->chip.irq_unmask = irq_gc_mask_set_bit;
+	ct->chip.irq_ack = irq_gc_mask_clr_bit;
+	ct->chip.irq_set_wake = irq_gc_set_wake;
+	ct->chip.irq_suspend = avic_irq_suspend;
+	ct->chip.irq_resume = avic_irq_resume;
+	ct->regs.mask = !idx ? AVIC_INTENABLEL : AVIC_INTENABLEH;
+	ct->regs.ack = ct->regs.mask;
+
+	irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0);
+}
+
+static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
+{
+	u32 nivector;
+
+	do {
+		nivector = imx_readl(avic_base + AVIC_NIVECSR) >> 16;
+		if (nivector == 0xffff)
+			break;
+
+		handle_domain_irq(domain, nivector, regs);
+	} while (1);
+}
+
+/*
+ * This function initializes the AVIC hardware and disables all the
+ * interrupts. It registers the interrupt enable and disable functions
+ * to the kernel for each interrupt source.
+ */
+void __init mxc_init_irq(void __iomem *irqbase)
+{
+	struct device_node *np;
+	int irq_base;
+	int i;
+
+	avic_base = irqbase;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx25-ccm");
+	mx25_ccm_base = of_iomap(np, 0);
+
+	if (mx25_ccm_base) {
+		/*
+		 * By default, we mask all interrupts. We set the actual mask
+		 * before we go into low-power mode.
+		 */
+		imx_writel(0xffffffff, mx25_ccm_base + MX25_CCM_LPIMR0);
+		imx_writel(0xffffffff, mx25_ccm_base + MX25_CCM_LPIMR1);
+	}
+
+	/* put the AVIC into the reset value with
+	 * all interrupts disabled
+	 */
+	imx_writel(0, avic_base + AVIC_INTCNTL);
+	imx_writel(0x1f, avic_base + AVIC_NIMASK);
+
+	/* disable all interrupts */
+	imx_writel(0, avic_base + AVIC_INTENABLEH);
+	imx_writel(0, avic_base + AVIC_INTENABLEL);
+
+	/* all IRQ no FIQ */
+	imx_writel(0, avic_base + AVIC_INTTYPEH);
+	imx_writel(0, avic_base + AVIC_INTTYPEL);
+
+	irq_base = irq_alloc_descs(-1, 0, AVIC_NUM_IRQS, numa_node_id());
+	WARN_ON(irq_base < 0);
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,avic");
+	domain = irq_domain_add_legacy(np, AVIC_NUM_IRQS, irq_base, 0,
+				       &irq_domain_simple_ops, NULL);
+	WARN_ON(!domain);
+
+	for (i = 0; i < AVIC_NUM_IRQS / 32; i++, irq_base += 32)
+		avic_init_gc(i, irq_base);
+
+	/* Set default priority value (0) for all IRQ's */
+	for (i = 0; i < 8; i++)
+		imx_writel(0, avic_base + AVIC_NIPRIORITY(i));
+
+	set_handle_irq(avic_handle_irq);
+
+#ifdef CONFIG_FIQ
+	/* Initialize FIQ */
+	init_FIQ(FIQ_START);
+#endif
+
+	printk(KERN_INFO "MXC IRQ initialized\n");
+}