]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx6q14.c
gpu: vivante: Update driver from Freescale 3.10.53-1.1-ga BSP
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / os / linux / kernel / platform / freescale / gc_hal_kernel_platform_imx6q14.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2014 by Vivante Corp.
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the license, or
8 *    (at your option) any later version.
9 *
10 *    This program is distributed in the hope that it will be useful,
11 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 *    GNU General Public License for more details.
14 *
15 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not write to the Free Software
17 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *****************************************************************************/
20
21
22 #include "gc_hal_kernel_linux.h"
23 #include "gc_hal_kernel_platform.h"
24 #include "gc_hal_kernel_device.h"
25 #include "gc_hal_driver.h"
26 #include <linux/slab.h>
27
28 #if USE_PLATFORM_DRIVER
29 #   include <linux/platform_device.h>
30 #endif
31
32 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
33 #include <mach/viv_gpu.h>
34 #else
35 #include <linux/pm_runtime.h>
36 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
37 #include <mach/busfreq.h>
38 #else
39 #include <linux/reset.h>
40 #endif
41 #endif
42
43 #include <linux/clk.h>
44
45 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
46 #include <mach/hardware.h>
47 #endif
48 #include <linux/pm_runtime.h>
49
50 #include <linux/regulator/consumer.h>
51
52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
53 #include <linux/device_cooling.h>
54 #define REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a);
55 #define UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a);
56 #else
57 extern int register_thermal_notifier(struct notifier_block *nb);
58 extern int unregister_thermal_notifier(struct notifier_block *nb);
59 #define REG_THERMAL_NOTIFIER(a) register_thermal_notifier(a);
60 #define UNREG_THERMAL_NOTIFIER(a) unregister_thermal_notifier(a);
61 #endif
62
63 static int initgpu3DMinClock = 1;
64 module_param(initgpu3DMinClock, int, 0644);
65
66 struct platform_device *pdevice;
67
68 #ifdef CONFIG_GPU_LOW_MEMORY_KILLER
69 #    include <linux/kernel.h>
70 #    include <linux/mm.h>
71 #    include <linux/oom.h>
72 #    include <linux/sched.h>
73
74 struct task_struct *lowmem_deathpending;
75
76 static int
77 task_notify_func(struct notifier_block *self, unsigned long val, void *data);
78
79 static struct notifier_block task_nb = {
80         .notifier_call  = task_notify_func,
81 };
82
83 static int
84 task_notify_func(struct notifier_block *self, unsigned long val, void *data)
85 {
86         struct task_struct *task = data;
87
88         if (task == lowmem_deathpending)
89                 lowmem_deathpending = NULL;
90
91         return NOTIFY_OK;
92 }
93
94 extern struct task_struct *lowmem_deathpending;
95 static unsigned long lowmem_deathpending_timeout;
96
97 static int force_contiguous_lowmem_shrink(IN gckKERNEL Kernel)
98 {
99         struct task_struct *p;
100         struct task_struct *selected = NULL;
101         int tasksize;
102         int ret = -1;
103         int min_adj = 0;
104         int selected_tasksize = 0;
105         int selected_oom_adj;
106         /*
107          * If we already have a death outstanding, then
108          * bail out right away; indicating to vmscan
109          * that we have nothing further to offer on
110          * this pass.
111          *
112          */
113         if (lowmem_deathpending &&
114             time_before_eq(jiffies, lowmem_deathpending_timeout))
115                 return 0;
116         selected_oom_adj = min_adj;
117
118        rcu_read_lock();
119         for_each_process(p) {
120                 struct mm_struct *mm;
121                 struct signal_struct *sig;
122                 gcuDATABASE_INFO info;
123                 int oom_adj;
124
125                 task_lock(p);
126                 mm = p->mm;
127                 sig = p->signal;
128                 if (!mm || !sig) {
129                         task_unlock(p);
130                         continue;
131                 }
132                 oom_adj = sig->oom_score_adj;
133                 if (oom_adj < min_adj) {
134                         task_unlock(p);
135                         continue;
136                 }
137
138                 tasksize = 0;
139                 task_unlock(p);
140                rcu_read_unlock();
141
142                 if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_VIDEO_MEMORY, &info) == gcvSTATUS_OK){
143                         tasksize += info.counters.bytes / PAGE_SIZE;
144                 }
145                 if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_CONTIGUOUS, &info) == gcvSTATUS_OK){
146                         tasksize += info.counters.bytes / PAGE_SIZE;
147                 }
148
149                rcu_read_lock();
150
151                 if (tasksize <= 0)
152                         continue;
153
154                 gckOS_Print("<gpu> pid %d (%s), adj %d, size %d \n", p->pid, p->comm, oom_adj, tasksize);
155
156                 if (selected) {
157                         if (oom_adj < selected_oom_adj)
158                                 continue;
159                         if (oom_adj == selected_oom_adj &&
160                             tasksize <= selected_tasksize)
161                                 continue;
162                 }
163                 selected = p;
164                 selected_tasksize = tasksize;
165                 selected_oom_adj = oom_adj;
166         }
167         if (selected) {
168                 gckOS_Print("<gpu> send sigkill to %d (%s), adj %d, size %d\n",
169                              selected->pid, selected->comm,
170                              selected_oom_adj, selected_tasksize);
171                 lowmem_deathpending = selected;
172                 lowmem_deathpending_timeout = jiffies + HZ;
173                 force_sig(SIGKILL, selected);
174                 ret = 0;
175         }
176        rcu_read_unlock();
177         return ret;
178 }
179
180
181 gceSTATUS
182 _ShrinkMemory(
183     IN gckPLATFORM Platform
184     )
185 {
186     struct platform_device *pdev;
187     gckGALDEVICE galDevice;
188     gckKERNEL kernel;
189
190     pdev = Platform->device;
191
192     galDevice = platform_get_drvdata(pdev);
193
194     kernel = galDevice->kernels[gcvCORE_MAJOR];
195
196     if (kernel != gcvNULL)
197     {
198         force_contiguous_lowmem_shrink(kernel);
199     }
200     else
201     {
202         gcmkPRINT("%s(%d) can't find kernel! ", __FUNCTION__, __LINE__);
203     }
204
205     return gcvSTATUS_OK;
206 }
207 #endif
208
209 #if gcdENABLE_FSCALE_VAL_ADJUST
210 static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
211        void *dummy)
212 {
213     static gctUINT orgFscale, minFscale, maxFscale;
214     static gctBOOL bAlreadyTooHot = gcvFALSE;
215     gckHARDWARE hardware;
216     gckGALDEVICE galDevice;
217
218     galDevice = platform_get_drvdata(pdevice);
219     if (!galDevice)
220     {
221         /* GPU is not ready, so it is meaningless to change GPU freq. */
222         return NOTIFY_OK;
223     }
224
225     if (!galDevice->kernels[gcvCORE_MAJOR])
226     {
227         return NOTIFY_OK;
228     }
229
230     hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;
231
232     if (!hardware)
233     {
234         return NOTIFY_OK;
235     }
236
237     if (event && !bAlreadyTooHot) {
238         gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
239         gckHARDWARE_SetFscaleValue(hardware, minFscale);
240         bAlreadyTooHot = gcvTRUE;
241         gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
242     } else if (!event && bAlreadyTooHot) {
243         gckHARDWARE_SetFscaleValue(hardware, orgFscale);
244         gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
245         bAlreadyTooHot = gcvFALSE;
246     }
247     return NOTIFY_OK;
248 }
249
250 static struct notifier_block thermal_hot_pm_notifier = {
251     .notifier_call = thermal_hot_pm_notify,
252     };
253
254 static ssize_t show_gpu3DMinClock(struct device_driver *dev, char *buf)
255 {
256     gctUINT currentf,minf,maxf;
257     gckGALDEVICE galDevice;
258
259     galDevice = platform_get_drvdata(pdevice);
260     if(galDevice->kernels[gcvCORE_MAJOR])
261     {
262          gckHARDWARE_GetFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,
263             &currentf, &minf, &maxf);
264     }
265     snprintf(buf, PAGE_SIZE, "%d\n", minf);
266     return strlen(buf);
267 }
268
269 static ssize_t update_gpu3DMinClock(struct device_driver *dev, const char *buf, size_t count)
270 {
271
272     gctINT fields;
273     gctUINT MinFscaleValue;
274     gckGALDEVICE galDevice;
275
276     galDevice = platform_get_drvdata(pdevice);
277     if(galDevice->kernels[gcvCORE_MAJOR])
278     {
279          fields = sscanf(buf, "%d", &MinFscaleValue);
280          if (fields < 1)
281              return -EINVAL;
282
283          gckHARDWARE_SetMinFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,MinFscaleValue);
284     }
285
286     return count;
287 }
288
289 static DRIVER_ATTR(gpu3DMinClock, S_IRUGO | S_IWUSR, show_gpu3DMinClock, update_gpu3DMinClock);
290 #endif
291
292
293
294
295 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
296 static const struct of_device_id mxs_gpu_dt_ids[] = {
297     { .compatible = "fsl,imx6q-gpu", },
298     {/* sentinel */}
299 };
300 MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids);
301 #endif
302
303
304 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
305 struct contiguous_mem_pool {
306     struct dma_attrs attrs;
307     dma_addr_t phys;
308     void *virt;
309     size_t size;
310 };
311 #endif
312
313 struct imx_priv {
314     /* Clock management.*/
315     struct clk         *clk_3d_core;
316     struct clk         *clk_3d_shader;
317     struct clk         *clk_3d_axi;
318     struct clk         *clk_2d_core;
319     struct clk         *clk_2d_axi;
320     struct clk         *clk_vg_axi;
321
322 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
323 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
324     /*Power management.*/
325     struct regulator      *gpu_regulator;
326 #endif
327 #endif
328        /*Run time pm*/
329        struct device           *pmdev;
330 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
331     struct contiguous_mem_pool *pool;
332     struct reset_control *rstc[gcdMAX_GPU_COUNT];
333 #endif
334 };
335
336 static struct imx_priv imxPriv;
337
338 gceSTATUS
339 gckPLATFORM_AdjustParam(
340     IN gckPLATFORM Platform,
341     OUT gcsMODULE_PARAMETERS *Args
342     )
343 {
344      struct resource* res;
345      struct platform_device* pdev = Platform->device;
346 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
347 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
348        struct device_node *dn =pdev->dev.of_node;
349        const u32 *prop;
350 #else
351        struct viv_gpu_platform_data *pdata;
352 #endif
353
354     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
355     if (res)
356         Args->baseAddress = res->start;
357
358     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
359     if (res)
360         Args->irqLine = res->start;
361
362     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
363     if (res)
364     {
365         Args->registerMemBase = res->start;
366         Args->registerMemSize = res->end - res->start + 1;
367     }
368
369     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
370     if (res)
371         Args->irqLine2D = res->start;
372
373     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
374     if (res)
375     {
376         Args->registerMemBase2D = res->start;
377         Args->registerMemSize2D = res->end - res->start + 1;
378     }
379
380     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
381     if (res)
382         Args->irqLineVG = res->start;
383
384     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
385     if (res)
386     {
387         Args->registerMemBaseVG = res->start;
388         Args->registerMemSizeVG = res->end - res->start + 1;
389     }
390
391 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
392        Args->contiguousBase = 0;
393 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
394        prop = of_get_property(dn, "contiguousbase", NULL);
395        if(prop)
396                Args->contiguousBase = *prop;
397        of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
398 #else
399     pdata = pdev->dev.platform_data;
400     if (pdata) {
401         Args->contiguousBase = pdata->reserved_mem_base;
402        Args->contiguousSize = pdata->reserved_mem_size;
403      }
404 #endif
405     if (Args->contiguousSize == 0)
406        gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n ");
407
408     Args->gpu3DMinClock = initgpu3DMinClock;
409
410     return gcvSTATUS_OK;
411 }
412
413 gceSTATUS
414 _AllocPriv(
415     IN gckPLATFORM Platform
416     )
417 {
418     Platform->priv = &imxPriv;
419
420 #ifdef CONFIG_GPU_LOW_MEMORY_KILLER
421     task_free_register(&task_nb);
422 #endif
423
424     return gcvSTATUS_OK;
425 }
426
427 gceSTATUS
428 _FreePriv(
429     IN gckPLATFORM Platform
430     )
431 {
432 #ifdef CONFIG_GPU_LOW_MEMORY_KILLER
433     task_free_unregister(&task_nb);
434 #endif
435
436     return gcvSTATUS_OK;
437 }
438
439 gceSTATUS
440 _GetPower(
441     IN gckPLATFORM Platform
442     )
443 {
444     struct device* pdev = &Platform->device->dev;
445     struct imx_priv *priv = Platform->priv;
446 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
447     struct reset_control *rstc;
448 #endif
449
450 #ifdef CONFIG_PM
451     /*Init runtime pm for gpu*/
452     pm_runtime_enable(pdev);
453     priv->pmdev = pdev;
454 #endif
455
456
457 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
458     rstc = devm_reset_control_get(pdev, "gpu3d");
459     priv->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc;
460     rstc = devm_reset_control_get(pdev, "gpu2d");
461     priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
462     rstc = devm_reset_control_get(pdev, "gpuvg");
463     priv->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc;
464 #endif
465
466 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
467 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
468     /*get gpu regulator*/
469     priv->gpu_regulator = regulator_get(pdev, "cpu_vddgpu");
470 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
471     priv->gpu_regulator = devm_regulator_get(pdev, "pu");
472 #endif
473 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
474     if (IS_ERR(priv->gpu_regulator)) {
475        gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER,
476                "%s(%d): Failed to get gpu regulator \n",
477                __FUNCTION__, __LINE__);
478        return gcvSTATUS_NOT_FOUND;
479     }
480 #endif
481 #endif
482
483     /*Initialize the clock structure*/
484     priv->clk_3d_core = clk_get(pdev, "gpu3d_clk");
485     if (!IS_ERR(priv->clk_3d_core)) {
486 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
487         if (cpu_is_mx6q()) {
488                priv->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk");
489                if (IS_ERR(priv->clk_3d_shader)) {
490                    clk_put(priv->clk_3d_core);
491                    priv->clk_3d_core = NULL;
492                    priv->clk_3d_shader = NULL;
493                    gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
494                }
495              }
496 #else
497                priv->clk_3d_axi = clk_get(pdev, "gpu3d_axi_clk");
498                priv->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk");
499                if (IS_ERR(priv->clk_3d_shader)) {
500                    clk_put(priv->clk_3d_core);
501                    priv->clk_3d_core = NULL;
502                    priv->clk_3d_shader = NULL;
503                    gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
504                }
505 #endif
506     } else {
507         priv->clk_3d_core = NULL;
508         gckOS_Print("galcore: clk_get gpu3d_clk failed, disable 3d!\n");
509     }
510
511     priv->clk_2d_core = clk_get(pdev, "gpu2d_clk");
512     if (IS_ERR(priv->clk_2d_core)) {
513         priv->clk_2d_core = NULL;
514         gckOS_Print("galcore: clk_get 2d core clock failed, disable 2d/vg!\n");
515     } else {
516         priv->clk_2d_axi = clk_get(pdev, "gpu2d_axi_clk");
517         if (IS_ERR(priv->clk_2d_axi)) {
518             priv->clk_2d_axi = NULL;
519             gckOS_Print("galcore: clk_get 2d axi clock failed, disable 2d\n");
520         }
521
522         priv->clk_vg_axi = clk_get(pdev, "openvg_axi_clk");
523         if (IS_ERR(priv->clk_vg_axi)) {
524                priv->clk_vg_axi = NULL;
525                gckOS_Print("galcore: clk_get vg clock failed, disable vg!\n");
526         }
527     }
528
529
530 #if gcdENABLE_FSCALE_VAL_ADJUST
531     pdevice = Platform->device;
532     REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
533     {
534         int ret = 0;
535         ret = driver_create_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock);
536         if(ret)
537             dev_err(&pdevice->dev, "create gpu3DMinClock attr failed (%d)\n", ret);
538     }
539 #endif
540
541     return gcvSTATUS_OK;
542 }
543
544 gceSTATUS
545 _PutPower(
546     IN gckPLATFORM Platform
547     )
548 {
549     struct imx_priv *priv = Platform->priv;
550
551     /*Disable clock*/
552 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
553     if (priv->clk_3d_axi) {
554        clk_put(priv->clk_3d_axi);
555        priv->clk_3d_axi = NULL;
556     }
557 #endif
558     if (priv->clk_3d_core) {
559        clk_put(priv->clk_3d_core);
560        priv->clk_3d_core = NULL;
561     }
562     if (priv->clk_3d_shader) {
563        clk_put(priv->clk_3d_shader);
564        priv->clk_3d_shader = NULL;
565     }
566     if (priv->clk_2d_core) {
567        clk_put(priv->clk_2d_core);
568        priv->clk_2d_core = NULL;
569     }
570     if (priv->clk_2d_axi) {
571        clk_put(priv->clk_2d_axi);
572        priv->clk_2d_axi = NULL;
573     }
574     if (priv->clk_vg_axi) {
575        clk_put(priv->clk_vg_axi);
576        priv->clk_vg_axi = NULL;
577     }
578
579 #ifdef CONFIG_PM
580     if(priv->pmdev)
581         pm_runtime_disable(priv->pmdev);
582 #endif
583
584 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
585     if (priv->gpu_regulator) {
586        regulator_put(priv->gpu_regulator);
587        priv->gpu_regulator = NULL;
588     }
589 #endif
590
591 #if gcdENABLE_FSCALE_VAL_ADJUST
592     UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
593
594     driver_remove_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock);
595 #endif
596
597     return gcvSTATUS_OK;
598 }
599
600 gceSTATUS
601 _SetPower(
602     IN gckPLATFORM Platform,
603     IN gceCORE GPU,
604     IN gctBOOL Enable
605     )
606 {
607     struct imx_priv* priv = Platform->priv;
608 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
609 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
610     int ret;
611 #endif
612 #endif
613
614     if (Enable)
615     {
616 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
617 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
618         if(!IS_ERR(priv->gpu_regulator)) {
619             ret = regulator_enable(priv->gpu_regulator);
620             if (ret != 0)
621                 gckOS_Print("%s(%d): fail to enable pu regulator %d!\n",
622                     __FUNCTION__, __LINE__, ret);
623         }
624 #else
625         imx_gpc_power_up_pu(true);
626 #endif
627 #endif
628
629 #ifdef CONFIG_PM
630                 pm_runtime_get_sync(priv->pmdev);
631 #endif
632         }
633     else
634     {
635 #ifdef CONFIG_PM
636         pm_runtime_put_sync(priv->pmdev);
637 #endif
638
639 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
640 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
641         if(!IS_ERR(priv->gpu_regulator))
642             regulator_disable(priv->gpu_regulator);
643 #else
644         imx_gpc_power_up_pu(false);
645 #endif
646 #endif
647
648     }
649
650     return gcvSTATUS_OK;
651 }
652
653 gceSTATUS
654 _SetClock(
655     IN gckPLATFORM Platform,
656     IN gceCORE GPU,
657     IN gctBOOL Enable
658     )
659 {
660     struct imx_priv* priv = Platform->priv;
661     struct clk *clk_3dcore = priv->clk_3d_core;
662     struct clk *clk_3dshader = priv->clk_3d_shader;
663 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
664     struct clk *clk_3d_axi = priv->clk_3d_axi;
665 #endif
666     struct clk *clk_2dcore = priv->clk_2d_core;
667     struct clk *clk_2d_axi = priv->clk_2d_axi;
668     struct clk *clk_vg_axi = priv->clk_vg_axi;
669
670
671 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
672     if (Enable) {
673         switch (GPU) {
674         case gcvCORE_MAJOR:
675             clk_enable(clk_3dcore);
676             if (cpu_is_mx6q())
677                 clk_enable(clk_3dshader);
678             break;
679         case gcvCORE_2D:
680             clk_enable(clk_2dcore);
681             clk_enable(clk_2d_axi);
682             break;
683         case gcvCORE_VG:
684             clk_enable(clk_2dcore);
685             clk_enable(clk_vg_axi);
686             break;
687         default:
688             break;
689         }
690     } else {
691         switch (GPU) {
692         case gcvCORE_MAJOR:
693             if (cpu_is_mx6q())
694                 clk_disable(clk_3dshader);
695             clk_disable(clk_3dcore);
696             break;
697        case gcvCORE_2D:
698             clk_disable(clk_2dcore);
699             clk_disable(clk_2d_axi);
700             break;
701         case gcvCORE_VG:
702             clk_disable(clk_2dcore);
703             clk_disable(clk_vg_axi);
704             break;
705         default:
706             break;
707         }
708     }
709 #else
710     if (Enable) {
711         switch (GPU) {
712         case gcvCORE_MAJOR:
713             clk_prepare(clk_3dcore);
714             clk_enable(clk_3dcore);
715             clk_prepare(clk_3dshader);
716             clk_enable(clk_3dshader);
717             clk_prepare(clk_3d_axi);
718             clk_enable(clk_3d_axi);
719             break;
720         case gcvCORE_2D:
721             clk_prepare(clk_2dcore);
722             clk_enable(clk_2dcore);
723             clk_prepare(clk_2d_axi);
724             clk_enable(clk_2d_axi);
725             break;
726         case gcvCORE_VG:
727             clk_prepare(clk_2dcore);
728             clk_enable(clk_2dcore);
729             clk_prepare(clk_vg_axi);
730             clk_enable(clk_vg_axi);
731             break;
732         default:
733             break;
734         }
735     } else {
736         switch (GPU) {
737         case gcvCORE_MAJOR:
738             clk_disable(clk_3dshader);
739             clk_unprepare(clk_3dshader);
740             clk_disable(clk_3dcore);
741             clk_unprepare(clk_3dcore);
742             clk_disable(clk_3d_axi);
743             clk_unprepare(clk_3d_axi);
744             break;
745        case gcvCORE_2D:
746             clk_disable(clk_2dcore);
747             clk_unprepare(clk_2dcore);
748             clk_disable(clk_2d_axi);
749             clk_unprepare(clk_2d_axi);
750             break;
751         case gcvCORE_VG:
752             clk_disable(clk_2dcore);
753             clk_unprepare(clk_2dcore);
754             clk_disable(clk_vg_axi);
755             clk_unprepare(clk_vg_axi);
756             break;
757         default:
758             break;
759         }
760     }
761 #endif
762
763     return gcvSTATUS_OK;
764 }
765
766 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
767 #ifdef CONFIG_PM
768 static int gpu_runtime_suspend(struct device *dev)
769 {
770     return 0;
771 }
772
773 static int gpu_runtime_resume(struct device *dev)
774 {
775     return 0;
776 }
777
778 static struct dev_pm_ops gpu_pm_ops;
779 #endif
780 #endif
781
782 gceSTATUS
783 _AdjustDriver(
784     IN gckPLATFORM Platform
785     )
786 {
787 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
788     struct platform_driver * driver = Platform->driver;
789 #endif
790
791 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
792     driver->driver.of_match_table = mxs_gpu_dt_ids;
793 #endif
794
795     /* Override PM callbacks to add runtime PM callbacks. */
796 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
797     /* Fill local structure with original value. */
798     memcpy(&gpu_pm_ops, driver->driver.pm, sizeof(struct dev_pm_ops));
799
800     /* Add runtime PM callback. */
801 #ifdef CONFIG_PM_RUNTIME
802     gpu_pm_ops.runtime_suspend = gpu_runtime_suspend;
803     gpu_pm_ops.runtime_resume = gpu_runtime_resume;
804     gpu_pm_ops.runtime_idle = NULL;
805 #endif
806
807     /* Replace callbacks. */
808     driver->driver.pm = &gpu_pm_ops;
809 #endif
810     return gcvSTATUS_OK;
811 }
812
813 gceSTATUS
814 _Reset(
815     IN gckPLATFORM Platform,
816     gceCORE GPU
817     )
818 {
819 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
820 #define SRC_SCR_OFFSET 0
821 #define BP_SRC_SCR_GPU3D_RST 1
822 #define BP_SRC_SCR_GPU2D_RST 4
823     void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR);
824     gctUINT32 bit_offset,val;
825
826     if(GPU == gcvCORE_MAJOR) {
827         bit_offset = BP_SRC_SCR_GPU3D_RST;
828     } else if((GPU == gcvCORE_VG)
829             ||(GPU == gcvCORE_2D)) {
830         bit_offset = BP_SRC_SCR_GPU2D_RST;
831     } else {
832         return gcvSTATUS_INVALID_CONFIG;
833     }
834     val = __raw_readl(src_base + SRC_SCR_OFFSET);
835     val &= ~(1 << (bit_offset));
836     val |= (1 << (bit_offset));
837     __raw_writel(val, src_base + SRC_SCR_OFFSET);
838
839     while ((__raw_readl(src_base + SRC_SCR_OFFSET) &
840                 (1 << (bit_offset))) != 0) {
841     }
842
843     return gcvSTATUS_NOT_SUPPORTED;
844 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
845     struct imx_priv* priv = Platform->priv;
846     struct reset_control *rstc = priv->rstc[GPU];
847     if (rstc)
848         reset_control_reset(rstc);
849 #else
850     imx_src_reset_gpu((int)GPU);
851 #endif
852     return gcvSTATUS_OK;
853 }
854
855 gcsPLATFORM_OPERATIONS platformOperations = {
856     .adjustParam  = gckPLATFORM_AdjustParam,
857     .allocPriv    = _AllocPriv,
858     .freePriv     = _FreePriv,
859     .getPower     = _GetPower,
860     .putPower     = _PutPower,
861     .setPower     = _SetPower,
862     .setClock     = _SetClock,
863     .adjustDriver = _AdjustDriver,
864     .reset        = _Reset,
865 #ifdef CONFIG_GPU_LOW_MEMORY_KILLER
866     .shrinkMemory = _ShrinkMemory,
867 #endif
868 };
869
870 void
871 gckPLATFORM_QueryOperations(
872     IN gcsPLATFORM_OPERATIONS ** Operations
873     )
874 {
875      *Operations = &platformOperations;
876 }
877