]> xenbits.xensource.com Git - people/aperard/xen-arm.git/commitdiff
xen: get GIC addresses from DT
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>
Thu, 13 Dec 2012 11:44:00 +0000 (11:44 +0000)
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>
Thu, 13 Dec 2012 11:44:00 +0000 (11:44 +0000)
Get the address of the GIC distributor, cpu, virtual and virtual cpu
interfaces registers from device tree.

Note: I couldn't completely get rid of GIC_BASE_ADDRESS, GIC_DR_OFFSET
and friends because we are using them from mode_switch.S, that is
executed before device tree has been parsed. But at least mode_switch.S
is known to contain vexpress specific code anyway.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
xen/arch/arm/gic.c
xen/common/device_tree.c
xen/include/xen/device_tree.h

index 0c6fab915107b031bb96f78965b756fd99279bad..ba76715192385b88b1665137b805313f224290ed 100644 (file)
@@ -26,6 +26,7 @@
 #include <xen/errno.h>
 #include <xen/softirq.h>
 #include <xen/list.h>
+#include <xen/device_tree.h>
 #include <asm/p2m.h>
 #include <asm/domain.h>
 
 
 /* Access to the GIC Distributor registers through the fixmap */
 #define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
-#define GICC ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICC1)  \
-                                     + (GIC_CR_OFFSET & 0xfff)))
-#define GICH ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICH)  \
-                                     + (GIC_HR_OFFSET & 0xfff)))
+#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
+#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH))
 static void gic_restore_pending_irqs(struct vcpu *v);
 
 /* Global state */
@@ -44,6 +43,7 @@ static struct {
     paddr_t dbase;       /* Address of distributor registers */
     paddr_t cbase;       /* Address of CPU interface registers */
     paddr_t hbase;       /* Address of virtual interface registers */
+    paddr_t vbase;       /* Address of virtual cpu interface registers */
     unsigned int lines;
     unsigned int cpus;
     spinlock_t lock;
@@ -306,10 +306,28 @@ static void __cpuinit gic_hyp_disable(void)
 /* Set up the GIC */
 void __init gic_init(void)
 {
-    /* XXX FIXME get this from devicetree */
-    gic.dbase = GIC_BASE_ADDRESS + GIC_DR_OFFSET;
-    gic.cbase = GIC_BASE_ADDRESS + GIC_CR_OFFSET;
-    gic.hbase = GIC_BASE_ADDRESS + GIC_HR_OFFSET;
+    printk("GIC initialization:\n"
+              "        gic_dist_addr=%"PRIpaddr"\n"
+              "        gic_cpu_addr=%"PRIpaddr"\n"
+              "        gic_hyp_addr=%"PRIpaddr"\n"
+              "        gic_vcpu_addr=%"PRIpaddr"\n",
+              early_info.gic.gic_dist_addr, early_info.gic.gic_cpu_addr,
+              early_info.gic.gic_hyp_addr, early_info.gic.gic_vcpu_addr);
+    if ( !early_info.gic.gic_dist_addr ||
+         !early_info.gic.gic_cpu_addr ||
+         !early_info.gic.gic_hyp_addr ||
+         !early_info.gic.gic_vcpu_addr )
+        panic("the physical address of one of the GIC interfaces is missing\n");
+    if ( (early_info.gic.gic_dist_addr & ~PAGE_MASK) ||
+         (early_info.gic.gic_cpu_addr & ~PAGE_MASK) ||
+         (early_info.gic.gic_hyp_addr & ~PAGE_MASK) ||
+         (early_info.gic.gic_vcpu_addr & ~PAGE_MASK) )
+        panic("GIC interfaces not page aligned.\n");
+
+    gic.dbase = early_info.gic.gic_dist_addr;
+    gic.cbase = early_info.gic.gic_cpu_addr;
+    gic.hbase = early_info.gic.gic_hyp_addr;
+    gic.vbase = early_info.gic.gic_vcpu_addr;
     set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED);
     BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) !=
                  FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE);
@@ -569,9 +587,9 @@ int gicv_setup(struct domain *d)
 {
     /* map the gic virtual cpu interface in the gic cpu interface region of
      * the guest */
-    return map_mmio_regions(d, GIC_BASE_ADDRESS + GIC_CR_OFFSET,
-                        GIC_BASE_ADDRESS + GIC_CR_OFFSET + (2 * PAGE_SIZE) - 1,
-                        GIC_BASE_ADDRESS + GIC_VR_OFFSET);
+    return map_mmio_regions(d, gic.cbase,
+                        gic.cbase + (2 * PAGE_SIZE) - 1,
+                        gic.vbase);
 }
 
 static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
