From bf8a71dbd221bf7245177f1848bbc9e10f2dfb7e Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 31 Mar 2025 14:41:45 +0100 Subject: [PATCH] PCI: pcie-brcmstb: add more safeguards for clkreq "safe" mode The existing implementation for clkreq-mode="safe" leaves the HARD_DEBUG with both control bits clear. This can cause link failure if L1 sub-states are enabled and if either of these conditions occurrs: - The platform does not connect the CLRKEQ# signal to the EP, and a pull-up is present on the line - The platform connects the signal to the EP, and the EP enters an L1.x or ClkPM state Additional register bits in the HARD_DEBUG register can be used to force the RC to drive CLKREQ# low. Also, un-advertise L1ss as a) additional power savings can't be realised and b) enabling L1ss may incur additional wake latency from L1.0. Signed-off-by: Jonathan Bell --- drivers/pci/controller/pcie-brcmstb.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -135,11 +135,15 @@ #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_REFCLK_OVRD_ENABLE_MASK 0x10000 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_OUT_MASK 0x100000 #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 #define PCIE_CLKREQ_MASK \ (PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK | \ + PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_ENABLE_MASK | \ + PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_OUT_MASK | \ PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK) #define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac @@ -1470,12 +1474,21 @@ static void brcm_config_clkreq(struct br } else { /* - * "safe" -- No power savings; refclk is driven by RC + * "safe" -- No power savings; refclk and CLKREQ# are driven by RC * unconditionally. */ if (strcmp(mode, "safe") != 0) dev_err(pcie->dev, err_msg); mode = "safe"; + clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_OUT_MASK; + clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_ENABLE_MASK; + /* + * Un-advertise L1ss as configuring an EP to enter L1.x with CLKREQ# + * physically unconnected will result in a dead link. + */ + tmp = readl(pcie->base + PCIE_RC_CFG_PRIV1_ROOT_CAP); + u32p_replace_bits(&tmp, 2, PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK); + writel(tmp, pcie->base + PCIE_RC_CFG_PRIV1_ROOT_CAP); } writel(clkreq_cntl, pcie->base + HARD_DEBUG(pcie));