diff options
Diffstat (limited to 'drivers/pci/controller/pcie-brcmstb.c')
| -rw-r--r-- | drivers/pci/controller/pcie-brcmstb.c | 583 |
1 files changed, 551 insertions, 32 deletions
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index e733a27dc8df..63020d7040c4 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -48,6 +48,15 @@ #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 +#define PCIE_RC_TL_VDM_CTL0 0x0a20 +#define PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK 0x10000 +#define PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK 0x20000 +#define PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK 0x40000 + +#define PCIE_RC_TL_VDM_CTL1 0x0a0c +#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID0_MASK 0x0000ffff +#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID1_MASK 0xffff0000 + #define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8 #define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8 @@ -55,6 +64,10 @@ #define PCIE_RC_DL_MDIO_WR_DATA 0x1104 #define PCIE_RC_DL_MDIO_RD_DATA 0x1108 +#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_MISC_CTRL 0x4008 #define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80 #define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400 @@ -85,9 +98,15 @@ #define PCIE_BRCM_MAX_INBOUND_WINS 16 #define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c #define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR1_CONFIG_HI 0x4030 -#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 +#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 +#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 +#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c +#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR3_CONFIG_HI 0x4040 #define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 @@ -96,12 +115,15 @@ #define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540 #define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540 +#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c + #define PCIE_MISC_PCIE_CTRL 0x4064 #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 #define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4 #define PCIE_MISC_PCIE_STATUS 0x4068 #define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 +#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712 0x40 #define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 #define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 #define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 @@ -127,6 +149,7 @@ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK 0x8 #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK 0x200000 #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 #define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000 @@ -134,10 +157,74 @@ (PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK | \ PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK) + #define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac #define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_EN_MASK BIT(0) #define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP 0x410c +#define PCIE_MISC_CTRL_1 0x40A0 +#define PCIE_MISC_CTRL_1_OUTBOUND_TC_MASK 0xf +#define PCIE_MISC_CTRL_1_OUTBOUND_NO_SNOOP_MASK BIT(3) +#define PCIE_MISC_CTRL_1_OUTBOUND_RO_MASK BIT(4) +#define PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK BIT(5) + +#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_UBUS_TIMEOUT 0x40A8 + +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI 0x40b0 + +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP 0x40b4 +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) + +/* Additional RC BARs */ +#define PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 +#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8 +/* ... */ +#define PCIE_MISC_RC_BAR10_CONFIG_LO 0x4104 +#define PCIE_MISC_RC_BAR10_CONFIG_HI 0x4108 + +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE 0x1 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110 +/* ... */ +#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_LO 0x413c +#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_HI 0x4140 + +/* AXI priority forwarding - automatic level-based */ +#define PCIE_MISC_TC_QUEUE_TO_QOS_MAP(x) (0x4160 - (x) * 4) +/* Defined in quarter-fullness */ +#define QUEUE_THRESHOLD_34_TO_QOS_MAP_SHIFT 12 +#define QUEUE_THRESHOLD_23_TO_QOS_MAP_SHIFT 8 +#define QUEUE_THRESHOLD_12_TO_QOS_MAP_SHIFT 4 +#define QUEUE_THRESHOLD_01_TO_QOS_MAP_SHIFT 0 +#define QUEUE_THRESHOLD_MASK 0xf + +/* VDM messages indexing TCs to AXI priorities */ +/* Indexes 8-15 */ +#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI 0x4164 +/* Indexes 0-7 */ +#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO 0x4168 +#define VDM_PRIORITY_TO_QOS_MAP_SHIFT(x) (4 * (x)) +#define VDM_PRIORITY_TO_QOS_MAP_MASK 0xf + +#define PCIE_MISC_AXI_INTF_CTRL 0x416C +#define AXI_EN_RCLK_QOS_ARRAY_FIX BIT(13) +#define AXI_EN_QOS_UPDATE_TIMING_FIX BIT(12) +#define AXI_DIS_QOS_GATING_IN_MASTER BIT(11) +#define AXI_REQFIFO_EN_QOS_PROPAGATION BIT(7) +#define AXI_BRIDGE_LOW_LATENCY_MODE BIT(6) +#define AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK 0x3f + +#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170 + #define PCIE_MSI_INTR2_BASE 0x4500 /* Offsets from INTR2_CPU and MSI_INTR2 BASE offsets */ @@ -226,6 +313,7 @@ enum pcie_soc_base { BCM7425, BCM7435, BCM7712, + BCM2712, }; struct inbound_win { @@ -257,7 +345,7 @@ struct brcm_msi { struct mutex lock; /* guards the alloc/free operations */ u64 target_addr; int irq; - DECLARE_BITMAP(used, BRCM_INT_PCI_MSI_NR); + DECLARE_BITMAP(used, 64); bool legacy; /* Some chips have MSIs in bits [31..24] of a shared register. */ int legacy_shift; @@ -291,6 +379,10 @@ struct brcm_pcie { bool ep_wakeup_capable; bool has_phy; u8 num_inbound_wins; + bool l1ss; + bool rcb_mps_mode; + u32 qos_map; + u32 tperst_clk_ms; }; static inline bool is_bmips(const struct brcm_pcie *pcie) @@ -309,8 +401,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 <= 35) - /* 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 */ return 0; @@ -399,12 +491,43 @@ static int brcm_pcie_set_ssc(struct brcm_pcie *pcie) return ssc && pll ? 0 : -EIO; } +static void brcm_pcie_munge_pll(struct brcm_pcie *pcie) +{ + //print "MDIO block 0x1600 written per Dannys instruction" + //tmp = pcie_mdio_write(phyad, &h16&, &h50b9&) + //tmp = pcie_mdio_write(phyad, &h17&, &hbd1a&) + //tmp = pcie_mdio_write(phyad, &h1b&, &h5030&) + //tmp = pcie_mdio_write(phyad, &h1e&, &h0007&) + + 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); + dev_dbg(pcie->dev, "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); + dev_dbg(pcie->dev, "PCIE MDIO post_refclk 0x%02x = 0x%04x\n", + regs[i], tmp); + } + usleep_range(100, 200); +} + /* Limits operation to a specific generation (1, 2, or 3) */ static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) { u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); + dev_info(pcie->dev, "Forcing gen %d\n", pcie->gen); + lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen; writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); @@ -456,6 +579,73 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); } +static void brcm_pcie_set_tc_qos(struct brcm_pcie *pcie) +{ + int i; + u32 reg; + + if (pcie->soc_base != BCM2712) + return; + + /* Disable broken QOS forwarding search. Set chicken bits for 2712D0 */ + reg = readl(pcie->base + PCIE_MISC_AXI_INTF_CTRL); + reg &= ~AXI_REQFIFO_EN_QOS_PROPAGATION; + reg |= AXI_EN_RCLK_QOS_ARRAY_FIX | AXI_EN_QOS_UPDATE_TIMING_FIX | + AXI_DIS_QOS_GATING_IN_MASTER; + writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL); + + /* + * If the QOS_UPDATE_TIMING_FIX bit is Reserved-0, then this is a + * 2712C1 chip, or a single-lane RC. Use the best-effort alternative + * which is to partially throttle AXI requests in-flight to the SDC. + */ + reg = readl(pcie->base + PCIE_MISC_AXI_INTF_CTRL); + if (!(reg & AXI_EN_QOS_UPDATE_TIMING_FIX)) { + reg &= ~AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK; + reg |= 15; + writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL); + } + + /* Disable VDM reception by default - QoS map defaults to 0 */ + reg = readl(pcie->base + PCIE_MISC_CTRL_1); + reg &= ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; + writel(reg, pcie->base + PCIE_MISC_CTRL_1); + + if (!of_property_read_u32(pcie->np, "brcm,fifo-qos-map", &pcie->qos_map)) { + /* + * Backpressure mode - bottom 4 nibbles are QoS for each + * quartile of FIFO level. Each TC gets the same map, because + * this mode is intended for nonrealtime EPs. + */ + + pcie->qos_map &= 0x0000ffff; + for (i = 0; i < 8; i++) + writel(pcie->qos_map, pcie->base + PCIE_MISC_TC_QUEUE_TO_QOS_MAP(i)); + + return; + } + + if (!of_property_read_u32(pcie->np, "brcm,vdm-qos-map", &pcie->qos_map)) { + + reg = readl(pcie->base + PCIE_MISC_CTRL_1); + reg |= PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; + writel(reg, pcie->base + PCIE_MISC_CTRL_1); + + /* No forwarding means no point separating panic priorities from normal */ + writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO); + writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI); + + /* Match Vendor ID of 0 */ + writel(0, pcie->base + PCIE_RC_TL_VDM_CTL1); + /* Forward VDMs to priority interface - at least the rx counters work */ + reg = readl(pcie->base + PCIE_RC_TL_VDM_CTL0); + reg |= PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK | + PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK | + PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK; + writel(reg, pcie->base + PCIE_RC_TL_VDM_CTL0); + } +} + static struct irq_chip brcm_msi_irq_chip = { .name = "BRCM STB PCIe MSI", .irq_ack = irq_chip_ack_parent, @@ -464,8 +654,8 @@ static struct irq_chip brcm_msi_irq_chip = { }; static struct msi_domain_info brcm_msi_domain_info = { - .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI, + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), .chip = &brcm_msi_irq_chip, }; @@ -484,10 +674,23 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc) status = readl(msi->intr_base + MSI_INT_STATUS); status >>= msi->legacy_shift; - for_each_set_bit(bit, &status, msi->nr) { - int ret; - ret = generic_handle_domain_irq(msi->inner_domain, bit); - if (ret) + for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR/*msi->nr*/) { + unsigned long virq; + bool found = false; + + virq = irq_find_mapping(msi->inner_domain, bit); + if (virq) { + found = true; + dev_dbg(dev, "MSI -> %ld\n", virq); + generic_handle_irq(virq); + } + virq = irq_find_mapping(msi->inner_domain, bit + 32); + if (virq) { + found = true; + dev_dbg(dev, "MSI -> %ld\n", virq); + generic_handle_irq(virq); + } + if (!found) dev_dbg(dev, "unexpected MSI\n"); } @@ -500,13 +703,13 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) msg->address_lo = lower_32_bits(msi->target_addr); msg->address_hi = upper_32_bits(msi->target_addr); - msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq; + msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | (data->hwirq & 0x1f); } static void brcm_msi_ack_irq(struct irq_data *data) { struct brcm_msi *msi = irq_data_get_irq_chip_data(data); - const int shift_amt = data->hwirq + msi->legacy_shift; + const int shift_amt = (data->hwirq & 0x1f) + msi->legacy_shift; writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR); } @@ -666,7 +869,7 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) msi->legacy_shift = 24; } else { msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE; - msi->nr = BRCM_INT_PCI_MSI_NR; + msi->nr = 64; //BRCM_INT_PCI_MSI_NR; msi->legacy_shift = 0; } @@ -688,6 +891,9 @@ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) void __iomem *base = pcie->base; u32 val = readl(base + PCIE_MISC_PCIE_STATUS); + if (pcie->soc_base == BCM2712) + return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712, val) | 1; //XXX + return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); } @@ -780,6 +986,21 @@ static int brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val) return 0; } +static int brcm_pcie_bridge_sw_init_set_2712(struct brcm_pcie *pcie, u32 val) +{ + int ret; + + if (WARN_ONCE(!pcie->bridge_reset, "missing bridge reset controller\n")) + return -EINVAL; + + if (val) + ret = reset_control_assert(pcie->bridge_reset); + else + ret = reset_control_deassert(pcie->bridge_reset); + + return ret; +} + static int brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val) { int ret; @@ -810,6 +1031,18 @@ static int brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val) return 0; } +static int 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, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK); + writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); + + return 0; +} + static int brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) { u32 tmp; @@ -821,6 +1054,8 @@ static int brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) return 0; } + +#if 0 static void add_inbound_win(struct inbound_win *b, u8 *count, u64 size, u64 cpu_addr, u64 pci_offset) { @@ -1023,17 +1258,137 @@ static void set_inbound_win_registers(struct brcm_pcie *pcie, } } } +#endif + +static int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, + u64 *rc_bar2_size, + u64 *rc_bar2_offset) +{ + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); + struct resource_entry *entry; + struct device *dev = pcie->dev; + u64 lowest_pcie_addr = ~(u64)0; + int ret, i = 0; + u64 size = 0; + + resource_list_for_each_entry(entry, &bridge->dma_ranges) { + u64 pcie_beg = entry->res->start - entry->offset; + + size += entry->res->end - entry->res->start + 1; + if (pcie_beg < lowest_pcie_addr) + lowest_pcie_addr = pcie_beg; + if (pcie->soc_base == BCM2711 || pcie->soc_base == BCM2712) + break; // Only consider the first entry + } + + if (lowest_pcie_addr == ~(u64)0) { + dev_err(dev, "DT node has no dma-ranges\n"); + return -EINVAL; + } + + ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1, + PCIE_BRCM_MAX_MEMC); + + if (ret <= 0) { + /* Make an educated guess */ + pcie->num_memc = 1; + pcie->memc_size[0] = 1ULL << fls64(size - 1); + } else { + pcie->num_memc = ret; + } + + /* Each memc is viewed through a "port" that is a power of 2 */ + for (i = 0, size = 0; i < pcie->num_memc; i++) + size += pcie->memc_size[i]; + + /* System memory starts at this address in PCIe-space */ + *rc_bar2_offset = lowest_pcie_addr; + /* The sum of all memc views must also be a power of 2 */ + *rc_bar2_size = 1ULL << fls64(size - 1); + + /* + * We validate the inbound memory view even though we should trust + * whatever the device-tree provides. This is because of an HW issue on + * early Raspberry Pi 4's revisions (bcm2711). It turns out its + * firmware has to dynamically edit dma-ranges due to a bug on the + * PCIe controller integration, which prohibits any access above the + * lower 3GB of memory. Given this, we decided to keep the dma-ranges + * in check, avoiding hard to debug device-tree related issues in the + * future: + * + * The PCIe host controller by design must set the inbound viewport to + * be a contiguous arrangement of all of the system's memory. In + * addition, its size mut be a power of two. To further complicate + * matters, the viewport must start on a pcie-address that is aligned + * on a multiple of its size. If a portion of the viewport does not + * represent system memory -- e.g. 3GB of memory requires a 4GB + * viewport -- we can map the outbound memory in or after 3GB and even + * though the viewport will overlap the outbound memory the controller + * will know to send outbound memory downstream and everything else + * upstream. + * + * For example: + * + * - The best-case scenario, memory up to 3GB, is to place the inbound + * region in the first 4GB of pcie-space, as some legacy devices can + * only address 32bits. We would also like to put the MSI under 4GB + * as well, since some devices require a 32bit MSI target address. + * + * - If the system memory is 4GB or larger we cannot start the inbound + * region at location 0 (since we have to allow some space for + * outbound memory @ 3GB). So instead it will start at the 1x + * multiple of its size + */ + if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) || + (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { + dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", + *rc_bar2_size, *rc_bar2_offset); + return -EINVAL; + } + + return 0; +} + +static int brcm_pcie_get_rc_bar_n(struct brcm_pcie *pcie, + int idx, + u64 *rc_bar_cpu, + u64 *rc_bar_size, + u64 *rc_bar_pci) +{ + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); + struct resource_entry *entry; + int i = 0; + + resource_list_for_each_entry(entry, &bridge->dma_ranges) { + if (i == idx) { + *rc_bar_cpu = entry->res->start; + *rc_bar_size = entry->res->end - entry->res->start + 1; + *rc_bar_pci = entry->res->start - entry->offset; + return 0; + } + + i++; + } + + return -EINVAL; +} static int brcm_pcie_setup(struct brcm_pcie *pcie) { +#if 0 struct inbound_win inbound_wins[PCIE_BRCM_MAX_INBOUND_WINS]; +#endif + u64 rc_bar2_offset, rc_bar2_size; void __iomem *base = pcie->base; struct pci_host_bridge *bridge; struct resource_entry *entry; u32 tmp, burst, aspm_support; u8 num_out_wins = 0; +#if 0 int num_inbound_wins = 0; +#endif int memc, ret; + int count, i; /* Reset the bridge */ ret = pcie->bridge_sw_init_set(pcie, 1); @@ -1065,6 +1420,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* Wait for SerDes to be stable */ usleep_range(100, 200); + if (pcie->soc_base == 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); + } + /* * SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it @@ -1074,6 +1440,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) burst = 0x1; /* 256 bytes */ else if (pcie->soc_base == BCM2711) burst = 0x0; /* 128 bytes */ + else if (pcie->soc_base == BCM2712) + burst = 0x1; /* 128 bytes */ else if (pcie->soc_base == BCM7278) burst = 0x3; /* 512 bytes */ else @@ -1081,27 +1449,38 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* * Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN, - * RCB_MPS_MODE, RCB_64B_MODE + * RCB_MPS_MODE */ tmp = readl(base + PCIE_MISC_MISC_CTRL); u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); - u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK); - u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK); + if (pcie->rcb_mps_mode) + u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK); writel(tmp, base + PCIE_MISC_MISC_CTRL); - num_inbound_wins = brcm_pcie_get_inbound_wins(pcie, inbound_wins); - if (num_inbound_wins < 0) - return num_inbound_wins; + brcm_pcie_set_tc_qos(pcie); + + ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, + &rc_bar2_offset); + if (ret) + return ret; - set_inbound_win_registers(pcie, inbound_wins, num_inbound_wins); + tmp = lower_32_bits(rc_bar2_offset); + u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size), + PCIE_MISC_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); if (!brcm_pcie_rc_mode(pcie)) { dev_err(pcie->dev, "PCIe RC controller misconfigured as Endpoint\n"); return -EINVAL; } + tmp = readl(base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); + u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK); + writel(tmp, base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); 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; @@ -1115,6 +1494,29 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) } writel(tmp, base + PCIE_MISC_MISC_CTRL); + if (pcie->soc_base == 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); + } + /* * We ideally want the MSI target address to be located in the 32bit * addressable memory area. Some devices might depend on it. This is @@ -1122,22 +1524,58 @@ 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 (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G) pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB; else pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; + /* disable the PCIe->GISB memory window (RC_BAR1) */ + tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); + tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; + writel(tmp, base + PCIE_MISC_RC_BAR1_CONFIG_LO); - /* Don't advertise L0s capability if 'aspm-no-l0s' */ - aspm_support = PCIE_LINK_STATE_L1; + /* disable the PCIe->SCB memory window (RC_BAR3) */ + tmp = readl(base + PCIE_MISC_RC_BAR3_CONFIG_LO); + tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK; + writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); + + /* Always advertise L1 capability */ + aspm_support = BIT(1); + /* Advertise L0s capability unless 'aspm-no-l0s' is set */ if (!of_property_read_bool(pcie->np, "aspm-no-l0s")) - aspm_support |= PCIE_LINK_STATE_L0S; + aspm_support |= BIT(0); tmp = readl(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); u32p_replace_bits(&tmp, aspm_support, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + /* program additional inbound windows (RC_BAR4..RC_BAR10) */ + count = (pcie->soc_base == BCM2712) ? 7 : 0; + for (i = 0; i < count; i++) { + u64 bar_cpu, bar_size, bar_pci; + + ret = brcm_pcie_get_rc_bar_n(pcie, 1 + i, &bar_cpu, &bar_size, + &bar_pci); + if (ret) + break; + + tmp = lower_32_bits(bar_pci); + u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size), + PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK); + writel(tmp, base + PCIE_MISC_RC_BAR4_CONFIG_LO + i * 8); + writel(upper_32_bits(bar_pci), + base + PCIE_MISC_RC_BAR4_CONFIG_HI + i * 8); + + tmp = upper_32_bits(bar_cpu) & + PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK; + writel(tmp, + base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI + i * 8); + tmp = lower_32_bits(bar_cpu) & + PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK; + writel(tmp | PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE, + base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + i * 8); + } + /* * For config space accesses on the RC, show the right class for * a PCIe-PCIe bridge (the default setting is to be EP mode). @@ -1199,7 +1637,7 @@ static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie) u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */ /* 7712 does not have this (RGR1) timer */ - if (pcie->soc_base == BCM7712) + if (pcie->soc_base == BCM7712 || pcie->soc_base == BCM2712) return; /* Each unit in timeout register is 1/216,000,000 seconds */ @@ -1274,12 +1712,35 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) void __iomem *base = pcie->base; u16 nlw, cls, lnksta; bool ssc_good = false; + u32 tmp; + u16 tmp16; int ret, i; + if (pcie->gen) + brcm_pcie_set_gen(pcie, pcie->gen); + /* Unassert the fundamental reset */ - ret = pcie->perst_set(pcie, 0); - if (ret) - return ret; + if (pcie->tperst_clk_ms) { + /* + * Increase Tperst_clk time by forcing PERST# output low while + * the internal reset is released, so the PLL generates stable + * refclk output further in advance of PERST# deassertion. + */ + tmp = readl(base + HARD_DEBUG(pcie)); + u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); + writel(tmp, base + HARD_DEBUG(pcie)); + + pcie->perst_set(pcie, 0); + msleep(pcie->tperst_clk_ms); + + tmp = readl(base + HARD_DEBUG(pcie)); + u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); + writel(tmp, base + HARD_DEBUG(pcie)); + } else { + ret = pcie->perst_set(pcie, 0); + if (ret) + return ret; + } /* * Wait for 100ms after PERST# deassertion; see PCIe CEM specification @@ -1302,9 +1763,6 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) brcm_config_clkreq(pcie); - if (pcie->gen) - brcm_pcie_set_gen(pcie, pcie->gen); - if (pcie->ssc) { ret = brcm_pcie_set_ssc(pcie); if (ret == 0) @@ -1320,6 +1778,16 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie) pci_speed_string(pcie_link_speed[cls]), nlw, ssc_good ? "(SSC)" : "(!SSC)"); + /* + * RootCtl bits are reset by perst_n, which undoes pci_enable_crs() + * called prior to pci_add_new_bus() during probe. Re-enable here. + */ + tmp16 = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCAP); + if (tmp16 & PCI_EXP_RTCAP_CRSVIS) { + tmp16 = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCTL); + u16p_replace_bits(&tmp16, 1, PCI_EXP_RTCTL_CRSSVE); + writew(tmp16, base + BRCM_PCIE_CAP_REGS + PCI_EXP_RTCTL); + } return 0; } @@ -1493,6 +1961,12 @@ static int brcm_pcie_turn_off(struct brcm_pcie *pcie) u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); writel(tmp, base + HARD_DEBUG(pcie)); + /* + * Shutting down this bridge on pcie1 means accesses to rescal block + * will hang the chip if another RC wants to assert/deassert rescal. + */ + if (pcie->soc_base == BCM2712) + return 0; /* Shutdown PCIe bridge */ ret = pcie->bridge_sw_init_set(pcie, 1); @@ -1688,6 +2162,13 @@ static const int pcie_offsets_bcm7712[] = { [PCIE_INTR2_CPU_BASE] = 0x4400, }; +static const int pcie_offsets_bcm2712[] = { + [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, @@ -1753,6 +2234,13 @@ static const struct pcie_cfg_data bcm7712_cfg = { .num_inbound_wins = 10, }; +static const struct pcie_cfg_data bcm2712_cfg = { + .offsets = pcie_offsets_bcm2712, + .perst_set = brcm_pcie_perst_set_2712, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_2712, + .soc_base = BCM2712, +}; + static const struct of_device_id brcm_pcie_match[] = { { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg }, @@ -1763,6 +2251,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,bcm2712-pcie", .data = &bcm2712_cfg }, {}, }; @@ -1822,6 +2311,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) pcie->gen = (ret < 0) ? 0 : ret; pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); + pcie->l1ss = of_property_read_bool(np, "brcm,enable-l1ss"); + pcie->rcb_mps_mode = of_property_read_bool(np, "brcm,enable-mps-rcb"); + of_property_read_u32(np, "brcm,tperst-clk-ms", &pcie->tperst_clk_ms); pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal"); if (IS_ERR(pcie->rescal)) @@ -1895,6 +2387,33 @@ static int brcm_pcie_probe(struct platform_device *pdev) dev_err(pcie->dev, "probe of internal MSI failed"); goto fail; } + } else if (pci_msi_enabled() && msi_np != pcie->np) { + /* Use RC_BAR1 for MIP access */ + u64 msi_pci_addr; + u64 msi_phys_addr; + + if (of_property_read_u64(msi_np, "brcm,msi-pci-addr", &msi_pci_addr)) { + dev_err(pcie->dev, "Unable to find MSI PCI address\n"); + ret = -EINVAL; + goto fail; + } + + if (of_property_read_u64(msi_np, "reg", &msi_phys_addr)) { + dev_err(pcie->dev, "Unable to find MSI physical address\n"); + ret = -EINVAL; + goto fail; + } + + writel(lower_32_bits(msi_pci_addr) | brcm_pcie_encode_ibar_size(0x1000), + pcie->base + PCIE_MISC_RC_BAR1_CONFIG_LO); + writel(upper_32_bits(msi_pci_addr), + pcie->base + PCIE_MISC_RC_BAR1_CONFIG_HI); + + writel(lower_32_bits(msi_phys_addr) | + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK, + pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP); + writel(upper_32_bits(msi_phys_addr), + pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI); } bridge->ops = pcie->soc_base == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops; |
