#define RTL_ICTL_IRR2          0x10
 #define RTL_ICTL_IRR3          0x14
 
+#define RTL_ICTL_NUM_INPUTS    32
+
 #define REG(x)         (realtek_ictl_base + x)
 
 static DEFINE_RAW_SPINLOCK(irq_lock);
 static void __iomem *realtek_ictl_base;
 
+/*
+ * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
+ * placing IRQ 31 in the first four bits. A routing value of '0' means the
+ * interrupt is left disconnected. Routing values {1..15} connect to output
+ * lines {0..14}.
+ */
+#define IRR_OFFSET(idx)                (4 * (3 - (idx * 4) / 32))
+#define IRR_SHIFT(idx)         ((idx * 4) % 32)
+
+static void write_irr(void __iomem *irr0, int idx, u32 value)
+{
+       unsigned int offset = IRR_OFFSET(idx);
+       unsigned int shift = IRR_SHIFT(idx);
+       u32 irr;
+
+       irr = readl(irr0 + offset) & ~(0xf << shift);
+       irr |= (value & 0xf) << shift;
+       writel(irr, irr0 + offset);
+}
+
 static void realtek_ictl_unmask_irq(struct irq_data *i)
 {
        unsigned long flags;
 
 static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 {
+       unsigned long flags;
+
        irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
 
+       raw_spin_lock_irqsave(&irq_lock, flags);
+       write_irr(REG(RTL_ICTL_IRR0), hw, 1);
+       raw_spin_unlock_irqrestore(&irq_lock, flags);
+
        return 0;
 }
 
        chained_irq_exit(chip, desc);
 }
 
-/*
- * SoC interrupts are cascaded to MIPS CPU interrupts according to the
- * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
- * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
- * thus go into 4 IRRs. A routing value of '0' means the interrupt is left
- * disconnected. Routing values {1..15} connect to output lines {0..14}.
- */
-static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
-{
-       struct device_node *cpu_ictl;
-       const __be32 *imap;
-       u32 imaplen, soc_int, cpu_int, tmp, regs[4];
-       int ret, i, irr_regs[] = {
-               RTL_ICTL_IRR3,
-               RTL_ICTL_IRR2,
-               RTL_ICTL_IRR1,
-               RTL_ICTL_IRR0,
-       };
-       u8 mips_irqs_set;
-
-       ret = of_property_read_u32(node, "#address-cells", &tmp);
-       if (ret || tmp)
-               return -EINVAL;
-
-       imap = of_get_property(node, "interrupt-map", &imaplen);
-       if (!imap || imaplen % 3)
-               return -EINVAL;
-
-       mips_irqs_set = 0;
-       memset(regs, 0, sizeof(regs));
-       for (i = 0; i < imaplen; i += 3 * sizeof(u32)) {
-               soc_int = be32_to_cpup(imap);
-               if (soc_int > 31)
-                       return -EINVAL;
-
-               cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1));
-               if (!cpu_ictl)
-                       return -EINVAL;
-               ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp);
-               of_node_put(cpu_ictl);
-               if (ret || tmp != 1)
-                       return -EINVAL;
-
-               cpu_int = be32_to_cpup(imap + 2);
-               if (cpu_int > 7 || cpu_int < 2)
-                       return -EINVAL;
-
-               if (!(mips_irqs_set & BIT(cpu_int))) {
-                       irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch,
-                                                        domain);
-                       mips_irqs_set |= BIT(cpu_int);
-               }
-
-               /* Use routing values (1..6) for CPU interrupts (2..7) */
-               regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
-               imap += 3;
-       }
-
-       for (i = 0; i < 4; i++)
-               writel(regs[i], REG(irr_regs[i]));
-
-       return 0;
-}
-
 static int __init realtek_rtl_of_init(struct device_node *node, struct device_node *parent)
 {
+       struct of_phandle_args oirq;
        struct irq_domain *domain;
-       int ret;
+       unsigned int soc_irq;
+       int parent_irq;
 
        realtek_ictl_base = of_iomap(node, 0);
        if (!realtek_ictl_base)
                return -ENXIO;
 
-       /* Disable all cascaded interrupts */
+       /* Disable all cascaded interrupts and clear routing */
        writel(0, REG(RTL_ICTL_GIMR));
+       for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
+               write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0);
+
+       if (WARN_ON(!of_irq_count(node))) {
+               /*
+                * If DT contains no parent interrupts, assume MIPS CPU IRQ 2
+                * (HW0) is connected to the first output. This is the case for
+                * all known hardware anyway. "interrupt-map" is deprecated, so
+                * don't bother trying to parse that.
+                */
+               oirq.np = of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-controller");
+               oirq.args_count = 1;
+               oirq.args[0] = 2;
+
+               parent_irq = irq_create_of_mapping(&oirq);
+
+               of_node_put(oirq.np);
+       } else {
+               parent_irq = of_irq_get(node, 0);
+       }
 
-       domain = irq_domain_add_linear(node, 32, &irq_domain_ops, NULL);
+       if (parent_irq < 0)
+               return parent_irq;
+       else if (!parent_irq)
+               return -ENODEV;
 
-       ret = map_interrupts(node, domain);
-       if (ret) {
-               pr_err("invalid interrupt map\n");
-               return ret;
-       }
+       domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, NULL);
+       if (!domain)
+               return -ENOMEM;
+
+       irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, domain);
 
        return 0;
 }