0a9ada95c52bfaf8f746a348fb3f68044a9585a4
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / linux / mali_kernel_linux.c
1 /**
2  * Copyright (C) 2010-2014 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11
12 /**
13  * @file mali_kernel_linux.c
14  * Implementation of the Linux device driver entrypoints
15  */
16 #include "../platform/rk30/custom_log.h"
17
18 #include <linux/module.h>   /* kernel module definitions */
19 #include <linux/fs.h>       /* file system operations */
20 #include <linux/cdev.h>     /* character device definitions */
21 #include <linux/mm.h>       /* memory manager definitions */
22 #include <linux/mali/mali_utgard_ioctl.h>
23 #include <linux/version.h>
24 #include <linux/device.h>
25 #include "mali_kernel_license.h"
26 #include <linux/platform_device.h>
27 #include <linux/miscdevice.h>
28 #include <linux/bug.h>
29 #include <linux/of.h>
30
31 #include <linux/mali/mali_utgard.h>
32 #include "mali_kernel_common.h"
33 #include "mali_session.h"
34 #include "mali_kernel_core.h"
35 #include "mali_osk.h"
36 #include "mali_kernel_linux.h"
37 #include "mali_ukk.h"
38 #include "mali_ukk_wrappers.h"
39 #include "mali_kernel_sysfs.h"
40 #include "mali_pm.h"
41 #include "mali_kernel_license.h"
42 #include "mali_memory.h"
43 #include "mali_memory_dma_buf.h"
44 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
45 #include "mali_profiling_internal.h"
46 #endif
47 #if defined(CONFIG_MALI400_PROFILING) && defined(CONFIG_MALI_DVFS)
48 #include "mali_osk_profiling.h"
49 #include "mali_dvfs_policy.h"
50 static int is_first_resume = 1;
51 /*Store the clk and vol for boot/insmod and mali_resume*/
52 static struct mali_gpu_clk_item mali_gpu_clk[2];
53 #endif
54
55 /* Streamline support for the Mali driver */
56 #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_MALI400_PROFILING)
57 /* Ask Linux to create the tracepoints */
58 #define CREATE_TRACE_POINTS
59 #include "mali_linux_trace.h"
60
61 EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_event);
62 EXPORT_TRACEPOINT_SYMBOL_GPL(mali_hw_counter);
63 EXPORT_TRACEPOINT_SYMBOL_GPL(mali_sw_counters);
64 #endif /* CONFIG_TRACEPOINTS */
65
66 /* from the __malidrv_build_info.c file that is generated during build */
67 extern const char *__malidrv_build_info(void);
68
69 /* Module parameter to control log level */
70 int mali_debug_level = 2;
71 module_param(mali_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
72 MODULE_PARM_DESC(mali_debug_level, "Higher number, more dmesg output");
73
74 extern int mali_max_job_runtime;
75 module_param(mali_max_job_runtime, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
76 MODULE_PARM_DESC(mali_max_job_runtime, "Maximum allowed job runtime in msecs.\nJobs will be killed after this no matter what");
77
78 extern int mali_l2_max_reads;
79 module_param(mali_l2_max_reads, int, S_IRUSR | S_IRGRP | S_IROTH);
80 MODULE_PARM_DESC(mali_l2_max_reads, "Maximum reads for Mali L2 cache");
81
82 extern unsigned int mali_dedicated_mem_start;
83 module_param(mali_dedicated_mem_start, uint, S_IRUSR | S_IRGRP | S_IROTH);
84 MODULE_PARM_DESC(mali_dedicated_mem_start, "Physical start address of dedicated Mali GPU memory.");
85
86 extern unsigned int mali_dedicated_mem_size;
87 module_param(mali_dedicated_mem_size, uint, S_IRUSR | S_IRGRP | S_IROTH);
88 MODULE_PARM_DESC(mali_dedicated_mem_size, "Size of dedicated Mali GPU memory.");
89
90 extern unsigned int mali_shared_mem_size;
91 module_param(mali_shared_mem_size, uint, S_IRUSR | S_IRGRP | S_IROTH);
92 MODULE_PARM_DESC(mali_shared_mem_size, "Size of shared Mali GPU memory.");
93
94 #if defined(CONFIG_MALI400_PROFILING)
95 extern int mali_boot_profiling;
96 module_param(mali_boot_profiling, int, S_IRUSR | S_IRGRP | S_IROTH);
97 MODULE_PARM_DESC(mali_boot_profiling, "Start profiling as a part of Mali driver initialization");
98 #endif
99
100 extern int mali_max_pp_cores_group_1;
101 module_param(mali_max_pp_cores_group_1, int, S_IRUSR | S_IRGRP | S_IROTH);
102 MODULE_PARM_DESC(mali_max_pp_cores_group_1, "Limit the number of PP cores to use from first PP group.");
103
104 extern int mali_max_pp_cores_group_2;
105 module_param(mali_max_pp_cores_group_2, int, S_IRUSR | S_IRGRP | S_IROTH);
106 MODULE_PARM_DESC(mali_max_pp_cores_group_2, "Limit the number of PP cores to use from second PP group (Mali-450 only).");
107
108 #if defined(CONFIG_MALI_DVFS)
109 /** the max fps the same as display vsync default 60, can set by module insert parameter */
110 extern int mali_max_system_fps;
111 module_param(mali_max_system_fps, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
112 MODULE_PARM_DESC(mali_max_system_fps, "Max system fps the same as display VSYNC.");
113
114 /** a lower limit on their desired FPS default 58, can set by module insert parameter*/
115 extern int mali_desired_fps;
116 module_param(mali_desired_fps, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
117 MODULE_PARM_DESC(mali_desired_fps, "A bit lower than max_system_fps which user desired fps");
118 #endif
119
120 #if MALI_ENABLE_CPU_CYCLES
121 #include <linux/cpumask.h>
122 #include <linux/timer.h>
123 #include <asm/smp.h>
124 static struct timer_list mali_init_cpu_clock_timers[8];
125 static u32 mali_cpu_clock_last_value[8] = {0,};
126 #endif
127
128 /* Export symbols from common code: mali_user_settings.c */
129 #include "mali_user_settings_db.h"
130 EXPORT_SYMBOL(mali_set_user_setting);
131 EXPORT_SYMBOL(mali_get_user_setting);
132
133 static char mali_dev_name[] = "mali"; /* should be const, but the functions we call requires non-cost */
134
135 /* This driver only supports one Mali device, and this variable stores this single platform device */
136 struct platform_device *mali_platform_device = NULL;
137
138 /* This driver only supports one Mali device, and this variable stores the exposed misc device (/dev/mali) */
139 static struct miscdevice mali_miscdevice = { 0, };
140
141 static int mali_miscdevice_register(struct platform_device *pdev);
142 static void mali_miscdevice_unregister(void);
143
144 static int mali_open(struct inode *inode, struct file *filp);
145 static int mali_release(struct inode *inode, struct file *filp);
146 #ifdef HAVE_UNLOCKED_IOCTL
147 static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
148 #else
149 static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
150 #endif
151
152 static int mali_probe(struct platform_device *pdev);
153 static int mali_remove(struct platform_device *pdev);
154
155 static int mali_driver_suspend_scheduler(struct device *dev);
156 static int mali_driver_resume_scheduler(struct device *dev);
157
158 #ifdef CONFIG_PM_RUNTIME
159 static int mali_driver_runtime_suspend(struct device *dev);
160 static int mali_driver_runtime_resume(struct device *dev);
161 static int mali_driver_runtime_idle(struct device *dev);
162 #endif
163
164 #if defined(MALI_FAKE_PLATFORM_DEVICE)
165 #if defined(CONFIG_MALI_DT)
166 extern int mali_platform_device_init(struct platform_device *device);
167 extern int mali_platform_device_deinit(struct platform_device *device);
168 #else
169 extern int mali_platform_device_register(void);
170 extern int mali_platform_device_unregister(void);
171 #endif
172 #endif
173
174 /* Linux power management operations provided by the Mali device driver */
175 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29))
176 struct pm_ext_ops mali_dev_ext_pm_ops = {
177         .base =
178         {
179                 .suspend = mali_driver_suspend_scheduler,
180                 .resume = mali_driver_resume_scheduler,
181                 .freeze = mali_driver_suspend_scheduler,
182                 .thaw =   mali_driver_resume_scheduler,
183         },
184 };
185 #else
186 static const struct dev_pm_ops mali_dev_pm_ops = {
187 #ifdef CONFIG_PM_RUNTIME
188         .runtime_suspend = mali_driver_runtime_suspend,
189         .runtime_resume = mali_driver_runtime_resume,
190         .runtime_idle = mali_driver_runtime_idle,
191 #endif
192         .suspend = mali_driver_suspend_scheduler,
193         .resume = mali_driver_resume_scheduler,
194         .freeze = mali_driver_suspend_scheduler,
195         .thaw = mali_driver_resume_scheduler,
196         .poweroff = mali_driver_suspend_scheduler,
197 };
198 #endif
199
200 #ifdef CONFIG_MALI_DT
201 static struct of_device_id base_dt_ids[] = {
202         {.compatible = "arm,mali-300"},
203     /*-------------------------------------------------------*/
204     /* rk_ext : to use dts_for_mali_ko_befor_r5p0-01rel0. */
205         // {.compatible = "arm,mali-400"},
206         {.compatible = "arm,mali400"},
207     /*-------------------------------------------------------*/
208         {.compatible = "arm,mali-450"},
209         {.compatible = "arm,mali-utgard"},
210         {},
211 };
212
213 MODULE_DEVICE_TABLE(of, base_dt_ids);
214 #endif
215
216 /* The Mali device driver struct */
217 static struct platform_driver mali_platform_driver = {
218         .probe  = mali_probe,
219         .remove = mali_remove,
220 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29))
221         .pm = &mali_dev_ext_pm_ops,
222 #endif
223         .driver =
224         {
225                 .name   = MALI_GPU_NAME_UTGARD,
226                 .owner  = THIS_MODULE,
227                 .bus = &platform_bus_type,
228 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
229                 .pm = &mali_dev_pm_ops,
230 #endif
231 #ifdef CONFIG_MALI_DT
232                 .of_match_table = of_match_ptr(base_dt_ids),
233 #endif
234         },
235 };
236
237 /* Linux misc device operations (/dev/mali) */
238 struct file_operations mali_fops = {
239         .owner = THIS_MODULE,
240         .open = mali_open,
241         .release = mali_release,
242 #ifdef HAVE_UNLOCKED_IOCTL
243         .unlocked_ioctl = mali_ioctl,
244 #else
245         .ioctl = mali_ioctl,
246 #endif
247         .compat_ioctl = mali_ioctl,
248         .mmap = mali_mmap
249 };
250
251 #if MALI_ENABLE_CPU_CYCLES
252 void mali_init_cpu_time_counters(int reset, int enable_divide_by_64)
253 {
254         /* The CPU assembly reference used is: ARM Architecture Reference Manual ARMv7-AR C.b */
255         u32 write_value;
256
257         /* See B4.1.116 PMCNTENSET, Performance Monitors Count Enable Set register, VMSA */
258         /* setting p15 c9 c12 1 to 0x8000000f==CPU_CYCLE_ENABLE |EVENT_3_ENABLE|EVENT_2_ENABLE|EVENT_1_ENABLE|EVENT_0_ENABLE */
259         asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(0x8000000f));
260
261
262         /* See B4.1.117 PMCR, Performance Monitors Control Register. Writing to p15, c9, c12, 0 */
263         write_value = 1 << 0; /* Bit 0 set. Enable counters */
264         if (reset) {
265                 write_value |= 1 << 1; /* Reset event counters */
266                 write_value |= 1 << 2; /* Reset cycle counter  */
267         }
268         if (enable_divide_by_64) {
269                 write_value |= 1 << 3; /* Enable the Clock divider by 64 */
270         }
271         write_value |= 1 << 4; /* Export enable. Not needed */
272         asm volatile("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(write_value));
273
274         /* PMOVSR Overflow Flag Status Register - Clear Clock and Event overflows */
275         asm volatile("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f));
276
277
278         /* See B4.1.124 PMUSERENR - setting p15 c9 c14 to 1" */
279         /* User mode access to the Performance Monitors enabled. */
280         /* Lets User space read cpu clock cycles */
281         asm volatile("mcr p15, 0, %0, c9, c14, 0" :: "r"(1));
282 }
283
284 /** A timer function that configures the cycle clock counter on current CPU.
285  * The function \a mali_init_cpu_time_counters_on_all_cpus sets up this
286  * function to trigger on all Cpus during module load.
287  */
288 static void mali_init_cpu_clock_timer_func(unsigned long data)
289 {
290         int reset_counters, enable_divide_clock_counter_by_64;
291         int current_cpu = raw_smp_processor_id();
292         unsigned int sample0;
293         unsigned int sample1;
294
295         MALI_IGNORE(data);
296
297         reset_counters = 1;
298         enable_divide_clock_counter_by_64 = 0;
299         mali_init_cpu_time_counters(reset_counters, enable_divide_clock_counter_by_64);
300
301         sample0 = mali_get_cpu_cyclecount();
302         sample1 = mali_get_cpu_cyclecount();
303
304         MALI_DEBUG_PRINT(3, ("Init Cpu %d cycle counter- First two samples: %08x %08x \n", current_cpu, sample0, sample1));
305 }
306
307 /** A timer functions for storing current time on all cpus.
308  * Used for checking if the clocks have similar values or if they are drifting.
309  */
310 static void mali_print_cpu_clock_timer_func(unsigned long data)
311 {
312         int current_cpu = raw_smp_processor_id();
313         unsigned int sample0;
314
315         MALI_IGNORE(data);
316         sample0 = mali_get_cpu_cyclecount();
317         if (current_cpu < 8) {
318                 mali_cpu_clock_last_value[current_cpu] = sample0;
319         }
320 }
321
322 /** Init the performance registers on all CPUs to count clock cycles.
323  * For init \a print_only should be 0.
324  * If \a print_only is 1, it will intead print the current clock value of all CPUs.
325  */
326 void mali_init_cpu_time_counters_on_all_cpus(int print_only)
327 {
328         int i = 0;
329         int cpu_number;
330         int jiffies_trigger;
331         int jiffies_wait;
332
333         jiffies_wait = 2;
334         jiffies_trigger = jiffies + jiffies_wait;
335
336         for (i = 0 ; i < 8 ; i++) {
337                 init_timer(&mali_init_cpu_clock_timers[i]);
338                 if (print_only) mali_init_cpu_clock_timers[i].function = mali_print_cpu_clock_timer_func;
339                 else            mali_init_cpu_clock_timers[i].function = mali_init_cpu_clock_timer_func;
340                 mali_init_cpu_clock_timers[i].expires = jiffies_trigger ;
341         }
342         cpu_number = cpumask_first(cpu_online_mask);
343         for (i = 0 ; i < 8 ; i++) {
344                 int next_cpu;
345                 add_timer_on(&mali_init_cpu_clock_timers[i], cpu_number);
346                 next_cpu = cpumask_next(cpu_number, cpu_online_mask);
347                 if (next_cpu >= nr_cpu_ids) break;
348                 cpu_number = next_cpu;
349         }
350
351         while (jiffies_wait) jiffies_wait = schedule_timeout_uninterruptible(jiffies_wait);
352
353         for (i = 0 ; i < 8 ; i++) {
354                 del_timer_sync(&mali_init_cpu_clock_timers[i]);
355         }
356
357         if (print_only) {
358                 if ((0 == mali_cpu_clock_last_value[2]) && (0 == mali_cpu_clock_last_value[3])) {
359                         /* Diff can be printed if we want to check if the clocks are in sync
360                         int diff = mali_cpu_clock_last_value[0] - mali_cpu_clock_last_value[1];*/
361                         MALI_DEBUG_PRINT(2, ("CPU cycle counters readout all: %08x %08x\n", mali_cpu_clock_last_value[0], mali_cpu_clock_last_value[1]));
362                 } else {
363                         MALI_DEBUG_PRINT(2, ("CPU cycle counters readout all: %08x %08x %08x %08x\n", mali_cpu_clock_last_value[0], mali_cpu_clock_last_value[1], mali_cpu_clock_last_value[2], mali_cpu_clock_last_value[3]));
364                 }
365         }
366 }
367 #endif
368
369 /** rk_ext : version of rk_ext on mali_ko, aka. rk_ko_ver. */
370 #define ROCKCHIP_VERSION    (1)
371
372 int mali_module_init(void)
373 {
374         int err = 0;
375
376         MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n", _MALI_API_VERSION));
377         MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__));
378         MALI_DEBUG_PRINT(2, ("Driver revision: %s\n", SVN_REV_STRING));
379     
380     I("arm_release_ver of this mali_ko is '%s', rk_ko_ver is '%d', built at '%s', on '%s'.",
381         SVN_REV_STRING,
382         ROCKCHIP_VERSION,
383         __TIME__,
384         __DATE__);
385
386 #if MALI_ENABLE_CPU_CYCLES
387         mali_init_cpu_time_counters_on_all_cpus(0);
388         MALI_DEBUG_PRINT(2, ("CPU cycle counter setup complete\n"));
389         /* Printing the current cpu counters */
390         mali_init_cpu_time_counters_on_all_cpus(1);
391 #endif
392
393         /* Initialize module wide settings */
394 #ifdef MALI_FAKE_PLATFORM_DEVICE
395 #ifndef CONFIG_MALI_DT
396         MALI_DEBUG_PRINT(2, ("mali_module_init() registering device\n"));
397         err = mali_platform_device_register();
398         if (0 != err) {
399                 return err;
400         }
401 #endif
402 #endif
403
404         MALI_DEBUG_PRINT(2, ("mali_module_init() registering driver\n"));
405
406         err = platform_driver_register(&mali_platform_driver);
407
408         if (0 != err) {
409                 MALI_DEBUG_PRINT(2, ("mali_module_init() Failed to register driver (%d)\n", err));
410 #ifdef MALI_FAKE_PLATFORM_DEVICE
411 #ifndef CONFIG_MALI_DT
412         mali_platform_device_unregister();
413 #endif
414 #endif
415                 mali_platform_device = NULL;
416                 return err;
417         }
418
419 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
420         err = _mali_internal_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE);
421         if (0 != err) {
422                 /* No biggie if we wheren't able to initialize the profiling */
423                 MALI_PRINT_ERROR(("Failed to initialize profiling, feature will be unavailable\n"));
424         }
425 #endif
426
427         /* Tracing the current frequency and voltage from boot/insmod*/
428 #if defined(CONFIG_MALI400_PROFILING) && defined(CONFIG_MALI_DVFS)
429         /* Just call mali_get_current_gpu_clk_item(),to record current clk info.*/
430         mali_get_current_gpu_clk_item(&mali_gpu_clk[0]);
431         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
432                                           MALI_PROFILING_EVENT_CHANNEL_GPU |
433                                           MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
434                                           mali_gpu_clk[0].clock,
435                                           mali_gpu_clk[0].vol / 1000,
436                                           0, 0, 0);
437 #endif
438
439         MALI_PRINT(("Mali device driver loaded\n"));
440
441         return 0; /* Success */
442 }
443
444 void mali_module_exit(void)
445 {
446         MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n", _MALI_API_VERSION));
447
448         MALI_DEBUG_PRINT(2, ("mali_module_exit() unregistering driver\n"));
449
450         platform_driver_unregister(&mali_platform_driver);
451
452 #if defined(MALI_FAKE_PLATFORM_DEVICE)
453 #ifndef CONFIG_MALI_DT
454         MALI_DEBUG_PRINT(2, ("mali_module_exit() unregistering device\n"));
455         mali_platform_device_unregister();
456 #endif
457 #endif
458
459         /* Tracing the current frequency and voltage from rmmod*/
460         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
461                                       MALI_PROFILING_EVENT_CHANNEL_GPU |
462                                       MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
463                                       0,
464                                       0,
465                                       0, 0, 0);
466
467 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
468         _mali_internal_profiling_term();
469 #endif
470
471         MALI_PRINT(("Mali device driver unloaded\n"));
472 }
473
474 static int mali_probe(struct platform_device *pdev)
475 {
476         int err;
477
478         MALI_DEBUG_PRINT(2, ("mali_probe(): Called for platform device %s\n", pdev->name));
479
480         if (NULL != mali_platform_device) {
481                 /* Already connected to a device, return error */
482                 MALI_PRINT_ERROR(("mali_probe(): The Mali driver is already connected with a Mali device."));
483                 return -EEXIST;
484         }
485
486         mali_platform_device = pdev;
487
488         dev_info(&pdev->dev, "mali_platform_device->num_resources = %d\n",
489                 mali_platform_device->num_resources);
490         
491         {
492                 int i = 0;
493
494                 for(i = 0; i < mali_platform_device->num_resources; i++)
495                         dev_info(&pdev->dev, "mali_platform_device->resource[%d].start = 0x%08x\n",
496                                 i, mali_platform_device->resource[i].start);
497         }
498
499 #ifdef CONFIG_MALI_DT
500         /* If we use DT to initialize our DDK, we have to prepare somethings. */
501         err = mali_platform_device_init(mali_platform_device);
502         if (0 != err) {
503                 MALI_PRINT_ERROR(("mali_probe(): Failed to initialize platform device."));
504                 return -EFAULT;
505         }
506 #endif
507
508         if (_MALI_OSK_ERR_OK == _mali_osk_wq_init()) {
509                 /* Initialize the Mali GPU HW specified by pdev */
510                 if (_MALI_OSK_ERR_OK == mali_initialize_subsystems()) {
511                         /* Register a misc device (so we are accessible from user space) */
512                         err = mali_miscdevice_register(pdev);
513                         if (0 == err) {
514                                 /* Setup sysfs entries */
515                                 err = mali_sysfs_register(mali_dev_name);
516
517                                 if (0 == err) {
518                                         MALI_DEBUG_PRINT(2, ("mali_probe(): Successfully initialized driver for platform device %s\n", pdev->name));
519
520                                         return 0;
521                                 } else {
522                                         MALI_PRINT_ERROR(("mali_probe(): failed to register sysfs entries"));
523                                 }
524                                 mali_miscdevice_unregister();
525                         } else {
526                                 MALI_PRINT_ERROR(("mali_probe(): failed to register Mali misc device."));
527                         }
528                         mali_terminate_subsystems();
529                 } else {
530                         MALI_PRINT_ERROR(("mali_probe(): Failed to initialize Mali device driver."));
531                 }
532                 _mali_osk_wq_term();
533         }
534
535         mali_platform_device = NULL;
536         return -EFAULT;
537 }
538
539 static int mali_remove(struct platform_device *pdev)
540 {
541         MALI_DEBUG_PRINT(2, ("mali_remove() called for platform device %s\n", pdev->name));
542         mali_sysfs_unregister();
543         mali_miscdevice_unregister();
544         mali_terminate_subsystems();
545         _mali_osk_wq_term();
546 #ifdef CONFIG_MALI_DT
547         mali_platform_device_deinit(mali_platform_device);
548 #endif
549         mali_platform_device = NULL;
550         return 0;
551 }
552
553 static int mali_miscdevice_register(struct platform_device *pdev)
554 {
555         int err;
556
557         mali_miscdevice.minor = MISC_DYNAMIC_MINOR;
558         mali_miscdevice.name = mali_dev_name;
559         mali_miscdevice.fops = &mali_fops;
560         mali_miscdevice.parent = get_device(&pdev->dev);
561
562         err = misc_register(&mali_miscdevice);
563         if (0 != err) {
564                 MALI_PRINT_ERROR(("Failed to register misc device, misc_register() returned %d\n", err));
565         }
566
567         return err;
568 }
569
570 static void mali_miscdevice_unregister(void)
571 {
572         misc_deregister(&mali_miscdevice);
573 }
574
575 static int mali_driver_suspend_scheduler(struct device *dev)
576 {
577         mali_pm_os_suspend(MALI_TRUE);
578         /* Tracing the frequency and voltage after mali is suspended */
579         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
580                                       MALI_PROFILING_EVENT_CHANNEL_GPU |
581                                       MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
582                                       0,
583                                       0,
584                                       0, 0, 0);
585         return 0;
586 }
587
588 static int mali_driver_resume_scheduler(struct device *dev)
589 {
590         /* Tracing the frequency and voltage after mali is resumed */
591 #if defined(CONFIG_MALI400_PROFILING) && defined(CONFIG_MALI_DVFS)
592         /* Just call mali_get_current_gpu_clk_item() once,to record current clk info.*/
593         if (is_first_resume == 1) {
594                 mali_get_current_gpu_clk_item(&mali_gpu_clk[1]);
595                 is_first_resume = 0;
596         }
597         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
598                                       MALI_PROFILING_EVENT_CHANNEL_GPU |
599                                       MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
600                                       mali_gpu_clk[1].clock,
601                                       mali_gpu_clk[1].vol / 1000,
602                                       0, 0, 0);
603 #endif
604         mali_pm_os_resume();
605         return 0;
606 }
607
608 #ifdef CONFIG_PM_RUNTIME
609 static int mali_driver_runtime_suspend(struct device *dev)
610 {
611         if (MALI_TRUE == mali_pm_runtime_suspend()) {
612                 /* Tracing the frequency and voltage after mali is suspended */
613                 _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
614                                               MALI_PROFILING_EVENT_CHANNEL_GPU |
615                                               MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
616                                               0,
617                                               0,
618                                               0, 0, 0);
619
620                 return 0;
621         } else {
622                 return -EBUSY;
623         }
624 }
625
626 static int mali_driver_runtime_resume(struct device *dev)
627 {
628         /* Tracing the frequency and voltage after mali is resumed */
629 #if defined(CONFIG_MALI400_PROFILING) && defined(CONFIG_MALI_DVFS)
630         /* Just call mali_get_current_gpu_clk_item() once,to record current clk info.*/
631         if (is_first_resume == 1) {
632                 mali_get_current_gpu_clk_item(&mali_gpu_clk[1]);
633                 is_first_resume = 0;
634         }
635         _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
636                                       MALI_PROFILING_EVENT_CHANNEL_GPU |
637                                       MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
638                                       mali_gpu_clk[1].clock,
639                                       mali_gpu_clk[1].vol / 1000,
640                                       0, 0, 0);
641 #endif
642
643         mali_pm_runtime_resume();
644         return 0;
645 }
646
647 static int mali_driver_runtime_idle(struct device *dev)
648 {
649         /* Nothing to do */
650         return 0;
651 }
652 #endif
653
654 static int mali_open(struct inode *inode, struct file *filp)
655 {
656         struct mali_session_data *session_data;
657         _mali_osk_errcode_t err;
658
659         /* input validation */
660         if (mali_miscdevice.minor != iminor(inode)) {
661                 MALI_PRINT_ERROR(("mali_open() Minor does not match\n"));
662                 return -ENODEV;
663         }
664
665         /* allocated struct to track this session */
666         err = _mali_ukk_open((void **)&session_data);
667         if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
668
669         /* initialize file pointer */
670         filp->f_pos = 0;
671
672         /* link in our session data */
673         filp->private_data = (void *)session_data;
674
675         return 0;
676 }
677
678 static int mali_release(struct inode *inode, struct file *filp)
679 {
680         _mali_osk_errcode_t err;
681
682         /* input validation */
683         if (mali_miscdevice.minor != iminor(inode)) {
684                 MALI_PRINT_ERROR(("mali_release() Minor does not match\n"));
685                 return -ENODEV;
686         }
687
688         err = _mali_ukk_close((void **)&filp->private_data);
689         if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
690
691         return 0;
692 }
693
694 int map_errcode(_mali_osk_errcode_t err)
695 {
696         switch (err) {
697         case _MALI_OSK_ERR_OK :
698                 return 0;
699         case _MALI_OSK_ERR_FAULT:
700                 return -EFAULT;
701         case _MALI_OSK_ERR_INVALID_FUNC:
702                 return -ENOTTY;
703         case _MALI_OSK_ERR_INVALID_ARGS:
704                 return -EINVAL;
705         case _MALI_OSK_ERR_NOMEM:
706                 return -ENOMEM;
707         case _MALI_OSK_ERR_TIMEOUT:
708                 return -ETIMEDOUT;
709         case _MALI_OSK_ERR_RESTARTSYSCALL:
710                 return -ERESTARTSYS;
711         case _MALI_OSK_ERR_ITEM_NOT_FOUND:
712                 return -ENOENT;
713         default:
714                 return -EFAULT;
715         }
716 }
717
718 #ifdef HAVE_UNLOCKED_IOCTL
719 static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
720 #else
721 static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
722 #endif
723 {
724         int err;
725         struct mali_session_data *session_data;
726
727 #ifndef HAVE_UNLOCKED_IOCTL
728         /* inode not used */
729         (void)inode;
730 #endif
731
732         MALI_DEBUG_PRINT(7, ("Ioctl received 0x%08X 0x%08lX\n", cmd, arg));
733
734         session_data = (struct mali_session_data *)filp->private_data;
735         if (NULL == session_data) {
736                 MALI_DEBUG_PRINT(7, ("filp->private_data was NULL\n"));
737                 return -ENOTTY;
738         }
739
740         if (NULL == (void *)arg) {
741                 MALI_DEBUG_PRINT(7, ("arg was NULL\n"));
742                 return -ENOTTY;
743         }
744
745         switch (cmd) {
746         case MALI_IOC_WAIT_FOR_NOTIFICATION:
747                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_wait_for_notification_s), sizeof(u64)));
748                 err = wait_for_notification_wrapper(session_data, (_mali_uk_wait_for_notification_s __user *)arg);
749                 break;
750
751         case MALI_IOC_GET_API_VERSION_V2:
752                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_get_api_version_v2_s), sizeof(u64)));
753                 err = get_api_version_v2_wrapper(session_data, (_mali_uk_get_api_version_v2_s __user *)arg);
754                 break;
755
756         case MALI_IOC_GET_API_VERSION:
757                 err = get_api_version_wrapper(session_data, (_mali_uk_get_api_version_s __user *)arg);
758                 break;
759
760         case MALI_IOC_POST_NOTIFICATION:
761                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_post_notification_s), sizeof(u64)));
762                 err = post_notification_wrapper(session_data, (_mali_uk_post_notification_s __user *)arg);
763                 break;
764
765         case MALI_IOC_GET_MALI_VERSION_IN_RK30:
766                 err = get_mali_version_in_rk30_wrapper(session_data, (_mali_uk_get_mali_version_in_rk30_s __user *)arg);
767                 break;
768
769         case MALI_IOC_GET_USER_SETTINGS:
770                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_get_user_settings_s), sizeof(u64)));
771                 err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg);
772                 break;
773
774         case MALI_IOC_REQUEST_HIGH_PRIORITY:
775                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_request_high_priority_s), sizeof(u64)));
776                 err = request_high_priority_wrapper(session_data, (_mali_uk_request_high_priority_s __user *)arg);
777                 break;
778
779 #if defined(CONFIG_MALI400_PROFILING)
780         case MALI_IOC_PROFILING_ADD_EVENT:
781                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_profiling_add_event_s), sizeof(u64)));
782                 err = profiling_add_event_wrapper(session_data, (_mali_uk_profiling_add_event_s __user *)arg);
783                 break;
784
785         case MALI_IOC_PROFILING_REPORT_SW_COUNTERS:
786                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_sw_counters_report_s), sizeof(u64)));
787                 err = profiling_report_sw_counters_wrapper(session_data, (_mali_uk_sw_counters_report_s __user *)arg);
788                 break;
789
790
791         case MALI_IOC_PROFILING_MEMORY_USAGE_GET:
792                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_profiling_memory_usage_get_s), sizeof(u64)));
793                 err = profiling_memory_usage_get_wrapper(session_data, (_mali_uk_profiling_memory_usage_get_s __user *)arg);
794                 break;
795
796 #else
797
798         case MALI_IOC_PROFILING_ADD_EVENT:          /* FALL-THROUGH */
799         case MALI_IOC_PROFILING_REPORT_SW_COUNTERS: /* FALL-THROUGH */
800         case MALI_IOC_PROFILING_MEMORY_USAGE_GET:   /* FALL-THROUGH */
801                 MALI_DEBUG_PRINT(2, ("Profiling not supported\n"));
802                 err = -ENOTTY;
803                 break;
804
805 #endif
806
807         case MALI_IOC_MEM_WRITE_SAFE:
808                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_mem_write_safe_s), sizeof(u64)));
809                 err = mem_write_safe_wrapper(session_data, (_mali_uk_mem_write_safe_s __user *)arg);
810                 break;
811
812         case MALI_IOC_MEM_MAP_EXT:
813                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_map_external_mem_s), sizeof(u64)));
814                 err = mem_map_ext_wrapper(session_data, (_mali_uk_map_external_mem_s __user *)arg);
815                 break;
816
817         case MALI_IOC_MEM_UNMAP_EXT:
818                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_unmap_external_mem_s), sizeof(u64)));
819                 err = mem_unmap_ext_wrapper(session_data, (_mali_uk_unmap_external_mem_s __user *)arg);
820                 break;
821
822         case MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE:
823                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_query_mmu_page_table_dump_size_s), sizeof(u64)));
824                 err = mem_query_mmu_page_table_dump_size_wrapper(session_data, (_mali_uk_query_mmu_page_table_dump_size_s __user *)arg);
825                 break;
826
827         case MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE:
828                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_dump_mmu_page_table_s), sizeof(u64)));
829                 err = mem_dump_mmu_page_table_wrapper(session_data, (_mali_uk_dump_mmu_page_table_s __user *)arg);
830                 break;
831
832 #if defined(CONFIG_MALI400_UMP)
833
834         case MALI_IOC_MEM_ATTACH_UMP:
835                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_attach_ump_mem_s), sizeof(u64)));
836                 err = mem_attach_ump_wrapper(session_data, (_mali_uk_attach_ump_mem_s __user *)arg);
837                 break;
838
839         case MALI_IOC_MEM_RELEASE_UMP:
840                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_release_ump_mem_s), sizeof(u64)));
841                 err = mem_release_ump_wrapper(session_data, (_mali_uk_release_ump_mem_s __user *)arg);
842                 break;
843
844 #else
845
846         case MALI_IOC_MEM_ATTACH_UMP:
847         case MALI_IOC_MEM_RELEASE_UMP: /* FALL-THROUGH */
848                 MALI_DEBUG_PRINT(2, ("UMP not supported\n"));
849                 err = -ENOTTY;
850                 break;
851 #endif
852
853 #ifdef CONFIG_DMA_SHARED_BUFFER
854         case MALI_IOC_MEM_ATTACH_DMA_BUF:
855                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_attach_dma_buf_s), sizeof(u64)));
856                 err = mali_attach_dma_buf(session_data, (_mali_uk_attach_dma_buf_s __user *)arg);
857                 break;
858
859         case MALI_IOC_MEM_RELEASE_DMA_BUF:
860                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_release_dma_buf_s), sizeof(u64)));
861                 err = mali_release_dma_buf(session_data, (_mali_uk_release_dma_buf_s __user *)arg);
862                 break;
863
864         case MALI_IOC_MEM_DMA_BUF_GET_SIZE:
865                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_dma_buf_get_size_s), sizeof(u64)));
866                 err = mali_dma_buf_get_size(session_data, (_mali_uk_dma_buf_get_size_s __user *)arg);
867                 break;
868 #else
869
870         case MALI_IOC_MEM_ATTACH_DMA_BUF:   /* FALL-THROUGH */
871         case MALI_IOC_MEM_RELEASE_DMA_BUF:  /* FALL-THROUGH */
872         case MALI_IOC_MEM_DMA_BUF_GET_SIZE: /* FALL-THROUGH */
873                 MALI_DEBUG_PRINT(2, ("DMA-BUF not supported\n"));
874                 err = -ENOTTY;
875                 break;
876 #endif
877
878         case MALI_IOC_PP_START_JOB:
879                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_pp_start_job_s), sizeof(u64)));
880                 err = pp_start_job_wrapper(session_data, (_mali_uk_pp_start_job_s __user *)arg);
881                 break;
882
883         case MALI_IOC_PP_AND_GP_START_JOB:
884                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_pp_and_gp_start_job_s), sizeof(u64)));
885                 err = pp_and_gp_start_job_wrapper(session_data, (_mali_uk_pp_and_gp_start_job_s __user *)arg);
886                 break;
887
888         case MALI_IOC_PP_NUMBER_OF_CORES_GET:
889                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_get_pp_number_of_cores_s), sizeof(u64)));
890                 err = pp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_pp_number_of_cores_s __user *)arg);
891                 break;
892
893         case MALI_IOC_PP_CORE_VERSION_GET:
894                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_get_pp_core_version_s), sizeof(u64)));
895                 err = pp_get_core_version_wrapper(session_data, (_mali_uk_get_pp_core_version_s __user *)arg);
896                 break;
897
898         case MALI_IOC_PP_DISABLE_WB:
899                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_pp_disable_wb_s), sizeof(u64)));
900                 err = pp_disable_wb_wrapper(session_data, (_mali_uk_pp_disable_wb_s __user *)arg);
901                 break;
902
903         case MALI_IOC_GP2_START_JOB:
904                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_gp_start_job_s), sizeof(u64)));
905                 err = gp_start_job_wrapper(session_data, (_mali_uk_gp_start_job_s __user *)arg);
906                 break;
907
908         case MALI_IOC_GP2_NUMBER_OF_CORES_GET:
909                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_get_gp_number_of_cores_s), sizeof(u64)));
910                 err = gp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_gp_number_of_cores_s __user *)arg);
911                 break;
912
913         case MALI_IOC_GP2_CORE_VERSION_GET:
914                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_get_gp_core_version_s), sizeof(u64)));
915                 err = gp_get_core_version_wrapper(session_data, (_mali_uk_get_gp_core_version_s __user *)arg);
916                 break;
917
918         case MALI_IOC_GP2_SUSPEND_RESPONSE:
919                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_gp_suspend_response_s), sizeof(u64)));
920                 err = gp_suspend_response_wrapper(session_data, (_mali_uk_gp_suspend_response_s __user *)arg);
921                 break;
922
923         case MALI_IOC_VSYNC_EVENT_REPORT:
924                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_vsync_event_report_s), sizeof(u64)));
925                 err = vsync_event_report_wrapper(session_data, (_mali_uk_vsync_event_report_s __user *)arg);
926                 break;
927
928         case MALI_IOC_TIMELINE_GET_LATEST_POINT:
929                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_timeline_get_latest_point_s), sizeof(u64)));
930                 err = timeline_get_latest_point_wrapper(session_data, (_mali_uk_timeline_get_latest_point_s __user *)arg);
931                 break;
932         case MALI_IOC_TIMELINE_WAIT:
933                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_timeline_wait_s), sizeof(u64)));
934                 err = timeline_wait_wrapper(session_data, (_mali_uk_timeline_wait_s __user *)arg);
935                 break;
936         case MALI_IOC_TIMELINE_CREATE_SYNC_FENCE:
937                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_timeline_create_sync_fence_s), sizeof(u64)));
938                 err = timeline_create_sync_fence_wrapper(session_data, (_mali_uk_timeline_create_sync_fence_s __user *)arg);
939                 break;
940         case MALI_IOC_SOFT_JOB_START:
941                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_soft_job_start_s), sizeof(u64)));
942                 err = soft_job_start_wrapper(session_data, (_mali_uk_soft_job_start_s __user *)arg);
943                 break;
944         case MALI_IOC_SOFT_JOB_SIGNAL:
945                 BUILD_BUG_ON(!IS_ALIGNED(sizeof(_mali_uk_soft_job_signal_s), sizeof(u64)));
946                 err = soft_job_signal_wrapper(session_data, (_mali_uk_soft_job_signal_s __user *)arg);
947                 break;
948
949         default:
950                 MALI_DEBUG_PRINT(2, ("No handler for ioctl 0x%08X 0x%08lX\n", cmd, arg));
951                 err = -ENOTTY;
952         };
953
954         return err;
955 }
956
957
958 module_init(mali_module_init);
959 module_exit(mali_module_exit);
960
961 MODULE_LICENSE(MALI_KERNEL_LINUX_LICENSE);
962 MODULE_AUTHOR("ARM Ltd.");
963 MODULE_VERSION(SVN_REV_STRING);