bf563493de104422b12ec316c77154cfb8763a37
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / ged / src / ged_main.c
1 /*
2 * (C) Copyright 2010
3 * MediaTek <www.MediaTek.com>
4 *
5 * MTK GPU Extension Device
6 *
7 */
8
9 #include <linux/cdev.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/fs.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 <mach/system.h>
24 #include <linux/slab.h>
25 #include <linux/spinlock.h>
26 #include <linux/semaphore.h>
27 #include <linux/workqueue.h>
28 #include <linux/kthread.h>
29 #include <mt-plat/aee.h>
30
31 #include "ged_debugFS.h"
32 #include "ged_log.h"
33 #include "ged_hal.h"
34 #include "ged_bridge.h"
35 #include "ged_profile_dvfs.h"
36 #include "ged_monitor_3D_fence.h"
37 #include "ged_notify_sw_vsync.h"
38 #include "ged_dvfs.h"
39
40
41 #define GED_DRIVER_DEVICE_NAME "ged"
42
43 #define GED_IOCTL_PARAM_BUF_SIZE 0x3000 //12KB
44
45 #ifdef GED_DEBUG
46 #define GED_LOG_BUF_COMMON_GLES "GLES"
47 static GED_LOG_BUF_HANDLE ghLogBuf_GLES = 0;
48 GED_LOG_BUF_HANDLE ghLogBuf_GED = 0;
49 #endif
50
51 #define GED_LOG_BUF_COMMON_HWC "HWC"
52 static GED_LOG_BUF_HANDLE ghLogBuf_HWC = 0;
53 #define GED_LOG_BUF_COMMON_FENCE "FENCE"
54 static GED_LOG_BUF_HANDLE ghLogBuf_FENCE = 0;
55
56 GED_LOG_BUF_HANDLE ghLogBuf_DVFS = 0;
57 GED_LOG_BUF_HANDLE ghLogBuf_ged_srv = 0;
58
59
60
61 static void* gvIOCTLParamBuf = NULL;
62
63 /******************************************************************************
64 * GED File operations
65 *****************************************************************************/
66 static int ged_open(struct inode *inode, struct file *filp)
67 {
68 GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
69 return 0;
70 }
71
72 static int ged_release(struct inode *inode, struct file *filp)
73 {
74 GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
75 return 0;
76 }
77
78 static unsigned int ged_poll(struct file *file, struct poll_table_struct *ptable)
79 {
80 return 0;
81 }
82
83 static ssize_t ged_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
84 {
85 return 0;
86 }
87
88 static ssize_t ged_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
89 {
90 return 0;
91 }
92
93 static long ged_dispatch(GED_BRIDGE_PACKAGE *psBridgePackageKM)
94 {
95 int ret = -EFAULT;
96 void *pvInt, *pvOut;
97 typedef int (ged_bridge_func_type)(void*, void*);
98 ged_bridge_func_type* pFunc = NULL;
99
100 if ((psBridgePackageKM->i32InBufferSize >=0) && (psBridgePackageKM->i32OutBufferSize >=0) &&
101 (psBridgePackageKM->i32InBufferSize + psBridgePackageKM->i32OutBufferSize < GED_IOCTL_PARAM_BUF_SIZE))
102 {
103 pvInt = gvIOCTLParamBuf;
104 pvOut = (void*)((char*)pvInt + (uintptr_t)psBridgePackageKM->i32InBufferSize);
105 if (psBridgePackageKM->i32InBufferSize > 0)
106 {
107 if (0 != ged_copy_from_user(pvInt, psBridgePackageKM->pvParamIn, psBridgePackageKM->i32InBufferSize))
108 {
109 GED_LOGE("ged_copy_from_user fail\n");
110 return ret;
111 }
112 }
113
114 // we will change the below switch into a function pointer mapping table in the future
115 switch(GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID))
116 {
117 case GED_BRIDGE_COMMAND_LOG_BUF_GET:
118 pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_get;
119 break;
120 case GED_BRIDGE_COMMAND_LOG_BUF_WRITE:
121 pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_write;
122 break;
123 case GED_BRIDGE_COMMAND_LOG_BUF_RESET:
124 pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_reset;
125 break;
126 case GED_BRIDGE_COMMAND_BOOST_GPU_FREQ:
127 pFunc = (ged_bridge_func_type*)ged_bridge_boost_gpu_freq;
128 break;
129 case GED_BRIDGE_COMMAND_MONITOR_3D_FENCE:
130 pFunc = (ged_bridge_func_type*)ged_bridge_monitor_3D_fence;
131 break;
132 case GED_BRIDGE_COMMAND_QUERY_INFO:
133 pFunc = (ged_bridge_func_type*)ged_bridge_query_info;
134 break;
135 case GED_BRIDGE_COMMAND_NOTIFY_VSYNC:
136 pFunc = (ged_bridge_func_type*)ged_bridge_notify_vsync;
137 break;
138 case GED_BRIDGE_COMMAND_DVFS_PROBE:
139 pFunc = (ged_bridge_func_type*)ged_bridge_dvfs_probe;
140 break;
141 case GED_BRIDGE_COMMAND_DVFS_UM_RETURN:
142 pFunc = (ged_bridge_func_type*)ged_bridge_dvfs_um_retrun;
143 break;
144 default:
145 GED_LOGE("Unknown Bridge ID: %u\n", GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID));
146 break;
147 }
148
149 if (pFunc)
150 {
151 ret = pFunc(pvInt, pvOut);
152 }
153
154 if (psBridgePackageKM->i32OutBufferSize > 0)
155 {
156 if (0 != ged_copy_to_user(psBridgePackageKM->pvParamOut, pvOut, psBridgePackageKM->i32OutBufferSize))
157 {
158 return ret;
159 }
160 }
161 }
162
163 return ret;
164 }
165
166 DEFINE_SEMAPHORE(ged_dal_sem);
167
168 static long ged_ioctl(struct file *pFile, unsigned int ioctlCmd, unsigned long arg)
169 {
170 int ret = -EFAULT;
171 GED_BRIDGE_PACKAGE *psBridgePackageKM, *psBridgePackageUM = (GED_BRIDGE_PACKAGE*)arg;
172 GED_BRIDGE_PACKAGE sBridgePackageKM;
173
174 if (down_interruptible(&ged_dal_sem) < 0)
175 {
176 GED_LOGE("Fail to down ged_dal_sem\n");
177 return -ERESTARTSYS;
178 }
179
180 psBridgePackageKM = &sBridgePackageKM;
181 if (0 != ged_copy_from_user(psBridgePackageKM, psBridgePackageUM, sizeof(GED_BRIDGE_PACKAGE)))
182 {
183 GED_LOGE("Fail to ged_copy_from_user\n");
184 goto unlock_and_return;
185 }
186
187 ret = ged_dispatch(psBridgePackageKM);
188
189 unlock_and_return:
190 up(&ged_dal_sem);
191
192 return ret;
193 }
194
195 #ifdef CONFIG_COMPAT
196 static long ged_ioctl_compat(struct file *pFile, unsigned int ioctlCmd, unsigned long arg)
197 {
198 typedef struct GED_BRIDGE_PACKAGE_32_TAG
199 {
200 unsigned int ui32FunctionID;
201 int i32Size;
202 unsigned int ui32ParamIn;
203 int i32InBufferSize;
204 unsigned int ui32ParamOut;
205 int i32OutBufferSize;
206 } GED_BRIDGE_PACKAGE_32;
207
208 int ret = -EFAULT;
209 GED_BRIDGE_PACKAGE sBridgePackageKM64;
210 GED_BRIDGE_PACKAGE_32 sBridgePackageKM32;
211 GED_BRIDGE_PACKAGE_32 *psBridgePackageKM32 = &sBridgePackageKM32;
212 GED_BRIDGE_PACKAGE_32 *psBridgePackageUM32 = (GED_BRIDGE_PACKAGE_32*)arg;
213
214 if (down_interruptible(&ged_dal_sem) < 0)
215 {
216 GED_LOGE("Fail to down ged_dal_sem\n");
217 return -ERESTARTSYS;
218 }
219
220 if (0 != ged_copy_from_user(psBridgePackageKM32, psBridgePackageUM32, sizeof(GED_BRIDGE_PACKAGE_32)))
221 {
222 GED_LOGE("Fail to ged_copy_from_user\n");
223 goto unlock_and_return;
224 }
225
226 sBridgePackageKM64.ui32FunctionID = psBridgePackageKM32->ui32FunctionID;
227 sBridgePackageKM64.i32Size = sizeof(GED_BRIDGE_PACKAGE);
228 sBridgePackageKM64.pvParamIn = (void*) ((size_t) psBridgePackageKM32->ui32ParamIn);
229 sBridgePackageKM64.pvParamOut = (void*) ((size_t) psBridgePackageKM32->ui32ParamOut);
230 sBridgePackageKM64.i32InBufferSize = psBridgePackageKM32->i32InBufferSize;
231 sBridgePackageKM64.i32OutBufferSize = psBridgePackageKM32->i32OutBufferSize;
232
233 ret = ged_dispatch(&sBridgePackageKM64);
234
235 unlock_and_return:
236 up(&ged_dal_sem);
237
238 return ret;
239 }
240 #endif
241
242 /******************************************************************************
243 * Module related
244 *****************************************************************************/
245
246 static struct file_operations ged_fops = {
247 .owner = THIS_MODULE,
248 .open = ged_open,
249 .release = ged_release,
250 .poll = ged_poll,
251 .read = ged_read,
252 .write = ged_write,
253 .unlocked_ioctl = ged_ioctl,
254 #ifdef CONFIG_COMPAT
255 .compat_ioctl = ged_ioctl_compat,
256 #endif
257 };
258
259 #if 0
260 static struct miscdevice ged_dev = {
261 .minor = MISC_DYNAMIC_MINOR,
262 .name = "ged",
263 .fops = &ged_fops,
264 };
265 #endif
266
267 static void ged_exit(void)
268 {
269 #ifdef GED_DVFS_DEBUG_BUF
270 ged_log_buf_free(ghLogBuf_DVFS);
271 ged_log_buf_free(ghLogBuf_ged_srv);
272 ghLogBuf_DVFS = 0;
273 ghLogBuf_ged_srv = 0;
274 #endif
275 #ifdef GED_DEBUG
276 ged_log_buf_free(ghLogBuf_GED);
277 ghLogBuf_GED = 0;
278 ged_log_buf_free(ghLogBuf_GLES);
279 ghLogBuf_GLES = 0;
280 #endif
281 ged_log_buf_free(ghLogBuf_FENCE);
282 ghLogBuf_FENCE = 0;
283 ged_log_buf_free(ghLogBuf_HWC);
284 ghLogBuf_HWC = 0;
285
286 ged_dvfs_system_exit();
287
288 ged_profile_dvfs_exit();
289
290 //ged_notify_vsync_system_exit();
291
292 ged_notify_sw_vsync_system_exit();
293
294 ged_hal_exit();
295
296 ged_log_system_exit();
297
298 ged_debugFS_exit();
299
300 remove_proc_entry(GED_DRIVER_DEVICE_NAME, NULL);
301
302 if (gvIOCTLParamBuf)
303 {
304 vfree(gvIOCTLParamBuf);
305 gvIOCTLParamBuf = NULL;
306 }
307 }
308
309 static int ged_init(void)
310 {
311 GED_ERROR err = GED_ERROR_FAIL;
312
313 gvIOCTLParamBuf = vmalloc(GED_IOCTL_PARAM_BUF_SIZE);
314 if (NULL == gvIOCTLParamBuf)
315 {
316 err = GED_ERROR_OOM;
317 goto ERROR;
318 }
319
320 if (NULL == proc_create(GED_DRIVER_DEVICE_NAME, 0644, NULL, &ged_fops))
321 {
322 err = GED_ERROR_FAIL;
323 GED_LOGE("ged: failed to register ged proc entry!\n");
324 goto ERROR;
325 }
326
327 err = ged_debugFS_init();
328 if (unlikely(err != GED_OK))
329 {
330 GED_LOGE("ged: failed to init debug FS!\n");
331 goto ERROR;
332 }
333
334 err = ged_log_system_init();
335 if (unlikely(err != GED_OK))
336 {
337 GED_LOGE("ged: failed to create gedlog entry!\n");
338 goto ERROR;
339 }
340
341 err = ged_hal_init();
342 if (unlikely(err != GED_OK))
343 {
344 GED_LOGE("ged: failed to create hal entry!\n");
345 goto ERROR;
346 }
347
348 err = ged_notify_sw_vsync_system_init();
349 if (unlikely(err != GED_OK))
350 {
351 GED_LOGE("ged: failed to init notify sw vsync!\n");
352 goto ERROR;
353 }
354
355 err = ged_profile_dvfs_init();
356 if (unlikely(err != GED_OK))
357 {
358 GED_LOGE("ged: failed to init profile dvfs!\n");
359 goto ERROR;
360 }
361
362
363 err = ged_dvfs_system_init();
364 if (unlikely(err != GED_OK))
365 {
366 GED_LOGE("ged: failed to init common dvfs!\n");
367 goto ERROR;
368 }
369
370
371 #ifdef GED_DEBUG
372 ghLogBuf_GLES = ged_log_buf_alloc(160, 128 * 160, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_GLES, NULL);
373 ghLogBuf_GED = ged_log_buf_alloc(32, 64 * 32, GED_LOG_BUF_TYPE_RINGBUFFER, "GED internal", NULL);
374 #endif
375 ghLogBuf_HWC = ged_log_buf_alloc(4096, 128 * 4096, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_HWC, NULL);
376 ghLogBuf_FENCE = ged_log_buf_alloc(256, 128 * 256, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_FENCE, NULL);
377
378 #ifdef GED_DVFS_DEBUG_BUF
379 #ifdef GED_LOG_SIZE_LIMITED
380 ghLogBuf_DVFS = ged_log_buf_alloc(20*60, 20*60*80, GED_LOG_BUF_TYPE_RINGBUFFER, "DVFS_Log", "ged_dvfs_debug_limited");
381 #else
382 ghLogBuf_DVFS = ged_log_buf_alloc(20*60*10, 20*60*10*80, GED_LOG_BUF_TYPE_RINGBUFFER, "DVFS_Log", "ged_dvfs_debug");
383 #endif
384 ghLogBuf_ged_srv = ged_log_buf_alloc(32, 32*80, GED_LOG_BUF_TYPE_RINGBUFFER, "ged_srv_Log", "ged_srv_debug");
385 #endif
386
387 return 0;
388
389 ERROR:
390 ged_exit();
391
392 return -EFAULT;
393 }
394
395 module_init(ged_init);
396 module_exit(ged_exit);
397
398 MODULE_LICENSE("GPL");
399 MODULE_DESCRIPTION("MediaTek GED Driver");
400 MODULE_AUTHOR("MediaTek Inc.");