diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2017-08-10 15:28:40 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2017-09-20 17:45:12 +0200 |
commit | 7ad9771527d2b1c884beb22d9df28bae899f8d3d (patch) | |
tree | 6f35ab125527b2d21ab2bee26012060e58f435d8 | |
parent | 9efd8683fc4b4d626e3116fc62ba2417a0fc5a94 (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>
-rw-r--r-- | arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-gpio.dtsi | 9 | ||||
-rw-r--r-- | arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-pmic.dtsi | 16 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-apalis-tk1.h | 4 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 149 |
4 files changed, 135 insertions, 43 deletions
diff --git a/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-gpio.dtsi b/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-gpio.dtsi index 100e3449c9b0..3dc15c51114b 100644 --- a/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-gpio.dtsi +++ b/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-gpio.dtsi @@ -36,6 +36,8 @@ >; gpio-output-low = < TEGRA_GPIO(C, 0) + TEGRA_GPIO(O, 5) /* LAN_WAKE_N */ + TEGRA_GPIO(O, 6) /* LAN_DEV_OFF_N */ TEGRA_GPIO(Q, 0) /* Shift_CTRL_OE[0] */ TEGRA_GPIO(Q, 1) /* Shift_CTRL_OE[1] */ TEGRA_GPIO(Q, 2) /* Shift_CTRL_OE[2] */ @@ -43,7 +45,9 @@ TEGRA_GPIO(R, 0) /* Shift_CTRL_Dir_In[0] */ TEGRA_GPIO(R, 1) /* Shift_CTRL_Dir_In[1] */ TEGRA_GPIO(R, 2) /* Shift_CTRL_OE[3] */ + TEGRA_GPIO(S, 2) /* LAN_RESET_N */ TEGRA_GPIO(S, 3) /* Shift_CTRL_Dir_In[2] */ + TEGRA_GPIO(U, 4) /* RESET_MOCI_CTRL */ TEGRA_GPIO(BB, 3) TEGRA_GPIO(BB, 6) >; @@ -51,14 +55,9 @@ TEGRA_GPIO(N, 2) TEGRA_GPIO(N, 4) TEGRA_GPIO(N, 5) -#if 0 - TEGRA_GPIO(O, 6) /* LAN_DEV_OFF# */ -#endif TEGRA_GPIO(Q, 5) /* Shift_CTRL_Dir_Out[0] */ TEGRA_GPIO(Q, 6) /* Shift_CTRL_Dir_Out[1] */ TEGRA_GPIO(Q, 7) /* Shift_CTRL_Dir_Out[2] */ - TEGRA_GPIO(S, 2) /* LAN_RESET# */ - TEGRA_GPIO(U, 4) TEGRA_GPIO(BB, 5) >; }; diff --git a/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-pmic.dtsi b/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-pmic.dtsi index 695891d28a80..342487b285f0 100644 --- a/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-pmic.dtsi +++ b/arch/arm/boot/dts/tegra124-platforms/tegra124-apalis-pmic.dtsi @@ -460,14 +460,26 @@ regulator-name = "+V3.3_ETH(ldo9)"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - regulator-always-on; + + consumers { + c1 { + regulator-consumer-supply = "i210_vdd3p3_ldo9"; + regulator-consumer-device = "pcie-controller.1"; + }; + }; }; as3722_ldo10: ldo10 { regulator-name = "+V3.3_ETH(ldo10)"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - regulator-always-on; + + consumers { + c1 { + regulator-consumer-supply = "i210_vdd3p3_ldo10"; + regulator-consumer-device = "pcie-controller.1"; + }; + }; }; as3722_ldo11: ldo11 { diff --git a/arch/arm/mach-tegra/board-apalis-tk1.h b/arch/arm/mach-tegra/board-apalis-tk1.h index b825abb0bdb2..d6114a1af820 100644 --- a/arch/arm/mach-tegra/board-apalis-tk1.h +++ b/arch/arm/mach-tegra/board-apalis-tk1.h @@ -60,7 +60,9 @@ #define I2C3_SCL TEGRA_GPIO_PBB1 #define I2C3_SDA TEGRA_GPIO_PBB2 +#define LAN_DEV_OFF_N TEGRA_GPIO_PO6 #define LAN_RESET_N TEGRA_GPIO_PS2 +#define LAN_WAKE_N TEGRA_GPIO_PO5 #define MMC1_CD_N TEGRA_GPIO_PV3 @@ -69,7 +71,7 @@ #define PWR_I2C_SCL TEGRA_GPIO_PZ6 #define PWR_I2C_SDA TEGRA_GPIO_PZ7 -#define RESET_MOCI_N TEGRA_GPIO_PU4 +#define RESET_MOCI_CTRL TEGRA_GPIO_PU4 #define SATA1_ACT_N TEGRA_GPIO_PN2 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"); |