summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <Richard.Zhu@freescale.com>2014-12-18 14:02:37 +0800
committerRichard Zhu <Richard.Zhu@freescale.com>2014-12-22 08:58:22 +0800
commitc0d12ce9fd7dbec07ec5f26f2ef830b9c385356f (patch)
tree5650692bd4fd32b362de0b8a61b675e97b0f52a7
parent6adee22e7fbcad3ea39cf12b2bc3a534ff2f28f6 (diff)
MLK-10017 PCI: save power when pcie is not used
In order to save power consumption, do the following actions when pcie is not used. - turn off clocks on imx6q/dl. - turn off clocks and power on imx6sx Signed-off-by: Richard Zhu <Richard.Zhu@freescale.com> (cherry picked from commit e9796dfbae2a8b732022a6c96b3d7803099a70b5)
-rw-r--r--drivers/pci/host/pci-imx6.c29
-rw-r--r--drivers/pci/host/pcie-designware.c9
-rw-r--r--drivers/pci/host/pcie-designware.h2
3 files changed, 33 insertions, 7 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index 1d0c96120e9a..1d88f4201bef 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -422,7 +422,7 @@ static irqreturn_t imx_pcie_msi_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static void imx6_pcie_host_init(struct pcie_port *pp)
+static int imx6_pcie_host_init(struct pcie_port *pp)
{
int count = 0;
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
@@ -459,14 +459,37 @@ static void imx6_pcie_host_init(struct pcie_port *pp)
"DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
- return;
+ clk_disable_unprepare(imx6_pcie->pcie_axi);
+ if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+ && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
+ clk_disable_unprepare(imx6_pcie->lvds_gate);
+ clk_disable_unprepare(imx6_pcie->pcie_ref_125m);
+ if (is_imx6sx_pcie(imx6_pcie)) {
+ /* Disable clks and power down PCIe PHY */
+ clk_disable_unprepare(imx6_pcie->dis_axi);
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ /* Put PCIe PHY to be isolation */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ IOMUXC_GPR0, BIT(6), 1 << 6);
+
+ /*
+ * Power down PCIe PHY.
+ */
+ regulator_disable(imx6_pcie->pcie_phy_reg);
+ regulator_disable(imx6_pcie->pcie_reg);
+ } else {
+ clk_disable_unprepare(imx6_pcie->sata_ref_100m);
+ release_bus_freq(BUS_FREQ_HIGH);
+ }
+ return -ENODEV;
}
}
if (IS_ENABLED(CONFIG_PCI_MSI))
dw_pcie_msi_init(pp);
- return;
+ return 0;
}
static int imx6_pcie_link_up(struct pcie_port *pp)
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 882c713145bb..a320e5a3d4f5 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -408,7 +408,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
struct of_pci_range range;
struct of_pci_range_parser parser;
u32 val;
- int i;
+ int i, ret = 0;
if (of_pci_range_parser_init(&parser, np)) {
dev_err(pp->dev, "missing ranges property\n");
@@ -489,8 +489,11 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
irq_create_mapping(pp->irq_domain, i);
}
- if (pp->ops->host_init)
- pp->ops->host_init(pp);
+ if (pp->ops->host_init) {
+ ret = pp->ops->host_init(pp);
+ if (ret < 0)
+ return -ENODEV;
+ }
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index c3caa81ad85f..6396ecdb198f 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -107,7 +107,7 @@ struct pcie_host_ops {
int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
int (*link_up)(struct pcie_port *pp);
- void (*host_init)(struct pcie_port *pp);
+ int (*host_init)(struct pcie_port *pp);
void (*msi_set_irq)(struct pcie_port *pp, int irq);
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
u32 (*get_msi_data)(struct pcie_port *pp);