[PATCH v4 3/9] pci: brcmstb: Support different variants using a cfg struct
Neil Armstrong
neil.armstrong at linaro.org
Tue May 26 09:08:03 CEST 2026
On 5/23/26 18:34, Torsten Duwe wrote:
> From: Torsten Duwe <duwe at suse.de>
>
> The Linux kernel driver already had support for multiple hardware
> variants when the bcm2712 was added (see e.g. linux commit
> 10dbedad3c818 which is the last in a longer set of changes). This
> patch brings in this required infrastructure and adds a
> differentiation between 2711 and 2712 register layouts on top.
>
> Signed-off-by: Torsten Duwe <duwe at suse.de>
> Co-authored-by: Oleksii Moisieiev <oleksii_moisieiev at epam.com>
> Tested-by: Pedro Falcato <pfalcato at suse.de>
> ---
> .../mach-bcm283x/include/mach/acpi/bcm2711.h | 5 +
> drivers/pci/pcie_brcmstb.c | 104 ++++++++++++++++--
> 2 files changed, 99 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h
> index a86875b1833..5171c593c72 100644
> --- a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h
> +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h
> @@ -70,6 +70,7 @@
> #define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
> #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
> #define RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
> +#define PCIE_MISC_PCIE_CTRL 0x4064
> #define PCIE_MISC_PCIE_STATUS 0x4068
> #define STATUS_PCIE_PORT_MASK 0x80
> #define STATUS_PCIE_PORT_SHIFT 7
> @@ -108,6 +109,10 @@
>
> #define PCIE_RGR1_SW_INIT_1 0x9210
> #define PCIE_EXT_CFG_INDEX 0x9000
> +#define RGR1_SW_INIT_1_PERST_MASK 0x1
> +#define RGR1_SW_INIT_1_PERSTB_MASK 0x4
> +#define RGR1_SW_INIT_1_INIT_MASK 0x2
> +
> /* A small window pointing at the ECAM of the device selected by CFG_INDEX */
> #define PCIE_EXT_CFG_DATA 0x8000
>
> diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c
> index 47c0802df23..5cb39dfd136 100644
> --- a/drivers/pci/pcie_brcmstb.c
> +++ b/drivers/pci/pcie_brcmstb.c
> @@ -49,6 +49,24 @@
> #define SSC_STATUS_PLL_LOCK_MASK 0x800
> #define SSC_STATUS_PLL_LOCK_SHIFT 11
>
> +enum {
> + RGR1_SW_INIT_1,
> + PCIE_HARD_DEBUG,
> +};
> +
> +enum brcm_pcie_type {
> + BCM2711,
> + BCM2712
> +};
> +
> +struct brcm_pcie;
> +
> +struct brcm_pcie_cfg_data {
> + const int *offsets;
> + const enum brcm_pcie_type type;
> + void (*perst_set)(struct brcm_pcie *pcie, u32 val);
> +};
> +
> /**
> * struct brcm_pcie - the PCIe controller state
> * @base: Base address of memory mapped IO registers of the controller
> @@ -61,6 +79,7 @@ struct brcm_pcie {
>
> int gen;
> bool ssc;
> + const struct brcm_pcie_cfg_data *pcie_cfg;
> };
>
> /**
> @@ -104,6 +123,36 @@ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
> return (val & STATUS_PCIE_PORT_MASK) >> STATUS_PCIE_PORT_SHIFT;
> }
>
> +static void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
> +{
> + if (val)
> + setbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1],
> + RGR1_SW_INIT_1_PERST_MASK);
> + else
> + clrbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1],
> + RGR1_SW_INIT_1_PERST_MASK);
> +}
> +
> +static void brcm_pcie_perst_set_2712(struct brcm_pcie *pcie, u32 val)
> +{
> + u32 tmp;
> +
> + /* Perst bit has moved and assert value is 0 */
> + tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL);
> + u32p_replace_bits(&tmp, !val, RGR1_SW_INIT_1_PERSTB_MASK);
> + writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL);
> +}
> +
> +static void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val)
> +{
> + if (val)
> + setbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1],
> + RGR1_SW_INIT_1_INIT_MASK);
> + else
> + clrbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1],
> + RGR1_SW_INIT_1_INIT_MASK);
> +}
> +
> /**
> * brcm_pcie_link_up() - Check whether the PCIe link is up
> * @pcie: Pointer to the PCIe controller state
> @@ -365,8 +414,9 @@ static int brcm_pcie_probe(struct udevice *dev)
> * e.g. BCM7278, the fundamental reset should not be asserted here.
> * This will need to be changed when support for other SoCs is added.
> */
> - setbits_le32(base + PCIE_RGR1_SW_INIT_1,
> - PCIE_RGR1_SW_INIT_1_INIT_MASK | PCIE_RGR1_SW_INIT_1_PERST_MASK);
> + brcm_pcie_bridge_sw_init_set(pcie, 1);
> + if (pcie->pcie_cfg->type != BCM2712)
> + pcie->pcie_cfg->perst_set(pcie, 1);
> /*
> * The delay is a safety precaution to preclude the reset signal
> * from looking like a glitch.
> @@ -374,9 +424,9 @@ static int brcm_pcie_probe(struct udevice *dev)
> udelay(100);
>
> /* Take the bridge out of reset */
> - clrbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK);
> + brcm_pcie_bridge_sw_init_set(pcie, 0);
>
> - clrbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
> + clrbits_le32(base + pcie->pcie_cfg->offsets[PCIE_HARD_DEBUG],
> PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
>
> /* Wait for SerDes to be stable */
> @@ -426,8 +476,7 @@ static int brcm_pcie_probe(struct udevice *dev)
> brcm_pcie_set_gen(pcie, pcie->gen);
>
> /* Unassert the fundamental reset */
> - clrbits_le32(pcie->base + PCIE_RGR1_SW_INIT_1,
> - PCIE_RGR1_SW_INIT_1_PERST_MASK);
> + pcie->pcie_cfg->perst_set(pcie, 0);
>
> /*
> * Wait for 100ms after PERST# deassertion; see PCIe CEM specification
> @@ -514,14 +563,25 @@ static int brcm_pcie_remove(struct udevice *dev)
> void __iomem *base = pcie->base;
>
> /* Assert fundamental reset */
> - setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST_MASK);
> + setbits_le32(base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1],
> + PCIE_RGR1_SW_INIT_1_PERST_MASK);
>
> /* Turn off SerDes */
> - setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
> + setbits_le32(base + pcie->pcie_cfg->offsets[PCIE_HARD_DEBUG],
> PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
>
> /* Shutdown bridge */
> - setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK);
> + brcm_pcie_bridge_sw_init_set(pcie, 1);
> +
> + /*
> + * For the controllers that are utilizing reset for bridge Sw init,
> + * such as BCM2712, reset should be deasserted after assertion.
> + * Leaving it in asserted state may lead to unexpected hangs in
> + * the Linux Kernel driver because it do not perform reset initialization
> + * and start accessing device memory.
> + */
> + if (pcie->pcie_cfg->type == BCM2712)
> + brcm_pcie_bridge_sw_init_set(pcie, 0);
>
> return 0;
> }
> @@ -546,6 +606,7 @@ static int brcm_pcie_of_to_plat(struct udevice *dev)
> else
> pcie->gen = max_link_speed;
>
> + pcie->pcie_cfg = (const struct brcm_pcie_cfg_data *)dev_get_driver_data(dev);
> return 0;
> }
>
> @@ -554,8 +615,31 @@ static const struct dm_pci_ops brcm_pcie_ops = {
> .write_config = brcm_pcie_write_config,
> };
>
> +static const int pcie_offsets[] = {
> + [RGR1_SW_INIT_1] = 0x9210,
> + [PCIE_HARD_DEBUG] = 0x4204,
> +};
> +
> +static const struct brcm_pcie_cfg_data bcm2711_cfg = {
> + .offsets = pcie_offsets,
> + .type = BCM2711,
> + .perst_set = brcm_pcie_perst_set_generic,
> +};
> +
> +static const int pcie_offsets_bcm2712[] = {
> + [RGR1_SW_INIT_1] = 0x0,
> + [PCIE_HARD_DEBUG] = 0x4304,
> +};
> +
> +static const struct brcm_pcie_cfg_data bcm2712_cfg = {
> + .offsets = pcie_offsets_bcm2712,
> + .type = BCM2712,
> + .perst_set = brcm_pcie_perst_set_2712,
> +};
> +
> static const struct udevice_id brcm_pcie_ids[] = {
> - { .compatible = "brcm,bcm2711-pcie" },
> + { .compatible = "brcm,bcm2711-pcie", .data = (ulong)&bcm2711_cfg },
> + { .compatible = "brcm,bcm2712-pcie", .data = (ulong)&bcm2712_cfg },
> { }
> };
>
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Thanks,
Neil
More information about the U-Boot
mailing list