MALI: utgard: RK: fix compile errors under arm64
[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  * 是否使能 core_scaling 机制.
40  * .DP : core_scaling : 根据当前 mali_utilization_data,
41  *                      配置 mali_gpu 中具体使用的 pp_core 的个数.
42  */
43 static int mali_core_scaling_enable;
44
45 u32 mali_group_error;
46
47 /*
48  * anchor_of_device_of_mali_gpu.
49  */
50 static struct device *mali_dev;
51
52 /*
53  * 设置 current_dvfs_level.
54  *
55  * @param level
56  *      待设置为 current 的 dvfs_level 实例,
57  *      在 dvfs_level_list 中的 index,
58  *      即 index_of_new_current_level.
59  *
60  * @return
61  *      0, 成功.
62  *      其他 value, 失败.
63  */
64 int mali_set_level(struct device *dev, int level)
65 {
66         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
67         /* gpu_clk_freq_of_new_current_level. */
68         unsigned long freq;
69         int ret;
70         /* index_of_old_current_level. */
71         unsigned int current_level;
72
73         _mali_osk_mutex_wait(drv_data->clock_set_lock);
74
75         current_level = drv_data->dvfs.current_level;
76         freq = drv_data->fv_info[level].freq;
77
78         if (level == current_level) {
79                 D("we are already in the target level, to exit.");
80                 _mali_osk_mutex_signal(drv_data->clock_set_lock);
81                 return 0;
82         }
83
84         /* .KP : 调用 dvfs_module 的接口, 将 cpu_clk 设置为 'freq'. */
85         ret = dvfs_clk_set_rate(drv_data->clk, freq);
86         if (ret) {
87                 _mali_osk_mutex_signal(drv_data->clock_set_lock);
88                 return ret;
89         }
90
91         D("have set gpu_clk to %lu of new_level %d, the old_level is %d.",
92           freq,
93           level,
94           current_level);
95         /* update index_of_current_dvfs_level. */
96         drv_data->dvfs.current_level = level;
97
98         _mali_osk_mutex_signal(drv_data->clock_set_lock);
99
100         return 0;
101 }
102
103 /*
104  * 初始化 gpu_dvfs_node 和 gpu_power_domain.
105  */
106 static int mali_clock_init(struct device *dev)
107 {
108         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
109         int err;
110         unsigned long rate = 200 * 1000 * 1000;
111
112         D("to get clk_mali.");
113         drv_data->clock = clk_get(drv_data->dev, "clk_mali");
114         if (IS_ERR_OR_NULL(drv_data->clock)) {
115                 err = PTR_ERR(drv_data->clock);
116
117                 drv_data->clock = NULL;
118                 E("fail to get clk_mali, err : %d", err);
119                 return err;
120         }
121         D("to preare and enable clk_mali.");
122         err = clk_prepare_enable(drv_data->clock);
123         if (err) {
124                 E("Failed to prepare and enable clock (%d)\n", err);
125                 return err;
126         }
127         I("to set freq_of_clk_gpu to %lu.", rate);
128         err = clk_set_rate(drv_data->clock, rate);
129         if (err) {
130                 E("Failed to set clock.");
131                 return err;
132         }
133
134         D("success to init clk_mali.");
135         return 0;
136 }
137
138 static void mali_clock_term(struct device *dev)
139 {
140 }
141
142 /*---------------------------------------------------------------------------*/
143
144 static ssize_t show_available_frequencies(struct device *dev,
145                                           struct device_attribute *attr,
146                                           char *buf)
147 {
148         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
149         ssize_t ret = 0;
150         u32 i;
151
152         for (i = 0; i < drv_data->fv_info_length; i++)
153                 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%lu\n",
154                                  drv_data->fv_info[i].freq);
155
156         return ret;
157 }
158
159 static ssize_t show_clock(struct device *dev,
160                           struct device_attribute *attr, char *buf)
161 {
162         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
163
164         return scnprintf(buf,
165                          PAGE_SIZE,
166                          "%lu\n",
167                          dvfs_clk_get_rate(drv_data->clk));
168 }
169
170 static ssize_t set_clock(struct device *dev,
171                          struct device_attribute *attr,
172                          const char *buf, size_t count)
173 {
174         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
175         unsigned long freq;
176         ssize_t ret;
177         u32 level;
178
179         ret = kstrtoul(buf, 10, &freq);
180         if (ret)
181                 return ret;
182
183         for (level = drv_data->fv_info_length - 1; level > 0; level--) {
184                 unsigned long tmp  = drv_data->fv_info[level].freq;
185
186                 if (tmp <= freq)
187                         break;
188         }
189
190         dev_info(dev, "Using fv_info table %d: for %lu Hz\n", level, freq);
191
192         ret = mali_set_level(dev, level);
193         if (ret)
194                 return ret;
195
196         return count;
197 }
198
199 static ssize_t show_dvfs_enable(struct device *dev,
200                                 struct device_attribute *attr,
201                                 char *buf)
202 {
203         return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_is_enabled(dev));
204 }
205
206 static ssize_t set_dvfs_enable(struct device *dev,
207                                struct device_attribute *attr,
208                                const char *buf,
209                                size_t count)
210 {
211         unsigned long enable;
212         ssize_t ret;
213
214         ret = kstrtoul(buf, 0, &enable);
215         if (ret)
216                 return ret;
217
218         if (enable == 1)
219                 mali_dvfs_enable(dev);
220         else if (enable == 0)
221                 mali_dvfs_disable(dev);
222         else
223                 return -EINVAL;
224
225         return count;
226 }
227
228 static ssize_t show_utilisation(struct device *dev,
229                                 struct device_attribute *attr,
230                                 char *buf)
231 {
232         return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_utilisation(dev));
233 }
234
235 static ssize_t error_count_show(struct device *dev,
236                                 struct device_attribute *attr,
237                                 char *buf)
238 {
239         return sprintf(buf, "%d\n", mali_group_error);
240 }
241
242 static DEVICE_ATTR(available_frequencies,
243                    S_IRUGO,
244                    show_available_frequencies,
245                    NULL);
246 static DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
247 static DEVICE_ATTR(dvfs_enable,
248                    S_IRUGO | S_IWUSR,
249                    show_dvfs_enable,
250                    set_dvfs_enable);
251 static DEVICE_ATTR(utilisation, S_IRUGO, show_utilisation, NULL);
252 static DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
253
254 static struct attribute *mali_sysfs_entries[] = {
255         &dev_attr_available_frequencies.attr,
256         &dev_attr_clock.attr,
257         &dev_attr_dvfs_enable.attr,
258         &dev_attr_utilisation.attr,
259         &dev_attr_error_count.attr,
260         NULL,
261 };
262
263 static const struct attribute_group mali_attr_group = {
264         .attrs  = mali_sysfs_entries,
265 };
266
267 /*
268  * 创建 sysfs_nodes_of_platform_dependent_part.
269  */
270 static int mali_create_sysfs(struct device *dev)
271 {
272         int ret;
273
274         ret = sysfs_create_group(&dev->kobj, &mali_attr_group);
275         if (ret)
276                 dev_err(dev, "create sysfs group error, %d\n", ret);
277
278         return ret;
279 }
280
281 static void mali_remove_sysfs(struct device *dev)
282 {
283         sysfs_remove_group(&dev->kobj, &mali_attr_group);
284 }
285
286 /*---------------------------------------------------------------------------*/
287
288 /*
289  * 对 platform_device_of_mali_gpu,
290  * 完成仅和 platform_dependent_part 有关的初始化.
291  */
292 _mali_osk_errcode_t mali_platform_init(struct platform_device *pdev)
293 {
294         struct device *dev = &pdev->dev;
295         /* mali_driver_private_data. */
296         struct mali_platform_drv_data *mali_drv_data;
297         int ret;
298
299         mali_drv_data = devm_kzalloc(dev, sizeof(*mali_drv_data), GFP_KERNEL);
300         if (!mali_drv_data)
301                 return _MALI_OSK_ERR_NOMEM;
302
303         dev_set_drvdata(dev, mali_drv_data);
304
305         mali_drv_data->dev = dev;
306
307         mali_dev = dev;
308
309         D("to c all mali_clock_init.");
310         ret = mali_clock_init(dev);
311         if (ret)
312                 goto err_init;
313
314         D("to call mali_dvfs_init.");
315         ret = mali_dvfs_init(dev);
316         if (ret)
317                 goto err_init;
318
319         D("to call mali_create_sysfs.");
320         ret = mali_create_sysfs(dev);
321         if (ret)
322                 goto term_clk;
323
324         mali_drv_data->clock_set_lock =
325                 _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
326                                      _MALI_OSK_LOCK_ORDER_UTILIZATION);
327         mali_core_scaling_enable = 1;
328
329         return 0;
330 term_clk:
331         mali_clock_term(dev);
332 err_init:
333         return _MALI_OSK_ERR_FAULT;
334 }
335
336 _mali_osk_errcode_t mali_platform_deinit(struct platform_device *pdev)
337 {
338         struct device *dev = &pdev->dev;
339         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
340
341         mali_remove_sysfs(dev);
342
343         mali_core_scaling_term();
344         mali_clock_term(dev);
345         _mali_osk_mutex_term(drv_data->clock_set_lock);
346
347         return 0;
348 }
349
350 /*---------------------------------------------------------------------------*/
351
352 /*
353  * 对  gpu_power_domain(mali_power_domain),
354  * "上电, 开 clk" / "下电, 关 clk".
355  * @param bpower_off
356  *      true, 下电.
357  *      false, 对 gpu_power_domain 上电.
358  */
359  #if 0
360 static _mali_osk_errcode_t mali_power_domain_control(bool bpower_off)
361 {
362         struct mali_platform_drv_data *drv_data = dev_get_drvdata(mali_dev);
363
364         /* 若要 上电, 则 ... */
365         if (!bpower_off) {
366                 if (!drv_data->power_state) {
367                         D("to ENABLE clk to gpu_dvfs_node.");
368                         dvfs_clk_prepare_enable(drv_data->clk);
369
370                         if (drv_data->pd) {
371                                 D("to power UP gpu_power_domain.");
372                                 clk_prepare_enable(drv_data->pd);
373                         }
374
375                         drv_data->power_state = true;
376                 }
377         } else {
378                 if (drv_data->power_state) {
379                         D("to DISABLE clk to gpu_dvfs_node.");
380                         dvfs_clk_disable_unprepare(drv_data->clk);
381
382                         if (drv_data->pd) {
383                                 D("to power DOWN gpu_power_domain.");
384                                 clk_disable_unprepare(drv_data->pd);
385                         }
386
387                         drv_data->power_state = false;
388                 }
389         }
390
391         return 0;
392 }
393 #endif
394 _mali_osk_errcode_t mali_platform_power_mode_change(
395                         enum mali_power_mode power_mode)
396 {
397         return 0;
398 }
399
400 /*---------------------------------------------------------------------------*/
401
402 /*
403  * 将注册到 common_part 中的, 对 mali_utilization_event 的 handler,
404  * 即 common_part 会直接将 mali_utilization_event 通知回调到本函数.
405  */
406 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
407 {
408         if (data->utilization_pp > 256)
409                 return;
410
411         if (mali_core_scaling_enable)
412                 mali_core_scaling_update(data);
413
414         /* dev_dbg(mali_dev, "utilization:%d\r\n", data->utilization_pp); */
415
416         mali_dvfs_event(mali_dev, data->utilization_pp);
417 }