From b20ce94bb9d06c0bffe6cf0b2795fb021f7c0052 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:20 +0200 Subject: ARM: bcm283x: Add bcm2712 PCIe memory window Add a mapping region for the PCIe bus address spaces to the BCM2712 memory controller setup. Generously merging the PCIe address spaces works sufficiently well for a boot loader. Signed-off-by: Torsten Duwe Co-authored-by: Oleksii Moisieiev Tested-by: Pedro Falcato Reviewed-by: Peter Robinson --- arch/arm/mach-bcm283x/init.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-bcm283x/init.c b/arch/arm/mach-bcm283x/init.c index 7a1de22e0ae..7a2faaa4de6 100644 --- a/arch/arm/mach-bcm283x/init.c +++ b/arch/arm/mach-bcm283x/init.c @@ -18,7 +18,7 @@ #ifdef CONFIG_ARM64 #include -#define MEM_MAP_MAX_ENTRIES (4) +#define MEM_MAP_MAX_ENTRIES (5) static struct mm_region bcm283x_mem_map[MEM_MAP_MAX_ENTRIES] = { { @@ -83,6 +83,14 @@ static struct mm_region bcm2712_mem_map[MEM_MAP_MAX_ENTRIES] = { .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* Whole PCIe section */ + .virt = 0x1800000000UL, + .phys = 0x1800000000UL, + .size = 0x0800000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN }, { /* SoC bus */ .virt = 0x107c000000UL, -- cgit v1.3.1 From b24c620e5e129277d50cceac2d758e8c5bf53293 Mon Sep 17 00:00:00 2001 From: Andrea della Porta Date: Mon, 1 Jun 2026 12:39:23 +0200 Subject: pci: brcmstb: Fix PCIe bus numbers The linux kernel assigns a new domain for every Root Complex where bus numbering starts from 0 for each domain. U-Boot does not have domains and uses a flattened bus numbering scheme instead. This means that any device or bridge on the second enumerated RC will receive a bus number equal to the last assigned one +1. This bus number contributes to the address written into the index register, which will select the configuration space to be read. Compensate for this contribution by subtracting the base bus number. Signed-off-by: Andrea della Porta Signed-off-by: Torsten Duwe Tested-by: Pedro Falcato Reviewed-by: Peter Robinson --- drivers/pci/pcie_brcmstb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index f089c48f028..47c0802df23 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -125,7 +125,7 @@ static int brcm_pcie_config_address(const struct udevice *dev, pci_dev_t bdf, uint offset, void **paddress) { struct brcm_pcie *pcie = dev_get_priv(dev); - unsigned int pci_bus = PCI_BUS(bdf); + unsigned int pci_bus = PCI_BUS(bdf) - dev_seq(dev); unsigned int pci_dev = PCI_DEV(bdf); unsigned int pci_func = PCI_FUNC(bdf); int idx; -- cgit v1.3.1 From d0b2a1cb3f33b63c316ad30aa9fda8ff02a6b01b Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:25 +0200 Subject: pci: brcmstb: Support different variants using a cfg struct 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 Co-authored-by: Oleksii Moisieiev Tested-by: Pedro Falcato Reviewed-by: Neil Armstrong --- arch/arm/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 }, { } }; -- cgit v1.3.1 From 64ae1351b5203581a512ad8510e45870fdef4409 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:27 +0200 Subject: reset: Add RPi5 brcmstb reset facilities A driver for Broadcom reset controllers ported from linux/drivers/reset/reset-brcmstb.c to U-Boot. Signed-off-by: Torsten Duwe Co-authored-by: Oleksii Moisieiev Tested-by: Pedro Falcato --- configs/rpi_arm64_defconfig | 1 + drivers/reset/Kconfig | 8 ++++ drivers/reset/Makefile | 1 + drivers/reset/reset-brcmstb.c | 97 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 drivers/reset/reset-brcmstb.c diff --git a/configs/rpi_arm64_defconfig b/configs/rpi_arm64_defconfig index 69e8e72c5d7..153d7ed301e 100644 --- a/configs/rpi_arm64_defconfig +++ b/configs/rpi_arm64_defconfig @@ -44,6 +44,7 @@ CONFIG_BCMGENET=y CONFIG_PCI_BRCMSTB=y CONFIG_PINCTRL=y # CONFIG_PINCTRL_GENERIC is not set +CONFIG_RESET_BRCMSTB=y CONFIG_DM_RNG=y CONFIG_RNG_IPROC200=y # CONFIG_REQUIRE_SERIAL_CONSOLE is not set diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index ebf484d9df4..7f1b2a304e3 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -64,6 +64,14 @@ config RESET_BCM6345 help Support reset controller on BCM6345. +config RESET_BRCMSTB + depends on ARCH_BCM283X + bool "Generic Reset controller driver for Broadcom" + help + This enables reset controller for Broadcom devices. + If you wish to use reset resources managed by the Broadcom + Reset Controller, say Y here. Otherwise, say N. + config RESET_UNIPHIER bool "Reset controller driver for UniPhier SoCs" depends on ARCH_UNIPHIER diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 088545c6473..ad5fe6b6184 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_RESET_AIROHA) += reset-airoha.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o +obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_AST2500) += reset-ast2500.o obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o diff --git a/drivers/reset/reset-brcmstb.c b/drivers/reset/reset-brcmstb.c new file mode 100644 index 00000000000..7861f7c9baf --- /dev/null +++ b/drivers/reset/reset-brcmstb.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Broadcom STB generic reset controller + * + * Copyright (C) 2024 EPAM Systems + * + * Moved from linux kernel: + * Author: Florian Fainelli + * Copyright (C) 2018 Broadcom + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct brcmstb_reset { + void __iomem *base; +}; + +#define SW_INIT_SET 0x00 +#define SW_INIT_CLEAR 0x04 +#define SW_INIT_STATUS 0x08 + +#define SW_INIT_BIT(id) BIT((id) & 0x1f) +#define SW_INIT_BANK(id) ((id) >> 5) + +#define usleep_range(a, b) udelay((b)) + +/* A full bank contains extra registers that we are not utilizing but still + * qualify as a single bank. + */ +#define SW_INIT_BANK_SIZE 0x18 + +static int brcmstb_reset_assert(struct reset_ctl *rst) +{ + unsigned int off = SW_INIT_BANK(rst->id) * SW_INIT_BANK_SIZE; + struct brcmstb_reset *priv = dev_get_priv(rst->dev); + + writel_relaxed(SW_INIT_BIT(rst->id), priv->base + off + SW_INIT_SET); + return 0; +} + +static int brcmstb_reset_deassert(struct reset_ctl *rst) +{ + unsigned int off = SW_INIT_BANK(rst->id) * SW_INIT_BANK_SIZE; + struct brcmstb_reset *priv = dev_get_priv(rst->dev); + + writel_relaxed(SW_INIT_BIT(rst->id), priv->base + off + SW_INIT_CLEAR); + /* Maximum reset delay after de-asserting a line and seeing block + * operation is typically 14us for the worst case, build some slack + * here. + */ + usleep_range(100, 200); + return 0; +} + +static int brcmstb_reset_status(struct reset_ctl *rst) +{ + unsigned int off = SW_INIT_BANK(rst->id) * SW_INIT_BANK_SIZE; + struct brcmstb_reset *priv = dev_get_priv(rst->dev); + + return readl_relaxed(priv->base + off + SW_INIT_STATUS) & + SW_INIT_BIT(rst->id); +} + +struct reset_ops brcmstb_reset_reset_ops = { + .rst_assert = brcmstb_reset_assert, + .rst_deassert = brcmstb_reset_deassert, + .rst_status = brcmstb_reset_status}; + +static int brcmstb_reset_probe(struct udevice *dev) +{ + struct brcmstb_reset *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + return 0; +} + +static const struct udevice_id brcmstb_reset_ids[] = { + {.compatible = "brcm,brcmstb-reset"}, {/* sentinel */}}; + +U_BOOT_DRIVER(brcmstb_reset) = { + .name = "brcmstb-reset", + .id = UCLASS_RESET, + .of_match = brcmstb_reset_ids, + .ops = &brcmstb_reset_reset_ops, + .probe = brcmstb_reset_probe, + .priv_auto = sizeof(struct brcmstb_reset), +}; -- cgit v1.3.1 From af4f915fd6d2ec9cc024a4d528cebc9c44d15036 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:29 +0200 Subject: reset: Add RPi5 rescal reset facilities A driver for Broadcom rescal reset controllers ported from linux/drivers/reset/reset-brcmstb-rescal.c to U-Boot. Signed-off-by: Torsten Duwe Co-authored-by: Oleksii Moisieiev Tested-by: Pedro Falcato --- configs/rpi_arm64_defconfig | 1 + drivers/reset/Kconfig | 8 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-brcmstb-rescal.c | 103 +++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 drivers/reset/reset-brcmstb-rescal.c diff --git a/configs/rpi_arm64_defconfig b/configs/rpi_arm64_defconfig index 153d7ed301e..38af5029403 100644 --- a/configs/rpi_arm64_defconfig +++ b/configs/rpi_arm64_defconfig @@ -45,6 +45,7 @@ CONFIG_PCI_BRCMSTB=y CONFIG_PINCTRL=y # CONFIG_PINCTRL_GENERIC is not set CONFIG_RESET_BRCMSTB=y +CONFIG_RESET_BRCMSTB_RESCAL=y CONFIG_DM_RNG=y CONFIG_RNG_IPROC200=y # CONFIG_REQUIRE_SERIAL_CONSOLE is not set diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 7f1b2a304e3..485f907b041 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -72,6 +72,14 @@ config RESET_BRCMSTB If you wish to use reset resources managed by the Broadcom Reset Controller, say Y here. Otherwise, say N. +config RESET_BRCMSTB_RESCAL + depends on ARCH_BCM283X + bool "Generic Rescal Reset controller driver for Broadcom" + help + Support rescal reset controller on Broadcom. + If you wish to use reset resources managed by the Broadcom + Reset Controller, say Y here. Otherwise, say N. + config RESET_UNIPHIER bool "Reset controller driver for UniPhier SoCs" depends on ARCH_UNIPHIER diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index ad5fe6b6184..c369bdb3d6c 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o +obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_AST2500) += reset-ast2500.o obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o diff --git a/drivers/reset/reset-brcmstb-rescal.c b/drivers/reset/reset-brcmstb-rescal.c new file mode 100644 index 00000000000..fc8fcfa8b3f --- /dev/null +++ b/drivers/reset/reset-brcmstb-rescal.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Broadcom STB generic reset controller + * + * Copyright (C) 2024 EPAM Systems + * Moved from linux kernel: + * Copyright (C) 2018-2020 Broadcom + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BRCM_RESCAL_START 0x0 +#define BRCM_RESCAL_START_BIT BIT(0) +#define BRCM_RESCAL_CTRL 0x4 +#define BRCM_RESCAL_STATUS 0x8 +#define BRCM_RESCAL_STATUS_BIT BIT(0) + +struct brcm_rescal_reset { + void __iomem *base; +}; + +/* Also doubles a deassert */ +static int brcm_rescal_reset_set(struct reset_ctl *rst) +{ + struct brcm_rescal_reset *data = dev_get_priv(rst->dev); + void __iomem *base = data->base; + u32 reg; + int ret; + + reg = readl(base + BRCM_RESCAL_START); + writel(reg | BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START); + reg = readl(base + BRCM_RESCAL_START); + if (!(reg & BRCM_RESCAL_START_BIT)) { + dev_err(rst->dev, "failed to start SATA/PCIe rescal\n"); + return -EIO; + } + + ret = readl_poll_timeout(base + BRCM_RESCAL_STATUS, reg, + (reg & BRCM_RESCAL_STATUS_BIT), 100); + if (ret) { + dev_err(rst->dev, "time out on SATA/PCIe rescal\n"); + return ret; + } + + reg = readl(base + BRCM_RESCAL_START); + writel(reg & ~BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START); + + dev_dbg(rst->dev, "SATA/PCIe rescal success\n"); + return 0; +} + +/* A dummy function - deassert/reset does all the work */ +static int brcm_rescal_reset_assert(struct reset_ctl *rst) +{ + return 0; +} + +static int brcm_rescal_reset_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + /* This is needed if #reset-cells == 0. */ + return 0; +} + +static const struct reset_ops brcm_rescal_reset_ops = { + .rst_deassert = brcm_rescal_reset_set, + .rst_assert = brcm_rescal_reset_assert, + .of_xlate = brcm_rescal_reset_xlate, +}; + +static int brcm_rescal_reset_probe(struct udevice *dev) +{ + struct brcm_rescal_reset *data = dev_get_priv(dev); + + data->base = dev_remap_addr(dev); + if (!data->base) + return -EINVAL; + + return 0; +} + +static const struct udevice_id brcm_rescal_reset_of_match[] = { + {.compatible = "brcm,bcm7216-pcie-sata-rescal"}, + {}, +}; + +U_BOOT_DRIVER(brcmstb_reset_rescal) = { + .name = "brcmstb-reset-rescal", + .id = UCLASS_RESET, + .of_match = brcm_rescal_reset_of_match, + .ops = &brcm_rescal_reset_ops, + .probe = brcm_rescal_reset_probe, + .priv_auto = sizeof(struct brcm_rescal_reset), +}; -- cgit v1.3.1 From b6f853f1cc5ce3f7bc2da2a6df421c300858ea8a Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:31 +0200 Subject: pci: brcmstb: Get and use bridge and rescal reset properties Check whether the device tree has nodes for the two reset controls and use them if so. Signed-off-by: Torsten Duwe Co-authored-by: Oleksii Moisieiev Tested-by: Pedro Falcato Reviewed-by: Neil Armstrong --- drivers/pci/pcie_brcmstb.c | 71 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index 5cb39dfd136..012b501078a 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -21,6 +21,7 @@ #include #include #include +#include /* PCIe parameters */ #define BRCM_NUM_PCIE_OUT_WINS 4 @@ -79,6 +80,8 @@ struct brcm_pcie { int gen; bool ssc; + struct reset_ctl rescal; + struct reset_ctl bridge_reset; const struct brcm_pcie_cfg_data *pcie_cfg; }; @@ -143,14 +146,58 @@ static void brcm_pcie_perst_set_2712(struct brcm_pcie *pcie, u32 val) writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); } -static void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) +static int brcm_pcie_get_resets_dt(struct udevice *dev) { + struct brcm_pcie *pcie = dev_get_priv(dev); + int ret; + + ret = reset_get_by_name(dev, "rescal", &pcie->rescal); + if (ret) { + printf("Unable to get rescal reset\n"); + return ret; + } + + ret = reset_get_by_name(dev, "bridge", &pcie->bridge_reset); + if (ret) + printf("Unable to get bridge reset\n"); + + return ret; +} + +static int brcm_pcie_do_reset(struct udevice *dev) +{ + struct brcm_pcie *pcie = dev_get_priv(dev); + int ret; + + ret = reset_deassert(&pcie->rescal); + if (ret) + printf("failed to deassert 'rescal'\n"); + return ret; +} + +static int brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) +{ + int ret = 0; + + if (reset_valid(&pcie->bridge_reset)) + { + if (val) + ret = reset_assert(&pcie->bridge_reset); + else + ret = reset_deassert(&pcie->bridge_reset); + if (ret) + log_err("failed to %sassert bridge reset, err=%d\n", + val ? "" : "de", ret); + return ret; + } + 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); + return 0; } /** @@ -405,16 +452,25 @@ static int brcm_pcie_probe(struct udevice *dev) int num_out_wins = 0; u64 rc_bar2_offset, rc_bar2_size; unsigned int scb_size_val; - int i, ret; + int i, ret = 0; u16 nlw, cls, lnksta; u32 tmp; + /* + * Ensure rescal reset for BCM2712 is really disabled. + */ + if (pcie->pcie_cfg->type == BCM2712) + ret = brcm_pcie_do_reset(dev); + if (ret) + return ret; /* * Reset the bridge, assert the fundamental reset. Note for some SoCs, * e.g. BCM7278, the fundamental reset should not be asserted here. * This will need to be changed when support for other SoCs is added. */ - brcm_pcie_bridge_sw_init_set(pcie, 1); + ret = brcm_pcie_bridge_sw_init_set(pcie, 1); + if (ret) + return ret; if (pcie->pcie_cfg->type != BCM2712) pcie->pcie_cfg->perst_set(pcie, 1); /* @@ -424,8 +480,9 @@ static int brcm_pcie_probe(struct udevice *dev) udelay(100); /* Take the bridge out of reset */ - brcm_pcie_bridge_sw_init_set(pcie, 0); - + ret = brcm_pcie_bridge_sw_init_set(pcie, 0); + if (ret) + return ret; clrbits_le32(base + pcie->pcie_cfg->offsets[PCIE_HARD_DEBUG], PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); @@ -607,6 +664,10 @@ static int brcm_pcie_of_to_plat(struct udevice *dev) pcie->gen = max_link_speed; pcie->pcie_cfg = (const struct brcm_pcie_cfg_data *)dev_get_driver_data(dev); + + if (pcie->pcie_cfg->type == BCM2712) + return brcm_pcie_get_resets_dt(dev); + return 0; } -- cgit v1.3.1 From df883ec51b5b602b68a517bc513eaba3b115d890 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:34 +0200 Subject: pci: brcmstb: Fix iBAR size calculation Fix inbound window size calculation, like Linux commit 25a98c7270156. Signed-off-by: Torsten Duwe Tested-by: Pedro Falcato Reviewed-by: Neil Armstrong --- drivers/pci/pcie_brcmstb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index 012b501078a..164d8e2b7fe 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -101,8 +101,8 @@ static int brcm_pcie_encode_ibar_size(u64 size) if (log2_in >= 12 && log2_in <= 15) /* Covers 4KB to 32KB (inclusive) */ return (log2_in - 12) + 0x1c; - else if (log2_in >= 16 && log2_in <= 37) - /* Covers 64KB to 32GB, (inclusive) */ + else if (log2_in >= 16 && log2_in <= 36) + /* Covers 64KB to 64GB, (inclusive) */ return log2_in - 15; /* Something is awry so disable */ -- cgit v1.3.1 From 585d6cfd9b6b886ddfde9b66c9399eadb5086936 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:36 +0200 Subject: 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 Tested-by: Pedro Falcato Reviewed-by: Neil Armstrong --- 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 164d8e2b7fe..624376fe235 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, 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, ®ion, 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, ®ion, 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, ®ion, 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); -- cgit v1.3.1 From de9ea19cf77817c6de2b74d26cfc18d648f88e03 Mon Sep 17 00:00:00 2001 From: Torsten Duwe Date: Mon, 1 Jun 2026 12:39:40 +0200 Subject: pci: brcmstb: Adapt to AXI bridge Fix-ups for the BCM root complex when it is located behind an AXI bridge and clocked with 54MHz. Some are from kernel commit 377bced88c326, some where picked by Oleksii off a now-stale older branch. All reworked for the simpler setup code in U-Boot. Signed-off-by: Torsten Duwe Co-authored-by: Oleksii Moisieiev Tested-by: Pedro Falcato Reviewed-by: Neil Armstrong --- arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h | 1 + drivers/pci/pcie_brcmstb.c | 64 ++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h index 5171c593c72..c72b47e1b10 100644 --- a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h @@ -54,6 +54,7 @@ #define MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 #define MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 #define MISC_CTRL_MAX_BURST_SIZE_128 0x0 +#define MISC_CTRL_MAX_BURST_SIZE_128_2712 0x100000 #define MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index 624376fe235..1b03b0a7b05 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -555,6 +555,30 @@ static void brcm_pcie_set_inbound_windows(struct udevice *dev) } } +static void brcm_pcie_munge_pll(struct brcm_pcie *pcie) +{ + u32 tmp; + int ret, i; + u8 regs[] = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e }; + u16 data[] = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 }; + + ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, + 0x1600); + for (i = 0; i < ARRAY_SIZE(regs); i++) { + brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp); + debug("PCIE MDIO pre_refclk 0x%02x = 0x%04x\n", + regs[i], tmp); + } + for (i = 0; i < ARRAY_SIZE(regs); i++) { + brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regs[i], data[i]); + brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp); + debug("PCIE MDIO post_refclk 0x%02x = 0x%04x\n", + regs[i], tmp); + } + + udelay(200); +} + static int brcm_pcie_probe(struct udevice *dev) { struct udevice *ctlr = pci_get_controller(dev); @@ -600,12 +624,27 @@ static int brcm_pcie_probe(struct udevice *dev) /* Wait for SerDes to be stable */ udelay(100); + if (pcie->pcie_cfg->type == BCM2712) { + /* Allow a 54MHz (xosc) refclk source */ + brcm_pcie_munge_pll(pcie); + /* Fix for L1SS errata */ + tmp = readl(base + PCIE_RC_PL_PHY_CTL_15); + tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK; + /* PM clock period is 18.52ns (round down) */ + tmp |= 0x12; + writel(tmp, base + PCIE_RC_PL_PHY_CTL_15); + } + + tmp = (pcie->pcie_cfg->type == BCM2712) ? + MISC_CTRL_MAX_BURST_SIZE_128_2712 : + MISC_CTRL_MAX_BURST_SIZE_128; /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ clrsetbits_le32(base + PCIE_MISC_MISC_CTRL, MISC_CTRL_MAX_BURST_SIZE_MASK, MISC_CTRL_SCB_ACCESS_EN_MASK | MISC_CTRL_CFG_READ_UR_MODE_MASK | - MISC_CTRL_MAX_BURST_SIZE_128); + MISC_CTRL_PCIE_RCB_MPS_MODE_MASK | + tmp); tmp = readl(base + PCIE_MISC_MISC_CTRL); if (pcie->pcie_cfg->type == BCM2712) { @@ -625,6 +664,29 @@ static int brcm_pcie_probe(struct udevice *dev) } writel(tmp, base + PCIE_MISC_MISC_CTRL); + if (pcie->pcie_cfg->type == BCM2712) { + /* Suppress AXI error responses and return 1s for read failures */ + tmp = readl(base + PCIE_MISC_UBUS_CTRL); + u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK); + u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK); + writel(tmp, base + PCIE_MISC_UBUS_CTRL); + writel(0xffffffff, base + PCIE_MISC_AXI_READ_ERROR_DATA); + + /* + * Adjust timeouts. The UBUS timeout also affects CRS + * completion retries, as the request will get terminated if + * either timeout expires, so both have to be a large value + * (in clocks of 750MHz). + * Set UBUS timeout to 250ms, then set RC config retry timeout + * to be ~240ms. + * + * Setting CRSVis=1 will stop the core from blocking on a CRS + * response, but does require the device to be well-behaved... + */ + writel(0xB2D0000, base + PCIE_MISC_UBUS_TIMEOUT); + writel(0xABA0000, base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT); + } + /* Disable the PCIe->GISB memory window (RC_BAR1) */ clrbits_le32(base + PCIE_MISC_RC_BAR1_CONFIG_LO, RC_BAR1_CONFIG_LO_SIZE_MASK); -- cgit v1.3.1