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