
Hi,
These patches are slight update for patches posted earlier here[1]. They are adding basic support for RPi5 and are based on v2 series from Dmitry Malkin[2].
What changed:
* Initial memory map now includes whole first 1GB of DRAM. At runtime, the firmware will adjust this size depending on whether an HDMI cable is plugged in or not. If there is HDMI monitor connected it will reserve framebufer memory region and will add simple-framebuffer device into devicetree.
* Dynamically calculate bits per pixel in video driver. This works on all prevous RPi's models that I have.
* I am dropping PCIe patch for now. I made some progress on porting changes from vendor Linux tree to U-Boot. Unfortunatly testing it is little bit tricky. They are many devices behind PCIe, but more or less all of them requires missing either "reset-controller" or "clock-controller" or "pin-controller" drivers. I was able to probe "cdns,macb" device, but access to ethernet PHY over MDIO bus is stucking. Then I ported "raspberrypi,rp1-adc" driver from vendor Linux tree, but it requires missing clock. And on top of that machine that I used for developing this crashed and I lost my PCIe changes :-|. Anyway.
These patches allows me to boot current openSUSE Tumbleweed without modification. I can see serial console log and boot process on HDMI connected monitor.
I think these patches should be enough for start. Please consider for inclusion.
Thanks, Ivan
[1] https://lore.kernel.org/all/20231218210341.30073-1-iivanov@suse.de/ [2] https://lore.kernel.org/all/CAKRNjQ0dsWozGo4n8g58m4cCEk3n=qx1R+L24WBgpo-iP1y...
Dmitry Malkin (2): rpi5: add initial memory map for bcm2712 rpi5: Use devicetree as alternative way to read IO base addresses
Ivan T. Ivanov (4): rpi5: Use devicetree to retrieve board revision bcm2835: Dynamically calculate bytes per pixel parameter mmc: bcmstb: Add support for bcm2712 SD controller configs: rpi_arm64: enable SDHCI BCMSTB driver
arch/arm/mach-bcm283x/include/mach/base.h | 5 +- arch/arm/mach-bcm283x/include/mach/mbox.h | 3 +- arch/arm/mach-bcm283x/include/mach/sdhci.h | 3 +- arch/arm/mach-bcm283x/include/mach/timer.h | 3 +- arch/arm/mach-bcm283x/include/mach/wdog.h | 3 +- arch/arm/mach-bcm283x/init.c | 74 ++++++++- board/raspberrypi/rpi/rpi.c | 22 ++- configs/rpi_arm64_defconfig | 1 + drivers/mmc/bcmstb_sdhci.c | 173 ++++++++++++++++++++- drivers/video/bcm2835.c | 18 ++- 10 files changed, 282 insertions(+), 23 deletions(-)

