diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2016-11-10 14:55:31 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2016-11-21 15:05:21 +0100 |
commit | 3e2259b04c2e2c029f742e9dda06a3a2739977d4 (patch) | |
tree | 7af7fe9210ccdf2e2e6d70f522014784e7ee888c | |
parent | 1cb425d3e668e3d2b77872d5440fffd87ac9cf21 (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.c | 22 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 50 |
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; |