Skip to content

Commit b6e57f0

Browse files
P33Mpopcornmix
authored andcommitted
PCI: pcie-brcmstb: optionally extend Tperst_clk time
Some endpoints need longer than the minimum Tperst_clk time of 100us that the PCIe specification allows for, as they may need to sequence internal resets off the stable output of internal PLLs prior to removal of fundamental reset. PCIe switches are an especially bad case, in some cases requiring up to 100 milliseconds for stable downstream link behaviour. Parse the DT property brcm,tperst-clk-ms and use this to hold PERST# low during brcm_pcie_start_link(). The BRCM RC typically outputs 200us of stable refclk before deasserting PERST#. By masking/forcing the output signal while deasserting the internal reset, the effect is to extend the length of time that the refclk is active and stable before PERST# is released. The TX lanes will enter the Polling state before PERST# is released, but this appears to be harmless. Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
1 parent 9a38449 commit b6e57f0

File tree

1 file changed

+24
-1
lines changed

1 file changed

+24
-1
lines changed

drivers/pci/controller/pcie-brcmstb.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
135135

136136
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
137+
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK 0x8
137138
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK 0x200000
138139
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
139140
#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
@@ -360,6 +361,7 @@ struct brcm_pcie {
360361
struct subdev_regulators *sr;
361362
bool ep_wakeup_capable;
362363
const struct pcie_cfg_data *cfg;
364+
u32 tperst_clk_ms;
363365
};
364366

365367
static inline bool is_bmips(const struct brcm_pcie *pcie)
@@ -1487,13 +1489,32 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
14871489
u16 nlw, cls, lnksta, tmp16;
14881490
bool ssc_good = false;
14891491
int ret, i;
1492+
u32 tmp;
14901493

14911494
/* Limit the generation if specified */
14921495
if (pcie->gen)
14931496
brcm_pcie_set_gen(pcie, pcie->gen);
14941497

14951498
/* Unassert the fundamental reset */
1496-
ret = pcie->cfg->perst_set(pcie, 0);
1499+
if (pcie->tperst_clk_ms) {
1500+
/*
1501+
* Increase Tperst_clk time by forcing PERST# output low while
1502+
* the internal reset is released, so the PLL generates stable
1503+
* refclk output further in advance of PERST# deassertion.
1504+
*/
1505+
tmp = readl(pcie->base + HARD_DEBUG(pcie));
1506+
u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK);
1507+
writel(tmp, pcie->base + HARD_DEBUG(pcie));
1508+
1509+
ret = pcie->cfg->perst_set(pcie, 0);
1510+
fsleep(pcie->tperst_clk_ms * USEC_PER_MSEC);
1511+
1512+
tmp = readl(pcie->base + HARD_DEBUG(pcie));
1513+
u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK);
1514+
writel(tmp, pcie->base + HARD_DEBUG(pcie));
1515+
} else {
1516+
ret = pcie->cfg->perst_set(pcie, 0);
1517+
}
14971518
if (ret)
14981519
return ret;
14991520

@@ -2058,6 +2079,8 @@ static int brcm_pcie_probe(struct platform_device *pdev)
20582079
pcie->ssc = !(pcie->cfg->quirks & CFG_QUIRK_NO_SSC) &&
20592080
of_property_read_bool(np, "brcm,enable-ssc");
20602081

2082+
of_property_read_u32(np, "brcm,tperst-clk-ms", &pcie->tperst_clk_ms);
2083+
20612084
pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal");
20622085
if (IS_ERR(pcie->rescal))
20632086
return PTR_ERR(pcie->rescal);

0 commit comments

Comments
 (0)