diff options
Diffstat (limited to 'drivers/video/samsung/s3cfb_ops.c')
-rw-r--r-- | drivers/video/samsung/s3cfb_ops.c | 694 |
1 files changed, 678 insertions, 16 deletions
diff --git a/drivers/video/samsung/s3cfb_ops.c b/drivers/video/samsung/s3cfb_ops.c index 82ece16..759fb63 100644 --- a/drivers/video/samsung/s3cfb_ops.c +++ b/drivers/video/samsung/s3cfb_ops.c @@ -15,6 +15,12 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/sw_sync.h> +#include <plat/regs-fb.h> +#include <plat/regs-fb-s5p.h> + #if defined(CONFIG_CMA) #include <linux/cma.h> #elif defined(CONFIG_S5P_MEM_BOOTMEM) @@ -43,6 +49,10 @@ #include <mach/dev.h> #endif +#ifdef CONFIG_FB_S5P_SYSMMU +#include <plat/s5p-sysmmu.h> +#endif + struct s3c_platform_fb *to_fb_plat(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -183,7 +193,10 @@ int s3cfb_enable_window(struct s3cfb_global *fbdev, int id) #endif #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) #ifdef CONFIG_BUSFREQ_OPP - if (id != CONFIG_FB_S5P_DEFAULT_WINDOW) + if (CONFIG_FB_S5P_DEFAULT_WINDOW == 3 && + id == CONFIG_FB_S5P_DEFAULT_WINDOW-1) + dev_lock(fbdev->bus_dev, fbdev->dev, 267160); + else if (id != CONFIG_FB_S5P_DEFAULT_WINDOW) dev_lock(fbdev->bus_dev, fbdev->dev, 133133); #endif #endif @@ -394,6 +407,10 @@ int s3cfb_map_default_video_memory(struct s3cfb_global *fbdev, memset(fb->screen_base, 0, fix->smem_len); win->owner = DMA_MEM_FIMD; +#ifdef CONFIG_FB_S5P_SYSMMU + fbdev->sysmmu.default_fb_addr = fix->smem_start; +#endif + return 0; } @@ -457,11 +474,19 @@ int s3cfb_set_bitfield(struct fb_var_screeninfo *var) break; case 32: +#if defined(CONFIG_FB_RGBA_ORDER) + var->red.offset = 0; +#else var->red.offset = 16; +#endif var->red.length = 8; var->green.offset = 8; var->green.length = 8; +#if defined(CONFIG_FB_RGBA_ORDER) + var->blue.offset = 16; +#else var->blue.offset = 0; +#endif var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; /* added for LCD RGB32 */ @@ -1082,30 +1107,631 @@ int s3cfb_cursor(struct fb_info *fb, struct fb_cursor *cursor) return 0; } -int s3cfb_vsync_timestamp_changed(struct s3cfb_global *fbdev, ktime_t prev_timestamp) +#if !defined(CONFIG_FB_S5P_VSYNC_THREAD) +int s3cfb_wait_for_vsync(struct s3cfb_global *fbdev) { - return !ktime_equal(prev_timestamp, fbdev->vsync_timestamp); + dev_dbg(fbdev->dev, "waiting for VSYNC interrupt\n"); + + sleep_on_timeout(&fbdev->wq, HZ / 10); + + dev_dbg(fbdev->dev, "got a VSYNC interrupt\n"); + + return 0; } +#endif -int s3cfb_wait_for_vsync(struct s3cfb_global *fbdev) + +/** + * s3c_fb_align_word() - align pixel count to word boundary + * @bpp: The number of bits per pixel + * @pix: The value to be aligned. + * + * Align the given pixel count so that it will start on an 32bit word + * boundary. + */ +static int s3c_fb_align_word(unsigned int bpp, unsigned int pix) +{ + int pix_per_word; + + if (bpp > 16) + return pix; + + pix_per_word = (8 * 32) / bpp; + return ALIGN(pix, pix_per_word); +} + +static u32 s3c_fb_red_length(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + case S3C_FB_PIXEL_FORMAT_RGB_888: + case S3C_FB_PIXEL_FORMAT_BGRA_8888: + return 8; + + case S3C_FB_PIXEL_FORMAT_RGB_565: + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + return 5; + + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 4; + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } +} + +static u32 s3c_fb_red_offset(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + case S3C_FB_PIXEL_FORMAT_RGB_888: + case S3C_FB_PIXEL_FORMAT_RGB_565: + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 0; + + case S3C_FB_PIXEL_FORMAT_BGRA_8888: + return 16; + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } +} + +static u32 s3c_fb_green_length(int format) +{ + if (format == S3C_FB_PIXEL_FORMAT_RGB_565) + return 6; + + return s3c_fb_red_length(format); +} + +static u32 s3c_fb_green_offset(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_RGB_888: + case S3C_FB_PIXEL_FORMAT_BGRA_8888: + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + return 8; + + case S3C_FB_PIXEL_FORMAT_RGB_565: + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + return 5; + + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 4; + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } +} + +static u32 s3c_fb_blue_length(int format) +{ + return s3c_fb_red_length(format); +} + +static u32 s3c_fb_blue_offset(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_RGB_888: + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + return 16; + + case S3C_FB_PIXEL_FORMAT_RGB_565: + return 11; + + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + return 10; + + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 8; + + case S3C_FB_PIXEL_FORMAT_BGRA_8888: + return 0; + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } +} + +static u32 s3c_fb_transp_length(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_BGRA_8888: + return 8; + + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + return 1; + + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 4; + + case S3C_FB_PIXEL_FORMAT_RGB_888: + case S3C_FB_PIXEL_FORMAT_RGB_565: + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + return 0; + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } +} + +static u32 s3c_fb_transp_offset(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_BGRA_8888: + return 24; + + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + return 15; + + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 12; + + case S3C_FB_PIXEL_FORMAT_RGB_888: + case S3C_FB_PIXEL_FORMAT_RGB_565: + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + return s3c_fb_blue_offset(format); + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } +} + +static u32 s3c_fb_padding(int format) +{ + switch (format) { + case S3C_FB_PIXEL_FORMAT_RGBX_8888: + return 8; + + case S3C_FB_PIXEL_FORMAT_RGB_565: + case S3C_FB_PIXEL_FORMAT_RGBA_8888: + case S3C_FB_PIXEL_FORMAT_RGBA_5551: + case S3C_FB_PIXEL_FORMAT_RGBA_4444: + return 0; + + default: + pr_warn("s3c-fb: unrecognized pixel format %u\n", format); + return 0; + } + +} + +static inline u32 fb_visual(u32 bits_per_pixel, unsigned short palette_sz) +{ + switch (bits_per_pixel) { + case 32: + case 24: + case 16: + case 12: + return FB_VISUAL_TRUECOLOR; + case 8: + if (palette_sz >= 256) + return FB_VISUAL_PSEUDOCOLOR; + else + return FB_VISUAL_TRUECOLOR; + case 1: + return FB_VISUAL_MONO01; + default: + return FB_VISUAL_PSEUDOCOLOR; + } +} + + +static inline u32 fb_linelength(u32 xres_virtual, u32 bits_per_pixel) +{ + return (xres_virtual * bits_per_pixel) / 8; +} + +static inline u16 fb_panstep(u32 res, u32 res_virtual) +{ + return res_virtual > res ? 1 : 0; +} + +static inline u32 vidw_buf_size(u32 xres, u32 line_length, u32 bits_per_pixel) +{ + u32 pagewidth = (xres * bits_per_pixel) >> 3; + return VIDW_BUF_SIZE_OFFSET(line_length - pagewidth) | + VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) | + VIDW_BUF_SIZE_OFFSET_E(line_length - pagewidth) | + VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth); +} + +inline u32 vidosd_a(int x, int y) +{ + return VIDOSDxA_TOPLEFT_X(x) | + VIDOSDxA_TOPLEFT_Y(y) | + VIDOSDxA_TOPLEFT_X_E(x) | + VIDOSDxA_TOPLEFT_Y_E(y); +} + +inline u32 vidosd_b(int x, int y, u32 xres, u32 yres, u32 bits_per_pixel) +{ + return VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(bits_per_pixel, + x + xres - 1)) | + VIDOSDxB_BOTRIGHT_Y(y + yres - 1) | + VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(bits_per_pixel, + x + xres - 1)) | + VIDOSDxB_BOTRIGHT_Y_E(y + yres - 1); +} + +static inline u32 wincon(u32 bits_per_pixel, u32 transp_length, u32 red_length) +{ + u32 data = 0; + + switch (bits_per_pixel) { + case 1: + data |= WINCON0_BPPMODE_1BPP; + data |= WINCONx_BITSWP; + data |= WINCONx_BURSTLEN_4WORD; + break; + case 2: + data |= WINCON0_BPPMODE_2BPP; + data |= WINCONx_BITSWP; + data |= WINCONx_BURSTLEN_8WORD; + break; + case 4: + data |= WINCON0_BPPMODE_4BPP; + data |= WINCONx_BITSWP; + data |= WINCONx_BURSTLEN_8WORD; + break; + case 8: + if (transp_length != 0) + data |= WINCON1_BPPMODE_8BPP_1232; + else + data |= WINCON0_BPPMODE_8BPP_PALETTE; + data |= WINCONx_BURSTLEN_8WORD; + data |= WINCONx_BYTSWP; + break; + case 16: + if (transp_length != 0) + data |= WINCON1_BPPMODE_16BPP_A1555; + else + data |= WINCON0_BPPMODE_16BPP_565; + data |= WINCONx_HAWSWP; + data |= WINCONx_BURSTLEN_16WORD; + break; + case 24: + case 32: + if (red_length == 6) { + if (transp_length != 0) + data |= WINCON1_BPPMODE_19BPP_A1666; + else + data |= WINCON1_BPPMODE_18BPP_666; + } else if (transp_length == 1) + data |= WINCON1_BPPMODE_25BPP_A1888 + | WINCON1_BLD_PIX; + else if ((transp_length == 4) || + (transp_length == 8)) + data |= WINCON1_BPPMODE_28BPP_A4888 + | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; + else + data |= WINCON0_BPPMODE_24BPP_888; + + data |= WINCONx_WSWP; + data |= WINCONx_BURSTLEN_16WORD; + break; + } + + return data; +} + +void s3c_fb_update_regs(struct s3cfb_global *fbdev, struct s3c_reg_data *regs) { - ktime_t prev_timestamp; + struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev); + unsigned short i; + bool wait_for_vsync; + struct s3cfb_window *win; + +#if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) +#ifdef CONFIG_BUSFREQ_OPP + unsigned int new_num_of_win = 0; + unsigned int pre_num_of_win = 0; + unsigned int shadow_regs = 0; + unsigned int clkval = 0; + + for (i = 0; i < pdata->nr_wins; i++) + if (regs->shadowcon & SHADOWCON_CHx_ENABLE(i)) + new_num_of_win++; + shadow_regs = readl(fbdev->regs + S3C_WINSHMAP); + for (i = 0; i < pdata->nr_wins; i++) + if (shadow_regs & SHADOWCON_CHx_ENABLE(i)) + pre_num_of_win++; + + if (pre_num_of_win < new_num_of_win) { + switch(new_num_of_win) { + case 0: + case 1: + clkval = 100100; + break; + case 2: + clkval = 133133; + break; + case 3: + clkval = 133133; + break; + case 4: + clkval = 133133; + break; + case 5: + clkval = 133133; + break; + } + dev_lock(fbdev->bus_dev, fbdev->dev, clkval); + } +#endif +#endif + + for (i = 0; i < pdata->nr_wins; i++) + s3cfb_set_window_protect(fbdev, i, 1); + + for (i = 0; i < pdata->nr_wins; i++) { + win = fbdev->fb[i]->par; + writel(regs->wincon[i], fbdev->regs + S3C_WINCON(i)); + writel(regs->vidosd_a[i], fbdev->regs + S3C_VIDOSD_A(i)); + writel(regs->vidosd_b[i], fbdev->regs + S3C_VIDOSD_B(i)); + writel(regs->vidosd_c[i], fbdev->regs + S3C_VIDOSD_C(i)); + if (i == 1 || i == 2) + writel(regs->vidosd_d[i], fbdev->regs + S3C_VIDOSD_D(i)); + writel(regs->vidw_buf_start[i], + fbdev->regs + S3C_VIDADDR_START0(i)); + writel(regs->vidw_buf_end[i], + fbdev->regs + S3C_VIDADDR_END0(i)); + writel(regs->vidw_buf_size[i], + fbdev->regs + S3C_VIDADDR_SIZE(i)); + + win->enabled = !!(regs->wincon[i] & WINCONx_ENWIN); + } + + writel(regs->shadowcon, fbdev->regs + S3C_WINSHMAP); + + for (i = 0; i < pdata->nr_wins; i++) + s3cfb_set_window_protect(fbdev, i, 0); + + do { +#if defined(CONFIG_FB_S5P_VSYNC_THREAD) + s3cfb_wait_for_vsync(fbdev, 0); +#else + s3cfb_wait_for_vsync(fbdev); +#endif + wait_for_vsync = false; + + for (i = 0; i < pdata->nr_wins; i++) { + u32 new_start = regs->vidw_buf_start[i]; + u32 shadow_start = s3cfb_get_win_cur_buf_addr(fbdev, i); + if (unlikely(new_start != shadow_start)) { + wait_for_vsync = true; + break; + } + } + } while (wait_for_vsync); + + sw_sync_timeline_inc(fbdev->timeline, 1); + +#ifdef CONFIG_FB_S5P_SYSMMU + if ((fbdev->sysmmu.enabled == false) && + (fbdev->sysmmu.pgd)) { + fbdev->sysmmu.enabled = true; + s5p_sysmmu_enable(fbdev->dev, + (unsigned long)virt_to_phys((unsigned int*)fbdev->sysmmu.pgd)); + } +#endif + +#if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) +#ifdef CONFIG_BUSFREQ_OPP + if (pre_num_of_win > new_num_of_win) { + switch(new_num_of_win) { + case 0: + case 1: + clkval = 100100; + break; + case 2: + clkval = 133133; + break; + case 3: + clkval = 133133; + break; + case 4: + clkval = 133133; + break; + case 5: + clkval = 133133; + break; + } + dev_lock(fbdev->bus_dev, fbdev->dev, clkval); + } +#endif +#endif +} + +static int s3c_fb_set_win_buffer(struct s3cfb_global *fbdev, + struct fb_info *fb, struct s3c_fb_win_config *win_config, + struct s3c_reg_data *regs) +{ + struct s3cfb_window *win = fb->par; + struct fb_fix_screeninfo prev_fix = fb->fix; + struct fb_var_screeninfo prev_var = fb->var; + unsigned short win_no = win->id; int ret; + size_t window_size; + u32 alpha, size; - dev_dbg(fbdev->dev, "waiting for VSYNC interrupt\n"); + if (win_config->format >= S3C_FB_PIXEL_FORMAT_MAX) { + dev_err(fbdev->dev, "unknown pixel format %u\n", + win_config->format); + return -EINVAL; + } - prev_timestamp = fbdev->vsync_timestamp; + fb->var.red.length = s3c_fb_red_length(win_config->format); + fb->var.red.offset = s3c_fb_red_offset(win_config->format); + fb->var.green.length = s3c_fb_green_length(win_config->format); + fb->var.green.offset = s3c_fb_green_offset(win_config->format); + fb->var.blue.length = s3c_fb_blue_length(win_config->format); + fb->var.blue.offset = s3c_fb_blue_offset(win_config->format); + fb->var.transp.length = s3c_fb_transp_length(win_config->format); + fb->var.transp.offset = s3c_fb_transp_offset(win_config->format); + fb->var.bits_per_pixel = fb->var.red.length + + fb->var.green.length + + fb->var.blue.length + + fb->var.transp.length + + s3c_fb_padding(win_config->format); + + window_size = win_config->stride * win_config->h; + + if (win_config->phys_addr != 0) + fb->fix.smem_start = win_config->phys_addr + win_config->offset; + else + fb->fix.smem_start = win_config->virt_addr + win_config->offset; + fb->fix.smem_len = window_size; + fb->var.xres = win_config->w; + fb->var.xres_virtual = win_config->stride * 8 / + fb->var.bits_per_pixel; + fb->var.yres = fb->var.yres_virtual = win_config->h; + fb->var.xoffset = win_config->offset % win_config->stride; + fb->var.yoffset = win_config->offset / win_config->stride; + + fb->fix.visual = fb_visual(fb->var.bits_per_pixel, 256); + fb->fix.line_length = win_config->stride; + fb->fix.xpanstep = fb_panstep(win_config->w, + fb->var.xres_virtual); + fb->fix.ypanstep = fb_panstep(win_config->h, win_config->h); + +#ifdef CONFIG_FB_S5P_SYSMMU + if ((fbdev->sysmmu.enabled == false) && + (current->mm)) + fbdev->sysmmu.pgd = (unsigned int)current->mm->pgd; +#endif - ret = wait_event_interruptible_timeout(fbdev->wq, - s3cfb_vsync_timestamp_changed(fbdev, prev_timestamp), - msecs_to_jiffies(100)); +#ifdef CONFIG_FB_S5P_SYSMMU + if (win_config->phys_addr != 0) + regs->vidw_buf_start[win_no] = (u32)phys_to_virt(fb->fix.smem_start); + else +#endif + regs->vidw_buf_start[win_no] = fb->fix.smem_start; - if (ret == 0) - return -ETIMEDOUT; - if (ret < 0) - return ret; + regs->vidw_buf_end[win_no] = regs->vidw_buf_start[win_no] + + window_size; - dev_dbg(fbdev->dev, "got a VSYNC interrupt\n"); + regs->vidw_buf_size[win_no] = vidw_buf_size(win_config->w, + fb->fix.line_length, + fb->var.bits_per_pixel); + +#ifdef CONFIG_FB_S5P_SYSMMU + if ((fb->fix.smem_start) && + (fb->fix.smem_start != fbdev->sysmmu.default_fb_addr)) + s3cfb_clean_outer_pagetable(regs->vidw_buf_start[win_no], + regs->vidw_buf_end[win_no] - regs->vidw_buf_start[win_no]); +#endif + + + regs->vidosd_a[win_no] = vidosd_a(win_config->x, win_config->y); + regs->vidosd_b[win_no] = vidosd_b(win_config->x, win_config->y, + win_config->w, win_config->h, + fb->var.bits_per_pixel); + + alpha = VIDISD14C_ALPHA1_R(0xf) | + VIDISD14C_ALPHA1_G(0xf) | + VIDISD14C_ALPHA1_B(0xf); + regs->vidosd_c[win_no] = alpha; + + if (win_no <= 2) { + size = win_config->w * win_config->h; + regs->vidosd_d[win_no] = size; + } + + regs->shadowcon |= SHADOWCON_CHx_ENABLE(win_no); + + regs->wincon[win_no] = wincon(fb->var.bits_per_pixel, + fb->var.transp.length, + fb->var.red.length); + + return 0; +} + +static int s3c_fb_set_win_config(struct s3cfb_global *fbdev, + struct s3c_fb_win_config_data *win_data) +{ + struct fb_info *fb; + struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev); + struct s3c_fb_win_config *win_config = win_data->config; + int ret = 0; + unsigned short i; + struct s3c_reg_data *regs = kzalloc(sizeof(struct s3c_reg_data), + GFP_KERNEL); + struct sync_fence *fence; + struct sync_pt *pt; + int fd; + + if (!regs) { + dev_err(fbdev->dev, "could not allocate s3c_reg_data"); + return -ENOMEM; + } + + fd = get_unused_fd(); + + for (i = 0; i < pdata->nr_wins && !ret; i++) { + struct s3c_fb_win_config *config = &win_config[i]; + bool enabled = 0; + u32 color_map = WINxMAP_MAP | WINxMAP_MAP_COLOUR(0); + + fb = fbdev->fb[i]; + + switch (config->state) { + case S3C_FB_WIN_STATE_DISABLED: + break; + case S3C_FB_WIN_STATE_COLOR: + enabled = 1; + color_map |= WINxMAP_MAP_COLOUR(config->color); + break; + case S3C_FB_WIN_STATE_BUFFER: + ret = s3c_fb_set_win_buffer(fbdev, fb, config, regs); + if (!ret) { + enabled = 1; + color_map = 0; + } + break; + default: + dev_warn(fbdev->dev, "unrecognized window state %u", + config->state); + ret = -EINVAL; + break; + } + + if (enabled) + regs->wincon[i] |= WINCONx_ENWIN; + else + regs->wincon[i] &= ~WINCONx_ENWIN; + regs->winmap[i] = color_map; + } + + if (ret) { + put_unused_fd(fd); + kfree(regs); + } else { + mutex_lock(&fbdev->update_regs_list_lock); + fbdev->timeline_max++; + pt = sw_sync_pt_create(fbdev->timeline, fbdev->timeline_max); + fence = sync_fence_create("display", pt); + sync_fence_install(fence, fd); + win_data->fence = fd; + + list_add_tail(®s->list, &fbdev->update_regs_list); + mutex_unlock(&fbdev->update_regs_list_lock); + queue_kthread_work(&fbdev->update_regs_worker, &fbdev->update_regs_work); + } return ret; } @@ -1128,6 +1754,7 @@ int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg) struct s3cfb_user_window user_window; struct s3cfb_user_plane_alpha user_alpha; struct s3cfb_user_chroma user_chroma; + struct s3c_fb_win_config_data win_data; int vsync; unsigned int alpha_mode; } p; @@ -1149,23 +1776,31 @@ int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg) if (fbdev->regs == 0) return 0; #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) - /* Enable Vsync */ #ifdef CONFIG_CPU_EXYNOS4412 if (!fbdev->regs) return ret; #endif +#if !defined(CONFIG_FB_S5P_VSYNC_THREAD) + /* Enable Vsync */ s3cfb_set_global_interrupt(fbdev, 1); s3cfb_set_vsync_interrupt(fbdev, 1); #endif +#endif /* Wait for Vsync */ +#if defined(CONFIG_FB_S5P_VSYNC_THREAD) + s3cfb_wait_for_vsync(fbdev, HZ/10); +#else s3cfb_wait_for_vsync(fbdev); +#endif if (fbdev->regs == 0) return 0; #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) +#if !defined(CONFIG_FB_S5P_VSYNC_THREAD) /* Disable Vsync */ s3cfb_set_global_interrupt(fbdev, 0); s3cfb_set_vsync_interrupt(fbdev, 0); #endif +#endif break; case S3CFB_WIN_POSITION: @@ -1238,8 +1873,12 @@ int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg) if (!fbdev->regs) return ret; #endif +#if defined(CONFIG_FB_S5P_VSYNC_THREAD) + ret = s3cfb_set_vsync_int(fb, p.vsync); +#else s3cfb_set_global_interrupt(fbdev, p.vsync); s3cfb_set_vsync_interrupt(fbdev, p.vsync); +#endif } break; @@ -1293,7 +1932,30 @@ int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg) else s3cfb_set_alpha_mode(fbdev, win->id, p.alpha_mode); break; + +#if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) + case S3CFB_WIN_CONFIG: + if (copy_from_user(&p.win_data, + (struct s3c_fb_win_config_data __user *)arg, + sizeof(p.win_data))) { + ret = -EFAULT; + break; + } + + ret = s3c_fb_set_win_config(fbdev, &p.win_data); + if (ret) + break; + + if (copy_to_user((struct s3c_fb_win_config_data __user *)arg, + &p.win_data, + sizeof(p.win_data))) { + ret = -EFAULT; + break; + } + break; +#endif } + return ret; } |