]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
pci: pcie_dw_rockchip: Speed up link probe
authorJonas Karlman <jonas@kwiboo.se>
Sat, 22 Jul 2023 13:30:19 +0000 (13:30 +0000)
committerKever Yang <kever.yang@rock-chips.com>
Fri, 28 Jul 2023 10:45:03 +0000 (18:45 +0800)
Use a similar pattern and delay values as the linux mainline driver to
speed up failing when nothing is connected.

Reduce fail speed from around 5+ seconds down to around one second on a
Radxa ROCK 3 Model A, where pcie2x1 is probed before pcie3x2 M2 slot.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
drivers/pci/pcie_dw_rockchip.c

index 1b8a1409f6dfdd98439b9a36f7673e78c51c57c7..82a8b9c96e2ba28fda2c6058a7dcc99a0b9df105 100644 (file)
@@ -61,9 +61,6 @@ struct rk_pcie {
 #define PCIE_CLIENT_DBG_TRANSITION_DATA        0xffff0000
 #define PCIE_CLIENT_DBF_EN             0xffff0003
 
-/* Parameters for the waiting for #perst signal */
-#define MACRO_US                       1000
-
 static int rk_pcie_read(void __iomem *addr, int size, u32 *val)
 {
        if ((uintptr_t)addr & (size - 1)) {
@@ -242,43 +239,46 @@ static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
        /* DW pre link configurations */
        rk_pcie_configure(priv, cap_speed);
 
-       /* Rest the device */
-       if (dm_gpio_is_valid(&priv->rst_gpio)) {
-               dm_gpio_set_value(&priv->rst_gpio, 0);
-               /*
-                * Minimal is 100ms from spec but we see
-                * some wired devices need much more, such as 600ms.
-                * Add a enough delay to cover all cases.
-                */
-               udelay(MACRO_US * 1000);
-               dm_gpio_set_value(&priv->rst_gpio, 1);
-       }
-
        rk_pcie_disable_ltssm(priv);
        rk_pcie_link_status_clear(priv);
        rk_pcie_enable_debug(priv);
 
+       /* Reset the device */
+       if (dm_gpio_is_valid(&priv->rst_gpio))
+               dm_gpio_set_value(&priv->rst_gpio, 0);
+
        /* Enable LTSSM */
        rk_pcie_enable_ltssm(priv);
 
-       for (retries = 0; retries < 5; retries++) {
-               if (is_link_up(priv)) {
-                       dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n",
-                                rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
-                       rk_pcie_debug_dump(priv);
-                       return 0;
-               }
-
-               dev_info(priv->dw.dev, "PCIe Linking... LTSSM is 0x%x\n",
-                        rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
-               rk_pcie_debug_dump(priv);
-               udelay(MACRO_US * 1000);
+       /*
+        * PCIe requires the refclk to be stable for 100ms prior to releasing
+        * PERST. See table 2-4 in section 2.6.2 AC Specifications of the PCI
+        * Express Card Electromechanical Specification, 1.1. However, we don't
+        * know if the refclk is coming from RC's PHY or external OSC. If it's
+        * from RC, so enabling LTSSM is the just right place to release #PERST.
+        */
+       mdelay(100);
+       if (dm_gpio_is_valid(&priv->rst_gpio))
+               dm_gpio_set_value(&priv->rst_gpio, 1);
+
+       /* Check if the link is up or not */
+       for (retries = 0; retries < 10; retries++) {
+               if (is_link_up(priv))
+                       break;
+
+               mdelay(100);
+       }
+
+       if (retries >= 10) {
+               dev_err(priv->dw.dev, "PCIe-%d Link Fail\n",
+                       dev_seq(priv->dw.dev));
+               return -EIO;
        }
 
-       dev_err(priv->dw.dev, "PCIe-%d Link Fail\n", dev_seq(priv->dw.dev));
-       /* Link maybe in Gen switch recovery but we need to wait more 1s */
-       udelay(MACRO_US * 1000);
-       return -EIO;
+       dev_info(priv->dw.dev, "PCIe Link up, LTSSM is 0x%x\n",
+                rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
+       rk_pcie_debug_dump(priv);
+       return 0;
 }
 
 static int rockchip_pcie_init_port(struct udevice *dev)
@@ -287,6 +287,12 @@ static int rockchip_pcie_init_port(struct udevice *dev)
        u32 val;
        struct rk_pcie *priv = dev_get_priv(dev);
 
+       ret = reset_assert_bulk(&priv->rsts);
+       if (ret) {
+               dev_err(dev, "failed to assert resets (ret=%d)\n", ret);
+               return ret;
+       }
+
        /* Set power and maybe external ref clk input */
        ret = regulator_set_enable_if_allowed(priv->vpcie3v3, true);
        if (ret && ret != -ENOSYS) {