From 364ad245a24efce0732245f050a80b9b702fc7b2 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 26 Mar 2020 11:57:43 +0000 Subject: [PATCH] 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 --- common/fdt_wrappers.c | 50 +++++++++++++++++++ include/common/fdt_wrappers.h | 2 + .../board/fvp/fconf/fconf_hw_config_getter.c | 29 ++++++----- .../fvp/include/fconf_hw_config_getter.h | 4 +- plat/arm/board/fvp/jmptbl.i | 3 ++ plat/arm/board/juno/jmptbl.i | 1 + 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c index 57e3bcd40..842d71339 100644 --- a/common/fdt_wrappers.c +++ b/common/fdt_wrappers.c @@ -226,3 +226,53 @@ int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop, 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; +} diff --git a/include/common/fdt_wrappers.h b/include/common/fdt_wrappers.h index 852fe1bf8..7a6b59893 100644 --- a/include/common/fdt_wrappers.h +++ b/include/common/fdt_wrappers.h @@ -28,5 +28,7 @@ int fdtw_read_bytes(const void *dtb, int node, const char *prop, unsigned int length, void *value); int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop, unsigned int length, const void *data); +int fdt_get_reg_props_by_index(const void *dtb, int node, int index, + uintptr_t *base, size_t *size); #endif /* FDT_WRAPPERS_H */ diff --git a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c index 44e9d0135..f1d9b93f7 100644 --- a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c +++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c @@ -18,7 +18,7 @@ int fconf_populate_gicv3_config(uintptr_t config) { int err; int node; - uint32_t addr[20]; + uintptr_t addr; /* Necessary to work with libfdt APIs */ const void *hw_config_dtb = (const void *)config; @@ -33,19 +33,24 @@ int fconf_populate_gicv3_config(uintptr_t config) WARN("FCONF: Unable to locate node with arm,gic-v3 compatible property\n"); return 0; } - /* Read the reg cell holding base address of GIC controller modules - A sample reg cell array is shown here: - reg = <0x0 0x2f000000 0 0x10000>, // GICD - <0x0 0x2f100000 0 0x200000>, // GICR - <0x0 0x2c000000 0 0x2000>, // GICC - <0x0 0x2c010000 0 0x2000>, // GICH - <0x0 0x2c02f000 0 0x2000>; // GICV - */ - - err = fdt_read_uint32_array(hw_config_dtb, node, "reg", 20, addr); + /* The GICv3 DT binding holds at least two address/size pairs, + * the first describing the distributor, the second the redistributors. + * See: bindings/interrupt-controller/arm,gic-v3.yaml + */ + err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL); if (err < 0) { - ERROR("FCONF: Failed to read reg property of GIC node\n"); + ERROR("FCONF: Failed to read GICD reg property of GIC node\n"); + return err; } + gicv3_config.gicd_base = addr; + + err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL); + if (err < 0) { + ERROR("FCONF: Failed to read GICR reg property of GIC node\n"); + } else { + gicv3_config.gicr_base = addr; + } + return err; } diff --git a/plat/arm/board/fvp/include/fconf_hw_config_getter.h b/plat/arm/board/fvp/include/fconf_hw_config_getter.h index cab832f68..a9e569e78 100644 --- a/plat/arm/board/fvp/include/fconf_hw_config_getter.h +++ b/plat/arm/board/fvp/include/fconf_hw_config_getter.h @@ -15,8 +15,8 @@ #define hw_config__topology_getter(prop) soc_topology.prop struct gicv3_config_t { - void *gicd_base; - void *gicr_base; + uintptr_t gicd_base; + uintptr_t gicr_base; }; struct hw_topology_t { diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i index 6469e2995..50a5ba4d9 100644 --- a/plat/arm/board/fvp/jmptbl.i +++ b/plat/arm/board/fvp/jmptbl.i @@ -25,6 +25,9 @@ fdt fdt_first_subnode fdt fdt_next_subnode fdt fdt_path_offset fdt fdt_subnode_offset +fdt fdt_address_cells +fdt fdt_size_cells +fdt fdt_parent_offset mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null diff --git a/plat/arm/board/juno/jmptbl.i b/plat/arm/board/juno/jmptbl.i index 66d6e4592..eb4399ec0 100644 --- a/plat/arm/board/juno/jmptbl.i +++ b/plat/arm/board/juno/jmptbl.i @@ -23,6 +23,7 @@ fdt fdt_node_offset_by_compatible fdt fdt_setprop_inplace_namelen_partial fdt fdt_first_subnode fdt fdt_next_subnode +fdt fdt_parent_offset mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null