From: Xi Pardee <xi.pardee@xxxxxxxxx> For Meteor Lake, retrieve the PMC Lower Power Mode (LPM) information using Intel PMT Telemetry API. Signed-off-by: Xi Pardee <xi.pardee@xxxxxxxxx> Signed-off-by: David E. Box <david.e.box@xxxxxxxxxxxxxxx> --- 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(+) 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. -- 2.34.1