summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2016-11-10 14:55:31 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2016-11-21 15:05:21 +0100
commit3e2259b04c2e2c029f742e9dda06a3a2739977d4 (patch)
tree7af7fe9210ccdf2e2e6d70f522014784e7ee888c
parent1cb425d3e668e3d2b77872d5440fffd87ac9cf21 (diff)
apalis-tk1: fix pcie clock and reset not conforming to specification
Fix PCIe clock and reset not conforming to specification by moving PCIe reset handling including the PLX PEX 8605 errata 5 workaround from the board platform data into the right places timing wise in the PCIe driver itself. Also add a kernel command line argument to allow using the Apalis GPIO7 as a regular GPIO rather than for above mentioned PLX PEX 8605 workaround: pex_perst=0 Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Acked-by: Dominik Sliwa <dominik.sliwa@toradex.com> (cherry picked from tegra-next commit a2f63805703b43d55d91ae17f10d0049bf0f625e)
-rw-r--r--arch/arm/mach-tegra/board-apalis-tk1.c22
-rw-r--r--drivers/pci/host/pci-tegra.c50
2 files changed, 50 insertions, 22 deletions
diff --git a/arch/arm/mach-tegra/board-apalis-tk1.c b/arch/arm/mach-tegra/board-apalis-tk1.c
index 22a1f7d10d21..ac6b122fbc1a 100644
--- a/arch/arm/mach-tegra/board-apalis-tk1.c
+++ b/arch/arm/mach-tegra/board-apalis-tk1.c
@@ -592,28 +592,6 @@ static void __init tegra_apalis_tk1_dt_init(void)
apalis_tk1_auxdata_lookup, &platform_bus);
#endif
- /* Reset PLX PEX 8605 PCIe Switch plus PCIe devices on Apalis Evaluation
- Board */
- gpio_request(PEX_PERST_N, "PEX_PERST_N");
- gpio_request(RESET_MOCI_N, "RESET_MOCI_N");
- gpio_direction_output(PEX_PERST_N, 0);
- gpio_direction_output(RESET_MOCI_N, 0);
- /* Must be asserted for 100 ms after power and clocks are stable */
- mdelay(100);
- gpio_set_value(PEX_PERST_N, 1);
- /* Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not Guaranteed Until
- 900 us After PEX_PERST# De-assertion */
- mdelay(1);
- gpio_set_value(RESET_MOCI_N, 1);
-
-#if 0
- /* Reset I210 Gigabit Ethernet Controller */
- gpio_request(LAN_RESET_N, "LAN_RESET_N");
- gpio_direction_output(LAN_RESET_N, 0);
- mdelay(100);
- gpio_set_value(LAN_RESET_N, 1);
-#endif
-
tegra_apalis_tk1_late_init();
}
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 371dc91c4cf5..9deee61446ff 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -59,6 +59,10 @@
#include <mach/pinmux.h>
#include <mach/pinmux-t12.h>
+#ifdef CONFIG_MACH_APALIS_TK1
+#include "../../../arch/arm/mach-tegra/board-apalis-tk1.h"
+#endif
+
/* register definitions */
#define AFI_OFFSET 0x3800
#define PADS_OFFSET 0x3000
@@ -304,6 +308,21 @@ static unsigned long tegra_pcie_mselect_rate = TEGRA_PCIE_MSELECT_CLK_204;
static unsigned long tegra_pcie_xclk_rate = TEGRA_PCIE_XCLK_250;
static unsigned long tegra_pcie_emc_rate = TEGRA_PCIE_EMC_CLK_102;
+#ifdef CONFIG_MACH_APALIS_TK1
+/* To disable the PCIe switch reset errata workaround */
+int g_pex_perst = 1;
+
+/* To disable the PCIe switch reset errata workaround */
+static int __init disable_pex_perst(char *s)
+{
+ if (!(*s) || !strcmp(s, "0"))
+ g_pex_perst = 0;
+
+ return 0;
+}
+__setup("pex_perst=", disable_pex_perst);
+#endif /* CONFIG_MACH_APALIS_TK1 */
+
static inline void afi_writel(u32 value, unsigned long offset)
{
writel(value, offset + AFI_OFFSET + tegra_pcie.regs);
@@ -963,6 +982,20 @@ static int tegra_pcie_enable_controller(void)
int i, ret = 0, lane_owner;
PR_FUNC_LINE;
+
+#ifdef CONFIG_MACH_APALIS_TK1
+ /* Reset PLX PEX 8605 PCIe Switch plus PCIe devices on Apalis Evaluation
+ Board */
+ if (g_pex_perst) gpio_request(PEX_PERST_N, "PEX_PERST_N");
+ gpio_request(RESET_MOCI_N, "RESET_MOCI_N");
+ if (g_pex_perst) gpio_direction_output(PEX_PERST_N, 0);
+ gpio_direction_output(RESET_MOCI_N, 0);
+
+ /* Reset I210 Gigabit Ethernet Controller */
+ gpio_request(LAN_RESET_N, "LAN_RESET_N");
+ gpio_direction_output(LAN_RESET_N, 0);
+#endif /* CONFIG_MACH_APALIS_TK1 */
+
/* Enable slot clock and ensure reset signal is assert */
for (i = 0; i < ARRAY_SIZE(pex_controller_registers); i++) {
reg = pex_controller_registers[i];
@@ -1035,12 +1068,28 @@ static int tegra_pcie_enable_controller(void)
/* Take the PCIe interface module out of reset */
tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
+ /* Wait for clock to latch (min of 100us) */
+ udelay(100);
+
/* deassert PEX reset signal */
for (i = 0; i < ARRAY_SIZE(pex_controller_registers); i++) {
val = afi_readl(pex_controller_registers[i]);
val |= AFI_PEX_CTRL_RST;
afi_writel(val, pex_controller_registers[i]);
}
+
+#ifdef CONFIG_MACH_APALIS_TK1
+ /* Must be asserted for 100 ms after power and clocks are stable */
+ if (g_pex_perst) gpio_set_value(PEX_PERST_N, 1);
+ /* Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not Guaranteed Until
+ 900 us After PEX_PERST# De-assertion */
+ if (g_pex_perst) mdelay(1);
+ gpio_set_value(RESET_MOCI_N, 1);
+
+ /* Release I210 Gigabit Ethernet Controller Reset */
+ gpio_set_value(LAN_RESET_N, 1);
+#endif /* CONFIG_MACH_APALIS_TK1 */
+
return ret;
}
@@ -1454,6 +1503,7 @@ static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
retry:
if (--retries) {
/* Pulse the PEX reset */
+/* TBD: timing not as per PCIe spec */
reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
afi_writel(reg, reset_reg);
reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;