[PATCH v2 8/9] pci: brcmstb: rework iBAR handling

Neil Armstrong neil.armstrong at linaro.org
Wed May 6 16:37:28 CEST 2026


On 4/28/26 18:39, Torsten Duwe wrote:
> From: Torsten Duwe <duwe at suse.de>
> 
> Rework the setup of inbound PCIe windows: use the convenience functions
> from Linux kernel commit ae6476c6de187 to calculate the BAR offsets and
> factor out the setup code into a separate function.
> 
> The Linux kernel first allocates and populates an array of inbound_win[]
> and sets the BARs from it later, while U-Boot does it all on the fly,
> in one go, so the code is not 1:1 comparable.
> 
> Signed-off-by: Torsten Duwe <duwe at suse.de>
> Tested-by: Pedro Falcato <pfalcato at suse.de>
> 
> ---
>   drivers/pci/pcie_brcmstb.c | 150 ++++++++++++++++++++++++++++++++-----
>   1 file changed, 131 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c
> index 8a25fb04563..05b80a45b50 100644
> --- a/drivers/pci/pcie_brcmstb.c
> +++ b/drivers/pci/pcie_brcmstb.c
> @@ -50,6 +50,29 @@
>   #define SSC_STATUS_PLL_LOCK_MASK			0x800
>   #define SSC_STATUS_PLL_LOCK_SHIFT			11
>   
> +#define PCIE_RC_PL_PHY_CTL_15				0x184c
> +#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK		0x400000
> +#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK	0xff
> +
> +#define PCIE_MISC_UBUS_CTRL				0x40a4
> +#define  PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK	BIT(13)
> +#define  PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK	BIT(19)
> +#define PCIE_MISC_AXI_READ_ERROR_DATA			0x4170
> +#define PCIE_MISC_UBUS_TIMEOUT				0x40A8
> +#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT		0x405c
> +#define PCIE_MISC_RC_BAR4_CONFIG_LO			0x40d4
> +#define PCIE_MISC_RC_BAR4_CONFIG_HI			0x40d8
> +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK		0xff
> +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI		0x4110
> +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE		0x1
> +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK		0xfffff000
> +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO		0x410c
> +
> +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP		0x40ac
> +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP		0x40b4
> +#define  PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK	BIT(0)
> +#define  MISC_CTRL_PCIE_RCB_MPS_MODE_MASK		0x400
> +
>   enum {
>   	RGR1_SW_INIT_1,
>   	EXT_CFG_INDEX,
> @@ -437,17 +460,105 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
>   	writel(tmp, base + PCIE_MEM_WIN0_LIMIT_HI(win));
>   }
>   
> +static u32 brcm_bar_reg_offset(int bar)
> +{
> +	if (bar <= 3)
> +		return PCIE_MISC_RC_BAR1_CONFIG_LO + 8 * (bar - 1);
> +	else
> +		return PCIE_MISC_RC_BAR4_CONFIG_LO + 8 * (bar - 4);
> +}
> +
> +static u32 brcm_ubus_reg_offset(int bar)
> +{
> +	if (bar <= 3)
> +		return PCIE_MISC_UBUS_BAR1_CONFIG_REMAP + 8 * (bar - 1);
> +	else
> +		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;
> +
> +	ibar_no = 0;
> +	/* pre-2712 chips leave the first entry empty */
> +	if (pcie->pcie_cfg->type != BCM2712)
> +		ibar_no++;
> +
> +	/* program inbound windows from OF property "dma-regions" */
> +	for (i = 0; i < 7; i++, ibar_no++) {
> +		u64 bar_cpu, bar_size, bar_pci;
> +		struct pci_region region;
> +		int ubus_bar_offset, rc_bar_offset;
> +
> +		ret = pci_get_dma_regions(dev, &region, i);
> +		if (ret)	/* no region #i? Then we're done. */
> +			break;
> +		ubus_bar_offset = brcm_ubus_reg_offset(ibar_no + 1);
> +		rc_bar_offset = brcm_bar_reg_offset(ibar_no + 1);
> +
> +		bar_pci = region.bus_start;
> +		bar_cpu = region.phys_start;
> +		bar_size = region.size;
> +
> +		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. */
> +		}
> +	}
> +}
> +
>   static int brcm_pcie_probe(struct udevice *dev)
>   {
>   	struct udevice *ctlr = pci_get_controller(dev);
>   	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
>   	struct brcm_pcie *pcie = dev_get_priv(dev);
>   	void __iomem *base = pcie->base;
> -	struct pci_region region;
>   	bool ssc_good = false;
>   	int num_out_wins = 0;
> -	u64 rc_bar2_offset, rc_bar2_size;
> -	unsigned int scb_size_val;
>   	int i, ret;
>   	u16 nlw, cls, lnksta;
>   	u32 tmp;
> @@ -488,23 +599,22 @@ static int brcm_pcie_probe(struct udevice *dev)
>   			MISC_CTRL_CFG_READ_UR_MODE_MASK |
>   			MISC_CTRL_MAX_BURST_SIZE_128);
>   
> -	pci_get_dma_regions(dev, &region, 0);
> -	rc_bar2_offset = region.bus_start - region.phys_start;
> -	rc_bar2_size = 1ULL << fls64(region.size - 1);
> -
> -	tmp = lower_32_bits(rc_bar2_offset);
> -	u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size),
> -			  RC_BAR2_CONFIG_LO_SIZE_MASK);
> -	writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
> -	writel(upper_32_bits(rc_bar2_offset),
> -	       base + PCIE_MISC_RC_BAR2_CONFIG_HI);
> -
> -	scb_size_val = rc_bar2_size ?
> -		       ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
> -
>   	tmp = readl(base + PCIE_MISC_MISC_CTRL);
> -	u32p_replace_bits(&tmp, scb_size_val,
> -			  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);
>   
>   	/* Disable the PCIe->GISB memory window (RC_BAR1) */
> @@ -521,6 +631,8 @@ static int brcm_pcie_probe(struct udevice *dev)
>   	/* Clear any interrupts we find on boot */
>   	writel(0xffffffff, base + PCIE_MSI_INTR2_CLR);
>   
> +	brcm_pcie_set_inbound_windows(dev);
> +
>   	if (pcie->gen)
>   		brcm_pcie_set_gen(pcie, pcie->gen);
>   

Looks fine

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>

Thanks,
Neil


More information about the U-Boot mailing list