diff options
author | Wang Dongsheng <dongsheng.wang@freescale.com> | 2014-04-25 07:59:49 (GMT) |
---|---|---|
committer | Jose Rivera <German.Rivera@freescale.com> | 2014-04-29 16:16:59 (GMT) |
commit | 9659e78cb8f5f086f661cd0b7f6b32bce18bbc34 (patch) | |
tree | aa2d93f9b698239804ade8fd2ce257487f4c5ad1 /arch | |
parent | 4f7b508a0a88bf49cd4ac0747769a3dc966034ad (diff) | |
download | linux-fsl-qoriq-9659e78cb8f5f086f661cd0b7f6b32bce18bbc34.tar.xz |
fsl/pci: The new pci suspend/resume implementation
If we do nothing in suspend/resume, some platform PCIe ip-block
can't guarantee the link back to L0 state from sleep, then, when
we read the EP device will hang. Only we send pme turnoff message
in pci controller suspend, and send pme exit message in resume, the
link state will be normal.
When we send pme turnoff message in pci controller suspend, the
links will into l2/l3 ready, then, host cannot communicate with
ep device, but pci-driver will call back EP device to save them
state. So we need to change platform_driver->suspend/resume to
syscore->suspend/resume.
So the new suspend/resume implementation, send pme turnoff message
in suspend, and send pme exit message in resume. And add a PME handler,
to response PME & message interrupt.
Change platform_driver->suspend/resume to syscore->suspend/resume.
pci-driver will call back EP device, to save EP state in
pci_pm_suspend_noirq, so we need to keep the link, until
pci_pm_suspend_noirq finish.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Change-Id: Id82d2e92994e466de1b2a4eb9ecef73c112ec753
Reviewed-on: http://git.am.freescale.net:8181/11538
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Yang Li <LeoLi@freescale.com>
Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/85xx/c293pcie.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/corenet_generic.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/ge_imp3a.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/mpc8536_ds.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/mpc85xx_cds.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/mpc85xx_ds.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/mpc85xx_mds.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/mpc85xx_rdb.c | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/p1010rdb.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/p1022_ds.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/p1022_rdk.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/p1023_rds.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/qemu_e500.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/sbc8548.c | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 245 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.h | 15 |
16 files changed, 264 insertions, 24 deletions
diff --git a/arch/powerpc/platforms/85xx/c293pcie.c b/arch/powerpc/platforms/85xx/c293pcie.c index 6208e49..7afaaff 100644 --- a/arch/powerpc/platforms/85xx/c293pcie.c +++ b/arch/powerpc/platforms/85xx/c293pcie.c @@ -67,6 +67,7 @@ define_machine(c293_pcie) { .init_IRQ = c293_pcie_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index 018ed5d..c086b0b 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -246,6 +246,7 @@ define_machine(corenet_generic) { .init_IRQ = corenet_gen_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_coreint_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c index e6285ae..0b3c041 100644 --- a/arch/powerpc/platforms/85xx/ge_imp3a.c +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -215,6 +215,7 @@ define_machine(ge_imp3a) { .show_cpuinfo = ge_imp3a_show_cpuinfo, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index 15ce4b5..5c88de0 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -76,6 +76,7 @@ define_machine(mpc8536_ds) { .init_IRQ = mpc8536_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 7a31a0e..633a514 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -385,6 +385,7 @@ define_machine(mpc85xx_cds) { #ifdef CONFIG_PCI .restart = mpc85xx_cds_restart, .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #else .restart = fsl_rstcr_restart, #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 9ebb91e..e5e4983 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -209,6 +209,7 @@ define_machine(mpc8544_ds) { .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -223,6 +224,7 @@ define_machine(mpc8572_ds) { .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -237,6 +239,7 @@ define_machine(p2020_ds) { .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 3c190b4..c111fba 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -392,6 +392,7 @@ define_machine(mpc8568_mds) { .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif }; @@ -413,6 +414,7 @@ define_machine(mpc8569_mds) { .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif }; @@ -435,6 +437,7 @@ define_machine(p1021_mds) { .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index 71149dc..2746b8b 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -273,6 +273,7 @@ define_machine(p2020_rdb) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -287,6 +288,7 @@ define_machine(p1020_rdb) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -301,6 +303,7 @@ define_machine(p1021_rdb_pc) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -315,6 +318,7 @@ define_machine(p2020_rdb_pc) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -329,6 +333,7 @@ define_machine(p1025_rdb) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -343,6 +348,7 @@ define_machine(p1020_mbg_pc) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -357,6 +363,7 @@ define_machine(p1020_utm_pc) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -371,6 +378,7 @@ define_machine(p1020_rdb_pc) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -385,6 +393,7 @@ define_machine(p1020_rdb_pd) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, @@ -399,6 +408,7 @@ define_machine(p1024_rdb) { .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index d6a3dd3..1a77ca7 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -78,6 +78,7 @@ define_machine(p1010_rdb) { .init_IRQ = p1010_rdb_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 3a68e4b..8a77b12 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -652,6 +652,7 @@ define_machine(p1022_ds) { .init_IRQ = p1022_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c index 8c92971..ba3cc2d 100644 --- a/arch/powerpc/platforms/85xx/p1022_rdk.c +++ b/arch/powerpc/platforms/85xx/p1022_rdk.c @@ -147,6 +147,7 @@ define_machine(p1022_rdk) { .init_IRQ = p1022_rdk_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index 47cd535..1c5ef8a 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c @@ -146,6 +146,7 @@ define_machine(p1023_rds) { .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .init_early = p1023_rds_init_early, }; @@ -162,5 +163,6 @@ define_machine(p1023_rdb) { .init_early = p1023_rds_init_early, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif }; diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c index 4677463..a299218 100644 --- a/arch/powerpc/platforms/85xx/qemu_e500.c +++ b/arch/powerpc/platforms/85xx/qemu_e500.c @@ -79,6 +79,7 @@ define_machine(qemu_e500) { .init_IRQ = qemu_e500_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_coreint_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index f621218..857c532 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -135,6 +135,7 @@ define_machine(sbc8548) { .restart = fsl_rstcr_restart, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index c89dbac..65be890 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -22,13 +22,17 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/bootmem.h> #include <linux/memblock.h> #include <linux/log2.h> #include <linux/slab.h> +#include <linux/suspend.h> +#include <linux/syscore_ops.h> #include <linux/uaccess.h> #include <asm/io.h> +#include <asm/fsl_pm.h> #include <asm/prom.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> @@ -1153,55 +1157,245 @@ void fsl_pci_assign_primary(void) } } -static int fsl_pci_probe(struct platform_device *pdev) +#ifdef CONFIG_PM_SLEEP +static irqreturn_t fsl_pci_pme_handle(int irq, void *dev_id) { - int ret; - struct device_node *node; + struct pci_controller *hose = dev_id; + struct ccsr_pci __iomem *pci = hose->private_data; + u32 dr; - node = pdev->dev.of_node; - ret = fsl_add_bridge(pdev, fsl_pci_primary == node); + dr = in_be32(&pci->pex_pme_mes_dr); + if (!dr) + return IRQ_NONE; - mpc85xx_pci_err_probe(pdev); + out_be32(&pci->pex_pme_mes_dr, dr); - return ret; + return IRQ_HANDLED; } -#ifdef CONFIG_PM -static int fsl_pci_resume(struct device *dev) +static int fsl_pci_pme_probe(struct pci_controller *hose) { - struct pci_controller *hose; - struct resource pci_rsrc; + struct ccsr_pci __iomem *pci; + struct pci_dev *dev; + int pme_irq; + int res; + u16 pms; + + /* Get hose's pci_dev */ + dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list); + + /* PME Disable */ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms); + pms &= ~PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms); + + pme_irq = irq_of_parse_and_map(hose->dn, 0); + if (!pme_irq) { + dev_err(&dev->dev, "Failed to map PME interrupt.\n"); + return -ENXIO; + } - hose = pci_find_hose_for_OF_device(dev->of_node); - if (!hose) + res = devm_request_irq(hose->parent, pme_irq, + fsl_pci_pme_handle, + IRQF_SHARED, + "[PCI] PME", hose); + if (res < 0) { + dev_err(&dev->dev, "PCI: Requiest irq %d failed\n", pme_irq); + irq_dispose_mapping(pme_irq); return -ENODEV; + } - if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) { - dev_err(dev, "Get pci register base failed."); - return -ENODEV; + pci = hose->private_data; + + /* Enable PTOD, ENL23D & EXL23D */ + clrbits32(&pci->pex_pme_mes_disr, + PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); + + out_be32(&pci->pex_pme_mes_ier, 0); + setbits32(&pci->pex_pme_mes_ier, + PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); + + /* PME Enable */ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms); + pms |= PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms); + + return 0; +} + +static int pcie_slot_flag; + +/* Workaround: p1022ds need reset slot when the system wakeup from deep sleep */ +static int reset_pcie_slot(void) +{ +#ifdef CONFIG_P1022_DS + p1022ds_reset_pcie_slot(); +#endif + return 0; +} + +static void send_pme_turnoff_message(struct pci_controller *hose) +{ + struct ccsr_pci __iomem *pci = hose->private_data; + u32 dr; + int i; + + /* Send PME_Turn_Off Message Request */ + setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR); + + /* Wait trun off done */ + /* RC will get this detect quickly */ + for (i = 0; i < 50; i++) { + dr = in_be32(&pci->pex_pme_mes_dr); + if (dr & ENL23_DETECT_BIT) { + out_be32(&pci->pex_pme_mes_dr, dr); + break; + } + + mdelay(1); } - setup_pci_atmu(hose); + /* + * "PCI Bus Power Management Interface Specification" define + * Minimum System Software Guaranteed Delays + * + * D0, D1 or D2 --> D3, need delay 10ms. + * But based on my test results, we need to delay 30ms when EP + * plug in p1022 slot2. And we need to delay 100ms when EP plug + * in p1022 slot1. So need to get maximum delay. + */ + mdelay(100); +} + +static void fsl_pci_syscore_do_suspend(struct pci_controller *hose) +{ + suspend_state_t pm_state; + pm_state = pm_suspend_state(); + + send_pme_turnoff_message(hose); + + if (pm_state == PM_SUSPEND_MEM) + pcie_slot_flag = 0; +} + +static int fsl_pci_syscore_suspend(void) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + fsl_pci_syscore_do_suspend(hose); return 0; } -static const struct dev_pm_ops pci_pm_ops = { - .resume = fsl_pci_resume, -}; +#define PCIE_RESET_SLOT_WAITTIME 100000 /* wait 100 ms */ +static void fsl_pci_syscore_do_resume(struct pci_controller *hose) +{ + struct ccsr_pci __iomem *pci = hose->private_data; + struct pci_dev *dev; + u32 svr = mfspr(SPRN_SVR); + u32 dr; + suspend_state_t pm_state; + int i; + u16 pms; -#define PCI_PM_OPS (&pci_pm_ops) + /* Send Exit L2 State Message */ + setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S); -#else + /* Wait exit done */ + /* RC will get this detect quickly */ + for (i = 0; i < 50; i++) { + dr = in_be32(&pci->pex_pme_mes_dr); + if (dr & EXL23_DETECT_BIT) { + out_be32(&pci->pex_pme_mes_dr, dr); + break; + } + + mdelay(1); + } + + /* + * "PCI Bus Power Management Interface Specification" define + * Minimum System Software Guaranteed Delays + * + * D0, D1 or D2 --> D3, need delay 10ms. + * But based on my test results, we need to delay 30ms when EP + * plug in p1022 slot2. And we need to delay 100ms when EP plug + * in p1022 slot1. So need to get maximum delay. + */ + mdelay(100); + + pm_state = pm_suspend_state(); + if (pm_state != PM_SUSPEND_MEM) + goto setup_atmu; + + /* After resume from deep-sleep, we need to restore below registers */ + /* Enable PTOD, ENL23D & EXL23D */ + clrbits32(&pci->pex_pme_mes_disr, + PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); + + out_be32(&pci->pex_pme_mes_ier, 0); + setbits32(&pci->pex_pme_mes_ier, + PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D); + + /* Get hose's pci_dev */ + dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list); -#define PCI_PM_OPS NULL + /* PME Enable */ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms); + pms |= PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms); + + /* Only reset slot, we can rework the EP device */ + if (SVR_SOC_VER(svr) == SVR_P1022 && !pcie_slot_flag) { + reset_pcie_slot(); + pcie_slot_flag = 1; + } + + spin_event_timeout(!fsl_pcie_check_link(hose), + PCIE_RESET_SLOT_WAITTIME, 0); + +setup_atmu: + setup_pci_atmu(hose); +} +static void fsl_pci_syscore_resume(void) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + fsl_pci_syscore_do_resume(hose); +} + +static struct syscore_ops pci_syscore_pm_ops = { + .suspend = fsl_pci_syscore_suspend, + .resume = fsl_pci_syscore_resume, +}; +#endif + +void fsl_pcibios_fixup_phb(struct pci_controller *phb) +{ +#ifdef CONFIG_PM_SLEEP + fsl_pci_pme_probe(phb); #endif +} + +static int fsl_pci_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *node; + + node = pdev->dev.of_node; + ret = fsl_add_bridge(pdev, fsl_pci_primary == node); + + mpc85xx_pci_err_probe(pdev); + + return ret; +} static struct platform_driver fsl_pci_driver = { .driver = { .name = "fsl-pci", - .pm = PCI_PM_OPS, .of_match_table = pci_ids, }, .probe = fsl_pci_probe, @@ -1209,6 +1403,9 @@ static struct platform_driver fsl_pci_driver = { static int __init fsl_pci_init(void) { +#ifdef CONFIG_PM_SLEEP + register_syscore_ops(&pci_syscore_pm_ops); +#endif return platform_driver_register(&fsl_pci_driver); } arch_initcall(fsl_pci_init); diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index f1b39d9..5d74092 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h @@ -32,6 +32,16 @@ struct platform_device; #define PIWAR_WRITE_SNOOP 0x00005000 #define PIWAR_SZ_MASK 0x0000003f +#define PEX_PMCR_PTOMR 0x1 +#define PEX_PMCR_EXL2S 0x2 + +#define PME_DISR_EN_PTOD 0x00008000 +#define PME_DISR_EN_ENL23D 0x00002000 +#define PME_DISR_EN_EXL23D 0x00001000 + +#define ENL23_DETECT_BIT 0x00002000 +#define EXL23_DETECT_BIT 0x00001000 + #define PAOR_LIODON_MODE 1 /* To access LIODN permission table */ #define PAOR_MSIX_VECTOR_MODE 2 /* To access MSI-X table structure */ #define PAOR_MSIX_PBA_MODE 3 /* To access MSI-X PBA structure */ @@ -193,6 +203,7 @@ struct vf_atmu_regs { extern int fsl_add_bridge(struct platform_device *pdev, int is_primary); extern void fsl_pcibios_fixup_bus(struct pci_bus *bus); +void fsl_pcibios_fixup_phb(struct pci_controller *phb); extern int mpc83xx_add_bridge(struct device_node *dev); u64 fsl_pci_immrbar_base(struct pci_controller *hose); @@ -206,6 +217,10 @@ void fsl_pci_assign_primary(void); static inline void fsl_pci_assign_primary(void) {} #endif +#ifdef CONFIG_P1022_DS +void p1022ds_reset_pcie_slot(void); +#endif + #ifdef CONFIG_EDAC_MPC85XX int mpc85xx_pci_err_probe(struct platform_device *op); #else |