aboutsummaryrefslogtreecommitdiff
path: root/common/fdt_fixup.c
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2020-08-24 18:28:44 +0100
committerAndre Przywara <andre.przywara@arm.com>2020-09-29 13:28:25 +0100
commit9f7bab42a103a44246116d89a3cca20ed935467c (patch)
tree00b8bcf90a3c7f05c058f743c8d970f0504729b1 /common/fdt_fixup.c
parent79d89e3da078fa0e169a47bcc360c5e3308cdf42 (diff)
downloadtrusted-firmware-a-9f7bab42a103a44246116d89a3cca20ed935467c.tar.gz
fdt: Add function to adjust GICv3 redistributor size
We now have code to detect the CPU topology at runtime, and can also populate the CPU nodes in a devicetree accordingly. This is used by the ARM FPGA port, for instance. But also a GICv3 compatible interrupt controller provides MMIO frames per core, so the size of this region needs to be adjusted in the DT, to match the number of cores as well. Provide a generic function to find the GICv3 interrupt controller in the DT, then adjust the "reg" entry to match the number of detected cores. Since the size of the GICR frame per cores differs between GICv4 and GICv3, this size is supplied as a parameter to the function. The caller should determine the applicable value by either hardcoding it or by observing GICR_TYPER.VLPIS. Change-Id: Ic2a6445c2c5381a36bf24263f52fcbefad378c05 Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Diffstat (limited to 'common/fdt_fixup.c')
-rw-r--r--common/fdt_fixup.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c
index 980e60d45b..a1604e74f7 100644
--- a/common/fdt_fixup.c
+++ b/common/fdt_fixup.c
@@ -377,3 +377,64 @@ int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
return offs;
}
+
+/**
+ * fdt_adjust_gic_redist() - Adjust GICv3 redistributor size
+ * @dtb: Pointer to the DT blob in memory
+ * @nr_cores: Number of CPU cores on this system.
+ * @gicr_frame_size: Size of the GICR frame per core
+ *
+ * On a GICv3 compatible interrupt controller, the redistributor provides
+ * a number of 64k pages per each supported core. So with a dynamic topology,
+ * this size cannot be known upfront and thus can't be hardcoded into the DTB.
+ *
+ * Find the DT node describing the GICv3 interrupt controller, and adjust
+ * the size of the redistributor to match the number of actual cores on
+ * this system.
+ * A GICv4 compatible redistributor uses four 64K pages per core, whereas GICs
+ * without support for direct injection of virtual interrupts use two 64K pages.
+ * The @gicr_frame_size parameter should be 262144 and 131072, respectively.
+ *
+ * Return: 0 on success, negative error value otherwise.
+ */
+int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
+ unsigned int gicr_frame_size)
+{
+ int offset = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-v3");
+ uint64_t redist_size_64;
+ uint32_t redist_size_32;
+ void *val;
+ int parent;
+ int ac, sc;
+
+ if (offset < 0) {
+ return offset;
+ }
+
+ parent = fdt_parent_offset(dtb, offset);
+ if (parent < 0) {
+ return parent;
+ }
+ ac = fdt_address_cells(dtb, parent);
+ sc = fdt_size_cells(dtb, parent);
+ if (ac < 0 || sc < 0) {
+ return -EINVAL;
+ }
+
+ if (sc == 1) {
+ redist_size_32 = cpu_to_fdt32(nr_cores * gicr_frame_size);
+ val = &redist_size_32;
+ } else {
+ redist_size_64 = cpu_to_fdt64(nr_cores * gicr_frame_size);
+ val = &redist_size_64;
+ }
+
+ /*
+ * The redistributor is described in the second "reg" entry.
+ * So we have to skip one address and one size cell, then another
+ * address cell to get to the second size cell.
+ */
+ return fdt_setprop_inplace_namelen_partial(dtb, offset, "reg", 3,
+ (ac + sc + ac) * 4,
+ val, sc * 4);
+}