diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-main.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 121 |
1 files changed, 106 insertions, 15 deletions
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); |