diff options
Diffstat (limited to 'drivers/video/omap2/omapfb')
-rw-r--r-- | drivers/video/omap2/omapfb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 31 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 121 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb.h | 7 |
4 files changed, 136 insertions, 24 deletions
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index aa33386..d15486e 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -7,6 +7,7 @@ menuconfig FB_OMAP2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select FB_MODE_HELPERS help Frame buffer driver for OMAP2+ based boards. diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index cff4503..8188e92 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -883,6 +883,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_GET_DISPLAY_INFO: { u16 xres, yres; + u32 w, h; DBG("ioctl GET_DISPLAY_INFO\n"); @@ -896,15 +897,9 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) p.display_info.xres = xres; p.display_info.yres = yres; - if (display->driver->get_dimensions) { - u32 w, h; - display->driver->get_dimensions(display, &w, &h); - p.display_info.width = w; - p.display_info.height = h; - } else { - p.display_info.width = 0; - p.display_info.height = 0; - } + omapdss_display_get_dimensions(display, &w, &h); + p.display_info.width = w; + p.display_info.height = h; if (copy_to_user((void __user *)arg, &p.display_info, sizeof(p.display_info))) @@ -912,6 +907,24 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } + case OMAPFB_ENABLEVSYNC: + if (get_user(p.crt, (__u32 __user *)arg)) { + r = -EFAULT; + break; + } + + omapfb_lock(fbdev); + fbdev->vsync_active = !!p.crt; + + if (display->state == OMAP_DSS_DISPLAY_ACTIVE) { + if (p.crt) + omapfb_enable_vsync(fbdev); + else + omapfb_disable_vsync(fbdev); + } + omapfb_unlock(fbdev); + break; + default: dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); r = -EINVAL; diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 505bc12..319c2ac 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -29,6 +29,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/omapfb.h> +#include <linux/wait.h> #include <video/omapdss.h> #include <plat/vram.h> @@ -303,7 +304,7 @@ static void assign_colormode_to_var(struct fb_var_screeninfo *var, var->transp = color->transp; } -static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var, +int omapfb_mode_to_dss_mode(struct fb_var_screeninfo *var, enum omap_color_mode *mode) { enum omap_color_mode dssmode; @@ -358,7 +359,7 @@ static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var, dssmode = OMAP_DSS_COLOR_RGB24P; break; case 32: - dssmode = OMAP_DSS_COLOR_RGB24U; + dssmode = OMAP_DSS_COLOR_ARGB32; break; default: return -EINVAL; @@ -375,6 +376,7 @@ static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var, return -EINVAL; } +EXPORT_SYMBOL(omapfb_mode_to_dss_mode); static int check_fb_res_bounds(struct fb_var_screeninfo *var) { @@ -512,7 +514,7 @@ static int setup_vrfb_rotation(struct fb_info *fbi) DBG("setup_vrfb_rotation\n"); - r = fb_mode_to_dss_mode(var, &mode); + r = omapfb_mode_to_dss_mode(var, &mode); if (r) return r; @@ -622,8 +624,9 @@ void set_fb_fix(struct fb_info *fbi) fix->smem_len = var->yres_virtual * fix->line_length; } else { - fix->line_length = - (var->xres_virtual * var->bits_per_pixel) >> 3; + /* SGX requires stride to be a multiple of 32 pixels */ + int xres_align = ALIGN(var->xres_virtual, 32); + fix->line_length = (xres_align * var->bits_per_pixel) >> 3; fix->smem_len = rg->size; } @@ -665,12 +668,13 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) enum omap_color_mode mode = 0; int i; int r; + u32 w = 0, h = 0; DBG("check_fb_var %d\n", ofbi->id); WARN_ON(!atomic_read(&ofbi->region->lock_count)); - r = fb_mode_to_dss_mode(var, &mode); + r = omapfb_mode_to_dss_mode(var, &mode); if (r) { DBG("cannot convert var to omap dss mode\n"); return r; @@ -702,9 +706,10 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) var->xres, var->yres, var->xres_virtual, var->yres_virtual); - if (display && display->driver->get_dimensions) { - u32 w, h; - display->driver->get_dimensions(display, &w, &h); + if (display) + omapdss_display_get_dimensions(display, &w, &h); + + if (w && h) { var->width = DIV_ROUND_CLOSEST(w, 1000); var->height = DIV_ROUND_CLOSEST(h, 1000); } else { @@ -757,6 +762,11 @@ static int omapfb_open(struct fb_info *fbi, int user) static int omapfb_release(struct fb_info *fbi, int user) { + struct omapfb_info *ofbi = FB2OFB(fbi); + struct omapfb2_device *fbdev = ofbi->fbdev; + + omapfb_disable_vsync(fbdev); + return 0; } @@ -879,9 +889,9 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p, &data_start_v); - r = fb_mode_to_dss_mode(var, &mode); + r = omapfb_mode_to_dss_mode(var, &mode); if (r) { - DBG("fb_mode_to_dss_mode failed"); + DBG("omapfb_mode_to_dss_mode failed"); goto err; } @@ -1018,6 +1028,41 @@ static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) return r; } +void omapfb_fb2dss_timings(struct fb_videomode *fb_timings, + struct omap_video_timings *dss_timings) +{ + dss_timings->x_res = fb_timings->xres; + dss_timings->y_res = fb_timings->yres; + if (fb_timings->vmode & FB_VMODE_INTERLACED) + dss_timings->y_res /= 2; + dss_timings->pixel_clock = fb_timings->pixclock ? + PICOS2KHZ(fb_timings->pixclock) : 0; + dss_timings->hfp = fb_timings->right_margin; + dss_timings->hbp = fb_timings->left_margin; + dss_timings->hsw = fb_timings->hsync_len; + dss_timings->vfp = fb_timings->lower_margin; + dss_timings->vbp = fb_timings->upper_margin; + dss_timings->vsw = fb_timings->vsync_len; +} +EXPORT_SYMBOL(omapfb_fb2dss_timings); + +void omapfb_dss2fb_timings(struct omap_video_timings *dss_timings, + struct fb_videomode *fb_timings) +{ + memset(fb_timings, 0, sizeof(*fb_timings)); + fb_timings->xres = dss_timings->x_res; + fb_timings->yres = dss_timings->y_res; + fb_timings->pixclock = dss_timings->pixel_clock ? + KHZ2PICOS(dss_timings->pixel_clock) : 0; + fb_timings->right_margin = dss_timings->hfp; + fb_timings->left_margin = dss_timings->hbp; + fb_timings->hsync_len = dss_timings->hsw; + fb_timings->lower_margin = dss_timings->vfp; + fb_timings->upper_margin = dss_timings->vbp; + fb_timings->vsync_len = dss_timings->vsw; +} +EXPORT_SYMBOL(omapfb_dss2fb_timings); + /* set the video mode according to info->var */ static int omapfb_set_par(struct fb_info *fbi) { @@ -1251,11 +1296,16 @@ static int omapfb_blank(int blank, struct fb_info *fbi) switch (blank) { case FB_BLANK_UNBLANK: - if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) - goto exit; + if (display->state == OMAP_DSS_DISPLAY_SUSPENDED) { + if (display->driver->resume) + r = display->driver->resume(display); + } else if (display->state == OMAP_DSS_DISPLAY_DISABLED) { + if (display->driver->enable) + r = display->driver->enable(display); + } - if (display->driver->resume) - r = display->driver->resume(display); + if (fbdev->vsync_active) + omapfb_enable_vsync(fbdev); break; @@ -1265,11 +1315,17 @@ static int omapfb_blank(int blank, struct fb_info *fbi) case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: + + if (fbdev->vsync_active) + omapfb_disable_vsync(fbdev); + if (display->state != OMAP_DSS_DISPLAY_ACTIVE) goto exit; if (display->driver->suspend) r = display->driver->suspend(display); + else if (display->driver->disable) + display->driver->disable(display); break; @@ -2233,6 +2289,39 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, return 0; } +static void omapfb_send_vsync_work(struct work_struct *work) +{ + struct omapfb2_device *fbdev = + container_of(work, typeof(*fbdev), vsync_work); + char buf[64]; + char *envp[2]; + + snprintf(buf, sizeof(buf), "VSYNC=%llu", + ktime_to_ns(fbdev->vsync_timestamp)); + envp[0] = buf; + envp[1] = NULL; + kobject_uevent_env(&fbdev->dev->kobj, KOBJ_CHANGE, envp); +} +static void omapfb_vsync_isr(void *data, u32 mask) +{ + struct omapfb2_device *fbdev = data; + fbdev->vsync_timestamp = ktime_get(); + schedule_work(&fbdev->vsync_work); +} + +int omapfb_enable_vsync(struct omapfb2_device *fbdev) +{ + int r; + /* TODO: should determine correct IRQ like dss_mgr_wait_for_vsync does*/ + r = omap_dispc_register_isr(omapfb_vsync_isr, fbdev, DISPC_IRQ_VSYNC); + return r; +} + +void omapfb_disable_vsync(struct omapfb2_device *fbdev) +{ + omap_dispc_unregister_isr(omapfb_vsync_isr, fbdev, DISPC_IRQ_VSYNC); +} + static int omapfb_probe(struct platform_device *pdev) { struct omapfb2_device *fbdev = NULL; @@ -2348,6 +2437,7 @@ static int omapfb_probe(struct platform_device *pdev) goto cleanup; } + INIT_WORK(&fbdev->vsync_work, omapfb_send_vsync_work); return 0; cleanup: @@ -2362,6 +2452,7 @@ static int omapfb_remove(struct platform_device *pdev) struct omapfb2_device *fbdev = platform_get_drvdata(pdev); /* FIXME: wait till completion of pending events */ + /* TODO: terminate vsync thread */ omapfb_remove_sysfs(fbdev); diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index aa1b1d9..649388f 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -97,6 +97,10 @@ struct omapfb2_device { struct omap_dss_device *dssdev; u8 bpp; } bpp_overrides[10]; + + bool vsync_active; + ktime_t vsync_timestamp; + struct work_struct vsync_work; }; struct omapfb_colormode { @@ -128,6 +132,9 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode, int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, u16 posx, u16 posy, u16 outw, u16 outh); +int omapfb_enable_vsync(struct omapfb2_device *fbdev); +void omapfb_disable_vsync(struct omapfb2_device *fbdev); + /* find the display connected to this fb, if any */ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) { |