D3-cold state indicates removal of the clock and power. however auxiliary (AUX) Power may remain available even after the main power rails are powered down.
wakeup from D3-cold state requires full context restore. Other things are taken care in pci-driver except ATMUs. ATMU windows needs to be saved and restored during suspend and resume. Signed-off-by: Jiang Yutang <b14...@freescale.com> Signed-off-by: Prabhakar Kushwaha <prabha...@freescale.com> --- Based upon git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git(branch master) arch/powerpc/sysdev/fsl_pci.c | 116 +++++++++++++++++++++++++++++++++++++++++ arch/powerpc/sysdev/fsl_pci.h | 7 ++- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index f8f7f28..809fbfe 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -35,6 +35,9 @@ #include <sysdev/fsl_pci.h> static int fsl_pcie_bus_fixup, is_mpc83xx_pci; +static int pcie_saved_pow_piw; +struct pci_outbound_window_regs pcie_saved_pow[PCIE_POW_NUMBER]; +struct pci_inbound_window_regs pcie_saved_piw[PCIE_PIW_NUMBER]; static void __init quirk_fsl_pcie_header(struct pci_dev *dev) { @@ -746,3 +749,116 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose) return 0; } + + +static int fsl_pcie_save_pow_piw(struct device_node *np, + struct resource *rsrc) +{ + struct ccsr_pci __iomem *pci; + int start_idx = 1, end_idx = 4; + unsigned int i; + + pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); + + if (!pci) { + printk(KERN_WARNING"pcie_pow ioremap error!\n"); + return -1; + } + + if (of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2")) { + start_idx = 0; + end_idx = 3; + } + + for (i = 0; i < PCIE_POW_NUMBER; i++) { + pcie_saved_pow[i].potar = in_be32(&pci->pow[i].potar); + pcie_saved_pow[i].potear = in_be32(&pci->pow[i].potear); + pcie_saved_pow[i].powbar = in_be32(&pci->pow[i].powbar); + pcie_saved_pow[i].powar = in_be32(&pci->pow[i].powar); + } + + for (i = start_idx; i < end_idx; i++) { + pcie_saved_piw[i].pitar = in_be32(&pci->piw[i].pitar); + pcie_saved_piw[i].piwbar = in_be32(&pci->piw[i].piwbar); + pcie_saved_piw[i].piwbear = in_be32(&pci->piw[i].piwbear); + pcie_saved_piw[i].piwar = in_be32(&pci->piw[i].piwar); + } + + iounmap(pci); + return 0; +} + +static int fsl_pcie_restore_pow_piw(struct device_node *np, + struct resource *rsrc) +{ + struct ccsr_pci __iomem *pci; + int start_idx = 1, end_idx = 4; + unsigned int i; + + pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); + + if (of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2")) { + start_idx = 0; + end_idx = 3; + } + if (!pci) { + printk(KERN_WARNING"pcie_pow ioremap error!\n"); + return -1; + } + + for (i = 0; i < PCIE_POW_NUMBER; i++) { + out_be32(&pci->pow[i].potar, pcie_saved_pow[i].potar); + out_be32(&pci->pow[i].potear, pcie_saved_pow[i].potear); + out_be32(&pci->pow[i].powbar, pcie_saved_pow[i].powbar); + out_be32(&pci->pow[i].powar, pcie_saved_pow[i].powar); + } + + for (i = 0; i < PCIE_PIW_NUMBER; i++) { + out_be32(&pci->piw[i].pitar, pcie_saved_piw[i].pitar); + out_be32(&pci->piw[i].piwbar, pcie_saved_piw[i].piwbar); + out_be32(&pci->piw[i].piwbear, pcie_saved_piw[i].piwbear); + out_be32(&pci->piw[i].piwar, pcie_saved_piw[i].piwar); + } + + iounmap(pci); + return 0; +} + +static void fsl_pcie_suspend_save(struct pci_dev *dev) +{ + struct device_node *np; + struct resource rsrc; + + if (pcie_saved_pow_piw == 1) + return; + + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,p1022-pcie")) { + of_address_to_resource(np, 0, &rsrc); + fsl_pcie_save_pow_piw(np, &rsrc); + } + } + pcie_saved_pow_piw = 1; +} +DECLARE_PCI_FIXUP_SUSPEND(0x1957, PCI_DEVICE_ID_P1022E, fsl_pcie_suspend_save); +DECLARE_PCI_FIXUP_SUSPEND(0x1957, PCI_DEVICE_ID_P1022, fsl_pcie_suspend_save); + +static void fsl_pcie_resume_restore(struct pci_dev *dev) +{ + struct device_node *np; + struct resource rsrc; + + if (pcie_saved_pow_piw == 0) + return; + + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,p1022-pcie")) { + of_address_to_resource(np, 0, &rsrc); + fsl_pcie_restore_pow_piw(np, &rsrc); + } + } + pcie_saved_pow_piw = 0; +} +DECLARE_PCI_FIXUP_RESUME(0x1957, PCI_DEVICE_ID_P1022E, fsl_pcie_resume_restore); +DECLARE_PCI_FIXUP_RESUME(0x1957, PCI_DEVICE_ID_P1022, fsl_pcie_resume_restore); + diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index a39ed5c..853672f 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h @@ -14,6 +14,9 @@ #ifndef __POWERPC_FSL_PCI_H #define __POWERPC_FSL_PCI_H +#define PCIE_POW_NUMBER 5 +#define PCIE_PIW_NUMBER 4 + #define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */ #define PCIE_LTSSM_L0 0x16 /* L0 state */ #define PIWAR_EN 0x80000000 /* Enable */ @@ -64,7 +67,7 @@ struct ccsr_pci { * The default outbound register set is used when a transaction misses * in all of the other outbound windows. */ - struct pci_outbound_window_regs pow[5]; + struct pci_outbound_window_regs pow[PCIE_POW_NUMBER]; u8 res14[96]; struct pci_inbound_window_regs pmit; /* 0xd00 - 0xd9c Inbound MSI */ u8 res6[96]; @@ -72,7 +75,7 @@ struct ccsr_pci { * inbound window 1 supports only a 32-bit base address and does not * define an inbound window base extended address register. */ - struct pci_inbound_window_regs piw[4]; + struct pci_inbound_window_regs piw[PCIE_PIW_NUMBER]; __be32 pex_err_dr; /* 0x.e00 - PCI/PCIE error detect register */ u8 res21[4]; -- 1.7.3 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev