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