tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / platform / pegasus-m400 / exynos4_pmm.c
1 /* drivers/gpu/mali400/mali/platform/pegasus-m400/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
18 #include "mali_kernel_common.h"
19 #include "mali_osk.h"
20 #include "exynos4_pmm.h"
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 #if defined(CONFIG_PM_RUNTIME)
32 #include <plat/pd.h>
33 #endif
34
35 #include <asm/io.h>
36 #include <mach/regs-pmu.h>
37 #include <mach/cpufreq.h>
38
39 #include <linux/workqueue.h>
40
41 #define MALI_DVFS_STEPS 5
42 #define MALI_DVFS_WATING 10 /* msec */
43 #define MALI_DVFS_DEFAULT_STEP 1
44 #define PD_G3D_LOCK_FLAG 2
45
46 #ifdef CONFIG_CPU_FREQ
47 #include <mach/asv.h>
48 #define EXYNOS4_ASV_ENABLED
49 #endif
50
51 #define MALI_DVFS_CLK_DEBUG 0
52 #define SEC_THRESHOLD 1
53
54 #define CPUFREQ_LOCK_DURING_440 1
55 #define CHIPID_REG              (S5P_VA_CHIPID + 0x4)
56
57 static int bMaliDvfsRun = 0;
58
59 typedef struct mali_dvfs_tableTag{
60         unsigned int clock;
61         unsigned int freq;
62         unsigned int vol;
63 #if SEC_THRESHOLD
64         unsigned int downthreshold;
65         unsigned int upthreshold;
66 #endif
67 }mali_dvfs_table;
68
69 typedef struct mali_dvfs_statusTag{
70         unsigned int currentStep;
71         mali_dvfs_table * pCurrentDvfs;
72
73 } mali_dvfs_status_t;
74
75 /* dvfs status */
76 mali_dvfs_status_t maliDvfsStatus;
77 int mali_dvfs_control;
78
79 typedef struct mali_runtime_resumeTag{
80         int clk;
81         int vol;
82         unsigned int step;
83 }mali_runtime_resume_table;
84
85 mali_runtime_resume_table mali_runtime_resume = {266, 900000, 1};
86
87 /* dvfs table */
88 mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={
89 #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412)
90                         /* step 0 */{160  ,1000000      ,875000 , 0   , 70},
91                         /* step 1 */{266  ,1000000      ,900000 ,62   , 90},
92                         /* step 2 */{350  ,1000000      ,950000 ,85   , 90},
93                         /* step 3 */{440  ,1000000      ,1025000   ,85   , 90},
94                         /* step 4 */{533  ,1000000      ,1075000   ,95   ,100} };
95 #else
96                         /* step 0 */{134  ,1000000      , 950000   ,85   , 90},
97                         /* step 1 */{267  ,1000000      ,1050000   ,85   ,100} };
98 #endif
99
100 #ifdef EXYNOS4_ASV_ENABLED
101 #define ASV_LEVEL     12        /* ASV0, 1, 11 is reserved */
102 #define ASV_LEVEL_PRIME     13  /* ASV0, 1, 12 is reserved */
103 #define ASV_LEVEL_PD    13
104
105
106 static unsigned int asv_3d_volt_9_table_1ghz_type[MALI_DVFS_STEPS-1][ASV_LEVEL] = {
107         {  975000,  950000,  950000,  950000,  925000,  925000,  925000,  900000,  900000,  900000,  900000,  875000},  /* L3(160Mhz) */
108 #if (MALI_DVFS_STEPS > 1)
109         { 1000000,  975000,  975000,  975000,  950000,  950000,  950000,  900000,  900000,  900000,  900000,  875000},  /* L2(266Mhz) */
110 #if (MALI_DVFS_STEPS > 2)
111         { 1075000, 1050000, 1050000, 1050000, 1000000, 1000000, 1000000,  975000,  975000,  975000,  975000,  925000},  /* L1(350Mhz) */
112 #if (MALI_DVFS_STEPS > 3)
113         { 1125000, 1100000, 1100000, 1100000, 1075000, 1075000, 1075000, 1025000, 1025000, 1025000, 1025000,  975000},  /* L0(440Mhz) */
114 #endif
115 #endif
116 #endif
117 };
118 static unsigned int asv_3d_volt_9_table[MALI_DVFS_STEPS-1][ASV_LEVEL] = {
119         {  950000,  925000,  900000,  900000,  875000,  875000,  875000,  875000,  850000,  850000,  850000,  850000},  /* L3(160Mhz) */
120 #if (MALI_DVFS_STEPS > 1)
121         {  975000,  950000,  925000,  925000,  925000,  900000,  900000,  875000,  875000,  875000,  875000,  850000},  /* L2(266Mhz) */
122 #if (MALI_DVFS_STEPS > 2)
123         { 1050000, 1025000, 1000000, 1000000,  975000,  950000,  950000,  950000,  925000,  925000,  925000,  900000},  /* L1(350Mhz) */
124 #if (MALI_DVFS_STEPS > 3)
125         { 1100000, 1075000, 1050000, 1050000, 1050000, 1025000, 1025000, 1000000, 1000000, 1000000,  975000,  950000},  /* L0(440Mhz) */
126 #endif
127 #endif
128 #endif
129 };
130
131 static unsigned int asv_3d_volt_9_table_for_prime[MALI_DVFS_STEPS][ASV_LEVEL_PRIME] = {
132         {  950000,  937500,  925000,  912500,  900000,  887500,  875000,  862500,  875000,  862500,  850000,  850000,  850000},  /* L4(160Mhz) */
133 #if (MALI_DVFS_STEPS > 1)
134         {  975000,  962500,  950000,  937500,  925000,  912500,  900000,  887500,  900000,  887500,  875000,  875000,  875000}, /* L3(266Mhz) */
135 #if (MALI_DVFS_STEPS > 2)
136         { 1025000, 1012500, 1000000,  987500,  975000,  962500,  950000,  937500,  950000,  937500,  912500,  900000,  887500}, /* L2(350Mhz) */
137 #if (MALI_DVFS_STEPS > 3)
138         { 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 1012500, 1000000,  975000,  962500,  950000}, /* L1(440Mhz) */
139 #if (MALI_DVFS_STEPS > 4)
140         { 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1075000, 1062500, 1037500, 1025000, 1012500}, /* L0(533Mhz) */
141 #endif
142 #endif
143 #endif
144 #endif
145 };
146
147 static unsigned int asv_3d_volt_4212_9_table[MALI_DVFS_STEPS][ASV_LEVEL_PD] = {
148         {  950000,  925000,  900000,  900000,  900000,  900000,  900000,  900000,  875000,  850000,  850000,  850000, 850000},  /* L3(160Mhz) */
149 #if (MALI_DVFS_STEPS > 1)
150         {  975000,  950000,  925000,  925000,  925000,  925000,  925000,  900000,  900000,  900000,  875000,  875000, 875000},  /* L2(266Mhz) */
151 #if (MALI_DVFS_STEPS > 2)
152         { 1025000, 1000000,  975000,  975000,  975000,  950000,  950000,  925000,  925000,  925000,  925000,  900000, 875000},  /* L1(350Mhz) */
153 #if (MALI_DVFS_STEPS > 3)
154         { 1100000, 1075000, 1050000, 1050000, 1050000, 1050000, 1025000, 1000000, 1000000,  975000,  975000,  950000, 925000},  /* L0(440Mhz) */
155 #endif
156 #endif
157 #endif
158 };
159 #endif /* ASV_LEVEL */
160
161 #define EXTXTALCLK_NAME  "ext_xtal"
162 #define VPLLSRCCLK_NAME  "vpll_src"
163 #define FOUTVPLLCLK_NAME "fout_vpll"
164 #define SCLVPLLCLK_NAME  "sclk_vpll"
165 #define GPUMOUT1CLK_NAME "mout_g3d1"
166
167 #define MPLLCLK_NAME     "mout_mpll"
168 #define GPUMOUT0CLK_NAME "mout_g3d0"
169 #define GPUCLK_NAME       "sclk_g3d"
170 #define CLK_DIV_STAT_G3D 0x1003C62C
171 #define CLK_DESC                 "clk-divider-status"
172
173 static struct clk *ext_xtal_clock       = NULL;
174 static struct clk *vpll_src_clock       = NULL;
175 static struct clk *fout_vpll_clock   = NULL;
176 static struct clk *sclk_vpll_clock   = NULL;
177
178 static struct clk *mpll_clock           = NULL;
179 static struct clk *mali_parent_clock = NULL;
180 static struct clk  *mali_mout0_clock = NULL;
181 static struct clk *mali_clock           = NULL;
182
183 #if defined(CONFIG_CPU_EXYNOS4412) || defined(CONFIG_CPU_EXYNOS4212)
184 /* Pegasus */
185 static const mali_bool bis_vpll = MALI_TRUE;
186 int mali_gpu_clk = 440;
187 int mali_gpu_vol = 1025000;
188 #else
189 /* Orion */
190 static const mali_bool bis_vpll = MALI_FALSE;
191 int mali_gpu_clk = 267;
192 int mali_gpu_vol = 1050000;
193 #endif
194
195 static unsigned int GPU_MHZ     = 1000000;
196
197 int  gpu_power_state;
198 static int bPoweroff;
199 atomic_t clk_active;
200
201 #define MAX_MALI_DVFS_STEPS 5
202 static _mali_osk_atomic_t bottomlock_status;
203 int bottom_lock_step = 0;
204
205 #if MALI_VOLTAGE_LOCK
206 int mali_lock_vol = 0;
207 static _mali_osk_atomic_t voltage_lock_status;
208 static mali_bool mali_vol_lock_flag = 0;
209 #endif
210
211 /* Declare for sysfs */
212 #ifdef CONFIG_MALI_DVFS
213 module_param(mali_dvfs_control, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP| S_IROTH); /* rw-rw-r-- */
214 MODULE_PARM_DESC(mali_dvfs_control, "Mali Current DVFS");
215
216 DEVICE_ATTR(time_in_state, S_IRUGO|S_IWUSR, show_time_in_state, set_time_in_state);
217 MODULE_PARM_DESC(time_in_state, "Time-in-state of Mali DVFS");
218 #endif
219
220 module_param(mali_gpu_clk, int, S_IRUSR | S_IRGRP | S_IROTH); /* r--r--r-- */
221 MODULE_PARM_DESC(mali_gpu_clk, "Mali Current Clock");
222
223 module_param(mali_gpu_vol, int, S_IRUSR | S_IRGRP | S_IROTH); /* r--r--r-- */
224 MODULE_PARM_DESC(mali_gpu_vol, "Mali Current Voltage");
225
226 module_param(gpu_power_state, int, S_IRUSR | S_IRGRP | S_IROTH); /* r--r--r-- */
227 MODULE_PARM_DESC(gpu_power_state, "Mali Power State");
228
229 #ifdef CONFIG_REGULATOR
230 struct regulator *g3d_regulator = NULL;
231 #endif
232 atomic_t mali_cpufreq_lock;
233
234 mali_io_address clk_register_map = 0;
235
236 /* DVFS */
237 static unsigned int mali_dvfs_utilization = 255;
238 u64 mali_dvfs_time[MALI_DVFS_STEPS];
239 #ifdef CONFIG_MALI_DVFS
240 static void update_time_in_state(int level);
241 #endif
242 static void mali_dvfs_work_handler(struct work_struct *w);
243 static struct workqueue_struct *mali_dvfs_wq = 0;
244 extern mali_io_address clk_register_map;
245 _mali_osk_mutex_t *mali_dvfs_lock;
246 int mali_runtime_resumed = -1;
247 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_work_handler);
248
249 int cpufreq_lock_by_mali(unsigned int freq)
250 {
251 #ifdef CONFIG_EXYNOS4_CPUFREQ
252         unsigned int level;
253
254         if (atomic_read(&mali_cpufreq_lock) == 0) {
255                 if (exynos_cpufreq_get_level(freq * 1000, &level)) {
256                         printk(KERN_ERR
257                                 "Mali: failed to get cpufreq level for %dMHz",
258                                 freq);
259                         return -EINVAL;
260                 }
261
262                 if (exynos_cpufreq_lock(DVFS_LOCK_ID_G3D, level)) {
263                         printk(KERN_ERR
264                                 "Mali: failed to cpufreq lock for L%d", level);
265                         return -EINVAL;
266                 }
267
268                 atomic_set(&mali_cpufreq_lock, 1);
269                 printk(KERN_DEBUG "Mali: cpufreq locked on <%d>%dMHz\n", level,
270                                                                         freq);
271         }
272 #endif
273         return 0;
274 }
275
276 void cpufreq_unlock_by_mali(void)
277 {
278 #ifdef CONFIG_EXYNOS4_CPUFREQ
279         if (atomic_read(&mali_cpufreq_lock) == 1) {
280                 exynos_cpufreq_lock_free(DVFS_LOCK_ID_G3D);
281                 atomic_set(&mali_cpufreq_lock, 0);
282                 printk(KERN_DEBUG "Mali: cpufreq locked off\n");
283         }
284 #endif
285 }
286
287 #ifdef CONFIG_REGULATOR
288 void mali_regulator_disable(void)
289 {
290         if(IS_ERR_OR_NULL(g3d_regulator))
291         {
292                 MALI_DEBUG_PRINT(1, ("error on mali_regulator_disable : g3d_regulator is null\n"));
293                 return;
294         }
295         regulator_disable(g3d_regulator);
296 }
297
298 void mali_regulator_enable(void)
299 {
300         if(IS_ERR_OR_NULL(g3d_regulator))
301         {
302                 MALI_DEBUG_PRINT(1, ("error on mali_regulator_enable : g3d_regulator is null\n"));
303                 return;
304         }
305         regulator_enable(g3d_regulator);
306 }
307
308 void mali_regulator_set_voltage(int min_uV, int max_uV)
309 {
310         _mali_osk_mutex_wait(mali_dvfs_lock);
311         if(IS_ERR_OR_NULL(g3d_regulator))
312         {
313                 MALI_DEBUG_PRINT(1, ("error on mali_regulator_set_voltage : g3d_regulator is null\n"));
314                 _mali_osk_mutex_signal(mali_dvfs_lock);
315                 return;
316         }
317         MALI_PRINT(("= regulator_set_voltage: %d, %d \n",min_uV, max_uV));
318         regulator_set_voltage(g3d_regulator, min_uV, max_uV);
319         mali_gpu_vol = regulator_get_voltage(g3d_regulator);
320         MALI_DEBUG_PRINT(1, ("Mali voltage: %d\n", mali_gpu_vol));
321         _mali_osk_mutex_signal(mali_dvfs_lock);
322 }
323 #endif
324
325 unsigned long mali_clk_get_rate(void)
326 {
327         return clk_get_rate(mali_clock);
328 }
329
330
331 static unsigned int get_mali_dvfs_status(void)
332 {
333         return maliDvfsStatus.currentStep;
334 }
335
336 mali_bool mali_clk_get(void)
337 {
338         if (bis_vpll)
339         {
340                 if (ext_xtal_clock == NULL)
341                 {
342                         ext_xtal_clock = clk_get(NULL, EXTXTALCLK_NAME);
343                         if (IS_ERR(ext_xtal_clock)) {
344                                 MALI_PRINT(("MALI Error : failed to get source ext_xtal_clock\n"));
345                                 return MALI_FALSE;
346                         }
347                 }
348
349                 if (vpll_src_clock == NULL)
350                 {
351                         vpll_src_clock = clk_get(NULL, VPLLSRCCLK_NAME);
352                         if (IS_ERR(vpll_src_clock)) {
353                                 MALI_PRINT(("MALI Error : failed to get source vpll_src_clock\n"));
354                                 return MALI_FALSE;
355                         }
356                 }
357
358                 if (fout_vpll_clock == NULL)
359                 {
360                         fout_vpll_clock = clk_get(NULL, FOUTVPLLCLK_NAME);
361                         if (IS_ERR(fout_vpll_clock)) {
362                                 MALI_PRINT(("MALI Error : failed to get source fout_vpll_clock\n"));
363                                 return MALI_FALSE;
364                         }
365                 }
366
367                 if (sclk_vpll_clock == NULL)
368                 {
369                         sclk_vpll_clock = clk_get(NULL, SCLVPLLCLK_NAME);
370                         if (IS_ERR(sclk_vpll_clock)) {
371                                 MALI_PRINT(("MALI Error : failed to get source sclk_vpll_clock\n"));
372                                 return MALI_FALSE;
373                         }
374                 }
375
376                 if (mali_parent_clock == NULL)
377                 {
378                         mali_parent_clock = clk_get(NULL, GPUMOUT1CLK_NAME);
379
380                         if (IS_ERR(mali_parent_clock)) {
381                                 MALI_PRINT(( "MALI Error : failed to get source mali parent clock\n"));
382                                 return MALI_FALSE;
383                         }
384                 }
385
386                 if (mali_mout0_clock == NULL)
387                 {
388                         mali_mout0_clock = clk_get(NULL, GPUMOUT0CLK_NAME);
389
390                         if (IS_ERR(mali_mout0_clock)) {
391                                 MALI_PRINT( ( "MALI Error : failed to get source mali mout0 clock\n"));
392                                 return MALI_FALSE;
393                         }
394                 }
395         }
396         else /* mpll */
397         {
398                 if (mpll_clock == NULL)
399                 {
400                         mpll_clock = clk_get(NULL, MPLLCLK_NAME);
401
402                         if (IS_ERR(mpll_clock)) {
403                                 MALI_PRINT(("MALI Error : failed to get source mpll clock\n"));
404                                 return MALI_FALSE;
405                         }
406                 }
407
408                 if (mali_parent_clock == NULL)
409                 {
410                         mali_parent_clock = clk_get(NULL, GPUMOUT0CLK_NAME);
411
412                         if (IS_ERR(mali_parent_clock)) {
413                                 MALI_PRINT(( "MALI Error : failed to get source mali parent clock\n"));
414                                 return MALI_FALSE;
415                         }
416                 }
417         }
418
419         /* mali clock get always. */
420         if (mali_clock == NULL)
421         {
422                 mali_clock = clk_get(NULL, GPUCLK_NAME);
423
424                 if (IS_ERR(mali_clock)) {
425                         MALI_PRINT(("MALI Error : failed to get source mali clock\n"));
426                         return MALI_FALSE;
427                 }
428         }
429
430         return MALI_TRUE;
431 }
432
433 void mali_clk_put(mali_bool binc_mali_clock)
434 {
435         if (mali_parent_clock)
436         {
437                 clk_put(mali_parent_clock);
438                 mali_parent_clock = NULL;
439         }
440
441         if (mali_mout0_clock)
442         {
443                 clk_put(mali_mout0_clock);
444                 mali_mout0_clock = NULL;
445         }
446
447         if (mpll_clock)
448         {
449                 clk_put(mpll_clock);
450                 mpll_clock = NULL;
451         }
452
453         if (sclk_vpll_clock)
454         {
455                 clk_put(sclk_vpll_clock);
456                 sclk_vpll_clock = NULL;
457         }
458
459         if (binc_mali_clock && fout_vpll_clock)
460         {
461                 clk_put(fout_vpll_clock);
462                 fout_vpll_clock = NULL;
463         }
464
465         if (vpll_src_clock)
466         {
467                 clk_put(vpll_src_clock);
468                 vpll_src_clock = NULL;
469         }
470
471         if (ext_xtal_clock)
472         {
473                 clk_put(ext_xtal_clock);
474                 ext_xtal_clock = NULL;
475         }
476
477         if (binc_mali_clock && mali_clock)
478         {
479                 clk_put(mali_clock);
480                 mali_clock = NULL;
481         }
482 }
483
484 void mali_clk_set_rate(unsigned int clk, unsigned int mhz)
485 {
486         int err;
487         unsigned long rate = (unsigned long)clk * (unsigned long)mhz;
488
489         _mali_osk_mutex_wait(mali_dvfs_lock);
490         MALI_DEBUG_PRINT(3, ("Mali platform: Setting frequency to %d mhz\n", clk));
491
492         if (mali_clk_get() == MALI_FALSE) {
493                 _mali_osk_mutex_signal(mali_dvfs_lock);
494                 return;
495         }
496
497         if (bis_vpll)
498         {
499                 clk_set_rate(fout_vpll_clock, (unsigned int)clk * GPU_MHZ);
500                 clk_set_parent(vpll_src_clock, ext_xtal_clock);
501                 clk_set_parent(sclk_vpll_clock, fout_vpll_clock);
502
503                 clk_set_parent(mali_parent_clock, sclk_vpll_clock);
504                 clk_set_parent(mali_clock, mali_parent_clock);
505         }
506         else
507         {
508                 clk_set_parent(mali_parent_clock, mpll_clock);
509                 clk_set_parent(mali_clock, mali_parent_clock);
510         }
511
512         if (atomic_read(&clk_active) == 0) {
513                 if (clk_enable(mali_clock) < 0) {
514                         _mali_osk_mutex_signal(mali_dvfs_lock);
515                         return;
516                 }
517                 atomic_set(&clk_active, 1);
518         }
519
520         err = clk_set_rate(mali_clock, rate);
521         if (err > 0)
522                 MALI_PRINT_ERROR(("Failed to set Mali clock: %d\n", err));
523
524         rate = mali_clk_get_rate();
525
526         MALI_PRINT(("Mali frequency %d\n", rate / mhz));
527         GPU_MHZ = mhz;
528         mali_gpu_clk = (int)(rate / mhz);
529
530         mali_clk_put(MALI_FALSE);
531
532         _mali_osk_mutex_signal(mali_dvfs_lock);
533 }
534
535 int get_mali_dvfs_control_status(void)
536 {
537         return mali_dvfs_control;
538 }
539
540 mali_bool set_mali_dvfs_current_step(unsigned int step)
541 {
542         _mali_osk_mutex_wait(mali_dvfs_lock);
543         maliDvfsStatus.currentStep = step % MALI_DVFS_STEPS;
544         if (step >= MALI_DVFS_STEPS)
545                 mali_runtime_resumed = maliDvfsStatus.currentStep;
546
547         _mali_osk_mutex_signal(mali_dvfs_lock);
548         return MALI_TRUE;
549 }
550
551
552 static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup)
553 {
554         u32 validatedStep=step;
555 #if MALI_DVFS_CLK_DEBUG
556         unsigned int *pRegMaliClkDiv;
557         unsigned int *pRegMaliMpll;
558 #endif
559
560         if(boostup)     {
561 #ifdef CONFIG_REGULATOR
562                 /* change the voltage */
563                 mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol);
564 #endif
565                 /* change the clock */
566                 mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
567         } else {
568                 /* change the clock */
569                 mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
570 #ifdef CONFIG_REGULATOR
571                 /* change the voltage */
572                 mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol);
573 #endif
574         }
575
576 #if defined(CONFIG_MALI400_PROFILING)
577         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|
578                         MALI_PROFILING_EVENT_CHANNEL_GPU|
579                         MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
580                         mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0);
581 #endif
582         mali_clk_put(MALI_FALSE);
583
584 #if MALI_DVFS_CLK_DEBUG
585         pRegMaliClkDiv = ioremap(0x1003c52c,32);
586         pRegMaliMpll = ioremap(0x1003c22c,32);
587         MALI_PRINT(("Mali MPLL reg:%d, CLK DIV: %d \n",*pRegMaliMpll, *pRegMaliClkDiv));
588 #endif
589
590 #ifdef EXYNOS4_ASV_ENABLED
591         if (samsung_rev() < EXYNOS4412_REV_2_0) {
592                 if (mali_dvfs[step].clock == 160)
593                         exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_100V);
594                 else
595                         exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_130V);
596         }
597 #endif
598
599         set_mali_dvfs_current_step(validatedStep);
600         /* for future use */
601         maliDvfsStatus.pCurrentDvfs = &mali_dvfs[validatedStep];
602
603 #if CPUFREQ_LOCK_DURING_440
604         /* lock/unlock CPU freq by Mali */
605         if (mali_dvfs[step].clock >= 440)
606                 cpufreq_lock_by_mali(1200);
607         else
608                 cpufreq_unlock_by_mali();
609 #endif
610
611
612         return MALI_TRUE;
613 }
614
615 static void mali_platform_wating(u32 msec)
616 {
617         /*
618         * sample wating
619         * change this in the future with proper check routine.
620         */
621         unsigned int read_val;
622         while(1) {
623                 read_val = _mali_osk_mem_ioread32(clk_register_map, 0x00);
624                 if ((read_val & 0x8000)==0x0000) break;
625
626                 _mali_osk_time_ubusydelay(100); /* 1000 -> 100 : 20101218 */
627         }
628 }
629
630 static mali_bool change_mali_dvfs_status(u32 step, mali_bool boostup )
631 {
632         MALI_DEBUG_PRINT(4, ("> change_mali_dvfs_status: %d, %d \n",step, boostup));
633
634         if (!set_mali_dvfs_status(step, boostup)) {
635                 MALI_DEBUG_PRINT(1, ("error on set_mali_dvfs_status: %d, %d \n",step, boostup));
636                 return MALI_FALSE;
637         }
638
639         /* wait until clock and voltage is stablized */
640         mali_platform_wating(MALI_DVFS_WATING); /* msec */
641
642         return MALI_TRUE;
643 }
644
645 #ifdef EXYNOS4_ASV_ENABLED
646 extern unsigned int exynos_result_of_asv;
647
648 static mali_bool mali_dvfs_table_update(void)
649 {
650         unsigned int i, tmp, g3d_lock_volt = 0;
651         unsigned int step_num = MALI_DVFS_STEPS;
652         bool lock_flag_g3d = false;
653
654         if(samsung_rev() < EXYNOS4412_REV_2_0)
655                 step_num = MALI_DVFS_STEPS - 1;
656
657         if(soc_is_exynos4412()) {
658                 if (exynos_armclk_max == 1000000) {
659                         MALI_PRINT(("::C::exynos_result_of_asv : %d\n", exynos_result_of_asv));
660                         for (i = 0; i < step_num; i++) {
661                                 mali_dvfs[i].vol = asv_3d_volt_9_table_1ghz_type[i][exynos_result_of_asv];
662                                 MALI_PRINT(("mali_dvfs[%d].vol = %d \n", i, mali_dvfs[i].vol));
663
664                                 // Update voltage using for resume
665                                 if (mali_runtime_resume.clk == mali_dvfs[i].clock) {
666                                         mali_runtime_resume.vol = mali_dvfs[i].vol;
667
668                                         MALI_PRINT(("mali_runtime_resume.vol = %d \n", mali_runtime_resume.vol));
669                                 }
670
671                                 // update voltage using for init timing
672                                 if (mali_gpu_clk == mali_dvfs[i].clock) {
673                                         mali_gpu_vol = mali_dvfs[i].vol;
674
675                                         MALI_PRINT(("init_gpu_vol = %d \n", mali_gpu_vol));
676                                 }
677                         }
678                 } else if(((is_special_flag() >> G3D_LOCK_FLAG) & 0x1) && (samsung_rev() >= EXYNOS4412_REV_2_0)) {
679                         MALI_PRINT(("::L::exynos_result_of_asv : %d\n", exynos_result_of_asv));
680                         for (i = 0; i < step_num; i++) {
681                                 mali_dvfs[i].vol = asv_3d_volt_9_table_for_prime[i][exynos_result_of_asv] + 25000;
682                                 MALI_PRINT(("mali_dvfs[%d].vol = %d \n ", i, mali_dvfs[i].vol));
683
684                                 // Update voltage using for resume
685                                 if (mali_runtime_resume.clk == mali_dvfs[i].clock) {
686                                         mali_runtime_resume.vol = mali_dvfs[i].vol;
687
688                                         MALI_PRINT(("mali_runtime_resume.vol = %d \n", mali_runtime_resume.vol));
689                                 }
690
691                                 // update voltage using for init timing
692                                 if (mali_gpu_clk == mali_dvfs[i].clock) {
693                                         mali_gpu_vol = mali_dvfs[i].vol;
694
695                                         MALI_PRINT(("init_gpu_vol = %d \n", mali_gpu_vol));
696                                 }
697                         }
698                 } else if (samsung_rev() >= EXYNOS4412_REV_2_0) {
699                         MALI_PRINT(("::P::exynos_result_of_asv : %d\n", exynos_result_of_asv));
700                         for (i = 0; i < step_num; i++) {
701                                 mali_dvfs[i].vol = asv_3d_volt_9_table_for_prime[i][exynos_result_of_asv];
702                                 MALI_PRINT(("mali_dvfs[%d].vol = %d \n", i, mali_dvfs[i].vol));
703
704                                 // Update voltage using for resume
705                                 if (mali_runtime_resume.clk == mali_dvfs[i].clock) {
706                                         mali_runtime_resume.vol = mali_dvfs[i].vol;
707
708                                         MALI_PRINT(("mali_runtime_resume.vol = %d \n", mali_runtime_resume.vol));
709                                 }
710
711                                 // update voltage using for init timing
712                                 if (mali_gpu_clk == mali_dvfs[i].clock) {
713                                         mali_gpu_vol = mali_dvfs[i].vol;
714
715                                         MALI_PRINT(("init_gpu_vol = %d \n", mali_gpu_vol));
716                                 }
717                         }
718                 } else {
719                         MALI_PRINT(("::Q::exynos_result_of_asv : %d\n", exynos_result_of_asv));
720                         for (i = 0; i < step_num; i++) {
721                                 mali_dvfs[i].vol = asv_3d_volt_9_table[i][exynos_result_of_asv];
722                                 MALI_PRINT(("mali_dvfs[%d].vol = %d \n", i, mali_dvfs[i].vol));
723
724                                 // Update voltage using for resume
725                                 if (mali_runtime_resume.clk == mali_dvfs[i].clock) {
726                                         mali_runtime_resume.vol = mali_dvfs[i].vol;
727
728                                         MALI_PRINT(("mali_runtime_resume.vol = %d \n", mali_runtime_resume.vol));
729                                 }
730
731                                 // update voltage using for init timing
732                                 if (mali_gpu_clk == mali_dvfs[i].clock) {
733                                         mali_gpu_vol = mali_dvfs[i].vol;
734
735                                         MALI_PRINT(("init_gpu_vol = %d \n", mali_gpu_vol));
736                                 }
737                         }
738                 }
739         }
740         else if(soc_is_exynos4212()) {
741                 tmp = __raw_readl(CHIPID_REG);
742                 lock_flag_g3d = (tmp >> PD_G3D_LOCK_FLAG) & 0x1;
743                 if (lock_flag_g3d)
744                         g3d_lock_volt = 25000;
745
746                 for (i = 0; i < step_num; i++) {
747                         MALI_PRINT((":::exynos_result_of_asv : %d\n", exynos_result_of_asv));
748                         mali_dvfs[i].vol = asv_3d_volt_4212_9_table[i][exynos_result_of_asv] + g3d_lock_volt;
749                         MALI_PRINT(("mali_dvfs[%d].vol = %d\n", i, mali_dvfs[i].vol));
750
751                         // Update voltage using for resume
752                         if (mali_runtime_resume.clk == mali_dvfs[i].clock) {
753                                 mali_runtime_resume.vol = mali_dvfs[i].vol;
754
755                                 MALI_PRINT(("mali_runtime_resume.vol = %d \n", mali_runtime_resume.vol));
756                         }
757
758                         // update voltage using for init timing
759                         if (mali_gpu_clk == mali_dvfs[i].clock) {
760                                 mali_gpu_vol = mali_dvfs[i].vol;
761
762                                 MALI_PRINT(("init_gpu_vol = %d \n", mali_gpu_vol));
763                         }
764                 }
765         }
766
767         return MALI_TRUE;
768 }
769 #endif
770
771 static unsigned int decideNextStatus(unsigned int utilization)
772 {
773         static unsigned int level = 0;
774         int iStepCount = 0;
775         if (mali_runtime_resumed >= 0) {
776                 level = mali_runtime_resumed;
777                 mali_runtime_resumed = -1;
778         }
779
780         if (mali_dvfs_control == 0 && level == get_mali_dvfs_status()) {
781                 if (utilization > (int)(255 * mali_dvfs[maliDvfsStatus.currentStep].upthreshold / 100) &&
782                                 level < MALI_DVFS_STEPS - 1) {
783                         level++;
784                         if ((samsung_rev() < EXYNOS4412_REV_2_0) && 3 == get_mali_dvfs_status()) {
785                                 level=get_mali_dvfs_status();
786                         }
787                 }
788                 else if (utilization < (int)(255 * mali_dvfs[maliDvfsStatus.currentStep].downthreshold / 100) &&
789                                 level > 0) {
790                         level--;
791                 }
792
793                 if (_mali_osk_atomic_read(&bottomlock_status) > 0) {
794                         if (level < bottom_lock_step)
795                                 level = bottom_lock_step;
796                 }
797         } else {
798                 for (iStepCount = MALI_DVFS_STEPS-1; iStepCount >= 0; iStepCount--) {
799                         if ( mali_dvfs_control >= mali_dvfs[iStepCount].clock ) {
800                                 level = iStepCount;
801                                 break;
802                         }
803                 }
804         }
805
806         return level;
807 }
808
809
810 static mali_bool mali_dvfs_status(unsigned int utilization)
811 {
812         unsigned int nextStatus = 0;
813         unsigned int curStatus = 0;
814         mali_bool boostup = MALI_FALSE;
815         static int stay_count = 5;
816
817         MALI_DEBUG_PRINT(4, ("> mali_dvfs_status: %d \n",utilization));
818
819         /* decide next step */
820         curStatus = get_mali_dvfs_status();
821         nextStatus = decideNextStatus(utilization);
822
823         MALI_DEBUG_PRINT(4, ("= curStatus %d, nextStatus %d, maliDvfsStatus.currentStep %d \n", curStatus, nextStatus, maliDvfsStatus.currentStep));
824         /* if next status is same with current status, don't change anything */
825         if(curStatus != nextStatus) {
826                 /*check if boost up or not*/
827                 if(maliDvfsStatus.currentStep < nextStatus) {
828                         boostup = 1;
829                         stay_count = 5;
830                 } else if (maliDvfsStatus.currentStep > nextStatus){
831                         stay_count--;
832                 }
833                 if( boostup == 1 || stay_count <= 0){
834                         /*change mali dvfs status*/
835 #ifdef CONFIG_MALI_DVFS
836                         update_time_in_state(curStatus);
837 #endif
838                         if (!change_mali_dvfs_status(nextStatus,boostup)) {
839                                 MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
840                                 return MALI_FALSE;
841                         }
842                         boostup = 0;
843                         stay_count = 5;
844                 }
845         }
846         else
847                 stay_count = 5;
848         return MALI_TRUE;
849 }
850
851
852 int mali_dvfs_is_running(void)
853 {
854         return bMaliDvfsRun;
855 }
856
857
858 static void mali_dvfs_work_handler(struct work_struct *w)
859 {
860         bMaliDvfsRun=1;
861
862         MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n"));
863
864         if(!mali_dvfs_status(mali_dvfs_utilization))
865         MALI_DEBUG_PRINT(1, ( "error on mali dvfs status in mali_dvfs_work_handler"));
866
867         bMaliDvfsRun=0;
868 }
869
870 mali_bool init_mali_dvfs_status(void)
871 {
872         /*
873         * default status
874         * add here with the right function to get initilization value.
875         */
876
877         if (!mali_dvfs_wq)
878                 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
879
880         _mali_osk_atomic_init(&bottomlock_status, 0);
881
882         /* add a error handling here */
883         maliDvfsStatus.currentStep = MALI_DVFS_DEFAULT_STEP;
884
885         return MALI_TRUE;
886 }
887
888 void deinit_mali_dvfs_status(void)
889 {
890         if (mali_dvfs_wq)
891                 destroy_workqueue(mali_dvfs_wq);
892
893         _mali_osk_atomic_term(&bottomlock_status);
894
895         mali_dvfs_wq = NULL;
896 }
897
898 mali_bool mali_dvfs_handler(unsigned int utilization)
899 {
900         mali_dvfs_utilization = utilization;
901         queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
902
903         return MALI_TRUE;
904 }
905
906 static mali_bool init_mali_clock(void)
907 {
908         mali_bool ret = MALI_TRUE;
909         gpu_power_state = 1;
910         bPoweroff = 1;
911
912         if (mali_clock != 0)
913                 return ret; /* already initialized */
914
915         mali_dvfs_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED, 0);
916         if (mali_dvfs_lock == NULL)
917                 return _MALI_OSK_ERR_FAULT;
918
919         if (!mali_clk_get())
920         {
921                 MALI_PRINT(("Error: Failed to get Mali clock\n"));
922                 goto err_clk;
923         }
924
925         mali_clk_set_rate((unsigned int)mali_gpu_clk, GPU_MHZ);
926
927         MALI_PRINT(("init_mali_clock mali_clock %x\n", mali_clock));
928
929 #ifdef CONFIG_REGULATOR
930         g3d_regulator = regulator_get(NULL, "vdd_g3d");
931
932         if (IS_ERR(g3d_regulator))
933         {
934                 MALI_PRINT(("MALI Error : failed to get vdd_g3d\n"));
935                 ret = MALI_FALSE;
936                 goto err_regulator;
937         }
938
939         regulator_enable(g3d_regulator);
940         mali_regulator_set_voltage(mali_gpu_vol, mali_gpu_vol);
941
942 #ifdef EXYNOS4_ASV_ENABLED
943         if (samsung_rev() < EXYNOS4412_REV_2_0) {
944                 if (mali_gpu_clk == 160)
945                         exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_100V);
946                 else
947                         exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_130V);
948         }
949 #endif
950 #endif
951
952 #if defined(CONFIG_MALI400_PROFILING)
953         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|
954                         MALI_PROFILING_EVENT_CHANNEL_GPU|
955                         MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
956                         mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0);
957 #endif
958
959         mali_clk_put(MALI_FALSE);
960
961         return MALI_TRUE;
962
963 #ifdef CONFIG_REGULATOR
964 err_regulator:
965         regulator_put(g3d_regulator);
966 #endif
967 err_clk:
968         mali_clk_put(MALI_TRUE);
969
970         return ret;
971 }
972
973 static mali_bool deinit_mali_clock(void)
974 {
975         if (mali_clock == 0)
976                 return MALI_TRUE;
977
978 #ifdef CONFIG_REGULATOR
979         if (g3d_regulator)
980         {
981                 regulator_put(g3d_regulator);
982                 g3d_regulator = NULL;
983         }
984 #endif
985
986         mali_clk_put(MALI_TRUE);
987
988         return MALI_TRUE;
989 }
990
991
992 static _mali_osk_errcode_t enable_mali_clocks(void)
993 {
994         int err;
995
996         if (atomic_read(&clk_active) == 0) {
997                 err = clk_enable(mali_clock);
998                 MALI_DEBUG_PRINT(3,("enable_mali_clocks mali_clock %p error %d \n", mali_clock, err));
999                 atomic_set(&clk_active, 1);
1000                 gpu_power_state = 1;
1001         }
1002
1003         /* set clock rate */
1004 #ifdef CONFIG_MALI_DVFS
1005         if (get_mali_dvfs_control_status() != 0 || mali_gpu_clk >= mali_runtime_resume.clk) {
1006                 mali_clk_set_rate(mali_gpu_clk, GPU_MHZ);
1007         } else {
1008 #ifdef CONFIG_REGULATOR
1009                 mali_regulator_set_voltage(mali_runtime_resume.vol, mali_runtime_resume.vol);
1010
1011 #ifdef EXYNOS4_ASV_ENABLED
1012                 if (samsung_rev() < EXYNOS4412_REV_2_0) {
1013                         if (mali_runtime_resume.clk == 160)
1014                                 exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_100V);
1015                         else
1016                                 exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_130V);
1017                 }
1018 #endif
1019 #endif
1020                 mali_clk_set_rate(mali_runtime_resume.clk, GPU_MHZ);
1021                 set_mali_dvfs_current_step(mali_runtime_resume.step);
1022         }
1023 #else
1024         mali_clk_set_rate((unsigned int)mali_gpu_clk, GPU_MHZ);
1025         maliDvfsStatus.currentStep = MALI_DVFS_DEFAULT_STEP;
1026 #endif
1027
1028
1029         MALI_SUCCESS;
1030 }
1031
1032 static _mali_osk_errcode_t disable_mali_clocks(void)
1033 {
1034         if (atomic_read(&clk_active) == 1) {
1035                 clk_disable(mali_clock);
1036                 atomic_set(&clk_active, 0);
1037                 gpu_power_state = 0;
1038         }
1039         MALI_DEBUG_PRINT(3, ("disable_mali_clocks mali_clock %p \n", mali_clock));
1040
1041         MALI_SUCCESS;
1042 }
1043
1044 /* Some defines changed names in later Odroid-A kernels. Make sure it works for both. */
1045 #ifndef S5P_G3D_CONFIGURATION
1046 #define S5P_G3D_CONFIGURATION S5P_PMU_G3D_CONF
1047 #endif
1048 #ifndef S5P_G3D_STATUS
1049 #define S5P_G3D_STATUS S5P_PMU_G3D_CONF + 0x4
1050 #endif
1051
1052 _mali_osk_errcode_t g3d_power_domain_control(int bpower_on)
1053 {
1054         if (bpower_on)
1055         {
1056                 void __iomem *status;
1057                 u32 timeout;
1058                 __raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_G3D_CONFIGURATION);
1059                 status = S5P_G3D_STATUS;
1060
1061                 timeout = 10;
1062                 while ((__raw_readl(status) & S5P_INT_LOCAL_PWR_EN)
1063                         != S5P_INT_LOCAL_PWR_EN) {
1064                         if (timeout == 0) {
1065                                 MALI_PRINTF(("Power domain  enable failed.\n"));
1066                                 return -ETIMEDOUT;
1067                         }
1068                         timeout--;
1069                         _mali_osk_time_ubusydelay(100);
1070                 }
1071         }
1072         else
1073         {
1074                 void __iomem *status;
1075                 u32 timeout;
1076                 __raw_writel(0, S5P_G3D_CONFIGURATION);
1077
1078                 status = S5P_G3D_STATUS;
1079                 /* Wait max 1ms */
1080                 timeout = 10;
1081                 while (__raw_readl(status) & S5P_INT_LOCAL_PWR_EN)
1082                 {
1083                         if (timeout == 0) {
1084                                 MALI_PRINTF(("Power domain  disable failed.\n" ));
1085                                 return -ETIMEDOUT;
1086                         }
1087                         timeout--;
1088                         _mali_osk_time_ubusydelay(100);
1089                 }
1090         }
1091
1092         MALI_SUCCESS;
1093 }
1094
1095 _mali_osk_errcode_t mali_platform_init(struct device *dev)
1096 {
1097 #ifdef EXYNOS4_ASV_ENABLED
1098         mali_dvfs_table_update();
1099 #endif
1100
1101         MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
1102
1103         atomic_set(&clk_active, 0);
1104
1105 #ifdef CONFIG_MALI_DVFS
1106         /* Create sysfs for time-in-state */
1107         if (device_create_file(dev, &dev_attr_time_in_state)) {
1108                 dev_err(dev, "Couldn't create sysfs file [time_in_state]\n");
1109         }
1110
1111         if (!clk_register_map) clk_register_map = _mali_osk_mem_mapioregion( CLK_DIV_STAT_G3D, 0x20, CLK_DESC );
1112         if (!init_mali_dvfs_status())
1113                 MALI_DEBUG_PRINT(1, ("mali_platform_init failed\n"));
1114 #endif
1115
1116         mali_platform_power_mode_change(dev, MALI_POWER_MODE_ON);
1117
1118         MALI_SUCCESS;
1119 }
1120
1121 _mali_osk_errcode_t mali_platform_deinit(struct device *dev)
1122 {
1123
1124         mali_platform_power_mode_change(dev, MALI_POWER_MODE_DEEP_SLEEP);
1125         deinit_mali_clock();
1126
1127 #ifdef CONFIG_MALI_DVFS
1128         deinit_mali_dvfs_status();
1129         if (clk_register_map )
1130         {
1131                 _mali_osk_mem_unmapioregion(CLK_DIV_STAT_G3D, 0x20, clk_register_map);
1132                 clk_register_map = NULL;
1133         }
1134 #endif
1135
1136         MALI_SUCCESS;
1137 }
1138
1139 _mali_osk_errcode_t mali_platform_power_mode_change(struct device *dev, mali_power_mode power_mode)
1140 {
1141         switch (power_mode)
1142         {
1143                 case MALI_POWER_MODE_ON:
1144                         MALI_DEBUG_PRINT(3, ("Mali platform: Got MALI_POWER_MODE_ON event, %s\n",
1145                                                                  bPoweroff ? "powering on" : "already on"));
1146                         if (bPoweroff == 1)
1147                         {
1148 #if !defined(CONFIG_PM_RUNTIME)
1149                                 g3d_power_domain_control(1);
1150 #endif
1151                                 MALI_DEBUG_PRINT(4, ("enable clock \n"));
1152                                 enable_mali_clocks();
1153 #if defined(CONFIG_MALI400_PROFILING)
1154                                 _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
1155                                                 MALI_PROFILING_EVENT_CHANNEL_GPU |
1156                                                 MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
1157                                                 mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0);
1158
1159 #endif
1160                                 bPoweroff=0;
1161                         }
1162                         break;
1163                 case MALI_POWER_MODE_LIGHT_SLEEP:
1164                 case MALI_POWER_MODE_DEEP_SLEEP:
1165                         MALI_DEBUG_PRINT(3, ("Mali platform: Got %s event, %s\n", power_mode ==
1166                                                 MALI_POWER_MODE_LIGHT_SLEEP ?  "MALI_POWER_MODE_LIGHT_SLEEP" :
1167                                                 "MALI_POWER_MODE_DEEP_SLEEP", bPoweroff ? "already off" : "powering off"));
1168                         if (bPoweroff == 0)
1169                         {
1170                                 disable_mali_clocks();
1171 #if defined(CONFIG_MALI400_PROFILING)
1172                                 _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
1173                                                 MALI_PROFILING_EVENT_CHANNEL_GPU |
1174                                                 MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
1175                                                 0, 0, 0, 0, 0);
1176 #endif
1177
1178 #if !defined(CONFIG_PM_RUNTIME)
1179                                 g3d_power_domain_control(0);
1180 #endif
1181                                 bPoweroff=1;
1182                         }
1183
1184                         break;
1185         }
1186         MALI_SUCCESS;
1187 }
1188
1189 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
1190 {
1191         if (bPoweroff==0)
1192         {
1193 #ifdef CONFIG_MALI_DVFS
1194                 if(!mali_dvfs_handler(data->utilization_gpu))
1195                         MALI_DEBUG_PRINT(1, ("error on mali dvfs status in utilization\n"));
1196 #endif
1197         }
1198 }
1199
1200 int mali_dvfs_bottom_lock_push(int lock_step)
1201 {
1202         int prev_status = _mali_osk_atomic_read(&bottomlock_status);
1203
1204         if (prev_status < 0) {
1205                 MALI_PRINT(("gpu bottom lock status is not valid for push\n"));
1206                 return -1;
1207         }
1208         if (bottom_lock_step < lock_step) {
1209                 bottom_lock_step = lock_step;
1210                 if (get_mali_dvfs_status() < lock_step) {
1211                         mali_regulator_set_voltage(mali_dvfs[lock_step].vol, mali_dvfs[lock_step].vol);
1212                         mali_clk_set_rate(mali_dvfs[lock_step].clock, mali_dvfs[lock_step].freq);
1213                         set_mali_dvfs_current_step(lock_step);
1214                 }
1215         }
1216         return _mali_osk_atomic_inc_return(&bottomlock_status);
1217 }
1218
1219 int mali_dvfs_bottom_lock_pop(void)
1220 {
1221         int prev_status = _mali_osk_atomic_read(&bottomlock_status);
1222         if (prev_status <= 0) {
1223                 MALI_PRINT(("gpu bottom lock status is not valid for pop\n"));
1224                 return -1;
1225         } else if (prev_status >= 1) {
1226                 bottom_lock_step = 0;
1227                 MALI_PRINT(("gpu bottom lock release\n"));
1228         }
1229
1230         return _mali_osk_atomic_dec_return(&bottomlock_status);
1231 }
1232
1233 int mali_dvfs_get_vol(int step)
1234 {
1235         step = step % MAX_MALI_DVFS_STEPS;
1236         MALI_DEBUG_ASSERT(step<MAX_MALI_DVFS_STEPS);
1237         return mali_dvfs[step].vol;
1238 }
1239
1240 #if MALI_VOLTAGE_LOCK
1241 int mali_voltage_lock_push(int lock_vol)
1242 {
1243         int prev_status = _mali_osk_atomic_read(&voltage_lock_status);
1244
1245         if (prev_status < 0) {
1246                 MALI_PRINT(("gpu voltage lock status is not valid for push\n"));
1247                 return -1;
1248         }
1249         if (prev_status == 0) {
1250                 mali_lock_vol = lock_vol;
1251                 if (mali_gpu_vol < mali_lock_vol)
1252                         mali_regulator_set_voltage(mali_lock_vol, mali_lock_vol);
1253         } else {
1254                 MALI_PRINT(("gpu voltage lock status is already pushed, current lock voltage : %d\n", mali_lock_vol));
1255                 return -1;
1256         }
1257
1258         return _mali_osk_atomic_inc_return(&voltage_lock_status);
1259 }
1260
1261 int mali_voltage_lock_pop(void)
1262 {
1263         if (_mali_osk_atomic_read(&voltage_lock_status) <= 0) {
1264                 MALI_PRINT(("gpu voltage lock status is not valid for pop\n"));
1265                 return -1;
1266         }
1267         return _mali_osk_atomic_dec_return(&voltage_lock_status);
1268 }
1269
1270 int mali_voltage_lock_init(void)
1271 {
1272         mali_vol_lock_flag = MALI_TRUE;
1273
1274         MALI_SUCCESS;
1275 }
1276
1277 int mali_vol_get_from_table(int vol)
1278 {
1279         int i;
1280         for (i = 0; i < MALI_DVFS_STEPS; i++) {
1281                 if (mali_dvfs[i].vol >= vol)
1282                         return mali_dvfs[i].vol;
1283         }
1284         MALI_PRINT(("Failed to get voltage from mali_dvfs table, maximum voltage is %d uV\n", mali_dvfs[MALI_DVFS_STEPS-1].vol));
1285         return 0;
1286 }
1287 #endif
1288
1289 #ifdef CONFIG_MALI_DVFS
1290 static void update_time_in_state(int level)
1291 {
1292         u64 current_time;
1293         static u64 prev_time=0;
1294
1295         if (prev_time ==0)
1296                 prev_time=get_jiffies_64();
1297
1298         current_time = get_jiffies_64();
1299         mali_dvfs_time[level] += current_time-prev_time;
1300         prev_time = current_time;
1301 }
1302
1303 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
1304 {
1305         ssize_t ret = 0;
1306         int i;
1307
1308         update_time_in_state(maliDvfsStatus.currentStep);
1309
1310         for (i = 0; i < MALI_DVFS_STEPS; i++) {
1311                 ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d %llu\n",
1312                                 mali_dvfs[i].clock,
1313                                 mali_dvfs_time[i]);
1314         }
1315
1316         if (ret < PAGE_SIZE - 1) {
1317                 ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
1318         } else {
1319                 buf[PAGE_SIZE-2] = '\n';
1320                 buf[PAGE_SIZE-1] = '\0';
1321                 ret = PAGE_SIZE-1;
1322         }
1323
1324         return ret;
1325 }
1326
1327 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1328 {
1329         int i;
1330
1331         for (i = 0; i < MALI_DVFS_STEPS; i++) {
1332                 mali_dvfs_time[i] = 0;
1333         }
1334
1335         return count;
1336 }
1337 #endif