Both the Raspberry Pi downstream kernel [1] and some userspace tools
[2] use the revision property to identify the board, and the latter
fails if it is absent. The firmware creates the /system node which is
not present in Linux DTS (mainline or vendor) for the Raspberry Pi
boards, so we need to do the same.

[1] 
https://github.com/raspberrypi/linux/blob/0f292fbb6346b05766152902076895558ac23f9a/arch/arm/mach-bcm/board_bcm2835.c#L23-L33
[2] 
https://github.com/jgarff/rpi_ws281x/blob/7fc0bf8b31d715bbecf28e852ede5aaa388180da/rpihw.c#L579

Signed-off-by: Fiona Klute <fiona.kl...@gmx.de>
Cc: Matthias Brugger <mbrug...@suse.com>
Cc: Peter Robinson <pbrobin...@gmail.com>
Cc: Tom Rini <tr...@konsulko.com>
---
I sent an RFC version of this patch [3] a while ago with the question
if there's a better way to create the /system node than creating a
temporary overlay. I didn't receive any response to that question, so
I guess not.

[3] https://lists.denx.de/pipermail/u-boot/2025-February/580364.html

 board/raspberrypi/rpi/rpi.c | 70 +++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 1b0b664fa2b..6545306f6da 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -562,6 +562,74 @@ int copy_property(void *dst, void *src, char *path, char 
*property)
        return fdt_setprop(dst, dst_offset, property, prop, len);
 }
 
+void copy_system_node(void *fdt, void *fw_fdt)
+{
+       void *fdt_copy = NULL;
+       const fdt32_t *prop;
+       char fdto[1024];
+       int src_offset;
+       u32 fdt_size;
+       int len;
+
+       /*
+        * If the firmware FDT does not have a /system node, there's
+        * nothing to do.
+        */
+       src_offset = fdt_path_offset(fw_fdt, "/system");
+       if (src_offset < 0)
+               return;
+
+       /* Create a temporary overlay that adds the /system node. */
+       if (fdt_create(fdto, sizeof(fdto)))
+               return;
+       if (fdt_finish_reservemap(fdto))
+               return;
+       if (fdt_begin_node(fdto, ""))
+               return;
+       if (fdt_begin_node(fdto, "fragment"))
+               return;
+       if (fdt_property_string(fdto, "target-path", "/"))
+               return;
+       if (fdt_begin_node(fdto, "__overlay__"))
+               return;
+       if (fdt_begin_node(fdto, "system"))
+               return;
+
+       prop = fdt_getprop(fw_fdt, src_offset, "linux,serial", &len);
+       if (prop)
+               fdt_property(fdto, "linux,serial", prop, len);
+       prop = fdt_getprop(fw_fdt, src_offset, "linux,revision", &len);
+       if (prop)
+               fdt_property(fdto, "linux,revision", prop, len);
+
+       if (fdt_end_node(fdto))
+               return;
+       if (fdt_end_node(fdto))
+               return;
+       if (fdt_end_node(fdto))
+               return;
+       if (fdt_end_node(fdto))
+               return;
+       if (fdt_finish(fdto))
+               return;
+
+       /*
+        * A failed overlay apply is destructive to the target, so use
+        * a temporary copy and replace the FDT if successful.
+        */
+       fdt_size = fdt_totalsize(fdt);
+       fdt_copy = malloc(fdt_size);
+       if (!fdt_copy)
+               return;
+       memcpy(fdt_copy, fdt, fdt_size);
+       if (fdt_overlay_apply_verbose(fdt_copy, fdto))
+               goto cleanup;
+       memcpy(fdt, fdt_copy, fdt_size);
+
+ cleanup:
+       free(fdt_copy);
+}
+
 /* Copy tweaks from the firmware dtb to the loaded dtb */
 void  update_fdt_from_fw(void *fdt, void *fw_fdt)
 {
@@ -572,6 +640,8 @@ void  update_fdt_from_fw(void *fdt, void *fw_fdt)
        /* The firmware provides a more precise model; so copy that */
        copy_property(fdt, fw_fdt, "/", "model");
 
+       copy_system_node(fdt, fw_fdt);
+
        /* memory reserve as suggested by the firmware */
        copy_property(fdt, fw_fdt, "/", "memreserve");
 
-- 
2.49.0

Reply via email to