1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/bitfield.h>
7#include <linux/cpufreq.h>
8#include <linux/init.h>
9#include <linux/interconnect.h>
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/of_address.h>
13#include <linux/of_platform.h>
14#include <linux/pm_opp.h>
15#include <linux/slab.h>
16
17#define LUT_MAX_ENTRIES			40U
18#define LUT_SRC				GENMASK(31, 30)
19#define LUT_L_VAL			GENMASK(7, 0)
20#define LUT_CORE_COUNT			GENMASK(18, 16)
21#define LUT_VOLT			GENMASK(11, 0)
22#define CLK_HW_DIV			2
23#define LUT_TURBO_IND			1
24
25struct qcom_cpufreq_soc_data {
26	u32 reg_enable;
27	u32 reg_freq_lut;
28	u32 reg_volt_lut;
29	u32 reg_perf_state;
30	u8 lut_row_size;
31};
32
33struct qcom_cpufreq_data {
34	void __iomem *base;
35	struct resource *res;
36	const struct qcom_cpufreq_soc_data *soc_data;
37};
38
39static unsigned long cpu_hw_rate, xo_rate;
40static bool icc_scaling_enabled;
41
42static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy,
43			       unsigned long freq_khz)
44{
45	unsigned long freq_hz = freq_khz * 1000;
46	struct dev_pm_opp *opp;
47	struct device *dev;
48	int ret;
49
50	dev = get_cpu_device(policy->cpu);
51	if (!dev)
52		return -ENODEV;
53
54	opp = dev_pm_opp_find_freq_exact(dev, freq_hz, true);
55	if (IS_ERR(opp))
56		return PTR_ERR(opp);
57
58	ret = dev_pm_opp_set_bw(dev, opp);
59	dev_pm_opp_put(opp);
60	return ret;
61}
62
63static int qcom_cpufreq_update_opp(struct device *cpu_dev,
64				   unsigned long freq_khz,
65				   unsigned long volt)
66{
67	unsigned long freq_hz = freq_khz * 1000;
68	int ret;
69
70	/* Skip voltage update if the opp table is not available */
71	if (!icc_scaling_enabled)
72		return dev_pm_opp_add(cpu_dev, freq_hz, volt);
73
74	ret = dev_pm_opp_adjust_voltage(cpu_dev, freq_hz, volt, volt, volt);
75	if (ret) {
76		dev_err(cpu_dev, "Voltage update failed freq=%ld\n", freq_khz);
77		return ret;
78	}
79
80	return dev_pm_opp_enable(cpu_dev, freq_hz);
81}
82
83static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
84					unsigned int index)
85{
86	struct qcom_cpufreq_data *data = policy->driver_data;
87	const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
88	unsigned long freq = policy->freq_table[index].frequency;
89
90	writel_relaxed(index, data->base + soc_data->reg_perf_state);
91
92	if (icc_scaling_enabled)
93		qcom_cpufreq_set_bw(policy, freq);
94
95	return 0;
96}
97
98static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
99{
100	struct qcom_cpufreq_data *data;
101	const struct qcom_cpufreq_soc_data *soc_data;
102	struct cpufreq_policy *policy;
103	unsigned int index;
104
105	policy = cpufreq_cpu_get_raw(cpu);
106	if (!policy)
107		return 0;
108
109	data = policy->driver_data;
110	soc_data = data->soc_data;
111
112	index = readl_relaxed(data->base + soc_data->reg_perf_state);
113	index = min(index, LUT_MAX_ENTRIES - 1);
114
115	return policy->freq_table[index].frequency;
116}
117
118static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
119						unsigned int target_freq)
120{
121	struct qcom_cpufreq_data *data = policy->driver_data;
122	const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
123	unsigned int index;
124
125	index = policy->cached_resolved_idx;
126	writel_relaxed(index, data->base + soc_data->reg_perf_state);
127
128	return policy->freq_table[index].frequency;
129}
130
131static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
132				    struct cpufreq_policy *policy)
133{
134	u32 data, src, lval, i, core_count, prev_freq = 0, freq;
135	u32 volt;
136	struct cpufreq_frequency_table	*table;
137	struct dev_pm_opp *opp;
138	unsigned long rate;
139	int ret;
140	struct qcom_cpufreq_data *drv_data = policy->driver_data;
141	const struct qcom_cpufreq_soc_data *soc_data = drv_data->soc_data;
142
143	table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
144	if (!table)
145		return -ENOMEM;
146
147	ret = dev_pm_opp_of_add_table(cpu_dev);
148	if (!ret) {
149		/* Disable all opps and cross-validate against LUT later */
150		icc_scaling_enabled = true;
151		for (rate = 0; ; rate++) {
152			opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
153			if (IS_ERR(opp))
154				break;
155
156			dev_pm_opp_put(opp);
157			dev_pm_opp_disable(cpu_dev, rate);
158		}
159	} else if (ret != -ENODEV) {
160		dev_err(cpu_dev, "Invalid opp table in device tree\n");
161		kfree(table);
162		return ret;
163	} else {
164		policy->fast_switch_possible = true;
165		icc_scaling_enabled = false;
166	}
167
168	for (i = 0; i < LUT_MAX_ENTRIES; i++) {
169		data = readl_relaxed(drv_data->base + soc_data->reg_freq_lut +
170				      i * soc_data->lut_row_size);
171		src = FIELD_GET(LUT_SRC, data);
172		lval = FIELD_GET(LUT_L_VAL, data);
173		core_count = FIELD_GET(LUT_CORE_COUNT, data);
174
175		data = readl_relaxed(drv_data->base + soc_data->reg_volt_lut +
176				      i * soc_data->lut_row_size);
177		volt = FIELD_GET(LUT_VOLT, data) * 1000;
178
179		if (src)
180			freq = xo_rate * lval / 1000;
181		else
182			freq = cpu_hw_rate / 1000;
183
184		if (freq != prev_freq && core_count != LUT_TURBO_IND) {
185			if (!qcom_cpufreq_update_opp(cpu_dev, freq, volt)) {
186				table[i].frequency = freq;
187				dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i,
188				freq, core_count);
189			} else {
190				dev_warn(cpu_dev, "failed to update OPP for freq=%d\n", freq);
191				table[i].frequency = CPUFREQ_ENTRY_INVALID;
192			}
193
194		} else if (core_count == LUT_TURBO_IND) {
195			table[i].frequency = CPUFREQ_ENTRY_INVALID;
196		}
197
198		/*
199		 * Two of the same frequencies with the same core counts means
200		 * end of table
201		 */
202		if (i > 0 && prev_freq == freq) {
203			struct cpufreq_frequency_table *prev = &table[i - 1];
204
205			/*
206			 * Only treat the last frequency that might be a boost
207			 * as the boost frequency
208			 */
209			if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
210				if (!qcom_cpufreq_update_opp(cpu_dev, prev_freq, volt)) {
211					prev->frequency = prev_freq;
212					prev->flags = CPUFREQ_BOOST_FREQ;
213				} else {
214					dev_warn(cpu_dev, "failed to update OPP for freq=%d\n",
215						 freq);
216				}
217			}
218
219			break;
220		}
221
222		prev_freq = freq;
223	}
224
225	table[i].frequency = CPUFREQ_TABLE_END;
226	policy->freq_table = table;
227	dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
228
229	return 0;
230}
231
232static void qcom_get_related_cpus(int index, struct cpumask *m)
233{
234	struct device_node *cpu_np;
235	struct of_phandle_args args;
236	int cpu, ret;
237
238	for_each_possible_cpu(cpu) {
239		cpu_np = of_cpu_device_node_get(cpu);
240		if (!cpu_np)
241			continue;
242
243		ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
244						 "#freq-domain-cells", 0,
245						 &args);
246		of_node_put(cpu_np);
247		if (ret < 0)
248			continue;
249
250		if (index == args.args[0])
251			cpumask_set_cpu(cpu, m);
252	}
253}
254
255static const struct qcom_cpufreq_soc_data qcom_soc_data = {
256	.reg_enable = 0x0,
257	.reg_freq_lut = 0x110,
258	.reg_volt_lut = 0x114,
259	.reg_perf_state = 0x920,
260	.lut_row_size = 32,
261};
262
263static const struct qcom_cpufreq_soc_data epss_soc_data = {
264	.reg_enable = 0x0,
265	.reg_freq_lut = 0x100,
266	.reg_volt_lut = 0x200,
267	.reg_perf_state = 0x320,
268	.lut_row_size = 4,
269};
270
271static const struct of_device_id qcom_cpufreq_hw_match[] = {
272	{ .compatible = "qcom,cpufreq-hw", .data = &qcom_soc_data },
273	{ .compatible = "qcom,cpufreq-epss", .data = &epss_soc_data },
274	{}
275};
276MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
277
278static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
279{
280	struct platform_device *pdev = cpufreq_get_driver_data();
281	struct device *dev = &pdev->dev;
282	struct of_phandle_args args;
283	struct device_node *cpu_np;
284	struct device *cpu_dev;
285	struct resource *res;
286	void __iomem *base;
287	struct qcom_cpufreq_data *data;
288	int ret, index;
289
290	cpu_dev = get_cpu_device(policy->cpu);
291	if (!cpu_dev) {
292		pr_err("%s: failed to get cpu%d device\n", __func__,
293		       policy->cpu);
294		return -ENODEV;
295	}
296
297	cpu_np = of_cpu_device_node_get(policy->cpu);
298	if (!cpu_np)
299		return -EINVAL;
300
301	ret = of_parse_phandle_with_args(cpu_np, "qcom,freq-domain",
302					 "#freq-domain-cells", 0, &args);
303	of_node_put(cpu_np);
304	if (ret)
305		return ret;
306
307	index = args.args[0];
308
309	res = platform_get_resource(pdev, IORESOURCE_MEM, index);
310	if (!res) {
311		dev_err(dev, "failed to get mem resource %d\n", index);
312		return -ENODEV;
313	}
314
315	if (!request_mem_region(res->start, resource_size(res), res->name)) {
316		dev_err(dev, "failed to request resource %pR\n", res);
317		return -EBUSY;
318	}
319
320	base = ioremap(res->start, resource_size(res));
321	if (!base) {
322		dev_err(dev, "failed to map resource %pR\n", res);
323		ret = -ENOMEM;
324		goto release_region;
325	}
326
327	data = kzalloc(sizeof(*data), GFP_KERNEL);
328	if (!data) {
329		ret = -ENOMEM;
330		goto unmap_base;
331	}
332
333	data->soc_data = of_device_get_match_data(&pdev->dev);
334	data->base = base;
335	data->res = res;
336
337	/* HW should be in enabled state to proceed */
338	if (!(readl_relaxed(base + data->soc_data->reg_enable) & 0x1)) {
339		dev_err(dev, "Domain-%d cpufreq hardware not enabled\n", index);
340		ret = -ENODEV;
341		goto error;
342	}
343
344	qcom_get_related_cpus(index, policy->cpus);
345	if (!cpumask_weight(policy->cpus)) {
346		dev_err(dev, "Domain-%d failed to get related CPUs\n", index);
347		ret = -ENOENT;
348		goto error;
349	}
350
351	policy->driver_data = data;
352
353	ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy);
354	if (ret) {
355		dev_err(dev, "Domain-%d failed to read LUT\n", index);
356		goto error;
357	}
358
359	ret = dev_pm_opp_get_opp_count(cpu_dev);
360	if (ret <= 0) {
361		dev_err(cpu_dev, "Failed to add OPPs\n");
362		ret = -ENODEV;
363		goto error;
364	}
365
366	dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
367
368	return 0;
369error:
370	kfree(data);
371unmap_base:
372	iounmap(base);
373release_region:
374	release_mem_region(res->start, resource_size(res));
375	return ret;
376}
377
378static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
379{
380	struct device *cpu_dev = get_cpu_device(policy->cpu);
381	struct qcom_cpufreq_data *data = policy->driver_data;
382	struct resource *res = data->res;
383	void __iomem *base = data->base;
384
385	dev_pm_opp_remove_all_dynamic(cpu_dev);
386	dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
387	kfree(policy->freq_table);
388	kfree(data);
389	iounmap(base);
390	release_mem_region(res->start, resource_size(res));
391
392	return 0;
393}
394
395static struct freq_attr *qcom_cpufreq_hw_attr[] = {
396	&cpufreq_freq_attr_scaling_available_freqs,
397	&cpufreq_freq_attr_scaling_boost_freqs,
398	NULL
399};
400
401static struct cpufreq_driver cpufreq_qcom_hw_driver = {
402	.flags		= CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
403			  CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
404			  CPUFREQ_IS_COOLING_DEV,
405	.verify		= cpufreq_generic_frequency_table_verify,
406	.target_index	= qcom_cpufreq_hw_target_index,
407	.get		= qcom_cpufreq_hw_get,
408	.init		= qcom_cpufreq_hw_cpu_init,
409	.exit		= qcom_cpufreq_hw_cpu_exit,
410	.fast_switch    = qcom_cpufreq_hw_fast_switch,
411	.name		= "qcom-cpufreq-hw",
412	.attr		= qcom_cpufreq_hw_attr,
413};
414
415static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
416{
417	struct device *cpu_dev;
418	struct clk *clk;
419	int ret;
420
421	clk = clk_get(&pdev->dev, "xo");
422	if (IS_ERR(clk))
423		return PTR_ERR(clk);
424
425	xo_rate = clk_get_rate(clk);
426	clk_put(clk);
427
428	clk = clk_get(&pdev->dev, "alternate");
429	if (IS_ERR(clk))
430		return PTR_ERR(clk);
431
432	cpu_hw_rate = clk_get_rate(clk) / CLK_HW_DIV;
433	clk_put(clk);
434
435	cpufreq_qcom_hw_driver.driver_data = pdev;
436
437	/* Check for optional interconnect paths on CPU0 */
438	cpu_dev = get_cpu_device(0);
439	if (!cpu_dev)
440		return -EPROBE_DEFER;
441
442	ret = dev_pm_opp_of_find_icc_paths(cpu_dev, NULL);
443	if (ret)
444		return ret;
445
446	ret = cpufreq_register_driver(&cpufreq_qcom_hw_driver);
447	if (ret)
448		dev_err(&pdev->dev, "CPUFreq HW driver failed to register\n");
449	else
450		dev_dbg(&pdev->dev, "QCOM CPUFreq HW driver initialized\n");
451
452	return ret;
453}
454
455static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
456{
457	return cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
458}
459
460static struct platform_driver qcom_cpufreq_hw_driver = {
461	.probe = qcom_cpufreq_hw_driver_probe,
462	.remove = qcom_cpufreq_hw_driver_remove,
463	.driver = {
464		.name = "qcom-cpufreq-hw",
465		.of_match_table = qcom_cpufreq_hw_match,
466	},
467};
468
469static int __init qcom_cpufreq_hw_init(void)
470{
471	return platform_driver_register(&qcom_cpufreq_hw_driver);
472}
473postcore_initcall(qcom_cpufreq_hw_init);
474
475static void __exit qcom_cpufreq_hw_exit(void)
476{
477	platform_driver_unregister(&qcom_cpufreq_hw_driver);
478}
479module_exit(qcom_cpufreq_hw_exit);
480
481MODULE_DESCRIPTION("QCOM CPUFREQ HW Driver");
482MODULE_LICENSE("GPL v2");
483