1 /****************************************************************************
3 * Copyright (C) 2005 - 2013 by Vivante Corp.
4 * Copyright (C) 2011-2012 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 #include <mach/busfreq.h>
74 /* Zone used for header/footer. */
75 #define _GC_OBJ_ZONE gcvZONE_DRIVER
77 #if gcdENABLE_FSCALE_VAL_ADJUST
78 extern int register_thermal_notifier(struct notifier_block *nb);
79 extern int unregister_thermal_notifier(struct notifier_block *nb);
82 MODULE_DESCRIPTION("Vivante Graphics Driver");
83 MODULE_LICENSE("GPL");
85 static struct class* gpuClass;
87 static gckGALDEVICE galDevice;
89 static uint major = 199;
90 module_param(major, uint, 0644);
92 static int irqLine = -1;
93 module_param(irqLine, int, 0644);
95 static ulong registerMemBase = 0x80000000;
96 module_param(registerMemBase, ulong, 0644);
98 static ulong registerMemSize = 2 << 10;
99 module_param(registerMemSize, ulong, 0644);
101 static int irqLine2D = -1;
102 module_param(irqLine2D, int, 0644);
104 static ulong registerMemBase2D = 0x00000000;
105 module_param(registerMemBase2D, ulong, 0644);
107 static ulong registerMemSize2D = 2 << 10;
108 module_param(registerMemSize2D, ulong, 0644);
110 static int irqLineVG = -1;
111 module_param(irqLineVG, int, 0644);
113 static ulong registerMemBaseVG = 0x00000000;
114 module_param(registerMemBaseVG, ulong, 0644);
116 static ulong registerMemSizeVG = 2 << 10;
117 module_param(registerMemSizeVG, ulong, 0644);
119 static ulong contiguousSize = 4 << 20;
120 module_param(contiguousSize, ulong, 0644);
122 static ulong contiguousBase = 0;
123 module_param(contiguousBase, ulong, 0644);
125 static ulong bankSize = 0;
126 module_param(bankSize, ulong, 0644);
128 static int fastClear = -1;
129 module_param(fastClear, int, 0644);
131 static int compression = -1;
132 module_param(compression, int, 0644);
134 static int powerManagement = 1;
135 module_param(powerManagement, int, 0644);
137 static int signal = 48;
138 module_param(signal, int, 0644);
140 static ulong baseAddress = 0;
141 module_param(baseAddress, ulong, 0644);
143 static ulong physSize = 0;
144 module_param(physSize, ulong, 0644);
146 static uint logFileSize=0;
147 module_param(logFileSize,uint, 0644);
149 static int showArgs = 0;
150 module_param(showArgs, int, 0644);
152 int gpu3DMinClock = 0;
153 module_param(gpu3DMinClock, int, 0644);
155 #if ENABLE_GPU_CLOCK_BY_DRIVER
156 unsigned long coreClock = 156000000;
157 module_param(coreClock, ulong, 0644);
165 static int drv_release(
170 static long drv_ioctl(
172 unsigned int ioctlCode,
178 struct vm_area_struct* vma
181 static struct file_operations driver_fops =
183 .owner = THIS_MODULE,
185 .release = drv_release,
186 .unlocked_ioctl = drv_ioctl,
187 #ifdef HAVE_COMPAT_IOCTL
188 .compat_ioctl = drv_ioctl,
193 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
194 static size_t viv_gpu_resmem_query(struct task_struct *p, struct reserved_memory_account *m);
195 static struct reserved_memory_account viv_gpu_resmem_handler = {
197 .get_page_used_by_process = viv_gpu_resmem_query,
200 size_t viv_gpu_resmem_query(struct task_struct *p, struct reserved_memory_account *m)
202 gcuDATABASE_INFO info;
203 unsigned int processid = p->pid;
204 gckKERNEL gpukernel = m->data;
206 /* ignore error happens in this api. */
207 if (gckKERNEL_QueryProcessDB(gpukernel, processid, false, gcvDB_VIDEO_MEMORY, &info) != gcvSTATUS_OK)
210 /* we return pages. */
211 if (info.counters.bytes > 0)
212 return info.counters.bytes / PAGE_SIZE;
223 gctBOOL attached = gcvFALSE;
224 gcsHAL_PRIVATE_DATA_PTR data = gcvNULL;
227 gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
232 gcvLEVEL_ERROR, gcvZONE_DRIVER,
233 "%s(%d): filp is NULL\n",
234 __FUNCTION__, __LINE__
237 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
240 data = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN);
245 gcvLEVEL_ERROR, gcvZONE_DRIVER,
246 "%s(%d): private_data is NULL\n",
247 __FUNCTION__, __LINE__
250 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
253 data->device = galDevice;
254 data->mappedMemory = gcvNULL;
255 data->contiguousLogical = gcvNULL;
256 gcmkONERROR(gckOS_GetProcessID(&data->pidOpen));
258 /* Attached the process. */
259 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
261 if (galDevice->kernels[i] != gcvNULL)
263 gcmkONERROR(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE));
268 if (!galDevice->contiguousMapped)
270 gcmkONERROR(gckOS_MapMemory(
272 galDevice->contiguousPhysical,
273 galDevice->contiguousSize,
274 &data->contiguousLogical
278 filp->private_data = data;
287 if (data->contiguousLogical != gcvNULL)
289 gcmkVERIFY_OK(gckOS_UnmapMemory(
291 galDevice->contiguousPhysical,
292 galDevice->contiguousSize,
293 data->contiguousLogical
302 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
304 if (galDevice->kernels[i] != gcvNULL)
306 gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE));
321 gcsHAL_PRIVATE_DATA_PTR data;
325 gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
330 gcvLEVEL_ERROR, gcvZONE_DRIVER,
331 "%s(%d): filp is NULL\n",
332 __FUNCTION__, __LINE__
335 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
338 data = filp->private_data;
343 gcvLEVEL_ERROR, gcvZONE_DRIVER,
344 "%s(%d): private_data is NULL\n",
345 __FUNCTION__, __LINE__
348 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
351 device = data->device;
353 if (device == gcvNULL)
356 gcvLEVEL_ERROR, gcvZONE_DRIVER,
357 "%s(%d): device is NULL\n",
358 __FUNCTION__, __LINE__
361 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
364 if (!device->contiguousMapped)
366 if (data->contiguousLogical != gcvNULL)
368 gcmkONERROR(gckOS_UnmapMemoryEx(
370 galDevice->contiguousPhysical,
371 galDevice->contiguousSize,
372 data->contiguousLogical,
376 data->contiguousLogical = gcvNULL;
380 /* A process gets detached. */
381 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
383 if (galDevice->kernels[i] != gcvNULL)
385 gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen));
390 filp->private_data = NULL;
403 unsigned int ioctlCode,
408 gcsHAL_INTERFACE iface;
412 gcsHAL_PRIVATE_DATA_PTR data;
416 "filp=0x%08X ioctlCode=0x%08X arg=0x%08X",
423 gcvLEVEL_ERROR, gcvZONE_DRIVER,
424 "%s(%d): filp is NULL\n",
425 __FUNCTION__, __LINE__
428 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
431 data = filp->private_data;
436 gcvLEVEL_ERROR, gcvZONE_DRIVER,
437 "%s(%d): private_data is NULL\n",
438 __FUNCTION__, __LINE__
441 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
444 device = data->device;
446 if (device == gcvNULL)
449 gcvLEVEL_ERROR, gcvZONE_DRIVER,
450 "%s(%d): device is NULL\n",
451 __FUNCTION__, __LINE__
454 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
457 if ((ioctlCode != IOCTL_GCHAL_INTERFACE)
458 && (ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE)
462 gcvLEVEL_ERROR, gcvZONE_DRIVER,
463 "%s(%d): unknown command %d\n",
464 __FUNCTION__, __LINE__,
468 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
471 /* Get the drvArgs. */
472 copyLen = copy_from_user(
473 &drvArgs, (void *) arg, sizeof(DRIVER_ARGS)
479 gcvLEVEL_ERROR, gcvZONE_DRIVER,
480 "%s(%d): error copying of the input arguments.\n",
481 __FUNCTION__, __LINE__
484 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
487 /* Now bring in the gcsHAL_INTERFACE structure. */
488 if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE))
489 || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE))
493 gcvLEVEL_ERROR, gcvZONE_DRIVER,
494 "%s(%d): input or/and output structures are invalid.\n",
495 __FUNCTION__, __LINE__
498 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
501 copyLen = copy_from_user(
502 &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE)
508 gcvLEVEL_ERROR, gcvZONE_DRIVER,
509 "%s(%d): error copying of input HAL interface.\n",
510 __FUNCTION__, __LINE__
513 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
516 if (iface.command == gcvHAL_CHIP_INFO)
519 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
521 if (device->kernels[i] != gcvNULL)
526 iface.u.ChipInfo.types[count] = gcvHARDWARE_VG;
531 gcmkVERIFY_OK(gckHARDWARE_GetType(device->kernels[i]->hardware,
532 &iface.u.ChipInfo.types[count]));
538 iface.u.ChipInfo.count = count;
539 iface.status = status = gcvSTATUS_OK;
543 if (iface.hardwareType < 0 || iface.hardwareType > 7)
546 gcvLEVEL_ERROR, gcvZONE_DRIVER,
547 "%s(%d): unknown hardwareType %d\n",
548 __FUNCTION__, __LINE__,
552 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
556 if (device->coreMapping[iface.hardwareType] == gcvCORE_VG)
558 status = gckVGKERNEL_Dispatch(device->kernels[gcvCORE_VG],
559 (ioctlCode == IOCTL_GCHAL_INTERFACE),
565 status = gckKERNEL_Dispatch(device->kernels[device->coreMapping[iface.hardwareType]],
566 (ioctlCode == IOCTL_GCHAL_INTERFACE),
571 /* Redo system call after pending signal is handled. */
572 if (status == gcvSTATUS_INTERRUPTED)
578 if (gcmIS_SUCCESS(status) && (iface.command == gcvHAL_LOCK_VIDEO_MEMORY))
580 gcuVIDMEM_NODE_PTR node = gcmUINT64_TO_PTR(iface.u.LockVideoMemory.node);
581 /* Special case for mapped memory. */
582 if ((data->mappedMemory != gcvNULL)
583 && (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
586 /* Compute offset into mapped memory. */
588 = (gctUINT8 *) gcmUINT64_TO_PTR(iface.u.LockVideoMemory.memory)
589 - (gctUINT8 *) device->contiguousBase;
591 /* Compute offset into user-mapped region. */
592 iface.u.LockVideoMemory.memory =
593 gcmPTR_TO_UINT64((gctUINT8 *) data->mappedMemory + offset);
597 /* Copy data back to the user. */
598 copyLen = copy_to_user(
599 gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE)
605 gcvLEVEL_ERROR, gcvZONE_DRIVER,
606 "%s(%d): error copying of output HAL interface.\n",
607 __FUNCTION__, __LINE__
610 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
624 struct vm_area_struct* vma
627 gceSTATUS status = gcvSTATUS_OK;
628 gcsHAL_PRIVATE_DATA_PTR data;
631 gcmkHEADER_ARG("filp=0x%08X vma=0x%08X", filp, vma);
636 gcvLEVEL_ERROR, gcvZONE_DRIVER,
637 "%s(%d): filp is NULL\n",
638 __FUNCTION__, __LINE__
641 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
644 data = filp->private_data;
649 gcvLEVEL_ERROR, gcvZONE_DRIVER,
650 "%s(%d): private_data is NULL\n",
651 __FUNCTION__, __LINE__
654 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
657 device = data->device;
659 if (device == gcvNULL)
662 gcvLEVEL_ERROR, gcvZONE_DRIVER,
663 "%s(%d): device is NULL\n",
664 __FUNCTION__, __LINE__
667 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
670 #if !gcdPAGED_MEMORY_CACHEABLE
671 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
672 vma->vm_flags |= gcdVM_FLAGS;
676 if (device->contiguousMapped)
678 unsigned long size = vma->vm_end - vma->vm_start;
681 if (size > device->contiguousSize)
684 gcvLEVEL_ERROR, gcvZONE_DRIVER,
685 "%s(%d): Invalid mapping size.\n",
686 __FUNCTION__, __LINE__
689 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
692 ret = io_remap_pfn_range(
695 device->requestedContiguousBase >> PAGE_SHIFT,
703 gcvLEVEL_ERROR, gcvZONE_DRIVER,
704 "%s(%d): io_remap_pfn_range failed %d\n",
705 __FUNCTION__, __LINE__,
709 data->mappedMemory = gcvNULL;
711 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
714 data->mappedMemory = (gctPOINTER) vma->vm_start;
728 #if !USE_PLATFORM_DRIVER
729 static int __init drv_init(void)
731 static int drv_init(struct device *pdev)
735 int result = -EINVAL;
737 gckGALDEVICE device = gcvNULL;
738 struct class* device_class = gcvNULL;
742 #if ENABLE_GPU_CLOCK_BY_DRIVER && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
747 clk = clk_get(NULL, "GCCLK");
752 gcvLEVEL_ERROR, gcvZONE_DRIVER,
753 "%s(%d): clk get error: %d\n",
754 __FUNCTION__, __LINE__,
759 gcmkONERROR(gcvSTATUS_GENERIC_IO);
763 * APMU_GC_156M, APMU_GC_312M, APMU_GC_PLL2, APMU_GC_PLL2_DIV2 currently.
766 if (clk_set_rate(clk, coreClock * 2))
769 gcvLEVEL_ERROR, gcvZONE_DRIVER,
770 "%s(%d): Failed to set core clock.\n",
771 __FUNCTION__, __LINE__
775 gcmkONERROR(gcvSTATUS_GENERIC_IO);
780 #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
787 printk(KERN_INFO "Galcore version %d.%d.%d.%d\n",
788 gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
792 printk("galcore options:\n");
793 printk(" irqLine = %d\n", irqLine);
794 printk(" registerMemBase = 0x%08lX\n", registerMemBase);
795 printk(" registerMemSize = 0x%08lX\n", registerMemSize);
799 printk(" irqLine2D = %d\n", irqLine2D);
800 printk(" registerMemBase2D = 0x%08lX\n", registerMemBase2D);
801 printk(" registerMemSize2D = 0x%08lX\n", registerMemSize2D);
806 printk(" irqLineVG = %d\n", irqLineVG);
807 printk(" registerMemBaseVG = 0x%08lX\n", registerMemBaseVG);
808 printk(" registerMemSizeVG = 0x%08lX\n", registerMemSizeVG);
811 printk(" contiguousSize = %ld\n", contiguousSize);
812 printk(" contiguousBase = 0x%08lX\n", contiguousBase);
813 printk(" bankSize = 0x%08lX\n", bankSize);
814 printk(" fastClear = %d\n", fastClear);
815 printk(" compression = %d\n", compression);
816 printk(" signal = %d\n", signal);
817 printk(" baseAddress = 0x%08lX\n", baseAddress);
818 printk(" physSize = 0x%08lX\n", physSize);
819 printk(" logFileSize = %d KB \n", logFileSize);
820 printk(" powerManagement = %d\n", powerManagement);
821 #if ENABLE_GPU_CLOCK_BY_DRIVER
822 printk(" coreClock = %lu\n", coreClock);
828 gckDebugFileSystemInitialize();
831 /* Create the GAL device. */
832 gcmkONERROR(gckGALDEVICE_Construct(
834 registerMemBase, registerMemSize,
836 registerMemBase2D, registerMemSize2D,
838 registerMemBaseVG, registerMemSizeVG,
839 contiguousBase, contiguousSize,
840 bankSize, fastClear, compression, baseAddress, physSize, signal,
847 /* Start the GAL device. */
848 gcmkONERROR(gckGALDEVICE_Start(device));
851 && (device->kernels[gcvCORE_MAJOR] != gcvNULL)
852 && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0))
854 status = gckMMU_Enable(device->kernels[gcvCORE_MAJOR]->mmu, baseAddress, physSize);
855 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER,
856 "Enable new MMU: status=%d\n", status);
858 if ((device->kernels[gcvCORE_2D] != gcvNULL)
859 && (device->kernels[gcvCORE_2D]->hardware->mmuVersion != 0))
861 status = gckMMU_Enable(device->kernels[gcvCORE_2D]->mmu, baseAddress, physSize);
862 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER,
863 "Enable new MMU for 2D: status=%d\n", status);
866 /* Reset the base address */
867 device->baseAddress = 0;
870 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
871 task_free_register(&task_nb);
872 viv_gpu_resmem_handler.data = device->kernels[gcvCORE_MAJOR];
873 register_reserved_memory_account(&viv_gpu_resmem_handler);
877 /* Register the character device. */
878 ret = register_chrdev(major, DRV_NAME, &driver_fops);
883 gcvLEVEL_ERROR, gcvZONE_DRIVER,
884 "%s(%d): Could not allocate major number for mmap.\n",
885 __FUNCTION__, __LINE__
888 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
896 /* Create the device class. */
897 device_class = class_create(THIS_MODULE, "graphics_class");
899 if (IS_ERR(device_class))
902 gcvLEVEL_ERROR, gcvZONE_DRIVER,
903 "%s(%d): Failed to create the class.\n",
904 __FUNCTION__, __LINE__
907 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
910 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
911 device_create(device_class, NULL, MKDEV(major, 0), NULL, "galcore");
913 device_create(device_class, NULL, MKDEV(major, 0), "galcore");
917 gpuClass = device_class;
920 gcvLEVEL_INFO, gcvZONE_DRIVER,
921 "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n",
922 __FUNCTION__, __LINE__,
923 irqLine, contiguousSize, registerMemBase
932 if (device_class != gcvNULL)
934 device_destroy(device_class, MKDEV(major, 0));
935 class_destroy(device_class);
938 if (device != gcvNULL)
940 gcmkVERIFY_OK(gckGALDEVICE_Stop(device));
941 gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
948 #if !USE_PLATFORM_DRIVER
949 static void __exit drv_exit(void)
951 static void drv_exit(void)
956 #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
957 task_free_unregister(&task_nb);
958 unregister_reserved_memory_account(&viv_gpu_resmem_handler);
961 gcmkASSERT(gpuClass != gcvNULL);
962 device_destroy(gpuClass, MKDEV(major, 0));
963 class_destroy(gpuClass);
965 unregister_chrdev(major, DRV_NAME);
967 gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice));
968 gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice));
970 if(gckDebugFileSystemIsEnabled())
972 gckDebugFileSystemTerminate();
975 #if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
978 struct clk * clk = NULL;
980 #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
983 clk = clk_get(NULL, "GCCLK");
992 #if !USE_PLATFORM_DRIVER
993 module_init(drv_init);
994 module_exit(drv_exit);
997 #ifdef CONFIG_DOVE_GPU
998 # define DEVICE_NAME "dove_gpu"
1000 # define DEVICE_NAME "galcore"
1003 #if gcdENABLE_FSCALE_VAL_ADJUST
1004 static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
1007 static gctUINT orgFscale, minFscale, maxFscale;
1008 static gctBOOL bAlreadyTooHot = gcvFALSE;
1009 gckHARDWARE hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;
1011 if (event && !bAlreadyTooHot) {
1012 gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
1013 gckHARDWARE_SetFscaleValue(hardware, minFscale);
1014 bAlreadyTooHot = gcvTRUE;
1015 gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
1016 } else if (!event && bAlreadyTooHot) {
1017 gckHARDWARE_SetFscaleValue(hardware, orgFscale);
1018 gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
1019 bAlreadyTooHot = gcvFALSE;
1024 static struct notifier_block thermal_hot_pm_notifier = {
1025 .notifier_call = thermal_hot_pm_notify,
1031 static int __devinit gpu_probe(struct platform_device *pdev)
1034 struct resource* res;
1035 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1036 struct device_node *dn =pdev->dev.of_node;
1039 struct viv_gpu_platform_data *pdata;
1043 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
1045 baseAddress = res->start;
1047 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
1049 irqLine = res->start;
1051 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
1054 registerMemBase = res->start;
1055 registerMemSize = res->end - res->start + 1;
1058 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
1060 irqLine2D = res->start;
1062 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
1065 registerMemBase2D = res->start;
1066 registerMemSize2D = res->end - res->start + 1;
1069 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
1071 irqLineVG = res->start;
1073 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
1076 registerMemBaseVG = res->start;
1077 registerMemSizeVG = res->end - res->start + 1;
1080 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1081 prop = of_get_property(dn, "contiguousbase", NULL);
1083 contiguousBase = *prop;
1084 of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
1086 pdata = pdev->dev.platform_data;
1088 contiguousBase = pdata->reserved_mem_base;
1089 contiguousSize = pdata->reserved_mem_size;
1092 if (contiguousSize == 0)
1093 gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n ");
1094 ret = drv_init(&pdev->dev);
1098 platform_set_drvdata(pdev, galDevice);
1100 #if gcdENABLE_FSCALE_VAL_ADJUST
1101 if(galDevice->kernels[gcvCORE_MAJOR])
1102 register_thermal_notifier(&thermal_hot_pm_notifier);
1107 #if gcdENABLE_FSCALE_VAL_ADJUST
1108 unregister_thermal_notifier(&thermal_hot_pm_notifier);
1110 gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret);
1114 static int __devexit gpu_remove(struct platform_device *pdev)
1117 #if gcdENABLE_FSCALE_VAL_ADJUST
1118 if(galDevice->kernels[gcvCORE_MAJOR])
1119 unregister_thermal_notifier(&thermal_hot_pm_notifier);
1126 static int gpu_suspend(struct platform_device *dev, pm_message_t state)
1129 gckGALDEVICE device;
1132 device = platform_get_drvdata(dev);
1134 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
1136 if (device->kernels[i] != gcvNULL)
1140 if (i == gcvCORE_VG)
1142 status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]);
1147 status = gckHARDWARE_QueryPowerManagementState(device->kernels[i]->hardware, &device->statesStored[i]);
1150 if (gcmIS_ERROR(status))
1156 if (i == gcvCORE_VG)
1158 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_OFF);
1163 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF);
1165 if (gcmIS_ERROR(status))
1176 static int gpu_resume(struct platform_device *dev)
1179 gckGALDEVICE device;
1181 gceCHIPPOWERSTATE statesStored;
1183 device = platform_get_drvdata(dev);
1185 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
1187 if (device->kernels[i] != gcvNULL)
1190 if (i == gcvCORE_VG)
1192 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
1197 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON);
1200 if (gcmIS_ERROR(status))
1205 /* Convert global state to crossponding internal state. */
1206 switch(device->statesStored[i])
1209 statesStored = gcvPOWER_OFF_BROADCAST;
1212 statesStored = gcvPOWER_IDLE_BROADCAST;
1214 case gcvPOWER_SUSPEND:
1215 statesStored = gcvPOWER_SUSPEND_BROADCAST;
1218 statesStored = gcvPOWER_ON_AUTO;
1221 statesStored = device->statesStored[i];
1225 /* Restore states. */
1227 if (i == gcvCORE_VG)
1229 status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, statesStored);
1234 status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, statesStored);
1237 if (gcmIS_ERROR(status))
1247 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1248 static const struct of_device_id mxs_gpu_dt_ids[] = {
1249 { .compatible = "fsl,imx6q-gpu", },
1252 MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids);
1255 static int gpu_runtime_suspend(struct device *dev)
1257 release_bus_freq(BUS_FREQ_HIGH);
1261 static int gpu_runtime_resume(struct device *dev)
1263 request_bus_freq(BUS_FREQ_HIGH);
1267 static int gpu_system_suspend(struct device *dev)
1269 pm_message_t state={0};
1270 return gpu_suspend(to_platform_device(dev), state);
1273 static int gpu_system_resume(struct device *dev)
1275 return gpu_resume(to_platform_device(dev));
1278 static const struct dev_pm_ops gpu_pm_ops = {
1279 SET_RUNTIME_PM_OPS(gpu_runtime_suspend, gpu_runtime_resume, NULL)
1280 SET_SYSTEM_SLEEP_PM_OPS(gpu_system_suspend, gpu_system_resume)
1285 static struct platform_driver gpu_driver = {
1287 .remove = __devexit_p(gpu_remove),
1289 .suspend = gpu_suspend,
1290 .resume = gpu_resume,
1293 .name = DEVICE_NAME,
1294 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
1295 .of_match_table = mxs_gpu_dt_ids,
1303 #if 0 /*CONFIG_DOVE_GPU*/
1304 static struct resource gpu_resources[] = {
1307 .flags = IORESOURCE_IRQ,
1311 .flags = IORESOURCE_MEM,
1315 .flags = IORESOURCE_MEM,
1319 static struct platform_device * gpu_device;
1322 static int __init gpu_init(void)
1326 #if 0 /*ndef CONFIG_DOVE_GPU*/
1327 gpu_resources[0].start = gpu_resources[0].end = irqLine;
1329 gpu_resources[1].start = registerMemBase;
1330 gpu_resources[1].end = registerMemBase + registerMemSize - 1;
1332 gpu_resources[2].start = contiguousBase;
1333 gpu_resources[2].end = contiguousBase + contiguousSize - 1;
1335 /* Allocate device */
1336 gpu_device = platform_device_alloc(DEVICE_NAME, -1);
1339 printk(KERN_ERR "galcore: platform_device_alloc failed.\n");
1344 /* Insert resource */
1345 ret = platform_device_add_resources(gpu_device, gpu_resources, 3);
1348 printk(KERN_ERR "galcore: platform_device_add_resources failed.\n");
1353 ret = platform_device_add(gpu_device);
1356 printk(KERN_ERR "galcore: platform_device_add failed.\n");
1361 ret = platform_driver_register(&gpu_driver);
1367 #if 0 /*ndef CONFIG_DOVE_GPU*/
1368 platform_device_del(gpu_device);
1370 platform_device_put(gpu_device);
1377 static void __exit gpu_exit(void)
1379 platform_driver_unregister(&gpu_driver);
1380 #if 0 /*ndef CONFIG_DOVE_GPU*/
1381 platform_device_unregister(gpu_device);
1385 module_init(gpu_init);
1386 module_exit(gpu_exit);