New SoCs are coming that are not encumbered with a baroque internal memory mapping scheme or power-of-two restrictions on the sizes of inbound regsions. Enable the driver to use these SoCs. Signed-off-by: Jim Quinlan <james.quinlan@xxxxxxxxxxxx> --- drivers/pci/controller/pcie-brcmstb.c | 61 ++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 5c8aa5e36338..362ac083e112 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -152,6 +152,8 @@ #define PCIE_MSI_INTR2_BASE 0x4500 +#define PCIE_MISC2_BAR1_CONFIG_SIZE 0x4700 + /* Offsets from INTR2_CPU and MSI_INTR2 BASE offsets */ #define MSI_INT_STATUS 0x0 #define MSI_INT_CLR 0x8 @@ -282,6 +284,15 @@ enum pcie_soc_base { */ #define IS_CM_SOC(t) ((t) == BCM3162 || (t) == BCM33940 || (t) == BCM3392) +/* + * Newer chips (NG is "Next Generation") have simplified the design of how + * inbound regions are mapped to system memory as compared to previous STB + * designs. In addition, the inbound window size is not restricted to be a + * power of two. Such systems may or may not have an IOMMU between the RC + * and memory. + */ +#define IS_NG_PCI_SOC(t) (0) + struct inbound_win { u64 size; u64 pci_offset; @@ -1008,7 +1019,8 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie, * memory. That being said, each window's size must still * be a power of two. */ - if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base)) + if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base) + || IS_NG_PCI_SOC(pcie->cfg->soc_base)) add_inbound_win(b++, &n, size, cpu_start, pcie_start); if (n > pcie->cfg->num_inbound_wins) @@ -1020,6 +1032,22 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie, return -EINVAL; } + if (IS_NG_PCI_SOC(pcie->cfg->soc_base)) { + /* + * STB NG SoCs may still be limited with three inbound + * windows, and if so, the last one should be disabled. + */ + if (pcie->cfg->num_inbound_wins == 3) { + n = 2; + add_inbound_win(b++, &n, 0, 0, 0); + } + /* + * NG SoCs do not have internal mapping system that enables + * multiple memory controllers, so return now. + */ + return n; + } + /* * 7712, CM, and newer chips do not have an internal memory * mapping system that enables multiple memory controllers. As @@ -1120,6 +1148,17 @@ static u32 brcm_ubus_reg_offset(int bar) return PCIE_MISC_UBUS_BAR4_CONFIG_REMAP + 8 * (bar - 4); } +/* + * NG SoCs have configurable inbound region size registers (as opposed to + * having to set them to a power of two). There are multiple contiguous + * registers, one for each inbound window. This function provides the + * register offset for a specific window. + */ +static unsigned int brcm_calc_config_size_reg_offset(int bar) +{ + return PCIE_MISC2_BAR1_CONFIG_SIZE + (bar - 1) * 4; +} + static void set_inbound_win_registers(struct brcm_pcie *pcie, const struct inbound_win *inbound_wins, u8 num_inbound_wins) @@ -1134,6 +1173,24 @@ static void set_inbound_win_registers(struct brcm_pcie *pcie, u32 reg_offset = brcm_bar_reg_offset(i); u32 tmp = lower_32_bits(pci_offset); + if (IS_NG_PCI_SOC(pcie->cfg->soc_base)) { + /* PCIe address */ + writel(lower_32_bits(pci_offset), base + reg_offset); + writel(upper_32_bits(pci_offset), base + reg_offset + 4); + + /* Size of region */ + reg_offset = brcm_calc_config_size_reg_offset(i); + /* Register value has granularity of 4k units */ + writel(size >> 12, base + reg_offset); + + /* CPU address */ + reg_offset = brcm_ubus_reg_offset(i); + writel(lower_32_bits(cpu_addr), base + reg_offset); + writel(upper_32_bits(cpu_addr), base + reg_offset + 4); + + continue; + } + u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(size), PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK); @@ -1264,6 +1321,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) */ if (IS_CM_SOC(pcie->cfg->soc_base)) pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_FOR_CM; + else if (IS_NG_PCI_SOC(pcie->cfg->soc_base)) + pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; else if (inbound_wins[2].pci_offset >= SZ_4G || (inbound_wins[2].size + inbound_wins[2].pci_offset) < SZ_4G) pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB; -- 2.34.1