aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/omapfb/omapfb-main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-main.c')
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c121
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);