[PATCH] rpi: copy the eMMC controller configuration from firmware-supplied DT

Jian-Hong Pan jhp at endlessos.org
Wed Oct 26 09:13:02 CEST 2022


From: Ilya Katsnelson <me at 0upti.me>

The RPi firmware adjusts the onboard eMMC controller's DMA mapping
ranges of the FDT for each BCM2711 SoC revisions on the Pi 4 and RPi 400
automatically.

If the following kernel does not boot with the correct eMMC controller's
DMA mapping ranges, the system on the SD card will boot failed and show
these error messages:

mmc1: invalid bus width
mmc1: error -22 whilst initialising SD card

This patch carries the adjustment from RPi firmware to the new loaded
FDT for the following kernel.

Link: https://lists.denx.de/pipermail/u-boot/2021-September/462006.html
Fixed: https://bugzilla.kernel.org/show_bug.cgi?id=213753
Signed-off-by: Ilya Katsnelson <me at 0upti.me>
Signed-off-by: Jian-Hong Pan <jhp at endlessos.org>
---
The code of this patch comes from "[RFC PATCH] rpi: copy the EMMC
controller configuration from firmware-supplied DT" [1] basically.
I only add the message and some modifcation:

* Fix the build failed error:
board/raspberrypi/rpi/rpi.c: In function 'copy_emmc_config':
board/raspberrypi/rpi/rpi.c:553:9: warning: dereferencing 'void *' pointer
  553 |         *fw_value = fdt_getprop(fw_fdt, fw_emmc_node, "dma-ranges", &length);
      |         ^~~~~~~~~
board/raspberrypi/rpi/rpi.c:553:19: error: invalid use of void expression
  553 |         *fw_value = fdt_getprop(fw_fdt, fw_emmc_node, "dma-ranges", &length);
      |                   ^
make[1]: *** [scripts/Makefile.build:258: board/raspberrypi/rpi/rpi.o] Error 1

* Replace "EMMC" to "eMMC".

* Replace the printf with log_[levels].

So, I keep "Ilya Katsnelson <me at 0upti.me>" as the author.

[1]: https://lists.denx.de/pipermail/u-boot/2021-September/462006.html

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

diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 00afb352bd..d7ff8e269e 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -504,6 +504,67 @@ void *board_fdt_blob_setup(int *err)
 	return (void *)fw_dtb_pointer;
 }
 
+void copy_emmc_config(void *our_fdt)
+{
+	/*
+	 * As of 2021-09-28, the Pi 4 has two different revisions, one using a
+	 * B0 stepping of the BCM2711 SoC, and one using a C0 stepping.
+	 *
+	 * The two SoC versions have different, incompatible DMA mappings for
+	 * the on-board eMMC controller, which would normally make them require
+	 * two different DTs.
+	 *
+	 * Unfortunately for us, the different revisions don't actually _use_
+	 * different DTs - instead, the proprietary stage0 bootloader reads the DT,
+	 * patches it in-memory, then passes the corrected DT to the OS.
+	 *
+	 * In our case, the OS is actually U-Boot, and U-Boot can choose to
+	 * completely disregard the firmware-supplied DT and load a custom one
+	 * instead, which is used by, e.g., NixOS.
+	 *
+	 * When that happens, the DT patches applied by the firmware are also
+	 * thrown out, which leads to BCM2711C0 boards being unable to boot
+	 * due to them trying to use the hardcoded DMA mappings in the DT
+	 * (which are for the B0 revision).
+	 *
+	 * Work around that by manually copying the DMA region setup from the
+	 * firmware-provided DT into whatever DT we're actually being asked
+	 * to load.
+	 */
+	void *fw_fdt = (void *)fw_dtb_pointer;
+	int fw_emmc_node;
+	int our_emmc_node;
+	int length;
+	const void *fw_value;
+	int result;
+
+	fw_emmc_node = fdt_path_offset(fw_fdt, "emmc2bus");
+	if (fw_emmc_node < 0) {
+		log_info("RPi: Failed to find eMMC config in FW DT: %d\n", fw_emmc_node);
+		return;
+	}
+
+	our_emmc_node = fdt_path_offset(our_fdt, "emmc2bus");
+	if (our_emmc_node < 0) {
+		log_info("RPi: Failed to find eMMC config in our DT: %d\n", our_emmc_node);
+		return;
+	}
+
+	fw_value = fdt_getprop(fw_fdt, fw_emmc_node, "dma-ranges", &length);
+	if (!fw_value) {
+		log_info("RPi: Failed to get eMMC DMA ranges property from FW DT: %d\n", length);
+		return;
+	}
+
+	result = fdt_setprop(our_fdt, our_emmc_node, "dma-ranges", fw_value, length);
+	if (result != 0) {
+		log_warning("RPi: Failed to set eMMC DMA ranges property in our DT: %d\n", result);
+		return;
+	}
+
+	log_debug("RPi: successfully copied FW DT eMMC configuration to our DT!\n");
+}
+
 int ft_board_setup(void *blob, struct bd_info *bd)
 {
 	int node;
@@ -518,5 +579,7 @@ int ft_board_setup(void *blob, struct bd_info *bd)
 			   EFI_RESERVED_MEMORY_TYPE);
 #endif
 
+	copy_emmc_config(blob);
+
 	return 0;
 }
-- 
2.38.1



More information about the U-Boot mailing list