summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorJay Agarwal <jagarwal@nvidia.com>2013-05-17 22:47:33 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:25:24 -0700
commit2ee545e148df4655ad9cd5b9e7e155903c0b9045 (patch)
treeb2eb6bf49a0c30ec01bf28ea8b8eacf13a561a44 /arch/arm/mach-tegra
parent1ed613d938f99233e234cc52036e3dc5e2613f80 (diff)
arm: tegra: pcie: T124: Add hotplug support
1. Set override bits in PRSNT MAP register based on endpoint presence on pcie slots. 2. Added FPGA phy init call in resume path. 3. Corrected root bus init in only cold boot path not in resume. 4. Correct power down sequece by turning of PCIe PME for all controllers. Bug 1263790 Bug 1264810 Change-Id: Iae8e60378f139343c5782380f16786d60ca75c1e Signed-off-by: Jay Agarwal <jagarwal@nvidia.com> Reviewed-on: http://git-master/r/223400 Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/board-bonaire-pinmux.c2
-rw-r--r--arch/arm/mach-tegra/board-bonaire.c4
-rw-r--r--arch/arm/mach-tegra/pcie.c145
3 files changed, 109 insertions, 42 deletions
diff --git a/arch/arm/mach-tegra/board-bonaire-pinmux.c b/arch/arm/mach-tegra/board-bonaire-pinmux.c
index f432e309aa91..8f078c5b5222 100644
--- a/arch/arm/mach-tegra/board-bonaire-pinmux.c
+++ b/arch/arm/mach-tegra/board-bonaire-pinmux.c
@@ -50,7 +50,7 @@ static __initdata struct tegra_drive_pingroup_config bonaire_drive_pinmux[] = {
/* !!!FIXME!!!! POPULATE THIS TABLE */
static __initdata struct tegra_pingroup_config bonaire_pinmux[] = {
- DEFAULT_PINMUX(ULPI_DATA0, SPI3, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA0, SPI3, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(ULPI_DATA1, SPI3, NORMAL, TRISTATE, INPUT),
DEFAULT_PINMUX(ULPI_DATA2, ULPI, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(ULPI_DATA3, ULPI, NORMAL, NORMAL, INPUT),
diff --git a/arch/arm/mach-tegra/board-bonaire.c b/arch/arm/mach-tegra/board-bonaire.c
index 5a3fa69f84ef..be0b331a4788 100644
--- a/arch/arm/mach-tegra/board-bonaire.c
+++ b/arch/arm/mach-tegra/board-bonaire.c
@@ -570,8 +570,8 @@ static void __init bonaire_hs_uart_init(void)
static struct tegra_pci_platform_data bonaire_pcie_platform_data = {
.port_status[0] = 1,
.port_status[1] = 1,
- .use_dock_detect = 0,
- .gpio = 0,
+ .use_dock_detect = 1,
+ .gpio = TEGRA_GPIO_PO1,
};
static void bonaire_pcie_init(void)
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 7313f21fa458..7d4233a7728b 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -136,7 +136,16 @@
#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7)
#define AFI_INTR_EN_PRSNT_SENSE (1 << 8)
-#define AFI_PCIE_CONFIG 0x0f8
+#define AFI_PCIE_PME 0x0f0
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+#define AFI_PCIE_PME_TURN_OFF 0x10101
+#define AFI_PCIE_PME_ACK 0x40420
+#else
+#define AFI_PCIE_PME_TURN_OFF 0x101
+#define AFI_PCIE_PME_ACK 0x420
+#endif
+
+#define AFI_PCIE_CONFIG 0x0f8
#define AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE (1 << 1)
#define AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE (1 << 2)
#define AFI_PCIE_CONFIG_PCIEC2_DISABLE_DEVICE (1 << 3)
@@ -213,7 +222,8 @@
#define NV_PCIE2_RP_RSR_PMESTAT (1 << 16)
#define NV_PCIE2_RP_PRIV_MISC 0x00000FE0
-#define PCIE2_RP_PRIV_MISC_PRSNT_MAP (0xE << 0)
+#define PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
+#define PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
#define PCIE2_RP_PRIV_MISC_CTRL_CLK_CLAMP_THRESHOLD (0xF << 16)
#define PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE (1 << 23)
#define PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD (0xF << 24)
@@ -363,6 +373,10 @@ static bool msi_enable;
/* this flag is used for enumeration by hotplug */
/* when dock is not connected while system boot */
static bool is_dock_conn_at_boot = true;
+/* used to identify if init is through boot or resume path */
+static bool is_resume_path;
+/* used to avoid successive hotplug disconnect or connect */
+static bool hotplug_event;
static inline void afi_writel(u32 value, unsigned long offset)
{
@@ -763,27 +777,55 @@ static void __init tegra_pcie_hotplug_init(void)
static int tegra_pcie_attach(void)
{
int err = 0;
+
+ if (!hotplug_event)
+ return err;
#ifdef CONFIG_PM
err = tegra_pcie_resume(NULL);
#endif
+ hotplug_event = false;
return err;
}
static int tegra_pcie_detach(void)
{
int err = 0;
+
+ if (hotplug_event)
+ return err;
#ifdef CONFIG_PM
err = tegra_pcie_suspend(NULL);
#endif
+ hotplug_event = true;
return err;
}
+#ifdef CONFIG_ARCH_TEGRA_12x_SOC
+static void tegra_pcie_prsnt_map_override(bool prsnt)
+{
+ unsigned int data;
+
+ if (hotplug_event)
+ return;
+ /* currently only hotplug on root port 0 supported */
+ PR_FUNC_LINE;
+ data = rp_readl(NV_PCIE2_RP_PRIV_MISC, 0);
+ data &= ~PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
+ if (prsnt)
+ data |= PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
+ else
+ data |= PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
+ rp_writel(data, NV_PCIE2_RP_PRIV_MISC, 0);
+}
+#endif
+
static void __init work_hotplug_handler(struct work_struct *work)
{
struct tegra_pcie_info *pcie_driver =
container_of(work, struct tegra_pcie_info, hotplug_detect);
int val;
+ PR_FUNC_LINE;
if (pcie_driver->plat_data->gpio == -1)
return;
val = gpio_get_value(pcie_driver->plat_data->gpio);
@@ -792,12 +834,16 @@ static void __init work_hotplug_handler(struct work_struct *work)
tegra_pcie_attach();
} else {
pr_info("Pcie Dock DisConnected\n");
+#ifdef CONFIG_ARCH_TEGRA_12x_SOC
+ tegra_pcie_prsnt_map_override(false);
+#endif
tegra_pcie_detach();
}
}
static irqreturn_t gpio_pcie_detect_isr(int irq, void *arg)
{
+ PR_FUNC_LINE;
schedule_work(&tegra_pcie.hotplug_detect);
return IRQ_HANDLED;
}
@@ -1142,7 +1188,6 @@ static int tegra_pcie_enable_regulators(void)
return 0;
}
-#endif
static int tegra_pcie_disable_regulators(void)
{
@@ -1167,6 +1212,7 @@ static int tegra_pcie_disable_regulators(void)
err_exit:
return err;
}
+#endif
static int tegra_pcie_power_regate(void)
{
@@ -1209,6 +1255,47 @@ void tegra_pcie_unmap_resources(void)
tegra_pcie.regs = 0;
}
}
+
+static void tegra_pcie_pme_turnoff(void)
+{
+ unsigned int data;
+
+ data = afi_readl(AFI_PCIE_PME);
+ data |= AFI_PCIE_PME_TURN_OFF;
+ afi_writel(data, AFI_PCIE_PME);
+ do {
+ data = afi_readl(AFI_PCIE_PME);
+ } while (!(data & AFI_PCIE_PME_ACK));
+}
+
+#ifdef CONFIG_TEGRA_FPGA_PLATFORM
+static int tegra_pcie_fpga_phy_init(void)
+{
+#define CLK_RST_BOND_OUT_REG 0x60006078
+#define CLK_RST_BOND_OUT_REG_PCIE (1 << 6)
+#define FPGA_GEN2_SPEED_SUPPORT 0x90000001
+ int val = 0;
+
+ PR_FUNC_LINE;
+ val = readl(IO_ADDRESS(CLK_RST_BOND_OUT_REG));
+ /* return if current netlist does not contain PCIE */
+ if (val & CLK_RST_BOND_OUT_REG_PCIE)
+ return -ENODEV;
+
+ /* Do reset for FPGA pcie phy */
+ afi_writel(AFI_WR_SCRATCH_0_RESET_VAL, AFI_WR_SCRATCH_0);
+ udelay(10);
+ afi_writel(AFI_WR_SCRATCH_0_DEFAULT_VAL, AFI_WR_SCRATCH_0);
+ udelay(10);
+ afi_writel(AFI_WR_SCRATCH_0_RESET_VAL, AFI_WR_SCRATCH_0);
+
+ /* required for gen2 speed support on FPGA */
+ rp_writel(FPGA_GEN2_SPEED_SUPPORT, RP_VEND_XP_BIST, 0);
+
+ return 0;
+}
+#endif
+
static int tegra_pcie_power_off(void);
static int tegra_pcie_power_on(void)
@@ -1238,6 +1325,13 @@ static int tegra_pcie_power_on(void)
pr_err("PCIE: Failed to map resources\n");
goto err_exit;
}
+#ifdef CONFIG_TEGRA_FPGA_PLATFORM
+ err = tegra_pcie_fpga_phy_init();
+ if (err) {
+ pr_err("PCIE: Failed to initialize FPGA Phy\n");
+ goto err_exit;
+ }
+#endif
err_exit:
if (err)
@@ -1254,6 +1348,7 @@ static int tegra_pcie_power_off(void)
pr_debug("PCIE: Already powered off");
goto err_exit;
}
+ tegra_pcie_pme_turnoff();
tegra_pcie_unmap_resources();
if (tegra_pcie.pll_e)
clk_disable_unprepare(tegra_pcie.pll_e);
@@ -1262,8 +1357,11 @@ static int tegra_pcie_power_off(void)
if (err)
goto err_exit;
+#ifndef CONFIG_TEGRA_FPGA_PLATFORM
err = tegra_pcie_disable_regulators();
-
+ if (err)
+ goto err_exit;
+#endif
tegra_pcie.pcie_power_enabled = 0;
err_exit:
return err;
@@ -1399,7 +1497,8 @@ static void tegra_pcie_enable_clock_clamp(int index)
/* Power mangagement settings */
/* Enable clock clamping by default */
data = PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE |
- PCIE2_RP_PRIV_MISC_PRSNT_MAP | PCIE2_RP_PRIV_MISC_CTRL_CLK_CLAMP_THRESHOLD |
+ PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT |
+ PCIE2_RP_PRIV_MISC_CTRL_CLK_CLAMP_THRESHOLD |
PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE;
rp_writel(data, NV_PCIE2_RP_PRIV_MISC, index);
}
@@ -1462,39 +1561,11 @@ static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
tegra_pcie.num_ports++;
pp->index = index;
/* don't initialize root bus in resume path but boot path only */
- if (!msi_enable)
+ if (!is_resume_path)
pp->root_bus_nr = -1;
memset(pp->res, 0, sizeof(pp->res));
}
-#ifdef CONFIG_TEGRA_FPGA_PLATFORM
-static int tegra_pcie_fpga_phy_init(void)
-{
-#define CLK_RST_BOND_OUT_REG 0x60006078
-#define CLK_RST_BOND_OUT_REG_PCIE (1 << 6)
-#define FPGA_GEN2_SPEED_SUPPORT 0x90000001
- int val = 0;
-
- PR_FUNC_LINE;
- val = readl(IO_ADDRESS(CLK_RST_BOND_OUT_REG));
- /* return if current netlist does not contain PCIE */
- if (val & CLK_RST_BOND_OUT_REG_PCIE)
- return -ENODEV;
-
- /* Do reset for FPGA pcie phy */
- afi_writel(AFI_WR_SCRATCH_0_RESET_VAL, AFI_WR_SCRATCH_0);
- udelay(10);
- afi_writel(AFI_WR_SCRATCH_0_DEFAULT_VAL, AFI_WR_SCRATCH_0);
- udelay(10);
- afi_writel(AFI_WR_SCRATCH_0_RESET_VAL, AFI_WR_SCRATCH_0);
-
- /* required for gen2 speed support on FPGA */
- rp_writel(FPGA_GEN2_SPEED_SUPPORT, RP_VEND_XP_BIST, 0);
-
- return 0;
-}
-#endif
-
static int tegra_pcie_change_link_speed(struct pci_dev *pdev, bool isGen2)
{
u16 val, link_up_spd, link_dn_spd;
@@ -1588,11 +1659,6 @@ static int __init tegra_pcie_init(void)
if (err)
return err;
-#ifdef CONFIG_TEGRA_FPGA_PLATFORM
- err = tegra_pcie_fpga_phy_init();
- if (err)
- return err;
-#endif
err = tegra_pcie_enable_controller();
if (err)
return err;
@@ -1722,6 +1788,7 @@ static int tegra_pcie_resume(struct device *dev)
tegra_pcie_enable_controller();
tegra_pcie_setup_translations();
+ is_resume_path = true;
for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
ctrl_offset += (port * 8);
rp_offset = (rp_offset + 0x1000) * port;