|
@@ -22,10 +22,13 @@
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/string.h>
|
|
#include <linux/string.h>
|
|
#include <linux/init.h>
|
|
#include <linux/init.h>
|
|
|
|
+#include <linux/interrupt.h>
|
|
#include <linux/bootmem.h>
|
|
#include <linux/bootmem.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/suspend.h>
|
|
|
|
+#include <linux/syscore_ops.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
@@ -1094,55 +1097,171 @@ 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 0;
|
|
|
|
|
|
+ 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;
|
|
|
|
|
|
- hose = pci_find_hose_for_OF_device(dev->of_node);
|
|
|
|
- if (!hose)
|
|
|
|
- return -ENODEV;
|
|
|
|
|
|
+ /* 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;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ res = devm_request_irq(hose->parent, pme_irq,
|
|
|
|
+ fsl_pci_pme_handle,
|
|
|
|
+ IRQF_SHARED,
|
|
|
|
+ "[PCI] PME", hose);
|
|
|
|
+ if (res < 0) {
|
|
|
|
+ dev_err(&dev->dev, "Unable to requiest irq %d for PME\n", pme_irq);
|
|
|
|
+ irq_dispose_mapping(pme_irq);
|
|
|
|
|
|
- if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
|
|
|
|
- dev_err(dev, "Get pci register base failed.");
|
|
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
- setup_pci_atmu(hose);
|
|
|
|
|
|
+ pci = hose->private_data;
|
|
|
|
+
|
|
|
|
+ /* Enable PTOD, ENL23D & EXL23D */
|
|
|
|
+ out_be32(&pci->pex_pme_mes_disr, 0);
|
|
|
|
+ setbits32(&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;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static const struct dev_pm_ops pci_pm_ops = {
|
|
|
|
- .resume = fsl_pci_resume,
|
|
|
|
-};
|
|
|
|
|
|
+static void send_pme_turnoff_message(struct pci_controller *hose)
|
|
|
|
+{
|
|
|
|
+ struct ccsr_pci __iomem *pci = hose->private_data;
|
|
|
|
+ u32 dr;
|
|
|
|
+ int i;
|
|
|
|
|
|
-#define PCI_PM_OPS (&pci_pm_ops)
|
|
|
|
|
|
+ /* Send PME_Turn_Off Message Request */
|
|
|
|
+ setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
|
|
|
|
|
|
-#else
|
|
|
|
|
|
+ /* Wait trun off done */
|
|
|
|
+ for (i = 0; i < 150; i++) {
|
|
|
|
+ dr = in_be32(&pci->pex_pme_mes_dr);
|
|
|
|
+ if (dr) {
|
|
|
|
+ out_be32(&pci->pex_pme_mes_dr, dr);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
|
|
-#define PCI_PM_OPS NULL
|
|
|
|
|
|
+ udelay(1000);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
|
|
+static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
|
|
|
|
+{
|
|
|
|
+ send_pme_turnoff_message(hose);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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 void fsl_pci_syscore_do_resume(struct pci_controller *hose)
|
|
|
|
+{
|
|
|
|
+ struct ccsr_pci __iomem *pci = hose->private_data;
|
|
|
|
+ u32 dr;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ /* Send Exit L2 State Message */
|
|
|
|
+ setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
|
|
|
|
+
|
|
|
|
+ /* Wait exit done */
|
|
|
|
+ for (i = 0; i < 150; i++) {
|
|
|
|
+ dr = in_be32(&pci->pex_pme_mes_dr);
|
|
|
|
+ if (dr) {
|
|
|
|
+ out_be32(&pci->pex_pme_mes_dr, dr);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ udelay(1000);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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
|
|
#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)
|
|
|
|
+{
|
|
|
|
+ struct device_node *node;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ node = pdev->dev.of_node;
|
|
|
|
+ ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
|
|
|
|
+
|
|
|
|
+ mpc85xx_pci_err_probe(pdev);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static struct platform_driver fsl_pci_driver = {
|
|
static struct platform_driver fsl_pci_driver = {
|
|
.driver = {
|
|
.driver = {
|
|
.name = "fsl-pci",
|
|
.name = "fsl-pci",
|
|
- .pm = PCI_PM_OPS,
|
|
|
|
.of_match_table = pci_ids,
|
|
.of_match_table = pci_ids,
|
|
},
|
|
},
|
|
.probe = fsl_pci_probe,
|
|
.probe = fsl_pci_probe,
|
|
@@ -1150,6 +1269,9 @@ static struct platform_driver fsl_pci_driver = {
|
|
|
|
|
|
static int __init fsl_pci_init(void)
|
|
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);
|
|
return platform_driver_register(&fsl_pci_driver);
|
|
}
|
|
}
|
|
arch_initcall(fsl_pci_init);
|
|
arch_initcall(fsl_pci_init);
|