1 /****************************************************************************
3 * Copyright (C) 2005 - 2013 by Vivante Corp.
4 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
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.
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.
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.
20 *****************************************************************************/
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"
29 #if USE_PLATFORM_DRIVER
30 # include <linux/platform_device.h>
33 #ifdef CONFIG_PXA_DVFM
34 # include <mach/dvfm.h>
35 # include <mach/pxa3xx_dvfm.h>
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>
47 struct task_struct *lowmem_deathpending;
50 task_notify_func(struct notifier_block *self, unsigned long val, void *data);
52 static struct notifier_block task_nb = {
53 .notifier_call = task_notify_func,
57 task_notify_func(struct notifier_block *self, unsigned long val, void *data)
59 struct task_struct *task = data;
61 if (task == lowmem_deathpending)
62 lowmem_deathpending = NULL;
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
69 #include <mach/viv_gpu.h>
71 #include <linux/pm_runtime.h>
72 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
73 #include <mach/busfreq.h>
75 #include <linux/reset.h>
78 /* Zone used for header/footer. */
79 #define _GC_OBJ_ZONE gcvZONE_DRIVER
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);
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);
94 MODULE_DESCRIPTION("Vivante Graphics Driver");
95 MODULE_LICENSE("GPL");
97 static struct class* gpuClass;
99 static gckGALDEVICE galDevice;
101 static uint major = 199;
102 module_param(major, uint, 0644);
104 static int irqLine = -1;
105 module_param(irqLine, int, 0644);
107 static ulong registerMemBase = 0x80000000;
108 module_param(registerMemBase, ulong, 0644);
110 static ulong registerMemSize = 2 << 10;
111 module_param(registerMemSize, ulong, 0644);
113 static int irqLine2D = -1;
114 module_param(irqLine2D, int, 0644);
116 static ulong registerMemBase2D = 0x00000000;
117 module_param(registerMemBase2D, ulong, 0644);
119 static ulong registerMemSize2D = 2 << 10;
120 module_param(registerMemSize2D, ulong, 0644);
122 static int irqLineVG = -1;
123 module_param(irqLineVG, int, 0644);
125 static ulong registerMemBaseVG = 0x00000000;
126 module_param(registerMemBaseVG, ulong, 0644);
128 static ulong registerMemSizeVG = 2 << 10;
129 module_param(registerMemSizeVG, ulong, 0644);
131 #if gcdENABLE_FSCALE_VAL_ADJUST
132 static ulong contiguousSize = 128 << 20;
134 static ulong contiguousSize = 4 << 20;
136 module_param(contiguousSize, ulong, 0644);
138 static ulong contiguousBase = 0;
139 module_param(contiguousBase, ulong, 0644);
141 static ulong bankSize = 0;
142 module_param(bankSize, ulong, 0644);
144 static int fastClear = -1;
145 module_param(fastClear, int, 0644);
147 static int compression = -1;
148 module_param(compression, int, 0644);
150 static int powerManagement = 1;
151 module_param(powerManagement, int, 0644);
153 static int signal = 48;
154 module_param(signal, int, 0644);
156 static ulong baseAddress = 0;
157 module_param(baseAddress, ulong, 0644);
159 static ulong physSize = 0;
160 module_param(physSize, ulong, 0644);
162 static uint logFileSize=0;
163 module_param(logFileSize,uint, 0644);
165 static int showArgs = 0;
166 module_param(showArgs, int, 0644);
168 int gpu3DMinClock = 0;
169 module_param(gpu3DMinClock, int, 0644);
171 #if ENABLE_GPU_CLOCK_BY_DRIVER
172 unsigned long coreClock = 156000000;
173 module_param(coreClock, ulong, 0644);
181 static int drv_release(
186 static long drv_ioctl(
188 unsigned int ioctlCode,
194 struct vm_area_struct* vma
197 static struct file_operations driver_fops =
199 .owner = THIS_MODULE,
201 .release = drv_release,
202 .unlocked_ioctl = drv_ioctl,
203 #ifdef HAVE_COMPAT_IOCTL
204 .compat_ioctl = drv_ioctl,
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 = {
213 .get_page_used_by_process = viv_gpu_resmem_query,
216 size_t viv_gpu_resmem_query(struct task_struct *p, struct reserved_memory_account *m)
218 gcuDATABASE_INFO info;
219 unsigned int processid = p->pid;
220 gckKERNEL gpukernel = m->data;
222 /* ignore error happens in this api. */
223 if (gckKERNEL_QueryProcessDB(gpukernel, processid, false, gcvDB_VIDEO_MEMORY, &info) != gcvSTATUS_OK)
226 /* we return pages. */
227 if (info.counters.bytes > 0)
228 return info.counters.bytes / PAGE_SIZE;
239 gctBOOL attached = gcvFALSE;
240 gcsHAL_PRIVATE_DATA_PTR data = gcvNULL;
243 gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
248 gcvLEVEL_ERROR, gcvZONE_DRIVER,
249 "%s(%d): filp is NULL\n",
250 __FUNCTION__, __LINE__
253 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
256 data = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN);
261 gcvLEVEL_ERROR, gcvZONE_DRIVER,
262 "%s(%d): private_data is NULL\n",
263 __FUNCTION__, __LINE__
266 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
269 data->device = galDevice;
270 data->mappedMemory = gcvNULL;
271 data->contiguousLogical = gcvNULL;
272 gcmkONERROR(gckOS_GetProcessID(&data->pidOpen));
274 /* Attached the process. */
275 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
277 if (galDevice->kernels[i] != gcvNULL)
279 gcmkONERROR(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE));
284 if (!galDevice->contiguousMapped)
286 gcmkONERROR(gckOS_MapMemory(
288 galDevice->contiguousPhysical,
289 galDevice->contiguousSize,
290 &data->contiguousLogical
294 filp->private_data = data;
303 if (data->contiguousLogical != gcvNULL)
305 gcmkVERIFY_OK(gckOS_UnmapMemory(
307 galDevice->contiguousPhysical,
308 galDevice->contiguousSize,
309 data->contiguousLogical
318 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
320 if (galDevice->kernels[i] != gcvNULL)
322 gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE));
337 gcsHAL_PRIVATE_DATA_PTR data;
341 gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
346 gcvLEVEL_ERROR, gcvZONE_DRIVER,
347 "%s(%d): filp is NULL\n",
348 __FUNCTION__, __LINE__
351 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
354 data = filp->private_data;
359 gcvLEVEL_ERROR, gcvZONE_DRIVER,
360 "%s(%d): private_data is NULL\n",
361 __FUNCTION__, __LINE__
364 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
367 device = data->device;
369 if (device == gcvNULL)
372 gcvLEVEL_ERROR, gcvZONE_DRIVER,
373 "%s(%d): device is NULL\n",
374 __FUNCTION__, __LINE__
377 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
380 if (!device->contiguousMapped)
382 if (data->contiguousLogical != gcvNULL)
384 gcmkONERROR(gckOS_UnmapMemoryEx(
386 galDevice->contiguousPhysical,
387 galDevice->contiguousSize,
388 data->contiguousLogical,
392 data->contiguousLogical = gcvNULL;
396 /* A process gets detached. */
397 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
399 if (galDevice->kernels[i] != gcvNULL)
401 gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen));
406 filp->private_data = NULL;
419 unsigned int ioctlCode,
424 gcsHAL_INTERFACE iface;
428 gcsHAL_PRIVATE_DATA_PTR data;
432 "filp=0x%08X ioctlCode=0x%08X arg=0x%08X",
439 gcvLEVEL_ERROR, gcvZONE_DRIVER,
440 "%s(%d): filp is NULL\n",
441 __FUNCTION__, __LINE__
444 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
447 data = filp->private_data;
452 gcvLEVEL_ERROR, gcvZONE_DRIVER,
453 "%s(%d): private_data is NULL\n",
454 __FUNCTION__, __LINE__
457 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
460 device = data->device;
462 if (device == gcvNULL)
465 gcvLEVEL_ERROR, gcvZONE_DRIVER,
466 "%s(%d): device is NULL\n",
467 __FUNCTION__, __LINE__
470 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
473 if ((ioctlCode != IOCTL_GCHAL_INTERFACE)
474 && (ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE)
478 gcvLEVEL_ERROR, gcvZONE_DRIVER,
479 "%s(%d): unknown command %d\n",
480 __FUNCTION__, __LINE__,
484 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
487 /* Get the drvArgs. */
488 copyLen = copy_from_user(
489 &drvArgs, (void *) arg, sizeof(DRIVER_ARGS)
495 gcvLEVEL_ERROR, gcvZONE_DRIVER,
496 "%s(%d): error copying of the input arguments.\n",
497 __FUNCTION__, __LINE__
500 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
503 /* Now bring in the gcsHAL_INTERFACE structure. */
504 if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE))
505 || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE))
509 gcvLEVEL_ERROR, gcvZONE_DRIVER,
510 "%s(%d): input or/and output structures are invalid.\n",
511 __FUNCTION__, __LINE__
514 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
517 copyLen = copy_from_user(
518 &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE)
524 gcvLEVEL_ERROR, gcvZONE_DRIVER,
525 "%s(%d): error copying of input HAL interface.\n",
526 __FUNCTION__, __LINE__
529 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
532 if (iface.command == gcvHAL_CHIP_INFO)
535 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
537 if (device->kernels[i] != gcvNULL)
542 iface.u.ChipInfo.types[count] = gcvHARDWARE_VG;
547 gcmkVERIFY_OK(gckHARDWARE_GetType(device->kernels[i]->hardware,
548 &iface.u.ChipInfo.types[count]));
554 iface.u.ChipInfo.count = count;
555 iface.status = status = gcvSTATUS_OK;
559 if (iface.hardwareType < 0 || iface.hardwareType > 7)
562 gcvLEVEL_ERROR, gcvZONE_DRIVER,
563 "%s(%d): unknown hardwareType %d\n",
564 __FUNCTION__, __LINE__,
568 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
572 if (device->coreMapping[iface.hardwareType] == gcvCORE_VG)
574 status = gckVGKERNEL_Dispatch(device->kernels[gcvCORE_VG],
575 (ioctlCode == IOCTL_GCHAL_INTERFACE),
581 status = gckKERNEL_Dispatch(device->kernels[device->coreMapping[iface.hardwareType]],
582 (ioctlCode == IOCTL_GCHAL_INTERFACE),
587 /* Redo system call after pending signal is handled. */
588 if (status == gcvSTATUS_INTERRUPTED)
594 if (gcmIS_SUCCESS(status) && (iface.command == gcvHAL_LOCK_VIDEO_MEMORY))
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)
602 /* Compute offset into mapped memory. */
604 = (gctUINT8 *) gcmUINT64_TO_PTR(iface.u.LockVideoMemory.memory)
605 - (gctUINT8 *) device->contiguousBase;
607 /* Compute offset into user-mapped region. */
608 iface.u.LockVideoMemory.memory =
609 gcmPTR_TO_UINT64((gctUINT8 *) data->mappedMemory + offset);
613 /* Copy data back to the user. */
614 copyLen = copy_to_user(
615 gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE)
621 gcvLEVEL_ERROR, gcvZONE_DRIVER,
622 "%s(%d): error copying of output HAL interface.\n",
623 __FUNCTION__, __LINE__
626 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
640 struct vm_area_struct* vma
643 gceSTATUS status = gcvSTATUS_OK;
644 gcsHAL_PRIVATE_DATA_PTR data;
647 gcmkHEADER_ARG("filp=0x%08X vma=0x%08X", filp, vma);
652 gcvLEVEL_ERROR, gcvZONE_DRIVER,
653 "%s(%d): filp is NULL\n",
654 __FUNCTION__, __LINE__
657 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
660 data = filp->private_data;
665 gcvLEVEL_ERROR, gcvZONE_DRIVER,
666 "%s(%d): private_data is NULL\n",
667 __FUNCTION__, __LINE__
670 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
673 device = data->device;
675 if (device == gcvNULL)
678 gcvLEVEL_ERROR, gcvZONE_DRIVER,
679 "%s(%d): device is NULL\n",
680 __FUNCTION__, __LINE__
683 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
686 #if !gcdPAGED_MEMORY_CACHEABLE
687 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
688 vma->vm_flags |= gcdVM_FLAGS;
692 if (device->contiguousMapped)
694 unsigned long size = vma->vm_end - vma->vm_start;
697 if (size > device->contiguousSize)
700 gcvLEVEL_ERROR, gcvZONE_DRIVER,
701 "%s(%d): Invalid mapping size.\n",
702 __FUNCTION__, __LINE__
705 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
708 ret = io_remap_pfn_range(
711 device->requestedContiguousBase >> PAGE_SHIFT,
719 gcvLEVEL_ERROR, gcvZONE_DRIVER,
720 "%s(%d): io_remap_pfn_range failed %d\n",
721 __FUNCTION__, __LINE__,
725 data->mappedMemory = gcvNULL;
727 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
730 data->mappedMemory = (gctPOINTER) vma->vm_start;
744 #if !USE_PLATFORM_DRIVER
745 static int __init drv_init(void)
747 static int drv_init(struct device *pdev)
751 int result = -EINVAL;
753 gckGALDEVICE device = gcvNULL;
754 struct class* device_class = gcvNULL;
758 #if ENABLE_GPU_CLOCK_BY_DRIVER && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
763 clk = clk_get(NULL, "GCCLK");
768 gcvLEVEL_ERROR, gcvZONE_DRIVER,
769 "%s(%d): clk get error: %d\n",
770 __FUNCTION__, __LINE__,
775 gcmkONERROR(gcvSTATUS_GENERIC_IO);
779 * APMU_GC_156M, APMU_GC_312M, APMU_GC_PLL2, APMU_GC_PLL2_DIV2 currently.
782 if (clk_set_rate(clk, coreClock * 2))
785 gcvLEVEL_ERROR, gcvZONE_DRIVER,
786 "%s(%d): Failed to set core clock.\n",
787 __FUNCTION__, __LINE__
791 gcmkONERROR(gcvSTATUS_GENERIC_IO);
796 #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
803 printk(KERN_INFO "Galcore version %d.%d.%d.%d\n",
804 gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
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);
815 printk(" irqLine2D = %d\n", irqLine2D);
816 printk(" registerMemBase2D = 0x%08lX\n", registerMemBase2D);
817 printk(" registerMemSize2D = 0x%08lX\n", registerMemSize2D);
822 printk(" irqLineVG = %d\n", irqLineVG);
823 printk(" registerMemBaseVG = 0x%08lX\n", registerMemBaseVG);
824 printk(" registerMemSizeVG = 0x%08lX\n", registerMemSizeVG);
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);
844 gckDebugFileSystemInitialize();
847 /* Create the GAL device. */
848 gcmkONERROR(gckGALDEVICE_Construct(
850 registerMemBase, registerMemSize,
852 registerMemBase2D, registerMemSize2D,
854 registerMemBaseVG, registerMemSizeVG,
855 contiguousBase, contiguousSize,
856 bankSize, fastClear, compression, baseAddress, physSize, signal,
863 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
864 device->pool = dev_get_drvdata(pdev);
867 /* Start the GAL device. */
868 gcmkONERROR(gckGALDEVICE_Start(device));
871 && (device->kernels[gcvCORE_MAJOR] != gcvNULL)
872 && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0))
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);
878 if ((device->kernels[gcvCORE_2D] != gcvNULL)
879 && (device->kernels[gcvCORE_2D]->hardware->mmuVersion != 0))
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);
886 /* Reset the base address */
887 device->baseAddress = 0;
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);
897 /* Register the character device. */
898 ret = register_chrdev(major, DRV_NAME, &driver_fops);
903 gcvLEVEL_ERROR, gcvZONE_DRIVER,
904 "%s(%d): Could not allocate major number for mmap.\n",
905 __FUNCTION__, __LINE__
908 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
916 /* Create the device class. */
917 device_class = class_create(THIS_MODULE, "graphics_class");
919 if (IS_ERR(device_class))
922 gcvLEVEL_ERROR, gcvZONE_DRIVER,
923 "%s(%d): Failed to create the class.\n",
924 __FUNCTION__, __LINE__
927 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
930 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
931 device_create(device_class, NULL, MKDEV(major, 0), NULL, "galcore");
933 device_create(device_class, NULL, MKDEV(major, 0), "galcore");
937 gpuClass = device_class;
940 gcvLEVEL_INFO, gcvZONE_DRIVER,
941 "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n",
942 __FUNCTION__, __LINE__,
943 irqLine, contiguousSize, registerMemBase
952 if (device_class != gcvNULL)
954 device_destroy(device_class, MKDEV(major, 0));
955 class_destroy(device_class);
958 if (device != gcvNULL)
960 gcmkVERIFY_OK(gckGALDEVICE_Stop(device));
961 gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
968 #if !USE_PLATFORM_DRIVER
969 static void __exit drv_exit(void)
971 static void drv_exit(void)
976 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
977 task_free_unregister(&task_nb);
978 unregister_reserved_memory_account(&viv_gpu_resmem_handler);
981 gcmkASSERT(gpuClass != gcvNULL);
982 device_destroy(gpuClass, MKDEV(major, 0));
983 class_destroy(gpuClass);
985 unregister_chrdev(major, DRV_NAME);
987 gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice));
988 gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice));
990 if(gckDebugFileSystemIsEnabled())
992 gckDebugFileSystemTerminate();
995 #if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
998 struct clk * clk = NULL;
1000 #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
1003 clk = clk_get(NULL, "GCCLK");
1012 #if !USE_PLATFORM_DRIVER
1013 module_init(drv_init);
1014 module_exit(drv_exit);
1017 #ifdef CONFIG_DOVE_GPU
1018 # define DEVICE_NAME "dove_gpu"
1020 # define DEVICE_NAME "galcore"
1023 #if gcdENABLE_FSCALE_VAL_ADJUST
1024 static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
1027 static gctUINT orgFscale, minFscale, maxFscale;
1028 static gctBOOL bAlreadyTooHot = gcvFALSE;
1029 gckHARDWARE hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;
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;
1044 static struct notifier_block thermal_hot_pm_notifier = {
1045 .notifier_call = thermal_hot_pm_notify,
1051 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
1052 static int gpu_probe(struct platform_device *pdev)
1054 static int __devinit gpu_probe(struct platform_device *pdev)
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;
1066 struct viv_gpu_platform_data *pdata;
1070 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
1072 baseAddress = res->start;
1074 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
1076 irqLine = res->start;
1078 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
1081 registerMemBase = res->start;
1082 registerMemSize = res->end - res->start + 1;
1085 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
1087 irqLine2D = res->start;
1089 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
1092 registerMemBase2D = res->start;
1093 registerMemSize2D = res->end - res->start + 1;
1096 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
1098 irqLineVG = res->start;
1100 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
1103 registerMemBaseVG = res->start;
1104 registerMemSizeVG = res->end - res->start + 1;
1107 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
1108 pool = devm_kzalloc(&pdev->dev, sizeof(*pool), GFP_KERNEL);
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);
1117 dev_err(&pdev->dev, "Failed to allocate contiguous memory\n");
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);
1125 contiguousBase = *prop;
1126 of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
1128 pdata = pdev->dev.platform_data;
1130 contiguousBase = pdata->reserved_mem_base;
1131 contiguousSize = pdata->reserved_mem_size;
1134 if (contiguousSize == 0)
1135 gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n ");
1136 ret = drv_init(&pdev->dev);
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;
1144 rstc = devm_reset_control_get(&pdev->dev, "gpu2d");
1145 galDevice->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
1147 rstc = devm_reset_control_get(&pdev->dev, "gpuvg");
1148 galDevice->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc;
1150 platform_set_drvdata(pdev, galDevice);
1152 #if gcdENABLE_FSCALE_VAL_ADJUST
1153 if (galDevice->kernels[gcvCORE_MAJOR])
1154 REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
1159 #if gcdENABLE_FSCALE_VAL_ADJUST
1160 UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
1162 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
1163 dma_free_attrs(&pdev->dev, pool->size, pool->virt, pool->phys,
1166 gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret);
1170 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
1171 static int gpu_remove(struct platform_device *pdev)
1173 static int __devexit gpu_remove(struct platform_device *pdev)
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;
1181 #if gcdENABLE_FSCALE_VAL_ADJUST
1182 if(galDevice->kernels[gcvCORE_MAJOR])
1183 UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
1186 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
1187 dma_free_attrs(&pdev->dev, pool->size, pool->virt, pool->phys,
1194 static int gpu_suspend(struct platform_device *dev, pm_message_t state)
1197 gckGALDEVICE device;
1200 device = platform_get_drvdata(dev);
1202 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
1204 if (device->kernels[i] != gcvNULL)
1208 if (i == gcvCORE_VG)
1210 status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]);
1215 status = gckHARDWARE_QueryPowerManagementState(device->kernels[i]->hardware, &device->statesStored[i]);
1218 if (gcmIS_ERROR(status))
1224 if (i == gcvCORE_VG)
1226 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_OFF);
1231 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF);
1233 if (gcmIS_ERROR(status))
1244 static int gpu_resume(struct platform_device *dev)
1247 gckGALDEVICE device;
1249 gceCHIPPOWERSTATE statesStored;
1251 device = platform_get_drvdata(dev);
1253 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
1255 if (device->kernels[i] != gcvNULL)
1258 if (i == gcvCORE_VG)
1260 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
1265 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON);
1268 if (gcmIS_ERROR(status))
1273 /* Convert global state to crossponding internal state. */
1274 switch(device->statesStored[i])
1277 statesStored = gcvPOWER_OFF_BROADCAST;
1280 statesStored = gcvPOWER_IDLE_BROADCAST;
1282 case gcvPOWER_SUSPEND:
1283 statesStored = gcvPOWER_SUSPEND_BROADCAST;
1286 statesStored = gcvPOWER_ON_AUTO;
1289 statesStored = device->statesStored[i];
1293 /* Restore states. */
1295 if (i == gcvCORE_VG)
1297 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, statesStored);
1302 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, statesStored);
1305 if (gcmIS_ERROR(status))
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", },
1320 MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids);
1323 static int gpu_runtime_suspend(struct device *dev)
1325 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
1326 release_bus_freq(BUS_FREQ_HIGH);
1331 static int gpu_runtime_resume(struct device *dev)
1333 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
1334 request_bus_freq(BUS_FREQ_HIGH);
1339 static int gpu_system_suspend(struct device *dev)
1341 pm_message_t state={0};
1342 return gpu_suspend(to_platform_device(dev), state);
1345 static int gpu_system_resume(struct device *dev)
1347 return gpu_resume(to_platform_device(dev));
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)
1357 static struct platform_driver gpu_driver = {
1359 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
1360 .remove = gpu_remove,
1362 .remove = __devexit_p(gpu_remove),
1365 .suspend = gpu_suspend,
1366 .resume = gpu_resume,
1369 .name = DEVICE_NAME,
1370 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1371 .of_match_table = mxs_gpu_dt_ids,
1379 #if 0 /*CONFIG_DOVE_GPU*/
1380 static struct resource gpu_resources[] = {
1383 .flags = IORESOURCE_IRQ,
1387 .flags = IORESOURCE_MEM,
1391 .flags = IORESOURCE_MEM,
1395 static struct platform_device * gpu_device;
1398 static int __init gpu_init(void)
1402 #if 0 /*ndef CONFIG_DOVE_GPU*/
1403 gpu_resources[0].start = gpu_resources[0].end = irqLine;
1405 gpu_resources[1].start = registerMemBase;
1406 gpu_resources[1].end = registerMemBase + registerMemSize - 1;
1408 gpu_resources[2].start = contiguousBase;
1409 gpu_resources[2].end = contiguousBase + contiguousSize - 1;
1411 /* Allocate device */
1412 gpu_device = platform_device_alloc(DEVICE_NAME, -1);
1415 printk(KERN_ERR "galcore: platform_device_alloc failed.\n");
1420 /* Insert resource */
1421 ret = platform_device_add_resources(gpu_device, gpu_resources, 3);
1424 printk(KERN_ERR "galcore: platform_device_add_resources failed.\n");
1429 ret = platform_device_add(gpu_device);
1432 printk(KERN_ERR "galcore: platform_device_add failed.\n");
1437 ret = platform_driver_register(&gpu_driver);
1443 #if 0 /*ndef CONFIG_DOVE_GPU*/
1444 platform_device_del(gpu_device);
1446 platform_device_put(gpu_device);
1453 static void __exit gpu_exit(void)
1455 platform_driver_unregister(&gpu_driver);
1456 #if 0 /*ndef CONFIG_DOVE_GPU*/
1457 platform_device_unregister(gpu_device);
1461 module_init(gpu_init);
1462 module_exit(gpu_exit);