aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/device_tree.c
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2012-12-13 11:44:00 +0000
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>2012-12-13 11:44:00 +0000
commit01dedfbcdfbcbdf15ac3d60edc2d15536f999349 (patch)
treefb1a529b97f2abb0eeff9ea24d2ece619de99968 /xen/common/device_tree.c
parentd27df538094f2fc5188de0b66538eaf3e3e85fad (diff)
downloadxen-01dedfbcdfbcbdf15ac3d60edc2d15536f999349.tar.gz
xen-01dedfbcdfbcbdf15ac3d60edc2d15536f999349.tar.bz2
xen-01dedfbcdfbcbdf15ac3d60edc2d15536f999349.zip
xen: get GIC addresses from DT
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>
Diffstat (limited to 'xen/common/device_tree.c')
-rw-r--r--xen/common/device_tree.c73
1 files changed, 70 insertions, 3 deletions
diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index da0af77d77..7a072cb930 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -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;
}