rk312x, mali_400: add comments and reform some detail codes in PDP.
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / platform / rk30 / mali_platform.c
1 /*
2  * This confidential and proprietary software may be used only as
3  * authorised by a licensing agreement from ARM Limited
4  * (C) COPYRIGHT 2009-2012 ARM Limited
5  * ALL RIGHTS RESERVED
6  * The entire notice above must be reproduced on all authorised
7  * copies and copies may only be made to the extent permitted
8  * by a licensing agreement from ARM Limited.
9  */
10
11 /**
12  * @file mali_platform.c
13  * Platform specific Mali driver functions
14  *      for a default platform
15  */
16
17 /* #define ENABLE_DEBUG_LOG */
18 #include "custom_log.h"
19
20 #include <linux/workqueue.h>
21 #include <linux/kernel.h>
22 #include <linux/slab.h>
23 #include <linux/gfp.h>
24 #include <linux/fs.h>
25 #include <linux/clk.h>
26 #include <linux/device.h>
27 #include <linux/regulator/driver.h>
28 #include <linux/miscdevice.h>
29 #include <linux/uaccess.h>
30 #include <linux/cpufreq.h>
31 #include <linux/of.h>
32
33 #include "mali_kernel_common.h"
34 #include "mali_osk.h"
35 #include "arm_core_scaling.h"
36 #include "mali_platform.h"
37
38
39 /**
40  * 是否使能 core_scaling 机制.
41  * .DP : core_scaling : 根据当前 mali_utilization_data,
42  *                      配置 mali_gpu 中具体使用的 pp_core 的个数.
43  */
44 static int mali_core_scaling_enable;
45
46 u32 mali_group_error;
47
48 /**
49  * anchor_of_device_of_mali_gpu.
50  */
51 static struct device *mali_dev;
52
53 /**
54  * 设置 current_dvfs_level.
55  *
56  * @param level
57  *      待设置为 current 的 dvfs_level 实例,
58  *      在 dvfs_level_list 中的 index,
59  *      即 index_of_new_current_level.
60  *
61  * @return
62  *      0, 成功.
63  *      其他 value, 失败.
64  */
65 int mali_set_level(struct device *dev, int level)
66 {
67         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
68         /* gpu_clk_freq_of_new_current_level. */
69         unsigned long freq;
70         int ret;
71         /* index_of_old_current_level. */
72         unsigned int current_level;
73
74         _mali_osk_mutex_wait(drv_data->clock_set_lock);
75
76         current_level = drv_data->dvfs.current_level;
77         freq = drv_data->fv_info[level].freq;
78
79         if (level == current_level) {
80                 D("we are already in the target level, to exit.");
81                 _mali_osk_mutex_signal(drv_data->clock_set_lock);
82                 return 0;
83         }
84
85         /* .KP : 调用 dvfs_module 的接口, 将 cpu_clk 设置为 'freq'. */
86         ret = dvfs_clk_set_rate(drv_data->clk, freq);
87         if (ret) {
88                 _mali_osk_mutex_signal(drv_data->clock_set_lock);
89                 return ret;
90         }
91
92         D("have set gpu_clk to %lu of new_level %d, " "the old_level is %d.",
93           freq,
94           level,
95           current_level);
96         /* update index_of_current_dvfs_level. */
97         drv_data->dvfs.current_level = level;
98
99         _mali_osk_mutex_signal(drv_data->clock_set_lock);
100
101         return 0;
102 }
103
104 /**
105  * 初始化 gpu_dvfs_node 和 gpu_power_domain.
106  */
107 static int mali_clock_init(struct device *dev)
108 {
109         int ret;
110
111         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
112
113         drv_data->pd = devm_clk_get(dev, "pd_gpu");
114         if (IS_ERR(drv_data->pd)) {
115                 ret = PTR_ERR(drv_data->pd);
116                 /* rk3228 gpu has no power domain,save NULL for compatible*/
117                 if (ret != -ENOENT) {
118                         dev_err(dev, "get pd_clk failed, %d\n", ret);
119                         return ret;
120                 }
121                 drv_data->pd = NULL;
122         }
123
124         if (drv_data->pd) {
125                 ret = clk_prepare_enable(drv_data->pd);
126                 if (ret) {
127                         dev_err(dev, "prepare pd_clk failed, %d\n", ret);
128                         return ret;
129                 }
130         }
131
132         drv_data->clk = clk_get_dvfs_node("clk_gpu");
133         if (IS_ERR(drv_data->clk)) {
134                 ret = PTR_ERR(drv_data->clk);
135                 dev_err(dev, "prepare clk gpu failed, %d\n", ret);
136                 return ret;
137         }
138
139         ret = dvfs_clk_prepare_enable(drv_data->clk);
140         if (ret) {
141                 dev_err(dev, "prepare clk failed, %d\n", ret);
142                 return ret;
143         }
144
145         drv_data->power_state = true;
146
147         return 0;
148 }
149
150 static void mali_clock_term(struct device *dev)
151 {
152         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
153
154         dvfs_clk_disable_unprepare(drv_data->clk);
155         if (drv_data->pd)
156                 clk_disable_unprepare(drv_data->pd);
157         drv_data->power_state = false;
158 }
159
160 /*---------------------------------------------------------------------------*/
161
162 static ssize_t show_available_frequencies(struct device *dev,
163                                           struct device_attribute *attr,
164                                           char *buf)
165 {
166         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
167         ssize_t ret = 0;
168         u32 i;
169
170         for (i = 0; i < drv_data->fv_info_length; i++)
171                 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%lu\n",
172                                  drv_data->fv_info[i].freq);
173
174         return ret;
175 }
176
177 static ssize_t show_clock(struct device *dev,
178                           struct device_attribute *attr, char *buf)
179 {
180         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
181
182         return scnprintf(buf,
183                          PAGE_SIZE,
184                          "%lu\n",
185                          dvfs_clk_get_rate(drv_data->clk));
186 }
187
188 static ssize_t set_clock(struct device *dev,
189                          struct device_attribute *attr,
190                          const char *buf, size_t count)
191 {
192         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
193         unsigned long freq;
194         ssize_t ret;
195         u32 level;
196
197         ret = kstrtoul(buf, 10, &freq);
198         if (ret)
199                 return ret;
200
201         for (level = drv_data->fv_info_length - 1; level > 0; level--) {
202                 unsigned long tmp  = drv_data->fv_info[level].freq;
203
204                 if (tmp <= freq)
205                         break;
206         }
207
208         dev_info(dev, "Using fv_info table %d: for %lu Hz\n", level, freq);
209
210         ret = mali_set_level(dev, level);
211         if (ret)
212                 return ret;
213
214         return count;
215 }
216
217 static ssize_t show_dvfs_enable(struct device *dev,
218                                 struct device_attribute *attr,
219                                 char *buf)
220 {
221         return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_is_enabled(dev));
222 }
223
224 static ssize_t set_dvfs_enable(struct device *dev,
225                                struct device_attribute *attr,
226                                const char *buf,
227                                size_t count)
228 {
229         unsigned long enable;
230         ssize_t ret;
231
232         ret = kstrtoul(buf, 0, &enable);
233         if (ret)
234                 return ret;
235
236         if (enable == 1)
237                 mali_dvfs_enable(dev);
238         else if (enable == 0)
239                 mali_dvfs_disable(dev);
240         else
241                 return -EINVAL;
242
243         return count;
244 }
245
246 static ssize_t show_utilisation(struct device *dev,
247                                 struct device_attribute *attr,
248                                 char *buf)
249 {
250         return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_utilisation(dev));
251 }
252
253 static int error_count_show(struct device *dev,
254                             struct device_attribute *attr,
255                             char *buf)
256 {
257         return sprintf(buf, "%d\n", mali_group_error);
258 }
259
260 DEVICE_ATTR(available_frequencies, S_IRUGO, show_available_frequencies, NULL);
261 DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
262 DEVICE_ATTR(dvfs_enable, S_IRUGO | S_IWUSR, show_dvfs_enable, set_dvfs_enable);
263 DEVICE_ATTR(utilisation, S_IRUGO, show_utilisation, NULL);
264 DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
265
266 static struct attribute *mali_sysfs_entries[] = {
267         &dev_attr_available_frequencies.attr,
268         &dev_attr_clock.attr,
269         &dev_attr_dvfs_enable.attr,
270         &dev_attr_utilisation.attr,
271         &dev_attr_error_count.attr,
272         NULL,
273 };
274
275 static const struct attribute_group mali_attr_group = {
276         .attrs  = mali_sysfs_entries,
277 };
278
279 /**
280  * 创建 sysfs_nodes_of_platform_dependent_part.
281  */
282 static int mali_create_sysfs(struct device *dev)
283 {
284         int ret;
285
286         ret = sysfs_create_group(&dev->kobj, &mali_attr_group);
287         if (ret)
288                 dev_err(dev, "create sysfs group error, %d\n", ret);
289
290         return ret;
291 }
292
293 static void mali_remove_sysfs(struct device *dev)
294 {
295         sysfs_remove_group(&dev->kobj, &mali_attr_group);
296 }
297
298 /*---------------------------------------------------------------------------*/
299
300 /**
301  * 对 platform_device_of_mali_gpu,
302  * 完成仅和 platform_dependent_part 有关的初始化.
303  */
304 _mali_osk_errcode_t mali_platform_init(struct platform_device *pdev)
305 {
306         struct device *dev = &pdev->dev;
307         /* mali_driver_private_data. */
308         struct mali_platform_drv_data *mali_drv_data;
309         int ret;
310
311         mali_drv_data = devm_kzalloc(dev, sizeof(*mali_drv_data), GFP_KERNEL);
312         if (!mali_drv_data) {
313                 dev_err(dev, "no mem\n");
314                 return _MALI_OSK_ERR_NOMEM;
315         }
316
317         dev_set_drvdata(dev, mali_drv_data);
318
319         mali_drv_data->dev = dev;
320
321         mali_dev = dev;
322
323         ret = mali_clock_init(dev);
324         if (ret)
325                 goto err_init;
326
327         ret = mali_dvfs_init(dev);
328         if (ret)
329                 goto err_init;
330
331         ret = mali_create_sysfs(dev);
332         if (ret)
333                 goto term_clk;
334
335         mali_drv_data->clock_set_lock =
336                 _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
337                                      _MALI_OSK_LOCK_ORDER_UTILIZATION);
338         mali_core_scaling_enable = 1;
339
340         return 0;
341 term_clk:
342         mali_clock_term(dev);
343 err_init:
344         return _MALI_OSK_ERR_FAULT;
345 }
346
347 _mali_osk_errcode_t mali_platform_deinit(struct platform_device *pdev)
348 {
349         struct device *dev = &pdev->dev;
350         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
351
352         mali_remove_sysfs(dev);
353
354         mali_core_scaling_term();
355         mali_clock_term(dev);
356         _mali_osk_mutex_term(drv_data->clock_set_lock);
357
358         return 0;
359 }
360
361 /*---------------------------------------------------------------------------*/
362
363 /**
364  * 对  gpu_power_domain(mali_power_domain), "上电, 开 clk" / "下电, 关 clk".
365  * @param bpower_off
366  *      true, 下电.
367  *      false, 对 gpu_power_domain 上电.
368  */
369 static _mali_osk_errcode_t mali_power_domain_control(bool bpower_off)
370 {
371         struct mali_platform_drv_data *drv_data = dev_get_drvdata(mali_dev);
372
373         /* 若要 上电, 则 ... */
374         if (!bpower_off) {
375                 if (!drv_data->power_state) {
376                         D("to ENABLE clk to gpu_dvfs_node.");
377                         dvfs_clk_prepare_enable(drv_data->clk);
378
379                         if (drv_data->pd) {
380                                 D("to power UP gpu_power_domain.");
381                                 clk_prepare_enable(drv_data->pd);
382                         }
383
384                         drv_data->power_state = true;
385                 }
386         } else {
387                 if (drv_data->power_state) {
388                         D("to DISABLE clk to gpu_dvfs_node.");
389                         dvfs_clk_disable_unprepare(drv_data->clk);
390
391                         if (drv_data->pd) {
392                                 D("to power DOWN gpu_power_domain.");
393                                 clk_disable_unprepare(drv_data->pd);
394                         }
395
396                         drv_data->power_state = false;
397                 }
398         }
399
400         return 0;
401 }
402
403 _mali_osk_errcode_t mali_platform_power_mode_change(
404                         enum mali_power_mode power_mode)
405 {
406         bool bpower_off;/* 下电. */
407
408         switch (power_mode) {
409         case MALI_POWER_MODE_ON:
410                 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_ON\r\n"));
411                 mali_dvfs_enable(mali_dev);
412                 bpower_off = false;
413                 break;
414
415         case MALI_POWER_MODE_LIGHT_SLEEP:
416                 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
417                 mali_dvfs_disable(mali_dev);
418                 /* 预置将下电. */
419                 bpower_off = true;
420                 break;
421
422         case MALI_POWER_MODE_DEEP_SLEEP:
423                 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
424                 mali_dvfs_disable(mali_dev);
425                 /* 预置将下电. */
426                 bpower_off = true;
427                 break;
428
429         default:
430                 MALI_DEBUG_PRINT(2,
431                                  ("power_mode(%d) not support\n", power_mode));
432                 return _MALI_OSK_ERR_INVALID_ARGS;
433         }
434
435         mali_power_domain_control(bpower_off);
436
437         return 0;
438 }
439
440 /*---------------------------------------------------------------------------*/
441
442 /**
443  * 将注册到 common_part 中的, 对 mali_utilization_event 的 handler,
444  * 即 common_part 会直接将 mali_utilization_event 通知回调到本函数.
445  */
446 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
447 {
448         if (data->utilization_pp > 256)
449                 return;
450
451         if (mali_core_scaling_enable)
452                 mali_core_scaling_update(data);
453
454         /* dev_dbg(mali_dev, "utilization:%d\r\n", data->utilization_pp); */
455
456         mali_dvfs_event(mali_dev, data->utilization_pp);
457 }