fdt: Use proper #address-cells and #size-cells for reserved-memory

The devicetree binding document[1] for the /reserved-memory node demands
that the number of address and size-cells in the reserved-memory node
must match those values in the root node. So far we were forcing a
64-bit address along with a 32-bit size.

Adjust the code to query the cells values from the root node, and
populate the newly created /reserved-memory node accordingly.

This fixes the fdt_add_reserved_memory() function when called on a
devicetree which does not use the 2/1 pair. Linux is picky about this
and will bail out the parsing routine, effectively ignoring the
reserved-memory node:
[    0.000000] OF: fdt: Reserved memory: unsupported node format, ignoring

[1] Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
    in the Linux kernel source tree

Change-Id: Ie126ebab4f3fedd48e12c9ed4bd8fa123acc86d3
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
This commit is contained in:
Andre Przywara 2021-01-17 02:11:32 +00:00 committed by André Przywara
parent 9e28b85444
commit 81146c46f6
1 changed files with 24 additions and 8 deletions

View File

@ -188,6 +188,8 @@ int dt_add_psci_cpu_enable_methods(void *fdt)
*
* See reserved-memory/reserved-memory.txt in the (Linux kernel) DT binding
* documentation for details.
* According to this binding, the address-cells and size-cells must match
* those of the root node.
*
* Return: 0 on success, a negative error value otherwise.
******************************************************************************/
@ -195,23 +197,37 @@ int fdt_add_reserved_memory(void *dtb, const char *node_name,
uintptr_t base, size_t size)
{
int offs = fdt_path_offset(dtb, "/reserved-memory");
uint32_t addresses[3];
uint32_t addresses[4];
int ac, sc;
unsigned int idx = 0;
ac = fdt_address_cells(dtb, 0);
sc = fdt_size_cells(dtb, 0);
if (offs < 0) { /* create if not existing yet */
offs = fdt_add_subnode(dtb, 0, "reserved-memory");
if (offs < 0)
if (offs < 0) {
return offs;
fdt_setprop_u32(dtb, offs, "#address-cells", 2);
fdt_setprop_u32(dtb, offs, "#size-cells", 1);
}
fdt_setprop_u32(dtb, offs, "#address-cells", ac);
fdt_setprop_u32(dtb, offs, "#size-cells", sc);
fdt_setprop(dtb, offs, "ranges", NULL, 0);
}
addresses[0] = cpu_to_fdt32(HIGH_BITS(base));
addresses[1] = cpu_to_fdt32(base & 0xffffffff);
addresses[2] = cpu_to_fdt32(size & 0xffffffff);
if (ac > 1) {
addresses[idx] = cpu_to_fdt32(HIGH_BITS(base));
idx++;
}
addresses[idx] = cpu_to_fdt32(base & 0xffffffff);
idx++;
if (sc > 1) {
addresses[idx] = cpu_to_fdt32(HIGH_BITS(size));
idx++;
}
addresses[idx] = cpu_to_fdt32(size & 0xffffffff);
idx++;
offs = fdt_add_subnode(dtb, offs, node_name);
fdt_setprop(dtb, offs, "no-map", NULL, 0);
fdt_setprop(dtb, offs, "reg", addresses, 12);
fdt_setprop(dtb, offs, "reg", addresses, idx * sizeof(uint32_t));
return 0;
}