1 /* linux/drivers/video/samsung/s3cfb-ops.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * Middle layer file for Samsung Display Controller (FIMD) driver
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.
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>
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>
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)
34 #ifdef CONFIG_SEC_DEBUG
35 #include <mach/sec_debug.h>
38 struct s3c_platform_fb *to_fb_plat(struct device *dev)
40 struct platform_device *pdev = to_platform_device(dev);
42 return (struct s3c_platform_fb *)pdev->dev.platform_data;
45 int conv_rgb565_to_rgb888(unsigned short rgb565, unsigned int sw)
47 char red, green, blue;
48 unsigned int threshold = 150;
50 red = (rgb565 & 0xF800) >> 11;
51 green = (rgb565 & 0x7E0) >> 5;
52 blue = (rgb565 & 0x1F);
58 /* correct error pixels of samsung logo. */
62 if (green > threshold)
68 return (red << 16 | green << 8 | blue);
71 void _draw_samsung_logo(void *lcdbase, int lcd_width, int x, int y, int w, int h, unsigned short *bmp)
73 int i, j, error_range = 40;
76 unsigned long *fb = (unsigned long*) lcdbase;
78 for (j = y; j < (y + h); j++) {
79 for (i = x; i < (x + w); i++) {
80 pixel = (*(bmp + k++));
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);
87 *(fb + (j * lcd_width) + i) =
88 conv_rgb565_to_rgb888(pixel, 0);
93 void _rotate_samsung_logo(void *lcdbase, int lcd_width, int x, int y, int w, int h, unsigned short *bmp)
95 int i, j, error_range = 40;
98 unsigned long *fb = (unsigned long*) lcdbase;
100 for (j = (y + h); j > y; j--) {
101 for (i = x; i < (x + w); i++) {
102 pixel = (*(bmp + k++));
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);
109 *(fb + (i * lcd_width) + j) =
110 conv_rgb565_to_rgb888(pixel, 0);
115 static void draw_samsung_logo(struct s3cfb_global *fbdev, struct s3c_platform_fb *pdata)
117 unsigned int x, y, win_id, width, height;
118 struct fb_info *pfb = NULL;
123 win_id = pdata->default_win;
124 pfb = fbdev->fb[win_id];
126 width = pfb->var.xres;
127 height = pfb->var.yres;
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);
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);
142 #ifndef CONFIG_FRAMEBUFFER_CONSOLE
143 int s3cfb_draw_logo(struct s3cfb_global *fbdev, int id)
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;
150 memcpy(fbdev->fb[pdata->default_win]->screen_base,
151 LOGO_RGB24, fix->line_length * var->yres);
153 u32 height = var->yres / 3;
154 u32 line = fix->line_length;
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);
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);
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);
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);
193 int fb_is_primary_device(struct fb_info *fb)
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);
199 dev_dbg(fbdev->dev, "[fb%d] checking for primary device\n", win->id);
201 if (win->id == pdata->default_win)
208 int s3cfb_enable_window(struct s3cfb_global *fbdev, int id)
210 struct s3cfb_window *win = fbdev->fb[id]->par;
213 atomic_inc(&fbdev->enabled_win);
215 if (s3cfb_window_on(fbdev, id)) {
224 int s3cfb_disable_window(struct s3cfb_global *fbdev, int id)
226 struct s3cfb_window *win = fbdev->fb[id]->par;
229 atomic_dec(&fbdev->enabled_win);
231 if (s3cfb_window_off(fbdev, id)) {
240 int s3cfb_update_power_state(struct s3cfb_global *fbdev, int id, int state)
242 struct s3cfb_window *win = fbdev->fb[id]->par;
243 win->power_state = state;
248 int s3cfb_init_global(struct s3cfb_global *fbdev)
250 fbdev->output = OUTPUT_RGB;
251 fbdev->rgb_mode = MODE_RGB_P;
254 init_waitqueue_head(&fbdev->wq);
255 mutex_init(&fbdev->lock);
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);
267 static const struct s5p_vcm_driver s3cfb_vcm_driver = {
268 .tlb_invalidator = NULL,
269 .pgd_base_specifier = NULL,
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)
278 ump_dd_physical_block ump_memory_description;
279 unsigned int buffer_size;
280 buffer_size = fix->smem_len / CONFIG_FB_S3C_NR_BUFFERS;
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);
286 win->ump_wrapped_buffer[id] =
287 ump_dd_handle_create_from_phys_blocks
288 (&ump_memory_description, 1);
290 if (ump_dd_meminfo_set(win->ump_wrapped_buffer[id], (void*)arg))
297 int s3cfb_map_video_memory(struct s3cfb_global *fbdev, struct fb_info *fb)
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;
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;
311 #if defined(CONFIG_VCM) || \
312 (MALI_USE_UNIFIED_MEMORY_PROVIDER && defined(CONFIG_UMP_VCM_ALLOC))
317 struct fb_var_screeninfo *var = &fb->var;
318 struct cma_info mem_info;
319 unsigned int reserved_size;
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];
328 #ifdef CONFIG_S5P_MEM_CMA
329 struct cma_info mem_info;
330 unsigned int reserved_size;
335 if (win->owner == DMA_MEM_OTHER)
339 phys = kmalloc(sizeof(*phys) + sizeof(*phys->parts), GFP_KERNEL);
340 memset(phys, 0, sizeof(*phys) + sizeof(*phys->parts));
347 err = cma_info(&mem_info, fbdev->dev, 0);
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);
356 phys->size = reserved_size;
358 phys->parts[0].size = reserved_size;
359 phys->parts[0].start = fix->smem_start;
361 win->s5p_vcm_res = vcm_map(fbdev->s5p_vcm, phys, 0);
363 if (IS_ERR(win->s5p_vcm_res)) {
364 return PTR_ERR(win->s5p_vcm_res);
367 device_virt_start = win->s5p_vcm_res->start;
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];
373 win->s3cfb_vcm[i].dev_vcm_res->start = device_virt_start
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))
384 #ifdef CONFIG_S5P_MEM_CMA
385 err = cma_info(&mem_info, fbdev->dev, 0);
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);
395 memset(fb->screen_base, 0, (fix->smem_len / frame_num));
396 win->owner = DMA_MEM_FIMD;
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;
404 arg = (unsigned int)&ump_vcm;
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);
410 win->ump_wrapped_buffer[i] =
411 ump_dd_handle_create_from_phys_blocks
412 (&ump_memory_description, 1);
414 if (ump_dd_meminfo_set(win->ump_wrapped_buffer[i], (void*)arg))
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);
430 int s3cfb_map_default_video_memory(struct s3cfb_global *fbdev,
431 struct fb_info *fb, int fimd_id)
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;
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;
445 #if defined(CONFIG_VCM) || \
446 (MALI_USE_UNIFIED_MEMORY_PROVIDER && defined(CONFIG_UMP_VCM_ALLOC))
451 struct cma_info mem_info;
452 unsigned int reserved_size;
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];
461 #ifdef CONFIG_S5P_MEM_CMA
462 struct cma_info mem_info;
463 unsigned int reserved_size;
468 if (win->owner == DMA_MEM_OTHER)
472 phys = kmalloc(sizeof(*phys) + sizeof(*phys->parts), GFP_KERNEL);
473 memset(phys, 0, sizeof(*phys) + sizeof(*phys->parts));
480 err = cma_info(&mem_info, fbdev->dev, 0);
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);
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);
495 phys->size = reserved_size;
497 phys->parts[0].size = reserved_size;
498 phys->parts[0].start = fix->smem_start;
500 win->s5p_vcm_res = vcm_map(fbdev->s5p_vcm, phys, 0);
501 device_virt_start = win->s5p_vcm_res->start;
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];
507 win->s3cfb_vcm[i].dev_vcm_res->start = device_virt_start
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))
517 #ifdef CONFIG_S5P_MEM_CMA
518 err = cma_info(&mem_info, fbdev->dev, 0);
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);
533 memset(fb->screen_base, 0, (fix->smem_len / CONFIG_FB_S3C_NR_BUFFERS));
534 win->owner = DMA_MEM_FIMD;
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;
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);
546 win->ump_wrapped_buffer[i] =
547 ump_dd_handle_create_from_phys_blocks
548 (&ump_memory_description, 1);
550 if (ump_dd_meminfo_set(win->ump_wrapped_buffer[i], (void*)arg))
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);
566 int s3cfb_unmap_video_memory(struct s3cfb_global *fbdev, struct fb_info *fb)
568 struct fb_fix_screeninfo *fix = &fb->fix;
569 struct s3cfb_window *win = fb->par;
571 struct fb_var_screeninfo *var = &fb->var;
572 int frame_num = var->yres_virtual / var->yres;
576 if (fix->smem_start) {
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);
583 dma_free_writecombine(fbdev->dev, fix->smem_len,
584 fb->screen_base, fix->smem_start);
588 dev_info(fbdev->dev, "[fb%d] video memory released\n", win->id);
593 int s3cfb_unmap_default_video_memory(struct s3cfb_global *fbdev,
596 struct fb_fix_screeninfo *fix = &fb->fix;
597 struct s3cfb_window *win = fb->par;
602 if (fix->smem_start) {
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);
612 dev_info(fbdev->dev, "[fb%d] video memory released\n", win->id);
618 int s3cfb_set_bitfield(struct fb_var_screeninfo *var)
620 switch (var->bits_per_pixel) {
622 if (var->transp.length == 1) {
623 var->red.offset = 10;
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) {
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;
639 var->red.offset = 11;
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;
650 var->red.offset = 16;
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;
661 var->red.offset = 16;
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;
674 int s3cfb_set_alpha_info(struct fb_var_screeninfo *var,
675 struct s3cfb_window *win)
677 if (var->transp.length > 0)
678 win->alpha.mode = PIXEL_BLENDING;
680 win->alpha.mode = PLANE_BLENDING;
681 win->alpha.channel = 0;
682 win->alpha.value = S3CFB_AVALUE(0xf, 0xf, 0xf);
688 int s3cfb_check_var_window(struct s3cfb_global *fbdev,
689 struct fb_var_screeninfo *var, struct fb_info *fb)
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;
695 dev_dbg(fbdev->dev, "[fb%d] check_var\n", win->id);
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");
703 if (var->xres > lcd->width)
704 var->xres = lcd->width;
706 if (var->yres > lcd->height)
707 var->yres = lcd->height;
709 if (var->xres_virtual < var->xres)
710 var->xres_virtual = var->xres;
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;
717 if (var->xoffset > (var->xres_virtual - var->xres))
718 var->xoffset = var->xres_virtual - var->xres;
720 if (var->yoffset + var->yres > var->yres_virtual)
721 var->yoffset = var->yres_virtual - var->yres;
723 if (win->x + var->xres > lcd->width)
724 win->x = lcd->width - var->xres;
726 if (win->y + var->yres > lcd->height)
727 win->y = lcd->height - var->yres;
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,
735 s3cfb_set_bitfield(var);
736 s3cfb_set_alpha_info(var, win);
741 int s3cfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
743 struct s3cfb_global *fbdev = get_fimd_global(fb->node);
745 s3cfb_check_var_window(fbdev, var, fb);
750 void s3cfb_set_win_params(struct s3cfb_global *fbdev, int id)
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);
759 s3cfb_set_alpha_blending(fbdev, id);
760 s3cfb_set_chroma_key(fbdev, id);
761 s3cfb_set_alpha_value_width(fbdev, id);
765 int s3cfb_set_par_window(struct s3cfb_global *fbdev, struct fb_info *fb)
767 struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
768 struct s3cfb_window *win = fb->par;
770 dev_dbg(fbdev->dev, "[fb%d] set_par\n", win->id);
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;
779 if (win->id != pdata->default_win && fb->fix.smem_start == 0)
780 s3cfb_map_video_memory(fbdev, fb);
782 s3cfb_set_win_params(fbdev, win->id);
787 int s3cfb_set_par(struct fb_info *fb)
789 struct s3cfb_global *fbdev = get_fimd_global(fb->node);
791 s3cfb_set_par_window(fbdev, fb);
796 int s3cfb_init_fbinfo(struct s3cfb_global *fbdev, int id)
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;
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));
812 win->path = DATA_PATH_DMA;
814 s3cfb_update_power_state(fbdev, win->id, FB_BLANK_POWERDOWN);
815 alpha->mode = PLANE_BLENDING;
818 fb->fbops = &s3cfb_ops;
819 fb->flags = FBINFO_FLAG_DEFAULT;
820 fb->pseudo_palette = &win->pseudo_pal;
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;
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;
835 var->xres_virtual = var->xres;
836 var->yres_virtual = var->yres * CONFIG_FB_S3C_NR_BUFFERS;
838 var->bits_per_pixel = 32;
841 var->width = lcd->width_mm;
842 var->height = lcd->height_mm;
843 var->transp.length = 0;
845 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
846 fix->smem_len = fix->line_length * var->yres_virtual;
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);
864 s3cfb_set_bitfield(var);
865 s3cfb_set_alpha_info(var, win);
870 int s3cfb_alloc_framebuffer(struct s3cfb_global *fbdev, int fimd_id)
872 struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
876 fbdev->fb = kmalloc(pdata->nr_wins *
877 sizeof(struct fb_info *), GFP_KERNEL);
879 dev_err(fbdev->dev, "not enough memory\n");
884 for (i = 0; i < pdata->nr_wins; i++) {
885 fbdev->fb[i] = framebuffer_alloc(sizeof(struct s3cfb_window),
888 dev_err(fbdev->dev, "not enough memory\n");
893 ret = s3cfb_init_fbinfo(fbdev, i);
896 "failed to allocate memory for fb%d\n", i);
901 if (i == pdata->default_win)
902 if (s3cfb_map_default_video_memory(fbdev,
903 fbdev->fb[i], fimd_id)) {
905 "failed to map video memory "
906 "for default window (%d)\n", i);
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);
922 for (i = 0; i < pdata->nr_wins; i++) {
924 framebuffer_release(fbdev->fb[i]);
932 int s3cfb_open(struct fb_info *fb, int user)
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);
939 mutex_lock(&fbdev->lock);
941 if (atomic_read(&win->in_use)) {
942 if (win->id == pdata->default_win) {
944 "mutiple open for default window\n");
948 "do not allow multiple open \
949 for non-default window\n");
953 atomic_inc(&win->in_use);
956 mutex_unlock(&fbdev->lock);
961 int s3cfb_release_window(struct fb_info *fb)
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);
967 if (win->id != pdata->default_win) {
968 s3cfb_disable_window(fbdev, win->id);
972 s3cfb_unmap_video_memory(fbdev, fb);
982 int s3cfb_release(struct fb_info *fb, int user)
984 struct s3cfb_window *win = fb->par;
985 struct s3cfb_global *fbdev = get_fimd_global(fb->node);
987 s3cfb_release_window(fb);
989 mutex_lock(&fbdev->lock);
990 atomic_dec(&win->in_use);
991 mutex_unlock(&fbdev->lock);
996 inline unsigned int __chan_to_field(unsigned int chan, struct fb_bitfield bf)
999 chan >>= 16 - bf.length;
1001 return chan << bf.offset;
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)
1008 unsigned int *pal = (unsigned int *)fb->pseudo_palette;
1009 unsigned int val = 0;
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);
1023 int s3cfb_blank(int blank_mode, struct fb_info *fb)
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;
1030 dev_dbg(fbdev->dev, "change blank mode\n");
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);
1040 if (win->power_state == FB_BLANK_UNBLANK) {
1041 dev_info(fbdev->dev, "[fb%d] already in \
1042 FB_BLANK_UNBLANK\n", win->id);
1045 s3cfb_update_power_state(fbdev, win->id,
1049 enabled_win = atomic_read(&fbdev->enabled_win);
1051 if(!atomic_read(&fbdev->enabled))
1052 pm_runtime_get_sync(fbdev->dev);
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);
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.
1063 s3cfb_win_map_off(fbdev, win->id);
1066 if (enabled_win == 0)
1067 s3cfb_display_on(fbdev);
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);
1077 s3cfb_update_power_state(fbdev, win->id,
1081 enabled_win = atomic_read(&fbdev->enabled_win);
1082 if(enabled_win == 0 || !atomic_read(&fbdev->enabled))
1083 pm_runtime_get_sync(fbdev->dev);
1085 s3cfb_win_map_on(fbdev, win->id, 0x0);
1087 if (!win->enabled) /* from FB_BLANK_POWERDOWN */
1088 s3cfb_enable_window(fbdev, win->id);
1090 if (enabled_win == 0)
1091 s3cfb_display_on(fbdev);
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);
1101 s3cfb_update_power_state(fbdev, win->id,
1102 FB_BLANK_POWERDOWN);
1105 s3cfb_disable_window(fbdev, win->id);
1106 s3cfb_win_map_off(fbdev, win->id);
1108 if(atomic_read(&fbdev->enabled) > 0)
1109 pm_runtime_put(fbdev->dev);
1115 case FB_BLANK_VSYNC_SUSPEND: /* fall through */
1116 case FB_BLANK_HSYNC_SUSPEND: /* fall through */
1118 dev_dbg(fbdev->dev, "unsupported blank mode\n");
1125 int s3cfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
1127 struct s3cfb_window *win = fb->par;
1128 struct s3cfb_global *fbdev = get_fimd_global(fb->node);
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
1135 if (atomic_read(&fbdev->enabled_win) <= 0 ||
1136 !atomic_read(&fbdev->enabled))
1139 if (var->yoffset + var->yres > var->yres_virtual) {
1140 dev_err(fbdev->dev, "invalid yoffset value\n");
1144 fb->var.yoffset = var->yoffset;
1146 dev_dbg(fbdev->dev, "[fb%d] yoffset for pan display: %d\n", win->id,
1149 s3cfb_set_buffer_address(fbdev, win->id);
1154 int s3cfb_cursor(struct fb_info *fb, struct fb_cursor *cursor)
1156 /* nothing to do for removing cursor */
1160 int s3cfb_wait_for_vsync(struct s3cfb_global *fbdev)
1162 dev_dbg(fbdev->dev, "waiting for VSYNC interrupt\n");
1164 s3cfb_set_global_interrupt(fbdev, 1);
1165 s3cfb_set_vsync_interrupt(fbdev, 1);
1167 sleep_on_timeout(&fbdev->wq, HZ / 10);
1169 dev_dbg(fbdev->dev, "got a VSYNC interrupt\n");
1174 int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg)
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;
1183 struct s3cfb_user_window user_window;
1184 struct s3cfb_user_plane_alpha user_alpha;
1185 struct s3cfb_user_chroma user_chroma;
1190 case FBIO_WAITFORVSYNC:
1191 s3cfb_wait_for_vsync(fbdev);
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)))
1200 if (p.user_window.x < 0)
1201 p.user_window.x = 0;
1203 if (p.user_window.y < 0)
1204 p.user_window.y = 0;
1206 if (p.user_window.x + var->xres > lcd->width)
1207 win->x = lcd->width - var->xres;
1209 win->x = p.user_window.x;
1211 if (p.user_window.y + var->yres > lcd->height)
1212 win->y = lcd->height - var->yres;
1214 win->y = p.user_window.y;
1216 s3cfb_set_window_position(fbdev, win->id);
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)))
1226 win->alpha.mode = PLANE_BLENDING;
1227 win->alpha.channel = p.user_alpha.channel;
1229 S3CFB_AVALUE(p.user_alpha.red,
1230 p.user_alpha.green, p.user_alpha.blue);
1232 s3cfb_set_alpha_blending(fbdev, win->id);
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)))
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);
1247 s3cfb_set_chroma_key(fbdev, win->id);
1251 case S3CFB_SET_VSYNC_INT:
1254 #if MALI_USE_UNIFIED_MEMORY_PROVIDER
1255 case S3CFB_GET_FB_UMP_SECURE_ID_0:
1257 u32 __user *psecureid = (u32 __user *) arg;
1258 ump_secure_id secure_id;
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);
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);
1272 case S3CFB_GET_FB_UMP_SECURE_ID_1:
1274 u32 __user *psecureid = (u32 __user *) arg;
1275 ump_secure_id secure_id;
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);
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);
1289 case S3CFB_GET_FB_UMP_SECURE_ID_2:
1291 u32 __user *psecureid = (u32 __user *) arg;
1292 ump_secure_id secure_id;
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);
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);
1312 int s3cfb_enable_localpath(struct s3cfb_global *fbdev, int id)
1314 struct s3cfb_window *win = fbdev->fb[id]->par;
1316 if (s3cfb_channel_localpath_on(fbdev, id)) {
1325 int s3cfb_disable_localpath(struct s3cfb_global *fbdev, int id)
1327 struct s3cfb_window *win = fbdev->fb[id]->par;
1329 if (s3cfb_channel_localpath_off(fbdev, id)) {
1338 int s3cfb_open_fifo(int id, int ch, int (*do_priv) (void *), void *param)
1340 struct s3cfb_global *fbdev = get_fimd_global(id);
1341 struct s3cfb_window *win = fbdev->fb[id]->par;
1343 WARN(pm_runtime_suspended(fbdev->dev), "%s\n", __func__);
1344 pm_runtime_get_sync(fbdev->dev);
1346 dev_dbg(fbdev->dev, "[fb%d] open fifo\n", win->id);
1348 if (win->path == DATA_PATH_DMA) {
1349 dev_err(fbdev->dev, "WIN%d is busy.\n", id);
1350 pm_runtime_put(fbdev->dev);
1354 win->local_channel = ch;
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);
1366 s3cfb_set_window_control(fbdev, id);
1367 s3cfb_enable_window(fbdev, id);
1368 s3cfb_enable_localpath(fbdev, id);
1370 pm_runtime_put(fbdev->dev);
1374 EXPORT_SYMBOL(s3cfb_open_fifo);
1376 int s3cfb_close_fifo(int id, int (*do_priv) (void *), void *param)
1378 struct s3cfb_global *fbdev = get_fimd_global(id);
1379 struct s3cfb_window *win = fbdev->fb[id]->par;
1380 win->path = DATA_PATH_DMA;
1382 WARN(pm_runtime_suspended(fbdev->dev), "%s\n", __func__);
1383 pm_runtime_get_sync(fbdev->dev);
1385 dev_dbg(fbdev->dev, "[fb%d] close fifo\n", win->id);
1388 s3cfb_display_off(fbdev);
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);
1399 s3cfb_disable_window(fbdev, id);
1400 s3cfb_disable_localpath(fbdev, id);
1401 s3cfb_display_on(fbdev);
1403 s3cfb_disable_window(fbdev, id);
1404 s3cfb_disable_localpath(fbdev, id);
1407 pm_runtime_put(fbdev->dev);
1411 EXPORT_SYMBOL(s3cfb_close_fifo);
1413 int s3cfb_direct_ioctl(int id, unsigned int cmd, unsigned long arg)
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;
1425 WARN(pm_runtime_suspended(fbdev->dev), "%s: cmd: 0x%x\n", __func__, cmd);
1426 pm_runtime_get_sync(fbdev->dev);
1429 case FBIOGET_FSCREENINFO:
1430 ret = memcpy(argp, &fb->fix, sizeof(fb->fix)) ? 0 : -EFAULT;
1433 case FBIOGET_VSCREENINFO:
1434 ret = memcpy(argp, &fb->var, sizeof(fb->var)) ? 0 : -EFAULT;
1437 case FBIOPUT_VSCREENINFO:
1438 ret = s3cfb_check_var((struct fb_var_screeninfo *)argp, fb);
1440 dev_err(fbdev->dev, "invalid vscreeninfo\n");
1444 ret = memcpy(&fb->var, (struct fb_var_screeninfo *)argp,
1445 sizeof(fb->var)) ? 0 : -EFAULT;
1447 dev_err(fbdev->dev, "failed to put new vscreeninfo\n");
1451 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
1452 fix->smem_len = fix->line_length * var->yres_virtual;
1454 s3cfb_set_win_params(fbdev, id);
1457 case S3CFB_WIN_POSITION:
1458 ret = memcpy(&user_win, (struct s3cfb_user_window __user *)arg,
1459 sizeof(user_win)) ? 0 : -EFAULT;
1461 dev_err(fbdev->dev, "failed to S3CFB_WIN_POSITION\n");
1471 if (user_win.x + var->xres > lcd->width)
1472 win->x = lcd->width - var->xres;
1474 win->x = user_win.x;
1476 if (user_win.y + var->yres > lcd->height)
1477 win->y = lcd->height - var->yres;
1479 win->y = user_win.y;
1481 s3cfb_set_window_position(fbdev, win->id);
1484 case S3CFB_GET_LCD_WIDTH:
1485 ret = memcpy(argp, &lcd->width, sizeof(int)) ? 0 : -EFAULT;
1487 dev_err(fbdev->dev, "failed to S3CFB_GET_LCD_WIDTH\n");
1493 case S3CFB_GET_LCD_HEIGHT:
1494 ret = memcpy(argp, &lcd->height, sizeof(int)) ? 0 : -EFAULT;
1496 dev_err(fbdev->dev, "failed to S3CFB_GET_LCD_HEIGHT\n");
1502 case S3CFB_SET_WRITEBACK:
1504 fbdev->output = OUTPUT_WB_RGB;
1506 fbdev->output = OUTPUT_RGB;
1508 s3cfb_set_output(fbdev);
1512 case S3CFB_SET_WIN_ON:
1513 s3cfb_enable_window(fbdev, id);
1516 case S3CFB_SET_WIN_OFF:
1517 s3cfb_disable_window(fbdev, id);
1520 case S3CFB_SET_WIN_PATH:
1521 win->path = (enum s3cfb_data_path_t)argp;
1524 case S3CFB_SET_WIN_ADDR:
1525 fix->smem_start = (unsigned long)argp;
1526 s3cfb_set_buffer_address(fbdev, id);
1529 case S3CFB_SET_WIN_MEM:
1530 win->owner = (enum s3cfb_mem_owner_t)argp;
1533 case S3CFB_SET_VSYNC_INT:
1535 s3cfb_set_global_interrupt(fbdev, 1);
1537 s3cfb_set_vsync_interrupt(fbdev, (int)argp);
1540 case S3CFB_GET_VSYNC_INT_STATUS:
1541 ret = s3cfb_get_vsync_interrupt(fbdev);
1545 ret = s3cfb_ioctl(fb, cmd, arg);
1549 pm_runtime_put(fbdev->dev);
1553 EXPORT_SYMBOL(s3cfb_direct_ioctl);
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");