uboot-tools/ARM-RPi-PCIe-fixes.patch
2026-04-12 17:39:36 +01:00

172 lines
6.5 KiB
Diff

From 354971c474d8a595f3fc610942bf160ac9959343 Mon Sep 17 00:00:00 2001
From: Peter Robinson <pbrobinson@gmail.com>
Date: Sat, 11 Apr 2026 16:14:50 +0100
Subject: [PATCH 1/2] pci: brcmstb: fix iBAR inbound window address for
pre-BCM2712
The reworked brcm_pcie_set_inbound_windows() writes bar_pci (the raw
PCI bus address) directly into the RC BAR config register, and relies
on the UBUS remap registers to supply the CPU-side translation.
This model works on BCM2712 (RPi5), which has a capable UBUS/AXI
remap block. On BCM2711 (RPi4) the BAR config register expects the
address *offset* (bus_start - phys_start), not the raw bus address,
and the older UBUS remap registers cannot compensate for the
difference. The result is a misconfigured inbound DMA window that
renders the PCIe-attached XHCI USB controller non-functional.
Fix by branching on the chip type inside brcm_pcie_set_inbound_windows():
- Pre-BCM2712: write the offset (bus_start - phys_start) into the BAR
config register, matching the behaviour of the code that was removed.
Skip the UBUS remap registers because the older hardware does not
need them for a single DMA region and setting them to an incorrect
value causes the regression.
- BCM2712: keep the new behaviour unchanged (raw PCI address in BAR
config, CPU address in UBUS remap registers).
Also restore the power-of-two size rounding that was present in the
original code (1ULL << fls64(size - 1)) for pre-BCM2712 paths, since
brcm_pcie_encode_ibar_size() is documented to require a power-of-two
input and the DT size value is not guaranteed to already be one.
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
drivers/pci/pcie_brcmstb.c | 58 +++++++++++++++++++++++++++++---------
1 file changed, 44 insertions(+), 14 deletions(-)
diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c
index bd1dd17e690..796c3b9ff9c 100644
--- a/drivers/pci/pcie_brcmstb.c
+++ b/drivers/pci/pcie_brcmstb.c
@@ -476,10 +476,22 @@ static u32 brcm_ubus_reg_offset(int bar)
return PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + 8 * (bar - 4);
}
+/*
+ * Round size up to the next power of two, as required by
+ * brcm_pcie_encode_ibar_size(). If size is already a power of two
+ * fls64(size - 1) still gives the correct result because the hardware
+ * encodes the exponent, not the raw value.
+ */
+static u64 brcm_ibar_round_size(u64 size)
+{
+ return 1ULL << fls64(size - 1);
+}
+
static void brcm_pcie_set_inbound_windows(struct udevice *dev)
{
struct brcm_pcie *pcie = dev_get_priv(dev);
void __iomem *base = pcie->base;
+ bool is_2712 = (pcie->pcie_cfg->type == BCM2712);
int i, ibar_no, ret;
u32 tmp;
@@ -504,20 +516,38 @@ static void brcm_pcie_set_inbound_windows(struct udevice *dev)
bar_cpu = region.phys_start;
bar_size = region.size;
- tmp = lower_32_bits(bar_pci);
- u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size),
- RC_BAR2_CONFIG_LO_SIZE_MASK);
- writel(tmp, base + rc_bar_offset);
- writel(upper_32_bits(bar_pci), base + rc_bar_offset + 4);
-
- tmp = lower_32_bits(bar_cpu) &
- PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK;
- tmp |= PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE;
- writel(tmp, base + ubus_bar_offset);
-
- tmp = upper_32_bits(bar_cpu) &
- PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK;
- writel(tmp, base + ubus_bar_offset + 4);
+ if (is_2712) {
+ /* BCM2712: BAR holds raw PCI address; UBUS remap
+ * registers supply the CPU-side translation. */
+ tmp = lower_32_bits(bar_pci);
+ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size),
+ RC_BAR2_CONFIG_LO_SIZE_MASK);
+ writel(tmp, base + rc_bar_offset);
+ writel(upper_32_bits(bar_pci), base + rc_bar_offset + 4);
+
+ tmp = lower_32_bits(bar_cpu) &
+ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK;
+ tmp |= PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE;
+ writel(tmp, base + ubus_bar_offset);
+
+ tmp = upper_32_bits(bar_cpu) &
+ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK;
+ writel(tmp, base + ubus_bar_offset + 4);
+ } else {
+ /* Pre-BCM2712 (e.g. BCM2711 / RPi4): the BAR config
+ * register holds the offset (bus_start - phys_start),
+ * not the raw PCI address. The size must be rounded
+ * up to the next power of two before encoding. */
+ u64 bar_offset = bar_pci - bar_cpu;
+ u64 bar_size_po2 = brcm_ibar_round_size(bar_size);
+
+ tmp = lower_32_bits(bar_offset);
+ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size_po2),
+ RC_BAR2_CONFIG_LO_SIZE_MASK);
+ writel(tmp, base + rc_bar_offset);
+ writel(upper_32_bits(bar_offset), base + rc_bar_offset + 4);
+ /* UBUS remap registers are not used on pre-2712 hardware. */
+ }
}
}
--
2.53.0
From d03a2f8be5519519cd1336295cb8627f6a685c07 Mon Sep 17 00:00:00 2001
From: Peter Robinson <pbrobinson@gmail.com>
Date: Sat, 11 Apr 2026 16:21:31 +0100
Subject: [PATCH 2/2] pci: brcmstb: restore dynamic SCB0 size for pre-BCM2712
The reworked probe code hardcodes SCB0 size to 20 (32GB) for all chip
variants. On BCM2712 (RPi5) this is intentional. On BCM2711 (RPi4)
the original code derived the SCB0 size from the actual DMA region size
using ilog2(size) - 15, e.g. 1GB -> value 15 (0xf). Writing 20
instead misconfigures the inbound memory window and is the remaining
cause of the USB regression after the BAR offset fix.
Restore the dynamic calculation for pre-BCM2712 chips.
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
---
drivers/pci/pcie_brcmstb.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c
index 796c3b9ff9c..f0b0f1cc117 100644
--- a/drivers/pci/pcie_brcmstb.c
+++ b/drivers/pci/pcie_brcmstb.c
@@ -638,9 +638,22 @@ static int brcm_pcie_probe(struct udevice *dev)
MISC_CTRL_PCIE_RCB_MPS_MODE_MASK |
tmp);
- /* Enable 32GB memory to be accessed from PCIe in the SCB0 */
tmp = readl(base + PCIE_MISC_MISC_CTRL);
- u32p_replace_bits(&tmp, 20, MISC_CTRL_SCB0_SIZE_MASK);
+ if (pcie->pcie_cfg->type == BCM2712) {
+ /* BCM2712: fixed 32GB SCB0 window */
+ u32p_replace_bits(&tmp, 20, MISC_CTRL_SCB0_SIZE_MASK);
+ } else {
+ /* Pre-BCM2712: size SCB0 to match the actual DMA region.
+ * rc_bar2_size must be a power of two; ilog2(size) - 15
+ * gives the hardware encoding (e.g. 1GB -> 15). */
+ struct pci_region region;
+ u64 rc_bar2_size;
+
+ pci_get_dma_regions(dev, &region, 0);
+ rc_bar2_size = brcm_ibar_round_size(region.size);
+ u32p_replace_bits(&tmp, rc_bar2_size ? ilog2(rc_bar2_size) - 15 : 0xf,
+ MISC_CTRL_SCB0_SIZE_MASK);
+ }
writel(tmp, base + PCIE_MISC_MISC_CTRL);
if (pcie->pcie_cfg->type == BCM2712) {
--
2.53.0