Merge branch 'rpi-2023.04' of https://source.denx.de/u-boot/custodians/u-boot-raspberrypi

- Fixes for booting newer revs of the SoC in the Raspberry Pi 4
- Propagate some firmware DT properties to the loaded DT
- Update the Zero2W upstream DT name
diff --git a/arch/arm/mach-bcm283x/include/mach/mbox.h b/arch/arm/mach-bcm283x/include/mach/mbox.h
index 2ae2d3d..490664f 100644
--- a/arch/arm/mach-bcm283x/include/mach/mbox.h
+++ b/arch/arm/mach-bcm283x/include/mach/mbox.h
@@ -224,6 +224,8 @@
 };
 
 #define BCM2835_MBOX_TAG_GET_CLOCK_RATE	0x00030002
+#define BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE	0x00030004
+#define BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE	0x00030007
 
 #define BCM2835_MBOX_CLOCK_ID_EMMC	1
 #define BCM2835_MBOX_CLOCK_ID_UART	2
@@ -250,6 +252,22 @@
 	} body;
 };
 
+#define BCM2835_MBOX_TAG_SET_SDHOST_CLOCK	0x00038042
+
+struct bcm2835_mbox_tag_set_sdhost_clock {
+	struct bcm2835_mbox_tag_hdr tag_hdr;
+	union {
+		struct {
+			u32 rate_hz;
+		} req;
+		struct {
+			u32 rate_hz;
+			u32 rate_1;
+			u32 rate_2;
+		} resp;
+	} body;
+};
+
 #define BCM2835_MBOX_TAG_ALLOCATE_BUFFER	0x00040001
 
 struct bcm2835_mbox_tag_allocate_buffer {
diff --git a/arch/arm/mach-bcm283x/include/mach/msg.h b/arch/arm/mach-bcm283x/include/mach/msg.h
index eb3da93..e54da86 100644
--- a/arch/arm/mach-bcm283x/include/mach/msg.h
+++ b/arch/arm/mach-bcm283x/include/mach/msg.h
@@ -23,6 +23,16 @@
 int bcm2835_get_mmc_clock(u32 clock_id);
 
 /**
+ * bcm2835_set_sdhost_clock() - determine if firmware controls sdhost cdiv
+ *
+ * @rate_hz: Input clock frequency
+ * @rate_1: Returns a clock frequency
+ * @rate_2: Returns a clock frequency
+ * @return 0 of OK, -EIO on error
+ */
+int bcm2835_set_sdhost_clock(u32 rate_hz, u32 *rate_1, u32 *rate_2);
+
+/**
  * bcm2835_get_video_size() - get the current display size
  *
  * @widthp: Returns the width in pixels
diff --git a/arch/arm/mach-bcm283x/msg.c b/arch/arm/mach-bcm283x/msg.c
index fe243e2..2188b38 100644
--- a/arch/arm/mach-bcm283x/msg.c
+++ b/arch/arm/mach-bcm283x/msg.c
@@ -21,6 +21,12 @@
 	u32 end_tag;
 };
 
+struct msg_set_sdhost_clock {
+	struct bcm2835_mbox_hdr hdr;
+	struct bcm2835_mbox_tag_set_sdhost_clock set_sdhost_clock;
+	u32 end_tag;
+};
+
 struct msg_query {
 	struct bcm2835_mbox_hdr hdr;
 	struct bcm2835_mbox_tag_physical_w_h physical_w_h;
@@ -75,6 +81,7 @@
 {
 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
 	int ret;
+	u32 clock_rate = 0;
 
 	ret = bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
 	if (ret)
@@ -90,7 +97,45 @@
 		return -EIO;
 	}
 
-	return msg_clk->get_clock_rate.body.resp.rate_hz;
+	clock_rate = msg_clk->get_clock_rate.body.resp.rate_hz;
+
+	if (clock_rate == 0) {
+		BCM2835_MBOX_INIT_HDR(msg_clk);
+		BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_MAX_CLOCK_RATE);
+		msg_clk->get_clock_rate.body.req.clock_id = clock_id;
+
+		ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
+		if (ret) {
+			printf("bcm2835: Could not query max eMMC clock rate\n");
+			return -EIO;
+		}
+
+		clock_rate = msg_clk->get_clock_rate.body.resp.rate_hz;
+	}
+
+	return clock_rate;
+}
+
+int bcm2835_set_sdhost_clock(u32 rate_hz, u32 *rate_1, u32 *rate_2)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_sdhost_clock, msg_sdhost_clk, 1);
+	int ret;
+
+	BCM2835_MBOX_INIT_HDR(msg_sdhost_clk);
+	BCM2835_MBOX_INIT_TAG(&msg_sdhost_clk->set_sdhost_clock, SET_SDHOST_CLOCK);
+
+	msg_sdhost_clk->set_sdhost_clock.body.req.rate_hz = rate_hz;
+
+	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_sdhost_clk->hdr);
+	if (ret) {
+		printf("bcm2835: Could not query sdhost clock rate\n");
+		return -EIO;
+	}
+
+	*rate_1 = msg_sdhost_clk->set_sdhost_clock.body.resp.rate_1;
+	*rate_2 = msg_sdhost_clk->set_sdhost_clock.body.resp.rate_2;
+
+	return 0;
 }
 
 int bcm2835_get_video_size(int *widthp, int *heightp)
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 8603c93..1057ebb 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -158,7 +158,7 @@
 	},
 	[0x12] = {
 		"Zero 2 W",
-		DTB_DIR "bcm2837-rpi-zero-2.dtb",
+		DTB_DIR "bcm2837-rpi-zero-2-w.dtb",
 		false,
 	},
 	[0x13] = {
@@ -503,10 +503,61 @@
 	return (void *)fw_dtb_pointer;
 }
 
+int copy_property(void *dst, void *src, char *path, char *property)
+{
+	int dst_offset, src_offset;
+	const fdt32_t *prop;
+	int len;
+
+	src_offset = fdt_path_offset(src, path);
+	dst_offset = fdt_path_offset(dst, path);
+
+	if (src_offset < 0 || dst_offset < 0)
+		return -1;
+
+	prop = fdt_getprop(src, src_offset, property, &len);
+	if (!prop)
+		return -1;
+
+	return fdt_setprop(dst, dst_offset, property, prop, len);
+}
+
+/* Copy tweaks from the firmware dtb to the loaded dtb */
+void  update_fdt_from_fw(void *fdt, void *fw_fdt)
+{
+	/* Using dtb from firmware directly; leave it alone */
+	if (fdt == fw_fdt)
+		return;
+
+	/* The firmware provides a more precie model; so copy that */
+	copy_property(fdt, fw_fdt, "/", "model");
+
+	/* memory reserve as suggested by the firmware */
+	copy_property(fdt, fw_fdt, "/", "memreserve");
+
+	/* Adjust dma-ranges for the SD card and PCI bus as they can depend on
+	 * the SoC revision
+	 */
+	copy_property(fdt, fw_fdt, "emmc2bus", "dma-ranges");
+	copy_property(fdt, fw_fdt, "pcie0", "dma-ranges");
+
+	/* Bootloader configuration template exposes as nvmem */
+	if (copy_property(fdt, fw_fdt, "blconfig", "reg") == 0)
+		copy_property(fdt, fw_fdt, "blconfig", "status");
+
+	/* kernel address randomisation seed as provided by the firmware */
+	copy_property(fdt, fw_fdt, "/chosen", "kaslr-seed");
+
+	/* address of the PHY device as provided by the firmware  */
+	copy_property(fdt, fw_fdt, "ethernet0/mdio@e14/ethernet-phy@1", "reg");
+}
+
 int ft_board_setup(void *blob, struct bd_info *bd)
 {
 	int node;
 
+	update_fdt_from_fw(blob, (void *)fw_dtb_pointer);
+
 	node = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer");
 	if (node < 0)
 		fdt_simplefb_add_node(blob);
diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c
index 894dbdd..5c23c03 100644
--- a/drivers/mmc/bcm2835_sdhost.c
+++ b/drivers/mmc/bcm2835_sdhost.c
@@ -181,6 +181,7 @@
 	struct udevice		*dev;
 	struct mmc		*mmc;
 	struct bcm2835_plat	*plat;
+	unsigned int		firmware_sets_cdiv:1;
 };
 
 static void bcm2835_dumpregs(struct bcm2835_host *host)
@@ -233,7 +234,7 @@
 	msleep(20);
 	host->clock = 0;
 	writel(host->hcfg, host->ioaddr + SDHCFG);
-	writel(host->cdiv, host->ioaddr + SDCDIV);
+	writel(SDCDIV_MAX_CDIV, host->ioaddr + SDCDIV);
 }
 
 static int bcm2835_wait_transfer_complete(struct bcm2835_host *host)
