mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
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>
This commit is contained in:
committed by
Dom Cobley
parent
341a40dcd6
commit
931cf43f8a
@@ -136,6 +136,7 @@
|
|||||||
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
|
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_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_L1SS_ENABLE_MASK 0x200000
|
||||||
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
|
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
|
||||||
#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
|
#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
|
||||||
@@ -361,6 +362,7 @@ struct brcm_pcie {
|
|||||||
struct subdev_regulators *sr;
|
struct subdev_regulators *sr;
|
||||||
bool ep_wakeup_capable;
|
bool ep_wakeup_capable;
|
||||||
const struct pcie_cfg_data *cfg;
|
const struct pcie_cfg_data *cfg;
|
||||||
|
u32 tperst_clk_ms;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool is_bmips(const struct brcm_pcie *pcie)
|
static inline bool is_bmips(const struct brcm_pcie *pcie)
|
||||||
@@ -1508,13 +1510,32 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
|
|||||||
u16 nlw, cls, lnksta, tmp16;
|
u16 nlw, cls, lnksta, tmp16;
|
||||||
bool ssc_good = false;
|
bool ssc_good = false;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
/* Limit the generation if specified */
|
/* Limit the generation if specified */
|
||||||
if (pcie->gen)
|
if (pcie->gen)
|
||||||
brcm_pcie_set_gen(pcie, pcie->gen);
|
brcm_pcie_set_gen(pcie, pcie->gen);
|
||||||
|
|
||||||
/* Unassert the fundamental reset */
|
/* Unassert the fundamental reset */
|
||||||
ret = pcie->cfg->perst_set(pcie, 0);
|
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(pcie->base + HARD_DEBUG(pcie));
|
||||||
|
u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK);
|
||||||
|
writel(tmp, pcie->base + HARD_DEBUG(pcie));
|
||||||
|
|
||||||
|
ret = pcie->cfg->perst_set(pcie, 0);
|
||||||
|
fsleep(pcie->tperst_clk_ms * USEC_PER_MSEC);
|
||||||
|
|
||||||
|
tmp = readl(pcie->base + HARD_DEBUG(pcie));
|
||||||
|
u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK);
|
||||||
|
writel(tmp, pcie->base + HARD_DEBUG(pcie));
|
||||||
|
} else {
|
||||||
|
ret = pcie->cfg->perst_set(pcie, 0);
|
||||||
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -2074,6 +2095,8 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
|||||||
pcie->ssc = !(pcie->cfg->quirks & CFG_QUIRK_NO_SSC) &&
|
pcie->ssc = !(pcie->cfg->quirks & CFG_QUIRK_NO_SSC) &&
|
||||||
of_property_read_bool(np, "brcm,enable-ssc");
|
of_property_read_bool(np, "brcm,enable-ssc");
|
||||||
|
|
||||||
|
of_property_read_u32(np, "brcm,tperst-clk-ms", &pcie->tperst_clk_ms);
|
||||||
|
|
||||||
pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal");
|
pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal");
|
||||||
if (IS_ERR(pcie->rescal))
|
if (IS_ERR(pcie->rescal))
|
||||||
return PTR_ERR(pcie->rescal);
|
return PTR_ERR(pcie->rescal);
|
||||||
|
|||||||
Reference in New Issue
Block a user