3 * MediaTek <www.MediaTek.com>
5 * MTK GPU Extension Device
9 #include <linux/cdev.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
13 #include <linux/hardirq.h>
14 #include <linux/init.h>
15 #include <linux/kallsyms.h>
16 #include <linux/miscdevice.h>
17 #include <linux/module.h>
18 #include <linux/poll.h>
19 #include <linux/proc_fs.h>
20 #include <linux/wait.h>
21 #include <linux/sched.h>
22 #include <linux/vmalloc.h>
23 #include <linux/disp_assert_layer.h>
24 #include <mach/system.h>
25 #include <linux/slab.h>
26 #include <linux/spinlock.h>
27 #include <linux/semaphore.h>
28 #include <linux/workqueue.h>
29 #include <linux/kthread.h>
30 #include <linux/aee.h>
32 #include "ged_debugFS.h"
34 #include "ged_bridge.h"
35 #include "ged_profile_dvfs.h"
36 #include "ged_monitor_3D_fence.h"
38 #define GED_DRIVER_DEVICE_NAME "ged"
40 #define GED_IOCTL_PARAM_BUF_SIZE 0x3000 //12KB
43 #define GED_LOG_BUF_COMMON_GLES "GLES"
44 static GED_LOG_BUF_HANDLE ghLogBuf_GLES
= 0;
45 GED_LOG_BUF_HANDLE ghLogBuf_GED
= 0;
48 static void* gvIOCTLParamBuf
= NULL
;
50 /******************************************************************************
52 *****************************************************************************/
53 static int ged_open(struct inode
*inode
, struct file
*filp
)
55 GED_LOGE("%s:%d:%d\n", __func__
, MAJOR(inode
->i_rdev
), MINOR(inode
->i_rdev
));
59 static int ged_release(struct inode
*inode
, struct file
*filp
)
61 GED_LOGE("%s:%d:%d\n", __func__
, MAJOR(inode
->i_rdev
), MINOR(inode
->i_rdev
));
65 static unsigned int ged_poll(struct file
*file
, struct poll_table_struct
*ptable
)
70 static ssize_t
ged_read(struct file
*filp
, char __user
*buf
, size_t count
, loff_t
*f_pos
)
75 static ssize_t
ged_write(struct file
*filp
, const char __user
*buf
, size_t count
, loff_t
*f_pos
)
80 static long ged_dispatch(GED_BRIDGE_PACKAGE
*psBridgePackageKM
)
84 typedef int (ged_bridge_func_type
)(void*, void*);
85 ged_bridge_func_type
* pFunc
= NULL
;
87 /* We make sure the both size and the sum of them are GE 0 integer.
88 * The sum will not overflow to zero, because we will get zero from two GE 0 integers
89 * if and only if they are both zero in a 2's complement numeral system.
90 * That is: if overflow happen, the sum will be a negative number.
92 if (psBridgePackageKM
->i32InBufferSize
>= 0 && psBridgePackageKM
->i32OutBufferSize
>= 0
93 && psBridgePackageKM
->i32InBufferSize
+ psBridgePackageKM
->i32OutBufferSize
>= 0
94 && psBridgePackageKM
->i32InBufferSize
+ psBridgePackageKM
->i32OutBufferSize
95 < GED_IOCTL_PARAM_BUF_SIZE
)
97 pvInt
= gvIOCTLParamBuf
;
98 pvOut
= (void*)((char*)pvInt
+ (uintptr_t)psBridgePackageKM
->i32InBufferSize
);
99 if (psBridgePackageKM
->i32InBufferSize
> 0)
101 if (0 != ged_copy_from_user(pvInt
, psBridgePackageKM
->pvParamIn
, psBridgePackageKM
->i32InBufferSize
))
103 GED_LOGE("ged_copy_from_user fail\n");
108 // we will change the below switch into a function pointer mapping table in the future
109 switch(GED_GET_BRIDGE_ID(psBridgePackageKM
->ui32FunctionID
))
111 case GED_BRIDGE_COMMAND_LOG_BUF_GET
:
112 pFunc
= (ged_bridge_func_type
*)ged_bridge_log_buf_get
;
114 case GED_BRIDGE_COMMAND_LOG_BUF_WRITE
:
115 pFunc
= (ged_bridge_func_type
*)ged_bridge_log_buf_write
;
117 case GED_BRIDGE_COMMAND_LOG_BUF_RESET
:
118 pFunc
= (ged_bridge_func_type
*)ged_bridge_log_buf_reset
;
120 case GED_BRIDGE_COMMAND_BOOST_GPU_FREQ
:
121 pFunc
= (ged_bridge_func_type
*)ged_bridge_boost_gpu_freq
;
123 case GED_BRIDGE_COMMAND_MONITOR_3D_FENCE
:
124 pFunc
= (ged_bridge_func_type
*)ged_bridge_monitor_3D_fence
;
127 GED_LOGE("Unknown Bridge ID: %u\n", GED_GET_BRIDGE_ID(psBridgePackageKM
->ui32FunctionID
));
133 ret
= pFunc(pvInt
, pvOut
);
136 if (psBridgePackageKM
->i32OutBufferSize
> 0)
138 if (0 != ged_copy_to_user(psBridgePackageKM
->pvParamOut
, pvOut
, psBridgePackageKM
->i32OutBufferSize
))
148 DEFINE_SEMAPHORE(ged_dal_sem
);
150 static long ged_ioctl(struct file
*pFile
, unsigned int ioctlCmd
, unsigned long arg
)
153 GED_BRIDGE_PACKAGE
*psBridgePackageKM
, *psBridgePackageUM
= (GED_BRIDGE_PACKAGE
*)arg
;
154 GED_BRIDGE_PACKAGE sBridgePackageKM
;
156 if (down_interruptible(&ged_dal_sem
) < 0)
158 GED_LOGE("Fail to down ged_dal_sem\n");
162 psBridgePackageKM
= &sBridgePackageKM
;
163 if (0 != ged_copy_from_user(psBridgePackageKM
, psBridgePackageUM
, sizeof(GED_BRIDGE_PACKAGE
)))
165 GED_LOGE("Fail to ged_copy_from_user\n");
166 goto unlock_and_return
;
169 ret
= ged_dispatch(psBridgePackageKM
);
178 static long ged_ioctl_compat(struct file
*pFile
, unsigned int ioctlCmd
, unsigned long arg
)
180 typedef struct GED_BRIDGE_PACKAGE_32_TAG
182 unsigned int ui32FunctionID
;
184 unsigned int ui32ParamIn
;
186 unsigned int ui32ParamOut
;
187 int i32OutBufferSize
;
188 } GED_BRIDGE_PACKAGE_32
;
191 GED_BRIDGE_PACKAGE sBridgePackageKM64
;
192 GED_BRIDGE_PACKAGE_32 sBridgePackageKM32
;
193 GED_BRIDGE_PACKAGE_32
*psBridgePackageKM32
= &sBridgePackageKM32
;
194 GED_BRIDGE_PACKAGE_32
*psBridgePackageUM32
= (GED_BRIDGE_PACKAGE_32
*)arg
;
196 if (down_interruptible(&ged_dal_sem
) < 0)
198 GED_LOGE("Fail to down ged_dal_sem\n");
202 if (0 != ged_copy_from_user(psBridgePackageKM32
, psBridgePackageUM32
, sizeof(GED_BRIDGE_PACKAGE_32
)))
204 GED_LOGE("Fail to ged_copy_from_user\n");
205 goto unlock_and_return
;
208 sBridgePackageKM64
.ui32FunctionID
= psBridgePackageKM32
->ui32FunctionID
;
209 sBridgePackageKM64
.i32Size
= sizeof(GED_BRIDGE_PACKAGE
);
210 sBridgePackageKM64
.pvParamIn
= (void*) ((size_t) psBridgePackageKM32
->ui32ParamIn
);
211 sBridgePackageKM64
.pvParamOut
= (void*) ((size_t) psBridgePackageKM32
->ui32ParamOut
);
212 sBridgePackageKM64
.i32InBufferSize
= psBridgePackageKM32
->i32InBufferSize
;
213 sBridgePackageKM64
.i32OutBufferSize
= psBridgePackageKM32
->i32OutBufferSize
;
215 ret
= ged_dispatch(&sBridgePackageKM64
);
224 /******************************************************************************
226 *****************************************************************************/
228 static struct file_operations ged_fops
= {
229 .owner
= THIS_MODULE
,
231 .release
= ged_release
,
235 .unlocked_ioctl
= ged_ioctl
,
237 .compat_ioctl
= ged_ioctl_compat
,
242 static struct miscdevice ged_dev
= {
243 .minor
= MISC_DYNAMIC_MINOR
,
249 static void ged_exit(void)
252 ged_log_buf_free(ghLogBuf_GED
);
255 ged_log_buf_free(ghLogBuf_GLES
);
259 ged_profile_dvfs_exit();
261 ged_log_system_exit();
265 remove_proc_entry(GED_DRIVER_DEVICE_NAME
, NULL
);
269 vfree(gvIOCTLParamBuf
);
270 gvIOCTLParamBuf
= NULL
;
274 static int ged_init(void)
276 GED_ERROR err
= GED_ERROR_FAIL
;
278 gvIOCTLParamBuf
= vmalloc(GED_IOCTL_PARAM_BUF_SIZE
);
279 if (NULL
== gvIOCTLParamBuf
)
285 if (NULL
== proc_create(GED_DRIVER_DEVICE_NAME
, 0644, NULL
, &ged_fops
))
287 err
= GED_ERROR_FAIL
;
288 GED_LOGE("ged: failed to register ged proc entry!\n");
292 err
= ged_debugFS_init();
293 if (unlikely(err
!= GED_OK
))
295 GED_LOGE("ged: failed to init debug FS!\n");
299 err
= ged_log_system_init();
300 if (unlikely(err
!= GED_OK
))
302 GED_LOGE("ged: failed to create gedlog entry!\n");
306 err
= ged_profile_dvfs_init();
307 if (unlikely(err
!= GED_OK
))
309 GED_LOGE("ged: failed to init profile dvfs!\n");
314 ghLogBuf_GLES
= ged_log_buf_alloc(160, 128, GED_LOG_BUF_TYPE_RINGBUFFER
, GED_LOG_BUF_COMMON_GLES
, NULL
);
315 ghLogBuf_GED
= ged_log_buf_alloc(32, 64, GED_LOG_BUF_TYPE_RINGBUFFER
, "GED internal", NULL
);
326 module_init(ged_init
);
327 module_exit(ged_exit
);
329 MODULE_LICENSE("GPL");
330 MODULE_DESCRIPTION("MediaTek GED Driver");
331 MODULE_AUTHOR("MediaTek Inc.");