media: tegra_camera: optimize single shot mode
Bryan Wu [Thu, 28 May 2015 00:09:45 +0000 (17:09 -0700)]
Current single shot mode, pixel parser is disabled after capture one
frame and software waits for memory write ack done syncpoint, which
only gives us half the frame rate.

Optimized single shot mode:
 - during capture setup, set single shot mode
 - for each frame, wait for FRAME_START syncpoint
 - arm single shot bit to start capture
 - for the last frame, wait for MWA_DONE syncpoint to make sure capture
   finished.

With optimized single shot mode, frame rate is about 4208x3120 @ 24fps
for IMX135 and 1920x1080 @ 30fps for AR0261.

Bug 1639982

Change-Id: I0b15d02c2853647d03f5b2d38a7fe5c145174bd5
Signed-off-by: Bryan Wu <pengw@nvidia.com>
Reviewed-on: http://git-master/r/754709
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: David Wang (SW-TEGRA) <davidw@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>

drivers/media/platform/soc_camera/tegra_camera/common.c
drivers/media/platform/soc_camera/tegra_camera/common.h
drivers/media/platform/soc_camera/tegra_camera/vi2.c

index 370035f..d8b4ff1 100644 (file)
@@ -179,7 +179,6 @@ static void tegra_camera_deactivate(struct tegra_camera_dev *cam)
 {
        struct tegra_camera_ops *cam_ops = cam->ops;
 
-
        if (cam_ops->clks_disable)
                cam_ops->clks_disable(cam);
 
@@ -227,8 +226,6 @@ static int tegra_camera_capture_frame(struct tegra_camera_dev *cam)
 
        while (retry) {
                err = cam->ops->capture_start(cam, buf);
-               /* Capturing succeed, stop capturing */
-               cam->ops->capture_stop(cam, port);
                if (err) {
                        retry--;
 
@@ -533,27 +530,12 @@ static int tegra_camera_stop_streaming(struct vb2_queue *q)
                                                     vb2_vidq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct tegra_camera_dev *cam = ici->priv;
-       struct list_head *buf_head, *tmp;
-
+       struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+       struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+       int port = pdata->port;
 
        mutex_lock(&cam->work_mutex);
-
-       spin_lock_irq(&cam->videobuf_queue_lock);
-       list_for_each_safe(buf_head, tmp, &cam->capture) {
-               struct tegra_camera_buffer *buf = container_of(buf_head,
-                               struct tegra_camera_buffer,
-                               queue);
-               if (buf->icd == icd)
-                       list_del_init(buf_head);
-       }
-       spin_unlock_irq(&cam->videobuf_queue_lock);
-
-       if (cam->active) {
-               struct tegra_camera_buffer *buf = to_tegra_vb(cam->active);
-               if (buf->icd == icd)
-                       cam->active = NULL;
-       }
-
+       cam->ops->capture_stop(cam, port);
        mutex_unlock(&cam->work_mutex);
 
        return 0;
index d4ffe41..18da08c 100644 (file)
@@ -122,7 +122,6 @@ struct tegra_camera_dev {
        int                             tpg_mode;
 
        int                             sof;
-
        int                             cal_done;
 };
 
index a6c3143..6a75e8e 100644 (file)
 #define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT                   200
 
 #define TEGRA_VI_CFG_VI_INCR_SYNCPT                    0x000
+#define                VI_MWA_REQ_DONE                         (4 << 8)
+#define                VI_MWB_REQ_DONE                         (5 << 8)
+#define                VI_MWA_ACK_DONE                         (6 << 8)
+#define                VI_MWB_ACK_DONE                         (7 << 8)
+#define                VI_ISPA_DONE                            (8 << 8)
+#define                VI_CSI_PPA_FRAME_START                  (9 << 8)
+#define                VI_CSI_PPB_FRAME_START                  (10 << 8)
+#define                VI_CSI_PPA_LINE_START                   (11 << 8)
+#define                VI_CSI_PPB_LINE_START                   (12 << 8)
+
 #define TEGRA_VI_CFG_VI_INCR_SYNCPT_CNTRL              0x004
 #define TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR              0x008
 #define TEGRA_VI_CFG_CTXSW                             0x020
@@ -663,6 +673,9 @@ static int vi2_capture_setup_csi_0(struct tegra_camera_dev *cam,
        TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_SIZE,
                        (icd->user_height << 16) | icd->user_width);
 
+       /* Start pixel parser in single shot mode at beginning */
+       TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf005);
+
        return 0;
 }
 
@@ -766,6 +779,9 @@ static int vi2_capture_setup_csi_1(struct tegra_camera_dev *cam,
        TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_SIZE,
                        (icd->user_height << 16) | icd->user_width);
 
+       /* Start pixel parser in single shot mode at beginning */
+       TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf005);
+
        return 0;
 }
 
