summaryrefslogtreecommitdiff
path: root/drivers/video/mxsfb.c
diff options
context:
space:
mode:
authorguoyin.chen <guoyin.chen@freescale.com>2015-01-28 11:12:06 +0800
committerNitin Garg <nitin.garg@freescale.com>2015-09-17 09:23:58 -0500
commit9fac9f4afa4f0fb596d978c3700c47fd639561ce (patch)
treee011c840361c8c44ccf01e901c027594daf61f71 /drivers/video/mxsfb.c
parent0ad96ee1f850275749de442089c003efda124044 (diff)
MLK-10732-1 mxsfb: support FBIOPUT_VSCREENINFO update frame buffer
Enable mxsfb frame buffer update by FBIOPUT_VSCREENINFO ioctl. The patch cherry pick from android branch. MA-5963-4 Upgrade kernel version from 3.10.y to 3.14.y Backport imx_3.10_y_android's mxsfb driver to add vsync timestamp Signed-off-by: guoyin.chen <guoyin.chen@freescale.com> (cherry picked from commit 8f24453e0b081f16338916f75ce73dc896f93f8e)
Diffstat (limited to 'drivers/video/mxsfb.c')
-rw-r--r--drivers/video/mxsfb.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 012e523ceca4..72378cdf54f1 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -56,6 +56,7 @@
#include <linux/regulator/consumer.h>
#include <video/of_display_timing.h>
#include <video/videomode.h>
+#include <linux/uaccess.h>
#include "mxc/mxc_dispdrv.h"
@@ -215,12 +216,14 @@ struct mxsfb_info {
struct regulator *reg_lcd;
bool wait4vsync;
struct completion vsync_complete;
+ ktime_t vsync_nf_timestamp;
struct semaphore flip_sem;
int cur_blank;
int restore_blank;
char disp_dev[32];
struct mxc_dispdrv_handle *dispdrv;
int id;
+ struct fb_var_screeninfo var;
};
#define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
@@ -410,6 +413,7 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *dev_id)
writel(CTRL1_VSYNC_EDGE_IRQ_EN,
host->base + LCDC_CTRL1 + REG_CLR);
host->wait4vsync = 0;
+ host->vsync_nf_timestamp = ktime_get();
complete(&host->vsync_complete);
}
@@ -623,6 +627,28 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
}
}
+/**
+ This function compare the fb parameter see whether it was different
+ parameter for hardware, if it was different parameter, the hardware
+ will reinitialize. All will compared except x/y offset.
+ */
+static bool mxsfb_par_equal(struct fb_info *fbi, struct mxsfb_info *host)
+{
+ /* Here we set the xoffset, yoffset to zero, and compare two
+ * var see have different or not. */
+ struct fb_var_screeninfo oldvar = host->var;
+ struct fb_var_screeninfo newvar = fbi->var;
+
+ if ((fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW &&
+ fbi->var.activate & FB_ACTIVATE_FORCE)
+ return false;
+
+ oldvar.xoffset = newvar.xoffset = 0;
+ oldvar.yoffset = newvar.yoffset = 0;
+
+ return memcmp(&oldvar, &newvar, sizeof(struct fb_var_screeninfo)) == 0;
+}
+
static int mxsfb_set_par(struct fb_info *fb_info)
{
struct mxsfb_info *host = to_imxfb_host(fb_info);
@@ -630,6 +656,10 @@ static int mxsfb_set_par(struct fb_info *fb_info)
int line_size, fb_size;
int reenable = 0;
+ /* If parameter no change, don't reconfigure. */
+ if (mxsfb_par_equal(fb_info, host))
+ return 0;
+
clk_enable_axi(host);
clk_enable_disp_axi(host);
clk_enable_pix(host);
@@ -758,6 +788,12 @@ static int mxsfb_set_par(struct fb_info *fb_info)
if (reenable)
mxsfb_enable_controller(fb_info);
+ /* Clear activate as not Reconfiguring framebuffer again */
+ if ((fb_info->var.activate & FB_ACTIVATE_FORCE) &&
+ (fb_info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
+ fb_info->var.activate = FB_ACTIVATE_NOW;
+
+ host->var = fb_info->var;
return 0;
}
@@ -837,7 +873,16 @@ static int mxsfb_ioctl(struct fb_info *fb_info, unsigned int cmd,
switch (cmd) {
case MXCFB_WAIT_FOR_VSYNC:
- ret = mxsfb_wait_for_vsync(fb_info);
+ {
+ long long timestamp;
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ ret = mxsfb_wait_for_vsync(fb_info);
+ timestamp = ktime_to_ns(host->vsync_nf_timestamp);
+ if ((ret == 0) && copy_to_user((void *)arg,
+ &timestamp, sizeof(timestamp))) {
+ ret = -EFAULT;
+ }
+ }
break;
default:
break;
@@ -865,6 +910,8 @@ static int mxsfb_blank(int blank, struct fb_info *fb_info)
break;
case FB_BLANK_UNBLANK:
+ fb_info->var.activate = (fb_info->var.activate & ~FB_ACTIVATE_MASK) |
+ FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
if (!host->enabled) {
clk_enable_pix(host);
clk_enable_axi(host);