diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index cc60af8..0762329 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -74,6 +74,7 @@ static struct {
     void __iomem * map_hbase; /* IO Address of virtual interface registers */
     paddr_t vbase;            /* Address of virtual cpu interface registers */
     spinlock_t lock;
+    struct dt_device_node *node;
 } gicv2;
 
 static struct gic_info gicv2_info;
@@ -560,8 +561,11 @@ static hw_irq_controller gicv2_guest_irq_type = {
     .set_affinity = gicv2_irq_set_affinity,
 };
 
+static int __init gicv2_init(void);
+
 const static struct gic_hw_operations gicv2_ops = {
     .info                = &gicv2_info,
+    .init                = gicv2_init,
     .secondary_init      = gicv2_secondary_cpu_init,
     .save_state          = gicv2_save_state,
     .restore_state       = gicv2_restore_state,
@@ -585,11 +589,20 @@ const static struct gic_hw_operations gicv2_ops = {
 };
 
 /* Set up the GIC */
-static int __init gicv2_init(struct dt_device_node *node, const void *data)
+static int __init gicv2_preinit(struct dt_device_node *node, const void *data)
 {
-    int res;
+    gicv2_info.hw_version = GIC_V2;
+    gicv2_info.node = node;
+    register_gic_ops(&gicv2_ops);
+    dt_irq_xlate = gic_irq_xlate;
 
-    dt_device_set_used_by(node, DOMID_XEN);
+    return 0;
+}
+
+static int __init gicv2_init(void)
+{
+    int res;
+    const struct dt_device_node *node = gicv2_info.node;
 
     res = dt_device_get_address(node, 0, &gicv2.dbase, NULL);
     if ( res || !gicv2.dbase || (gicv2.dbase & ~PAGE_MASK) )
@@ -612,9 +625,6 @@ static int __init gicv2_init(struct dt_device_node *node, const void *data)
         panic("GICv2: Cannot find the maintenance IRQ");
     gicv2_info.maintenance_irq = res;
 
-    /* Set the GIC as the primary interrupt controller */
-    dt_interrupt_controller = node;
-
     /* TODO: Add check on distributor, cpu size */
 
     printk("GICv2 initialization:\n"
@@ -656,9 +666,6 @@ static int __init gicv2_init(struct dt_device_node *node, const void *data)
 
     spin_unlock(&gicv2.lock);
 
-    gicv2_info.hw_version = GIC_V2;
-    register_gic_ops(&gicv2_ops);
-
     return 0;
 }
 
@@ -671,7 +678,7 @@ static const char * const gicv2_dt_compat[] __initconst =
 
 DT_DEVICE_START(gicv2, "GICv2:", DEVICE_GIC)
         .compatible = gicv2_dt_compat,
-        .init = gicv2_init,
+        .init = gicv2_preinit,
 DT_DEVICE_END
 
 /*
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 83b004c..91552fb 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -161,8 +161,10 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
     return 0;
 }
 
-/* Set up the GIC */
-void __init gic_init(void)
+/* Find the interrupt controller and set up the callback to translate
+ * device tree IRQ.
+ */
+void __init gic_preinit(void)
 {
     int rc;
     struct dt_device_node *node;
@@ -187,6 +189,16 @@ void __init gic_init(void)
     if ( !num_gics )
         panic("Unable to find compatible GIC in the device tree");
 
+    /* Set the GIC as the primary interrupt controller */
+    dt_interrupt_controller = node;
+    dt_device_set_used_by(node, DOMID_XEN);
+}
+
+/* Set up the GIC */
+void __init gic_init(void)
+{
+    if ( gic_hw_ops->init() )
+        panic("Failed to initialize the GIC drivers");
     /* Clear LR mask for cpu0 */
     clear_cpu_lr_mask();
 }
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 78dc7f5..36104fc 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -692,10 +692,11 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     vm_init();
     dt_unflatten_host_device_tree();
-    dt_irq_xlate = gic_irq_xlate;
 
     init_IRQ();
 
+    gic_preinit();
+
     dt_uart_init();
     console_init_preirq();
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index ed610cb..fec57b5 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -209,6 +209,10 @@ extern void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq);
 
 /* Accept an interrupt from the GIC and dispatch its handler */
 extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
+/* Find the interrupt controller and set up the callback to translate
+ * device tree IRQ.
+ */
+extern void gic_preinit(void);
 /* Bring up the interrupt controller, and report # cpus attached */
 extern void gic_init(void);
 /* Bring up a secondary CPU's per-CPU GIC interface */
@@ -261,11 +265,15 @@ struct gic_info {
     uint8_t nr_lrs;
     /* Maintenance irq number */
     unsigned int maintenance_irq;
+    /* Pointer to the device tree node representing the interrupt controller */
+    const struct dt_device_node *node;
 };
 
 struct gic_hw_operations {
     /* Hold GIC HW information */
     const struct gic_info *info;
+    /* Initialize the GIC and the boot CPU */
+    int (*init)(void);
     /* Save GIC registers */
     void (*save_state)(struct vcpu *);
     /* Restore GIC registers */
