arm: fconf: Fix GICv3 dynamic configuration

At the moment the fconf_populate_gicv3_config() implementation is
somewhat incomplete: First it actually fails to store the retrieved
information (the local addr[] array is going nowhere), but also it makes
quite some assumptions about the device tree passed to it: it needs to
use two address-cells and two size-cells, and also requires all five
register regions to be specified, where actually only the first two
are mandatory according to the binding (and needed by our code).

Fix this by introducing a proper generic function to retrieve "reg"
property information from a DT node:
We retrieve the #address-cells and #size-cells properties from the
parent node, then use those to extract the right values from the "reg"
property. The function takes an index to select one region of a reg
property.

This is loosely based on the STM32 implementation using "reg-names",
which we will subsume in a follow-up patch.

Change-Id: Ia59bfdf80aea4e36876c7b6ed4d153e303f482e8
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c
index 57e3bcd..842d713 100644
--- a/common/fdt_wrappers.c
+++ b/common/fdt_wrappers.c
@@ -226,3 +226,53 @@
 
 	return err;
 }
+
+static uint64_t fdt_read_prop_cells(const fdt32_t *prop, int nr_cells)
+{
+	uint64_t reg = fdt32_to_cpu(prop[0]);
+
+	if (nr_cells > 1) {
+		reg = (reg << 32) | fdt32_to_cpu(prop[1]);
+	}
+
+	return reg;
+}
+
+int fdt_get_reg_props_by_index(const void *dtb, int node, int index,
+			       uintptr_t *base, size_t *size)
+{
+	const fdt32_t *prop;
+	int parent, len;
+	int ac, sc;
+	int cell;
+
+	parent = fdt_parent_offset(dtb, node);
+	if (parent < 0) {
+		return -FDT_ERR_BADOFFSET;
+	}
+
+	ac = fdt_address_cells(dtb, parent);
+	sc = fdt_size_cells(dtb, parent);
+
+	cell = index * (ac + sc);
+
+	prop = fdt_getprop(dtb, node, "reg", &len);
+	if (prop == NULL) {
+		WARN("Couldn't find \"reg\" property in dtb\n");
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	if (((cell + ac + sc) * (int)sizeof(uint32_t)) > len) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	if (base != NULL) {
+		*base = (uintptr_t)fdt_read_prop_cells(&prop[cell], ac);
+	}
+
+	if (size != NULL) {
+		*size = (size_t)fdt_read_prop_cells(&prop[cell + ac], sc);
+	}
+
+	return 0;
+}