From 46e0ac55e56638d2543fc5a4c1ed28470095233e Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sat, 15 Nov 2025 09:33:29 +0200 Subject: [PATCH 1/4] rpi: Fix compilation with larger configs Tom reports that adding more Kconfig options fails with board/raspberrypi/rpi/lowlevel_init.o: in function `save_boot_params': board/raspberrypi/rpi/lowlevel_init.S:20:(.text+0x0): relocation truncated to fit: R_AARCH64_ADR_PREL_LO21 against symbol `fw_dtb_pointer' defined in .data section in board/raspberrypi/rpi/rpi.o make: *** [Makefile:2029: u-boot] Error 1 Since fw_dtb_pointer lives in .data it might end up above the +-1MB that adr can reach. So switch over to adrp+add which has a +-4gb reach. Reported-by: Tom Rini Closes: https://source.denx.de/u-boot/custodians/u-boot-raspberrypi/-/issues/2 Signed-off-by: Ilias Apalodimas Reviewed-by: Peter Robinson --- board/raspberrypi/rpi/lowlevel_init.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/board/raspberrypi/rpi/lowlevel_init.S b/board/raspberrypi/rpi/lowlevel_init.S index 8c39b3e12e8..30c0b0c27a8 100644 --- a/board/raspberrypi/rpi/lowlevel_init.S +++ b/board/raspberrypi/rpi/lowlevel_init.S @@ -16,7 +16,8 @@ save_boot_params: /* The firmware provided ATAG/FDT address can be found in r2/x0 */ #ifdef CONFIG_ARM64 - adr x8, fw_dtb_pointer + adrp x8, fw_dtb_pointer + add x8, x8, #:lo12:fw_dtb_pointer str x0, [x8] #else ldr r8, =fw_dtb_pointer From 2c39d975f87cfcce3805bff34918708bf7491b25 Mon Sep 17 00:00:00 2001 From: Cibil Pankiras Date: Fri, 14 Nov 2025 00:45:32 +0100 Subject: [PATCH 2/4] pinctrl: bcm283x: Add GPIO pull-up/down control for BCM2835 and BCM2711 This patch adds support for configuring GPIO pull-up and pull-down resistors in the BCM283x pinctrl driver. It implements the brcm,pull device tree property to control pin bias settings. The implementation follows the hardware-specific pull control mechanisms: - BCM2835: two-step GPPUD register sequence - BCM2711: direct per-pin control registers This enables device tree configurations to specify pull-up, pull-down, or no bias for individual GPIO pins. Tested on Raspberry Pi boards with both BCM2835 and BCM2711 SoCs. Signed-off-by: Cibil Pankiras Reviewed-by: Matthias Brugger --- arch/arm/mach-bcm283x/include/mach/gpio.h | 10 ++ drivers/pinctrl/broadcom/pinctrl-bcm283x.c | 105 ++++++++++++++++++++- 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-bcm283x/include/mach/gpio.h b/arch/arm/mach-bcm283x/include/mach/gpio.h index 4aeb48eeb20..c54414a012c 100644 --- a/arch/arm/mach-bcm283x/include/mach/gpio.h +++ b/arch/arm/mach-bcm283x/include/mach/gpio.h @@ -26,6 +26,16 @@ #define BCM2835_GPIO_FSEL_BANK(gpio) (gpio / 10) #define BCM2835_GPIO_FSEL_SHIFT(gpio) ((gpio % 10) * 3) +/* BCM2835 GPIO Pull-up/down register offsets */ +#define BCM2835_GPPUD 37 +#define BCM2835_GPPUDCLK0 38 + +/* BCM2711 GPIO Pull-up/down control */ +#define BCM2711_GPPUD_CNTRL_REG0 57 +#define BCM2711_PUD_REG_OFFSET(gpio) ((gpio) / 16) +#define BCM2711_PUD_REG_SHIFT(gpio) (((gpio) % 16) * 2) +#define BCM2711_PUD_2711_MASK 0x3 + struct bcm2835_gpio_regs { u32 gpfsel[6]; u32 reserved1; diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c index cf9350c151e..4ecc8bac645 100644 --- a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c +++ b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include struct bcm283x_pinctrl_priv { u32 *base_reg; @@ -54,7 +56,66 @@ static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio) } /* - * bcm283x_pinctrl_set_state: configure pin functions. + * bcm2835_gpio_set_pull: Set GPIO pull-up/down resistor for BCM2835 + * @dev: the pinctrl device + * @gpio: the GPIO pin number + * @pull: pull setting (BCM2835_PUD_OFF, BCM2835_PUD_DOWN, BCM2835_PUD_UP) + */ +static void bcm2835_gpio_set_pull(struct udevice *dev, unsigned int gpio, int pull) +{ + struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev); + u32 bank = BCM2835_GPPUDCLK0 + BCM2835_GPIO_COMMON_BANK(gpio); + u32 bit = BCM2835_GPIO_COMMON_SHIFT(gpio); + + /* Set required control signal */ + writel(pull & 0x3, &priv->base_reg[BCM2835_GPPUD]); + udelay(1); + + /* Clock the control signal into the GPIO pads */ + writel(1 << bit, &priv->base_reg[bank]); + udelay(1); + + /* Remove the control signal and clock */ + writel(0, &priv->base_reg[BCM2835_GPPUD]); + writel(0, &priv->base_reg[bank]); +} + +/* + * bcm2711_gpio_set_pull: Set GPIO pull-up/down resistor for BCM2711 + * @dev: the pinctrl device + * @gpio: the GPIO pin number + * @pull: pull setting (BCM2835_PUD_OFF, BCM2835_PUD_DOWN, BCM2835_PUD_UP) + */ +static void bcm2711_gpio_set_pull(struct udevice *dev, unsigned int gpio, int pull) +{ + struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev); + u32 reg_offset; + u32 bit_shift; + u32 pull_bits; + + /* Findout which GPIO_PUP_PDN_CNTRL register to use */ + reg_offset = BCM2711_GPPUD_CNTRL_REG0 + BCM2711_PUD_REG_OFFSET(gpio); + + /* Findout the bit position */ + bit_shift = BCM2711_PUD_REG_SHIFT(gpio); + + /* Update the 2-bit field for this GPIO */ + pull_bits = pull & BCM2711_PUD_2711_MASK; + clrsetbits_le32(&priv->base_reg[reg_offset], + BCM2711_PUD_2711_MASK << bit_shift, + pull_bits << bit_shift); +} + +static void bcm283x_gpio_set_pull(struct udevice *dev, unsigned int gpio, int pull) +{ + if (device_is_compatible(dev, "brcm,bcm2835-gpio")) + bcm2835_gpio_set_pull(dev, gpio, pull); + else + bcm2711_gpio_set_pull(dev, gpio, pull); +} + +/* + * bcm283x_pinctrl_set_state: configure pin functions and pull states. * @dev: the pinctrl device to be configured. * @config: the state to be configured. * @return: 0 in success @@ -62,8 +123,10 @@ static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio) int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config) { u32 pin_arr[MAX_PINS_PER_BANK]; + u32 pull_arr[MAX_PINS_PER_BANK]; int function; - int i, len, pin_count = 0; + int i, len, pin_count = 0, pull_len = 0, pull_count = 0; + int pull_value; if (!dev_read_prop(config, "brcm,pins", &len) || !len || len & 0x3 || dev_read_u32_array(config, "brcm,pins", pin_arr, @@ -82,8 +145,44 @@ int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config) return -EINVAL; } - for (i = 0; i < pin_count; i++) + /* Check if brcm,pull property exists */ + if (dev_read_prop(config, "brcm,pull", &pull_len) && pull_len > 0) { + if (pull_len & 0x3) { + debug("Invalid pull array length for pinconfig %s (%d)\n", + config->name, pull_len); + return -EINVAL; + } + + pull_count = pull_len / sizeof(u32); + + if (pull_count != 1 && pull_count != pin_count) { + debug("Pull array count (%d) must be 1 or match pin count (%d) for pinconfig %s\n", + pull_count, pin_count, config->name); + return -EINVAL; + } + + if (dev_read_u32_array(config, "brcm,pull", pull_arr, pull_count)) { + debug("Failed reading pull array for pinconfig %s\n", config->name); + return -EINVAL; + } + + /* Validate pull values */ + for (i = 0; i < pull_count; i++) { + if (pull_arr[i] > 2) { + debug("Invalid pull value %d for pin %d in pinconfig %s\n", + pull_arr[i], pin_arr[i], config->name); + return -EINVAL; + } + } + } + + for (i = 0; i < pin_count; i++) { bcm2835_gpio_set_func_id(dev, pin_arr[i], function); + if (pull_count > 0) { + pull_value = (pull_count == 1) ? pull_arr[0] : pull_arr[i]; + bcm283x_gpio_set_pull(dev, pin_arr[i], pull_value); + } + } return 0; } From 15c719174cf30c4ef1c5a3638156db8c318fbd18 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 27 Sep 2025 05:30:15 -0600 Subject: [PATCH 3/4] rpi: Use the U-Boot control FDT for fdt_addr The fdt_addr variable is used in extlinux as a fallback devicetree if none is provided by the boot command. Otherwise the only use in U-Boot seems to me efi_install_fdt() when the internal FDT is required. The existing mechanism uses the devicetree provided to U-Boot, but in its original, unrelocated position. In my testing on an rpi_4, this ends up at 2b35ef00 which is not a convenient place in memory, if the ramdisk is large. U-Boot already deals with this sort of problem by relocating the FDT to a safe address. So use the control-FDT address instead. Remove the existing comment, which is confusing, since the FDT is not actually passed unmodified to the kernel: U-Boot adds various things using its FDT-fixup mechanism. Note that board_get_usable_ram_top() reduces the RAM top for boards with less RAM. This behaviour is left unchanged as there is no other mechanism for U-Boot to handle this. Signed-off-by: Simon Glass Reviewed-by: Christopher Obbard Tested-by: Christopher Obbard # CM4 1G --- board/raspberrypi/rpi/rpi.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 1b0b664fa2b..6f96c1ebc96 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -3,6 +3,8 @@ * (C) Copyright 2012-2016 Stephen Warren */ +#define LOG_CATEGORY LOGC_BOARD + #include #include #include @@ -354,15 +356,13 @@ static void set_fdtfile(void) } /* - * If the firmware provided a valid FDT at boot time, let's expose it in - * ${fdt_addr} so it may be passed unmodified to the kernel. + * Allow U-Boot to use its control FDT with extlinux if one is not provided. + * This will then go through the usual fixups that U-Boot does, before being + * handed off to Linux */ static void set_fdt_addr(void) { - if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC) - return; - - env_set_hex("fdt_addr", fw_dtb_pointer); + env_set_hex("fdt_addr", (ulong)gd->fdt_blob); } /* @@ -608,7 +608,10 @@ int ft_board_setup(void *blob, struct bd_info *bd) { int node; - update_fdt_from_fw(blob, (void *)fw_dtb_pointer); + if (blob == gd->fdt_blob) + log_debug("Same FDT: nothing to do\n"); + else + update_fdt_from_fw(blob, (void *)gd->fdt_blob); if (CONFIG_IS_ENABLED(FDT_SIMPLEFB)) { node = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer"); From 5b702cf4d09f84f6cfe2989038b67feafe9945ed Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 25 Nov 2025 11:23:58 +0100 Subject: [PATCH 4/4] rpi: Fix DRAM size reporting to show total RAM The VideoCore mailbox GET_ARM_MEMORY only reports the size of the first accessible memory region (~947 MiB on RPi4 with 8GB), not the total RAM. This causes U-Boot to display "DRAM: 947 MiB (total 7.9 GiB)" instead of "DRAM: 7.9 GiB". On Raspberry Pi 4 with 8GB RAM, the memory is split across multiple non-contiguous banks. The dram_init() function only sets gd->ram_size to the first bank size reported by the VideoCore firmware, while fdtdec_setup_memory_banksize() correctly populates all memory banks from the device tree. Fix this by updating gd->ram_size after dram_init_banksize() has populated all memory banks, so it reflects the actual total RAM across all banks. Signed-off-by: Anders Roxell Reviewed-by: Peter Robinson --- board/raspberrypi/rpi/rpi.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 6f96c1ebc96..f9b643555dd 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -334,13 +334,27 @@ int dram_init(void) #ifdef CONFIG_OF_BOARD int dram_init_banksize(void) { + phys_addr_t total_size = 0; + int i; int ret; ret = fdtdec_setup_memory_banksize(); if (ret) return ret; - return fdtdec_setup_mem_size_base(); + ret = fdtdec_setup_mem_size_base(); + if (ret) + return ret; + + /* Update gd->ram_size to reflect total RAM across all banks */ + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + if (gd->bd->bi_dram[i].size == 0) + break; + total_size += gd->bd->bi_dram[i].size; + } + gd->ram_size = total_size; + + return 0; } #endif