pci: pcie_dw_rockchip: Speed up link probe
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>
diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c
index 1b8a140..82a8b9c 100644
--- a/drivers/pci/pcie_dw_rockchip.c
+++ b/drivers/pci/pcie_dw_rockchip.c
@@ -61,9 +61,6 @@
#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 @@
/* 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;
- }
+ /*
+ * 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);
+ }
- 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);
+ 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 @@
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) {