diff options
author | Peter Gielda <pgielda@antmicro.com> | 2017-07-30 23:47:55 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2019-04-24 17:50:41 +0200 |
commit | 358111678438051309fead63f3f7ea5265cb5873 (patch) | |
tree | e65e5a6fec518566cc90e06074baf579ba498d28 /drivers | |
parent | 86abb55585528216b1b364fcccfc0e8ee39cd59d (diff) |
Modify the way vi2 handles frame grabbing.
(cherry picked from commit 0a8984655b5239833a3e6e0d54c7c867dbc7ea63)
This fixes the dual camera use case.
Acked-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/platform/soc_camera/tegra_camera/vi2.c | 174 |
1 files changed, 53 insertions, 121 deletions
diff --git a/drivers/media/platform/soc_camera/tegra_camera/vi2.c b/drivers/media/platform/soc_camera/tegra_camera/vi2.c index fb03bb7854b1..2c805a4724ce 100644 --- a/drivers/media/platform/soc_camera/tegra_camera/vi2.c +++ b/drivers/media/platform/soc_camera/tegra_camera/vi2.c @@ -133,6 +133,10 @@ #define TEGRA_VI_CSI_1_WD_CTRL 0x28c #define TEGRA_VI_CSI_1_WD_PERIOD 0x290 +#define CSI_PPx_ENABLE (0x1 << 0) +#define CSI_PPx_DISABLE (0x2 << 0) +#define CSI_PPx_SINGLE_SHOT (0x1 << 2) + #define TEGRA_CSI_CSI_CAP_CIL 0x808 #define TEGRA_CSI_CSI_CAP_CSI 0x818 #define TEGRA_CSI_CSI_CAP_PP 0x828 @@ -336,6 +340,8 @@ #define MIPI_CAL_BASE 0x700e3000 +static int vi2_capture_stop(struct tegra_camera_dev *cam, int port); + static const struct regmap_config mipi_cal_config = { .reg_bits = 32, .reg_stride = 4, @@ -708,9 +714,6 @@ 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) | im_width); - /* Start pixel parser in single shot mode at beginning */ - TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf005); - return 0; } @@ -822,9 +825,6 @@ 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) | im_width); - /* Start pixel parser in single shot mode at beginning */ - TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf005); - return 0; } @@ -999,6 +999,26 @@ static void vi2_capture_error_status(struct tegra_camera_dev *cam) pr_err("TEGRA_VI_CSI_1_ERROR_STATUS 0x%08x\n", val); } +char *get_port_name(int port) { + switch (port) { + case TEGRA_CAMERA_PORT_CSI_A: return "CSI_A"; + case TEGRA_CAMERA_PORT_CSI_B: return "CSI_B"; + case TEGRA_CAMERA_PORT_CSI_C: return "CSI_C"; + default: return "UNKNOWN PORT"; + } +} + +static void csi_pending(struct tegra_camera_dev *cam, int port, char *from) { + int timeout = 10000; + while (--timeout) { + if (!(TC_VI_REG_RD(cam, TEGRA_CSI_CSI_READONLY_STATUS) == ((port == TEGRA_CAMERA_PORT_CSI_A) ? 0x1 : 0x2))) break; + usleep_range(100,200); + } + if (!timeout) { + dev_err(&cam->ndev->dev, "%s csi_pending timeout from %s!", get_port_name(port), from); + } +} + static int vi2_capture_start(struct tegra_camera_dev *cam, struct tegra_camera_buffer *buf) { @@ -1014,28 +1034,31 @@ static int vi2_capture_start(struct tegra_camera_dev *cam, return err; 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); - - TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, - VI_CSI_PPA_FRAME_START | cam->syncpt_id_csi_a); + TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf000 | CSI_PPx_ENABLE | CSI_PPx_SINGLE_SHOT); // Start capturing one frame. + 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); + TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, VI_CSI_PPA_FRAME_START | cam->syncpt_id_csi_a); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SINGLE_SHOT, 0x1); - } 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); - - TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, - VI_CSI_PPB_FRAME_START | cam->syncpt_id_csi_b); + err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_a, cam->syncpt_csi_a, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); + } 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, 0xf000 | CSI_PPx_ENABLE | CSI_PPx_SINGLE_SHOT); // Start capturing one frame. + 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); + TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, 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, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); } + /* Mark SOF flag to Zero after we captured the FIRST frame */ + if (cam->sof[port-1]) + cam->sof[port-1] = 0; + if (err) { + dev_err(&cam->ndev->dev, "%s syncpt timeout, syncpt = %d, err = %d\n", get_port_name(port), + port == TEGRA_CAMERA_PORT_CSI_A ? cam->syncpt_csi_a : cam->syncpt_csi_b, err); + vi2_capture_error_status(cam); + } else { + csi_pending(cam, port, __func__); + vi2_capture_stop(cam, port); + } + csi_pending(cam, port, __func__); return err; } @@ -1046,106 +1069,13 @@ static int vi2_capture_wait(struct tegra_camera_dev *cam, struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int port = pdata->port; - int err = 0; - - /* Only wait on CSI frame end syncpt if we're using CSI. */ - if (port == TEGRA_CAMERA_PORT_CSI_A) { - err = nvhost_syncpt_wait_timeout_ext(cam->ndev, - cam->syncpt_id_csi_a, - cam->syncpt_csi_a, - TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, - NULL, - NULL); - } else if (port == TEGRA_CAMERA_PORT_CSI_B || - port == TEGRA_CAMERA_PORT_CSI_C) { - err = nvhost_syncpt_wait_timeout_ext(cam->ndev, - cam->syncpt_id_csi_b, - cam->syncpt_csi_b, - TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, - NULL, - NULL); - } - - /* Mark SOF flag to Zero after we captured the FIRST frame */ - if (cam->sof[port-1]) - cam->sof[port-1] = 0; - - /* Capture syncpt timeout err, then dump error status */ - if (err) { - if (port == TEGRA_CAMERA_PORT_CSI_A) - dev_err(&cam->ndev->dev, - "CSI_A syncpt timeout, syncpt = %d, err = %d\n", - cam->syncpt_csi_a, err); - else if (port == TEGRA_CAMERA_PORT_CSI_B || - port == TEGRA_CAMERA_PORT_CSI_C) - dev_err(&cam->ndev->dev, - "CSI_B/CSI_C syncpt timeout, syncpt = %d, err = %d\n", - cam->syncpt_csi_b, err); - vi2_capture_error_status(cam); - } - - return err; + csi_pending(cam, port, __func__); + return 0; } static int vi2_capture_done(struct tegra_camera_dev *cam, int port) { - u32 val; - int err = 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); - } 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); - } - - return err; + return 0; } static int vi2_capture_stop(struct tegra_camera_dev *cam, int port) @@ -1154,7 +1084,9 @@ static int vi2_capture_stop(struct tegra_camera_dev *cam, int port) TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND : TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND; - TC_VI_REG_WT(cam, reg, 0xf002); + TC_VI_REG_WT(cam, reg, 0xf000 | CSI_PPx_DISABLE); + + csi_pending(cam, port, __func__); return 0; } |