tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / platform / exynos4415 / exynos4_pmm.c
1 /* drivers/gpu/mali400/mali/platform/exynos4415/exynos4_pmm.c
2  *
3  * Copyright 2011 by S.LSI. Samsung Electronics Inc.
4  * San#24, Nongseo-Dong, Giheung-Gu, Yongin, Korea
5  *
6  * Samsung SoC Mali400 DVFS driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software FoundatIon.
11  */
12
13 /**
14  * @file exynos4_pmm.c
15  * Platform specific Mali driver functions for the exynos 4XXX based platforms
16  */
17 #include "mali_kernel_common.h"
18 #include "mali_osk.h"
19 #include "exynos4_pmm.h"
20
21 #include <linux/clk.h>
22 #include <linux/err.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/regulator/consumer.h>
26
27 #if defined(CONFIG_MALI400_PROFILING)
28 #include "mali_osk_profiling.h"
29 #endif
30
31 /* lock/unlock CPU freq by Mali */
32 #include <linux/types.h>
33 #include <mach/cpufreq.h>
34 #include <mach/regs-clock-exynos4415.h>
35 #include <mach/asv-exynos.h>
36 #ifdef CONFIG_CPU_FREQ
37 #ifndef CONFIG_SOC_EXYNOS4415
38 #define EXYNOS4_ASV_ENABLED
39 #endif
40 #endif
41
42 #ifdef CONFIG_MALI_DVFS_FULL_LEVEL
43 #define MALI_DVFS_FULL_LEVEL
44 #endif
45
46 /* Some defines changed names in later Odroid-A kernels. Make sure it works for both. */
47 #ifndef S5P_G3D_CONFIGURATION
48 #define S5P_G3D_CONFIGURATION EXYNOS4_G3D_CONFIGURATION
49 #endif
50 #ifndef S5P_G3D_STATUS
51 #define S5P_G3D_STATUS (EXYNOS4_G3D_CONFIGURATION + 0x4)
52 #endif
53 #ifndef S5P_INT_LOCAL_PWR_EN
54 #define S5P_INT_LOCAL_PWR_EN EXYNOS_INT_LOCAL_PWR_EN
55 #endif
56
57 #include <asm/io.h>
58 #include <mach/regs-pmu.h>
59 #include <linux/workqueue.h>
60
61 #ifdef MALI_DVFS_FULL_LEVEL
62 #define MALI_DVFS_STEPS 7
63 #else
64 #define MALI_DVFS_STEPS 4
65 #endif
66
67 #define MALI_DVFS_WATING 10 /* msec */
68 #define MALI_DVFS_DEFAULT_STEP 1
69 #define PD_G3D_LOCK_FLAG 2
70
71 #define MALI_DVFS_CLK_DEBUG 0
72 #define CPUFREQ_LOCK_DURING_440 1
73
74 static int bMaliDvfsRun = 0;
75
76 typedef struct mali_dvfs_tableTag{
77         unsigned int clock;
78         unsigned int freq;
79         unsigned int vol;
80         unsigned int downthreshold;
81         unsigned int upthreshold;
82 }mali_dvfs_table;
83
84 typedef struct mali_dvfs_statusTag{
85         unsigned int currentStep;
86         mali_dvfs_table * pCurrentDvfs;
87
88 } mali_dvfs_status_t;
89
90 /*dvfs status*/
91 mali_dvfs_status_t maliDvfsStatus;
92 int mali_dvfs_control;
93
94 typedef struct mali_runtime_resumeTag{
95                 int clk;
96                 int vol;
97                 unsigned int step;
98 }mali_runtime_resume_table;
99
100 mali_runtime_resume_table mali_runtime_resume = {266, 875000, 1};
101
102 #ifdef MALI_DVFS_FULL_LEVEL
103 /*dvfs table updated on 131203*/
104 mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={
105         /*step 0*/{160, 1000000,  850000,  0,  60},
106         /*step 1*/{266, 1000000,  875000, 52,  70},
107         /*step 2*/{350, 1000000,  950000, 62,  80},
108         /*step 3*/{440, 1000000, 1025000, 75,  80},
109         /*step 4*/{550, 1000000, 1125000, 85,  90},
110         /*step 5*/{667, 1000000, 1225000, 85,  95},
111         /*step 6*/{733, 1000000, 1300000, 95, 100} };
112 #else
113 /*dvfs table updated on 131203*/
114 mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={
115         /*step 0*/{160, 1000000,  850000,  0,  70},
116         /*step 1*/{266, 1000000,  875000, 62,  90},
117         /*step 2*/{350, 1000000,  950000, 85,  90},
118         /*step 3*/{440, 1000000, 1025000, 85, 100} };
119 #endif
120
121 /* Exynos4415 */
122 int mali_gpu_clk = 266;
123 int mali_gpu_vol = 875000;
124 #ifdef MALI_DVFS_FULL_LEVEL
125 char *mali_freq_table = "733 667 550 440 350 266 160";
126 #else
127 char *mali_freq_table = "440 350 266 160";
128 #endif
129
130 #define EXTXTALCLK_NAME  "ext_xtal"
131 #define VPLLSRCCLK_NAME  "vpll_src"
132 #define FOUTVPLLCLK_NAME "fout_vpll"
133 #define SCLKEPLLCLK_NAME "sclk_epll"
134 #define SCLVPLLCLK_NAME  "sclk_vpll"
135 #define GPUMOUT1CLK_NAME "mout_g3d1"
136 #define GPUMOUT0CLK_NAME "mout_g3d0"
137 #define GPUCLK_NAME      "sclk_g3d"
138 #define CLK_DIV_STAT_G3D 0x1003C62C
139 #define CLK_DESC         "clk-divider-status"
140
141 static struct clk *ext_xtal_clock = NULL;
142 static struct clk *vpll_src_clock = NULL;
143 static struct clk *fout_vpll_clock = NULL;
144 static struct clk *sclk_epll_clock = NULL;
145 static struct clk *sclk_vpll_clock = NULL;
146 static struct clk *mali_parent_clock = NULL;
147 static struct clk *mali_clock = NULL;
148
149 static unsigned int GPU_MHZ     = 1000000;
150 static unsigned int const GPU_ASV_VOLT = 1000;
151 static int nPowermode;
152 static atomic_t clk_active;
153
154 mali_io_address clk_register_map = 0;
155
156 /* export GPU frequency as a read-only parameter so that it can be read in /sys */
157 module_param(mali_gpu_clk, int, S_IRUSR | S_IRGRP | S_IROTH);
158 module_param(mali_gpu_vol, int, S_IRUSR | S_IRGRP | S_IROTH);
159 module_param(mali_freq_table, charp, S_IRUSR | S_IRGRP | S_IROTH);
160 #ifdef CONFIG_MALI_DVFS
161 module_param(mali_dvfs_control, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP| S_IROTH); /* rw-rw-r-- */
162 MODULE_PARM_DESC(mali_dvfs_control, "Mali Current DVFS");
163 DEVICE_ATTR(time_in_state, S_IRUGO|S_IWUSR, show_time_in_state, set_time_in_state);
164 MODULE_PARM_DESC(time_in_state, "Time-in-state of Mali DVFS");
165 #endif
166 MODULE_PARM_DESC(mali_gpu_clk, "Mali Current Clock");
167 MODULE_PARM_DESC(mali_gpu_vol, "Mali Current Voltage");
168 MODULE_PARM_DESC(mali_freq_table, "Mali frequency table");
169
170 #ifdef CONFIG_REGULATOR
171 struct regulator *g3d_regulator = NULL;
172 #endif
173 atomic_t mali_cpufreq_lock;
174
175 /* DVFS */
176 #ifdef CONFIG_MALI_DVFS
177 static unsigned int mali_dvfs_utilization = 255;
178 static void update_time_in_state(int level);
179 u64 mali_dvfs_time[MALI_DVFS_STEPS];
180 #endif
181
182 static void mali_dvfs_work_handler(struct work_struct *w);
183 static struct workqueue_struct *mali_dvfs_wq = 0;
184 _mali_osk_mutex_t *mali_dvfs_lock;
185 int mali_runtime_resumed = -1;
186 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_work_handler);
187
188 int cpufreq_lock_by_mali(unsigned int freq)
189 {
190 #ifdef CONFIG_EXYNOS4_CPUFREQ
191         unsigned int level;
192
193         if (atomic_read(&mali_cpufreq_lock) == 0) {
194                 if (exynos_cpufreq_get_level(freq * 1000, &level)) {
195                         printk(KERN_ERR "Mali: failed to get cpufreq level for %dMHz", freq);
196                         return -EINVAL;
197                 }
198
199                 if (exynos_cpufreq_lock(DVFS_LOCK_ID_G3D, level)) {
200                         printk(KERN_ERR "Mali: failed to cpufreq lock for L%d", level);
201                         return -EINVAL;
202                 }
203
204                 atomic_set(&mali_cpufreq_lock, 1);
205                 printk(KERN_DEBUG "Mali: cpufreq locked on <%d>%dMHz\n", level, freq);
206         }
207 #endif
208         return 0;
209 }
210
211 void cpufreq_unlock_by_mali(void)
212 {
213 #ifdef CONFIG_EXYNOS4_CPUFREQ
214         if (atomic_read(&mali_cpufreq_lock) == 1) {
215                 exynos_cpufreq_lock_free(DVFS_LOCK_ID_G3D);
216                 atomic_set(&mali_cpufreq_lock, 0);
217                 printk(KERN_DEBUG "Mali: cpufreq locked off\n");
218         }
219 #endif
220 }
221
222 #ifdef CONFIG_REGULATOR
223 void mali_regulator_disable(void)
224 {
225         if(IS_ERR_OR_NULL(g3d_regulator))
226         {
227                 MALI_DEBUG_PRINT(1, ("error on mali_regulator_disable : g3d_regulator is null\n"));
228                 return;
229         }
230         regulator_disable(g3d_regulator);
231 }
232
233 void mali_regulator_enable(void)
234 {
235         if(IS_ERR_OR_NULL(g3d_regulator))
236         {
237                 MALI_DEBUG_PRINT(1, ("error on mali_regulator_enable : g3d_regulator is null\n"));
238                 return;
239         }
240         regulator_enable(g3d_regulator);
241 }
242
243 void mali_regulator_set_voltage(int min_uV, int max_uV)
244 {
245         _mali_osk_mutex_wait(mali_dvfs_lock);
246         if(IS_ERR_OR_NULL(g3d_regulator))
247         {
248                 MALI_DEBUG_PRINT(1, ("error on mali_regulator_set_voltage : g3d_regulator is null\n"));
249                 _mali_osk_mutex_signal(mali_dvfs_lock);
250                 return;
251         }
252         MALI_DEBUG_PRINT(1, ("= regulator_set_voltage: %d, %d \n", min_uV, max_uV));
253         regulator_set_voltage(g3d_regulator, min_uV, max_uV);
254         mali_gpu_vol = regulator_get_voltage(g3d_regulator);
255         MALI_DEBUG_PRINT(1, ("Mali voltage: %d\n", mali_gpu_vol));
256         _mali_osk_mutex_signal(mali_dvfs_lock);
257 }
258 #endif
259
260 static unsigned int get_mali_dvfs_status(void)
261 {
262         return maliDvfsStatus.currentStep;
263 }
264
265 mali_bool mali_clk_get(void)
266 {
267         if (ext_xtal_clock == NULL)     {
268                 ext_xtal_clock = clk_get(NULL, EXTXTALCLK_NAME);
269                 if (IS_ERR(ext_xtal_clock)) {
270                         MALI_PRINT(("MALI Error : failed to get source ext_xtal_clock\n"));
271                         return MALI_FALSE;
272                 }
273         }
274
275         if (vpll_src_clock == NULL)     {
276                 vpll_src_clock = clk_get(NULL, VPLLSRCCLK_NAME);
277                 if (IS_ERR(vpll_src_clock)) {
278                         MALI_PRINT(("MALI Error : failed to get source vpll_src_clock\n"));
279                         return MALI_FALSE;
280                 }
281         }
282
283         if (fout_vpll_clock == NULL) {
284                 fout_vpll_clock = clk_get(NULL, FOUTVPLLCLK_NAME);
285                 if (IS_ERR(fout_vpll_clock)) {
286                         MALI_PRINT(("MALI Error : failed to get source fout_vpll_clock\n"));
287                         return MALI_FALSE;
288                 }
289         }
290
291         if (sclk_epll_clock == NULL) {
292                 sclk_epll_clock = clk_get(NULL, SCLKEPLLCLK_NAME);
293                 if (IS_ERR(fout_vpll_clock)) {
294                         MALI_PRINT(("MALI Error : failed to get source sclk_epll_clock\n"));
295                         return MALI_FALSE;
296                 }
297         }
298
299         if (sclk_vpll_clock == NULL) {
300                 sclk_vpll_clock = clk_get(NULL, SCLVPLLCLK_NAME);
301                 if (IS_ERR(sclk_vpll_clock)) {
302                         MALI_PRINT(("MALI Error : failed to get source sclk_vpll_clock\n"));
303                         return MALI_FALSE;
304                 }
305         }
306
307         if (mali_parent_clock == NULL) {
308                 mali_parent_clock = clk_get(NULL, GPUMOUT1CLK_NAME);
309                 if (IS_ERR(mali_parent_clock)) {
310                         MALI_PRINT(("MALI Error : failed to get source mali parent clock\n"));
311                         return MALI_FALSE;
312                 }
313         }
314
315         /* mali clock get always. */
316         if (mali_clock == NULL) {
317                 mali_clock = clk_get(NULL, GPUCLK_NAME);
318                 if (IS_ERR(mali_clock)) {
319                         MALI_PRINT(("MALI Error : failed to get source mali clock\n"));
320                         return MALI_FALSE;
321                 }
322         }
323
324         return MALI_TRUE;
325 }
326
327 void mali_clk_put(mali_bool binc_mali_clock)
328 {
329         if (mali_parent_clock)
330         {
331                 clk_put(mali_parent_clock);
332                 mali_parent_clock = NULL;
333         }
334
335         if (sclk_vpll_clock)
336         {
337                 clk_put(sclk_vpll_clock);
338                 sclk_vpll_clock = NULL;
339         }
340
341         if (binc_mali_clock && fout_vpll_clock)
342         {
343                 clk_put(fout_vpll_clock);
344                 fout_vpll_clock = NULL;
345         }
346
347         if (sclk_epll_clock)
348         {
349                 clk_put(sclk_epll_clock);
350                 sclk_epll_clock = NULL;
351         }
352
353         if (vpll_src_clock)
354         {
355                 clk_put(vpll_src_clock);
356                 vpll_src_clock = NULL;
357         }
358
359         if (ext_xtal_clock)
360         {
361                 clk_put(ext_xtal_clock);
362                 ext_xtal_clock = NULL;
363         }
364
365         if (binc_mali_clock && mali_clock)
366         {
367                 clk_put(mali_clock);
368                 mali_clock = NULL;
369         }
370 }
371
372 void mali_clk_set_rate(unsigned int clk, unsigned int mhz)
373 {
374         int err;
375         unsigned int read_val;
376         unsigned long rate = (unsigned long)clk * (unsigned long)mhz;
377         unsigned long CurRate = 0;
378
379         _mali_osk_mutex_wait(mali_dvfs_lock);
380         MALI_DEBUG_PRINT(3, ("Mali platform: Setting frequency to %d mhz\n", clk));
381
382         if (mali_clk_get() == MALI_FALSE) {
383                 _mali_osk_mutex_signal(mali_dvfs_lock);
384                 return;
385         }
386
387         CurRate = clk_get_rate(mali_clock);
388
389         if (CurRate == 0) {
390                 _mali_osk_mutex_signal(mali_dvfs_lock);
391                 MALI_PRINT_ERROR(("clk_get_rate[mali_clock] is 0 - return\n"));
392                 return;
393         }
394
395         err = clk_set_rate(mali_clock, CurRate / 4);
396
397         if (err > 0)
398                 MALI_PRINT_ERROR(("Failed to set Mali clock before change PLL: %d\n", err));
399
400         err = clk_set_parent(mali_parent_clock, sclk_epll_clock);
401
402         if (err)
403                 MALI_PRINT_ERROR(("mali_parent set parent to sclk_epll failed\n"));
404
405         do {
406                 cpu_relax();
407                 read_val = __raw_readl(EXYNOS4415_CLKMUX_STAT_G3D0);
408         } while (((read_val >> 4) & 0x7) != 0x1);
409
410         MALI_DEBUG_PRINT(3, ("Mali platform: set to EPLL EXYNOS4415_CLKMUX_STAT_G3D0: 0x%08x\n", __raw_readl(EXYNOS4415_CLKMUX_STAT_G3D0)));
411
412         err = clk_set_rate(fout_vpll_clock, (unsigned int)clk * GPU_MHZ);
413
414         if (err > 0)
415                 MALI_PRINT_ERROR(("Failed to set fout_vpll clock: %d\n", err));
416
417
418         err = clk_set_parent(vpll_src_clock, ext_xtal_clock);
419
420         if (err)
421                 MALI_PRINT_ERROR(("vpll_src set parent to ext_xtal failed\n"));
422
423         err = clk_set_parent(sclk_vpll_clock, fout_vpll_clock);
424
425         if (err)
426                 MALI_PRINT_ERROR(("sclk_vpll set parent to fout_vpll failed\n"));
427
428         MALI_DEBUG_PRINT(3, ("Mali platform: set_parent_vpll : %8.x \n", (__raw_readl(EXYNOS4_CLKSRC_TOP0) >> 8) & 0x1));
429
430         err = clk_set_parent(mali_parent_clock, sclk_vpll_clock);
431
432         if (err)
433                 MALI_PRINT_ERROR(("mali_parent set parent to sclk_vpll failed\n"));
434
435         do {
436                 cpu_relax();
437                 read_val = __raw_readl(EXYNOS4415_CLKMUX_STAT_G3D0);
438         } while (((read_val >> 4) & 0x7) != 0x2);
439
440         MALI_DEBUG_PRINT(3, ("SET to VPLL EXYNOS4_CLKMUX_STAT_G3D0 : 0x%08x\n", __raw_readl(EXYNOS4415_CLKMUX_STAT_G3D0)));
441
442         err = clk_set_parent(mali_clock, mali_parent_clock);
443
444         if (err)
445                 MALI_PRINT_ERROR(("mali_clock set parent to mali_parent failed\n"));
446
447         if (atomic_read(&clk_active) == 0) {
448                 if (clk_enable(mali_clock) < 0) {
449                         _mali_osk_mutex_signal(mali_dvfs_lock);
450                         return;
451                 }
452                 atomic_set(&clk_active, 1);
453         }
454
455         err = clk_set_rate(mali_clock, rate);
456
457         if (err > 0)
458                 MALI_PRINT_ERROR(("Failed to set Mali clock: %d\n", err));
459
460         rate = clk_get_rate(mali_clock);
461
462         MALI_DEBUG_PRINT(1, ("Mali frequency %d\n", rate / mhz));
463         GPU_MHZ = mhz;
464
465         mali_gpu_clk = (int)(rate / mhz);
466         mali_clk_put(MALI_FALSE);
467
468         _mali_osk_mutex_signal(mali_dvfs_lock);
469 }
470
471 mali_bool set_mali_dvfs_current_step(unsigned int step)
472 {
473         _mali_osk_mutex_wait(mali_dvfs_lock);
474         maliDvfsStatus.currentStep = step % MALI_DVFS_STEPS;
475         _mali_osk_mutex_signal(mali_dvfs_lock);
476         return MALI_TRUE;
477 }
478
479 static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup)
480 {
481         u32 validatedStep = step;
482 #if MALI_DVFS_CLK_DEBUG
483         unsigned int *pRegMaliClkDiv;
484         unsigned int *pRegMaliMpll;
485 #endif
486
487         if(boostup)     {
488 #ifdef CONFIG_REGULATOR
489                 /*change the voltage*/
490 #ifdef EXYNOS4_ASV_ENABLED
491                 mali_regulator_set_voltage(get_match_volt(ID_G3D, mali_dvfs[step].clock * GPU_ASV_VOLT), get_match_volt(ID_G3D, mali_dvfs[step].clock * GPU_ASV_VOLT));
492                 exynos_set_abb(ID_G3D, get_match_abb(ID_G3D, mali_dvfs[step].clock * GPU_ASV_VOLT));
493 #else
494                 mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol);
495 #endif
496 #endif
497                 /*change the clock*/
498                 mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
499         } else {
500                 /*change the clock*/
501                 mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
502 #ifdef CONFIG_REGULATOR
503 #ifdef EXYNOS4_ASV_ENABLED
504                 /*change the voltage*/
505                 mali_regulator_set_voltage(get_match_volt(ID_G3D, mali_dvfs[step].clock * GPU_ASV_VOLT), get_match_volt(ID_G3D, mali_dvfs[step].clock * GPU_ASV_VOLT));
506                 exynos_set_abb(ID_G3D, get_match_abb(ID_G3D, mali_dvfs[step].clock * GPU_ASV_VOLT));
507 #else
508                 mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol);
509 #endif
510 #endif
511         }
512
513 #if defined(CONFIG_MALI400_PROFILING)
514         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|
515                         MALI_PROFILING_EVENT_CHANNEL_GPU|
516                         MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
517                         mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0);
518 #endif
519         mali_clk_put(MALI_FALSE);
520
521 #if MALI_DVFS_CLK_DEBUG
522         pRegMaliClkDiv = ioremap(0x1003c52c, 32);
523         pRegMaliMpll = ioremap(0x1003c22c, 32);
524         MALI_PRINT(("Mali MPLL reg:%d, CLK DIV: %d \n", *pRegMaliMpll, *pRegMaliClkDiv));
525 #endif
526         set_mali_dvfs_current_step(validatedStep);
527         /*for future use*/
528         maliDvfsStatus.pCurrentDvfs = &mali_dvfs[validatedStep];
529
530 #if CPUFREQ_LOCK_DURING_440
531         /* lock/unlock CPU freq by Mali */
532         if (mali_dvfs[step].clock >= 440)
533                 cpufreq_lock_by_mali(400);
534         else
535                 cpufreq_unlock_by_mali();
536 #endif
537         return MALI_TRUE;
538 }
539
540 static void mali_platform_wating(u32 msec)
541 {
542         /*
543         * sample wating
544         * change this in the future with proper check routine.
545         */
546         unsigned int read_val;
547         while(1) {
548                 read_val = _mali_osk_mem_ioread32(clk_register_map, 0x00);
549                 if ((read_val & 0x8000)==0x0000) break;
550
551                 _mali_osk_time_ubusydelay(100); /* 1000 -> 100 : 20101218 */
552         }
553 }
554
555 static mali_bool change_mali_dvfs_status(u32 step, mali_bool boostup )
556 {
557         MALI_DEBUG_PRINT(4, ("> change_mali_dvfs_status: %d, %d \n", step, boostup));
558
559         if (!set_mali_dvfs_status(step, boostup)) {
560                 MALI_DEBUG_PRINT(1, ("error on set_mali_dvfs_status: %d, %d \n",step, boostup));
561                 return MALI_FALSE;
562         }
563
564         /* wait until clock and voltage is stablized */
565         mali_platform_wating(MALI_DVFS_WATING); /* msec */
566         return MALI_TRUE;
567 }
568
569 static unsigned int decideNextStatus(unsigned int utilization)
570 {
571         static unsigned int level = 0;
572         int iStepCount = 0;
573
574         if (mali_runtime_resumed >= 0) {
575                 level = mali_runtime_resumed;
576                 mali_runtime_resumed = -1;
577         }
578
579         if (mali_dvfs_control == 0) {
580                 if (utilization > (int)(255 * mali_dvfs[maliDvfsStatus.currentStep].upthreshold / 100) &&
581                                 level < MALI_DVFS_STEPS - 1) {
582                         level++;
583                 } else if (utilization < (int)(255 * mali_dvfs[maliDvfsStatus.currentStep].downthreshold / 100) &&
584                         level > 0) {
585                         level--;
586                 }
587         } else {
588                 for (iStepCount = MALI_DVFS_STEPS-1; iStepCount >= 0; iStepCount--) {
589                         if (mali_dvfs_control >= mali_dvfs[iStepCount].clock) {
590                                 level = iStepCount;
591                                 break;
592                         }
593                 }
594         }
595         return level;
596 }
597
598 static mali_bool mali_dvfs_status(unsigned int utilization)
599 {
600         unsigned int nextStatus = 0;
601         unsigned int curStatus = 0;
602         mali_bool boostup = MALI_FALSE;
603         static int stay_count = 5;
604
605         MALI_DEBUG_PRINT(4, ("> mali_dvfs_status: %d \n", utilization));
606
607         /* decide next step */
608         curStatus = get_mali_dvfs_status();
609         nextStatus = decideNextStatus(utilization);
610
611         MALI_DEBUG_PRINT(4, ("= curStatus %d, nextStatus %d, maliDvfsStatus.currentStep %d \n", curStatus, nextStatus, maliDvfsStatus.currentStep));
612         /* if next status is same with current status, don't change anything */
613         if(curStatus != nextStatus) {
614                 /*check if boost up or not*/
615                 if(maliDvfsStatus.currentStep < nextStatus) {
616                         boostup = 1;
617                         stay_count = 5;
618                 } else if (maliDvfsStatus.currentStep > nextStatus){
619                         stay_count--;
620                 }
621
622                 if( boostup == 1 || stay_count <= 0){
623                         /*change mali dvfs status*/
624 #ifdef CONFIG_MALI_DVFS
625                         update_time_in_state(curStatus);
626 #endif
627                         if (!change_mali_dvfs_status(nextStatus, boostup)) {
628                                 MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
629                                 return MALI_FALSE;
630                         }
631                         boostup = 0;
632                         stay_count = 5;
633                 }
634         }
635         else
636                 stay_count = 5;
637
638         return MALI_TRUE;
639 }
640
641 static void mali_dvfs_work_handler(struct work_struct *w)
642 {
643         bMaliDvfsRun = 1;
644         MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n"));
645
646         if(!mali_dvfs_status(mali_dvfs_utilization))
647                 MALI_DEBUG_PRINT(1, ( "error on mali dvfs status in mali_dvfs_work_handler"));
648
649         bMaliDvfsRun = 0;
650 }
651
652 mali_bool init_mali_dvfs_status(void)
653 {
654         /*
655         * default status
656         * add here with the right function to get initilization value.
657         */
658         if (!mali_dvfs_wq)
659                 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
660
661         /* add a error handling here */
662         maliDvfsStatus.currentStep = MALI_DVFS_DEFAULT_STEP;
663
664         return MALI_TRUE;
665 }
666
667 void deinit_mali_dvfs_status(void)
668 {
669         if (mali_dvfs_wq)
670                 destroy_workqueue(mali_dvfs_wq);
671
672         mali_dvfs_wq = NULL;
673 }
674
675 mali_bool mali_dvfs_handler(unsigned int utilization)
676 {
677         mali_dvfs_utilization = utilization;
678         queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
679
680         return MALI_TRUE;
681 }
682
683 static mali_bool init_mali_clock(void)
684 {
685         mali_bool ret = MALI_TRUE;
686         nPowermode = MALI_POWER_MODE_DEEP_SLEEP;
687
688         if (mali_clock != 0)
689                 return ret; /* already initialized */
690
691         mali_dvfs_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED, 0);
692
693         if (mali_dvfs_lock == NULL)
694                 return _MALI_OSK_ERR_FAULT;
695
696         if (!mali_clk_get())
697         {
698                 MALI_PRINT(("Error: Failed to get Mali clock\n"));
699                 goto err_clk;
700         }
701
702         mali_clk_set_rate((unsigned int)mali_gpu_clk, GPU_MHZ);
703
704         MALI_PRINT(("init_mali_clock mali_clock %x\n", mali_clock));
705
706 #ifdef CONFIG_REGULATOR
707         g3d_regulator = regulator_get(NULL, "vdd_g3d");
708
709         if (IS_ERR(g3d_regulator))
710         {
711                 MALI_PRINT( ("MALI Error : failed to get vdd_g3d\n"));
712                 ret = MALI_FALSE;
713                 goto err_regulator;
714         }
715
716         mali_gpu_vol = mali_runtime_resume.vol;
717 #ifdef EXYNOS4_ASV_ENABLED
718         mali_gpu_vol = get_match_volt(ID_G3D, mali_gpu_clk * GPU_ASV_VOLT);
719         mali_runtime_resume.vol = get_match_volt(ID_G3D, mali_runtime_resume.clk * GPU_ASV_VOLT);
720 #endif
721
722         regulator_enable(g3d_regulator);
723         mali_regulator_set_voltage(mali_gpu_vol, mali_gpu_vol);
724
725 #ifdef EXYNOS4_ASV_ENABLED
726         exynos_set_abb(ID_G3D, get_match_abb(ID_G3D, mali_runtime_resume.clk * GPU_ASV_VOLT));
727 #endif
728 #endif
729
730 #if defined(CONFIG_MALI400_PROFILING)
731         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|
732                         MALI_PROFILING_EVENT_CHANNEL_GPU|
733                         MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
734                         mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0);
735 #endif
736         mali_clk_put(MALI_FALSE);
737
738         return MALI_TRUE;
739
740 #ifdef CONFIG_REGULATOR
741 err_regulator:
742         regulator_put(g3d_regulator);
743 #endif
744 err_clk:
745         mali_clk_put(MALI_TRUE);
746
747         return ret;
748 }
749
750 static mali_bool deinit_mali_clock(void)
751 {
752         if (mali_clock == 0)
753                 return MALI_TRUE;
754
755 #ifdef CONFIG_REGULATOR
756         if (g3d_regulator)
757         {
758                 regulator_put(g3d_regulator);
759                 g3d_regulator = NULL;
760         }
761 #endif
762         mali_clk_put(MALI_TRUE);
763
764         return MALI_TRUE;
765 }
766
767 static _mali_osk_errcode_t enable_mali_clocks(void)
768 {
769         int err;
770
771         if (atomic_read(&clk_active) == 0) {
772                 err = clk_enable(mali_clock);
773                 MALI_DEBUG_PRINT(3,("enable_mali_clocks mali_clock %p error %d \n", mali_clock, err));
774                 atomic_set(&clk_active, 1);
775         }
776
777         /* set clock rate */
778 #ifdef CONFIG_MALI_DVFS
779         if (mali_dvfs_control != 0 || mali_gpu_clk >= mali_runtime_resume.clk) {
780                 mali_clk_set_rate(mali_gpu_clk, GPU_MHZ);
781         } else {
782 #ifdef CONFIG_REGULATOR
783                 mali_regulator_set_voltage(mali_runtime_resume.vol, mali_runtime_resume.vol);
784 #ifdef EXYNOS4_ASV_ENABLED
785                 exynos_set_abb(ID_G3D, get_match_abb(ID_G3D, mali_runtime_resume.clk * GPU_ASV_VOLT));
786 #endif
787 #endif
788                 mali_clk_set_rate(mali_runtime_resume.clk, GPU_MHZ);
789                 set_mali_dvfs_current_step(mali_runtime_resume.step);
790         }
791 #else
792         mali_clk_set_rate((unsigned int)mali_gpu_clk, GPU_MHZ);
793         maliDvfsStatus.currentStep = MALI_DVFS_DEFAULT_STEP;
794 #endif
795
796         MALI_SUCCESS;
797 }
798
799 static _mali_osk_errcode_t disable_mali_clocks(void)
800 {
801         if (atomic_read(&clk_active)) {
802                 clk_disable(mali_clock);
803                 MALI_DEBUG_PRINT(3, ("disable_mali_clocks mali_clock %p\n", mali_clock));
804                 atomic_set(&clk_active, 0);
805         }
806         MALI_SUCCESS;
807 }
808
809 _mali_osk_errcode_t mali_platform_init(struct device *dev)
810 {
811         MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
812         atomic_set(&clk_active, 0);
813
814 #ifdef CONFIG_MALI_DVFS
815         if (!clk_register_map)
816                 clk_register_map = _mali_osk_mem_mapioregion(CLK_DIV_STAT_G3D, 0x20, CLK_DESC);
817
818         if (!init_mali_dvfs_status())
819                 MALI_DEBUG_PRINT(1, ("mali_platform_init failed\n"));
820
821         maliDvfsStatus.currentStep = MALI_DVFS_DEFAULT_STEP;
822 #endif
823         mali_platform_power_mode_change(dev, MALI_POWER_MODE_ON);
824         MALI_SUCCESS;
825 }
826
827 _mali_osk_errcode_t mali_platform_deinit(struct device *dev)
828 {
829         mali_platform_power_mode_change(dev, MALI_POWER_MODE_DEEP_SLEEP);
830         deinit_mali_clock();
831
832 #ifdef CONFIG_MALI_DVFS
833         deinit_mali_dvfs_status();
834         if (clk_register_map)
835         {
836                 _mali_osk_mem_unmapioregion(CLK_DIV_STAT_G3D, 0x20, clk_register_map);
837                 clk_register_map = NULL;
838         }
839 #endif
840         MALI_SUCCESS;
841 }
842
843 _mali_osk_errcode_t mali_platform_power_mode_change(struct device *dev, mali_power_mode power_mode)
844 {
845         switch (power_mode)
846         {
847         case MALI_POWER_MODE_ON:
848                 MALI_DEBUG_PRINT(3, ("Mali platform: Got MALI_POWER_MODE_ON event, %s\n",
849                                         nPowermode ? "powering on" : "already on"));
850                 if (nPowermode == MALI_POWER_MODE_LIGHT_SLEEP || nPowermode == MALI_POWER_MODE_DEEP_SLEEP)      {
851                         MALI_DEBUG_PRINT(4, ("enable clock\n"));
852                         enable_mali_clocks();
853
854 #if defined(CONFIG_MALI400_PROFILING)
855                         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
856                         MALI_PROFILING_EVENT_CHANNEL_GPU |
857                         MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
858                         mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0);
859 #endif
860                         nPowermode = power_mode;
861                 }
862                 break;
863         case MALI_POWER_MODE_DEEP_SLEEP:
864         case MALI_POWER_MODE_LIGHT_SLEEP:
865                 MALI_DEBUG_PRINT(3, ("Mali platform: Got %s event, %s\n", power_mode == MALI_POWER_MODE_LIGHT_SLEEP ?
866                                         "MALI_POWER_MODE_LIGHT_SLEEP" : "MALI_POWER_MODE_DEEP_SLEEP",
867                                         nPowermode ? "already off" : "powering off"));
868                 if (nPowermode == MALI_POWER_MODE_ON)   {
869                         disable_mali_clocks();
870
871 #if defined(CONFIG_MALI400_PROFILING)
872                         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
873                         MALI_PROFILING_EVENT_CHANNEL_GPU |
874                         MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
875                         0, 0, 0, 0, 0);
876 #endif
877                         nPowermode = power_mode;
878                 }
879                 break;
880         }
881         MALI_SUCCESS;
882 }
883
884 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
885 {
886         if (nPowermode == MALI_POWER_MODE_ON)
887         {
888 #ifdef CONFIG_MALI_DVFS
889                 if(!mali_dvfs_handler(data->utilization_gpu))
890                         MALI_DEBUG_PRINT(1, ("error on mali dvfs status in utilization\n"));
891 #endif
892         }
893 }
894
895 #ifdef CONFIG_MALI_DVFS
896 static void update_time_in_state(int level)
897 {
898         u64 current_time;
899         static u64 prev_time = 0;
900
901         if (prev_time == 0)
902                 prev_time = get_jiffies_64();
903
904         current_time = get_jiffies_64();
905         mali_dvfs_time[level] += current_time - prev_time;
906         prev_time = current_time;
907 }
908
909 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
910 {
911         ssize_t ret = 0;
912         int i;
913
914         update_time_in_state(maliDvfsStatus.currentStep);
915
916         for (i = 0; i < MALI_DVFS_STEPS; i++) {
917                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d %llu\n",
918                                                 mali_dvfs[i].clock,
919                                                 mali_dvfs_time[i]);
920         }
921
922         if (ret < PAGE_SIZE - 1) {
923                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
924         } else {
925                 buf[PAGE_SIZE - 2] = '\n';
926                 buf[PAGE_SIZE - 1] = '\0';
927                 ret = PAGE_SIZE - 1;
928         }
929         return ret;
930 }
931
932 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
933 {
934         int i;
935
936         for (i = 0; i < MALI_DVFS_STEPS; i++) {
937                 mali_dvfs_time[i] = 0;
938         }
939         return count;
940 }
941 #endif