summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Agarwal <jagarwal@nvidia.com>2012-07-21 23:47:33 +0530
committerLokesh Pathak <lpathak@nvidia.com>2012-07-26 04:46:15 -0700
commit971106a7f14552ff7785eedcd97301b75a586474 (patch)
tree05311d757c7849cc93f982f2d435951347e85905
parent9b30c9e8b7c3ec08f56a610644491125690e9ef2 (diff)
arm: tegra: pci: Organize pcie initialization code
1. Initialize PCIe on every resume whether device is dock/undocked. 2. Poweroff PCIe if Poweron failed at any stage. 3. Make PCIe initialization robust so that it is successful anytime dock is connected i.e while in LP0 or after it's exit or else. Bug 1020949 Change-Id: I79cd75f2bf7164a9b5c8906a370364dba5183ac8 Signed-off-by: Jay Agarwal <jagarwal@nvidia.com> Reviewed-on: http://git-master/r/117532 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/pcie.c109
1 files changed, 44 insertions, 65 deletions
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 24ca4900daa5..c6f0e4bf2bb8 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -313,11 +313,6 @@ struct tegra_pcie_info {
struct tegra_pci_platform_data *plat_data;
}tegra_pcie;
-#define pmc_writel(value, reg) \
- __raw_writel(value, (u32)reg_pmc_base + (reg))
-#define pmc_readl(reg) \
- __raw_readl((u32)reg_pmc_base + (reg))
-
struct resource tegra_pcie_res_mmio = {
.name = "PCI IO",
.start = MMIO_BASE,
@@ -637,9 +632,6 @@ static void tegra_pcie_hotplug_init(void)
static void tegra_pcie_attach(void)
{
- /* this hardcode is just to bypass the check in resume */
- if (!is_dock_conn_at_boot)
- tegra_pcie.num_ports = 1;
#ifdef CONFIG_PM
tegra_pcie_resume(NULL);
#endif
@@ -904,6 +896,8 @@ static int tegra_pcie_enable_regulators(void)
pr_debug("PCIE: Already power rails enabled");
return 0;
}
+ tegra_pcie.power_rails_enabled = 1;
+
if (tegra_pcie.regulator_hvdd == NULL) {
printk(KERN_INFO "PCIE.C: %s : regulator hvdd_pex\n",
__func__);
@@ -948,8 +942,6 @@ static int tegra_pcie_enable_regulators(void)
if (tegra_pcie.regulator_avdd_plle)
regulator_enable(tegra_pcie.regulator_avdd_plle);
- tegra_pcie.power_rails_enabled = 1;
-
return 0;
}
@@ -988,8 +980,6 @@ static int tegra_pcie_power_regate(void)
return clk_enable(tegra_pcie.pll_e);
}
-static int tegra_pcie_power_off(void);
-
static int tegra_pcie_map_resources(void)
{
int err;
@@ -998,14 +988,13 @@ static int tegra_pcie_map_resources(void)
tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
if (tegra_pcie.regs == NULL) {
pr_err("PCIE: Failed to map PCI/AFI registers\n");
- err = -ENOMEM;
- goto err_exit;
+ return -ENOMEM;
}
err = request_resource(&iomem_resource, &tegra_pcie_res_mmio);
if (err) {
pr_err("PCIE: Failed to request resources: %d\n", err);
- goto err_exit;
+ return err;
}
tegra_pcie.res_mmio = &tegra_pcie_res_mmio;
@@ -1014,13 +1003,8 @@ static int tegra_pcie_map_resources(void)
resource_size(&tegra_pcie_res_mmio));
if (tegra_pcie_io_base == NULL) {
pr_err("PCIE: Failed to map IO\n");
- err = -ENOMEM;
- goto err_exit;
+ return -ENOMEM;
}
- return 0;
-
-err_exit:
- tegra_pcie_power_off();
return err;
}
@@ -1039,8 +1023,8 @@ void tegra_pcie_unmap_resources(void)
tegra_pcie.regs = 0;
}
}
+static int tegra_pcie_power_off(void);
-#ifdef CONFIG_PM
static int tegra_pcie_power_on(void)
{
int err = 0;
@@ -1049,21 +1033,29 @@ static int tegra_pcie_power_on(void)
pr_debug("PCIE: Already powered on");
goto err_exit;
}
+ tegra_pcie.pcie_power_enabled = 1;
+
err = tegra_pcie_enable_regulators();
- if (err)
+ if (err) {
+ pr_err("PCIE: Failed to enable regulators\n");
goto err_exit;
+ }
err = tegra_pcie_power_regate();
- if (err)
+ if (err) {
+ pr_err("PCIE: Failed to power regate\n");
goto err_exit;
+ }
err = tegra_pcie_map_resources();
- if (err)
+ if (err) {
+ pr_err("PCIE: Failed to map resources\n");
goto err_exit;
+ }
- tegra_pcie.pcie_power_enabled = 1;
err_exit:
+ if (err)
+ tegra_pcie_power_off();
return err;
}
-#endif
static int tegra_pcie_power_off(void)
{
@@ -1112,8 +1104,10 @@ error_exit:
static void tegra_pcie_clocks_put(void)
{
- clk_put(tegra_pcie.pll_e);
- clk_put(tegra_pcie.pcie_xclk);
+ if (tegra_pcie.pll_e)
+ clk_put(tegra_pcie.pll_e);
+ if (tegra_pcie.pcie_xclk)
+ clk_put(tegra_pcie.pcie_xclk);
}
static int tegra_pcie_get_resources(void)
@@ -1121,31 +1115,18 @@ static int tegra_pcie_get_resources(void)
int err;
tegra_pcie.power_rails_enabled = 0;
- err = tegra_pcie_enable_regulators();
- if (err) {
- pr_err("PCIE: failed to enable power rails %d\n", err);
- goto err_pwr_on_rail;
- }
- tegra_unpowergate_partition(TEGRA_POWERGATE_PCIE);
+ tegra_pcie.pcie_power_enabled = 0;
err = tegra_pcie_clocks_get();
if (err) {
pr_err("PCIE: failed to get clocks: %d\n", err);
- return err;
+ goto err_clk_get;
}
-
- err = tegra_pcie_power_regate();
+ err = tegra_pcie_power_on();
if (err) {
- pr_err("PCIE: failed to power up: %d\n", err);
+ pr_err("PCIE: Failed to power on: %d\n", err);
goto err_pwr_on;
}
-
- err = tegra_pcie_map_resources();
- if (err) {
- pr_err("PCIE: failed to map resources: %d\n", err);
- goto err_pwr_on;
- }
-
err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
IRQF_SHARED, "PCIE", &tegra_pcie);
if (err) {
@@ -1156,9 +1137,9 @@ static int tegra_pcie_get_resources(void)
return 0;
err_pwr_on:
+ tegra_pcie_power_off();
+err_clk_get:
tegra_pcie_clocks_put();
-err_pwr_on_rail:
- tegra_pcie_disable_regulators();
return err;
}
@@ -1291,7 +1272,6 @@ static int tegra_pcie_init(void)
tegra_pcie_add_port(port, rp_offset, ctrl_offset);
}
- tegra_pcie.pcie_power_enabled = 1;
if (tegra_pcie.plat_data->use_dock_detect) {
unsigned int irq;
@@ -1331,7 +1311,6 @@ err_irq:
static int tegra_pcie_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",
@@ -1342,23 +1321,14 @@ static int tegra_pcie_probe(struct platform_device *pdev)
__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 ret;
}
#ifdef CONFIG_PM
static int tegra_pcie_suspend(struct device *dev)
{
- int ret = 0;
struct pci_dev *pdev = NULL;
- if (!tegra_pcie.num_ports)
- return ret;
-
for_each_pci_dev(pdev) {
pci_remove_bus_device(pdev);
break;
@@ -1366,6 +1336,8 @@ static int tegra_pcie_suspend(struct device *dev)
/* disable read/write registers before powering off */
is_pcie_noirq_op = true;
+ /* reset number of ports since fresh initialization occurs in resume */
+ tegra_pcie.num_ports = 0;
return tegra_pcie_power_off();
}
@@ -1395,24 +1367,31 @@ static int tegra_pcie_resume(struct device *dev)
int port, rp_offset = 0;
int ctrl_offset = AFI_PEX0_CTRL;
- if (!tegra_pcie.num_ports)
- return ret;
+ /* return w/o resume if cardhu dock is not connected */
+ if (gpio_get_value(tegra_pcie.plat_data->gpio))
+ goto exit;
ret = tegra_pcie_power_on();
+ if (ret) {
+ pr_err("PCIE: Failed to power on: %d\n", ret);
+ return ret;
+ }
/* enable read/write registers after powering on */
is_pcie_noirq_op = false;
tegra_pcie_enable_controller();
tegra_pcie_setup_translations();
msi_enable = false;
- /* reset number of ports before adding port */
- tegra_pcie.num_ports = 0;
for (port = 0; port < MAX_PCIE_SUPPORTED_PORTS; port++) {
ctrl_offset += (port * 8);
rp_offset = (rp_offset + 0x1000) * port;
if (tegra_pcie.plat_data->port_status[port])
tegra_pcie_add_port(port, rp_offset, ctrl_offset);
}
+ if (!tegra_pcie.num_ports) {
+ tegra_pcie_power_off();
+ goto exit;
+ }
tegra_pcie_hotplug_init();
while ((bus = pci_find_next_bus(bus)) != NULL) {
@@ -1432,8 +1411,8 @@ static int tegra_pcie_resume(struct device *dev)
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
}
-
- return ret;
+exit:
+ return 0;
}
#endif