summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/pcie.c
diff options
context:
space:
mode:
authorJay Agarwal <jagarwal@nvidia.com>2012-03-03 00:08:07 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-03-30 08:02:11 -0700
commitacc671b9cc8f6c945ab0e98c1b5fa4987e1253b7 (patch)
treef4440dabc9cf47fddbee812350df1f2b4e2f3c54 /arch/arm/mach-tegra/pcie.c
parent78ee8259728a92f807910ac04dc98fe1ad6683f2 (diff)
ARM:tegra:pcie: fix pcie power management
1. disable pci devices asynchronous suspend/resume. 2. correct resume function of tegra pcie driver. 3. enable clock clamping 4. require noirq suspend/resume calls to be commented Bug 790141 Bug 947673 Change-Id: I49ebba43f296c3c38bc960d7db5fe847232e29a8 Signed-off-by: Jay Agarwal <jagarwal@nvidia.com> Reviewed-on: http://git-master/r/87316 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Tested-by: Penny Chiu <pchiu@nvidia.com> Reviewed-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-by: Krishna Thota <kthota@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/pcie.c')
-rw-r--r--arch/arm/mach-tegra/pcie.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index ca914a2b257c..b7d7eefe2661 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -95,9 +95,7 @@
/* register definitions */
#define AFI_OFFSET 0x3800
#define PADS_OFFSET 0x3000
-#define RP0_OFFSET 0x0000
-#define RP1_OFFSET 0x1000
-#define RP2_OFFSET 0x4000
+#define RP_OFFSET 0x1000
#define AFI_AXI_BAR0_SZ 0x00
#define AFI_AXI_BAR1_SZ 0x04
@@ -206,7 +204,11 @@
/* PMC access is required for PCIE xclk (un)clamping */
#define PMC_SCRATCH42 0x144
-#define PMC_SCRATCH42_PCX_CLAMP (1 << 0)
+#define PMC_SCRATCH42_PCX_CLAMP (1 << 0)
+
+#define NV_PCIE2_RP_PRIV_MISC 0x00000FE0
+#define PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE 1 << 23
+#define PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE 1 << 31
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
/*
@@ -365,6 +367,20 @@ static inline u32 pads_readl(unsigned long offset)
return readl(offset + PADS_OFFSET + tegra_pcie.regs);
}
+static inline void rp_writel(u32 value, unsigned long offset, int rp)
+{
+ BUG_ON(rp != 0 && rp != 1 && rp != 2);
+ offset += rp * (0x1UL << (rp - 1)) * RP_OFFSET;
+ writel(value, offset + tegra_pcie.regs);
+}
+
+static inline unsigned int rp_readl(unsigned long offset, int rp)
+{
+ BUG_ON(rp != 0 && rp != 1 && rp != 2);
+ offset += rp * (0x1UL << (rp - 1)) * RP_OFFSET;
+ return readl(offset + tegra_pcie.regs);
+}
+
static struct tegra_pcie_port *bus_to_port(int bus)
{
int i;
@@ -591,6 +607,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
"Target abort",
"Master abort",
"Invalid write",
+ ""
"Response decoding error",
"AXI response decoding error",
"Transcation timeout",
@@ -1083,6 +1100,7 @@ retry:
static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
{
struct tegra_pcie_port *pp;
+ unsigned int data;
pp = tegra_pcie.port + tegra_pcie.num_ports;
@@ -1095,6 +1113,12 @@ static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
return;
}
+ /* Power mangagement settings */
+ /* Enable clock clamping by default */
+ data = rp_readl(NV_PCIE2_RP_PRIV_MISC, index);
+ data |= (PCIE2_RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE) |
+ (PCIE2_RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE);
+ rp_writel(data, NV_PCIE2_RP_PRIV_MISC, index);
tegra_pcie.num_ports++;
pp->index = index;
@@ -1141,6 +1165,9 @@ static int tegra_pcie_init(void)
static int tegra_pci_probe(struct platform_device *pdev)
{
+ int ret;
+ struct pci_dev *dev = NULL;
+
tegra_pcie.plat_data = pdev->dev.platform_data;
dev_dbg(&pdev->dev, "PCIE.C: %s : _port_status[0] %d\n",
__func__, tegra_pcie.plat_data->port_status[0]);
@@ -1148,8 +1175,14 @@ static int tegra_pci_probe(struct platform_device *pdev)
__func__, tegra_pcie.plat_data->port_status[1]);
dev_dbg(&pdev->dev, "PCIE.C: %s : _port_status[2] %d\n",
__func__, tegra_pcie.plat_data->port_status[2]);
+ ret = tegra_pcie_init();
+
+ /* disable async PM of pci devices to ensure right order */
+ /* suspend/resume calls of tegra and bus driver */
+ for_each_pci_dev(dev)
+ device_disable_async_suspend(&dev->dev);
- return tegra_pcie_init();
+ return ret;
}
static int tegra_pci_suspend(struct platform_device *pdev, pm_message_t state)
@@ -1159,7 +1192,13 @@ static int tegra_pci_suspend(struct platform_device *pdev, pm_message_t state)
static int tegra_pci_resume(struct platform_device *pdev)
{
- return tegra_pcie_power_on();
+ int ret;
+
+ ret = tegra_pcie_power_on();
+ tegra_pcie_enable_controller();
+ tegra_pcie_setup_translations();
+
+ return ret;
}
static int tegra_pci_remove(struct platform_device *pdev)