Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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) + 4);
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");