]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: mediatek-gen3: Avoid PCIe resetting via PERST# for Airoha EN7581 SoC
authorLorenzo Bianconi <lorenzo@kernel.org>
Wed, 8 Jan 2025 23:30:45 +0000 (00:30 +0100)
committerKrzysztof Wilczyński <kwilczynski@kernel.org>
Mon, 13 Jan 2025 07:09:42 +0000 (07:09 +0000)
Airoha EN7581 has a hw bug asserting/releasing PERST# signal causing
occasional PCIe link down issues. In order to overcome the problem,
PERST# signal is not asserted/released during device probe or
suspend/resume phase and the PCIe block is reset using
en7523_reset_assert() and en7581_pci_enable().

Introduce flags field in the mtk_gen3_pcie_pdata struct in order to
specify per-SoC capabilities.

Link: https://lore.kernel.org/r/20250109-pcie-en7581-rst-fix-v4-1-4a45c89fb143@kernel.org
Tested-by: Hui Ma <hui.ma@airoha.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
drivers/pci/controller/pcie-mediatek-gen3.c

index aa511965eb914f7e58e78194491ca7a23790b99d..1edf5d6708c2df73fd55ec622c356e71aefe04f7 100644 (file)
@@ -135,10 +135,18 @@ struct mtk_gen3_pcie;
 #define PCIE_CONF_LINK2_CTL_STS                (PCIE_CFG_OFFSET_ADDR + 0xb0)
 #define PCIE_CONF_LINK2_LCR2_LINK_SPEED        GENMASK(3, 0)
 
+enum mtk_gen3_pcie_flags {
+       SKIP_PCIE_RSTB  = BIT(0), /* Skip PERST# assertion during device
+                                  * probing or suspend/resume phase to
+                                  * avoid hw bugs/issues.
+                                  */
+};
+
 /**
  * struct mtk_gen3_pcie_pdata - differentiate between host generations
  * @power_up: pcie power_up callback
  * @phy_resets: phy reset lines SoC data.
+ * @flags: pcie device flags.
  */
 struct mtk_gen3_pcie_pdata {
        int (*power_up)(struct mtk_gen3_pcie *pcie);
@@ -146,6 +154,7 @@ struct mtk_gen3_pcie_pdata {
                const char *id[MAX_NUM_PHY_RESETS];
                int num_resets;
        } phy_resets;
+       u32 flags;
 };
 
 /**
@@ -440,22 +449,33 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie)
        val |= PCIE_DISABLE_DVFSRC_VLT_REQ;
        writel_relaxed(val, pcie->base + PCIE_MISC_CTRL_REG);
 
-       /* Assert all reset signals */
-       val = readl_relaxed(pcie->base + PCIE_RST_CTRL_REG);
-       val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB;
-       writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
-
        /*
-        * Described in PCIe CEM specification sections 2.2 (PERST# Signal)
-        * and 2.2.1 (Initial Power-Up (G3 to S0)).
-        * The deassertion of PERST# should be delayed 100ms (TPVPERL)
-        * for the power and clock to become stable.
+        * Airoha EN7581 has a hw bug asserting/releasing PCIE_PE_RSTB signal
+        * causing occasional PCIe link down. In order to overcome the issue,
+        * PCIE_RSTB signals are not asserted/released at this stage and the
+        * PCIe block is reset using en7523_reset_assert() and
+        * en7581_pci_enable().
         */
-       msleep(100);
-
-       /* De-assert reset signals */
-       val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB);
-       writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
+       if (!(pcie->soc->flags & SKIP_PCIE_RSTB)) {
+               /* Assert all reset signals */
+               val = readl_relaxed(pcie->base + PCIE_RST_CTRL_REG);
+               val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB |
+                      PCIE_PE_RSTB;
+               writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
+
+               /*
+                * Described in PCIe CEM specification revision 6.0.
+                *
+                * The deassertion of PERST# should be delayed 100ms (TPVPERL)
+                * for the power and clock to become stable.
+                */
+               msleep(PCIE_T_PVPERL_MS);
+
+               /* De-assert reset signals */
+               val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB |
+                        PCIE_PE_RSTB);
+               writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
+       }
 
        /* Check if the link is up or not */
        err = readl_poll_timeout(pcie->base + PCIE_LINK_STATUS_REG, val,
@@ -1242,10 +1262,12 @@ static int mtk_pcie_suspend_noirq(struct device *dev)
                return err;
        }
 
-       /* Pull down the PERST# pin */
-       val = readl_relaxed(pcie->base + PCIE_RST_CTRL_REG);
-       val |= PCIE_PE_RSTB;
-       writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
+       if (!(pcie->soc->flags & SKIP_PCIE_RSTB)) {
+               /* Assert the PERST# pin */
+               val = readl_relaxed(pcie->base + PCIE_RST_CTRL_REG);
+               val |= PCIE_PE_RSTB;
+               writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG);
+       }
 
        dev_dbg(pcie->dev, "entered L2 states successfully");
 
@@ -1296,6 +1318,7 @@ static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_en7581 = {
                .id[2] = "phy-lane2",
                .num_resets = 3,
        },
+       .flags = SKIP_PCIE_RSTB,
 };
 
 static const struct of_device_id mtk_pcie_of_match[] = {