[PATCH SDK1.2 3/3] powerpc/fsl-pci: Add pci inbound/outbound PM support
Jia Hongtao
B38951 at freescale.com
Wed Dec 21 18:10:58 EST 2011
Power supply for PCI inbound/outbound window registers is off when system
go to deep-sleep state. We save the values of registers before suspend
and restore to registers after resume.
Signed-off-by: Jiang Yutang <b14898 at freescale.com>
Signed-off-by: Jia Hongtao <B38951 at freescale.com>
Signed-off-by: Li Yang <leoli at freescale.com>
---
arch/powerpc/include/asm/pci-bridge.h | 6 ++
arch/powerpc/sysdev/fsl_pci.c | 108 +++++++++++++++++++++++++++++++++
2 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 882b6aa..c99b40e 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -92,6 +92,12 @@ struct pci_controller {
void *private_data;
#endif /* CONFIG_PPC64 */
+
+#ifdef CONFIG_SUSPEND
+ struct pci_outbound_window_regs __iomem *pci_pow;
+ struct pci_inbound_window_regs __iomem *pci_piw;
+ void *saved_regs;
+#endif
};
/* These are used for config access before all the PCI probing
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index e318e9d..046866f 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -756,12 +756,120 @@ static int __devinit fsl_pci_probe(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_SUSPEND
+
+#define PCI_POW_NUMBER 5
+#define PCI_POW_BIAS 0xc00
+#define PCI_PIW_NUMBER 3
+#define PCI_PIW_BIAS 0xda0
+
+static int fsl_pci_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct pci_controller *hose;
+ struct pci_outbound_window_regs *pci_saved_pow;
+ struct pci_inbound_window_regs *pci_saved_piw;
+ struct resource pci_rsrc;
+ unsigned int i;
+
+ hose = pci_find_hose_for_OF_device(dev->dev.of_node);
+ of_address_to_resource(dev->dev.of_node, 0, &pci_rsrc);
+
+ hose->pci_pow = ioremap(pci_rsrc.start + PCI_POW_BIAS,
+ sizeof(struct pci_outbound_window_regs)
+ * PCI_POW_NUMBER);
+ if (!hose->pci_pow) {
+ pr_err("pci_pow ioremap error!\n");
+ return -ENOMEM;
+ }
+
+ hose->pci_piw = ioremap(pci_rsrc.start + PCI_PIW_BIAS,
+ sizeof(struct pci_inbound_window_regs)
+ * PCI_PIW_NUMBER);
+ if (!hose->pci_piw) {
+ pr_err("pci_piw ioremap error!\n");
+ goto err1;
+ }
+
+ hose->saved_regs = kmalloc(
+ sizeof(struct pci_outbound_window_regs) * PCI_POW_NUMBER +
+ sizeof(struct pci_inbound_window_regs) * PCI_PIW_NUMBER,
+ GFP_KERNEL);
+ if (!hose->saved_regs)
+ goto err2;
+
+ pci_saved_pow = hose->saved_regs;
+ for (i = 0; i < PCI_POW_NUMBER; i++) {
+ pci_saved_pow[i].potar = in_be32(&hose->pci_pow[i].potar);
+ pci_saved_pow[i].potear = in_be32(&hose->pci_pow[i].potear);
+ pci_saved_pow[i].powbar = in_be32(&hose->pci_pow[i].powbar);
+ pci_saved_pow[i].powar = in_be32(&hose->pci_pow[i].powar);
+ }
+
+ pci_saved_piw = (struct pci_inbound_window_regs *)
+ (pci_saved_pow + PCI_POW_NUMBER);
+ for (i = 0; i < PCI_PIW_NUMBER; i++) {
+ pci_saved_piw[i].pitar = in_be32(&hose->pci_piw[i].pitar);
+ pci_saved_piw[i].piwbar = in_be32(&hose->pci_piw[i].piwbar);
+ pci_saved_piw[i].piwbear = in_be32(&hose->pci_piw[i].piwbear);
+ pci_saved_piw[i].piwar = in_be32(&hose->pci_piw[i].piwar);
+ }
+
+ return 0;
+
+err2:
+ iounmap(hose->pci_piw);
+
+err1:
+ iounmap(hose->pci_pow);
+ return -ENOMEM;
+}
+
+static int fsl_pci_resume(struct platform_device *dev)
+{
+ struct pci_controller *hose;
+ struct pci_outbound_window_regs *pci_saved_pow;
+ struct pci_inbound_window_regs *pci_saved_piw;
+ unsigned int i;
+
+ hose = pci_find_hose_for_OF_device(dev->dev.of_node);
+ if (!hose->pci_pow || !hose->pci_piw || !hose->saved_regs)
+ return 0;
+
+ pci_saved_pow = hose->saved_regs;
+ for (i = 0; i < PCI_POW_NUMBER; i++) {
+ out_be32(&hose->pci_pow[i].potar, pci_saved_pow[i].potar);
+ out_be32(&hose->pci_pow[i].potear, pci_saved_pow[i].potear);
+ out_be32(&hose->pci_pow[i].powbar, pci_saved_pow[i].powbar);
+ out_be32(&hose->pci_pow[i].powar, pci_saved_pow[i].powar);
+ }
+ iounmap(hose->pci_pow);
+
+ pci_saved_piw = (struct pci_inbound_window_regs *)
+ (pci_saved_pow + PCI_POW_NUMBER);
+ for (i = 0; i < PCI_PIW_NUMBER; i++) {
+ out_be32(&hose->pci_piw[i].pitar, pci_saved_piw[i].pitar);
+ out_be32(&hose->pci_piw[i].piwbar, pci_saved_piw[i].piwbar);
+ out_be32(&hose->pci_piw[i].piwbear, pci_saved_piw[i].piwbear);
+ out_be32(&hose->pci_piw[i].piwar, pci_saved_piw[i].piwar);
+ }
+ iounmap(hose->pci_piw);
+ kfree(hose->saved_regs);
+ hose->saved_regs = NULL;
+
+ return 0;
+}
+#endif
+
static struct platform_driver fsl_pci_driver = {
.driver = {
.name = "fsl-pci",
.of_match_table = pci_ids,
},
.probe = fsl_pci_probe,
+#ifdef CONFIG_SUSPEND
+ .suspend = fsl_pci_suspend,
+ .resume = fsl_pci_resume,
+#endif
};
static int __init fsl_pci_init(void)
--
1.7.5.1
More information about the Linuxppc-dev
mailing list