/memreserve/ 0x00001000 0x000ef000;    // ROM data
 /memreserve/ 0x000f0000 0x004cc000;    // reserved
 
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+
 / {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "mti,sead-3";
+       interrupt-parent = <&gic>;
 
        cpus {
                cpu@0 {
                device_type = "memory";
                reg = <0x0 0x08000000>;
        };
+
+       cpu_intc: interrupt-controller {
+               compatible = "mti,cpu-interrupt-controller";
+
+               interrupt-controller;
+               #interrupt-cells = <1>;
+       };
+
+       gic: interrupt-controller@1b1c0000 {
+               compatible = "mti,gic";
+               reg = <0x1b1c0000 0x20000>;
+
+               interrupt-controller;
+               #interrupt-cells = <3>;
+
+               /*
+                * Declare the interrupt-parent even though the mti,gic
+                * binding doesn't require it, such that the kernel can
+                * figure out that cpu_intc is the root interrupt
+                * controller & should be probed first.
+                */
+               interrupt-parent = <&cpu_intc>;
+
+               timer {
+                       compatible = "mti,gic-timer";
+                       interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
+               };
+       };
 };
 
--- /dev/null
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * 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.
+ */
+
+#ifndef __MIPS_SEAD3_DTSHIM_H__
+#define __MIPS_SEAD3_DTSHIM_H__
+
+#include <linux/init.h>
+
+#ifdef CONFIG_MIPS_SEAD3
+
+extern void __init *sead3_dt_shim(void *fdt);
+
+#else /* !CONFIG_MIPS_SEAD3 */
+
+static inline void *sead3_dt_shim(void *fdt)
+{
+       return fdt;
+}
+
+#endif /* !CONFIG_MIPS_SEAD3 */
+
+#endif /* __MIPS_SEAD3_DTSHIM_H__ */
 
 
 #include <linux/irqchip/mips-gic.h>
 
-/* SEAD-3 GIC address space definitions. */
-#define GIC_BASE_ADDR          0x1b1c0000
-#define GIC_ADDRSPACE_SZ       (128 * 1024)
-
 /* CPU interrupt offsets */
-#define CPU_INT_GIC            2
 #define CPU_INT_EHCI           2
 #define CPU_INT_UART0          4
 #define CPU_INT_UART1          4
 
 #
 obj-y := sead3-lcd.o
 obj-y += sead3-display.o
+obj-y += sead3-dtshim.o
 obj-y += sead3-init.o
 obj-y += sead3-int.o
 obj-y += sead3-platform.o
 
--- /dev/null
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "sead3-dtshim: " fmt
+
+#include <linux/errno.h>
+#include <linux/libfdt.h>
+#include <linux/printk.h>
+
+#include <asm/io.h>
+
+#define SEAD_CONFIG                    CKSEG1ADDR(0x1b100110)
+#define SEAD_CONFIG_GIC_PRESENT                BIT(1)
+
+static unsigned char fdt_buf[16 << 10] __initdata;
+
+static int remove_gic(void *fdt)
+{
+       int gic_off, cpu_off, err;
+       uint32_t cfg, cpu_phandle;
+
+       /* leave the GIC node intact if a GIC is present */
+       cfg = __raw_readl((uint32_t *)SEAD_CONFIG);
+       if (cfg & SEAD_CONFIG_GIC_PRESENT)
+               return 0;
+
+       gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
+       if (gic_off < 0) {
+               pr_err("unable to find DT GIC node: %d\n", gic_off);
+               return gic_off;
+       }
+
+       err = fdt_nop_node(fdt, gic_off);
+       if (err) {
+               pr_err("unable to nop GIC node\n");
+               return err;
+       }
+
+       cpu_off = fdt_node_offset_by_compatible(fdt, -1,
+                       "mti,cpu-interrupt-controller");
+       if (cpu_off < 0) {
+               pr_err("unable to find CPU intc node: %d\n", cpu_off);
+               return cpu_off;
+       }
+
+       cpu_phandle = fdt_get_phandle(fdt, cpu_off);
+       if (!cpu_phandle) {
+               pr_err("unable to get CPU intc phandle\n");
+               return -EINVAL;
+       }
+
+       err = fdt_setprop_u32(fdt, 0, "interrupt-parent", cpu_phandle);
+       if (err) {
+               pr_err("unable to set root interrupt-parent: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+void __init *sead3_dt_shim(void *fdt)
+{
+       int err;
+
+       if (fdt_check_header(fdt))
+               panic("Corrupt DT");
+
+       /* if this isn't SEAD3, leave the DT alone */
+       if (fdt_node_check_compatible(fdt, 0, "mti,sead-3"))
+               return fdt;
+
+       err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
+       if (err)
+               panic("Unable to open FDT: %d", err);
+
+       err = remove_gic(fdt_buf);
+       if (err)
+               panic("Unable to patch FDT: %d", err);
+
+       err = fdt_pack(fdt_buf);
+       if (err)
+               panic("Unable to pack FDT: %d\n", err);
+
+       return fdt_buf;
+}
 
  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
  */
 #include <linux/init.h>
-#include <linux/irq.h>
+#include <linux/irqchip.h>
 #include <linux/irqchip/mips-gic.h>
-#include <linux/io.h>
 
-#include <asm/irq_cpu.h>
-#include <asm/setup.h>
-
-#include <asm/mips-boards/sead3int.h>
-
-#define SEAD_CONFIG_GIC_PRESENT_SHF    1
-#define SEAD_CONFIG_GIC_PRESENT_MSK    (1 << SEAD_CONFIG_GIC_PRESENT_SHF)
-#define SEAD_CONFIG_BASE               0x1b100110
-#define SEAD_CONFIG_SIZE               4
-
-static void __iomem *sead3_config_reg;
+#include <asm/cpu-info.h>
+#include <asm/irq.h>
 
 void __init arch_init_irq(void)
 {
-       if (!cpu_has_veic)
-               mips_cpu_irq_init();
+       irqchip_init();
 
-       sead3_config_reg = ioremap_nocache(SEAD_CONFIG_BASE, SEAD_CONFIG_SIZE);
-       gic_present = (__raw_readl(sead3_config_reg) &
-                      SEAD_CONFIG_GIC_PRESENT_MSK) >>
-               SEAD_CONFIG_GIC_PRESENT_SHF;
        pr_info("GIC: %spresent\n", (gic_present) ? "" : "not ");
        pr_info("EIC: %s\n",
                (current_cpu_data.options & MIPS_CPU_VEIC) ?  "on" : "off");
-
-       if (gic_present)
-               gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC,
-                        MIPS_GIC_IRQ_BASE);
 }
 
 
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/irqchip/mips-gic.h>
+#include <linux/irqdomain.h>
 #include <linux/leds.h>
 #include <linux/mtd/physmap.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/smsc911x.h>
 
 static int __init sead3_platforms_device_init(void)
 {
+       const char *intc_compat;
+       struct device_node *node;
+       struct irq_domain *irqd;
+
+       if (gic_present)
+               intc_compat = "mti,gic";
+       else
+               intc_compat = "mti,cpu-interrupt-controller";
+
+       node = of_find_compatible_node(NULL, NULL, intc_compat);
+       if (!node) {
+               pr_err("unable to find interrupt controller DT node\n");
+               return -ENODEV;
+       }
+
+       irqd = irq_find_host(node);
+       if (!irqd) {
+               pr_err("unable to find interrupt controller IRQ domain\n");
+               return -ENODEV;
+       }
+
        if (gic_present) {
-               uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0;
-               uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1;
-               ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI;
-               sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET;
+               uart8250_data[0].irq = irq_create_mapping(irqd, GIC_INT_UART0);
+               uart8250_data[1].irq = irq_create_mapping(irqd, GIC_INT_UART1);
+               ehci_resources[1].start =
+                       irq_create_mapping(irqd, GIC_INT_EHCI);
+               sead3_net_resources[1].start =
+                       irq_create_mapping(irqd, GIC_INT_NET);
        } else {
-               uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0;
-               uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1;
-               ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI;
-               sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET;
+               uart8250_data[0].irq = irq_create_mapping(irqd, CPU_INT_UART0);
+               uart8250_data[1].irq = irq_create_mapping(irqd, CPU_INT_UART1);
+               ehci_resources[1].start =
+                       irq_create_mapping(irqd, CPU_INT_EHCI);
+               sead3_net_resources[1].start =
+                       irq_create_mapping(irqd, CPU_INT_NET);
        }
 
        return platform_add_devices(sead3_platform_devices,
 
 #include <asm/prom.h>
 #include <asm/fw/fw.h>
 
+#include <asm/mach-sead3/sead3-dtshim.h>
 #include <asm/mips-boards/generic.h>
 
 const char *get_system_type(void)
 
 void __init plat_mem_setup(void)
 {
+       void *fdt = plat_get_fdt();
+
        /* allow command line/bootloader env to override memory size in DT */
        parse_memsize_param();
 
-       /*
-        * Load the builtin devicetree. This causes the chosen node to be
-        * parsed resulting in our memory appearing
-        */
-       __dt_setup_arch(__dtb_start);
+       fdt = sead3_dt_shim(fdt);
+       __dt_setup_arch(fdt);
 }
 
 void __init device_tree_init(void)
 {
-       if (!initial_boot_params)
-               return;
-
        unflatten_and_copy_device_tree();
 }