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