Merge branch 'remotes/lorenzo/pci/rcar'
[platform/kernel/linux-starfive.git] / drivers / pci / controller / pcie-rcar.c
index e4cebeb..f6a669a 100644 (file)
@@ -46,6 +46,7 @@
 
 /* Transfer control */
 #define PCIETCTLR              0x02000
+#define  DL_DOWN               BIT(3)
 #define  CFINIT                        BIT(0)
 #define PCIETSTR               0x02004
 #define  DATA_LINK_ACTIVE      BIT(0)
@@ -94,6 +95,7 @@
 #define MACCTLR                        0x011058
 #define  SPEED_CHANGE          BIT(24)
 #define  SCRAMBLE_DISABLE      BIT(27)
+#define PMSR                   0x01105c
 #define MACS2R                 0x011078
 #define MACCGSPSETR            0x011084
 #define  SPCNGRSN              BIT(31)
@@ -1134,6 +1136,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
        pcie = pci_host_bridge_priv(bridge);
 
        pcie->dev = dev;
+       platform_set_drvdata(pdev, pcie);
 
        err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
        if (err)
@@ -1225,10 +1228,28 @@ err_free_bridge:
        return err;
 }
 
+static int rcar_pcie_resume_noirq(struct device *dev)
+{
+       struct rcar_pcie *pcie = dev_get_drvdata(dev);
+
+       if (rcar_pci_read_reg(pcie, PMSR) &&
+           !(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN))
+               return 0;
+
+       /* Re-establish the PCIe link */
+       rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
+       return rcar_pcie_wait_for_dl(pcie);
+}
+
+static const struct dev_pm_ops rcar_pcie_pm_ops = {
+       .resume_noirq = rcar_pcie_resume_noirq,
+};
+
 static struct platform_driver rcar_pcie_driver = {
        .driver = {
                .name = "rcar-pcie",
                .of_match_table = rcar_pcie_of_match,
+               .pm = &rcar_pcie_pm_ops,
                .suppress_bind_attrs = true,
        },
        .probe = rcar_pcie_probe,