index da0af77d778c994b1cc0dde49733ceedc2388fed..7a072cb930ad57cf568138252beb2a9dbb54e19d 100644 (file)
@@ -54,6 +54,33 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match)
     return !strncmp(prop, match, len);
 }
 
+bool_t device_tree_node_compatible(const void *fdt, int node, const char *match)
+{
+    int len, l;
+    const void *prop;
+
+    prop = fdt_getprop(fdt, node, "compatible", &len);
+    if ( prop == NULL )
+        return 0;
+
+    while ( len > 0 ) {
+        if ( !strcmp(prop, match) )
+            return 1;
+        l = strlen(prop) + 1;
+        prop += l;
+        len -= l;
+    }
+
+    return 0;
+}
+
+static int device_tree_nr_reg_ranges(const struct fdt_property *prop,
+        u32 address_cells, u32 size_cells)
+{
+    u32 reg_cells = address_cells + size_cells;
+    return fdt32_to_cpu(prop->len) / (reg_cells * sizeof(u32));
+}
+
 static void __init get_val(const u32 **cell, u32 cells, u64 *val)
 {
     *val = 0;
@@ -209,7 +236,6 @@ static void __init process_memory_node(const void *fdt, int node,
                                        u32 address_cells, u32 size_cells)
 {
     const struct fdt_property *prop;
-    size_t reg_cells;
     int i;
     int banks;
     const u32 *cell;
@@ -230,8 +256,7 @@ static void __init process_memory_node(const void *fdt, int node,
     }
 
     cell = (const u32 *)prop->data;
-    reg_cells = address_cells + size_cells;
-    banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof(u32));
+    banks = device_tree_nr_reg_ranges(prop, address_cells, size_cells);
 
     for ( i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++ )
     {
@@ -270,6 +295,46 @@ static void __init process_cpu_node(const void *fdt, int node,
     cpumask_set_cpu(start, &cpu_possible_map);
 }
 
+static void __init process_gic_node(const void *fdt, int node,
+                                    const char *name,
+                                    u32 address_cells, u32 size_cells)
+{
+    const struct fdt_property *prop;
+    const u32 *cell;
+    paddr_t start, size;
+    int interfaces;
+
+    if ( address_cells < 1 || size_cells < 1 )
+    {
+        early_printk("fdt: node `%s': invalid #address-cells or #size-cells",
+                     name);
+        return;
+    }
+
+    prop = fdt_get_property(fdt, node, "reg", NULL);
+    if ( !prop )
+    {
+        early_printk("fdt: node `%s': missing `reg' property\n", name);
+        return;
+    }
+
+    cell = (const u32 *)prop->data;
+    interfaces = device_tree_nr_reg_ranges(prop, address_cells, size_cells);
+    if ( interfaces < 4 )
+    {
+        early_printk("fdt: node `%s': not enough ranges\n", name);
+        return;
+    }
+    device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
+    early_info.gic.gic_dist_addr = start;
+    device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
+    early_info.gic.gic_cpu_addr = start;
+    device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
+    early_info.gic.gic_hyp_addr = start;
+    device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
+    early_info.gic.gic_vcpu_addr = start;
+}
+
 static int __init early_scan_node(const void *fdt,
                                   int node, const char *name, int depth,
                                   u32 address_cells, u32 size_cells,
@@ -279,6 +344,8 @@ static int __init early_scan_node(const void *fdt,
         process_memory_node(fdt, node, name, address_cells, size_cells);
     else if ( device_tree_type_matches(fdt, node, "cpu") )
         process_cpu_node(fdt, node, name, address_cells, size_cells);
+    else if ( device_tree_node_compatible(fdt, node, "arm,cortex-a15-gic") )
+        process_gic_node(fdt, node, name, address_cells, size_cells);
 
     return 0;
 }
index 4d010c0c6a884b8d5008026c83bb56b31cbc06cc..a0e3a979224bdcde678cebe08d132f3c6a3f1680 100644 (file)
@@ -26,8 +26,16 @@ struct dt_mem_info {
     struct membank bank[NR_MEM_BANKS];
 };
 
+struct dt_gic_info {
+    paddr_t gic_dist_addr;
+    paddr_t gic_cpu_addr;
+    paddr_t gic_hyp_addr;
+    paddr_t gic_vcpu_addr;
+};
+
 struct dt_early_info {
     struct dt_mem_info mem;
+    struct dt_gic_info gic;
 };
 
 typedef int (*device_tree_node_func)(const void *fdt,