@@ -598,6 +599,7 @@
 static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
 {
 	int div;
+	u32 clock_rate[2] = { 0 };
 
 	/* The SDCDIV register has 11 bits, and holds (div - 2).  But
 	 * in data mode the max is 50MHz wihout a minimum, and only
@@ -620,26 +622,34 @@
 	 * clock divisor at all times.
 	 */
 
-	if (clock < 100000) {
-		/* Can't stop the clock, but make it as slow as possible
-		 * to show willing
-		 */
-		host->cdiv = SDCDIV_MAX_CDIV;
+	if (host->firmware_sets_cdiv) {
+		bcm2835_set_sdhost_clock(clock, &clock_rate[0], &clock_rate[1]);
+		clock = max(clock_rate[0], clock_rate[1]);
+	} else {
+		if (clock < 100000) {
+			/* Can't stop the clock, but make it as slow as possible
+			* to show willing
+			*/
+			host->cdiv = SDCDIV_MAX_CDIV;
+			writel(host->cdiv, host->ioaddr + SDCDIV);
+			return;
+		}
+
+		div = host->max_clk / clock;
+		if (div < 2)
+			div = 2;
+		if ((host->max_clk / div) > clock)
+			div++;
+		div -= 2;
+
+		if (div > SDCDIV_MAX_CDIV)
+			div = SDCDIV_MAX_CDIV;
+
+		clock = host->max_clk / (div + 2);
+		host->cdiv = div;
 		writel(host->cdiv, host->ioaddr + SDCDIV);
-		return;
 	}
 
-	div = host->max_clk / clock;
-	if (div < 2)
-		div = 2;
-	if ((host->max_clk / div) > clock)
-		div++;
-	div -= 2;
-
-	if (div > SDCDIV_MAX_CDIV)
-		div = SDCDIV_MAX_CDIV;
-
-	clock = host->max_clk / (div + 2);
 	host->mmc->clock = clock;
 
 	/* Calibrate some delays */
@@ -647,9 +657,6 @@
 	host->ns_per_fifo_word = (1000000000 / clock) *
 		((host->mmc->card_caps & MMC_MODE_4BIT) ? 8 : 32);
 
-	host->cdiv = div;
-	writel(host->cdiv, host->ioaddr + SDCDIV);
-
 	/* Set the timeout to 500ms */
 	writel(host->mmc->clock / 2, host->ioaddr + SDTOUT);
 }
@@ -759,6 +766,7 @@
 	struct bcm2835_host *host = dev_get_priv(dev);
 	struct mmc *mmc = mmc_get_mmc_dev(dev);
 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	u32 clock_rate[2] = { ~0 };
 
 	host->dev = dev;
 	host->mmc = mmc;
@@ -776,6 +784,9 @@
 
 	host->max_clk = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_CORE);
 
+	bcm2835_set_sdhost_clock(0, &clock_rate[0], &clock_rate[1]);
+	host->firmware_sets_cdiv = (clock_rate[0] != ~0);
+
 	bcm2835_add_host(host);
 
 	dev_dbg(dev, "%s -> OK\n", __func__);