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