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