upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / video / samsung / s3cfb_ops.c
1 /* linux/drivers/video/samsung/s3cfb-ops.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * Middle layer file for Samsung Display Controller (FIMD) driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/poll.h>
14 #include <linux/dma-mapping.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <asm/cacheflush.h>
18 #include "s3cfb.h"
19 #include "logo.h"
20
21 #if defined(CONFIG_S5P_MEM_CMA)
22 #include <linux/cma.h>
23 #elif defined(CONFIG_S5P_MEM_BOOTMEM)
24 #include <plat/media.h>
25 #include <mach/media.h>
26 #endif
27
28 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
29 #include "ump_kernel_interface_ref_drv.h"
30 #include "ump_kernel_interface_vcm.h"
31 #define UMP_HANDLE_DD_INVALID ((void *)-1)
32 #endif
33
34 #ifdef  CONFIG_SEC_DEBUG
35 #include <mach/sec_debug.h>
36 #endif
37
38 struct s3c_platform_fb *to_fb_plat(struct device *dev)
39 {
40         struct platform_device *pdev = to_platform_device(dev);
41
42         return (struct s3c_platform_fb *)pdev->dev.platform_data;
43 }
44
45 int conv_rgb565_to_rgb888(unsigned short rgb565, unsigned int sw)
46 {
47         char red, green, blue;
48         unsigned int threshold = 150;
49
50         red = (rgb565 & 0xF800) >> 11;
51         green = (rgb565 & 0x7E0) >> 5;
52         blue = (rgb565 & 0x1F);
53
54         red = red << 3;
55         green = green << 2;
56         blue = blue << 3;
57
58         /* correct error pixels of samsung logo. */
59         if (sw) {
60                 if (red > threshold)
61                         red = 255;
62                 if (green > threshold)
63                         green = 255;
64                 if (blue > threshold)
65                         blue = 255;
66         }
67
68         return (red << 16 | green << 8 | blue);
69 }
70
71 void _draw_samsung_logo(void *lcdbase, int lcd_width, int x, int y, int w, int h, unsigned short *bmp)
72 {
73         int i, j, error_range = 40;
74         short k = 0;
75         unsigned int pixel;
76         unsigned long *fb = (unsigned  long*) lcdbase;
77
78         for (j = y; j < (y + h); j++) {
79                 for (i = x; i < (x + w); i++) {
80                         pixel = (*(bmp + k++));
81
82                         /* 40 lines under samsung logo image are error range. */
83                         if (j > h + y - error_range)
84                                 *(fb + (j * lcd_width) + i) =
85                                         conv_rgb565_to_rgb888(pixel, 1);
86                         else
87                                 *(fb + (j * lcd_width) + i) =
88                                         conv_rgb565_to_rgb888(pixel, 0);
89                 }
90         }
91 }
92
93 void _rotate_samsung_logo(void *lcdbase, int lcd_width, int x, int y, int w, int h, unsigned short *bmp)
94 {
95         int i, j, error_range = 40;
96         short k = 0;
97         unsigned int pixel;
98         unsigned long *fb = (unsigned  long*) lcdbase;
99
100         for (j = (y + h); j > y; j--) {
101                 for (i = x; i < (x + w); i++) {
102                         pixel = (*(bmp + k++));
103
104                         /* 40 lines under samsung logo image are error range. */
105                         if (j > h + y - error_range)
106                                 *(fb + (i * lcd_width) + j) =
107                                         conv_rgb565_to_rgb888(pixel, 1);
108                         else
109                                 *(fb + (i * lcd_width) + j) =
110                                         conv_rgb565_to_rgb888(pixel, 0);
111                 }
112         }
113 }
114
115 static void draw_samsung_logo(struct s3cfb_global *fbdev, struct s3c_platform_fb *pdata)
116 {
117         unsigned int x, y, win_id, width, height;
118         struct fb_info *pfb = NULL;
119
120         if (pdata->logo_on)
121                 return;
122
123         win_id = pdata->default_win;
124         pfb = fbdev->fb[win_id];
125
126         width = pfb->var.xres;
127         height = pfb->var.yres;
128
129         if (pdata->screen_type == SCREEN_PORTRAIT) {
130                 x = (width - 298) / 2;
131                 y = (height - 78) / 2 - 5;
132                 _draw_samsung_logo(pfb->screen_base, width, x, y, 298, 78,
133                         (unsigned short *) logo);
134         } else {
135                 x = (height - 298) / 2;
136                 y = (width - 78) / 2;
137                 _rotate_samsung_logo(pfb->screen_base, width, x, y, 298, 78,
138                         (unsigned short *) logo);
139         }
140 }
141
142 #ifndef CONFIG_FRAMEBUFFER_CONSOLE
143 int s3cfb_draw_logo(struct s3cfb_global *fbdev, int id)
144 {
145         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
146         struct fb_fix_screeninfo *fix = &fbdev->fb[id]->fix;
147 #ifdef CONFIG_FB_S3C_SPLASH_SCREEN
148         struct fb_var_screeninfo *var = &fbdev->fb[id]->var;
149 #if 0
150         memcpy(fbdev->fb[pdata->default_win]->screen_base,
151                LOGO_RGB24, fix->line_length * var->yres);
152 #else
153         u32 height = var->yres / 3;
154         u32 line = fix->line_length;
155         u32 i, j;
156
157         for (i = 0; i < height; i++) {
158                 for (j = 0; j < var->xres; j++) {
159                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 0, 0x00, 1);
160                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 1, 0x00, 1);
161                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 2, 0xff, 1);
162                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 3, 0x00, 1);
163                 }
164         }
165
166         for (i = height; i < height * 2; i++) {
167                 for (j = 0; j < var->xres; j++) {
168                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 0, 0x00, 1);
169                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 1, 0xff, 1);
170                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 2, 0x00, 1);
171                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 3, 0x00, 1);
172                 }
173         }
174
175         for (i = height * 2; i < height * 3; i++) {
176                 for (j = 0; j < var->xres; j++) {
177                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 0, 0xff, 1);
178                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 1, 0x00, 1);
179                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 2, 0x00, 1);
180                         memset(fbdev->fb[id]->screen_base + i * line + j * 4 + 3, 0x00, 1);
181                 }
182         }
183 #endif
184 #endif
185
186         draw_samsung_logo(fbdev, pdata);
187         dmac_map_area((void *)fbdev->fb[id]->screen_base, fix->smem_len, DMA_TO_DEVICE);
188         outer_clean_range(fix->smem_start, fix->smem_start + fix->smem_len);
189
190         return 0;
191 }
192 #else
193 int fb_is_primary_device(struct fb_info *fb)
194 {
195         struct s3cfb_window *win = fb->par;
196         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
197         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
198
199         dev_dbg(fbdev->dev, "[fb%d] checking for primary device\n", win->id);
200
201         if (win->id == pdata->default_win)
202                 return 1;
203         else
204                 return 0;
205 }
206 #endif
207
208 int s3cfb_enable_window(struct s3cfb_global *fbdev, int id)
209 {
210         struct s3cfb_window *win = fbdev->fb[id]->par;
211
212         if (!win->enabled)
213                 atomic_inc(&fbdev->enabled_win);
214
215         if (s3cfb_window_on(fbdev, id)) {
216                 win->enabled = 0;
217                 return -EFAULT;
218         } else {
219                 win->enabled = 1;
220                 return 0;
221         }
222 }
223
224 int s3cfb_disable_window(struct s3cfb_global *fbdev, int id)
225 {
226         struct s3cfb_window *win = fbdev->fb[id]->par;
227
228         if (win->enabled)
229                 atomic_dec(&fbdev->enabled_win);
230
231         if (s3cfb_window_off(fbdev, id)) {
232                 win->enabled = 1;
233                 return -EFAULT;
234         } else {
235                 win->enabled = 0;
236                 return 0;
237         }
238 }
239
240 int s3cfb_update_power_state(struct s3cfb_global *fbdev, int id, int state)
241 {
242         struct s3cfb_window *win = fbdev->fb[id]->par;
243         win->power_state = state;
244
245         return 0;
246 }
247
248 int s3cfb_init_global(struct s3cfb_global *fbdev)
249 {
250         fbdev->output = OUTPUT_RGB;
251         fbdev->rgb_mode = MODE_RGB_P;
252
253         fbdev->wq_count = 0;
254         init_waitqueue_head(&fbdev->wq);
255         mutex_init(&fbdev->lock);
256
257         s3cfb_set_output(fbdev);
258         s3cfb_set_display_mode(fbdev);
259         s3cfb_set_polarity(fbdev);
260         s3cfb_set_timing(fbdev);
261         s3cfb_set_lcd_size(fbdev);
262
263         return 0;
264 }
265
266 #ifdef CONFIG_VCM
267 static const struct s5p_vcm_driver s3cfb_vcm_driver = {
268         .tlb_invalidator = NULL,
269         .pgd_base_specifier = NULL,
270         .phys_alloc = NULL,
271         .phys_free = NULL,
272 };
273 #endif
274 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
275 int s3cfb_ump_wrapper(struct fb_fix_screeninfo *fix, int arg, int id,
276                         struct s3cfb_window *win)
277 {
278         ump_dd_physical_block ump_memory_description;
279         unsigned int buffer_size;
280         buffer_size = fix->smem_len / CONFIG_FB_S3C_NR_BUFFERS;
281
282         /*  add 4kbyte to buffer_size because of fimg2d hardware bug. */
283         ump_memory_description.size = ALIGN(buffer_size, SZ_4K);
284         ump_memory_description.addr = fix->smem_start + (ump_memory_description.size * id);
285
286         win->ump_wrapped_buffer[id] =
287                 ump_dd_handle_create_from_phys_blocks
288                 (&ump_memory_description, 1);
289
290         if (ump_dd_meminfo_set(win->ump_wrapped_buffer[id], (void*)arg))
291                 return -ENOMEM;
292
293         return 0;
294 }
295 #endif
296
297 int s3cfb_map_video_memory(struct s3cfb_global *fbdev, struct fb_info *fb)
298 {
299         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
300         struct fb_fix_screeninfo *fix = &fb->fix;
301         struct s3cfb_window *win = fb->par;
302
303 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
304         unsigned int arg = 0;
305 #ifdef CONFIG_UMP_VCM_ALLOC
306         struct ump_vcm ump_vcm;
307         ump_dd_physical_block ump_memory_description;
308 #endif
309 #endif
310
311 #if defined(CONFIG_VCM) || \
312         (MALI_USE_UNIFIED_MEMORY_PROVIDER && defined(CONFIG_UMP_VCM_ALLOC))
313         int i;
314 #endif
315
316 #ifdef CONFIG_VCM
317         struct fb_var_screeninfo *var = &fb->var;
318         struct cma_info mem_info;
319         unsigned int reserved_size;
320         int err;
321         struct vcm_phys *phys = NULL;
322         unsigned int device_virt_start = 0;
323         int frame_num = var->yres_virtual / var->yres;
324         int frame_size = fix->smem_len / frame_num;
325         struct  vcm_res *fb_dev_vcm_res[frame_num];
326         enum vcm_dev_id id;
327 #else
328 #ifdef CONFIG_S5P_MEM_CMA
329         struct cma_info mem_info;
330         unsigned int reserved_size;
331         int err;
332 #endif
333 #endif
334
335         if (win->owner == DMA_MEM_OTHER)
336                 return 0;
337
338 #ifdef CONFIG_VCM
339         phys = kmalloc(sizeof(*phys) + sizeof(*phys->parts), GFP_KERNEL);
340         memset(phys, 0, sizeof(*phys) + sizeof(*phys->parts));
341
342         if (win->id < 5)
343                 id = VCM_DEV_FIMD0;
344         else
345                 id = VCM_DEV_FIMD1;
346
347         err = cma_info(&mem_info, fbdev->dev, 0);
348         if (ERR_PTR(err))
349                 return -ENOMEM;
350         reserved_size = ALIGN(fix->smem_len, SZ_4K);
351         fix->smem_start = (dma_addr_t)cma_alloc
352                 (fbdev->dev, "fimd", (size_t)reserved_size, 0);
353         fb->screen_base = cma_get_virt(fix->smem_start, reserved_size, 1);
354
355         phys->count = 1;
356         phys->size = reserved_size;
357         phys->free = NULL;
358         phys->parts[0].size = reserved_size;
359         phys->parts[0].start = fix->smem_start;
360
361         win->s5p_vcm_res = vcm_map(fbdev->s5p_vcm, phys, 0);
362
363         if (IS_ERR(win->s5p_vcm_res)) {
364                 return PTR_ERR(win->s5p_vcm_res);
365         }
366
367         device_virt_start = win->s5p_vcm_res->start;
368
369         for (i = 0; i < frame_num; i++) {
370                 fb_dev_vcm_res[i] = kzalloc(sizeof(struct vcm_res), GFP_KERNEL);
371                 win->s3cfb_vcm[i].dev_vcm_res = fb_dev_vcm_res[i];
372
373                 win->s3cfb_vcm[i].dev_vcm_res->start = device_virt_start
374                                                         + frame_size * i;
375                 win->s3cfb_vcm[i].dev_vcm_res->bound_size = frame_size;
376                 win->s3cfb_vcm[i].dev_vcm_res->res_size = frame_size;
377                 win->s3cfb_vcm[i].dev_vcm = fbdev->s5p_vcm;
378                 win->s3cfb_vcm[i].dev_vcm_res->vcm = fbdev->s5p_vcm;
379                 if (IS_ERR(win->s3cfb_vcm[i].dev_vcm_res))
380                         return -ENOMEM;
381         }
382
383 #else
384 #ifdef CONFIG_S5P_MEM_CMA
385         err = cma_info(&mem_info, fbdev->dev, 0);
386         if (ERR_PTR(err))
387                 return -ENOMEM;
388         reserved_size = mem_info.total_size;
389         fix->smem_start = (dma_addr_t)cma_alloc
390                 (fbdev->dev, "fimd", (size_t)reserved_size, 0);
391         fb->screen_base = cma_get_virt(fix->smem_start, reserved_size, 1);
392 #endif
393 #endif
394
395         memset(fb->screen_base, 0, (fix->smem_len / frame_num));
396         win->owner = DMA_MEM_FIMD;
397
398 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
399 #ifdef CONFIG_UMP_VCM_ALLOC
400         for (i = 0; i < frame_num; i++) {
401                 ump_vcm.vcm = win->s3cfb_vcm[i].dev_vcm;
402                 ump_vcm.vcm_res = win->s3cfb_vcm[i].dev_vcm_res;
403                 ump_vcm.dev_id = id;
404                 arg = (unsigned int)&ump_vcm;
405
406                 ump_memory_description.size = ALIGN(fix->smem_len / frame_num, SZ_4K);
407                 ump_memory_description.addr = fix->smem_start +
408                                         (ump_memory_description.size * i);
409
410                 win->ump_wrapped_buffer[i] =
411                         ump_dd_handle_create_from_phys_blocks
412                         (&ump_memory_description, 1);
413
414                 if (ump_dd_meminfo_set(win->ump_wrapped_buffer[i], (void*)arg))
415                         return -ENOMEM;
416
417         }
418 #else
419         if (s3cfb_ump_wrapper(fix, arg, 0, win)) {
420                 dev_info(fbdev->dev, "[fb%d] : Wrapped UMP memory : %x\n"
421                                 , win->id, (unsigned int)(win->ump_wrapped_buffer));
422                 s3cfb_unmap_video_memory(fbdev, fb);
423                 return -ENOMEM;
424         }
425 #endif
426 #endif
427         return 0;
428 }
429
430 int s3cfb_map_default_video_memory(struct s3cfb_global *fbdev,
431                                         struct fb_info *fb, int fimd_id)
432 {
433         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
434         struct fb_fix_screeninfo *fix = &fb->fix;
435         struct s3cfb_window *win = fb->par;
436
437 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
438         unsigned int arg = 0;
439 #ifdef CONFIG_UMP_VCM_ALLOC
440         struct ump_vcm ump_vcm;
441         ump_dd_physical_block ump_memory_description;
442 #endif
443 #endif
444
445 #if defined(CONFIG_VCM) || \
446         (MALI_USE_UNIFIED_MEMORY_PROVIDER && defined(CONFIG_UMP_VCM_ALLOC))
447         int i;
448 #endif
449
450 #ifdef CONFIG_VCM
451         struct cma_info mem_info;
452         unsigned int reserved_size;
453         int err;
454         struct vcm_phys *phys = NULL;
455         unsigned int device_virt_start = 0;
456         int frame_size = fix->smem_len / CONFIG_FB_S3C_NR_BUFFERS;
457         struct  vcm_res *fb_dev_vcm_res[CONFIG_FB_S3C_NR_BUFFERS];
458
459         enum vcm_dev_id id;
460 #else
461 #ifdef CONFIG_S5P_MEM_CMA
462         struct cma_info mem_info;
463         unsigned int reserved_size;
464         int err;
465 #endif
466 #endif
467
468         if (win->owner == DMA_MEM_OTHER)
469                 return 0;
470
471 #ifdef CONFIG_VCM
472         phys = kmalloc(sizeof(*phys) + sizeof(*phys->parts), GFP_KERNEL);
473         memset(phys, 0, sizeof(*phys) + sizeof(*phys->parts));
474
475         if (fimd_id == 0)
476                 id = VCM_DEV_FIMD0;
477         else
478                 id = VCM_DEV_FIMD1;
479
480         err = cma_info(&mem_info, fbdev->dev, 0);
481         if (ERR_PTR(err))
482                 return -ENOMEM;
483         reserved_size = ALIGN(fix->smem_len, SZ_4K);    
484         fix->smem_start = (dma_addr_t)cma_alloc
485                 (fbdev->dev, "fimd", (size_t)reserved_size, 0);
486         fb->screen_base = cma_get_virt(fix->smem_start, reserved_size, 1);
487
488         fbdev->s5p_vcm = vcm_create_unified((SZ_64M), id, &s3cfb_vcm_driver);
489         if (IS_ERR(fbdev->s5p_vcm))
490                 return PTR_ERR(fbdev->s5p_vcm);
491         if (vcm_activate(fbdev->s5p_vcm))
492                 dev_info(fbdev->dev, "[fb%d] : VCM activated", win->id);
493
494         phys->count = 1;
495         phys->size = reserved_size;
496         phys->free = NULL;
497         phys->parts[0].size = reserved_size;
498         phys->parts[0].start = fix->smem_start;
499
500         win->s5p_vcm_res = vcm_map(fbdev->s5p_vcm, phys, 0);
501         device_virt_start = win->s5p_vcm_res->start;
502
503         for (i = 0; i < CONFIG_FB_S3C_NR_BUFFERS; i++) {
504                 fb_dev_vcm_res[i] = kzalloc(sizeof(struct vcm_res), GFP_KERNEL);
505                 win->s3cfb_vcm[i].dev_vcm_res = fb_dev_vcm_res[i];
506
507                 win->s3cfb_vcm[i].dev_vcm_res->start = device_virt_start
508                                                         + frame_size * i;
509                 win->s3cfb_vcm[i].dev_vcm_res->bound_size = frame_size;
510                 win->s3cfb_vcm[i].dev_vcm_res->res_size = frame_size;
511                 win->s3cfb_vcm[i].dev_vcm = fbdev->s5p_vcm;
512                 win->s3cfb_vcm[i].dev_vcm_res->vcm = fbdev->s5p_vcm;
513                 if (IS_ERR(win->s3cfb_vcm[i].dev_vcm_res))
514                         return -ENOMEM;
515         }
516 #else
517 #ifdef CONFIG_S5P_MEM_CMA
518         err = cma_info(&mem_info, fbdev->dev, 0);
519         if (ERR_PTR(err))
520                 return -ENOMEM;
521         reserved_size = mem_info.total_size;
522         fix->smem_start = (dma_addr_t)cma_alloc
523                 (fbdev->dev, "fimd", (size_t)reserved_size, 0);
524         fb->screen_base = cma_get_virt(fix->smem_start, reserved_size, 1);
525 #elif defined(CONFIG_S5P_MEM_BOOTMEM)
526         fix->smem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMD, 0);
527         fix->smem_len = s5p_get_media_memsize_bank(S5P_MDEV_FIMD, 0);
528         fb->screen_base = phys_to_virt(fix->smem_start);
529 #endif
530 #endif
531
532         if (!pdata->logo_on)
533                 memset(fb->screen_base, 0, (fix->smem_len / CONFIG_FB_S3C_NR_BUFFERS));
534         win->owner = DMA_MEM_FIMD;
535
536 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
537 #ifdef CONFIG_UMP_VCM_ALLOC
538         for (i = 0; i < CONFIG_FB_S3C_NR_BUFFERS; i++) {
539                 ump_vcm.vcm = win->s3cfb_vcm[i].dev_vcm;
540                 ump_vcm.vcm_res = win->s3cfb_vcm[i].dev_vcm_res;
541                 ump_vcm.dev_id = id;
542                 arg = (unsigned int)&ump_vcm;
543                 ump_memory_description.size = ALIGN(fix->smem_len / CONFIG_FB_S3C_NR_BUFFERS, SZ_4K);
544                 ump_memory_description.addr = fix->smem_start + (ump_memory_description.size * i);
545
546                 win->ump_wrapped_buffer[i] =
547                         ump_dd_handle_create_from_phys_blocks
548                         (&ump_memory_description, 1);
549
550                 if (ump_dd_meminfo_set(win->ump_wrapped_buffer[i], (void*)arg))
551                         return -ENOMEM;
552         }
553 #else
554         if (s3cfb_ump_wrapper(fix, arg, 0, win)) {
555                 dev_info(fbdev->dev, "[fb%d] : Wrapped UMP memory : %x\n"
556                                 , win->id, (unsigned int)(win->ump_wrapped_buffer));
557                 s3cfb_unmap_video_memory(fbdev, fb);
558                 return -ENOMEM;
559         }
560 #endif
561 #endif
562
563         return 0;
564 }
565
566 int s3cfb_unmap_video_memory(struct s3cfb_global *fbdev, struct fb_info *fb)
567 {
568         struct fb_fix_screeninfo *fix = &fb->fix;
569         struct s3cfb_window *win = fb->par;
570 #ifdef CONFIG_VCM
571         struct fb_var_screeninfo *var = &fb->var;
572         int frame_num = var->yres_virtual / var->yres;
573         int i;
574 #endif
575
576         if (fix->smem_start) {
577 #ifdef CONFIG_VCM
578                 vcm_unmap(win->s5p_vcm_res);
579                 cma_free(fix->smem_start);
580                 for (i = 0; i < frame_num; i++)
581                         kfree(win->s3cfb_vcm[i].dev_vcm_res);
582 #else
583                 dma_free_writecombine(fbdev->dev, fix->smem_len,
584                                         fb->screen_base, fix->smem_start);
585 #endif
586                 fix->smem_start = 0;
587                 fix->smem_len = 0;
588                 dev_info(fbdev->dev, "[fb%d] video memory released\n", win->id);
589         }
590         return 0;
591 }
592
593 int s3cfb_unmap_default_video_memory(struct s3cfb_global *fbdev,
594                                         struct fb_info *fb)
595 {
596         struct fb_fix_screeninfo *fix = &fb->fix;
597         struct s3cfb_window *win = fb->par;
598 #ifdef CONFIG_VCM
599         int i;
600 #endif
601
602         if (fix->smem_start) {
603
604 #ifdef CONFIG_VCM
605                 vcm_unmap(win->s5p_vcm_res);
606                 cma_free(fix->smem_start);
607                 for (i = 0; i < CONFIG_FB_S3C_NR_BUFFERS; i++)
608                         kfree(win->s3cfb_vcm[i].dev_vcm_res);
609 #endif
610                 fix->smem_start = 0;
611                 fix->smem_len = 0;
612                 dev_info(fbdev->dev, "[fb%d] video memory released\n", win->id);
613         }
614
615         return 0;
616 }
617
618 int s3cfb_set_bitfield(struct fb_var_screeninfo *var)
619 {
620         switch (var->bits_per_pixel) {
621         case 16:
622                 if (var->transp.length == 1) {
623                         var->red.offset = 10;
624                         var->red.length = 5;
625                         var->green.offset = 5;
626                         var->green.length = 5;
627                         var->blue.offset = 0;
628                         var->blue.length = 5;
629                         var->transp.offset = 15;
630                 } else if (var->transp.length == 4) {
631                         var->red.offset = 8;
632                         var->red.length = 4;
633                         var->green.offset = 4;
634                         var->green.length = 4;
635                         var->blue.offset = 0;
636                         var->blue.length = 4;
637                         var->transp.offset = 12;
638                 } else {
639                         var->red.offset = 11;
640                         var->red.length = 5;
641                         var->green.offset = 5;
642                         var->green.length = 6;
643                         var->blue.offset = 0;
644                         var->blue.length = 5;
645                         var->transp.offset = 0;
646                 }
647                 break;
648
649         case 24:
650                 var->red.offset = 16;
651                 var->red.length = 8;
652                 var->green.offset = 8;
653                 var->green.length = 8;
654                 var->blue.offset = 0;
655                 var->blue.length = 8;
656                 var->transp.offset = 0;
657                 var->transp.length = 0;
658                 break;
659
660         case 32:
661                 var->red.offset = 16;
662                 var->red.length = 8;
663                 var->green.offset = 8;
664                 var->green.length = 8;
665                 var->blue.offset = 0;
666                 var->blue.length = 8;
667                 var->transp.offset = 24;
668                 break;
669         }
670
671         return 0;
672 }
673
674 int s3cfb_set_alpha_info(struct fb_var_screeninfo *var,
675                                 struct s3cfb_window *win)
676 {
677         if (var->transp.length > 0)
678                 win->alpha.mode = PIXEL_BLENDING;
679         else {
680                 win->alpha.mode = PLANE_BLENDING;
681                 win->alpha.channel = 0;
682                 win->alpha.value = S3CFB_AVALUE(0xf, 0xf, 0xf);
683         }
684
685         return 0;
686 }
687
688 int s3cfb_check_var_window(struct s3cfb_global *fbdev,
689                         struct fb_var_screeninfo *var, struct fb_info *fb)
690 {
691         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
692         struct s3cfb_window *win = fb->par;
693         struct s3cfb_lcd *lcd = fbdev->lcd;
694
695         dev_dbg(fbdev->dev, "[fb%d] check_var\n", win->id);
696
697         if (var->bits_per_pixel != 16 && var->bits_per_pixel != 24 &&
698             var->bits_per_pixel != 32) {
699                 dev_err(fbdev->dev, "invalid bits per pixel\n");
700                 return -EINVAL;
701         }
702
703         if (var->xres > lcd->width)
704                 var->xres = lcd->width;
705
706         if (var->yres > lcd->height)
707                 var->yres = lcd->height;
708
709         if (var->xres_virtual < var->xres)
710                 var->xres_virtual = var->xres;
711
712 #if defined(CONFIG_FB_S3C_VIRTUAL)
713         if (var->yres_virtual < var->yres)
714                 var->yres_virtual = var->yres * CONFIG_FB_S3C_NR_BUFFERS;
715 #endif
716
717         if (var->xoffset > (var->xres_virtual - var->xres))
718                 var->xoffset = var->xres_virtual - var->xres;
719
720         if (var->yoffset + var->yres > var->yres_virtual)
721                 var->yoffset = var->yres_virtual - var->yres;
722
723         if (win->x + var->xres > lcd->width)
724                 win->x = lcd->width - var->xres;
725
726         if (win->y + var->yres > lcd->height)
727                 win->y = lcd->height - var->yres;
728
729         if (var->pixclock != fbdev->fb[pdata->default_win]->var.pixclock) {
730                 dev_info(fbdev->dev, "pixclk is changed from %d Hz to %d Hz\n",
731                         fbdev->fb[pdata->default_win]->var.pixclock,
732                         var->pixclock);
733         }
734
735         s3cfb_set_bitfield(var);
736         s3cfb_set_alpha_info(var, win);
737
738         return 0;
739 }
740
741 int s3cfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
742 {
743         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
744
745         s3cfb_check_var_window(fbdev, var, fb);
746
747         return 0;
748 }
749
750 void s3cfb_set_win_params(struct s3cfb_global *fbdev, int id)
751 {
752         s3cfb_set_window_control(fbdev, id);
753         s3cfb_set_window_position(fbdev, id);
754         s3cfb_set_window_size(fbdev, id);
755         s3cfb_set_buffer_address(fbdev, id);
756         s3cfb_set_buffer_size(fbdev, id);
757
758         if (id > 0) {
759                 s3cfb_set_alpha_blending(fbdev, id);
760                 s3cfb_set_chroma_key(fbdev, id);
761                 s3cfb_set_alpha_value_width(fbdev, id);
762         }
763 }
764
765 int s3cfb_set_par_window(struct s3cfb_global *fbdev, struct fb_info *fb)
766 {
767         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
768         struct s3cfb_window *win = fb->par;
769
770         dev_dbg(fbdev->dev, "[fb%d] set_par\n", win->id);
771
772         /* modify the fix info */
773         if (win->id != pdata->default_win) {
774                 fb->fix.line_length = fb->var.xres_virtual *
775                                                 fb->var.bits_per_pixel / 8;
776                 fb->fix.smem_len = fb->fix.line_length * fb->var.yres_virtual;
777         }
778
779         if (win->id != pdata->default_win && fb->fix.smem_start == 0)
780                 s3cfb_map_video_memory(fbdev, fb);
781
782         s3cfb_set_win_params(fbdev, win->id);
783
784         return 0;
785 }
786
787 int s3cfb_set_par(struct fb_info *fb)
788 {
789         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
790
791         s3cfb_set_par_window(fbdev, fb);
792
793         return 0;
794 }
795
796 int s3cfb_init_fbinfo(struct s3cfb_global *fbdev, int id)
797 {
798         struct fb_info *fb = fbdev->fb[id];
799         struct fb_fix_screeninfo *fix = &fb->fix;
800         struct fb_var_screeninfo *var = &fb->var;
801         struct s3cfb_window *win = fb->par;
802         struct s3cfb_alpha *alpha = &win->alpha;
803         struct s3cfb_lcd *lcd = fbdev->lcd;
804         struct s3cfb_lcd_timing *timing = &lcd->timing;
805
806         memset(win, 0, sizeof(struct s3cfb_window));
807         platform_set_drvdata(to_platform_device(fbdev->dev), fb);
808         strncpy(fix->id, S3CFB_NAME, sizeof(fix->id));
809
810         /* fimd specific */
811         win->id = id;
812         win->path = DATA_PATH_DMA;
813         win->dma_burst = 16;
814         s3cfb_update_power_state(fbdev, win->id, FB_BLANK_POWERDOWN);
815         alpha->mode = PLANE_BLENDING;
816
817         /* fbinfo */
818         fb->fbops = &s3cfb_ops;
819         fb->flags = FBINFO_FLAG_DEFAULT;
820         fb->pseudo_palette = &win->pseudo_pal;
821
822         fix->xpanstep = 2;
823         fix->ypanstep = 1;
824
825         fix->type = FB_TYPE_PACKED_PIXELS;
826         fix->accel = FB_ACCEL_NONE;
827         fix->visual = FB_VISUAL_TRUECOLOR;
828         var->xres = lcd->width;
829         var->yres = lcd->height;
830
831 #if defined(CONFIG_FB_S3C_VIRTUAL)
832         var->xres_virtual = CONFIG_FB_S3C_X_VRES;
833         var->yres_virtual = CONFIG_FB_S3C_Y_VRES * CONFIG_FB_S3C_NR_BUFFERS;
834 #else
835         var->xres_virtual = var->xres;
836         var->yres_virtual = var->yres * CONFIG_FB_S3C_NR_BUFFERS;
837 #endif
838         var->bits_per_pixel = 32;
839         var->xoffset = 0;
840         var->yoffset = 0;
841         var->width = lcd->width_mm;
842         var->height = lcd->height_mm;
843         var->transp.length = 0;
844
845         fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
846         fix->smem_len = fix->line_length * var->yres_virtual;
847
848         var->nonstd = 0;
849         var->activate = FB_ACTIVATE_NOW;
850         var->vmode = FB_VMODE_NONINTERLACED;
851         var->hsync_len = timing->h_sw;
852         var->vsync_len = timing->v_sw;
853         var->left_margin = timing->h_bp;
854         var->right_margin = timing->h_fp;
855         var->upper_margin = timing->v_bp;
856         var->lower_margin = timing->v_fp;
857         var->pixclock = (lcd->freq *
858                 (var->left_margin + var->right_margin
859                 + var->hsync_len + var->xres) *
860                 (var->upper_margin + var->lower_margin
861                 + var->vsync_len + var->yres));
862         var->pixclock = KHZ2PICOS(var->pixclock/1000);
863
864         s3cfb_set_bitfield(var);
865         s3cfb_set_alpha_info(var, win);
866
867         return 0;
868 }
869
870 int s3cfb_alloc_framebuffer(struct s3cfb_global *fbdev, int fimd_id)
871 {
872         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
873         int ret = 0;
874         int i;
875
876         fbdev->fb = kmalloc(pdata->nr_wins *
877                                 sizeof(struct fb_info *), GFP_KERNEL);
878         if (!fbdev->fb) {
879                 dev_err(fbdev->dev, "not enough memory\n");
880                 ret = -ENOMEM;
881                 goto err_alloc;
882         }
883
884         for (i = 0; i < pdata->nr_wins; i++) {
885                 fbdev->fb[i] = framebuffer_alloc(sizeof(struct s3cfb_window),
886                                                 fbdev->dev);
887                 if (!fbdev->fb[i]) {
888                         dev_err(fbdev->dev, "not enough memory\n");
889                         ret = -ENOMEM;
890                         goto err_alloc_fb;
891                 }
892
893                 ret = s3cfb_init_fbinfo(fbdev, i);
894                 if (ret) {
895                         dev_err(fbdev->dev,
896                                 "failed to allocate memory for fb%d\n", i);
897                         ret = -ENOMEM;
898                         goto err_alloc_fb;
899                 }
900
901                 if (i == pdata->default_win)
902                         if (s3cfb_map_default_video_memory(fbdev,
903                                                 fbdev->fb[i], fimd_id)) {
904                                 dev_err(fbdev->dev,
905                                 "failed to map video memory "
906                                 "for default window (%d)\n", i);
907                         ret = -ENOMEM;
908                         goto err_alloc_fb;
909                 }
910 #ifdef CONFIG_SEC_DEBUG
911                 sec_getlog_supply_fbinfo((i - pdata->default_win),
912                 (void *)fbdev->fb[i]->fix.smem_start,
913                 fbdev->fb[i]->var.xres,
914                 fbdev->fb[i]->var.yres,
915                 fbdev->fb[i]->var.bits_per_pixel);
916 #endif
917         }
918
919         return 0;
920
921 err_alloc_fb:
922         for (i = 0; i < pdata->nr_wins; i++) {
923                 if (fbdev->fb[i])
924                         framebuffer_release(fbdev->fb[i]);
925         }
926         kfree(fbdev->fb);
927
928 err_alloc:
929         return ret;
930 }
931
932 int s3cfb_open(struct fb_info *fb, int user)
933 {
934         struct s3cfb_window *win = fb->par;
935         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
936         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
937         int ret = 0;
938
939         mutex_lock(&fbdev->lock);
940
941         if (atomic_read(&win->in_use)) {
942                 if (win->id == pdata->default_win) {
943                         dev_dbg(fbdev->dev,
944                                 "mutiple open for default window\n");
945                         ret = 0;
946                 } else {
947                         dev_dbg(fbdev->dev,
948                                 "do not allow multiple open     \
949                                 for non-default window\n");
950                         ret = -EBUSY;
951                 }
952         } else {
953                 atomic_inc(&win->in_use);
954         }
955
956         mutex_unlock(&fbdev->lock);
957
958         return ret;
959 }
960
961 int s3cfb_release_window(struct fb_info *fb)
962 {
963         struct s3cfb_window *win = fb->par;
964         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
965         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
966
967         if (win->id != pdata->default_win) {
968                 s3cfb_disable_window(fbdev, win->id);
969
970 #if 0
971                 /* FIXME!!! */
972                 s3cfb_unmap_video_memory(fbdev, fb);
973 #endif
974         }
975
976         win->x = 0;
977         win->y = 0;
978
979         return 0;
980 }
981
982 int s3cfb_release(struct fb_info *fb, int user)
983 {
984         struct s3cfb_window *win = fb->par;
985         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
986
987         s3cfb_release_window(fb);
988
989         mutex_lock(&fbdev->lock);
990         atomic_dec(&win->in_use);
991         mutex_unlock(&fbdev->lock);
992
993         return 0;
994 }
995
996 inline unsigned int __chan_to_field(unsigned int chan, struct fb_bitfield bf)
997 {
998         chan &= 0xffff;
999         chan >>= 16 - bf.length;
1000
1001         return chan << bf.offset;
1002 }
1003
1004 int s3cfb_setcolreg(unsigned int regno, unsigned int red,
1005                         unsigned int green, unsigned int blue,
1006                         unsigned int transp, struct fb_info *fb)
1007 {
1008         unsigned int *pal = (unsigned int *)fb->pseudo_palette;
1009         unsigned int val = 0;
1010
1011         if (regno < 16) {
1012                 /* fake palette of 16 colors */
1013                 val |= __chan_to_field(red, fb->var.red);
1014                 val |= __chan_to_field(green, fb->var.green);
1015                 val |= __chan_to_field(blue, fb->var.blue);
1016                 val |= __chan_to_field(transp, fb->var.transp);
1017                 pal[regno] = val;
1018         }
1019
1020         return 0;
1021 }
1022
1023 int s3cfb_blank(int blank_mode, struct fb_info *fb)
1024 {
1025         struct s3cfb_window *win = fb->par;
1026         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
1027         struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
1028         int enabled_win = 0;
1029
1030         dev_dbg(fbdev->dev, "change blank mode\n");
1031
1032         switch (blank_mode) {
1033         case FB_BLANK_UNBLANK:
1034                 if (!fb->fix.smem_start) {
1035                         dev_info(fbdev->dev, "[fb%d] no allocated memory \
1036                                 for unblank\n", win->id);
1037                         return -EINVAL;
1038                 }
1039
1040                 if (win->power_state == FB_BLANK_UNBLANK) {
1041                         dev_info(fbdev->dev, "[fb%d] already in \
1042                                 FB_BLANK_UNBLANK\n", win->id);
1043                         return -EINVAL;
1044                 } else {
1045                         s3cfb_update_power_state(fbdev, win->id,
1046                                                 FB_BLANK_UNBLANK);
1047                 }
1048
1049                 enabled_win = atomic_read(&fbdev->enabled_win);
1050
1051                 if(!atomic_read(&fbdev->enabled))
1052                         pm_runtime_get_sync(fbdev->dev);
1053
1054                 if (win->enabled)       /* from FB_BLANK_NORMAL */
1055                         s3cfb_win_map_off(fbdev, win->id);
1056                 else {          /* from FB_BLANK_POWERDOWN */
1057                         s3cfb_enable_window(fbdev, win->id);
1058                         /**
1059                          * if some layer was released with FB_BLANK_NORMAL
1060                          * then window map should be off because this layer
1061                          * would be disabled(win->enabled = 0) when released.
1062                          */
1063                         s3cfb_win_map_off(fbdev, win->id);
1064                 }
1065
1066                 if (enabled_win == 0)
1067                         s3cfb_display_on(fbdev);
1068
1069                 break;
1070
1071         case FB_BLANK_NORMAL:
1072                 if (win->power_state == FB_BLANK_NORMAL) {
1073                         dev_info(fbdev->dev, "[fb%d] already in \
1074                                 FB_BLANK_NORMAL\n", win->id);
1075                         return -EINVAL;
1076                 } else {
1077                         s3cfb_update_power_state(fbdev, win->id,
1078                                                 FB_BLANK_NORMAL);
1079                 }
1080
1081                 enabled_win = atomic_read(&fbdev->enabled_win);
1082                 if(enabled_win == 0 || !atomic_read(&fbdev->enabled))
1083                         pm_runtime_get_sync(fbdev->dev);
1084
1085                 s3cfb_win_map_on(fbdev, win->id, 0x0);
1086
1087                 if (!win->enabled)      /* from FB_BLANK_POWERDOWN */
1088                         s3cfb_enable_window(fbdev, win->id);
1089
1090                 if (enabled_win == 0)
1091                         s3cfb_display_on(fbdev);
1092
1093                 break;
1094
1095         case FB_BLANK_POWERDOWN:
1096                 if (win->power_state == FB_BLANK_POWERDOWN) {
1097                         dev_info(fbdev->dev, "[fb%d] already in \
1098                                 FB_BLANK_POWERDOWN\n", win->id);
1099                         return -EINVAL;
1100                 } else {
1101                         s3cfb_update_power_state(fbdev, win->id,
1102                                                 FB_BLANK_POWERDOWN);
1103                 }
1104
1105                 s3cfb_disable_window(fbdev, win->id);
1106                 s3cfb_win_map_off(fbdev, win->id);
1107
1108                 if(atomic_read(&fbdev->enabled) > 0)
1109                         pm_runtime_put(fbdev->dev);
1110                 else
1111                         return -EINVAL;
1112
1113                 break;
1114
1115         case FB_BLANK_VSYNC_SUSPEND:    /* fall through */
1116         case FB_BLANK_HSYNC_SUSPEND:    /* fall through */
1117         default:
1118                 dev_dbg(fbdev->dev, "unsupported blank mode\n");
1119                 return -EINVAL;
1120         }
1121
1122         return 0;
1123 }
1124
1125 int s3cfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
1126 {
1127         struct s3cfb_window *win = fb->par;
1128         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
1129
1130          /**
1131           * if there is no any enabled window  or fimd hardware is off
1132           * then return -EINVAL to avoid access to fimd from pan request
1133           * by user.
1134           */
1135         if (atomic_read(&fbdev->enabled_win) <= 0 ||
1136                         !atomic_read(&fbdev->enabled))
1137                 return -EINVAL;
1138
1139         if (var->yoffset + var->yres > var->yres_virtual) {
1140                 dev_err(fbdev->dev, "invalid yoffset value\n");
1141                 return -EINVAL;
1142         }
1143
1144         fb->var.yoffset = var->yoffset;
1145
1146         dev_dbg(fbdev->dev, "[fb%d] yoffset for pan display: %d\n", win->id,
1147                 var->yoffset);
1148
1149         s3cfb_set_buffer_address(fbdev, win->id);
1150
1151         return 0;
1152 }
1153
1154 int s3cfb_cursor(struct fb_info *fb, struct fb_cursor *cursor)
1155 {
1156         /* nothing to do for removing cursor */
1157         return 0;
1158 }
1159
1160 int s3cfb_wait_for_vsync(struct s3cfb_global *fbdev)
1161 {
1162         dev_dbg(fbdev->dev, "waiting for VSYNC interrupt\n");
1163
1164         s3cfb_set_global_interrupt(fbdev, 1);
1165         s3cfb_set_vsync_interrupt(fbdev, 1);
1166
1167         sleep_on_timeout(&fbdev->wq, HZ / 10);
1168
1169         dev_dbg(fbdev->dev, "got a VSYNC interrupt\n");
1170
1171         return 0;
1172 }
1173
1174 int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg)
1175 {
1176         struct fb_var_screeninfo *var = &fb->var;
1177         struct s3cfb_window *win = fb->par;
1178         struct s3cfb_global *fbdev = get_fimd_global(fb->node);
1179         struct s3cfb_lcd *lcd = fbdev->lcd;
1180         int ret = 0;
1181
1182         union {
1183                 struct s3cfb_user_window user_window;
1184                 struct s3cfb_user_plane_alpha user_alpha;
1185                 struct s3cfb_user_chroma user_chroma;
1186                 int vsync;
1187         } p;
1188
1189         switch (cmd) {
1190         case FBIO_WAITFORVSYNC:
1191                 s3cfb_wait_for_vsync(fbdev);
1192                 break;
1193
1194         case S3CFB_WIN_POSITION:
1195                 if (copy_from_user(&p.user_window,
1196                                    (struct s3cfb_user_window __user *)arg,
1197                                    sizeof(p.user_window)))
1198                         ret = -EFAULT;
1199                 else {
1200                         if (p.user_window.x < 0)
1201                                 p.user_window.x = 0;
1202
1203                         if (p.user_window.y < 0)
1204                                 p.user_window.y = 0;
1205
1206                         if (p.user_window.x + var->xres > lcd->width)
1207                                 win->x = lcd->width - var->xres;
1208                         else
1209                                 win->x = p.user_window.x;
1210
1211                         if (p.user_window.y + var->yres > lcd->height)
1212                                 win->y = lcd->height - var->yres;
1213                         else
1214                                 win->y = p.user_window.y;
1215
1216                         s3cfb_set_window_position(fbdev, win->id);
1217                 }
1218                 break;
1219
1220         case S3CFB_WIN_SET_PLANE_ALPHA:
1221                 if (copy_from_user(&p.user_alpha,
1222                                    (struct s3cfb_user_plane_alpha __user *)arg,
1223                                    sizeof(p.user_alpha)))
1224                         ret = -EFAULT;
1225                 else {
1226                         win->alpha.mode = PLANE_BLENDING;
1227                         win->alpha.channel = p.user_alpha.channel;
1228                         win->alpha.value =
1229                             S3CFB_AVALUE(p.user_alpha.red,
1230                                          p.user_alpha.green, p.user_alpha.blue);
1231
1232                         s3cfb_set_alpha_blending(fbdev, win->id);
1233                 }
1234                 break;
1235
1236         case S3CFB_WIN_SET_CHROMA:
1237                 if (copy_from_user(&p.user_chroma,
1238                                    (struct s3cfb_user_chroma __user *)arg,
1239                                    sizeof(p.user_chroma)))
1240                         ret = -EFAULT;
1241                 else {
1242                         win->chroma.enabled = p.user_chroma.enabled;
1243                         win->chroma.key = S3CFB_CHROMA(p.user_chroma.red,
1244                                                        p.user_chroma.green,
1245                                                        p.user_chroma.blue);
1246
1247                         s3cfb_set_chroma_key(fbdev, win->id);
1248                 }
1249                 break;
1250
1251         case S3CFB_SET_VSYNC_INT:
1252                 break;
1253
1254 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
1255         case S3CFB_GET_FB_UMP_SECURE_ID_0:
1256                 {
1257                         u32 __user *psecureid = (u32 __user *) arg;
1258                         ump_secure_id secure_id;
1259
1260                         dev_info(fbdev->dev, "ump_dd_secure_id_get\n");
1261                         secure_id = ump_dd_secure_id_get(win->ump_wrapped_buffer[0]);
1262                         dev_info(fbdev->dev,
1263                                 "Saving secure id 0x%x in userptr %p\n"
1264                                 , (unsigned int)secure_id, psecureid);
1265                         dev_dbg(fbdev->dev,
1266                                 "Saving secure id 0x%x in userptr %p\n"
1267                                 , (unsigned int)secure_id, psecureid);
1268                         return put_user((unsigned int)secure_id, psecureid);
1269                 }
1270                 break;
1271
1272         case S3CFB_GET_FB_UMP_SECURE_ID_1:
1273                 {
1274                         u32 __user *psecureid = (u32 __user *) arg;
1275                         ump_secure_id secure_id;
1276
1277                         dev_info(fbdev->dev, "ump_dd_secure_id_get\n");
1278                         secure_id = ump_dd_secure_id_get(win->ump_wrapped_buffer[1]);
1279                         dev_info(fbdev->dev,
1280                                         "Saving secure id 0x%x in userptr %p\n"
1281                                         , (unsigned int)secure_id, psecureid);
1282                         dev_dbg(fbdev->dev,
1283                                         "Saving secure id 0x%x in userptr %p\n"
1284                                         , (unsigned int)secure_id, psecureid);
1285                         return put_user((unsigned int)secure_id, psecureid);
1286                 }
1287                 break;
1288
1289         case S3CFB_GET_FB_UMP_SECURE_ID_2:
1290                 {
1291                         u32 __user *psecureid = (u32 __user *) arg;
1292                         ump_secure_id secure_id;
1293
1294                         dev_info(fbdev->dev, "ump_dd_secure_id_get\n");
1295                         secure_id = ump_dd_secure_id_get(win->ump_wrapped_buffer[2]);
1296                         dev_info(fbdev->dev,
1297                                         "Saving secure id 0x%x in userptr %p\n"
1298                                         , (unsigned int)secure_id, psecureid);
1299                         dev_dbg(fbdev->dev,
1300                                         "Saving secure id 0x%x in userptr %p\n"
1301                                         , (unsigned int)secure_id, psecureid);
1302                         return put_user((unsigned int)secure_id, psecureid);
1303                 }
1304                 break;
1305
1306 #endif
1307         }
1308
1309         return ret;
1310 }
1311
1312 int s3cfb_enable_localpath(struct s3cfb_global *fbdev, int id)
1313 {
1314         struct s3cfb_window *win = fbdev->fb[id]->par;
1315
1316         if (s3cfb_channel_localpath_on(fbdev, id)) {
1317                 win->enabled = 0;
1318                 return -EFAULT;
1319         } else {
1320                 win->enabled = 1;
1321                 return 0;
1322         }
1323 }
1324
1325 int s3cfb_disable_localpath(struct s3cfb_global *fbdev, int id)
1326 {
1327         struct s3cfb_window *win = fbdev->fb[id]->par;
1328
1329         if (s3cfb_channel_localpath_off(fbdev, id)) {
1330                 win->enabled = 1;
1331                 return -EFAULT;
1332         } else {
1333                 win->enabled = 0;
1334                 return 0;
1335         }
1336 }
1337
1338 int s3cfb_open_fifo(int id, int ch, int (*do_priv) (void *), void *param)
1339 {
1340         struct s3cfb_global *fbdev = get_fimd_global(id);
1341         struct s3cfb_window *win = fbdev->fb[id]->par;
1342
1343         WARN(pm_runtime_suspended(fbdev->dev), "%s\n", __func__);
1344         pm_runtime_get_sync(fbdev->dev);
1345
1346         dev_dbg(fbdev->dev, "[fb%d] open fifo\n", win->id);
1347
1348         if (win->path == DATA_PATH_DMA) {
1349                 dev_err(fbdev->dev, "WIN%d is busy.\n", id);
1350                 pm_runtime_put(fbdev->dev);
1351                 return -EFAULT;
1352         }
1353
1354         win->local_channel = ch;
1355
1356         if (do_priv) {
1357                 if (do_priv(param)) {
1358                         dev_err(fbdev->dev, "failed to run for "
1359                                 "private fifo open\n");
1360                         s3cfb_enable_window(fbdev, id);
1361                         pm_runtime_put(fbdev->dev);
1362                         return -EFAULT;
1363                 }
1364         }
1365
1366         s3cfb_set_window_control(fbdev, id);
1367         s3cfb_enable_window(fbdev, id);
1368         s3cfb_enable_localpath(fbdev, id);
1369
1370         pm_runtime_put(fbdev->dev);
1371
1372         return 0;
1373 }
1374 EXPORT_SYMBOL(s3cfb_open_fifo);
1375
1376 int s3cfb_close_fifo(int id, int (*do_priv) (void *), void *param)
1377 {
1378         struct s3cfb_global *fbdev = get_fimd_global(id);
1379         struct s3cfb_window *win = fbdev->fb[id]->par;
1380         win->path = DATA_PATH_DMA;
1381
1382         WARN(pm_runtime_suspended(fbdev->dev), "%s\n", __func__);
1383         pm_runtime_get_sync(fbdev->dev);
1384
1385         dev_dbg(fbdev->dev, "[fb%d] close fifo\n", win->id);
1386
1387         if (do_priv) {
1388                 s3cfb_display_off(fbdev);
1389
1390                 if (do_priv(param)) {
1391                         dev_err(fbdev->dev, "failed to run for"
1392                                 "private fifo close\n");
1393                         s3cfb_enable_window(fbdev, id);
1394                         s3cfb_display_on(fbdev);
1395                         pm_runtime_put(fbdev->dev);
1396                         return -EFAULT;
1397                 }
1398
1399                 s3cfb_disable_window(fbdev, id);
1400                 s3cfb_disable_localpath(fbdev, id);
1401                 s3cfb_display_on(fbdev);
1402         } else {
1403                 s3cfb_disable_window(fbdev, id);
1404                 s3cfb_disable_localpath(fbdev, id);
1405         }
1406
1407         pm_runtime_put(fbdev->dev);
1408
1409         return 0;
1410 }
1411 EXPORT_SYMBOL(s3cfb_close_fifo);
1412
1413 int s3cfb_direct_ioctl(int id, unsigned int cmd, unsigned long arg)
1414 {
1415         struct s3cfb_global *fbdev = get_fimd_global(id);
1416         struct fb_info *fb = fbdev->fb[id];
1417         struct fb_var_screeninfo *var = &fb->var;
1418         struct fb_fix_screeninfo *fix = &fb->fix;
1419         struct s3cfb_window *win = fb->par;
1420         struct s3cfb_lcd *lcd = fbdev->lcd;
1421         struct s3cfb_user_window user_win;
1422         void *argp = (void *)arg;
1423         int ret = 0;
1424
1425         WARN(pm_runtime_suspended(fbdev->dev), "%s: cmd: 0x%x\n", __func__, cmd);
1426         pm_runtime_get_sync(fbdev->dev);
1427
1428         switch (cmd) {
1429         case FBIOGET_FSCREENINFO:
1430                 ret = memcpy(argp, &fb->fix, sizeof(fb->fix)) ? 0 : -EFAULT;
1431                 break;
1432
1433         case FBIOGET_VSCREENINFO:
1434                 ret = memcpy(argp, &fb->var, sizeof(fb->var)) ? 0 : -EFAULT;
1435                 break;
1436
1437         case FBIOPUT_VSCREENINFO:
1438                 ret = s3cfb_check_var((struct fb_var_screeninfo *)argp, fb);
1439                 if (ret) {
1440                         dev_err(fbdev->dev, "invalid vscreeninfo\n");
1441                         break;
1442                 }
1443
1444                 ret = memcpy(&fb->var, (struct fb_var_screeninfo *)argp,
1445                              sizeof(fb->var)) ? 0 : -EFAULT;
1446                 if (ret) {
1447                         dev_err(fbdev->dev, "failed to put new vscreeninfo\n");
1448                         break;
1449                 }
1450
1451                 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
1452                 fix->smem_len = fix->line_length * var->yres_virtual;
1453
1454                 s3cfb_set_win_params(fbdev, id);
1455                 break;
1456
1457         case S3CFB_WIN_POSITION:
1458                 ret = memcpy(&user_win, (struct s3cfb_user_window __user *)arg,
1459                              sizeof(user_win)) ? 0 : -EFAULT;
1460                 if (ret) {
1461                         dev_err(fbdev->dev, "failed to S3CFB_WIN_POSITION\n");
1462                         break;
1463                 }
1464
1465                 if (user_win.x < 0)
1466                         user_win.x = 0;
1467
1468                 if (user_win.y < 0)
1469                         user_win.y = 0;
1470
1471                 if (user_win.x + var->xres > lcd->width)
1472                         win->x = lcd->width - var->xres;
1473                 else
1474                         win->x = user_win.x;
1475
1476                 if (user_win.y + var->yres > lcd->height)
1477                         win->y = lcd->height - var->yres;
1478                 else
1479                         win->y = user_win.y;
1480
1481                 s3cfb_set_window_position(fbdev, win->id);
1482                 break;
1483
1484         case S3CFB_GET_LCD_WIDTH:
1485                 ret = memcpy(argp, &lcd->width, sizeof(int)) ? 0 : -EFAULT;
1486                 if (ret) {
1487                         dev_err(fbdev->dev, "failed to S3CFB_GET_LCD_WIDTH\n");
1488                         break;
1489                 }
1490
1491                 break;
1492
1493         case S3CFB_GET_LCD_HEIGHT:
1494                 ret = memcpy(argp, &lcd->height, sizeof(int)) ? 0 : -EFAULT;
1495                 if (ret) {
1496                         dev_err(fbdev->dev, "failed to S3CFB_GET_LCD_HEIGHT\n");
1497                         break;
1498                 }
1499
1500                 break;
1501
1502         case S3CFB_SET_WRITEBACK:
1503                 if ((u32)argp == 1)
1504                         fbdev->output = OUTPUT_WB_RGB;
1505                 else
1506                         fbdev->output = OUTPUT_RGB;
1507
1508                 s3cfb_set_output(fbdev);
1509
1510                 break;
1511
1512         case S3CFB_SET_WIN_ON:
1513                 s3cfb_enable_window(fbdev, id);
1514                 break;
1515
1516         case S3CFB_SET_WIN_OFF:
1517                 s3cfb_disable_window(fbdev, id);
1518                 break;
1519
1520         case S3CFB_SET_WIN_PATH:
1521                 win->path = (enum s3cfb_data_path_t)argp;
1522                 break;
1523
1524         case S3CFB_SET_WIN_ADDR:
1525                 fix->smem_start = (unsigned long)argp;
1526                 s3cfb_set_buffer_address(fbdev, id);
1527                 break;
1528
1529         case S3CFB_SET_WIN_MEM:
1530                 win->owner = (enum s3cfb_mem_owner_t)argp;
1531                 break;
1532
1533         case S3CFB_SET_VSYNC_INT:
1534                 if (argp)
1535                         s3cfb_set_global_interrupt(fbdev, 1);
1536
1537                 s3cfb_set_vsync_interrupt(fbdev, (int)argp);
1538                 break;
1539
1540         case S3CFB_GET_VSYNC_INT_STATUS:
1541                 ret = s3cfb_get_vsync_interrupt(fbdev);
1542                 break;
1543
1544         default:
1545                 ret = s3cfb_ioctl(fb, cmd, arg);
1546                 break;
1547         }
1548
1549         pm_runtime_put(fbdev->dev);
1550
1551         return ret;
1552 }
1553 EXPORT_SYMBOL(s3cfb_direct_ioctl);
1554
1555 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
1556 MODULE_AUTHOR("Jonghun, Han <jonghun.han@samsung.com>");
1557 MODULE_AUTHOR("Jinsung, Yang <jsgood.yang@samsung.com>");
1558 MODULE_DESCRIPTION("Samsung Display Controller (FIMD) driver");
1559 MODULE_LICENSE("GPL");