From: Dmitry Malkin dmitry@bedrocksystems.com
This includes: * 1GB of RAM (from 4GB or 8GB total) * AXI ranges (main peripherals)
When HDMI cable is plugged in at boot time firmware will insert "simple-framebuffer" device into devicetree and will shrink first memory region to 0x3f800000UL. Board setup then will properly reserve frameboofer region.
When no HDMI cable is plugged in size of the region will be 0x3fc00000UL.
Signed-off-by: Dmitry Malkin dmitry@bedrocksystems.com Signed-off-by: Ivan T. Ivanov iivanov@suse.de --- arch/arm/mach-bcm283x/init.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/arch/arm/mach-bcm283x/init.c b/arch/arm/mach-bcm283x/init.c index 7265faf6ce..f1a0c8588d 100644 --- a/arch/arm/mach-bcm283x/init.c +++ b/arch/arm/mach-bcm283x/init.c @@ -68,6 +68,36 @@ static struct mm_region bcm2711_mem_map[MEM_MAP_MAX_ENTRIES] = { } };
+static struct mm_region bcm2712_mem_map[MEM_MAP_MAX_ENTRIES] = { + { + /* First 1GB of DRAM */ + .virt = 0x00000000UL, + .phys = 0x00000000UL, + .size = 0x40000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* Beginning of AXI bus where uSD controller lives */ + .virt = 0x1000000000UL, + .phys = 0x1000000000UL, + .size = 0x0002000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* SoC bus */ + .virt = 0x107c000000UL, + .phys = 0x107c000000UL, + .size = 0x0004000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* List terminator */ + 0, + } +}; + struct mm_region *mem_map = bcm283x_mem_map;
/* @@ -78,6 +108,7 @@ static const struct udevice_id board_ids[] = { { .compatible = "brcm,bcm2837", .data = (ulong)&bcm283x_mem_map}, { .compatible = "brcm,bcm2838", .data = (ulong)&bcm2711_mem_map}, { .compatible = "brcm,bcm2711", .data = (ulong)&bcm2711_mem_map}, + { .compatible = "brcm,bcm2712", .data = (ulong)&bcm2712_mem_map}, { }, };

On 1/10/24 04:29, Ivan T. Ivanov wrote:
From: Dmitry Malkin dmitry@bedrocksystems.com
This includes:
- 1GB of RAM (from 4GB or 8GB total)
- AXI ranges (main peripherals)
When HDMI cable is plugged in at boot time firmware will insert "simple-framebuffer" device into devicetree and will shrink first memory region to 0x3f800000UL. Board setup then will properly reserve frameboofer region.
s/frameboofer/framebuffer/
When no HDMI cable is plugged in size of the region will be 0x3fc00000UL.
s/in size/in the size/

From: Dmitry Malkin dmitry@bedrocksystems.com
MBOX and Watchdog on RPi5/bcm2712 has a different base IO offsets. Find them via devicetree blob passed by bootloader.
Signed-off-by: Dmitry Malkin dmitry@bedrocksystems.com Reviewed-by: Matthias Brugger mbrugger@suse.com Signed-off-by: Ivan T. Ivanov iivanov@suse.de --- arch/arm/mach-bcm283x/include/mach/base.h | 5 ++- arch/arm/mach-bcm283x/include/mach/mbox.h | 3 +- arch/arm/mach-bcm283x/include/mach/sdhci.h | 3 +- arch/arm/mach-bcm283x/include/mach/timer.h | 3 +- arch/arm/mach-bcm283x/include/mach/wdog.h | 3 +- arch/arm/mach-bcm283x/init.c | 43 ++++++++++++++++++---- 6 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-bcm283x/include/mach/base.h b/arch/arm/mach-bcm283x/include/mach/base.h index 4ccaf69693..6de99e7ea1 100644 --- a/arch/arm/mach-bcm283x/include/mach/base.h +++ b/arch/arm/mach-bcm283x/include/mach/base.h @@ -6,7 +6,10 @@ #ifndef _BCM283x_BASE_H_ #define _BCM283x_BASE_H_
-extern unsigned long rpi_bcm283x_base; +extern unsigned long rpi_mbox_base; +extern unsigned long rpi_timer_base; +extern unsigned long rpi_sdhci_base; +extern unsigned long rpi_wdog_base;
#ifdef CONFIG_ARMV7_LPAE #ifdef CONFIG_TARGET_RPI_4_32B diff --git a/arch/arm/mach-bcm283x/include/mach/mbox.h b/arch/arm/mach-bcm283x/include/mach/mbox.h index 490664f878..35d4e2f075 100644 --- a/arch/arm/mach-bcm283x/include/mach/mbox.h +++ b/arch/arm/mach-bcm283x/include/mach/mbox.h @@ -38,8 +38,7 @@
/* Raw mailbox HW */
-#define BCM2835_MBOX_PHYSADDR ({ BUG_ON(!rpi_bcm283x_base); \ - rpi_bcm283x_base + 0x0000b880; }) +#define BCM2835_MBOX_PHYSADDR rpi_mbox_base
struct bcm2835_mbox_regs { u32 read; diff --git a/arch/arm/mach-bcm283x/include/mach/sdhci.h b/arch/arm/mach-bcm283x/include/mach/sdhci.h index 7323690687..e837c679c4 100644 --- a/arch/arm/mach-bcm283x/include/mach/sdhci.h +++ b/arch/arm/mach-bcm283x/include/mach/sdhci.h @@ -8,8 +8,7 @@
#include <asm/arch/base.h>
-#define BCM2835_SDHCI_PHYSADDR ({ BUG_ON(!rpi_bcm283x_base); \ - rpi_bcm283x_base + 0x00300000; }) +#define BCM2835_SDHCI_PHYSADDR rpi_sdhci_base
int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq);
diff --git a/arch/arm/mach-bcm283x/include/mach/timer.h b/arch/arm/mach-bcm283x/include/mach/timer.h index 5567dbd7f3..60500a256d 100644 --- a/arch/arm/mach-bcm283x/include/mach/timer.h +++ b/arch/arm/mach-bcm283x/include/mach/timer.h @@ -11,8 +11,7 @@ #include <linux/bug.h> #endif
-#define BCM2835_TIMER_PHYSADDR ({ BUG_ON(!rpi_bcm283x_base); \ - rpi_bcm283x_base + 0x00003000; }) +#define BCM2835_TIMER_PHYSADDR rpi_timer_base
#define BCM2835_TIMER_CS_M3 (1 << 3) #define BCM2835_TIMER_CS_M2 (1 << 2) diff --git a/arch/arm/mach-bcm283x/include/mach/wdog.h b/arch/arm/mach-bcm283x/include/mach/wdog.h index 9942666720..b950560674 100644 --- a/arch/arm/mach-bcm283x/include/mach/wdog.h +++ b/arch/arm/mach-bcm283x/include/mach/wdog.h @@ -8,8 +8,7 @@
#include <asm/arch/base.h>
-#define BCM2835_WDOG_PHYSADDR ({ BUG_ON(!rpi_bcm283x_base); \ - rpi_bcm283x_base + 0x00100000; }) +#define BCM2835_WDOG_PHYSADDR rpi_wdog_base
struct bcm2835_wdog_regs { u32 unknown0[7]; diff --git a/arch/arm/mach-bcm283x/init.c b/arch/arm/mach-bcm283x/init.c index f1a0c8588d..016bc1eb41 100644 --- a/arch/arm/mach-bcm283x/init.c +++ b/arch/arm/mach-bcm283x/init.c @@ -146,7 +146,11 @@ static void rpi_update_mem_map(void) static void rpi_update_mem_map(void) {} #endif
-unsigned long rpi_bcm283x_base = 0x3f000000; +/* Default bcm283x devices addresses */ +unsigned long rpi_mbox_base = 0x3f00b880; +unsigned long rpi_sdhci_base = 0x3f300000; +unsigned long rpi_wdog_base = 0x3f100000; +unsigned long rpi_timer_base = 0x3f003000;
int arch_cpu_init(void) { @@ -157,22 +161,45 @@ int arch_cpu_init(void)
int mach_cpu_init(void) { - int ret, soc_offset; + int ret, soc, offset; u64 io_base, size;
rpi_update_mem_map();
/* Get IO base from device tree */ - soc_offset = fdt_path_offset(gd->fdt_blob, "/soc"); - if (soc_offset < 0) - return soc_offset; + soc = fdt_path_offset(gd->fdt_blob, "/soc"); + if (soc < 0) + return soc;
- ret = fdt_read_range((void *)gd->fdt_blob, soc_offset, 0, NULL, - &io_base, &size); + ret = fdt_read_range((void *)gd->fdt_blob, soc, 0, NULL, + &io_base, &size); if (ret) return ret;
- rpi_bcm283x_base = io_base; + rpi_mbox_base = io_base + 0x00b880; + rpi_sdhci_base = io_base + 0x300000; + rpi_wdog_base = io_base + 0x100000; + rpi_timer_base = io_base + 0x003000; + + offset = fdt_node_offset_by_compatible(gd->fdt_blob, soc, + "brcm,bcm2835-mbox"); + if (offset > soc) + rpi_mbox_base = fdt_get_base_address(gd->fdt_blob, offset); + + offset = fdt_node_offset_by_compatible(gd->fdt_blob, soc, + "brcm,bcm2835-sdhci"); + if (offset > soc) + rpi_sdhci_base = fdt_get_base_address(gd->fdt_blob, offset); + + offset = fdt_node_offset_by_compatible(gd->fdt_blob, soc, + "brcm,bcm2835-system-timer"); + if (offset > soc) + rpi_timer_base = fdt_get_base_address(gd->fdt_blob, offset); + + offset = fdt_node_offset_by_compatible(gd->fdt_blob, soc, + "brcm,bcm2712-pm"); + if (offset > soc) + rpi_wdog_base = fdt_get_base_address(gd->fdt_blob, offset);
return 0; }

On 1/10/24 04:29, Ivan T. Ivanov wrote:
From: Dmitry Malkin dmitry@bedrocksystems.com
MBOX and Watchdog on RPi5/bcm2712 has a different base IO offsets.
s/has a/have a /
Find them via devicetree blob passed by bootloader.
Signed-off-by: Dmitry Malkin dmitry@bedrocksystems.com Reviewed-by: Matthias Brugger mbrugger@suse.com Signed-off-by: Ivan T. Ivanov iivanov@suse.de
arch/arm/mach-bcm283x/include/mach/base.h | 5 ++- arch/arm/mach-bcm283x/include/mach/mbox.h | 3 +- arch/arm/mach-bcm283x/include/mach/sdhci.h | 3 +- arch/arm/mach-bcm283x/include/mach/timer.h | 3 +- arch/arm/mach-bcm283x/include/mach/wdog.h | 3 +- arch/arm/mach-bcm283x/init.c | 43 ++++++++++++++++++---- 6 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-bcm283x/include/mach/base.h b/arch/arm/mach-bcm283x/include/mach/base.h index 4ccaf69693..6de99e7ea1 100644 --- a/arch/arm/mach-bcm283x/include/mach/base.h +++ b/arch/arm/mach-bcm283x/include/mach/base.h @@ -6,7 +6,10 @@ #ifndef _BCM283x_BASE_H_ #define _BCM283x_BASE_H_
-extern unsigned long rpi_bcm283x_base; +extern unsigned long rpi_mbox_base; +extern unsigned long rpi_timer_base; +extern unsigned long rpi_sdhci_base; +extern unsigned long rpi_wdog_base;
Maybe suffix those variables with _phys_base to denote they are physical addresses, even if you seem to use a 1:1 mapping between virtual and physical, knowing which type of address we are dealing with right away is clearer.

On 01-10 10:00, Florian Fainelli wrote:
On 1/10/24 04:29, Ivan T. Ivanov wrote:
From: Dmitry Malkin dmitry@bedrocksystems.com
MBOX and Watchdog on RPi5/bcm2712 has a different base IO offsets.
s/has a/have a /
Thanks!
Find them via devicetree blob passed by bootloader.
Signed-off-by: Dmitry Malkin dmitry@bedrocksystems.com Reviewed-by: Matthias Brugger mbrugger@suse.com Signed-off-by: Ivan T. Ivanov iivanov@suse.de
arch/arm/mach-bcm283x/include/mach/base.h | 5 ++- arch/arm/mach-bcm283x/include/mach/mbox.h | 3 +- arch/arm/mach-bcm283x/include/mach/sdhci.h | 3 +- arch/arm/mach-bcm283x/include/mach/timer.h | 3 +- arch/arm/mach-bcm283x/include/mach/wdog.h | 3 +- arch/arm/mach-bcm283x/init.c | 43 ++++++++++++++++++---- 6 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-bcm283x/include/mach/base.h b/arch/arm/mach-bcm283x/include/mach/base.h index 4ccaf69693..6de99e7ea1 100644 --- a/arch/arm/mach-bcm283x/include/mach/base.h +++ b/arch/arm/mach-bcm283x/include/mach/base.h @@ -6,7 +6,10 @@ #ifndef _BCM283x_BASE_H_ #define _BCM283x_BASE_H_ -extern unsigned long rpi_bcm283x_base; +extern unsigned long rpi_mbox_base; +extern unsigned long rpi_timer_base; +extern unsigned long rpi_sdhci_base; +extern unsigned long rpi_wdog_base;
Maybe suffix those variables with _phys_base to denote they are physical addresses, even if you seem to use a 1:1 mapping between virtual and physical, knowing which type of address we are dealing with right away is clearer.
I am not an expert on U-Boot, but I think mapping is always 1:1, so explicit naming it that way looks redundant. As you can see even initial naming don't specify it. But if you insist I could change it.
Regards, Ivan

Firmware on RPi5 return error on board revision query through firmware interface, but on the other hand it fills "linux,revision" in "system" node, so use it to detect board revision.
system { linux,revision = <0xc04170>; linux,serial = <0x6cf44e80 0x3c533ede>; };
Reviewed-by: Matthias Brugger mbrugger@suse.com Signed-off-by: Ivan T. Ivanov iivanov@suse.de --- board/raspberrypi/rpi/rpi.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index cd823ad746..2851ebc985 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -171,6 +171,11 @@ static const struct rpi_model rpi_models_new_scheme[] = { DTB_DIR "bcm2711-rpi-cm4.dtb", true, }, + [0x17] = { + "5 Model B", + DTB_DIR "bcm2712-rpi-5-b.dtb", + true, + }, };
static const struct rpi_model rpi_models_old_scheme[] = { @@ -429,15 +434,27 @@ static void get_board_revision(void) int ret; const struct rpi_model *models; uint32_t models_count; + ofnode node;
BCM2835_MBOX_INIT_HDR(msg); BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); if (ret) { - printf("bcm2835: Could not query board revision\n"); /* Ignore error; not critical */ - return; + node = ofnode_path("/system"); + if (!ofnode_valid(node)) { + printf("bcm2835: Could not find /system node\n"); + return; + } + + ret = ofnode_read_u32(node, "linux,revision", &revision); + if (ret) { + printf("bcm2835: Could not find linux,revision\n"); + return; + } + } else { + revision = msg->get_board_rev.body.resp.rev; }
/* @@ -451,7 +468,6 @@ static void get_board_revision(void) * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=2... * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594 */ - revision = msg->get_board_rev.body.resp.rev; if (revision & 0x800000) { rev_scheme = 1; rev_type = (revision >> 4) & 0xff;

brcm,bcm2708-fb device provided by firmware on RPi5 uses 16 bits per pixel, so lets calculate framebuffer bytes per pixel dynamically based on queried information.
Tested to work for RPi2b v1.2, RPi3b v1.3, RPi4b v1.1, RPi2 Zero W, RPi5b v1.0.
Signed-off-by: Ivan T. Ivanov iivanov@suse.de --- drivers/video/bcm2835.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index 14942526f1..63efa762db 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -16,7 +16,7 @@ static int bcm2835_video_probe(struct udevice *dev) struct video_uc_plat *plat = dev_get_uclass_plat(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev); int ret; - int w, h, pitch; + int w, h, pitch, bpp; ulong fb_base, fb_size, fb_start, fb_end;
debug("bcm2835: Query resolution...\n"); @@ -41,9 +41,23 @@ static int bcm2835_video_probe(struct udevice *dev) DCACHE_WRITEBACK); video_set_flush_dcache(dev, true);
+ bpp = pitch / w; + switch (bpp) { + case 2: + uc_priv->bpix = VIDEO_BPP16; + break; + case 4: + uc_priv->bpix = VIDEO_BPP32; + break; + default: + printf("bcm2835: unexpected bpp %d, pitch %d, width %d\n", + bpp, pitch, w); + uc_priv->bpix = VIDEO_BPP32; + break; + } + uc_priv->xsize = w; uc_priv->ysize = h; - uc_priv->bpix = VIDEO_BPP32; plat->base = fb_base; plat->size = fb_size;

On 10/01/2024 13:29, Ivan T. Ivanov wrote:
brcm,bcm2708-fb device provided by firmware on RPi5 uses 16 bits per pixel, so lets calculate framebuffer bytes per pixel dynamically based on queried information.
Tested to work for RPi2b v1.2, RPi3b v1.3, RPi4b v1.1, RPi2 Zero W, RPi5b v1.0.
Signed-off-by: Ivan T. Ivanov iivanov@suse.de
Reviewed-by: Matthias Brugger mbrugger@suse.com
drivers/video/bcm2835.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index 14942526f1..63efa762db 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -16,7 +16,7 @@ static int bcm2835_video_probe(struct udevice *dev) struct video_uc_plat *plat = dev_get_uclass_plat(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev); int ret;
- int w, h, pitch;
int w, h, pitch, bpp; ulong fb_base, fb_size, fb_start, fb_end;
debug("bcm2835: Query resolution...\n");
@@ -41,9 +41,23 @@ static int bcm2835_video_probe(struct udevice *dev) DCACHE_WRITEBACK); video_set_flush_dcache(dev, true);
- bpp = pitch / w;
- switch (bpp) {
- case 2:
uc_priv->bpix = VIDEO_BPP16;
break;
- case 4:
uc_priv->bpix = VIDEO_BPP32;
break;
- default:
printf("bcm2835: unexpected bpp %d, pitch %d, width %d\n",
bpp, pitch, w);
uc_priv->bpix = VIDEO_BPP32;
break;
- }
- uc_priv->xsize = w; uc_priv->ysize = h;
- uc_priv->bpix = VIDEO_BPP32; plat->base = fb_base; plat->size = fb_size;