@@ -954,10 +970,9 @@ static int vi2_capture_start(struct tegra_camera_dev *cam,
                                                cam->syncpt_id_csi_a, 1);
 
                TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT,
-                               (6 << 8) | cam->syncpt_id_csi_a);
-               TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
-                               0x0000f005);
+                            VI_CSI_PPA_FRAME_START | cam->syncpt_id_csi_a);
                TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SINGLE_SHOT, 0x1);
+
                err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
                                cam->syncpt_id_csi_a,
                                cam->syncpt_csi_a,
@@ -973,10 +988,9 @@ static int vi2_capture_start(struct tegra_camera_dev *cam,
                                                cam->syncpt_id_csi_b, 1);
 
                TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT,
-                               (7 << 8) | cam->syncpt_id_csi_b);
-               TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
-                               0x0000f005);
+                            VI_CSI_PPB_FRAME_START | cam->syncpt_id_csi_b);
                TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SINGLE_SHOT, 0x1);
+
                err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
                                cam->syncpt_id_csi_b,
                                cam->syncpt_csi_b,
@@ -1008,15 +1022,65 @@ static int vi2_capture_start(struct tegra_camera_dev *cam,
 
 static int vi2_capture_stop(struct tegra_camera_dev *cam, int port)
 {
-       if (port == TEGRA_CAMERA_PORT_CSI_A)
-               TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
-                            0x0000f002);
-       else if (port == TEGRA_CAMERA_PORT_CSI_B ||
-                       port == TEGRA_CAMERA_PORT_CSI_C)
-               TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
-                            0x0000f002);
+       u32 val;
+       int err = 0;
 
-       return 0;
+       if (port == TEGRA_CAMERA_PORT_CSI_A) {
+               if (!nvhost_syncpt_read_ext_check(cam->ndev,
+                                                 cam->syncpt_id_csi_a, &val))
+                       cam->syncpt_csi_a = nvhost_syncpt_incr_max_ext(
+                                               cam->ndev,
+                                               cam->syncpt_id_csi_a, 1);
+
+               /*
+                * Make sure recieve VI_MWA_ACK_DONE of the last frame before
+                * stop and dequeue buffer, otherwise MC error will shows up
+                * for the last frame.
+                */
+               TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT,
+                            VI_MWA_ACK_DONE | cam->syncpt_id_csi_a);
+
+               /*
+                * Ignore error here and just stop pixel parser after waiting,
+                * even if it's timeout
+                */
+               err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+                               cam->syncpt_id_csi_a,
+                               cam->syncpt_csi_a,
+                               TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+                               NULL,
+                               NULL);
+               TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf002);
+       } else if (port == TEGRA_CAMERA_PORT_CSI_B ||
+                       port == TEGRA_CAMERA_PORT_CSI_C) {
+               if (!nvhost_syncpt_read_ext_check(cam->ndev,
+                                                 cam->syncpt_id_csi_b, &val))
+                       cam->syncpt_csi_b = nvhost_syncpt_incr_max_ext(
+                                               cam->ndev,
+                                               cam->syncpt_id_csi_b, 1);
+
+               /*
+                * Make sure recieve VI_MWB_ACK_DONE of the last frame before
+                * stop and dequeue buffer, otherwise MC error will shows up
+                * for the last frame.
+                */
+               TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT,
+                            VI_MWB_ACK_DONE | cam->syncpt_id_csi_b);
+
+               /*
+                * Ignore error here and just stop pixel parser after waiting,
+                * even if it's timeout
+                */
+               err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+                               cam->syncpt_id_csi_b,
+                               cam->syncpt_csi_b,
+                               TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+                               NULL,
+                               NULL);
+               TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf002);
+       }
+
+       return err;
 }
 
 /* Reset VI2/CSI2 when activating, no sepecial ops for deactiving  */