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 <b14...@freescale.com> Signed-off-by: Jia Hongtao <b38...@freescale.com> Signed-off-by: Li Yang <le...@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 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev