pci: brcmstb: rework iBAR handling

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@suse.de>
Tested-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
This commit is contained in:
Torsten Duwe
2026-06-04 10:50:04 +01:00
committed by Peter Robinson
parent df883ec51b
commit 585d6cfd9b
+131 -19
View File
@@ -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,
PCIE_HARD_DEBUG,
@@ -441,17 +464,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 = 0;
u16 nlw, cls, lnksta;
u32 tmp;
@@ -496,23 +607,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) */
@@ -529,6 +639,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);