|
55 | 55 | #define PCIE_RC_DL_MDIO_WR_DATA 0x1104
|
56 | 56 | #define PCIE_RC_DL_MDIO_RD_DATA 0x1108
|
57 | 57 |
|
| 58 | +#define PCIE_RC_PL_PHY_CTL_15 0x184c |
| 59 | +#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK 0x400000 |
| 60 | +#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff |
| 61 | + |
58 | 62 | #define PCIE_MISC_MISC_CTRL 0x4008
|
59 | 63 | #define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80
|
60 | 64 | #define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400
|
@@ -234,13 +238,24 @@ struct inbound_win {
|
234 | 238 | u64 cpu_addr;
|
235 | 239 | };
|
236 | 240 |
|
| 241 | +/* |
| 242 | + * The RESCAL block is tied to PCIe controller #1, regardless of the number of |
| 243 | + * controllers, and turning off PCIe controller #1 prevents access to the RESCAL |
| 244 | + * register blocks, therefore no other controller can access this register |
| 245 | + * space, and depending upon the bus fabric we may get a timeout (UBUS/GISB), |
| 246 | + * or a hang (AXI). |
| 247 | + */ |
| 248 | +#define CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN BIT(0) |
| 249 | + |
237 | 250 | struct pcie_cfg_data {
|
238 | 251 | const int *offsets;
|
239 | 252 | const enum pcie_soc_base soc_base;
|
240 | 253 | const bool has_phy;
|
| 254 | + const u32 quirks; |
241 | 255 | u8 num_inbound_wins;
|
242 | 256 | int (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
243 | 257 | int (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
| 258 | + int (*post_setup)(struct brcm_pcie *pcie); |
244 | 259 | };
|
245 | 260 |
|
246 | 261 | struct subdev_regulators {
|
@@ -816,6 +831,38 @@ static int brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
|
816 | 831 | return 0;
|
817 | 832 | }
|
818 | 833 |
|
| 834 | +static int brcm_pcie_post_setup_bcm2712(struct brcm_pcie *pcie) |
| 835 | +{ |
| 836 | + const u16 data[] = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 }; |
| 837 | + const u8 regs[] = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e }; |
| 838 | + int ret, i; |
| 839 | + u32 tmp; |
| 840 | + |
| 841 | + /* Allow a 54MHz (xosc) refclk source */ |
| 842 | + ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, 0x1600); |
| 843 | + if (ret < 0) |
| 844 | + return ret; |
| 845 | + |
| 846 | + for (i = 0; i < ARRAY_SIZE(regs); i++) { |
| 847 | + ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regs[i], data[i]); |
| 848 | + if (ret < 0) |
| 849 | + return ret; |
| 850 | + } |
| 851 | + |
| 852 | + usleep_range(100, 200); |
| 853 | + |
| 854 | + /* |
| 855 | + * Set L1SS sub-state timers to avoid lengthy state transitions, |
| 856 | + * PM clock period is 18.52ns (1/54MHz, round down). |
| 857 | + */ |
| 858 | + tmp = readl(pcie->base + PCIE_RC_PL_PHY_CTL_15); |
| 859 | + tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK; |
| 860 | + tmp |= 0x12; |
| 861 | + writel(tmp, pcie->base + PCIE_RC_PL_PHY_CTL_15); |
| 862 | + |
| 863 | + return 0; |
| 864 | +} |
| 865 | + |
819 | 866 | static void add_inbound_win(struct inbound_win *b, u8 *count, u64 size,
|
820 | 867 | u64 cpu_addr, u64 pci_offset)
|
821 | 868 | {
|
@@ -1179,6 +1226,12 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
1179 | 1226 | PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
|
1180 | 1227 | writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
|
1181 | 1228 |
|
| 1229 | + if (pcie->cfg->post_setup) { |
| 1230 | + ret = pcie->cfg->post_setup(pcie); |
| 1231 | + if (ret < 0) |
| 1232 | + return ret; |
| 1233 | + } |
| 1234 | + |
1182 | 1235 | return 0;
|
1183 | 1236 | }
|
1184 | 1237 |
|
@@ -1488,8 +1541,9 @@ static int brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
1488 | 1541 | u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
|
1489 | 1542 | writel(tmp, base + HARD_DEBUG(pcie));
|
1490 | 1543 |
|
1491 |
| - /* Shutdown PCIe bridge */ |
1492 |
| - ret = pcie->cfg->bridge_sw_init_set(pcie, 1); |
| 1544 | + if (!(pcie->cfg->quirks & CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN)) |
| 1545 | + /* Shutdown PCIe bridge */ |
| 1546 | + ret = pcie->cfg->bridge_sw_init_set(pcie, 1); |
1493 | 1547 |
|
1494 | 1548 | return ret;
|
1495 | 1549 | }
|
@@ -1699,6 +1753,16 @@ static const struct pcie_cfg_data bcm2711_cfg = {
|
1699 | 1753 | .num_inbound_wins = 3,
|
1700 | 1754 | };
|
1701 | 1755 |
|
| 1756 | +static const struct pcie_cfg_data bcm2712_cfg = { |
| 1757 | + .offsets = pcie_offsets_bcm7712, |
| 1758 | + .soc_base = BCM7712, |
| 1759 | + .perst_set = brcm_pcie_perst_set_7278, |
| 1760 | + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, |
| 1761 | + .post_setup = brcm_pcie_post_setup_bcm2712, |
| 1762 | + .quirks = CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN, |
| 1763 | + .num_inbound_wins = 10, |
| 1764 | +}; |
| 1765 | + |
1702 | 1766 | static const struct pcie_cfg_data bcm4908_cfg = {
|
1703 | 1767 | .offsets = pcie_offsets,
|
1704 | 1768 | .soc_base = BCM4908,
|
@@ -1750,6 +1814,7 @@ static const struct pcie_cfg_data bcm7712_cfg = {
|
1750 | 1814 |
|
1751 | 1815 | static const struct of_device_id brcm_pcie_match[] = {
|
1752 | 1816 | { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
|
| 1817 | + { .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg }, |
1753 | 1818 | { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg },
|
1754 | 1819 | { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg },
|
1755 | 1820 | { .compatible = "brcm,bcm7216-pcie", .data = &bcm7216_cfg },
|
|
0 commit comments