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