From d6bcba51931c73202c9b7962b0bd2439b135a8c9 Mon Sep 17 00:00:00 2001 From: Anubhav Rai Date: Tue, 30 Aug 2022 00:23:01 -0700 Subject: [PATCH] vi5: fix v4l2 VI driver channel open unmap chan_id from DT with capture channel id. Capture channel id is shared between isp capture and v4l2. Find a free capture channel that does not conflict with other clients bug 3691031 Change-Id: If3cd887db6feb2a1817a7451249185de47d6e9ad Signed-off-by: Anubhav Rai Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2768753 (cherry picked from commit cf54cc587eba0854236c634b8ec0c1c2c98a3a5d) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2866951 Reviewed-by: svcacv Reviewed-by: Ankur Pawar Reviewed-by: Laxman Dewangan Tested-by: Ankur Pawar GVS: Gerrit_Virtual_Submit --- .../media/platform/tegra/camera/vi/vi5_fops.c | 72 ++++++++++++++++--- include/media/mc_common.h | 3 +- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/tegra/camera/vi/vi5_fops.c b/drivers/media/platform/tegra/camera/vi/vi5_fops.c index 53b6ec2d..54b59992 100644 --- a/drivers/media/platform/tegra/camera/vi/vi5_fops.c +++ b/drivers/media/platform/tegra/camera/vi/vi5_fops.c @@ -2,12 +2,15 @@ /* * Tegra Video Input 5 device common APIs * - * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ +#include +#include #include #include #include +#include #include #include #include @@ -25,6 +28,9 @@ #define PG_BITRATE 32 #define SLVSEC_STREAM_MAIN 0U +#define VI_CHANNEL_DEV "/dev/capture-vi-channel" +#define VI_CHAN_PATH_MAX 40 + #define CAPTURE_TIMEOUT_MS 2500 static const struct vi_capture_setup default_setup = { @@ -213,6 +219,50 @@ static int vi5_add_ctrls(struct tegra_channel *chan) return 0; } +/* + * Find a free VI channel to open. Synchronize vi capture channel sharing + * with other clients. + */ +static int vi5_channel_open(struct tegra_channel *chan, u32 vi_port) +{ + bool found = false; + char chanFilePath[VI_CHAN_PATH_MAX]; + int channel = 0; + struct file *filp = NULL; + long err = 0; + + while (!found) { + sprintf(chanFilePath, "%s%u", VI_CHANNEL_DEV, channel); + + filp = filp_open(chanFilePath, O_RDONLY, 0); + + if (IS_ERR(filp)) { + err = PTR_ERR(filp); + /* Retry with the next available channel. Opening + * a channel number greater than the ones supported + * by the platform will trigger a ENODEV from the + * VI capture channel driver + */ + if (err == -EBUSY) + channel++; + else { + dev_err(&chan->video->dev, + "Error opening VI capture channel node %s with err: %ld\n", + chanFilePath, err); + return -ENODEV; + } + } else + found = true; + } + + err = 0; + chan->vi_channel_id[vi_port] = channel; + + chan->tegra_vi_channel[vi_port] = filp->private_data; + + return err; +} + static int vi5_channel_setup_queue(struct tegra_channel *chan, unsigned int *nbuffers) { @@ -534,7 +584,8 @@ static int vi5_channel_error_recover(struct tegra_channel *chan, dev_err(&chan->video->dev, "vi capture release failed\n"); goto done; } - vi_channel_close_ex(chan->id + vi_port, chan->tegra_vi_channel[vi_port]); + vi_channel_close_ex(chan->vi_channel_id[vi_port], + chan->tegra_vi_channel[vi_port]); chan->tegra_vi_channel[vi_port] = NULL; } @@ -573,7 +624,7 @@ static int vi5_channel_error_recover(struct tegra_channel *chan, /* restart vi channel */ for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) { - chan->tegra_vi_channel[vi_port] = vi_channel_open_ex(chan->id + vi_port, false); + err = vi5_channel_open(chan, vi_port); if (IS_ERR(chan->tegra_vi_channel[vi_port])) { err = PTR_ERR(chan); goto done; @@ -766,12 +817,11 @@ static int vi5_channel_start_streaming(struct vb2_queue *vq, u32 count) /* Skip in bypass mode */ if (!chan->bypass) { for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) { - chan->tegra_vi_channel[vi_port] = - vi_channel_open_ex(chan->id + vi_port, false); - if (IS_ERR(chan->tegra_vi_channel[vi_port])) { - ret = PTR_ERR(chan); + int err = vi5_channel_open(chan, vi_port); + + if (err) goto err_open_ex; - } + spin_lock_irqsave(&chan->capture_state_lock, flags); chan->capture_state = CAPTURE_IDLE; spin_unlock_irqrestore(&chan->capture_state_lock, flags); @@ -880,7 +930,8 @@ err_start_kthreads: err_setup: if (!chan->bypass) for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) { - vi_channel_close_ex(chan->id + vi_port, chan->tegra_vi_channel[vi_port]); + vi_channel_close_ex(chan->vi_channel_id[vi_port], + chan->tegra_vi_channel[vi_port]); chan->tegra_vi_channel[vi_port] = NULL; } @@ -911,7 +962,8 @@ static int vi5_channel_stop_streaming(struct vb2_queue *vq) dev_err(&chan->video->dev, "vi capture release failed\n"); - vi_channel_close_ex(chan->id + vi_port, chan->tegra_vi_channel[vi_port]); + vi_channel_close_ex(chan->vi_channel_id[vi_port], + chan->tegra_vi_channel[vi_port]); chan->tegra_vi_channel[vi_port] = NULL; } diff --git a/include/media/mc_common.h b/include/media/mc_common.h index c419adf5..deed6b25 100644 --- a/include/media/mc_common.h +++ b/include/media/mc_common.h @@ -2,7 +2,7 @@ /* * Tegra Media controller common APIs * - * Copyright (c) 2012-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ #ifndef __CAMERA_MC_COMMON_H__ @@ -157,6 +157,7 @@ struct tegra_channel { unsigned int num_video_formats; struct mutex stop_kthread_lock; + unsigned int vi_channel_id[TEGRA_CSI_BLOCKS]; unsigned char port[TEGRA_CSI_BLOCKS]; unsigned int virtual_channel; unsigned int syncpt[TEGRA_CSI_BLOCKS][MAX_SYNCPT_PER_CHANNEL];