Broadcom's Cable Modem (CM) group also uses this PCIe driver as it shares the PCIe HW core with the STB group. Make the modifications to enable the CM SoCs. Signed-off-by: Jim Quinlan <james.quinlan@xxxxxxxxxxxx> --- drivers/pci/controller/pcie-brcmstb.c | 186 +++++++++++++++++++++----- 1 file changed, 152 insertions(+), 34 deletions(-) diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index db7872cda960..e25dbcdc56a7 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -51,6 +51,9 @@ #define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8 #define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8 +#define PCIE_RC_DL_PDL_CONTROL_4 0x1010 +#define PCIE_RC_DL_PDL_CONTROL_4_NPH_FC_INIT_MASK 0xff000000 + #define PCIE_RC_DL_MDIO_ADDR 0x1100 #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 #define PCIE_RC_DL_MDIO_RD_DATA 0x1108 @@ -60,6 +63,7 @@ #define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff #define PCIE_MISC_MISC_CTRL 0x4008 +#define PCIE_MISC_MISC_CTRL_PCIE_IN_CPL_RO_MASK 0x20 #define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80 #define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400 #define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 @@ -170,6 +174,7 @@ /* MSI target addresses */ #define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL #define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL +#define BRCM_MSI_TARGET_ADDR_FOR_CM 0xfffffffffcULL /* MDIO registers */ #define MDIO_PORT0 0x0 @@ -223,13 +228,23 @@ enum { enum pcie_soc_base { GENERIC, BCM2711, + BCM3162, + BCM3392, + BCM3390, BCM4908, BCM7278, BCM7425, BCM7435, BCM7712, + BCM33940, }; +/* + * BCM3390 CM chip actually conforms to STB design, so it + * is not present in the macro below. + */ +#define IS_CM_SOC(t) ((t) == BCM3162 || (t) == BCM33940 || (t) == BCM3392) + struct inbound_win { u64 size; u64 pci_offset; @@ -757,6 +772,9 @@ static int brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val) u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT; int ret = 0; + if (IS_CM_SOC(pcie->cfg->soc_base)) + return 0; + if (pcie->bridge_reset) { if (val) ret = reset_control_assert(pcie->bridge_reset); @@ -891,13 +909,13 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie, struct inbound_win *b = b_begin; /* - * STB chips beside 7712 disable the first inbound window default. - * Rather being mapped to system memory it is mapped to the - * internal registers of the SoC. This feature is deprecated, has - * security considerations, and is not implemented in our modern - * SoCs. + * STB chips beside CM chips and 7712 disable the first inbound + * window default. Rather being mapped to system memory it is + * mapped to the internal registers of the SoC. This feature is + * deprecated, has security considerations, and is not + * implemented in our modern SoCs. */ - if (pcie->cfg->soc_base != BCM7712) + if (pcie->cfg->soc_base != BCM7712 && !IS_CM_SOC(pcie->cfg->soc_base)) add_inbound_win(b++, &n, 0, 0, 0); resource_list_for_each_entry(entry, &bridge->dma_ranges) { @@ -905,16 +923,32 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie, u64 cpu_start = entry->res->start; size = resource_size(entry->res); + + /* + * For BCM3390, single dma-range may map to the SoC + * register space in [0xf0000000..0xffffffff]. If present, + * this has to be assigned to inbound window #1, as this is + * the only one that HW allows to map to register space. + * So if we see this range, place it in inbound_wins[1] + * which is previously disabled (zeroed out). + */ + if (pcie->cfg->soc_base == BCM3390 && cpu_start >= 0xf0000000 + && cpu_start + size - 1 <= 0xffffffff) { + add_inbound_win(b_begin, &n, size, cpu_start, pcie_start); + n--; + continue; + } + tot_size += size; if (pcie_start < lowest_pcie_addr) lowest_pcie_addr = pcie_start; /* - * 7712 and newer chips may have many BARs, with each - * offering a non-overlapping viewport to system memory. - * That being said, each BARs size must still be a power of - * two. + * 7712, CM, and newer chips may have many inbound windows, + * with each offering a non-overlapping viewport to system + * memory. That being said, each window's size must still + * be a power of two. */ - if (pcie->cfg->soc_base == BCM7712) + if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base)) add_inbound_win(b++, &n, size, cpu_start, pcie_start); if (n > pcie->cfg->num_inbound_wins) @@ -927,11 +961,11 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie, } /* - * 7712 and newer chips do not have an internal memory mapping system - * that enables multiple memory controllers. As such, it can return - * now w/o doing special configuration. + * 7712, CM, and newer chips do not have an internal memory + * mapping system that enables multiple memory controllers. As + * such, it can return now w/o doing special configuration. */ - if (pcie->cfg->soc_base == BCM7712) + if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base)) return n; ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1, @@ -1051,10 +1085,10 @@ static void set_inbound_win_registers(struct brcm_pcie *pcie, /* * Most STB chips: * Do nothing. - * 7712: - * All of their BARs need to be set. + * 7712, CM: + * All of their inbound windows need to be set. */ - if (pcie->cfg->soc_base == BCM7712) { + if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base)) { /* BUS remap register settings */ reg_offset = brcm_ubus_reg_offset(i); tmp = lower_32_bits(cpu_addr) & ~0xfff; @@ -1118,6 +1152,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) burst = 0x0; /* 128 bytes */ else if (pcie->cfg->soc_base == BCM7278) burst = 0x3; /* 512 bytes */ + else if (pcie->cfg->soc_base == BCM3162 || pcie->cfg->soc_base == BCM33940) + burst = 0x1; /* Encoding: 0=64, 1=128, 2=Rsvd, 3=Rsvd */ else burst = 0x2; /* 512 bytes */ @@ -1144,18 +1180,20 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) return -EINVAL; } - tmp = readl(base + PCIE_MISC_MISC_CTRL); - for (memc = 0; memc < pcie->num_memc; memc++) { - u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15; - - if (memc == 0) - u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0)); - else if (memc == 1) - u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1)); - else if (memc == 2) - u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); + if (!IS_CM_SOC(pcie->cfg->soc_base)) { + tmp = readl(base + PCIE_MISC_MISC_CTRL); + for (memc = 0; memc < pcie->num_memc; memc++) { + u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15; + + if (memc == 0) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0)); + else if (memc == 1) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1)); + else if (memc == 2) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); + } + writel(tmp, base + PCIE_MISC_MISC_CTRL); } - writel(tmp, base + PCIE_MISC_MISC_CTRL); /* * We ideally want the MSI target address to be located in the 32bit @@ -1164,8 +1202,10 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) * 4GB or when the inbound area is smaller than 4GB (taking into * account the rounding-up we're forced to perform). */ - if (inbound_wins[2].pci_offset >= SZ_4G || - (inbound_wins[2].size + inbound_wins[2].pci_offset) < SZ_4G) + if (IS_CM_SOC(pcie->cfg->soc_base)) + pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_FOR_CM; + 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; else pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; @@ -1226,6 +1266,29 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK); writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); + /* + * Relax read ordering for chip architectures using RBUS/SCB that + * use WiFi Runner offload (i.e. BCM3390) to avoid deadlock where + * reads are blocked by writes. + */ + if (pcie->cfg->soc_base == BCM3390) { + tmp = readl(base + PCIE_MISC_MISC_CTRL); + u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_IN_CPL_RO_MASK); + writel(tmp, base + PCIE_MISC_MISC_CTRL); + } + + /* + * The 3392 has a bug that requires the NP credit advertised by the + * MAC to be overwritten with 0x10 in bits 31:24 of the following + * register. + */ + if (pcie->cfg->soc_base == BCM3392) { + tmp = readl(base + PCIE_RC_DL_PDL_CONTROL_4); + u32p_replace_bits(&tmp, 0x10, + PCIE_RC_DL_PDL_CONTROL_4_NPH_FC_INIT_MASK); + writel(tmp, base + PCIE_RC_DL_PDL_CONTROL_4); + } + if (pcie->cfg->post_setup) { ret = pcie->cfg->post_setup(pcie); if (ret < 0) @@ -1246,8 +1309,8 @@ static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie) const unsigned int REG_OFFSET = PCIE_RGR1_SW_INIT_1(pcie) - 8; u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */ - /* 7712 does not have this (RGR1) timer */ - if (pcie->cfg->soc_base == BCM7712) + /* CM and 7712 do not have this (RGR1) timer */ + if (IS_CM_SOC(pcie->cfg->soc_base) || pcie->cfg->soc_base == BCM7712) return; /* Each unit in timeout register is 1/216,000,000 seconds */ @@ -1354,7 +1417,10 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) brcm_config_clkreq(pcie); - if (pcie->ssc) { + if (IS_CM_SOC(pcie->cfg->soc_base)) { + /* This driver does configure SSC for CM chips */ + ssc_str = ""; + } else if (pcie->ssc) { ret = brcm_pcie_set_ssc(pcie); if (ret == 0) ssc_str = "(SSC)"; @@ -1715,6 +1781,14 @@ static const int pcie_offsets[] = { [PCIE_INTR2_CPU_BASE] = 0x4300, }; +static const int pcie_offset_bcm3162[] = { + [RGR1_SW_INIT_1] = 0x9210, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x9004, + [PCIE_HARD_DEBUG] = 0x4204, + [PCIE_INTR2_CPU_BASE] = 0x4300 +}; + static const int pcie_offsets_bcm7278[] = { [RGR1_SW_INIT_1] = 0xc010, [EXT_CFG_INDEX] = 0x9000, @@ -1739,6 +1813,14 @@ static const int pcie_offsets_bcm7712[] = { [PCIE_INTR2_CPU_BASE] = 0x4400, }; +static const int pcie_offset_bcm33940[] = { + [RGR1_SW_INIT_1] = 0x9210, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x9004, + [PCIE_HARD_DEBUG] = 0x4304, + [PCIE_INTR2_CPU_BASE] = 0x4400 +}; + static const struct pcie_cfg_data generic_cfg = { .offsets = pcie_offsets, .soc_base = GENERIC, @@ -1765,6 +1847,30 @@ static const struct pcie_cfg_data bcm2712_cfg = { .num_inbound_wins = 10, }; +static const struct pcie_cfg_data bcm3162_cfg = { + .offsets = pcie_offset_bcm3162, + .soc_base = BCM3162, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_data bcm3392_cfg = { + .offsets = pcie_offset_bcm33940, + .soc_base = BCM3392, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 10, +}; + +static const struct pcie_cfg_data bcm3390_cfg = { + .offsets = pcie_offsets, + .soc_base = BCM3390, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + static const struct pcie_cfg_data bcm4908_cfg = { .offsets = pcie_offsets, .soc_base = BCM4908, @@ -1814,9 +1920,20 @@ static const struct pcie_cfg_data bcm7712_cfg = { .num_inbound_wins = 10, }; +static const struct pcie_cfg_data bcm33940_cfg = { + .offsets = pcie_offset_bcm33940, + .soc_base = BCM33940, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 10, +}; + static const struct of_device_id brcm_pcie_match[] = { { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, { .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg }, + { .compatible = "brcm,bcm3162-pcie", .data = &bcm3162_cfg }, + { .compatible = "brcm,bcm3390-pcie", .data = &bcm3390_cfg }, + { .compatible = "brcm,bcm3392-pcie", .data = &bcm3392_cfg }, { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg }, { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, { .compatible = "brcm,bcm7216-pcie", .data = &bcm7216_cfg }, @@ -1825,6 +1942,7 @@ static const struct of_device_id brcm_pcie_match[] = { { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg }, { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg }, { .compatible = "brcm,bcm7712-pcie", .data = &bcm7712_cfg }, + { .compatible = "brcm,bcm33940-pcie", .data = &bcm33940_cfg }, {}, }; -- 2.43.0