]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
pcie: host: tegra: optimize boot time
authorVidya Sagar <vidyas@nvidia.com>
Mon, 28 Dec 2015 11:32:12 +0000 (17:02 +0530)
committermobile promotions <svcmobile_promotions@nvidia.com>
Tue, 19 Jan 2016 18:02:40 +0000 (10:02 -0800)
optimizes pcie link detection by initially checking for
DL_LINK_ACTIVE with a timeout out of 100ms (spec defined)
and further PERST and link detection cycles are based on
whether or not RDET_STATUS of UPHY lanes corresponding to
PCIe ports is set

Bug 200159257

Change-Id: I8dcbd37cdff5b60c0f36c61e492ba685862802d0
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-on: http://git-master/r/927110
(cherry picked from commit ed5b09a5ebfb576a5105ea5fd6633285a4f55030)
Reviewed-on: http://git-master/r/932523
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Hayden Du <haydend@nvidia.com>
arch/arm/mach-tegra/include/mach/tegra_usb_pad_ctrl.h
drivers/pci/host/pci-tegra.c
drivers/platform/tegra/tegra_usb_pad_ctrl.c

index 6727febaa4cfacf86238b78b033383eacb34391f..1df0808994ce63364af2c706f3332b13b33c8e2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2016, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -141,8 +141,11 @@ static inline enum padctl_lane usb3_laneowner_to_lane_enum(u8 laneowner)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1      0x460
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_RX_IDLE_TH_MASK  (0x3 << 24)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_RX_IDLE_TH       (1 << 24)
+#define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_TX_RDET_STATUS   (1 << 7)
 
 #define XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL1      0x4A0
+#define XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL1_AUX_TX_RDET_STATUS   (1 << 7)
+
 #define XUSB_PADCTL_UPHY_MISC_PAD_P2_CTL1      0x4E0
 #define XUSB_PADCTL_UPHY_MISC_PAD_P3_CTL1      0x520
 #define XUSB_PADCTL_UPHY_MISC_PAD_P4_CTL1      0x560
@@ -647,6 +650,7 @@ int utmi_phy_pad_enable(struct tegra_prod_list *prod_list);
 #endif
 int usb3_phy_pad_enable(u32 lane_owner);
 int pcie_phy_pad_enable(bool enable, int lane_owner);
+bool tegra_phy_get_lane_rdet(u8 lane_num);
 
 int utmi_phy_iddq_override(bool set);
 void tegra_usb_pad_reg_update(u32 reg_offset, u32 mask, u32 val);
index 503edfec2324b64f1fe8b390a8176f4500dfd4fc..3de1789922298d4a0f7fbcc7a2a1a53e1d18e8a6 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/tegra-powergate.h>
 #include <linux/tegra-soc.h>
-#include <linux/pci-tegra.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #include <linux/of_gpio.h>
 #include <linux/of_pci.h>
+#include <linux/tegra_prod.h>
 #include <linux/tegra_pm_domains.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/consumer.h>
@@ -65,6 +65,7 @@
 
 #include <mach/tegra_usb_pad_ctrl.h>
 #include <mach/io_dpd.h>
+#include <linux/pci-tegra.h>
 
 #define PCI_CFG_SPACE_SIZE             256
 #define PCI_EXT_CFG_SPACE_SIZE 4096
 #define RP_LINK_CONTROL_STATUS_L0s_ENABLED             0x00000001
 #define RP_LINK_CONTROL_STATUS_L1_ENABLED              0x00000002
 
+#define RP_LINK_CONTROL_STATUS_2                               0x000000B0
+#define RP_LINK_CONTROL_STATUS_2_TRGT_LNK_SPD_MASK     0x0000000F
+#define RP_LINK_CONTROL_STATUS_2_TRGT_LNK_SPD_GEN1     0x00000001
+#define RP_LINK_CONTROL_STATUS_2_TRGT_LNK_SPD_GEN2     0x00000002
+
 #define NV_PCIE2_RP_RSR                                        0x000000A0
 #define NV_PCIE2_RP_RSR_PMESTAT                                (1 << 16)
 
