[PATCH V3 4/5] powerpc/fsl-pci: Add pci inbound/outbound PM support
Jia Hongtao
B38951 at freescale.com
Thu Jul 26 22:30:26 EST 2012
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 | 2 +-
arch/powerpc/sysdev/fsl_pci.c | 121 +++++++++++++++++++++++++++++++++
2 files changed, 122 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index b48fa7f..f0f00a7 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -90,9 +90,9 @@ struct pci_controller {
#ifdef CONFIG_PPC64
unsigned long buid;
+#endif /* CONFIG_PPC64 */
void *private_data;
-#endif /* CONFIG_PPC64 */
};
/* 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 97557c5..90e7ab9 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -966,12 +966,133 @@ static int __devinit fsl_pci_probe(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_SUSPEND
+
+#define PCI_POW_PIW_OFFSET 0xc00
+#define PCI_POW_PIW_SIZE 0x200
+#define PCI_POW_NUMBER 5
+
+static int fsl_pci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct pci_controller *hose;
+ struct pci_outbound_window_regs *pci_saved_pow;
+ struct pci_inbound_window_regs *pci_saved_piw, *temp_piw;
+ struct resource pci_rsrc;
+ unsigned int i;
+ struct fsl_pci_private_data *sus_info;
+
+ hose = pci_find_hose_for_OF_device(pdev->dev.of_node);
+ of_address_to_resource(pdev->dev.of_node, 0, &pci_rsrc);
+
+ sus_info = kmalloc(
+ sizeof(struct fsl_pci_private_data), GFP_KERNEL);
+ if (!sus_info)
+ return -ENOMEM;
+
+ hose->private_data = sus_info;
+
+ sus_info->pci_pow = ioremap(pci_rsrc.start + PCI_POW_PIW_OFFSET,
+ PCI_POW_PIW_SIZE);
+ if (!sus_info->pci_pow) {
+ dev_err(&pdev->dev, "pci outbound/inbound windows ioremap error!\n");
+ goto err1;
+ }
+
+ sus_info->pci_piw = (struct pci_inbound_window_regs *)
+ ((void *)sus_info->pci_pow + PCI_POW_PIW_SIZE) - 1;
+
+ if (of_device_is_compatible(pdev->dev.of_node, "fsl,qoriq-pcie-v2.2"))
+ sus_info->inbound_num = 4;
+ else
+ sus_info->inbound_num = 3;
+
+ sus_info->saved_regs = kmalloc(
+ sizeof(struct pci_outbound_window_regs) * PCI_POW_NUMBER +
+ sizeof(struct pci_inbound_window_regs) * sus_info->inbound_num,
+ GFP_KERNEL);
+ if (!sus_info->saved_regs)
+ goto err2;
+
+ pci_saved_pow = sus_info->saved_regs;
+ for (i = 0; i < PCI_POW_NUMBER; i++) {
+ pci_saved_pow[i].potar = in_be32(&sus_info->pci_pow[i].potar);
+ pci_saved_pow[i].potear = in_be32(&sus_info->pci_pow[i].potear);
+ pci_saved_pow[i].powbar = in_be32(&sus_info->pci_pow[i].powbar);
+ pci_saved_pow[i].powar = in_be32(&sus_info->pci_pow[i].powar);
+ }
+
+ pci_saved_piw = (struct pci_inbound_window_regs *)
+ (pci_saved_pow + PCI_POW_NUMBER);
+ temp_piw = sus_info->pci_piw;
+ for (i = 0; i < sus_info->inbound_num; i++, temp_piw--) {
+ pci_saved_piw[i].pitar = in_be32(&temp_piw->pitar);
+ pci_saved_piw[i].piwbar = in_be32(&temp_piw->piwbar);
+ pci_saved_piw[i].piwbear = in_be32(&temp_piw->piwbear);
+ pci_saved_piw[i].piwar = in_be32(&temp_piw->piwar);
+ }
+
+ return 0;
+
+err2:
+ iounmap(sus_info->pci_pow);
+
+err1:
+ kfree(sus_info);
+ return -ENOMEM;
+}
+
+static int fsl_pci_resume(struct platform_device *pdev)
+{
+ struct pci_controller *hose;
+ struct pci_outbound_window_regs *pci_saved_pow;
+ struct pci_inbound_window_regs *pci_saved_piw, *temp_piw;
+ unsigned int i;
+ struct fsl_pci_private_data *sus_info;
+
+ hose = pci_find_hose_for_OF_device(pdev->dev.of_node);
+ sus_info = (struct fsl_pci_private_data *)hose->private_data;
+
+ if (!sus_info->pci_pow || !sus_info->pci_piw || !sus_info->saved_regs)
+ return 0;
+
+ pci_saved_pow = sus_info->saved_regs;
+ for (i = 0; i < PCI_POW_NUMBER; i++) {
+ out_be32(&sus_info->pci_pow[i].potar, pci_saved_pow[i].potar);
+ out_be32(&sus_info->pci_pow[i].potear, pci_saved_pow[i].potear);
+ out_be32(&sus_info->pci_pow[i].powbar, pci_saved_pow[i].powbar);
+ out_be32(&sus_info->pci_pow[i].powar, pci_saved_pow[i].powar);
+ }
+
+ pci_saved_piw = (struct pci_inbound_window_regs *)
+ (pci_saved_pow + PCI_POW_NUMBER);
+ temp_piw = sus_info->pci_piw;
+ for (i = 0; i < sus_info->inbound_num; i++, temp_piw--) {
+ out_be32(&temp_piw->pitar, pci_saved_piw[i].pitar);
+ out_be32(&temp_piw->piwbar, pci_saved_piw[i].piwbar);
+ out_be32(&temp_piw->piwbear, pci_saved_piw[i].piwbear);
+ out_be32(&temp_piw->piwar, pci_saved_piw[i].piwar);
+ }
+ iounmap(sus_info->pci_pow);
+ kfree(sus_info->saved_regs);
+ sus_info->saved_regs = NULL;
+ kfree(sus_info);
+ sus_info = NULL;
+ hose->private_data = 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