]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
9d9dc57a78d2cc8d6cf945283a1b609cd007d108
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / os / linux / kernel / gc_hal_kernel_driver.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2013 by Vivante Corp.
4 *    Copyright (C) 2011-2012 Freescale Semiconductor, Inc.
5 *
6 *    This program is free software; you can redistribute it and/or modify
7 *    it under the terms of the GNU General Public License as published by
8 *    the Free Software Foundation; either version 2 of the license, or
9 *    (at your option) any later version.
10 *
11 *    This program is distributed in the hope that it will be useful,
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *    GNU General Public License for more details.
15 *
16 *    You should have received a copy of the GNU General Public License
17 *    along with this program; if not write to the Free Software
18 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 *****************************************************************************/
21
22
23 #include <linux/device.h>
24 #include <linux/slab.h>
25 #include <linux/notifier.h>
26 #include "gc_hal_kernel_linux.h"
27 #include "gc_hal_driver.h"
28
29 #if USE_PLATFORM_DRIVER
30 #   include <linux/platform_device.h>
31 #endif
32
33 #ifdef CONFIG_PXA_DVFM
34 #   include <mach/dvfm.h>
35 #   include <mach/pxa3xx_dvfm.h>
36 #endif
37
38
39 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
40 #    include <linux/resmem_account.h>
41 #    include <linux/kernel.h>
42 #    include <linux/mm.h>
43 #    include <linux/oom.h>
44 #    include <linux/sched.h>
45 #    include <linux/notifier.h>
46
47 struct task_struct *lowmem_deathpending;
48
49 static int
50 task_notify_func(struct notifier_block *self, unsigned long val, void *data);
51
52 static struct notifier_block task_nb = {
53         .notifier_call  = task_notify_func,
54 };
55
56 static int
57 task_notify_func(struct notifier_block *self, unsigned long val, void *data)
58 {
59         struct task_struct *task = data;
60
61         if (task == lowmem_deathpending)
62                 lowmem_deathpending = NULL;
63
64         return NOTIFY_OK;
65 }
66 #endif
67
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
69 #include <mach/viv_gpu.h>
70 #else
71 #include <linux/pm_runtime.h>
72 #include <mach/busfreq.h>
73 #endif
74 /* Zone used for header/footer. */
75 #define _GC_OBJ_ZONE    gcvZONE_DRIVER
76
77 #if gcdENABLE_FSCALE_VAL_ADJUST
78 extern int register_thermal_notifier(struct notifier_block *nb);
79 extern int unregister_thermal_notifier(struct notifier_block *nb);
80 #endif
81
82 MODULE_DESCRIPTION("Vivante Graphics Driver");
83 MODULE_LICENSE("GPL");
84
85 static struct class* gpuClass;
86
87 static gckGALDEVICE galDevice;
88
89 static uint major = 199;
90 module_param(major, uint, 0644);
91
92 static int irqLine = -1;
93 module_param(irqLine, int, 0644);
94
95 static ulong registerMemBase = 0x80000000;
96 module_param(registerMemBase, ulong, 0644);
97
98 static ulong registerMemSize = 2 << 10;
99 module_param(registerMemSize, ulong, 0644);
100
101 static int irqLine2D = -1;
102 module_param(irqLine2D, int, 0644);
103
104 static ulong registerMemBase2D = 0x00000000;
105 module_param(registerMemBase2D, ulong, 0644);
106
107 static ulong registerMemSize2D = 2 << 10;
108 module_param(registerMemSize2D, ulong, 0644);
109
110 static int irqLineVG = -1;
111 module_param(irqLineVG, int, 0644);
112
113 static ulong registerMemBaseVG = 0x00000000;
114 module_param(registerMemBaseVG, ulong, 0644);
115
116 static ulong registerMemSizeVG = 2 << 10;
117 module_param(registerMemSizeVG, ulong, 0644);
118
119 static ulong contiguousSize = 4 << 20;
120 module_param(contiguousSize, ulong, 0644);
121
122 static ulong contiguousBase = 0;
123 module_param(contiguousBase, ulong, 0644);
124
125 static ulong bankSize = 0;
126 module_param(bankSize, ulong, 0644);
127
128 static int fastClear = -1;
129 module_param(fastClear, int, 0644);
130
131 static int compression = -1;
132 module_param(compression, int, 0644);
133
134 static int powerManagement = 1;
135 module_param(powerManagement, int, 0644);
136
137 static int signal = 48;
138 module_param(signal, int, 0644);
139
140 static ulong baseAddress = 0;
141 module_param(baseAddress, ulong, 0644);
142
143 static ulong physSize = 0;
144 module_param(physSize, ulong, 0644);
145
146 static uint logFileSize=0;
147 module_param(logFileSize,uint, 0644);
148
149 static int showArgs = 0;
150 module_param(showArgs, int, 0644);
151
152 int gpu3DMinClock = 0;
153 module_param(gpu3DMinClock, int, 0644);
154
155 #if ENABLE_GPU_CLOCK_BY_DRIVER
156     unsigned long coreClock = 156000000;
157     module_param(coreClock, ulong, 0644);
158 #endif
159
160 static int drv_open(
161     struct inode* inode,
162     struct file* filp
163     );
164
165 static int drv_release(
166     struct inode* inode,
167     struct file* filp
168     );
169
170 static long drv_ioctl(
171     struct file* filp,
172     unsigned int ioctlCode,
173     unsigned long arg
174     );
175
176 static int drv_mmap(
177     struct file* filp,
178     struct vm_area_struct* vma
179     );
180
181 static struct file_operations driver_fops =
182 {
183     .owner      = THIS_MODULE,
184     .open       = drv_open,
185     .release    = drv_release,
186     .unlocked_ioctl = drv_ioctl,
187 #ifdef HAVE_COMPAT_IOCTL
188     .compat_ioctl = drv_ioctl,
189 #endif
190     .mmap       = drv_mmap,
191 };
192
193 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
194 static size_t viv_gpu_resmem_query(struct task_struct *p, struct reserved_memory_account *m);
195 static struct reserved_memory_account viv_gpu_resmem_handler = {
196     .name = "viv_gpu",
197     .get_page_used_by_process = viv_gpu_resmem_query,
198 };
199
200 size_t viv_gpu_resmem_query(struct task_struct *p, struct reserved_memory_account *m)
201 {
202     gcuDATABASE_INFO info;
203     unsigned int processid = p->pid;
204     gckKERNEL gpukernel = m->data;
205
206     /* ignore error happens in this api. */
207     if (gckKERNEL_QueryProcessDB(gpukernel, processid, false, gcvDB_VIDEO_MEMORY, &info) != gcvSTATUS_OK)
208         return 0;
209
210     /* we return pages. */
211     if (info.counters.bytes > 0)
212         return info.counters.bytes / PAGE_SIZE;
213     return 0;
214 }
215 #endif
216
217 int drv_open(
218     struct inode* inode,
219     struct file* filp
220     )
221 {
222     gceSTATUS status;
223     gctBOOL attached = gcvFALSE;
224     gcsHAL_PRIVATE_DATA_PTR data = gcvNULL;
225     gctINT i;
226
227     gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
228
229     if (filp == gcvNULL)
230     {
231         gcmkTRACE_ZONE(
232             gcvLEVEL_ERROR, gcvZONE_DRIVER,
233             "%s(%d): filp is NULL\n",
234             __FUNCTION__, __LINE__
235             );
236
237         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
238     }
239
240     data = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN);
241
242     if (data == gcvNULL)
243     {
244         gcmkTRACE_ZONE(
245             gcvLEVEL_ERROR, gcvZONE_DRIVER,
246             "%s(%d): private_data is NULL\n",
247             __FUNCTION__, __LINE__
248             );
249
250         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
251     }
252
253     data->device             = galDevice;
254     data->mappedMemory       = gcvNULL;
255     data->contiguousLogical  = gcvNULL;
256     gcmkONERROR(gckOS_GetProcessID(&data->pidOpen));
257
258     /* Attached the process. */
259     for (i = 0; i < gcdMAX_GPU_COUNT; i++)
260     {
261         if (galDevice->kernels[i] != gcvNULL)
262         {
263             gcmkONERROR(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE));
264         }
265     }
266     attached = gcvTRUE;
267
268     if (!galDevice->contiguousMapped)
269     {
270         gcmkONERROR(gckOS_MapMemory(
271             galDevice->os,
272             galDevice->contiguousPhysical,
273             galDevice->contiguousSize,
274             &data->contiguousLogical
275             ));
276     }
277
278     filp->private_data = data;
279
280     /* Success. */
281     gcmkFOOTER_NO();
282     return 0;
283
284 OnError:
285     if (data != gcvNULL)
286     {
287         if (data->contiguousLogical != gcvNULL)
288         {
289             gcmkVERIFY_OK(gckOS_UnmapMemory(
290                 galDevice->os,
291                 galDevice->contiguousPhysical,
292                 galDevice->contiguousSize,
293                 data->contiguousLogical
294                 ));
295         }
296
297         kfree(data);
298     }
299
300     if (attached)
301     {
302         for (i = 0; i < gcdMAX_GPU_COUNT; i++)
303         {
304             if (galDevice->kernels[i] != gcvNULL)
305             {
306                 gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE));
307             }
308         }
309     }
310
311     gcmkFOOTER();
312     return -ENOTTY;
313 }
314
315 int drv_release(
316     struct inode* inode,
317     struct file* filp
318     )
319 {
320     gceSTATUS status;
321     gcsHAL_PRIVATE_DATA_PTR data;
322     gckGALDEVICE device;
323     gctINT i;
324
325     gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
326
327     if (filp == gcvNULL)
328     {
329         gcmkTRACE_ZONE(
330             gcvLEVEL_ERROR, gcvZONE_DRIVER,
331             "%s(%d): filp is NULL\n",
332             __FUNCTION__, __LINE__
333             );
334
335         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
336     }
337
338     data = filp->private_data;
339
340     if (data == gcvNULL)
341     {
342         gcmkTRACE_ZONE(
343             gcvLEVEL_ERROR, gcvZONE_DRIVER,
344             "%s(%d): private_data is NULL\n",
345             __FUNCTION__, __LINE__
346             );
347
348         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
349     }
350
351     device = data->device;
352
353     if (device == gcvNULL)
354     {
355         gcmkTRACE_ZONE(
356             gcvLEVEL_ERROR, gcvZONE_DRIVER,
357             "%s(%d): device is NULL\n",
358             __FUNCTION__, __LINE__
359             );
360
361         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
362     }
363
364     if (!device->contiguousMapped)
365     {
366         if (data->contiguousLogical != gcvNULL)
367         {
368             gcmkONERROR(gckOS_UnmapMemoryEx(
369                 galDevice->os,
370                 galDevice->contiguousPhysical,
371                 galDevice->contiguousSize,
372                 data->contiguousLogical,
373                 data->pidOpen
374                 ));
375
376             data->contiguousLogical = gcvNULL;
377         }
378     }
379
380     /* A process gets detached. */
381     for (i = 0; i < gcdMAX_GPU_COUNT; i++)
382     {
383         if (galDevice->kernels[i] != gcvNULL)
384         {
385             gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen));
386         }
387     }
388
389     kfree(data);
390     filp->private_data = NULL;
391
392     /* Success. */
393     gcmkFOOTER_NO();
394     return 0;
395
396 OnError:
397     gcmkFOOTER();
398     return -ENOTTY;
399 }
400
401 long drv_ioctl(
402     struct file* filp,
403     unsigned int ioctlCode,
404     unsigned long arg
405     )
406 {
407     gceSTATUS status;
408     gcsHAL_INTERFACE iface;
409     gctUINT32 copyLen;
410     DRIVER_ARGS drvArgs;
411     gckGALDEVICE device;
412     gcsHAL_PRIVATE_DATA_PTR data;
413     gctINT32 i, count;
414
415     gcmkHEADER_ARG(
416         "filp=0x%08X ioctlCode=0x%08X arg=0x%08X",
417         filp, ioctlCode, arg
418         );
419
420     if (filp == gcvNULL)
421     {
422         gcmkTRACE_ZONE(
423             gcvLEVEL_ERROR, gcvZONE_DRIVER,
424             "%s(%d): filp is NULL\n",
425             __FUNCTION__, __LINE__
426             );
427
428         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
429     }
430
431     data = filp->private_data;
432
433     if (data == gcvNULL)
434     {
435         gcmkTRACE_ZONE(
436             gcvLEVEL_ERROR, gcvZONE_DRIVER,
437             "%s(%d): private_data is NULL\n",
438             __FUNCTION__, __LINE__
439             );
440
441         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
442     }
443
444     device = data->device;
445
446     if (device == gcvNULL)
447     {
448         gcmkTRACE_ZONE(
449             gcvLEVEL_ERROR, gcvZONE_DRIVER,
450             "%s(%d): device is NULL\n",
451             __FUNCTION__, __LINE__
452             );
453
454         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
455     }
456
457     if ((ioctlCode != IOCTL_GCHAL_INTERFACE)
458     &&  (ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE)
459     )
460     {
461         gcmkTRACE_ZONE(
462             gcvLEVEL_ERROR, gcvZONE_DRIVER,
463             "%s(%d): unknown command %d\n",
464             __FUNCTION__, __LINE__,
465             ioctlCode
466             );
467
468         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
469     }
470
471     /* Get the drvArgs. */
472     copyLen = copy_from_user(
473         &drvArgs, (void *) arg, sizeof(DRIVER_ARGS)
474         );
475
476     if (copyLen != 0)
477     {
478         gcmkTRACE_ZONE(
479             gcvLEVEL_ERROR, gcvZONE_DRIVER,
480             "%s(%d): error copying of the input arguments.\n",
481             __FUNCTION__, __LINE__
482             );
483
484         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
485     }
486
487     /* Now bring in the gcsHAL_INTERFACE structure. */
488     if ((drvArgs.InputBufferSize  != sizeof(gcsHAL_INTERFACE))
489     ||  (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE))
490     )
491     {
492         gcmkTRACE_ZONE(
493             gcvLEVEL_ERROR, gcvZONE_DRIVER,
494             "%s(%d): input or/and output structures are invalid.\n",
495             __FUNCTION__, __LINE__
496             );
497
498         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
499     }
500
501     copyLen = copy_from_user(
502         &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE)
503         );
504
505     if (copyLen != 0)
506     {
507         gcmkTRACE_ZONE(
508             gcvLEVEL_ERROR, gcvZONE_DRIVER,
509             "%s(%d): error copying of input HAL interface.\n",
510             __FUNCTION__, __LINE__
511             );
512
513         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
514     }
515
516     if (iface.command == gcvHAL_CHIP_INFO)
517     {
518         count = 0;
519         for (i = 0; i < gcdMAX_GPU_COUNT; i++)
520         {
521             if (device->kernels[i] != gcvNULL)
522             {
523 #if gcdENABLE_VG
524                 if (i == gcvCORE_VG)
525                 {
526                     iface.u.ChipInfo.types[count] = gcvHARDWARE_VG;
527                 }
528                 else
529 #endif
530                 {
531                     gcmkVERIFY_OK(gckHARDWARE_GetType(device->kernels[i]->hardware,
532                                                       &iface.u.ChipInfo.types[count]));
533                 }
534                 count++;
535             }
536         }
537
538         iface.u.ChipInfo.count = count;
539         iface.status = status = gcvSTATUS_OK;
540     }
541     else
542     {
543         if (iface.hardwareType < 0 || iface.hardwareType > 7)
544         {
545             gcmkTRACE_ZONE(
546                 gcvLEVEL_ERROR, gcvZONE_DRIVER,
547                 "%s(%d): unknown hardwareType %d\n",
548                 __FUNCTION__, __LINE__,
549                 iface.hardwareType
550                 );
551
552             gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
553         }
554
555 #if gcdENABLE_VG
556         if (device->coreMapping[iface.hardwareType] == gcvCORE_VG)
557         {
558             status = gckVGKERNEL_Dispatch(device->kernels[gcvCORE_VG],
559                                         (ioctlCode == IOCTL_GCHAL_INTERFACE),
560                                         &iface);
561         }
562         else
563 #endif
564         {
565             status = gckKERNEL_Dispatch(device->kernels[device->coreMapping[iface.hardwareType]],
566                                         (ioctlCode == IOCTL_GCHAL_INTERFACE),
567                                         &iface);
568         }
569     }
570
571     /* Redo system call after pending signal is handled. */
572     if (status == gcvSTATUS_INTERRUPTED)
573     {
574         gcmkFOOTER();
575         return -ERESTARTSYS;
576     }
577
578     if (gcmIS_SUCCESS(status) && (iface.command == gcvHAL_LOCK_VIDEO_MEMORY))
579     {
580         gcuVIDMEM_NODE_PTR node = gcmUINT64_TO_PTR(iface.u.LockVideoMemory.node);
581         /* Special case for mapped memory. */
582         if ((data->mappedMemory != gcvNULL)
583         &&  (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
584         )
585         {
586             /* Compute offset into mapped memory. */
587             gctUINT32 offset
588                 = (gctUINT8 *) gcmUINT64_TO_PTR(iface.u.LockVideoMemory.memory)
589                 - (gctUINT8 *) device->contiguousBase;
590
591             /* Compute offset into user-mapped region. */
592             iface.u.LockVideoMemory.memory =
593                 gcmPTR_TO_UINT64((gctUINT8 *) data->mappedMemory + offset);
594         }
595     }
596
597     /* Copy data back to the user. */
598     copyLen = copy_to_user(
599         gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE)
600         );
601
602     if (copyLen != 0)
603     {
604         gcmkTRACE_ZONE(
605             gcvLEVEL_ERROR, gcvZONE_DRIVER,
606             "%s(%d): error copying of output HAL interface.\n",
607             __FUNCTION__, __LINE__
608             );
609
610         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
611     }
612
613     /* Success. */
614     gcmkFOOTER_NO();
615     return 0;
616
617 OnError:
618     gcmkFOOTER();
619     return -ENOTTY;
620 }
621
622 static int drv_mmap(
623     struct file* filp,
624     struct vm_area_struct* vma
625     )
626 {
627     gceSTATUS status = gcvSTATUS_OK;
628     gcsHAL_PRIVATE_DATA_PTR data;
629     gckGALDEVICE device;
630
631     gcmkHEADER_ARG("filp=0x%08X vma=0x%08X", filp, vma);
632
633     if (filp == gcvNULL)
634     {
635         gcmkTRACE_ZONE(
636             gcvLEVEL_ERROR, gcvZONE_DRIVER,
637             "%s(%d): filp is NULL\n",
638             __FUNCTION__, __LINE__
639             );
640
641         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
642     }
643
644     data = filp->private_data;
645
646     if (data == gcvNULL)
647     {
648         gcmkTRACE_ZONE(
649             gcvLEVEL_ERROR, gcvZONE_DRIVER,
650             "%s(%d): private_data is NULL\n",
651             __FUNCTION__, __LINE__
652             );
653
654         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
655     }
656
657     device = data->device;
658
659     if (device == gcvNULL)
660     {
661         gcmkTRACE_ZONE(
662             gcvLEVEL_ERROR, gcvZONE_DRIVER,
663             "%s(%d): device is NULL\n",
664             __FUNCTION__, __LINE__
665             );
666
667         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
668     }
669
670 #if !gcdPAGED_MEMORY_CACHEABLE
671     vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
672     vma->vm_flags    |= gcdVM_FLAGS;
673 #endif
674     vma->vm_pgoff     = 0;
675
676     if (device->contiguousMapped)
677     {
678         unsigned long size = vma->vm_end - vma->vm_start;
679         int ret = 0;
680
681         if (size > device->contiguousSize)
682         {
683             gcmkTRACE_ZONE(
684                 gcvLEVEL_ERROR, gcvZONE_DRIVER,
685                 "%s(%d): Invalid mapping size.\n",
686                 __FUNCTION__, __LINE__
687                 );
688
689             gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
690         }
691
692         ret = io_remap_pfn_range(
693             vma,
694             vma->vm_start,
695             device->requestedContiguousBase >> PAGE_SHIFT,
696             size,
697             vma->vm_page_prot
698             );
699
700         if (ret != 0)
701         {
702             gcmkTRACE_ZONE(
703                 gcvLEVEL_ERROR, gcvZONE_DRIVER,
704                 "%s(%d): io_remap_pfn_range failed %d\n",
705                 __FUNCTION__, __LINE__,
706                 ret
707                 );
708
709             data->mappedMemory = gcvNULL;
710
711             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
712         }
713
714         data->mappedMemory = (gctPOINTER) vma->vm_start;
715
716         /* Success. */
717         gcmkFOOTER_NO();
718         return 0;
719     }
720
721
722 OnError:
723     gcmkFOOTER();
724     return -ENOTTY;
725 }
726
727
728 #if !USE_PLATFORM_DRIVER
729 static int __init drv_init(void)
730 #else
731 static int drv_init(struct device *pdev)
732 #endif
733 {
734     int ret;
735     int result = -EINVAL;
736     gceSTATUS status;
737     gckGALDEVICE device = gcvNULL;
738     struct class* device_class = gcvNULL;
739
740     gcmkHEADER();
741
742 #if ENABLE_GPU_CLOCK_BY_DRIVER && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
743     {
744 # if 0
745         struct clk * clk;
746
747         clk = clk_get(NULL, "GCCLK");
748
749         if (IS_ERR(clk))
750         {
751             gcmkTRACE_ZONE(
752                 gcvLEVEL_ERROR, gcvZONE_DRIVER,
753                 "%s(%d): clk get error: %d\n",
754                 __FUNCTION__, __LINE__,
755                 PTR_ERR(clk)
756                 );
757
758             result = -ENODEV;
759             gcmkONERROR(gcvSTATUS_GENERIC_IO);
760         }
761
762         /*
763          * APMU_GC_156M, APMU_GC_312M, APMU_GC_PLL2, APMU_GC_PLL2_DIV2 currently.
764          * Use the 2X clock.
765          */
766         if (clk_set_rate(clk, coreClock * 2))
767         {
768             gcmkTRACE_ZONE(
769                 gcvLEVEL_ERROR, gcvZONE_DRIVER,
770                 "%s(%d): Failed to set core clock.\n",
771                 __FUNCTION__, __LINE__
772                 );
773
774             result = -EAGAIN;
775             gcmkONERROR(gcvSTATUS_GENERIC_IO);
776         }
777
778         clk_enable(clk);
779
780 #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
781         gc_pwr(1);
782 #   endif
783 # endif
784     }
785 #endif
786
787     printk(KERN_INFO "Galcore version %d.%d.%d.%d\n",
788         gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
789
790     if (showArgs)
791     {
792         printk("galcore options:\n");
793         printk("  irqLine           = %d\n",      irqLine);
794         printk("  registerMemBase   = 0x%08lX\n", registerMemBase);
795         printk("  registerMemSize   = 0x%08lX\n", registerMemSize);
796
797         if (irqLine2D != -1)
798         {
799             printk("  irqLine2D         = %d\n",      irqLine2D);
800             printk("  registerMemBase2D = 0x%08lX\n", registerMemBase2D);
801             printk("  registerMemSize2D = 0x%08lX\n", registerMemSize2D);
802         }
803
804         if (irqLineVG != -1)
805         {
806             printk("  irqLineVG         = %d\n",      irqLineVG);
807             printk("  registerMemBaseVG = 0x%08lX\n", registerMemBaseVG);
808             printk("  registerMemSizeVG = 0x%08lX\n", registerMemSizeVG);
809         }
810
811         printk("  contiguousSize    = %ld\n",     contiguousSize);
812         printk("  contiguousBase    = 0x%08lX\n", contiguousBase);
813         printk("  bankSize          = 0x%08lX\n", bankSize);
814         printk("  fastClear         = %d\n",      fastClear);
815         printk("  compression       = %d\n",      compression);
816         printk("  signal            = %d\n",      signal);
817         printk("  baseAddress       = 0x%08lX\n", baseAddress);
818         printk("  physSize          = 0x%08lX\n", physSize);
819         printk("  logFileSize       = %d KB \n",  logFileSize);
820         printk("  powerManagement   = %d\n",      powerManagement);
821 #if ENABLE_GPU_CLOCK_BY_DRIVER
822         printk("  coreClock       = %lu\n",     coreClock);
823 #endif
824     }
825
826     if(logFileSize != 0)
827     {
828         gckDebugFileSystemInitialize();
829     }
830
831     /* Create the GAL device. */
832     gcmkONERROR(gckGALDEVICE_Construct(
833         irqLine,
834         registerMemBase, registerMemSize,
835         irqLine2D,
836         registerMemBase2D, registerMemSize2D,
837         irqLineVG,
838         registerMemBaseVG, registerMemSizeVG,
839         contiguousBase, contiguousSize,
840         bankSize, fastClear, compression, baseAddress, physSize, signal,
841         logFileSize,
842         pdev,
843         powerManagement,
844         &device
845         ));
846
847     /* Start the GAL device. */
848     gcmkONERROR(gckGALDEVICE_Start(device));
849
850     if ((physSize != 0)
851        && (device->kernels[gcvCORE_MAJOR] != gcvNULL)
852        && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0))
853     {
854         status = gckMMU_Enable(device->kernels[gcvCORE_MAJOR]->mmu, baseAddress, physSize);
855         gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER,
856             "Enable new MMU: status=%d\n", status);
857
858         if ((device->kernels[gcvCORE_2D] != gcvNULL)
859             && (device->kernels[gcvCORE_2D]->hardware->mmuVersion != 0))
860         {
861             status = gckMMU_Enable(device->kernels[gcvCORE_2D]->mmu, baseAddress, physSize);
862             gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER,
863                 "Enable new MMU for 2D: status=%d\n", status);
864         }
865
866         /* Reset the base address */
867         device->baseAddress = 0;
868     }
869
870 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
871     task_free_register(&task_nb);
872     viv_gpu_resmem_handler.data = device->kernels[gcvCORE_MAJOR];
873     register_reserved_memory_account(&viv_gpu_resmem_handler);
874 #endif
875
876
877     /* Register the character device. */
878     ret = register_chrdev(major, DRV_NAME, &driver_fops);
879
880     if (ret < 0)
881     {
882         gcmkTRACE_ZONE(
883             gcvLEVEL_ERROR, gcvZONE_DRIVER,
884             "%s(%d): Could not allocate major number for mmap.\n",
885             __FUNCTION__, __LINE__
886             );
887
888         gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
889     }
890
891     if (major == 0)
892     {
893         major = ret;
894     }
895
896     /* Create the device class. */
897     device_class = class_create(THIS_MODULE, "graphics_class");
898
899     if (IS_ERR(device_class))
900     {
901         gcmkTRACE_ZONE(
902             gcvLEVEL_ERROR, gcvZONE_DRIVER,
903             "%s(%d): Failed to create the class.\n",
904             __FUNCTION__, __LINE__
905             );
906
907         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
908     }
909
910 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
911     device_create(device_class, NULL, MKDEV(major, 0), NULL, "galcore");
912 #else
913     device_create(device_class, NULL, MKDEV(major, 0), "galcore");
914 #endif
915
916     galDevice = device;
917     gpuClass  = device_class;
918
919     gcmkTRACE_ZONE(
920         gcvLEVEL_INFO, gcvZONE_DRIVER,
921         "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n",
922         __FUNCTION__, __LINE__,
923         irqLine, contiguousSize, registerMemBase
924         );
925
926     /* Success. */
927     gcmkFOOTER_NO();
928     return 0;
929
930 OnError:
931     /* Roll back. */
932     if (device_class != gcvNULL)
933     {
934         device_destroy(device_class, MKDEV(major, 0));
935         class_destroy(device_class);
936     }
937
938     if (device != gcvNULL)
939     {
940         gcmkVERIFY_OK(gckGALDEVICE_Stop(device));
941         gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
942     }
943
944     gcmkFOOTER();
945     return result;
946 }
947
948 #if !USE_PLATFORM_DRIVER
949 static void __exit drv_exit(void)
950 #else
951 static void drv_exit(void)
952 #endif
953 {
954     gcmkHEADER();
955
956 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
957     task_free_unregister(&task_nb);
958     unregister_reserved_memory_account(&viv_gpu_resmem_handler);
959 #endif
960
961     gcmkASSERT(gpuClass != gcvNULL);
962     device_destroy(gpuClass, MKDEV(major, 0));
963     class_destroy(gpuClass);
964
965     unregister_chrdev(major, DRV_NAME);
966
967     gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice));
968     gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice));
969
970    if(gckDebugFileSystemIsEnabled())
971    {
972          gckDebugFileSystemTerminate();
973    }
974
975 #if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
976     {
977 # if 0
978         struct clk * clk = NULL;
979
980 #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
981         gc_pwr(0);
982 #endif
983         clk = clk_get(NULL, "GCCLK");
984         clk_disable(clk);
985 # endif
986     }
987 #endif
988
989     gcmkFOOTER_NO();
990 }
991
992 #if !USE_PLATFORM_DRIVER
993     module_init(drv_init);
994     module_exit(drv_exit);
995 #else
996
997 #ifdef CONFIG_DOVE_GPU
998 #   define DEVICE_NAME "dove_gpu"
999 #else
1000 #   define DEVICE_NAME "galcore"
1001 #endif
1002
1003 #if gcdENABLE_FSCALE_VAL_ADJUST
1004 static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
1005         void *dummy)
1006 {
1007     static gctUINT orgFscale, minFscale, maxFscale;
1008     static gctBOOL bAlreadyTooHot = gcvFALSE;
1009     gckHARDWARE hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;
1010
1011     if (event && !bAlreadyTooHot) {
1012         gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
1013         gckHARDWARE_SetFscaleValue(hardware, minFscale);
1014         bAlreadyTooHot = gcvTRUE;
1015         gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
1016     } else if (!event && bAlreadyTooHot) {
1017         gckHARDWARE_SetFscaleValue(hardware, orgFscale);
1018         gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
1019         bAlreadyTooHot = gcvFALSE;
1020     }
1021     return NOTIFY_OK;
1022 }
1023
1024 static struct notifier_block thermal_hot_pm_notifier = {
1025     .notifier_call = thermal_hot_pm_notify,
1026     };
1027 #endif
1028
1029
1030
1031 static int __devinit gpu_probe(struct platform_device *pdev)
1032 {
1033     int ret = -ENODEV;
1034     struct resource* res;
1035 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1036         struct device_node *dn =pdev->dev.of_node;
1037         const u32 *prop;
1038 #else
1039         struct viv_gpu_platform_data *pdata;
1040 #endif
1041     gcmkHEADER();
1042
1043     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
1044     if (res)
1045         baseAddress = res->start;
1046
1047     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
1048     if (res)
1049         irqLine = res->start;
1050
1051     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
1052     if (res)
1053     {
1054         registerMemBase = res->start;
1055         registerMemSize = res->end - res->start + 1;
1056     }
1057
1058     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
1059     if (res)
1060         irqLine2D = res->start;
1061
1062     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
1063     if (res)
1064     {
1065         registerMemBase2D = res->start;
1066         registerMemSize2D = res->end - res->start + 1;
1067     }
1068
1069     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
1070     if (res)
1071         irqLineVG = res->start;
1072
1073     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
1074     if (res)
1075     {
1076         registerMemBaseVG = res->start;
1077         registerMemSizeVG = res->end - res->start + 1;
1078     }
1079
1080 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1081         prop = of_get_property(dn, "contiguousbase", NULL);
1082         if(prop)
1083                 contiguousBase = *prop;
1084         of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
1085 #else
1086     pdata = pdev->dev.platform_data;
1087     if (pdata) {
1088         contiguousBase = pdata->reserved_mem_base;
1089         contiguousSize = pdata->reserved_mem_size;
1090      }
1091 #endif
1092     if (contiguousSize == 0)
1093        gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n ");
1094     ret = drv_init(&pdev->dev);
1095
1096     if (!ret)
1097     {
1098         platform_set_drvdata(pdev, galDevice);
1099
1100 #if gcdENABLE_FSCALE_VAL_ADJUST
1101         if(galDevice->kernels[gcvCORE_MAJOR])
1102             register_thermal_notifier(&thermal_hot_pm_notifier);
1103 #endif
1104         gcmkFOOTER_NO();
1105         return ret;
1106     }
1107 #if gcdENABLE_FSCALE_VAL_ADJUST
1108     unregister_thermal_notifier(&thermal_hot_pm_notifier);
1109 #endif
1110     gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret);
1111     return ret;
1112 }
1113
1114 static int __devexit gpu_remove(struct platform_device *pdev)
1115 {
1116     gcmkHEADER();
1117 #if gcdENABLE_FSCALE_VAL_ADJUST
1118     if(galDevice->kernels[gcvCORE_MAJOR])
1119         unregister_thermal_notifier(&thermal_hot_pm_notifier);
1120 #endif
1121     drv_exit();
1122     gcmkFOOTER_NO();
1123     return 0;
1124 }
1125
1126 static int gpu_suspend(struct platform_device *dev, pm_message_t state)
1127 {
1128     gceSTATUS status;
1129     gckGALDEVICE device;
1130     gctINT i;
1131
1132     device = platform_get_drvdata(dev);
1133
1134     for (i = 0; i < gcdMAX_GPU_COUNT; i++)
1135     {
1136         if (device->kernels[i] != gcvNULL)
1137         {
1138             /* Store states. */
1139 #if gcdENABLE_VG
1140             if (i == gcvCORE_VG)
1141             {
1142                 status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]);
1143             }
1144             else
1145 #endif
1146             {
1147                 status = gckHARDWARE_QueryPowerManagementState(device->kernels[i]->hardware, &device->statesStored[i]);
1148             }
1149
1150             if (gcmIS_ERROR(status))
1151             {
1152                 return -1;
1153             }
1154
1155 #if gcdENABLE_VG
1156             if (i == gcvCORE_VG)
1157             {
1158                 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_OFF);
1159             }
1160             else
1161 #endif
1162             {
1163                 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF);
1164             }
1165             if (gcmIS_ERROR(status))
1166             {
1167                 return -1;
1168             }
1169
1170         }
1171     }
1172
1173     return 0;
1174 }
1175
1176 static int gpu_resume(struct platform_device *dev)
1177 {
1178     gceSTATUS status;
1179     gckGALDEVICE device;
1180     gctINT i;
1181     gceCHIPPOWERSTATE   statesStored;
1182
1183     device = platform_get_drvdata(dev);
1184
1185     for (i = 0; i < gcdMAX_GPU_COUNT; i++)
1186     {
1187         if (device->kernels[i] != gcvNULL)
1188         {
1189 #if gcdENABLE_VG
1190             if (i == gcvCORE_VG)
1191             {
1192                 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
1193             }
1194             else
1195 #endif
1196             {
1197                 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON);
1198             }
1199
1200             if (gcmIS_ERROR(status))
1201             {
1202                 return -1;
1203             }
1204
1205             /* Convert global state to crossponding internal state. */
1206             switch(device->statesStored[i])
1207             {
1208             case gcvPOWER_OFF:
1209                 statesStored = gcvPOWER_OFF_BROADCAST;
1210                 break;
1211             case gcvPOWER_IDLE:
1212                 statesStored = gcvPOWER_IDLE_BROADCAST;
1213                 break;
1214             case gcvPOWER_SUSPEND:
1215                 statesStored = gcvPOWER_SUSPEND_BROADCAST;
1216                 break;
1217             case gcvPOWER_ON:
1218                 statesStored = gcvPOWER_ON_AUTO;
1219                 break;
1220             default:
1221                 statesStored = device->statesStored[i];
1222                 break;
1223         }
1224
1225             /* Restore states. */
1226 #if gcdENABLE_VG
1227             if (i == gcvCORE_VG)
1228             {
1229                 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, statesStored);
1230     }
1231             else
1232 #endif
1233             {
1234                 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, statesStored);
1235             }
1236
1237             if (gcmIS_ERROR(status))
1238             {
1239                 return -1;
1240             }
1241         }
1242     }
1243
1244     return 0;
1245 }
1246
1247 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1248 static const struct of_device_id mxs_gpu_dt_ids[] = {
1249         { .compatible = "fsl,imx6q-gpu", },
1250         {/* sentinel */}
1251 };
1252 MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids);
1253
1254 #ifdef CONFIG_PM
1255 static int gpu_runtime_suspend(struct device *dev)
1256 {
1257         release_bus_freq(BUS_FREQ_HIGH);
1258         return 0;
1259 }
1260
1261 static int gpu_runtime_resume(struct device *dev)
1262 {
1263         request_bus_freq(BUS_FREQ_HIGH);
1264         return 0;
1265 }
1266
1267 static int gpu_system_suspend(struct device *dev)
1268 {
1269         pm_message_t state={0};
1270         return gpu_suspend(to_platform_device(dev), state);
1271 }
1272
1273 static int gpu_system_resume(struct device *dev)
1274 {
1275         return gpu_resume(to_platform_device(dev));
1276 }
1277
1278 static const struct dev_pm_ops gpu_pm_ops = {
1279         SET_RUNTIME_PM_OPS(gpu_runtime_suspend, gpu_runtime_resume, NULL)
1280         SET_SYSTEM_SLEEP_PM_OPS(gpu_system_suspend, gpu_system_resume)
1281 };
1282 #endif
1283 #endif
1284
1285 static struct platform_driver gpu_driver = {
1286     .probe      = gpu_probe,
1287     .remove     = __devexit_p(gpu_remove),
1288
1289     .suspend    = gpu_suspend,
1290     .resume     = gpu_resume,
1291
1292     .driver     = {
1293         .name   = DEVICE_NAME,
1294 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1295                 .of_match_table = mxs_gpu_dt_ids,
1296 #if CONFIG_PM
1297                 .pm             = &gpu_pm_ops,
1298 #endif
1299 #endif
1300     }
1301 };
1302
1303 #if 0 /*CONFIG_DOVE_GPU*/
1304 static struct resource gpu_resources[] = {
1305     {
1306         .name   = "gpu_irq",
1307         .flags  = IORESOURCE_IRQ,
1308     },
1309     {
1310         .name   = "gpu_base",
1311         .flags  = IORESOURCE_MEM,
1312     },
1313     {
1314         .name   = "gpu_mem",
1315         .flags  = IORESOURCE_MEM,
1316     },
1317 };
1318
1319 static struct platform_device * gpu_device;
1320 #endif
1321
1322 static int __init gpu_init(void)
1323 {
1324     int ret = 0;
1325
1326 #if 0 /*ndef CONFIG_DOVE_GPU*/
1327     gpu_resources[0].start = gpu_resources[0].end = irqLine;
1328
1329     gpu_resources[1].start = registerMemBase;
1330     gpu_resources[1].end   = registerMemBase + registerMemSize - 1;
1331
1332     gpu_resources[2].start = contiguousBase;
1333     gpu_resources[2].end   = contiguousBase + contiguousSize - 1;
1334
1335     /* Allocate device */
1336     gpu_device = platform_device_alloc(DEVICE_NAME, -1);
1337     if (!gpu_device)
1338     {
1339         printk(KERN_ERR "galcore: platform_device_alloc failed.\n");
1340         ret = -ENOMEM;
1341         goto out;
1342     }
1343
1344     /* Insert resource */
1345     ret = platform_device_add_resources(gpu_device, gpu_resources, 3);
1346     if (ret)
1347     {
1348         printk(KERN_ERR "galcore: platform_device_add_resources failed.\n");
1349         goto put_dev;
1350     }
1351
1352     /* Add device */
1353     ret = platform_device_add(gpu_device);
1354     if (ret)
1355     {
1356         printk(KERN_ERR "galcore: platform_device_add failed.\n");
1357         goto put_dev;
1358     }
1359 #endif
1360
1361     ret = platform_driver_register(&gpu_driver);
1362     if (!ret)
1363     {
1364         goto out;
1365     }
1366
1367 #if 0 /*ndef CONFIG_DOVE_GPU*/
1368     platform_device_del(gpu_device);
1369 put_dev:
1370     platform_device_put(gpu_device);
1371 #endif
1372
1373 out:
1374     return ret;
1375 }
1376
1377 static void __exit gpu_exit(void)
1378 {
1379     platform_driver_unregister(&gpu_driver);
1380 #if 0 /*ndef CONFIG_DOVE_GPU*/
1381     platform_device_unregister(gpu_device);
1382 #endif
1383 }
1384
1385 module_init(gpu_init);
1386 module_exit(gpu_exit);
1387
1388 #endif