Borrow SD quirks from vendor Linux driver.
"BCM2712 unfortunately carries with it a perennial bug with the SD controller register interface present on previous chips (2711/2709/2708). Accesses must be dword-sized and a read-modify-write cycle to the 32-bit registers containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers tramples the upper/lower 16 bits of data written. BCM2712 does not seem to need the extreme delay between each write as on previous chips, just the serialisation of writes to these registers in a single 32-bit operation."
Signed-off-by: Ivan T. Ivanov iivanov@suse.de --- drivers/mmc/bcmstb_sdhci.c | 173 ++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c index dc96818cff..21489e66c0 100644 --- a/drivers/mmc/bcmstb_sdhci.c +++ b/drivers/mmc/bcmstb_sdhci.c @@ -38,6 +38,16 @@ */ #define BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY 400000
+#define SDIO_CFG_CTRL 0x0 +#define SDIO_CFG_CTRL_SDCD_N_TEST_EN BIT(31) +#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV BIT(30) + +#define SDIO_CFG_SD_PIN_SEL 0x44 +#define SDIO_CFG_SD_PIN_SEL_MASK 0x3 +#define SDIO_CFG_SD_PIN_SEL_CARD BIT(1) + +#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) + /* * This driver has only been tested with eMMC devices; SD devices may * not work. @@ -47,6 +57,53 @@ struct sdhci_bcmstb_plat { struct mmc mmc; };
+struct sdhci_bcmstb_host { + struct sdhci_host host; + u32 shadow_cmd; + u32 shadow_blk; + bool is_cmd_shadowed; + bool is_blk_shadowed; +}; + +struct sdhci_brcmstb_dev_priv { + int (*init)(struct udevice *dev); + struct sdhci_ops *ops; +}; + +static inline struct sdhci_bcmstb_host *to_bcmstb_host(struct sdhci_host *host) +{ + return container_of(host, struct sdhci_bcmstb_host, host); +} + +static int sdhci_brcmstb_init_2712(struct udevice *dev) +{ + struct sdhci_host *host = dev_get_priv(dev); + void *cfg_regs; + u32 reg; + + /* Map in the non-standard CFG registers */ + cfg_regs = dev_remap_addr_name(dev, "cfg"); + if (!cfg_regs) + return -ENOENT; + + if ((host->mmc->host_caps & MMC_CAP_NONREMOVABLE) || + (host->mmc->host_caps & MMC_CAP_NEEDS_POLL)) { + /* Force presence */ + reg = readl(cfg_regs + SDIO_CFG_CTRL); + reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV; + reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN; + writel(reg, cfg_regs + SDIO_CFG_CTRL); + } else { + /* Enable card detection line */ + reg = readl(cfg_regs + SDIO_CFG_SD_PIN_SEL); + reg &= ~SDIO_CFG_SD_PIN_SEL_MASK; + reg |= SDIO_CFG_SD_PIN_SEL_CARD; + writel(reg, cfg_regs + SDIO_CFG_SD_PIN_SEL); + } + + return 0; +} + static int sdhci_bcmstb_bind(struct udevice *dev) { struct sdhci_bcmstb_plat *plat = dev_get_plat(dev); @@ -58,10 +115,14 @@ static int sdhci_bcmstb_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_bcmstb_plat *plat = dev_get_plat(dev); - struct sdhci_host *host = dev_get_priv(dev); + struct sdhci_bcmstb_host *bcmstb = dev_get_priv(dev); + struct sdhci_host *host = &bcmstb->host; + struct sdhci_brcmstb_dev_priv *dev_priv; fdt_addr_t base; int ret;
+ dev_priv = (struct sdhci_brcmstb_dev_priv *)dev_get_driver_data(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; @@ -75,6 +136,10 @@ static int sdhci_bcmstb_probe(struct udevice *dev)
host->mmc = &plat->mmc; host->mmc->dev = dev; + + if (dev_priv && dev_priv->ops) + host->ops = dev_priv->ops; + ret = sdhci_setup_cfg(&plat->cfg, host, BCMSTB_SDHCI_MAXIMUM_CLOCK_FREQUENCY, BCMSTB_SDHCI_MINIMUM_CLOCK_FREQUENCY); @@ -84,10 +149,116 @@ static int sdhci_bcmstb_probe(struct udevice *dev) upriv->mmc = &plat->mmc; host->mmc->priv = host;
+ if (dev_priv && dev_priv->init) { + ret = dev_priv->init(dev); + if (ret) + return ret; + } + return sdhci_probe(dev); }
+static u16 sdhci_brcmstb_32bits_readw(struct sdhci_host *host, int reg) +{ + struct sdhci_bcmstb_host *bcmstb = to_bcmstb_host(host); + u16 word; + u32 val; + + if (reg == SDHCI_TRANSFER_MODE && bcmstb->is_cmd_shadowed) { + /* Get the saved transfer mode */ + val = bcmstb->shadow_cmd; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + bcmstb->is_blk_shadowed) { + /* Get the saved block info */ + val = bcmstb->shadow_blk; + } else { + val = readl(host->ioaddr + (reg & ~3)); + } + + word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + return word; +} + +static u8 sdhci_brcmstb_32bits_readb(struct sdhci_host *host, int reg) +{ + u32 val = readl(host->ioaddr + (reg & ~3)); + u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; + return byte; +} + +/* + * BCM2712 unfortunately carries with it a perennial bug with the SD + * controller register interface present on previous chips (2711/2709/2708). + * Accesses must be dword-sized and a read-modify-write cycle to the + * 32-bit registers containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and + * BLOCK_COUNT registers tramples the upper/lower 16 bits of data written. + * BCM2712 does not seem to need the extreme delay between each write as + * on previous chips, just the serialisation of writes to these registers + * in a single 32-bit operation. + */ +static void sdhci_brcmstb_32bits_writew(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_bcmstb_host *bcmstb = to_bcmstb_host(host); + u32 word_shift = REG_OFFSET_IN_BITS(reg); + u32 mask = 0xffff << word_shift; + u32 oldval, newval; + + if (reg == SDHCI_COMMAND) { + /* Write the block now as we are issuing a command */ + if (bcmstb->is_blk_shadowed) { + writel(bcmstb->shadow_blk, host->ioaddr + SDHCI_BLOCK_SIZE); + bcmstb->is_blk_shadowed = false; + } + oldval = bcmstb->shadow_cmd; + bcmstb->is_cmd_shadowed = false; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + bcmstb->is_blk_shadowed) { + /* Block size and count are stored in shadow reg */ + oldval = bcmstb->shadow_blk; + } else { + /* Read reg, all other registers are not shadowed */ + oldval = readl(host->ioaddr + (reg & ~3)); + } + newval = (oldval & ~mask) | (val << word_shift); + + if (reg == SDHCI_TRANSFER_MODE) { + /* Save the transfer mode until the command is issued */ + bcmstb->shadow_cmd = newval; + bcmstb->is_cmd_shadowed = true; + } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + /* Save the block info until the command is issued */ + bcmstb->shadow_blk = newval; + bcmstb->is_blk_shadowed = true; + } else { + /* Command or other regular 32-bit write */ + writel(newval, host->ioaddr + (reg & ~3)); + } +} + +static void sdhci_brcmstb_32bits_writeb(struct sdhci_host *host, u8 val, int reg) +{ + u32 oldval = readl(host->ioaddr + (reg & ~3)); + u32 byte_shift = REG_OFFSET_IN_BITS(reg); + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + + writel(newval, host->ioaddr + (reg & ~3)); +} + +static struct sdhci_ops sdhci_brcmstb_ops_2712 = { + .read_b = sdhci_brcmstb_32bits_readb, + .read_w = sdhci_brcmstb_32bits_readw, + .write_w = sdhci_brcmstb_32bits_writew, + .write_b = sdhci_brcmstb_32bits_writeb, +}; + +static const struct sdhci_brcmstb_dev_priv match_priv_2712 = { + .init = sdhci_brcmstb_init_2712, + .ops = &sdhci_brcmstb_ops_2712, +}; + static const struct udevice_id sdhci_bcmstb_match[] = { + { .compatible = "brcm,bcm2712-sdhci", .data = (ulong)&match_priv_2712 }, { .compatible = "brcm,bcm7425-sdhci" }, { .compatible = "brcm,sdhci-brcmstb" }, { }

Hi Ivan,
Am 10.01.24 um 13:29 schrieb Ivan T. Ivanov:
Borrow SD quirks from vendor Linux driver.
"BCM2712 unfortunately carries with it a perennial bug with the SD controller register interface present on previous chips (2711/2709/2708). Accesses must be dword-sized and a read-modify-write cycle to the 32-bit registers containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers tramples the upper/lower 16 bits of data written. BCM2712 does not seem to need the extreme delay between each write as on previous chips, just the serialisation of writes to these registers in a single 32-bit operation."
Signed-off-by: Ivan T. Ivanov iivanov@suse.de
did you noticed this commit/pull request?
https://github.com/raspberrypi/linux/pull/5842/commits/3c9d840dc933cfb13a77f...

On 01-11 23:07, Stefan Wahren wrote:
Hi Ivan,
Am 10.01.24 um 13:29 schrieb Ivan T. Ivanov:
Borrow SD quirks from vendor Linux driver.
"BCM2712 unfortunately carries with it a perennial bug with the SD controller register interface present on previous chips (2711/2709/2708). Accesses must be dword-sized and a read-modify-write cycle to the 32-bit registers containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers tramples the upper/lower 16 bits of data written. BCM2712 does not seem to need the extreme delay between each write as on previous chips, just the serialisation of writes to these registers in a single 32-bit operation."
Signed-off-by: Ivan T. Ivanov iivanov@suse.de
did you noticed this commit/pull request?
https://github.com/raspberrypi/linux/pull/5842/commits/3c9d840dc933cfb13a77f...
Doh, no. Let me check.
Thanks! Ivan

Hi,
On 01-12 09:44, Ivan T. Ivanov wrote: On 01-11 23:07, Stefan Wahren wrote:
Hi Ivan,
Am 10.01.24 um 13:29 schrieb Ivan T. Ivanov:
Borrow SD quirks from vendor Linux driver.
"BCM2712 unfortunately carries with it a perennial bug with the SD controller register interface present on previous chips (2711/2709/2708). Accesses must be dword-sized and a read-modify-write cycle to the 32-bit registers containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers tramples the upper/lower 16 bits of data written. BCM2712 does not seem to need the extreme delay between each write as on previous chips, just the serialisation of writes to these registers in a single 32-bit operation."
Signed-off-by: Ivan T. Ivanov iivanov@suse.de
did you noticed this commit/pull request?
https://github.com/raspberrypi/linux/pull/5842/commits/3c9d840dc933cfb13a77f...
Doh, no. Let me check.
And indeed, no special accessors are needed. I am preparing new version and will send it shortly.
Thanks, Ivan

RPi5 have "brcm,bcm2712-sdhci" controller which is handled by "sdhci-bcmstb" driver, so enable it.
Signed-off-by: Ivan T. Ivanov iivanov@suse.de --- configs/rpi_arm64_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/rpi_arm64_defconfig b/configs/rpi_arm64_defconfig index 08bb30b1d7..11ede9435d 100644 --- a/configs/rpi_arm64_defconfig +++ b/configs/rpi_arm64_defconfig @@ -33,6 +33,7 @@ CONFIG_BCM2835_GPIO=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_SDMA=y CONFIG_MMC_SDHCI_BCM2835=y +CONFIG_MMC_SDHCI_BCMSTB=y CONFIG_BCMGENET=y CONFIG_PCI_BRCMSTB=y CONFIG_PINCTRL=y

On 10/01/2024 13:29, Ivan T. Ivanov wrote:
Hi,
These patches are slight update for patches posted earlier here[1]. They are adding basic support for RPi5 and are based on v2 series from Dmitry Malkin[2].
What changed:
Initial memory map now includes whole first 1GB of DRAM. At runtime, the firmware will adjust this size depending on whether an HDMI cable is plugged in or not. If there is HDMI monitor connected it will reserve framebufer memory region and will add simple-framebuffer device into devicetree.
Dynamically calculate bits per pixel in video driver. This works on all prevous RPi's models that I have.
I am dropping PCIe patch for now. I made some progress on porting changes from vendor Linux tree to U-Boot. Unfortunatly testing it is little bit tricky. They are many devices behind PCIe, but more or less all of them requires missing either "reset-controller" or "clock-controller" or "pin-controller" drivers. I was able to probe "cdns,macb" device, but access to ethernet PHY over MDIO bus is stucking. Then I ported "raspberrypi,rp1-adc" driver from vendor Linux tree, but it requires missing clock. And on top of that machine that I used for developing this crashed and I lost my PCIe changes :-|. Anyway.
These patches allows me to boot current openSUSE Tumbleweed without modification. I can see serial console log and boot process on HDMI connected monitor.
I think these patches should be enough for start. Please consider for inclusion.
Thanks, Ivan
[1] https://lore.kernel.org/all/20231218210341.30073-1-iivanov@suse.de/ [2] https://lore.kernel.org/all/CAKRNjQ0dsWozGo4n8g58m4cCEk3n=qx1R+L24WBgpo-iP1y...
Dmitry Malkin (2): rpi5: add initial memory map for bcm2712 rpi5: Use devicetree as alternative way to read IO base addresses
Ivan T. Ivanov (4): rpi5: Use devicetree to retrieve board revision bcm2835: Dynamically calculate bytes per pixel parameter mmc: bcmstb: Add support for bcm2712 SD controller configs: rpi_arm64: enable SDHCI BCMSTB driver
In the meantime I was able to test this series. So here my: Tested-by: Matthias Brugger mbrugger@suse.com
arch/arm/mach-bcm283x/include/mach/base.h | 5 +- arch/arm/mach-bcm283x/include/mach/mbox.h | 3 +- arch/arm/mach-bcm283x/include/mach/sdhci.h | 3 +- arch/arm/mach-bcm283x/include/mach/timer.h | 3 +- arch/arm/mach-bcm283x/include/mach/wdog.h | 3 +- arch/arm/mach-bcm283x/init.c | 74 ++++++++- board/raspberrypi/rpi/rpi.c | 22 ++- configs/rpi_arm64_defconfig | 1 + drivers/mmc/bcmstb_sdhci.c | 173 ++++++++++++++++++++- drivers/video/bcm2835.c | 18 ++- 10 files changed, 282 insertions(+), 23 deletions(-)

Hi Ivan,
I am looking into enabling NVMe boot support using U-Boot on Raspberry Pi 5. Which brings me to some questions wrt PCIe support (see below).
On 2024-01-10 13:29, Ivan T. Ivanov wrote:
Hi,
These patches are slight update for patches posted earlier here[1]. They are adding basic support for RPi5 and are based on v2 series from Dmitry Malkin[2].
What changed:
Initial memory map now includes whole first 1GB of DRAM. At runtime, the firmware will adjust this size depending on whether an HDMI cable is plugged in or not. If there is HDMI monitor connected it will reserve framebufer memory region and will add simple-framebuffer device into devicetree.
Dynamically calculate bits per pixel in video driver. This works on all prevous RPi's models that I have.
I am dropping PCIe patch for now. I made some progress on porting changes from vendor Linux tree to U-Boot. Unfortunatly testing it is little bit tricky. They are many devices behind PCIe, but more or less all of them requires missing either "reset-controller" or "clock-controller" or "pin-controller" drivers. I was able to probe "cdns,macb" device, but access to ethernet PHY over MDIO bus is stucking. Then I ported "raspberrypi,rp1-adc" driver from vendor Linux tree, but it requires missing clock. And on top of that machine that I used for developing this crashed and I lost my PCIe changes :-|. Anyway.
Have you tried using a M.2 HAT? This likely won't require much in terms of enabling the device.
You write that you made some progress, is that compared to v3? Do you mind sharing the latest version of your patches?
Best regards, Stefan
These patches allows me to boot current openSUSE Tumbleweed without modification. I can see serial console log and boot process on HDMI connected monitor.
I think these patches should be enough for start. Please consider for inclusion.
Thanks, Ivan
[1] https://lore.kernel.org/all/20231218210341.30073-1-iivanov@suse.de/ [2] https://lore.kernel.org/all/CAKRNjQ0dsWozGo4n8g58m4cCEk3n=qx1R+L24WBgpo-iP1y...
Dmitry Malkin (2): rpi5: add initial memory map for bcm2712 rpi5: Use devicetree as alternative way to read IO base addresses
Ivan T. Ivanov (4): rpi5: Use devicetree to retrieve board revision bcm2835: Dynamically calculate bytes per pixel parameter mmc: bcmstb: Add support for bcm2712 SD controller configs: rpi_arm64: enable SDHCI BCMSTB driver
arch/arm/mach-bcm283x/include/mach/base.h | 5 +- arch/arm/mach-bcm283x/include/mach/mbox.h | 3 +- arch/arm/mach-bcm283x/include/mach/sdhci.h | 3 +- arch/arm/mach-bcm283x/include/mach/timer.h | 3 +- arch/arm/mach-bcm283x/include/mach/wdog.h | 3 +- arch/arm/mach-bcm283x/init.c | 74 ++++++++- board/raspberrypi/rpi/rpi.c | 22 ++- configs/rpi_arm64_defconfig | 1 + drivers/mmc/bcmstb_sdhci.c | 173 ++++++++++++++++++++- drivers/video/bcm2835.c | 18 ++- 10 files changed, 282 insertions(+), 23 deletions(-)

Hi Stefan,
On 19 Sep 2024, at 12:36, Stefan Agner stefan@agner.ch wrote:
Hi Ivan,
I am looking into enabling NVMe boot support using U-Boot on Raspberry Pi 5. Which brings me to some questions wrt PCIe support (see below).
On 2024-01-10 13:29, Ivan T. Ivanov wrote:
- I am dropping PCIe patch for now. I made some progress on porting changes
from vendor Linux tree to U-Boot. Unfortunatly testing it is little bit tricky. They are many devices behind PCIe, but more or less all of them requires missing either "reset-controller" or "clock-controller" or "pin-controller" drivers. I was able to probe "cdns,macb" device, but access to ethernet PHY over MDIO bus is stucking. Then I ported "raspberrypi,rp1-adc" driver from vendor Linux tree, but it requires missing clock. And on top of that machine that I used for developing this crashed and I lost my PCIe changes :-|. Anyway.
Have you tried using a M.2 HAT? This likely won't require much in terms of enabling the device.
You write that you made some progress, is that compared to v3? Do you mind sharing the latest version of your patches?
No further progress on PCIe for U-Boot from my side was made, sorry.
Stan is working on adding support for 2712 PCIe in Linux [1]. Perhaps once this is complete we can work on adding U-Boot support for the same, unless someone don’t beat us, of course.
Regards, Ivan

Hi Ivan,
Thanks for the quick response!
On 2024-09-19 11:52, Ivan T. Ivanov wrote:
Hi Stefan,
On 19 Sep 2024, at 12:36, Stefan Agner stefan@agner.ch wrote:
Hi Ivan,
I am looking into enabling NVMe boot support using U-Boot on Raspberry Pi 5. Which brings me to some questions wrt PCIe support (see below).
On 2024-01-10 13:29, Ivan T. Ivanov wrote:
- I am dropping PCIe patch for now. I made some progress on porting changes
from vendor Linux tree to U-Boot. Unfortunatly testing it is little bit tricky. They are many devices behind PCIe, but more or less all of them requires missing either "reset-controller" or "clock-controller" or "pin-controller" drivers. I was able to probe "cdns,macb" device, but access to ethernet PHY over MDIO bus is stucking. Then I ported "raspberrypi,rp1-adc" driver from vendor Linux tree, but it requires missing clock. And on top of that machine that I used for developing this crashed and I lost my PCIe changes :-|. Anyway.
Have you tried using a M.2 HAT? This likely won't require much in terms of enabling the device.
You write that you made some progress, is that compared to v3? Do you mind sharing the latest version of your patches?
No further progress on PCIe for U-Boot from my side was made, sorry.
So v3 the patch you've shared in v3 is your latest state? I was wondering since you wrote in this v4 patch set "I made some progress on porting changes from vendor Linux tree to U-Boot."...
Stan is working on adding support for 2712 PCIe in Linux [1]. Perhaps once this is complete we can work on adding U-Boot support for the same, unless someone don’t beat us, of course.
Hm, it seems the link did not make it. I guess you meant to link this patch set [1]
-- Stefan
[1] https://lore.kernel.org/lkml/20240910151845.17308-1-svarbanov@suse.de/T/
Regards, Ivan

Hi,
On 09-19 16:01, Stefan Agner wrote:
Hi Ivan,
Thanks for the quick response!
On 2024-09-19 11:52, Ivan T. Ivanov wrote:
Hi Stefan,
On 19 Sep 2024, at 12:36, Stefan Agner stefan@agner.ch wrote:
Hi Ivan,
I am looking into enabling NVMe boot support using U-Boot on Raspberry Pi 5. Which brings me to some questions wrt PCIe support (see below).
On 2024-01-10 13:29, Ivan T. Ivanov wrote:
- I am dropping PCIe patch for now. I made some progress on porting changes
from vendor Linux tree to U-Boot. Unfortunatly testing it is little bit tricky. They are many devices behind PCIe, but more or less all of them requires missing either "reset-controller" or "clock-controller" or "pin-controller" drivers. I was able to probe "cdns,macb" device, but access to ethernet PHY over MDIO bus is stucking. Then I ported "raspberrypi,rp1-adc" driver from vendor Linux tree, but it requires missing clock. And on top of that machine that I used for developing this crashed and I lost my PCIe changes :-|. Anyway.
Have you tried using a M.2 HAT? This likely won't require much in terms of enabling the device.
You write that you made some progress, is that compared to v3? Do you mind sharing the latest version of your patches?
No further progress on PCIe for U-Boot from my side was made, sorry.
So v3 the patch you've shared in v3 is your latest state? I was wondering since you wrote in this v4 patch set "I made some progress on porting changes from vendor Linux tree to U-Boot."...
And then " .. And on top of that machine that I used for developing this crashed and I lost my PCIe changes ... ". Reading the whole paragraph now I agree it is not completely clear what happened.
Stan is working on adding support for 2712 PCIe in Linux [1]. Perhaps once this is complete we can work on adding U-Boot support for the same, unless someone don’t beat us, of course.
Hm, it seems the link did not make it. I guess you meant to link this patch set [1]
-- Stefan
[1] https://lore.kernel.org/lkml/20240910151845.17308-1-svarbanov@suse.de/T/
Yes.
Regards, Ivan
participants (5)
-
Florian Fainelli
-
Ivan T. Ivanov
-
Matthias Brugger
-
Stefan Agner
-
Stefan Wahren