diff options
| author | Xi Pardee <xi.pardee@linux.intel.com> | 2025-04-09 12:10:43 -0700 |
|---|---|---|
| committer | Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> | 2025-04-11 15:26:01 +0300 |
| commit | 78a7491d5cba8b63c8dbaafc15cc92a2e3f049ca (patch) | |
| tree | a840ae6020e78a5c24c7a2a2848cd7283089e9b1 /drivers/platform/x86/intel/pmc/core.c | |
| parent | platform/x86: silicom: use new GPIO line value setter callbacks (diff) | |
| download | linux-78a7491d5cba8b63c8dbaafc15cc92a2e3f049ca.tar.gz linux-78a7491d5cba8b63c8dbaafc15cc92a2e3f049ca.zip | |
platform/x86:intel/pmc: Move PMC Core related functions
Move functions that implements PMC Core feature from core_ssram.c
to core.c. This patch is a preparation step to introduce a new
SSRAM Telemetry driver for the SSRAM device.
Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20250409191056.15434-2-xi.pardee@linux.intel.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Diffstat (limited to 'drivers/platform/x86/intel/pmc/core.c')
| -rw-r--r-- | drivers/platform/x86/intel/pmc/core.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 7a1d11f2914f..a42dc62d70da 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1345,6 +1345,173 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev) } } +static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map) +{ + for (; list->map; ++list) + if (list->map == map) + return list->guid; + + return 0; +} + +static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc) +{ + struct telem_endpoint *ep; + const u8 *lpm_indices; + int num_maps, mode_offset = 0; + int ret, mode; + int lpm_size; + u32 guid; + + lpm_indices = pmc->map->lpm_reg_index; + num_maps = pmc->map->lpm_num_maps; + lpm_size = LPM_MAX_NUM_MODES * num_maps; + + guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map); + if (!guid) + return -ENXIO; + + ep = pmt_telem_find_and_register_endpoint(pmcdev->ssram_pcidev, guid, 0); + if (IS_ERR(ep)) { + dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %ld", + PTR_ERR(ep)); + return -EPROBE_DEFER; + } + + pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev, + lpm_size * sizeof(u32), + GFP_KERNEL); + if (!pmc->lpm_req_regs) { + ret = -ENOMEM; + goto unregister_ep; + } + + /* + * PMC Low Power Mode (LPM) table + * + * In telemetry space, the LPM table contains a 4 byte header followed + * by 8 consecutive mode blocks (one for each LPM mode). Each block + * has a 4 byte header followed by a set of registers that describe the + * IP state requirements for the given mode. The IP mapping is platform + * specific but the same for each block, making for easy analysis. + * Platforms only use a subset of the space to track the requirements + * for their IPs. Callers provide the requirement registers they use as + * a list of indices. Each requirement register is associated with an + * IP map that's maintained by the caller. + * + * Header + * +----+----------------------------+----------------------------+ + * | 0 | REVISION | ENABLED MODES | + * +----+--------------+-------------+-------------+--------------+ + * + * Low Power Mode 0 Block + * +----+--------------+-------------+-------------+--------------+ + * | 1 | SUB ID | SIZE | MAJOR | MINOR | + * +----+--------------+-------------+-------------+--------------+ + * | 2 | LPM0 Requirements 0 | + * +----+---------------------------------------------------------+ + * | | ... | + * +----+---------------------------------------------------------+ + * | 29 | LPM0 Requirements 27 | + * +----+---------------------------------------------------------+ + * + * ... + * + * Low Power Mode 7 Block + * +----+--------------+-------------+-------------+--------------+ + * | | SUB ID | SIZE | MAJOR | MINOR | + * +----+--------------+-------------+-------------+--------------+ + * | 60 | LPM7 Requirements 0 | + * +----+---------------------------------------------------------+ + * | | ... | + * +----+---------------------------------------------------------+ + * | 87 | LPM7 Requirements 27 | + * +----+---------------------------------------------------------+ + * + */ + mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET; + pmc_for_each_mode(mode, pmcdev) { + u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps); + int m; + + for (m = 0; m < num_maps; m++) { + u8 sample_id = lpm_indices[m] + mode_offset; + + ret = pmt_telem_read32(ep, sample_id, req_offset, 1); + if (ret) { + dev_err(&pmcdev->pdev->dev, + "couldn't read Low Power Mode requirements: %d\n", ret); + devm_kfree(&pmcdev->pdev->dev, pmc->lpm_req_regs); + goto unregister_ep; + } + ++req_offset; + } + mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET; + } + +unregister_ep: + pmt_telem_unregister_endpoint(ep); + + return ret; +} + +static int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev) +{ + int ret, i; + + if (!pmcdev->ssram_pcidev) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { + if (!pmcdev->pmcs[i]) + continue; + + ret = pmc_core_get_lpm_req(pmcdev, pmcdev->pmcs[i]); + if (ret) + return ret; + } + + return 0; +} + +const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid) +{ + for (; list->map; ++list) + if (devid == list->devid) + return list->map; + + return NULL; +} + +int pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base, + const struct pmc_reg_map *reg_map, int pmc_index) +{ + struct pmc *pmc = pmcdev->pmcs[pmc_index]; + + if (!pwrm_base) + return -ENODEV; + + /* Memory for primary PMC has been allocated in core.c */ + if (!pmc) { + pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL); + if (!pmc) + return -ENOMEM; + } + + pmc->map = reg_map; + pmc->base_addr = pwrm_base; + pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length); + + if (!pmc->regbase) { + devm_kfree(&pmcdev->pdev->dev, pmc); + return -ENOMEM; + } + + pmcdev->pmcs[pmc_index] = pmc; + + return 0; +} + /* * When supported, ssram init is used to achieve all available PMCs. * If ssram init fails, this function uses legacy method to at least get the @@ -1719,5 +1886,6 @@ static struct platform_driver pmc_core_driver = { module_platform_driver(pmc_core_driver); +MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel PMC Core Driver"); |