@@ -358,6 +364,10 @@ static struct of_device_id tegra_pcie_pd[] = {
 };
 #endif
 
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+static u32 rp_to_lane_map[] = {1, 0};
+#endif
+
 struct tegra_pcie_soc_data {
        unsigned int    num_ports;
        char                    **pcie_regulator_names;
@@ -1749,7 +1759,7 @@ static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
  * can result in the increase of the bootup time as there are big timeout
  * loops.
  */
-#define TEGRA_PCIE_LINKUP_TIMEOUT      200     /* up to 1.2 seconds */
+#define TEGRA_PCIE_LINKUP_TIMEOUT      100     /* up to 100 ms */
 static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
 {
        unsigned int retries = 3;
@@ -1759,33 +1769,23 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
        do {
                unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
 
-               do {
-                       value = readl(port->base + RP_VEND_XP);
-
-                       if (value & RP_VEND_XP_DL_UP)
-                               break;
-
-                       usleep_range(1000, 2000);
-               } while (--timeout);
-
-               if (!timeout) {
-                       dev_info(port->pcie->dev, "link %u down, retrying\n",
-                               port->index);
-                       goto retry;
-               }
-
-               timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
-
                do {
                        value = readl(port->base + RP_LINK_CONTROL_STATUS);
-
                        if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
                                return true;
-
                        usleep_range(1000, 2000);
                } while (--timeout);
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+               if (tegra_phy_get_lane_rdet(
+                               rp_to_lane_map[port->index]))
+                       goto retry;
+               else
+                       return false;
 
 retry:
+#endif
+               dev_info(port->pcie->dev, "link %u down, retrying\n",
+                                       port->index);
                tegra_pcie_port_reset(port);
        } while (--retries);
 
@@ -1819,6 +1819,18 @@ static void tegra_pcie_apply_sw_war(struct tegra_pcie_port *port,
                        if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
                                pdev->msi_enabled = 0;
        } else {
+
+               /* Some of the old PCIe end points don't get enumerated
+                * if RP advertises both Gen-1 and Gen-2 speeds. Hence, the
+                * strategy followed here is to initially advertise only
+                * Gen-1 and after link is up, check end point's capability
+                * for Gen-2 and retrain link to Gen-2 speed
+                */
+               data = rp_readl(port, RP_LINK_CONTROL_STATUS_2);
+               data &= ~RP_LINK_CONTROL_STATUS_2_TRGT_LNK_SPD_MASK;
+               data |= RP_LINK_CONTROL_STATUS_2_TRGT_LNK_SPD_GEN1;
+               rp_writel(port, data, RP_LINK_CONTROL_STATUS_2);
+
                /* Avoid warning during enumeration for invalid IRQ of RP */
                data = rp_readl(port, NV_PCIE2_RP_INTR_BCR);
                data |= NV_PCIE2_RP_INTR_BCR_INTR_LINE;
index 8252f93a2f29a4c7795b8fef2cec658a389e3f85..902215081eff57f9fd4038dba2778b9a14cd9164 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2016, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -2082,6 +2082,29 @@ static void tegra_pcie_lane_aux_idle(bool ovdr, int lane)
        val |= XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_RX_IDLE_TH;
        writel(val, pad_base + misc_pad_ctl1_regs[lane]);
 }
+
+bool tegra_phy_get_lane_rdet(u8 lane_num)
+{
+       u32 data;
+       void __iomem *pad_base = IO_ADDRESS(TEGRA_XUSB_PADCTL_BASE);
+
+       switch (lane_num) {
+       case 0:
+               data = readl(pad_base + XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1);
+               data = data &
+                       XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_TX_RDET_STATUS;
+               break;
+       case 1:
+               data = readl(pad_base + XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL1);
+               data = data &
+                       XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL1_AUX_TX_RDET_STATUS;
+               break;
+       default:
+               return 0;
+       }
+       return !(!data);
+}
+EXPORT_SYMBOL_GPL(tegra_phy_get_lane_rdet);
 #endif
 
 static void tegra_pcie_lane_misc_pad_override(bool ovdr, int lane_owner)