summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/dc/dc.c')
-rw-r--r--drivers/video/tegra/dc/dc.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index a3011b873aae..80d052a61e12 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -873,6 +873,36 @@ static inline void enable_dc_irq(unsigned int irq)
#endif
}
+void tegra_dc_get_fbvblank(struct tegra_dc *dc, struct fb_vblank *vblank)
+{
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ vblank->flags = FB_VBLANK_HAVE_VSYNC;
+}
+
+int tegra_dc_wait_for_vsync(struct tegra_dc *dc)
+{
+ int ret = -ENOTTY;
+
+ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) || !dc->enabled)
+ return ret;
+
+ /*
+ * Logic is as follows
+ * a) Indicate we need a vblank.
+ * b) Wait for completion to be signalled from isr.
+ * c) Initialize completion for next iteration.
+ */
+
+ tegra_dc_hold_dc_out(dc);
+ dc->out->user_needs_vblank = true;
+
+ ret = wait_for_completion_interruptible(&dc->out->user_vblank_comp);
+ init_completion(&dc->out->user_vblank_comp);
+ tegra_dc_release_dc_out(dc);
+
+ return ret;
+}
+
static void tegra_dc_vblank(struct work_struct *work)
{
struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work);
@@ -1023,6 +1053,13 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
{
+ /* pending user vblank, so wakeup */
+ if ((status & (V_BLANK_INT | MSF_INT)) &&
+ (dc->out->user_needs_vblank)) {
+ dc->out->user_needs_vblank = false;
+ complete(&dc->out->user_vblank_comp);
+ }
+
if (status & V_BLANK_INT) {
/* Sync up windows. */
tegra_dc_trigger_windows(dc);
@@ -1232,6 +1269,7 @@ static u32 get_syncpt(struct tegra_dc *dc, int idx)
static int tegra_dc_init(struct tegra_dc *dc)
{
int i;
+ int int_enable;
tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
if (dc->ndev->id == 0) {
@@ -1267,8 +1305,12 @@ static int tegra_dc_init(struct tegra_dc *dc)
tegra_dc_writel(dc, 0x00000000, DC_DISP_DISP_MISC_CONTROL);
#endif
/* enable interrupts for vblank, frame_end and underflows */
- tegra_dc_writel(dc, (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT),
- DC_CMD_INT_ENABLE);
+ int_enable = (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
+ /* for panels with one-shot mode enable tearing effect interrupt */
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ int_enable |= MSF_INT;
+
+ tegra_dc_writel(dc, int_enable, DC_CMD_INT_ENABLE);
tegra_dc_writel(dc, ALL_UF_INT, DC_CMD_INT_MASK);
tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);