video: tegra: dsi: Stop dc stream at the frame end
kevinh [Fri, 18 Mar 2011 07:12:40 +0000 (00:12 -0700)]
Fixed tegra_dsi_stop_dc_stream() to flush register immediately.
Added tegra_dsi_stop_dc_stream_at_frame_end().

Original-Change-Id: Ie4fe1f6d59e6bf0dab40251f33a0c2f8d816fdd8
Reviewed-on: http://git-master/r/23488
Reviewed-by: Kevin Huang <kevinh@nvidia.com>
Tested-by: Kevin Huang <kevinh@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Original-Change-Id: I398cb977146656936c5768c2bc3ec83f7bdc7c66

Rebase-Id: Rda5a11692992edd47c49e0f30446efc0a26e747e

drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_priv.h
drivers/video/tegra/dc/dsi.c

index 201c034..1099b87 100644 (file)
@@ -1181,6 +1181,9 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
        status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
        tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
 
+       if (status & V_BLANK_INT)
+               complete(&dc->v_blank_complete);
+
        if (status & FRAME_END_INT) {
                int completed = 0;
                int dirty = 0;
@@ -1640,6 +1643,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
                dc->enabled = true;
 
        mutex_init(&dc->lock);
+       init_completion(&dc->v_blank_complete);
        init_waitqueue_head(&dc->wq);
        INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
 
index 2042310..b01f569 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/wait.h>
+#include <linux/completion.h>
+
 #include "../host/dev.h"
 
 struct tegra_dc;
@@ -90,6 +92,8 @@ struct tegra_dc {
 
        unsigned long                   underflow_mask;
        struct work_struct              reset_work;
+
+       struct completion               v_blank_complete;
 };
 
 static inline void tegra_dc_io_start(struct tegra_dc *dc)
index ab99a70..c82e403 100755 (executable)
@@ -38,6 +38,7 @@
 
 #define DSI_USE_SYNC_POINTS 0
 
+#define DSI_STOP_DC_DURATION_MSEC 1000
 
 #define DSI_MODULE_NOT_INIT            0x0
 #define DSI_MODULE_INIT                        0x1
@@ -697,11 +698,39 @@ static void tegra_dsi_set_pkt_seq(struct tegra_dc *dc,
 static void tegra_dsi_stop_dc_stream(struct tegra_dc *dc,
                                                struct tegra_dc_dsi_data *dsi)
 {
-       /*
-        * TODO: It is possible that we are in the middle of video stream,
-        * Add code to wait for vsync and then stop DC from sending data to dsi
-        */
        tegra_dc_writel(dc, 0, DC_DISP_DISP_WIN_OPTIONS);
+       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+}
+
+void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc, struct tegra_dc_dsi_data *dsi)
+{
+       int val;
+       long timeout;
+
+       /* stop dc */
+       tegra_dsi_stop_dc_stream(dc, dsi);
+
+       /* enable vblank interrupt */
+       val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+       val |= V_BLANK_INT;
+       tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+
+       val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
+       val |= V_BLANK_INT;
+       tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
+
+       /* wait for vblank completion */
+       timeout = wait_for_completion_interruptible_timeout(
+               &dc->v_blank_complete, DSI_STOP_DC_DURATION_MSEC);
+
+       /* disable vblank interrupt */
+       val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+       val &= ~V_BLANK_INT;
+       tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+
+       if(timeout == 0)
+               printk("Warning: dc dosen't stop at the end of the frame.\n");
 }
 
 static void tegra_dsi_start_dc_stream(struct tegra_dc *dc,