xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/linux/mali_devfreq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2011-2017 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10 
11 #include "mali_osk_mali.h"
12 #include "mali_kernel_common.h"
13 
14 #include <linux/clk.h>
15 #include <linux/clk-provider.h>
16 #include <linux/devfreq.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/regulator/driver.h>
19 #ifdef CONFIG_DEVFREQ_THERMAL
20 #include <linux/devfreq_cooling.h>
21 #endif
22 
23 #include <linux/version.h>
24 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
25 #include <linux/pm_opp.h>
26 #else /* Linux >= 3.13 */
27 /* In 3.13 the OPP include header file, types, and functions were all
28  * renamed. Use the old filename for the include, and define the new names to
29  * the old, when an old kernel is detected.
30  */
31 #include <linux/opp.h>
32 #define dev_pm_opp opp
33 #define dev_pm_opp_get_voltage opp_get_voltage
34 #define dev_pm_opp_get_opp_count opp_get_opp_count
35 #define dev_pm_opp_find_freq_ceil opp_find_freq_ceil
36 #endif /* Linux >= 3.13 */
37 
38 #include "mali_pm_metrics.h"
39 
40 #include <soc/rockchip/rockchip_opp_select.h>
41 #include <soc/rockchip/rockchip_system_monitor.h>
42 
43 static struct monitor_dev_profile mali_mdevp = {
44 	.type = MONITOR_TYPE_DEV,
45 	.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
46 	.high_temp_adjust = rockchip_monitor_dev_high_temp_adjust,
47 };
48 
49 static struct devfreq_simple_ondemand_data ondemand_data;
50 
51 static int
mali_devfreq_target(struct device * dev,unsigned long * target_freq,u32 flags)52 mali_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
53 {
54 	struct mali_device *mdev = dev_get_drvdata(dev);
55 	struct dev_pm_opp *opp;
56 	unsigned long freq = 0;
57 	unsigned long old_freq = mdev->current_freq;
58 	unsigned long voltage;
59 	int err;
60 
61 	freq = *target_freq;
62 
63 	opp = devfreq_recommended_opp(dev, &freq, flags);
64 	if (IS_ERR(opp)) {
65 		MALI_PRINT_ERROR(("Failed to get opp (%ld)\n", PTR_ERR(opp)));
66 		return PTR_ERR(opp);
67 	}
68 	voltage = dev_pm_opp_get_voltage(opp);
69 	dev_pm_opp_put(opp);
70 
71 	MALI_DEBUG_PRINT(2, ("mali_devfreq_target:set_freq = %lld flags = 0x%x\n", freq, flags));
72 	/*
73 	 * Only update if there is a change of frequency
74 	 */
75 	if (old_freq == freq) {
76 		*target_freq = freq;
77 		mali_pm_reset_dvfs_utilisation(mdev);
78 #ifdef CONFIG_REGULATOR
79 		if (mdev->current_voltage == voltage)
80 			return 0;
81 		err = regulator_set_voltage(mdev->regulator, voltage, INT_MAX);
82 		if (err) {
83 			dev_err(dev, "Failed to set voltage (%d)\n", err);
84 			return err;
85 		}
86 		mdev->current_voltage = voltage;
87 #endif
88 		return 0;
89 	}
90 
91 	err = clk_bulk_enable(mdev->num_clks, mdev->clks);
92 	if (err)
93 		return err;
94 
95 #ifdef CONFIG_REGULATOR
96 	if (mdev->regulator && mdev->current_voltage != voltage &&
97 	    old_freq < freq) {
98 		err = regulator_set_voltage(mdev->regulator, voltage, INT_MAX);
99 		if (err) {
100 			MALI_PRINT_ERROR(("Failed to increase voltage (%d)\n", err));
101 			goto err;
102 		}
103 	}
104 #endif
105 
106 	err = clk_set_rate(mdev->clock, freq);
107 	if (err) {
108 		MALI_PRINT_ERROR(("Failed to set clock %lu (target %lu)\n", freq, *target_freq));
109 		goto err;
110 	}
111 
112 	*target_freq = freq;
113 	mdev->current_freq = freq;
114 	if (mdev->devfreq)
115 		mdev->devfreq->last_status.current_frequency = freq;
116 
117 #ifdef CONFIG_REGULATOR
118 	if (mdev->regulator && mdev->current_voltage != voltage &&
119 	    old_freq > freq) {
120 		err = regulator_set_voltage(mdev->regulator, voltage, INT_MAX);
121 		if (err) {
122 			MALI_PRINT_ERROR(("Failed to decrease voltage (%d)\n", err));
123 			goto err;
124 		}
125 	}
126 #endif
127 
128 	mdev->current_voltage = voltage;
129 
130 	mali_pm_reset_dvfs_utilisation(mdev);
131 err:
132 	clk_bulk_disable(mdev->num_clks, mdev->clks);
133 
134 	return err;
135 }
136 
137 static int
mali_devfreq_cur_freq(struct device * dev,unsigned long * freq)138 mali_devfreq_cur_freq(struct device *dev, unsigned long *freq)
139 {
140 	struct mali_device *mdev = dev_get_drvdata(dev);
141 
142 	*freq = mdev->current_freq;
143 
144 	MALI_DEBUG_PRINT(2, ("mali_devfreq_cur_freq: freq = %d \n", *freq));
145 	return 0;
146 }
147 
148 static int
mali_devfreq_status(struct device * dev,struct devfreq_dev_status * stat)149 mali_devfreq_status(struct device *dev, struct devfreq_dev_status *stat)
150 {
151 	struct mali_device *mdev = dev_get_drvdata(dev);
152 
153 	stat->current_frequency = mdev->current_freq;
154 
155 	mali_pm_get_dvfs_utilisation(mdev,
156 				     &stat->total_time, &stat->busy_time);
157 
158 	stat->private_data = NULL;
159 
160 #ifdef CONFIG_DEVFREQ_THERMAL
161 	memcpy(&mdev->devfreq->last_status, stat, sizeof(*stat));
162 #endif
163 
164 	return 0;
165 }
166 
167 /* setup platform specific opp in platform.c*/
setup_opps(void)168 int __weak setup_opps(void)
169 {
170 	return 0;
171 }
172 
173 /* term platform specific opp in platform.c*/
term_opps(struct device * dev)174 int __weak term_opps(struct device *dev)
175 {
176 	return 0;
177 }
178 
mali_devfreq_init_freq_table(struct mali_device * mdev,struct devfreq_dev_profile * dp)179 static int mali_devfreq_init_freq_table(struct mali_device *mdev,
180 					struct devfreq_dev_profile *dp)
181 {
182 	int err, count;
183 	int i = 0;
184 	unsigned long freq = 0;
185 	struct dev_pm_opp *opp;
186 
187 	err = setup_opps();
188 	if (err)
189 		return err;
190 
191 	count = dev_pm_opp_get_opp_count(mdev->dev);
192 	if (count < 0) {
193 		return count;
194 	}
195 
196 	MALI_DEBUG_PRINT(2, ("mali devfreq table count %d\n", count));
197 
198 	dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]),
199 				       GFP_KERNEL);
200 	if (!dp->freq_table)
201 		return -ENOMEM;
202 
203 	for (i = 0; i < count; i++, freq++) {
204 		opp = dev_pm_opp_find_freq_ceil(mdev->dev, &freq);
205 		if (IS_ERR(opp))
206 			break;
207 		dev_pm_opp_put(opp);
208 
209 		dp->freq_table[i] = freq;
210 		MALI_DEBUG_PRINT(2, ("mali devfreq table array[%d] = %d\n", i, freq));
211 	}
212 
213 	if (count != i)
214 		MALI_PRINT_ERROR(("Unable to enumerate all OPPs (%d!=%d)\n",
215 				  count, i));
216 
217 	dp->max_state = i;
218 
219 	return 0;
220 }
221 
mali_devfreq_term_freq_table(struct mali_device * mdev)222 static void mali_devfreq_term_freq_table(struct mali_device *mdev)
223 {
224 	struct devfreq_dev_profile *dp = mdev->devfreq->profile;
225 
226 	kfree(dp->freq_table);
227 	term_opps(mdev->dev);
228 }
229 
mali_devfreq_exit(struct device * dev)230 static void mali_devfreq_exit(struct device *dev)
231 {
232 	struct mali_device *mdev = dev_get_drvdata(dev);
233 
234 	mali_devfreq_term_freq_table(mdev);
235 }
236 
mali_devfreq_init(struct mali_device * mdev)237 int mali_devfreq_init(struct mali_device *mdev)
238 {
239 	struct device_node *np = mdev->dev->of_node;
240 #ifdef CONFIG_DEVFREQ_THERMAL
241 	struct devfreq_cooling_power *callbacks = NULL;
242 	_mali_osk_device_data data;
243 #endif
244 	struct devfreq_dev_profile *dp;
245 	struct dev_pm_opp *opp;
246 	unsigned long opp_rate;
247 	int err;
248 
249 	MALI_DEBUG_PRINT(2, ("Init Mali devfreq\n"));
250 
251 	if (!mdev->clock)
252 		return -ENODEV;
253 
254 	mdev->current_freq = clk_get_rate(mdev->clock);
255 
256 	dp = &mdev->devfreq_profile;
257 
258 	dp->initial_freq = mdev->current_freq;
259 	dp->polling_ms = 100;
260 	dp->target = mali_devfreq_target;
261 	dp->get_dev_status = mali_devfreq_status;
262 	dp->get_cur_freq = mali_devfreq_cur_freq;
263 	dp->exit = mali_devfreq_exit;
264 
265 	if (mali_devfreq_init_freq_table(mdev, dp))
266 		return -EFAULT;
267 
268 	of_property_read_u32(np, "upthreshold",
269 			     &ondemand_data.upthreshold);
270 	of_property_read_u32(np, "downdifferential",
271 			     &ondemand_data.downdifferential);
272 
273 	mdev->devfreq = devfreq_add_device(mdev->dev, dp,
274 					   "simple_ondemand", &ondemand_data);
275 	if (IS_ERR(mdev->devfreq)) {
276 		mali_devfreq_term_freq_table(mdev);
277 		return PTR_ERR(mdev->devfreq);
278 	}
279 
280 	err = devfreq_register_opp_notifier(mdev->dev, mdev->devfreq);
281 	if (err) {
282 		MALI_PRINT_ERROR(("Failed to register OPP notifier (%d)\n", err));
283 		goto opp_notifier_failed;
284 	}
285 
286 	opp_rate = mdev->current_freq;
287 	opp = devfreq_recommended_opp(mdev->dev, &opp_rate, 0);
288 	if (!IS_ERR(opp))
289 		dev_pm_opp_put(opp);
290 	mdev->devfreq->last_status.current_frequency = opp_rate;
291 
292 	mali_mdevp.data = mdev->devfreq;
293 	mdev->mdev_info = rockchip_system_monitor_register(mdev->dev,
294 							   &mali_mdevp);
295 	if (IS_ERR(mdev->mdev_info)) {
296 		dev_dbg(mdev->dev, "without system monitor\n");
297 		mdev->mdev_info = NULL;
298 	}
299 #ifdef CONFIG_DEVFREQ_THERMAL
300 	if (of_machine_is_compatible("rockchip,rk3036"))
301 		return 0;
302 
303 	/* Initilization last_status it will be used when first power allocate called */
304 	mdev->devfreq->last_status.current_frequency = mdev->current_freq;
305 
306 	if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) {
307 		if (NULL != data.gpu_cooling_ops) {
308 			callbacks = data.gpu_cooling_ops;
309 			MALI_DEBUG_PRINT(2, ("Mali GPU Thermal: Callback handler installed \n"));
310 		}
311 	}
312 
313 	if (callbacks) {
314 		mdev->devfreq_cooling = of_devfreq_cooling_register_power(
315 						mdev->dev->of_node,
316 						mdev->devfreq,
317 						callbacks);
318 		if (IS_ERR_OR_NULL(mdev->devfreq_cooling)) {
319 			err = PTR_ERR(mdev->devfreq_cooling);
320 			MALI_PRINT_ERROR(("Failed to register cooling device (%d)\n", err));
321 			goto cooling_failed;
322 		} else {
323 			MALI_DEBUG_PRINT(2, ("Mali GPU Thermal Cooling installed \n"));
324 		}
325 	}
326 #endif
327 
328 	return 0;
329 
330 #ifdef CONFIG_DEVFREQ_THERMAL
331 cooling_failed:
332 	devfreq_unregister_opp_notifier(mdev->dev, mdev->devfreq);
333 #endif /* CONFIG_DEVFREQ_THERMAL */
334 opp_notifier_failed:
335 	err = devfreq_remove_device(mdev->devfreq);
336 	if (err)
337 		MALI_PRINT_ERROR(("Failed to terminate devfreq (%d)\n", err));
338 	else
339 		mdev->devfreq = NULL;
340 
341 	return err;
342 }
343 
mali_devfreq_term(struct mali_device * mdev)344 void mali_devfreq_term(struct mali_device *mdev)
345 {
346 	int err;
347 
348 	MALI_DEBUG_PRINT(2, ("Term Mali devfreq\n"));
349 
350 	rockchip_system_monitor_unregister(mdev->mdev_info);
351 #ifdef CONFIG_DEVFREQ_THERMAL
352 	devfreq_cooling_unregister(mdev->devfreq_cooling);
353 #endif
354 
355 	devfreq_unregister_opp_notifier(mdev->dev, mdev->devfreq);
356 
357 	err = devfreq_remove_device(mdev->devfreq);
358 	if (err)
359 		MALI_PRINT_ERROR(("Failed to terminate devfreq (%d)\n", err));
360 	else
361 		mdev->devfreq = NULL;
362 }
363