@@ -5632,3 +5632,60 @@ static void apex_pci_fixup_class(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);
+
+#ifdef CONFIG_PCIE_PTM
+/*
+ * On Intel Platform Controller Hubs (PCH) since Cannon Lake, the Precision
+ * Time Measurement (PTM) capability can prevent the PCIe root port from
+ * power gating during suspend-to-idle, causing increased power consumption.
+ * So disable the feature on suspend on all Intel root ports and enable
+ * again on resume.
+ */
+static void quirk_intel_ptm_disable_suspend(struct pci_dev *dev)
+{
+ int pos;
+ u32 ctrl;
+
+ if (!(dev->ptm_enabled && dev->ptm_root))
+ return;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
+ if (!pos)
+ return;
+
+ pci_dbg(dev, "quirk: disabling PTM\n");
+
+ dev->ptm_enabled = 0;
+ dev->ptm_root = 0;
+
+ pci_read_config_dword(dev, pos + PCI_PTM_CTRL, &ctrl);
+ ctrl &= ~(PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT);
+ pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
+}
+
+static void quirk_intel_ptm_enable_resume(struct pci_dev *dev)
+{
+ int pos;
+ u32 ctrl;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
+ if (!pos)
+ return;
+
+ pci_dbg(dev, "quirk: re-enabling PTM\n");
+
+ pci_read_config_dword(dev, pos + PCI_PTM_CTRL, &ctrl);
+ ctrl |= PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT;
+ pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
+
+ dev->ptm_enabled = 1;
+ dev->ptm_root = 1;
+}
+
+DECLARE_PCI_FIXUP_CLASS_SUSPEND(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_PCI, 8,
+ quirk_intel_ptm_disable_suspend)
+DECLARE_PCI_FIXUP_CLASS_RESUME(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+ PCI_CLASS_BRIDGE_PCI, 8,
+ quirk_intel_ptm_enable_resume)
+#endif