[11/11] platform/x86/intel/pmc/mtl: get LPM information using Intel PMT

Message ID 20230315183405.2465630-12-david.e.box@linux.intel.com
State New
Headers
Series Intel pmc_core: Enable telemetry |

Commit Message

David E. Box March 15, 2023, 6:34 p.m. UTC
  From: Xi Pardee <xi.pardee@intel.com>

For Meteor Lake, retrieve the PMC Lower Power Mode (LPM) information using
Intel PMT Telemetry API.

Signed-off-by: Xi Pardee <xi.pardee@intel.com>
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
 drivers/platform/x86/intel/pmc/core.c |  1 +
 drivers/platform/x86/intel/pmc/core.h |  1 +
 drivers/platform/x86/intel/pmc/mtl.c  | 64 +++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)
  

Patch

diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index 3833ea4a758e..2e4a9ca1be62 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -1291,4 +1291,5 @@  module_platform_driver(pmc_core_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel PMC Core Driver");
+MODULE_IMPORT_NS(INTEL_PMT);
 MODULE_IMPORT_NS(INTEL_VSEC);
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index f4b69861c17b..e5d33999c865 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -306,6 +306,7 @@  struct pmc_reg_map {
 	const u32 lpm_status_offset;
 	const u32 lpm_live_status_offset;
 	const u32 etr3_offset;
+	const u8  *lpm_reg_index;
 };
 
 /**
diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
index 74f1f4c44812..d51ec35e085d 100644
--- a/drivers/platform/x86/intel/pmc/mtl.c
+++ b/drivers/platform/x86/intel/pmc/mtl.c
@@ -21,6 +21,13 @@ 
 #define SSRAM_PCH_OFFSET	0x60
 #define SSRAM_IOE_OFFSET	0x68
 
+#define SOCS_LPM_REQ_GUID	0x2625030
+#define LPM_REG_INDEX_OFFSET	2
+#define LPM_REG_NUM		28
+#define LPM_SUBSTATE_NUM	1
+
+static const u8 MTL_LPM_REG_INDEX[] = {0, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20};
+
 const struct pmc_reg_map mtl_reg_map = {
 	.pfear_sts = ext_tgl_pfear_map,
 	.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
@@ -45,8 +52,60 @@  const struct pmc_reg_map mtl_reg_map = {
 	.lpm_sts = adl_lpm_maps,
 	.lpm_status_offset = MTL_LPM_STATUS_OFFSET,
 	.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
+	.lpm_reg_index = MTL_LPM_REG_INDEX,
 };
 
+/*
+ * Only return error EPROBE_DEFER when telem handle is not yet available,
+ * otherwise returns 0.
+ */
+static int pmc_core_get_mtl_lpm_reqs(struct pmc_dev *pmcdev)
+{
+	const u8 *reg_index = pmcdev->map->lpm_reg_index;
+	const int num_maps = pmcdev->map->lpm_num_maps;
+	struct pci_dev *pcidev = pmcdev->ssram_pcidev;
+	u32 lpm_size = LPM_MAX_NUM_MODES * num_maps;
+	struct telem_handle *handle;
+	int i, j, map_offset = 0;
+	u32 *lpm_req_regs;
+
+	if (!pcidev)
+		return 0;
+
+	handle = pmt_telem_find_and_register_handle(pcidev, SOCS_LPM_REQ_GUID, 0);
+	if (IS_ERR(handle)) {
+		dev_err(&pmcdev->pdev->dev,
+				"pmc_core: couldn't get telem handle %ld", PTR_ERR(handle));
+		return -EPROBE_DEFER;
+	}
+
+	lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev, lpm_size * sizeof(u32),
+				     GFP_KERNEL);
+
+	for (j = 0; j < pmcdev->num_lpm_modes; j++) {
+		int mode = pmcdev->lpm_en_modes[j];
+		u32 *ptr = lpm_req_regs + mode * num_maps;
+
+		for (i = 0; i < num_maps; ++i) {
+			u8 index = reg_index[i] + LPM_REG_INDEX_OFFSET + map_offset;
+			int err;
+
+			err = pmt_telem_read32(handle, index, ptr, 1);
+			if (err) {
+				dev_err(&pmcdev->pdev->dev, "pmt_telem read failed: %d", err);
+				pmt_telem_unregister_handle(handle);
+				return 0;
+			}
+			++ptr;
+		}
+		map_offset += LPM_REG_NUM + LPM_SUBSTATE_NUM;
+	}
+	pmcdev->lpm_req_regs = lpm_req_regs;
+	pmt_telem_unregister_handle(handle);
+
+	return 0;
+}
+
 static void
 mtl_pmc_add_pmt(struct pmc_dev *pmcdev, struct pci_dev *pdev, u64 ssram_base)
 {
@@ -152,6 +211,11 @@  int mtl_core_init(struct pmc_dev *pmcdev)
 	mtl_pmc_ssram_init(pmcdev);
 
 	pmc_core_get_low_power_modes(pmcdev->pdev);
+	ret = pmc_core_get_mtl_lpm_reqs(pmcdev);
+	if (ret) {
+		iounmap(pmcdev->regbase);
+		return ret;
+	}
 
 	/* Due to a hardware limitation, the GBE LTR blocks PC10
 	 * when a cable is attached. Tell the PMC to ignore it.