summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2017-08-10 15:28:40 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2017-09-20 17:45:12 +0200
commit7ad9771527d2b1c884beb22d9df28bae899f8d3d (patch)
tree6f35ab125527b2d21ab2bee26012060e58f435d8 /drivers
parent9efd8683fc4b4d626e3116fc62ba2417a0fc5a94 (diff)
apalis-tk1: fix pcie reset for reliable gigabit ethernet operation
It turns out that the current PCIe reset implementation is not quite working reliably due to some Intel i210 errata. Fix this by making sure the i210's +V3.3_ETH rail is properly disabled during its reset sequence. Also further improve on the bringing up the PCIe switch as found on the Apalis Evaluation board. Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Acked-by: Dominik Sliwa <dominik.sliwa@toradex.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/host/pci-tegra.c149
1 files changed, 114 insertions, 35 deletions
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 1ef5791a892b..e0e7998f57f3 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -282,6 +282,10 @@ struct tegra_pcie_info {
struct regulator *regulator_hvdd;
struct regulator *regulator_pexio;
struct regulator *regulator_avdd_plle;
+#ifdef CONFIG_MACH_APALIS_TK1
+ struct regulator *regulator_apalis_tk1_ldo9;
+ struct regulator *regulator_apalis_tk1_ldo10;
+#endif /* CONFIG_MACH_APALIS_TK1 */
struct clk *pcie_xclk;
struct clk *pcie_mselect;
struct clk *pcie_emc;
@@ -976,25 +980,87 @@ static int tegra_pcie_enable_pads(bool enable)
return err;
}
-static int tegra_pcie_enable_controller(void)
+static void tegra_pcie_port_reset(struct tegra_pcie_port *pp, u32 reset_reg)
{
- u32 val, reg;
- int i, ret = 0, lane_owner;
+ u32 reg;
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);
+ gpio_direction_output(RESET_MOCI_CTRL, 0);
/* Reset I210 Gigabit Ethernet Controller */
- gpio_request(LAN_RESET_N, "LAN_RESET_N");
gpio_direction_output(LAN_RESET_N, 0);
+
+ /*
+ * Make sure we don't get any back feeding from LAN_WAKE_N resp.
+ * DEV_OFF_N
+ */
+ gpio_direction_output(LAN_WAKE_N, 0);
+ gpio_direction_output(LAN_DEV_OFF_N, 0);
+
+ /* Make sure LDO9 and LDO10 are initially disabled @ 0V */
+ if (regulator_is_enabled(tegra_pcie.regulator_apalis_tk1_ldo9))
+ regulator_disable(tegra_pcie.regulator_apalis_tk1_ldo9);
+ if (regulator_is_enabled(tegra_pcie.regulator_apalis_tk1_ldo10))
+ regulator_disable(tegra_pcie.regulator_apalis_tk1_ldo10);
+
+ mdelay(100);
+
+ /* Make sure LAN_WAKE_N gets re-configured as a GPIO input */
+ gpio_direction_input(LAN_WAKE_N);
+
+ /* Make sure controller gets enabled by disabling DEV_OFF_N */
+ gpio_set_value(LAN_DEV_OFF_N, 1);
+
+ /*
+ * Enable LDO9 and LDO10 for +V3.3_ETH on patched prototype
+ * V1.0A and sample V1.0B and newer modules
+ */
+ if (regulator_enable(tegra_pcie.regulator_apalis_tk1_ldo9) < 0) {
+ pr_err("pcie: couldn't enable regulator i210_vdd3p3_ldo9\n");
+ return;
+ }
+ if (regulator_enable(tegra_pcie.regulator_apalis_tk1_ldo10) < 0) {
+ pr_err("pcie: couldn't enable regulator i210_vdd3p3_ldo10\n");
+ return;
+ }
+#endif /* CONFIG_MACH_APALIS_TK1 */
+
+ /* Pulse the PEX reset */
+ reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+
+ /* Must be asserted for 100 ms after power and clocks are stable */
+ mdelay(100);
+
+ reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
+ afi_writel(reg, reset_reg);
+
+#ifdef CONFIG_MACH_APALIS_TK1
+ gpio_set_value(LAN_RESET_N, 1);
+
+ 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_CTRL, 1);
+
+ /* Release I210 Gigabit Ethernet Controller Reset */
+ gpio_set_value(LAN_RESET_N, 1);
#endif /* CONFIG_MACH_APALIS_TK1 */
+}
+
+static int tegra_pcie_enable_controller(void)
+{
+ u32 val, reg;
+ int i, ret = 0, lane_owner;
+ struct tegra_pcie_port *pp;
+ int ctrl_offset = AFI_PEX0_CTRL;
+
+ PR_FUNC_LINE;
/* Enable slot clock and ensure reset signal is assert */
for (i = 0; i < ARRAY_SIZE(pex_controller_registers); i++) {
@@ -1071,25 +1137,12 @@ static int tegra_pcie_enable_controller(void)
/* 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]);
+ pp = tegra_pcie.port + tegra_pcie.num_ports;
+ for (i = 0; i < MAX_PCIE_SUPPORTED_PORTS; i++) {
+ ctrl_offset += (i * 8);
+ tegra_pcie_port_reset(pp, ctrl_offset);
}
-#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;
}
@@ -1138,12 +1191,37 @@ static int tegra_pcie_enable_regulators(void)
tegra_pcie.regulator_avdd_plle = 0;
}
}
+
+#ifdef CONFIG_MACH_APALIS_TK1
+ if (tegra_pcie.regulator_apalis_tk1_ldo9 == NULL) {
+ tegra_pcie.regulator_apalis_tk1_ldo9 = regulator_get(tegra_pcie.dev, "i210_vdd3p3_ldo9");
+ if (IS_ERR(tegra_pcie.regulator_apalis_tk1_ldo9)) {
+ pr_err("pcie: couldn't get regulator i210_vdd3p3_ldo9\n");
+ tegra_pcie.regulator_apalis_tk1_ldo9 = 0;
+ }
+ }
+
+ if (tegra_pcie.regulator_apalis_tk1_ldo10 == NULL) {
+ tegra_pcie.regulator_apalis_tk1_ldo10 = regulator_get(tegra_pcie.dev, "i210_vdd3p3_ldo10");
+ if (IS_ERR(tegra_pcie.regulator_apalis_tk1_ldo10)) {
+ pr_err("pcie: couldn't get regulator i210_vdd3p3_ldo10\n");
+ tegra_pcie.regulator_apalis_tk1_ldo10 = 0;
+ }
+ }
+#endif /* CONFIG_MACH_APALIS_TK1 */
+
if (tegra_pcie.regulator_hvdd)
ret = regulator_enable(tegra_pcie.regulator_hvdd);
if (tegra_pcie.regulator_pexio)
ret = regulator_enable(tegra_pcie.regulator_pexio);
if (tegra_pcie.regulator_avdd_plle)
ret = regulator_enable(tegra_pcie.regulator_avdd_plle);
+#ifdef CONFIG_MACH_APALIS_TK1
+ if (tegra_pcie.regulator_apalis_tk1_ldo9)
+ ret = regulator_enable(tegra_pcie.regulator_apalis_tk1_ldo9);
+ if (tegra_pcie.regulator_apalis_tk1_ldo10)
+ ret = regulator_enable(tegra_pcie.regulator_apalis_tk1_ldo10);
+#endif /* CONFIG_MACH_APALIS_TK1 */
return 0;
}
@@ -1506,16 +1584,8 @@ 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;
- afi_writel(reg, reset_reg);
- }
-
- } while (retries);
+ tegra_pcie_port_reset(pp, reset_reg);
+ } while (--retries);
return false;
}
@@ -1943,6 +2013,15 @@ static int __init tegra_pcie_init(void)
tegra_pcie_power_off(false);
return err;
}
+
+#ifdef CONFIG_MACH_APALIS_TK1
+ gpio_request(LAN_DEV_OFF_N, "LAN_DEV_OFF_N");
+ gpio_request(LAN_RESET_N, "LAN_RESET_N");
+ gpio_request(LAN_WAKE_N, "LAN_WAKE_N");
+ if (g_pex_perst) gpio_request(PEX_PERST_N, "PEX_PERST_N");
+ gpio_request(RESET_MOCI_CTRL, "RESET_MOCI_CTRL");
+#endif /* CONFIG_MACH_APALIS_TK1 */
+
err = tegra_pcie_enable_controller();
if (err) {
pr_err("PCIE: enable controller failed\n");