aboutsummaryrefslogtreecommitdiff
path: root/drivers/platform/x86/intel/pmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/intel/pmc')
-rw-r--r--drivers/platform/x86/intel/pmc/core.c35
-rw-r--r--drivers/platform/x86/intel/pmc/core.h4
-rw-r--r--drivers/platform/x86/intel/pmc/mtl.c31
3 files changed, 56 insertions, 14 deletions
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index 3a15d32d7644..da6e7206d38b 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -66,7 +66,18 @@ static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int reg_offset,
static inline u64 pmc_core_adjust_slp_s0_step(struct pmc_dev *pmcdev, u32 value)
{
- return (u64)value * pmcdev->map->slp_s0_res_counter_step;
+ /*
+ * ADL PCH does not have the SLP_S0 counter and LPM Residency counters are
+ * used as a workaround which uses 30.5 usec tick. All other client
+ * programs have the legacy SLP_S0 residency counter that is using the 122
+ * usec tick.
+ */
+ const int lpm_adj_x2 = pmcdev->map->lpm_res_counter_step_x2;
+
+ if (pmcdev->map == &adl_reg_map)
+ return (u64)value * GET_X2_COUNTER((u64)lpm_adj_x2);
+ else
+ return (u64)value * pmcdev->map->slp_s0_res_counter_step;
}
static int set_etr3(struct pmc_dev *pmcdev)
@@ -1142,6 +1153,8 @@ static int pmc_core_probe(struct platform_device *pdev)
pmc_core_do_dmi_quirks(pmcdev);
pmc_core_dbgfs_register(pmcdev);
+ pm_report_max_hw_sleep(FIELD_MAX(SLP_S0_RES_COUNTER_MASK) *
+ pmc_core_adjust_slp_s0_step(pmcdev, 1));
device_initialized = true;
dev_info(&pdev->dev, " initialized\n");
@@ -1149,7 +1162,7 @@ static int pmc_core_probe(struct platform_device *pdev)
return 0;
}
-static int pmc_core_remove(struct platform_device *pdev)
+static void pmc_core_remove(struct platform_device *pdev)
{
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
@@ -1157,7 +1170,6 @@ static int pmc_core_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
mutex_destroy(&pmcdev->lock);
iounmap(pmcdev->regbase);
- return 0;
}
static bool warn_on_s0ix_failures;
@@ -1168,12 +1180,6 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
{
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
- pmcdev->check_counters = false;
-
- /* No warnings on S0ix failures */
- if (!warn_on_s0ix_failures)
- return 0;
-
/* Check if the syspend will actually use S0ix */
if (pm_suspend_via_firmware())
return 0;
@@ -1186,7 +1192,6 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
if (pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter))
return -EIO;
- pmcdev->check_counters = true;
return 0;
}
@@ -1210,6 +1215,8 @@ static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
if (pmc_core_dev_state_get(pmcdev, &s0ix_counter))
return false;
+ pm_report_hw_sleep_time((u32)(s0ix_counter - pmcdev->s0ix_counter));
+
if (s0ix_counter == pmcdev->s0ix_counter)
return true;
@@ -1222,12 +1229,16 @@ static __maybe_unused int pmc_core_resume(struct device *dev)
const struct pmc_bit_map **maps = pmcdev->map->lpm_sts;
int offset = pmcdev->map->lpm_status_offset;
- if (!pmcdev->check_counters)
+ /* Check if the syspend used S0ix */
+ if (pm_suspend_via_firmware())
return 0;
if (!pmc_core_is_s0ix_failed(pmcdev))
return 0;
+ if (!warn_on_s0ix_failures)
+ return 0;
+
if (pmc_core_is_pc10_failed(pmcdev)) {
/* S0ix failed because of PC10 entry failure */
dev_info(dev, "CPU did not enter PC10!!! (PC10 cnt=0x%llx)\n",
@@ -1264,7 +1275,7 @@ static struct platform_driver pmc_core_driver = {
.dev_groups = pmc_dev_groups,
},
.probe = pmc_core_probe,
- .remove = pmc_core_remove,
+ .remove_new = pmc_core_remove,
};
module_platform_driver(pmc_core_driver);
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 810204d758ab..9ca9b9746719 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -16,6 +16,8 @@
#include <linux/bits.h>
#include <linux/platform_device.h>
+#define SLP_S0_RES_COUNTER_MASK GENMASK(31, 0)
+
#define PMC_BASE_ADDR_DEFAULT 0xFE000000
/* Sunrise Point Power Management Controller PCI Device ID */
@@ -319,7 +321,6 @@ struct pmc_reg_map {
* @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
* used to read MPHY PG and PLL status are available
* @mutex_lock: mutex to complete one transcation
- * @check_counters: On resume, check if counters are getting incremented
* @pc10_counter: PC10 residency counter
* @s0ix_counter: S0ix residency (step adjusted)
* @num_lpm_modes: Count of enabled modes
@@ -338,7 +339,6 @@ struct pmc_dev {
int pmc_xram_read_bit;
struct mutex lock; /* generic mutex lock for PMC Core */
- bool check_counters; /* Check for counter increments on resume */
u64 pc10_counter;
u64 s0ix_counter;
int num_lpm_modes;
diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
index eeb3bd8c2502..e8cc156412ce 100644
--- a/drivers/platform/x86/intel/pmc/mtl.c
+++ b/drivers/platform/x86/intel/pmc/mtl.c
@@ -8,6 +8,7 @@
*
*/
+#include <linux/pci.h>
#include "core.h"
const struct pmc_reg_map mtl_reg_map = {
@@ -45,8 +46,38 @@ void mtl_core_configure(struct pmc_dev *pmcdev)
pmc_core_send_ltr_ignore(pmcdev, 3);
}
+#define MTL_GNA_PCI_DEV 0x7e4c
+#define MTL_IPU_PCI_DEV 0x7d19
+#define MTL_VPU_PCI_DEV 0x7d1d
+static void mtl_set_device_d3(unsigned int device)
+{
+ struct pci_dev *pcidev;
+
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+ if (pcidev) {
+ if (!device_trylock(&pcidev->dev)) {
+ pci_dev_put(pcidev);
+ return;
+ }
+ if (!pcidev->dev.driver) {
+ dev_info(&pcidev->dev, "Setting to D3hot\n");
+ pci_set_power_state(pcidev, PCI_D3hot);
+ }
+ device_unlock(&pcidev->dev);
+ pci_dev_put(pcidev);
+ }
+}
+
void mtl_core_init(struct pmc_dev *pmcdev)
{
pmcdev->map = &mtl_reg_map;
pmcdev->core_configure = mtl_core_configure;
+
+ /*
+ * Set power state of select devices that do not have drivers to D3
+ * so that they do not block Package C entry.
+ */
+ mtl_set_device_d3(MTL_GNA_PCI_DEV);
+ mtl_set_device_d3(MTL_IPU_PCI_DEV);
+ mtl_set_device_d3(MTL_VPU_PCI_DEV);
}