Merge tag 'lsk-v3.10-15.05-android' into develop-3.10
[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 for a default platform
14  */
15 #include <linux/workqueue.h>
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/gfp.h>
19 #include <linux/fs.h>
20 #include <linux/clk.h>
21 #include <linux/device.h>
22 #include <linux/regulator/driver.h>
23 #include <linux/miscdevice.h>
24 #include <asm/uaccess.h>
25 #include <linux/cpufreq.h>
26 #include <linux/of.h>
27
28 #include "mali_kernel_common.h"
29 #include "mali_osk.h"
30 #include "arm_core_scaling.h"
31 #include "mali_platform.h"
32
33
34 static int mali_core_scaling_enable;
35
36 u32 mali_group_error;
37
38 struct device *mali_dev;
39
40 int mali_set_level(struct device *dev, int level)
41 {
42         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
43         unsigned long freq;
44         int ret;
45         unsigned int current_level;
46
47         _mali_osk_mutex_wait(drv_data->clockSetlock);
48
49         current_level = drv_data->dvfs.current_level;
50         freq = drv_data->fv_info[level].freq;
51
52         if (level == current_level) {
53                 _mali_osk_mutex_signal(drv_data->clockSetlock);
54                 return 0;
55         }
56
57         ret = dvfs_clk_set_rate(drv_data->clk, freq);
58         if (ret) {
59                 _mali_osk_mutex_signal(drv_data->clockSetlock);
60                 return ret;
61         }
62
63         dev_dbg(dev, "set freq %lu\n", freq);
64
65         drv_data->dvfs.current_level = level;
66
67         _mali_osk_mutex_signal(drv_data->clockSetlock);
68
69         return 0;
70 }
71
72 static int mali_clock_init(struct device *dev)
73 {
74         int ret;
75
76         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
77
78         drv_data->pd = devm_clk_get(dev, "pd_gpu");
79         if (IS_ERR(drv_data->pd)) {
80                 ret = PTR_ERR(drv_data->pd);
81                 dev_err(dev, "get pd_clk failed, %d\n", ret);
82                 return ret;
83         }
84
85         ret = clk_prepare_enable(drv_data->pd);
86         if (ret) {
87                 dev_err(dev, "prepare pd_clk failed, %d\n", ret);
88                 return ret;
89         }
90
91         drv_data->clk = clk_get_dvfs_node("clk_gpu");
92         if (IS_ERR(drv_data->clk)) {
93                 ret = PTR_ERR(drv_data->clk);
94                 dev_err(dev, "prepare clk gpu failed, %d\n", ret);
95                 return ret;
96         }
97
98         ret = dvfs_clk_prepare_enable(drv_data->clk);
99         if (ret) {
100                 dev_err(dev, "prepare clk failed, %d\n", ret);
101                 return ret;
102         }
103
104         drv_data->power_state = true;
105
106         return 0;
107 }
108
109 static void mali_clock_term(struct device *dev)
110 {
111         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
112
113         dvfs_clk_disable_unprepare(drv_data->clk);
114         clk_disable_unprepare(drv_data->pd);
115         drv_data->power_state = false;
116 }
117
118 static ssize_t show_available_frequencies(struct device *dev,
119                                           struct device_attribute *attr,
120                                           char *buf)
121 {
122         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
123         ssize_t ret = 0;
124         u32 i;
125
126         for (i = 0; i < drv_data->fv_info_length; i++)
127                 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%lu\n",
128                                  drv_data->fv_info[i].freq);
129
130         return ret;
131 }
132
133 static ssize_t show_clock(struct device *dev,
134                           struct device_attribute *attr, char *buf)
135 {
136         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
137
138         return scnprintf(buf, PAGE_SIZE, "%lu\n", dvfs_clk_get_rate(drv_data->clk));
139 }
140
141 static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
142                          const char *buf, size_t count)
143 {       
144         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
145         unsigned long freq;
146         ssize_t ret;
147         u32 level;
148
149         ret = kstrtoul(buf, 10, &freq);
150         if (ret)
151                 return ret;
152
153         for (level = drv_data->fv_info_length - 1; level > 0; level--) {
154                 unsigned long tmp  = drv_data->fv_info[level].freq;
155                 if (tmp <= freq)
156                         break;
157         }
158
159         dev_info(dev, "Using fv_info table %d: for %lu Hz\n", level, freq);
160
161         ret = mali_set_level(dev, level);
162         if (ret)
163                 return ret;
164
165         return count;
166 }
167
168 static ssize_t show_dvfs_enable(struct device *dev,
169                                 struct device_attribute *attr, char *buf)
170 {
171         return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_is_enabled(dev));
172 }
173
174 static ssize_t set_dvfs_enable(struct device *dev,
175                                 struct device_attribute *attr, const char *buf,
176                                 size_t count)
177 {
178         unsigned long enable;
179         ssize_t ret;
180
181         ret = kstrtoul(buf, 0, &enable);
182         if (ret)
183                 return ret;
184
185         if (enable == 1)
186                 mali_dvfs_enable(dev);
187         else if (enable == 0)
188                 mali_dvfs_disable(dev);
189         else
190                 return -EINVAL;
191
192         return count;
193 }
194
195 static ssize_t show_utilisation(struct device *dev,
196                                 struct device_attribute *attr, char *buf)
197 {
198         return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_utilisation(dev));
199 }
200
201 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
202 {
203         return sprintf(buf, "%d\n", mali_group_error);
204 }
205
206 DEVICE_ATTR(available_frequencies, S_IRUGO, show_available_frequencies, NULL);
207 DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
208 DEVICE_ATTR(dvfs_enable, S_IRUGO | S_IWUSR, show_dvfs_enable, set_dvfs_enable);
209 DEVICE_ATTR(utilisation, S_IRUGO, show_utilisation, NULL);
210 DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
211
212 static struct attribute *mali_sysfs_entries[] = {
213         &dev_attr_available_frequencies.attr,
214         &dev_attr_clock.attr,
215         &dev_attr_dvfs_enable.attr,
216         &dev_attr_utilisation.attr,
217         &dev_attr_error_count.attr,
218         NULL,
219 };
220
221 static const struct attribute_group mali_attr_group = {
222         .attrs  = mali_sysfs_entries,
223 };
224
225 static int mali_create_sysfs(struct device *dev)
226 {
227         int ret;
228
229         ret = sysfs_create_group(&dev->kobj, &mali_attr_group);
230         if (ret)
231                 dev_err(dev, "create sysfs group error, %d\n", ret);
232
233         return ret;
234 }
235
236 void mali_remove_sysfs(struct device *dev)
237 {
238         sysfs_remove_group(&dev->kobj, &mali_attr_group);
239 }
240
241 _mali_osk_errcode_t mali_platform_init(struct platform_device *pdev)
242 {
243         struct device *dev = &pdev->dev;
244         struct mali_platform_drv_data *mali_drv_data;
245         int ret;
246
247         mali_drv_data = devm_kzalloc(dev, sizeof(*mali_drv_data), GFP_KERNEL);
248         if (!mali_drv_data) {
249                 dev_err(dev, "no mem\n");
250                 return _MALI_OSK_ERR_NOMEM;
251         }
252
253         dev_set_drvdata(dev, mali_drv_data);
254
255         mali_drv_data->dev = dev;
256
257         mali_dev = dev;
258
259         ret = mali_clock_init(dev);
260         if (ret)
261                 goto err_init;
262
263         ret = mali_dvfs_init(dev);
264         if (ret)
265                 goto err_init;
266
267         ret = mali_create_sysfs(dev);
268         if (ret)
269                 goto term_clk;
270
271         mali_drv_data->clockSetlock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
272                                 _MALI_OSK_LOCK_ORDER_UTILIZATION);
273         mali_core_scaling_enable = 1;
274
275         return 0;
276 term_clk:
277         mali_clock_term(dev);
278 err_init:
279         return _MALI_OSK_ERR_FAULT;
280 }
281
282 _mali_osk_errcode_t mali_platform_deinit(struct platform_device *pdev)
283 {
284         struct device *dev = &pdev->dev;
285         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
286
287         mali_core_scaling_term();
288         mali_clock_term(dev);
289         _mali_osk_mutex_term(drv_data->clockSetlock);
290
291         return 0;
292 }
293
294 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
295 {
296         struct mali_platform_drv_data *drv_data = dev_get_drvdata(mali_dev);
297
298         if (bpower_off == 0) {
299                 if (!drv_data->power_state) {
300                         dvfs_clk_prepare_enable(drv_data->clk);
301                         clk_prepare_enable(drv_data->pd);
302                         drv_data->power_state = true;
303                 }
304         } else if (bpower_off == 1) {
305                 if (drv_data->power_state) {
306                         dvfs_clk_disable_unprepare(drv_data->clk);
307                         clk_disable_unprepare(drv_data->pd);
308                         drv_data->power_state = false;
309                 }
310         }
311
312         return 0;
313 }
314
315 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
316 {
317         switch(power_mode) {
318                 case MALI_POWER_MODE_ON:
319                         MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_ON\r\n"));
320                         mali_power_domain_control(MALI_POWER_MODE_ON);
321                         break;
322                 case MALI_POWER_MODE_LIGHT_SLEEP:
323                         MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
324                         mali_power_domain_control(MALI_POWER_MODE_LIGHT_SLEEP);
325                         break;
326                 case MALI_POWER_MODE_DEEP_SLEEP:
327                         MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
328                         mali_power_domain_control(MALI_POWER_MODE_DEEP_SLEEP);
329                         break;
330                 default:
331                         MALI_DEBUG_PRINT(2, ("mali_platform_power_mode_change:power_mode(%d) not support \r\n",
332                                          power_mode));
333         }
334         
335     return 0;
336 }
337 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
338 {
339         if(data->utilization_pp > 256)
340                 return;
341
342         if (mali_core_scaling_enable)
343                 mali_core_scaling_update(data);
344
345         // dev_dbg(mali_dev, "utilization:%d\r\n", data->utilization_pp);
346
347         mali_dvfs_event(mali_dev, data->utilization_pp);
348 }