cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

qcom-cpufreq-nvmem.c (12435B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
      4 */
      5
      6/*
      7 * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
      8 * the CPU frequency subset and voltage value of each OPP varies
      9 * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
     10 * defines the voltage and frequency value based on the msm-id in SMEM
     11 * and speedbin blown in the efuse combination.
     12 * The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC
     13 * to provide the OPP framework with required information.
     14 * This is used to determine the voltage and frequency value for each OPP of
     15 * operating-points-v2 table when it is parsed by the OPP framework.
     16 */
     17
     18#include <linux/cpu.h>
     19#include <linux/err.h>
     20#include <linux/init.h>
     21#include <linux/kernel.h>
     22#include <linux/module.h>
     23#include <linux/nvmem-consumer.h>
     24#include <linux/of.h>
     25#include <linux/of_device.h>
     26#include <linux/platform_device.h>
     27#include <linux/pm_domain.h>
     28#include <linux/pm_opp.h>
     29#include <linux/slab.h>
     30#include <linux/soc/qcom/smem.h>
     31
     32#define MSM_ID_SMEM	137
     33
     34enum _msm_id {
     35	MSM8996V3 = 0xF6ul,
     36	APQ8096V3 = 0x123ul,
     37	MSM8996SG = 0x131ul,
     38	APQ8096SG = 0x138ul,
     39};
     40
     41enum _msm8996_version {
     42	MSM8996_V3,
     43	MSM8996_SG,
     44	NUM_OF_MSM8996_VERSIONS,
     45};
     46
     47struct qcom_cpufreq_drv;
     48
     49struct qcom_cpufreq_match_data {
     50	int (*get_version)(struct device *cpu_dev,
     51			   struct nvmem_cell *speedbin_nvmem,
     52			   char **pvs_name,
     53			   struct qcom_cpufreq_drv *drv);
     54	const char **genpd_names;
     55};
     56
     57struct qcom_cpufreq_drv {
     58	struct opp_table **names_opp_tables;
     59	struct opp_table **hw_opp_tables;
     60	struct opp_table **genpd_opp_tables;
     61	u32 versions;
     62	const struct qcom_cpufreq_match_data *data;
     63};
     64
     65static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
     66
     67static void get_krait_bin_format_a(struct device *cpu_dev,
     68					  int *speed, int *pvs, int *pvs_ver,
     69					  struct nvmem_cell *pvs_nvmem, u8 *buf)
     70{
     71	u32 pte_efuse;
     72
     73	pte_efuse = *((u32 *)buf);
     74
     75	*speed = pte_efuse & 0xf;
     76	if (*speed == 0xf)
     77		*speed = (pte_efuse >> 4) & 0xf;
     78
     79	if (*speed == 0xf) {
     80		*speed = 0;
     81		dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed);
     82	} else {
     83		dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
     84	}
     85
     86	*pvs = (pte_efuse >> 10) & 0x7;
     87	if (*pvs == 0x7)
     88		*pvs = (pte_efuse >> 13) & 0x7;
     89
     90	if (*pvs == 0x7) {
     91		*pvs = 0;
     92		dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs);
     93	} else {
     94		dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
     95	}
     96}
     97
     98static void get_krait_bin_format_b(struct device *cpu_dev,
     99					  int *speed, int *pvs, int *pvs_ver,
    100					  struct nvmem_cell *pvs_nvmem, u8 *buf)
    101{
    102	u32 pte_efuse, redundant_sel;
    103
    104	pte_efuse = *((u32 *)buf);
    105	redundant_sel = (pte_efuse >> 24) & 0x7;
    106
    107	*pvs_ver = (pte_efuse >> 4) & 0x3;
    108
    109	switch (redundant_sel) {
    110	case 1:
    111		*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
    112		*speed = (pte_efuse >> 27) & 0xf;
    113		break;
    114	case 2:
    115		*pvs = (pte_efuse >> 27) & 0xf;
    116		*speed = pte_efuse & 0x7;
    117		break;
    118	default:
    119		/* 4 bits of PVS are in efuse register bits 31, 8-6. */
    120		*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
    121		*speed = pte_efuse & 0x7;
    122	}
    123
    124	/* Check SPEED_BIN_BLOW_STATUS */
    125	if (pte_efuse & BIT(3)) {
    126		dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
    127	} else {
    128		dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n");
    129		*speed = 0;
    130	}
    131
    132	/* Check PVS_BLOW_STATUS */
    133	pte_efuse = *(((u32 *)buf) + 1);
    134	pte_efuse &= BIT(21);
    135	if (pte_efuse) {
    136		dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
    137	} else {
    138		dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n");
    139		*pvs = 0;
    140	}
    141
    142	dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver);
    143}
    144
    145static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
    146{
    147	size_t len;
    148	u32 *msm_id;
    149	enum _msm8996_version version;
    150
    151	msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
    152	if (IS_ERR(msm_id))
    153		return NUM_OF_MSM8996_VERSIONS;
    154
    155	/* The first 4 bytes are format, next to them is the actual msm-id */
    156	msm_id++;
    157
    158	switch ((enum _msm_id)*msm_id) {
    159	case MSM8996V3:
    160	case APQ8096V3:
    161		version = MSM8996_V3;
    162		break;
    163	case MSM8996SG:
    164	case APQ8096SG:
    165		version = MSM8996_SG;
    166		break;
    167	default:
    168		version = NUM_OF_MSM8996_VERSIONS;
    169	}
    170
    171	return version;
    172}
    173
    174static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
    175					  struct nvmem_cell *speedbin_nvmem,
    176					  char **pvs_name,
    177					  struct qcom_cpufreq_drv *drv)
    178{
    179	size_t len;
    180	u8 *speedbin;
    181	enum _msm8996_version msm8996_version;
    182	*pvs_name = NULL;
    183
    184	msm8996_version = qcom_cpufreq_get_msm_id();
    185	if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
    186		dev_err(cpu_dev, "Not Snapdragon 820/821!");
    187		return -ENODEV;
    188	}
    189
    190	speedbin = nvmem_cell_read(speedbin_nvmem, &len);
    191	if (IS_ERR(speedbin))
    192		return PTR_ERR(speedbin);
    193
    194	switch (msm8996_version) {
    195	case MSM8996_V3:
    196		drv->versions = 1 << (unsigned int)(*speedbin);
    197		break;
    198	case MSM8996_SG:
    199		drv->versions = 1 << ((unsigned int)(*speedbin) + 4);
    200		break;
    201	default:
    202		BUG();
    203		break;
    204	}
    205
    206	kfree(speedbin);
    207	return 0;
    208}
    209
    210static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
    211					   struct nvmem_cell *speedbin_nvmem,
    212					   char **pvs_name,
    213					   struct qcom_cpufreq_drv *drv)
    214{
    215	int speed = 0, pvs = 0, pvs_ver = 0;
    216	u8 *speedbin;
    217	size_t len;
    218
    219	speedbin = nvmem_cell_read(speedbin_nvmem, &len);
    220
    221	if (IS_ERR(speedbin))
    222		return PTR_ERR(speedbin);
    223
    224	switch (len) {
    225	case 4:
    226		get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver,
    227				       speedbin_nvmem, speedbin);
    228		break;
    229	case 8:
    230		get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver,
    231				       speedbin_nvmem, speedbin);
    232		break;
    233	default:
    234		dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
    235		return -ENODEV;
    236	}
    237
    238	snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
    239		 speed, pvs, pvs_ver);
    240
    241	drv->versions = (1 << speed);
    242
    243	kfree(speedbin);
    244	return 0;
    245}
    246
    247static const struct qcom_cpufreq_match_data match_data_kryo = {
    248	.get_version = qcom_cpufreq_kryo_name_version,
    249};
    250
    251static const struct qcom_cpufreq_match_data match_data_krait = {
    252	.get_version = qcom_cpufreq_krait_name_version,
    253};
    254
    255static const char *qcs404_genpd_names[] = { "cpr", NULL };
    256
    257static const struct qcom_cpufreq_match_data match_data_qcs404 = {
    258	.genpd_names = qcs404_genpd_names,
    259};
    260
    261static int qcom_cpufreq_probe(struct platform_device *pdev)
    262{
    263	struct qcom_cpufreq_drv *drv;
    264	struct nvmem_cell *speedbin_nvmem;
    265	struct device_node *np;
    266	struct device *cpu_dev;
    267	char *pvs_name = "speedXX-pvsXX-vXX";
    268	unsigned cpu;
    269	const struct of_device_id *match;
    270	int ret;
    271
    272	cpu_dev = get_cpu_device(0);
    273	if (!cpu_dev)
    274		return -ENODEV;
    275
    276	np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
    277	if (!np)
    278		return -ENOENT;
    279
    280	ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
    281	if (!ret) {
    282		of_node_put(np);
    283		return -ENOENT;
    284	}
    285
    286	drv = kzalloc(sizeof(*drv), GFP_KERNEL);
    287	if (!drv)
    288		return -ENOMEM;
    289
    290	match = pdev->dev.platform_data;
    291	drv->data = match->data;
    292	if (!drv->data) {
    293		ret = -ENODEV;
    294		goto free_drv;
    295	}
    296
    297	if (drv->data->get_version) {
    298		speedbin_nvmem = of_nvmem_cell_get(np, NULL);
    299		if (IS_ERR(speedbin_nvmem)) {
    300			if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
    301				dev_err(cpu_dev,
    302					"Could not get nvmem cell: %ld\n",
    303					PTR_ERR(speedbin_nvmem));
    304			ret = PTR_ERR(speedbin_nvmem);
    305			goto free_drv;
    306		}
    307
    308		ret = drv->data->get_version(cpu_dev,
    309							speedbin_nvmem, &pvs_name, drv);
    310		if (ret) {
    311			nvmem_cell_put(speedbin_nvmem);
    312			goto free_drv;
    313		}
    314		nvmem_cell_put(speedbin_nvmem);
    315	}
    316	of_node_put(np);
    317
    318	drv->names_opp_tables = kcalloc(num_possible_cpus(),
    319				  sizeof(*drv->names_opp_tables),
    320				  GFP_KERNEL);
    321	if (!drv->names_opp_tables) {
    322		ret = -ENOMEM;
    323		goto free_drv;
    324	}
    325	drv->hw_opp_tables = kcalloc(num_possible_cpus(),
    326				  sizeof(*drv->hw_opp_tables),
    327				  GFP_KERNEL);
    328	if (!drv->hw_opp_tables) {
    329		ret = -ENOMEM;
    330		goto free_opp_names;
    331	}
    332
    333	drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
    334					sizeof(*drv->genpd_opp_tables),
    335					GFP_KERNEL);
    336	if (!drv->genpd_opp_tables) {
    337		ret = -ENOMEM;
    338		goto free_opp;
    339	}
    340
    341	for_each_possible_cpu(cpu) {
    342		cpu_dev = get_cpu_device(cpu);
    343		if (NULL == cpu_dev) {
    344			ret = -ENODEV;
    345			goto free_genpd_opp;
    346		}
    347
    348		if (drv->data->get_version) {
    349
    350			if (pvs_name) {
    351				drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
    352								     cpu_dev,
    353								     pvs_name);
    354				if (IS_ERR(drv->names_opp_tables[cpu])) {
    355					ret = PTR_ERR(drv->names_opp_tables[cpu]);
    356					dev_err(cpu_dev, "Failed to add OPP name %s\n",
    357						pvs_name);
    358					goto free_opp;
    359				}
    360			}
    361
    362			drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
    363									 cpu_dev, &drv->versions, 1);
    364			if (IS_ERR(drv->hw_opp_tables[cpu])) {
    365				ret = PTR_ERR(drv->hw_opp_tables[cpu]);
    366				dev_err(cpu_dev,
    367					"Failed to set supported hardware\n");
    368				goto free_genpd_opp;
    369			}
    370		}
    371
    372		if (drv->data->genpd_names) {
    373			drv->genpd_opp_tables[cpu] =
    374				dev_pm_opp_attach_genpd(cpu_dev,
    375							drv->data->genpd_names,
    376							NULL);
    377			if (IS_ERR(drv->genpd_opp_tables[cpu])) {
    378				ret = PTR_ERR(drv->genpd_opp_tables[cpu]);
    379				if (ret != -EPROBE_DEFER)
    380					dev_err(cpu_dev,
    381						"Could not attach to pm_domain: %d\n",
    382						ret);
    383				goto free_genpd_opp;
    384			}
    385		}
    386	}
    387
    388	cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
    389							  NULL, 0);
    390	if (!IS_ERR(cpufreq_dt_pdev)) {
    391		platform_set_drvdata(pdev, drv);
    392		return 0;
    393	}
    394
    395	ret = PTR_ERR(cpufreq_dt_pdev);
    396	dev_err(cpu_dev, "Failed to register platform device\n");
    397
    398free_genpd_opp:
    399	for_each_possible_cpu(cpu) {
    400		if (IS_ERR(drv->genpd_opp_tables[cpu]))
    401			break;
    402		dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
    403	}
    404	kfree(drv->genpd_opp_tables);
    405free_opp:
    406	for_each_possible_cpu(cpu) {
    407		if (IS_ERR(drv->names_opp_tables[cpu]))
    408			break;
    409		dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
    410	}
    411	for_each_possible_cpu(cpu) {
    412		if (IS_ERR(drv->hw_opp_tables[cpu]))
    413			break;
    414		dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
    415	}
    416	kfree(drv->hw_opp_tables);
    417free_opp_names:
    418	kfree(drv->names_opp_tables);
    419free_drv:
    420	kfree(drv);
    421
    422	return ret;
    423}
    424
    425static int qcom_cpufreq_remove(struct platform_device *pdev)
    426{
    427	struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev);
    428	unsigned int cpu;
    429
    430	platform_device_unregister(cpufreq_dt_pdev);
    431
    432	for_each_possible_cpu(cpu) {
    433		dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
    434		dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
    435		dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
    436	}
    437
    438	kfree(drv->names_opp_tables);
    439	kfree(drv->hw_opp_tables);
    440	kfree(drv->genpd_opp_tables);
    441	kfree(drv);
    442
    443	return 0;
    444}
    445
    446static struct platform_driver qcom_cpufreq_driver = {
    447	.probe = qcom_cpufreq_probe,
    448	.remove = qcom_cpufreq_remove,
    449	.driver = {
    450		.name = "qcom-cpufreq-nvmem",
    451	},
    452};
    453
    454static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
    455	{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
    456	{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
    457	{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
    458	{ .compatible = "qcom,ipq8064", .data = &match_data_krait },
    459	{ .compatible = "qcom,apq8064", .data = &match_data_krait },
    460	{ .compatible = "qcom,msm8974", .data = &match_data_krait },
    461	{ .compatible = "qcom,msm8960", .data = &match_data_krait },
    462	{},
    463};
    464MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list);
    465
    466/*
    467 * Since the driver depends on smem and nvmem drivers, which may
    468 * return EPROBE_DEFER, all the real activity is done in the probe,
    469 * which may be defered as well. The init here is only registering
    470 * the driver and the platform device.
    471 */
    472static int __init qcom_cpufreq_init(void)
    473{
    474	struct device_node *np = of_find_node_by_path("/");
    475	const struct of_device_id *match;
    476	int ret;
    477
    478	if (!np)
    479		return -ENODEV;
    480
    481	match = of_match_node(qcom_cpufreq_match_list, np);
    482	of_node_put(np);
    483	if (!match)
    484		return -ENODEV;
    485
    486	ret = platform_driver_register(&qcom_cpufreq_driver);
    487	if (unlikely(ret < 0))
    488		return ret;
    489
    490	cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq-nvmem",
    491						     -1, match, sizeof(*match));
    492	ret = PTR_ERR_OR_ZERO(cpufreq_pdev);
    493	if (0 == ret)
    494		return 0;
    495
    496	platform_driver_unregister(&qcom_cpufreq_driver);
    497	return ret;
    498}
    499module_init(qcom_cpufreq_init);
    500
    501static void __exit qcom_cpufreq_exit(void)
    502{
    503	platform_device_unregister(cpufreq_pdev);
    504	platform_driver_unregister(&qcom_cpufreq_driver);
    505}
    506module_exit(qcom_cpufreq_exit);
    507
    508MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver");
    509MODULE_LICENSE("GPL v2");