[PATCH] powerpc/85xx: Save and restore pcie ATMU windows for PM
Prabhakar Kushwaha
prabhakar at freescale.com
Thu Apr 28 16:38:49 EST 2011
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 <b14898 at freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar at 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
More information about the Linuxppc-dev
mailing list