From 6d0642494993f39440a4d6e95f88c0456ee6d689 Mon Sep 17 00:00:00 2001 From: Antoine Mazeas Date: Fri, 19 Aug 2022 10:56:45 +0200 Subject: rpi: Copy properties from firmware dtb to the loaded dtb The RPI firmware adjusts several property values in the dtb it passes to u-boot depending on the board/SoC revision. Inherit some of these when u-boot loads a dtb itself. Specificaly copy: * /model: The firmware provides a more specific string * /memreserve: The firmware defines a reserved range, better keep it * emmc2bus and pcie0 dma-ranges: The C0T revision of the bcm2711 Soc (as present on rpi 400 and some rpi 4B boards) has different values for these then the B0T revision. So these need to be adjusted to boot on these boards * blconfig: The firmware defines the memory area where the blconfig stored. Copy those over so it can be enabled. * /chosen/kaslr-seed: The firmware generates a kaslr seed, take advantage of that. Signed-off-by: Sjoerd Simons Signed-off-by: Antoine Mazeas Reviewed-by: Simon Glass Signed-off-by: Peter Robinson --- board/raspberrypi/rpi/rpi.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 8603c93..d4b059c 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -503,10 +503,58 @@ void *board_fdt_blob_setup(int *err) 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"); +} + 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); -- cgit v1.1 From 4a45086c0ca874858d4064ee26d45199bcab494d Mon Sep 17 00:00:00 2001 From: Antoine Mazeas Date: Fri, 19 Aug 2022 10:56:46 +0200 Subject: rpi: Copy eth PHY address from fw DT to loaded DT Some Raspberry Pi 400 boards, specifically rev 1.1, have a different address for the ethernet PHY device than what is provided by the kernel DTB. The correct address is provided by the firmware, so we should carry it over into the loaded device tree so that ethernet works on such boards. Signed-off-by: Antoine Mazeas Signed-off-by: Peter Robinson --- board/raspberrypi/rpi/rpi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index d4b059c..fc1fffe 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -547,6 +547,9 @@ void update_fdt_from_fw(void *fdt, void *fw_fdt) /* 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) -- cgit v1.1 From 0e8c94054fd80535e868900deb978a9a1ebcab67 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Tue, 28 Feb 2023 10:17:26 +0000 Subject: rpi: Update the RPi Zero 2W DT filename Update the Raspberry Pi Zero 2W device tree file name to match what landed upstream. Signed-off-by: Peter Robinson --- board/raspberrypi/rpi/rpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index fc1fffe..1057ebb 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -158,7 +158,7 @@ static const struct rpi_model rpi_models_new_scheme[] = { }, [0x12] = { "Zero 2 W", - DTB_DIR "bcm2837-rpi-zero-2.dtb", + DTB_DIR "bcm2837-rpi-zero-2-w.dtb", false, }, [0x13] = { -- cgit v1.1 From 0a36afa82356b89ffc66ed7557d115186c5bd7f1 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Tue, 14 Sep 2021 13:19:18 -0500 Subject: arm: rpi: fallback to max clock rate for MMC clock In rpi-firmware 25e2b597ebfb2495eab4816a276758dcc6ea21f1, the GET_CLOCK_RATE mailbox property was changed to return the last value set by SET_CLOCK_RATE. https://github.com/raspberrypi/firmware/issues/1619#issuecomment-917025502 Due to this change in firmware behavior, bcm2835_get_mmc_clock now returns a clock rate of zero since we do not issue SET_CLOCK_RATE. This results in degraded MMC performance. SET_CLOCK_RATE fixes the clock to a specific value and disables scaling so is not an ideal solution. Instead, fallback to GET_MAX_CLOCK_RATE in bcm2835_get_mmc_clock if GET_CLOCK_RATE returns zero. Signed-off-by: Vincent Fazio Signed-off-by: Peter Robinson --- arch/arm/mach-bcm283x/include/mach/mbox.h | 2 ++ arch/arm/mach-bcm283x/msg.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-bcm283x/include/mach/mbox.h b/arch/arm/mach-bcm283x/include/mach/mbox.h index 2ae2d3d..7dcac58 100644 --- a/arch/arm/mach-bcm283x/include/mach/mbox.h +++ b/arch/arm/mach-bcm283x/include/mach/mbox.h @@ -224,6 +224,8 @@ struct bcm2835_mbox_tag_set_power_state { }; #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 diff --git a/arch/arm/mach-bcm283x/msg.c b/arch/arm/mach-bcm283x/msg.c index fe243e2..68b2773 100644 --- a/arch/arm/mach-bcm283x/msg.c +++ b/arch/arm/mach-bcm283x/msg.c @@ -75,6 +75,7 @@ int bcm2835_get_mmc_clock(u32 clock_id) { 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 +91,23 @@ int bcm2835_get_mmc_clock(u32 clock_id) 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_get_video_size(int *widthp, int *heightp) -- cgit v1.1 From 85bdd28d2bb0827f311913e00e4e338f8e4e6565 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Tue, 14 Sep 2021 13:19:19 -0500 Subject: mmc: bcm2835-host: let firmware manage the clock divisor Newer firmware can manage the SDCDIV clock divisor register, allowing the divisor to scale with the core as necessary. Leverage this ability if the firmware supports it. Adapted from the following raspberrypi Linux kernel commit: bcm2835-sdhost: Firmware manages the clock divisor https://github.com/raspberrypi/linux/commit/08532d242d7702ae0add95096aa49c5e96e066e2 Signed-off-by: Vincent Fazio Signed-off-by: Peter Robinson --- arch/arm/mach-bcm283x/include/mach/mbox.h | 16 ++++++++++ arch/arm/mach-bcm283x/include/mach/msg.h | 10 ++++++ arch/arm/mach-bcm283x/msg.c | 28 ++++++++++++++++ drivers/mmc/bcm2835_sdhost.c | 53 +++++++++++++++++++------------ 4 files changed, 86 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-bcm283x/include/mach/mbox.h b/arch/arm/mach-bcm283x/include/mach/mbox.h index 7dcac58..490664f 100644 --- a/arch/arm/mach-bcm283x/include/mach/mbox.h +++ b/arch/arm/mach-bcm283x/include/mach/mbox.h @@ -252,6 +252,22 @@ struct bcm2835_mbox_tag_get_clock_rate { } 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_power_on_module(u32 module); 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 68b2773..2188b38 100644 --- a/arch/arm/mach-bcm283x/msg.c +++ b/arch/arm/mach-bcm283x/msg.c @@ -21,6 +21,12 @@ struct msg_get_clock_rate { 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; @@ -110,6 +116,28 @@ int bcm2835_get_mmc_clock(u32 clock_id) 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) { ALLOC_CACHE_ALIGN_BUFFER(struct msg_query, msg_query, 1); 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 bcm2835_host { 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 @@ static void bcm2835_reset_internal(struct bcm2835_host *host) 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 int bcm2835_transmit(struct bcm2835_host *host) 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 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) * 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; - writel(host->cdiv, host->ioaddr + SDCDIV); - return; - } + 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; + 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; + if (div > SDCDIV_MAX_CDIV) + div = SDCDIV_MAX_CDIV; + + clock = host->max_clk / (div + 2); + host->cdiv = div; + writel(host->cdiv, host->ioaddr + SDCDIV); + } - clock = host->max_clk / (div + 2); host->mmc->clock = clock; /* Calibrate some delays */ @@ -647,9 +657,6 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) 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 @@ static int bcm2835_probe(struct udevice *dev) 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 @@ static int bcm2835_probe(struct udevice *dev) 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__); -- cgit v1.1