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/platform_device.h>
26#include <linux/pm_domain.h>
27#include <linux/pm_opp.h>
28#include <linux/slab.h>
29#include <linux/soc/qcom/smem.h>
30
31#include <dt-bindings/arm/qcom,ids.h>
32
33struct qcom_cpufreq_drv;
34
35struct qcom_cpufreq_match_data {
36	int (*get_version)(struct device *cpu_dev,
37			   struct nvmem_cell *speedbin_nvmem,
38			   char **pvs_name,
39			   struct qcom_cpufreq_drv *drv);
40	const char **genpd_names;
41};
42
43struct qcom_cpufreq_drv {
44	int *opp_tokens;
45	u32 versions;
46	const struct qcom_cpufreq_match_data *data;
47};
48
49static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
50
51static void get_krait_bin_format_a(struct device *cpu_dev,
52					  int *speed, int *pvs, int *pvs_ver,
53					  u8 *buf)
54{
55	u32 pte_efuse;
56
57	pte_efuse = *((u32 *)buf);
58
59	*speed = pte_efuse & 0xf;
60	if (*speed == 0xf)
61		*speed = (pte_efuse >> 4) & 0xf;
62
63	if (*speed == 0xf) {
64		*speed = 0;
65		dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed);
66	} else {
67		dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
68	}
69
70	*pvs = (pte_efuse >> 10) & 0x7;
71	if (*pvs == 0x7)
72		*pvs = (pte_efuse >> 13) & 0x7;
73
74	if (*pvs == 0x7) {
75		*pvs = 0;
76		dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs);
77	} else {
78		dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
79	}
80}
81
82static void get_krait_bin_format_b(struct device *cpu_dev,
83					  int *speed, int *pvs, int *pvs_ver,
84					  u8 *buf)
85{
86	u32 pte_efuse, redundant_sel;
87
88	pte_efuse = *((u32 *)buf);
89	redundant_sel = (pte_efuse >> 24) & 0x7;
90
91	*pvs_ver = (pte_efuse >> 4) & 0x3;
92
93	switch (redundant_sel) {
94	case 1:
95		*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
96		*speed = (pte_efuse >> 27) & 0xf;
97		break;
98	case 2:
99		*pvs = (pte_efuse >> 27) & 0xf;
100		*speed = pte_efuse & 0x7;
101		break;
102	default:
103		/* 4 bits of PVS are in efuse register bits 31, 8-6. */
104		*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
105		*speed = pte_efuse & 0x7;
106	}
107
108	/* Check SPEED_BIN_BLOW_STATUS */
109	if (pte_efuse & BIT(3)) {
110		dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
111	} else {
112		dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n");
113		*speed = 0;
114	}
115
116	/* Check PVS_BLOW_STATUS */
117	pte_efuse = *(((u32 *)buf) + 1);
118	pte_efuse &= BIT(21);
119	if (pte_efuse) {
120		dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
121	} else {
122		dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n");
123		*pvs = 0;
124	}
125
126	dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver);
127}
128
129static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
130					  struct nvmem_cell *speedbin_nvmem,
131					  char **pvs_name,
132					  struct qcom_cpufreq_drv *drv)
133{
134	size_t len;
135	u32 msm_id;
136	u8 *speedbin;
137	int ret;
138	*pvs_name = NULL;
139
140	ret = qcom_smem_get_soc_id(&msm_id);
141	if (ret)
142		return ret;
143
144	speedbin = nvmem_cell_read(speedbin_nvmem, &len);
145	if (IS_ERR(speedbin))
146		return PTR_ERR(speedbin);
147
148	switch (msm_id) {
149	case QCOM_ID_MSM8996:
150	case QCOM_ID_APQ8096:
151		drv->versions = 1 << (unsigned int)(*speedbin);
152		break;
153	case QCOM_ID_MSM8996SG:
154	case QCOM_ID_APQ8096SG:
155		drv->versions = 1 << ((unsigned int)(*speedbin) + 4);
156		break;
157	default:
158		BUG();
159		break;
160	}
161
162	kfree(speedbin);
163	return 0;
164}
165
166static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
167					   struct nvmem_cell *speedbin_nvmem,
168					   char **pvs_name,
169					   struct qcom_cpufreq_drv *drv)
170{
171	int speed = 0, pvs = 0, pvs_ver = 0;
172	u8 *speedbin;
173	size_t len;
174	int ret = 0;
175
176	speedbin = nvmem_cell_read(speedbin_nvmem, &len);
177
178	if (IS_ERR(speedbin))
179		return PTR_ERR(speedbin);
180
181	switch (len) {
182	case 4:
183		get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver,
184				       speedbin);
185		break;
186	case 8:
187		get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver,
188				       speedbin);
189		break;
190	default:
191		dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
192		ret = -ENODEV;
193		goto len_error;
194	}
195
196	snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
197		 speed, pvs, pvs_ver);
198
199	drv->versions = (1 << speed);
200
201len_error:
202	kfree(speedbin);
203	return ret;
204}
205
206static const struct qcom_cpufreq_match_data match_data_kryo = {
207	.get_version = qcom_cpufreq_kryo_name_version,
208};
209
210static const struct qcom_cpufreq_match_data match_data_krait = {
211	.get_version = qcom_cpufreq_krait_name_version,
212};
213
214static const char *qcs404_genpd_names[] = { "cpr", NULL };
215
216static const struct qcom_cpufreq_match_data match_data_qcs404 = {
217	.genpd_names = qcs404_genpd_names,
218};
219
220static int qcom_cpufreq_probe(struct platform_device *pdev)
221{
222	struct qcom_cpufreq_drv *drv;
223	struct nvmem_cell *speedbin_nvmem;
224	struct device_node *np;
225	struct device *cpu_dev;
226	char pvs_name_buffer[] = "speedXX-pvsXX-vXX";
227	char *pvs_name = pvs_name_buffer;
228	unsigned cpu;
229	const struct of_device_id *match;
230	int ret;
231
232	cpu_dev = get_cpu_device(0);
233	if (!cpu_dev)
234		return -ENODEV;
235
236	np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
237	if (!np)
238		return -ENOENT;
239
240	ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
241	if (!ret) {
242		of_node_put(np);
243		return -ENOENT;
244	}
245
246	drv = kzalloc(sizeof(*drv), GFP_KERNEL);
247	if (!drv)
248		return -ENOMEM;
249
250	match = pdev->dev.platform_data;
251	drv->data = match->data;
252	if (!drv->data) {
253		ret = -ENODEV;
254		goto free_drv;
255	}
256
257	if (drv->data->get_version) {
258		speedbin_nvmem = of_nvmem_cell_get(np, NULL);
259		if (IS_ERR(speedbin_nvmem)) {
260			ret = dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem),
261					    "Could not get nvmem cell\n");
262			goto free_drv;
263		}
264
265		ret = drv->data->get_version(cpu_dev,
266							speedbin_nvmem, &pvs_name, drv);
267		if (ret) {
268			nvmem_cell_put(speedbin_nvmem);
269			goto free_drv;
270		}
271		nvmem_cell_put(speedbin_nvmem);
272	}
273	of_node_put(np);
274
275	drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens),
276				  GFP_KERNEL);
277	if (!drv->opp_tokens) {
278		ret = -ENOMEM;
279		goto free_drv;
280	}
281
282	for_each_possible_cpu(cpu) {
283		struct dev_pm_opp_config config = {
284			.supported_hw = NULL,
285		};
286
287		cpu_dev = get_cpu_device(cpu);
288		if (NULL == cpu_dev) {
289			ret = -ENODEV;
290			goto free_opp;
291		}
292
293		if (drv->data->get_version) {
294			config.supported_hw = &drv->versions;
295			config.supported_hw_count = 1;
296
297			if (pvs_name)
298				config.prop_name = pvs_name;
299		}
300
301		if (drv->data->genpd_names) {
302			config.genpd_names = drv->data->genpd_names;
303			config.virt_devs = NULL;
304		}
305
306		if (config.supported_hw || config.genpd_names) {
307			drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config);
308			if (drv->opp_tokens[cpu] < 0) {
309				ret = drv->opp_tokens[cpu];
310				dev_err(cpu_dev, "Failed to set OPP config\n");
311				goto free_opp;
312			}
313		}
314	}
315
316	cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
317							  NULL, 0);
318	if (!IS_ERR(cpufreq_dt_pdev)) {
319		platform_set_drvdata(pdev, drv);
320		return 0;
321	}
322
323	ret = PTR_ERR(cpufreq_dt_pdev);
324	dev_err(cpu_dev, "Failed to register platform device\n");
325
326free_opp:
327	for_each_possible_cpu(cpu)
328		dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
329	kfree(drv->opp_tokens);
330free_drv:
331	kfree(drv);
332
333	return ret;
334}
335
336static void qcom_cpufreq_remove(struct platform_device *pdev)
337{
338	struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev);
339	unsigned int cpu;
340
341	platform_device_unregister(cpufreq_dt_pdev);
342
343	for_each_possible_cpu(cpu)
344		dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
345
346	kfree(drv->opp_tokens);
347	kfree(drv);
348}
349
350static struct platform_driver qcom_cpufreq_driver = {
351	.probe = qcom_cpufreq_probe,
352	.remove_new = qcom_cpufreq_remove,
353	.driver = {
354		.name = "qcom-cpufreq-nvmem",
355	},
356};
357
358static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
359	{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
360	{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
361	{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
362	{ .compatible = "qcom,ipq8064", .data = &match_data_krait },
363	{ .compatible = "qcom,apq8064", .data = &match_data_krait },
364	{ .compatible = "qcom,msm8974", .data = &match_data_krait },
365	{ .compatible = "qcom,msm8960", .data = &match_data_krait },
366	{},
367};
368MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list);
369
370/*
371 * Since the driver depends on smem and nvmem drivers, which may
372 * return EPROBE_DEFER, all the real activity is done in the probe,
373 * which may be defered as well. The init here is only registering
374 * the driver and the platform device.
375 */
376static int __init qcom_cpufreq_init(void)
377{
378	struct device_node *np = of_find_node_by_path("/");
379	const struct of_device_id *match;
380	int ret;
381
382	if (!np)
383		return -ENODEV;
384
385	match = of_match_node(qcom_cpufreq_match_list, np);
386	of_node_put(np);
387	if (!match)
388		return -ENODEV;
389
390	ret = platform_driver_register(&qcom_cpufreq_driver);
391	if (unlikely(ret < 0))
392		return ret;
393
394	cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq-nvmem",
395						     -1, match, sizeof(*match));
396	ret = PTR_ERR_OR_ZERO(cpufreq_pdev);
397	if (0 == ret)
398		return 0;
399
400	platform_driver_unregister(&qcom_cpufreq_driver);
401	return ret;
402}
403module_init(qcom_cpufreq_init);
404
405static void __exit qcom_cpufreq_exit(void)
406{
407	platform_device_unregister(cpufreq_pdev);
408	platform_driver_unregister(&qcom_cpufreq_driver);
409}
410module_exit(qcom_cpufreq_exit);
411
412MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver");
413MODULE_LICENSE("GPL v2");
414