summaryrefslogtreecommitdiff
path: root/drivers/video/mxsfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/mxsfb.c')
-rw-r--r--drivers/video/mxsfb.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index d4312467a55b..7f825fb42a9c 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"
@@ -203,12 +204,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)
@@ -373,6 +376,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);
}
@@ -573,6 +577,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);
@@ -580,6 +606,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);
@@ -594,6 +624,7 @@ static int mxsfb_set_par(struct fb_info *fb_info)
mxsfb_disable_controller(fb_info);
}
+
sema_init(&host->flip_sem, 1);
/* clear the FIFOs */
@@ -706,6 +737,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;
}
@@ -787,7 +824,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;
@@ -814,6 +860,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)
mxsfb_enable_controller(fb_info);
mxsfb_set_par(&host->fb_info);