drivers: pci: brcmstb: optionally extend Tperst_clk time during link-up
authorJonathan Bell <jonathan@raspberrypi.com>
Wed, 20 Sep 2023 12:01:11 +0000 (13:01 +0100)
committerDom Cobley <popcornmix@gmail.com>
Mon, 19 Feb 2024 11:35:09 +0000 (11:35 +0000)
The RC has a feature that allows for manual control over the deassertion
of the PERST# output pin, which allows the time between refclk active
and reset deassert at the EP to be increased.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
drivers/pci/controller/pcie-brcmstb.c

index 3722443..618e844 100644 (file)
 
 #define PCIE_MISC_HARD_PCIE_HARD_DEBUG pcie->reg_offsets[PCIE_HARD_DEBUG]
 #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_SERDES_IDDQ_MASK               0x08000000
 #define  PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK         0x00800000
 #define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK                0x00200000
@@ -354,6 +355,7 @@ struct brcm_pcie {
        bool                    (*rc_mode)(struct brcm_pcie *pcie);
        struct subdev_regulators *sr;
        bool                    ep_wakeup_capable;
+       u32                     tperst_clk_ms;
 };
 
 static inline bool is_bmips(const struct brcm_pcie *pcie)
@@ -1386,9 +1388,28 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
        u16 nlw, cls, lnksta;
        bool ssc_good = false;
        int ret, i;
+       u32 tmp;
 
        /* Unassert the fundamental reset */
-       pcie->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(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+               u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK);
+               writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+
+               pcie->perst_set(pcie, 0);
+               msleep(pcie->tperst_clk_ms);
+
+               tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+               u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK);
+               writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+       } else {
+               pcie->perst_set(pcie, 0);
+       }
 
        /*
         * Wait for 100ms after PERST# deassertion; see PCIe CEM specification
@@ -1919,6 +1940,7 @@ static int brcm_pcie_probe(struct platform_device *pdev)
        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);
 
        ret = clk_prepare_enable(pcie->clk);
        if (ret) {