LCOV - code coverage report
Current view: top level - ipu4 - ipu6-isys-video.c (source / functions) Coverage Total Hit
Test: ipu4.info Lines: 64.0 % 555 355
Test Date: 2026-05-12 04:57:36 Functions: 78.0 % 41 32

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-only
       2              : /*
       3              :  * Copyright (C) 2013--2024 Intel Corporation
       4              :  */
       5              : 
       6              : #include <linux/align.h>
       7              : #include <linux/bits.h>
       8              : #include <linux/bug.h>
       9              : #include <linux/completion.h>
      10              : #include <linux/container_of.h>
      11              : #include <linux/delay.h>
      12              : #include <linux/device.h>
      13              : #include <linux/list.h>
      14              : #include <linux/math64.h>
      15              : #include <linux/minmax.h>
      16              : #include <linux/module.h>
      17              : #include <linux/mutex.h>
      18              : #include <linux/pm_runtime.h>
      19              : #include <linux/spinlock.h>
      20              : #include <linux/string.h>
      21              : 
      22              : #include <media/media-entity.h>
      23              : #include <media/v4l2-ctrls.h>
      24              : #include <media/v4l2-dev.h>
      25              : #include <media/v4l2-fh.h>
      26              : #include <media/v4l2-ioctl.h>
      27              : #include <media/v4l2-subdev.h>
      28              : #include <media/videobuf2-v4l2.h>
      29              : 
      30              : #include "ipu6.h"
      31              : #include "ipu6-bus.h"
      32              : #include "ipu6-cpd.h"
      33              : #include "ipu6-fw-isys.h"
      34              : #include "ipu6-isys.h"
      35              : #include "ipu6-isys-csi2.h"
      36              : #include "ipu6-isys-queue.h"
      37              : #include "ipu6-isys-video.h"
      38              : #include "ipu4-compat.h"
      39              : 
      40              : bool force_need_reset;
      41              : module_param(force_need_reset, bool, 0644);
      42              : MODULE_PARM_DESC(force_need_reset, "emulate 'isys power cycle required' on next video_open");
      43              : 
      44              : bool silent_reset_enable = true;
      45              : module_param(silent_reset_enable, bool, 0644);
      46              : MODULE_PARM_DESC(silent_reset_enable, "perform a silent reset of existing streams when 'isys power cycle required' would otherwise be logged");
      47              : 
      48              : const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = {
      49              :         { V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
      50              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      51              :         { V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
      52              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      53              :         { V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
      54              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      55              :         { V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
      56              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      57              :         { V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
      58              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      59              :         { V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
      60              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      61              :         { V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
      62              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      63              :         { V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
      64              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      65              :         { V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8,
      66              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
      67              :         { V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8,
      68              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
      69              :         { V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8,
      70              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
      71              :         { V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8,
      72              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
      73              :         { V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
      74              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
      75              :         { V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
      76              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
      77              :         { V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
      78              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
      79              :         { V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
      80              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
      81              :         { V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
      82              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
      83              :         { V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
      84              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
      85              :         { V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
      86              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
      87              :         { V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
      88              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
      89              : 
      90              :         { V4L2_PIX_FMT_GREY, 8, 8, MEDIA_BUS_FMT_Y8_1X8,
      91              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
      92              :         { V4L2_PIX_FMT_Y10, 16, 10, MEDIA_BUS_FMT_Y10_1X10,
      93              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      94              :         { V4L2_PIX_FMT_Y12, 16, 12, MEDIA_BUS_FMT_Y12_1X12,
      95              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      96              :         { V4L2_PIX_FMT_Y16, 16, 16, MEDIA_BUS_FMT_Y16_1X16,
      97              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
      98              :         { V4L2_PIX_FMT_Y10P, 10, 10, MEDIA_BUS_FMT_Y10_1X10,
      99              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
     100              :         { V4L2_PIX_FMT_Y12P, 12, 12, MEDIA_BUS_FMT_Y12_1X12,
     101              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
     102              : 
     103              :         { V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16,
     104              :           IPU6_FW_ISYS_FRAME_FORMAT_UYVY},
     105              :         { V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16,
     106              :           IPU6_FW_ISYS_FRAME_FORMAT_YUYV},
     107              :         { V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16,
     108              :           IPU6_FW_ISYS_FRAME_FORMAT_RGB565 },
     109              :         { V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
     110              :           IPU6_FW_ISYS_FRAME_FORMAT_RGBA888 },
     111              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     112              :         { V4L2_META_FMT_GENERIC_8, 8, 8, MEDIA_BUS_FMT_META_8,
     113              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW8, true },
     114              :         { V4L2_META_FMT_GENERIC_CSI2_10, 10, 10, MEDIA_BUS_FMT_META_10,
     115              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW10, true },
     116              :         { V4L2_META_FMT_GENERIC_CSI2_12, 12, 12, MEDIA_BUS_FMT_META_12,
     117              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW12, true },
     118              :         { V4L2_META_FMT_GENERIC_CSI2_16, 16, 16, MEDIA_BUS_FMT_META_16,
     119              :           IPU6_FW_ISYS_FRAME_FORMAT_RAW16, true },
     120              : #endif
     121              :         { V4L2_PIX_FMT_XBGR32, 32, 24, MEDIA_BUS_FMT_RGB888_1X24,
     122              :          IPU6_FW_ISYS_FRAME_FORMAT_RGBA888},
     123              : };
     124              : 
     125            3 : static void wait_for_not_resetting(struct ipu6_isys *isys, const char *context)
     126              : {
     127            3 :         struct device *dev = &isys->adev->auxdev.dev;
     128              : 
     129            3 :         while (isys->resetting) {
     130            0 :                 mutex_unlock(&isys->mutex);
     131            0 :                 dev_info(dev, "%s: Waiting for isys resetting\n", context);
     132            0 :                 msleep_interruptible(100);
     133            0 :                 mutex_lock(&isys->mutex);
     134              :         }
     135            3 : }
     136              : 
     137            1 : static int video_open(struct file *file)
     138              : {
     139              :         struct ipu6_isys_video *av = video_drvdata(file);
     140            1 :         struct ipu6_isys *isys = av->isys;
     141            1 :         struct ipu6_bus_device *adev = isys->adev;
     142            1 :         struct device *dev = &adev->auxdev.dev;
     143              :         int ret = 0;
     144              : 
     145            1 :         mutex_lock(&isys->mutex);
     146            1 :         wait_for_not_resetting(isys, __func__);
     147              : 
     148            1 :         if (isys->need_reset || force_need_reset) {
     149            0 :                 if (silent_reset_enable) {
     150            0 :                         isys->resetting = true;
     151            0 :                         mutex_unlock(&isys->mutex);
     152              : 
     153            0 :                         dev_warn(dev, "restarting other streams (need_reset=%d, force_need_reset=%d)\n",
     154              :                                  isys->need_reset,
     155              :                                  force_need_reset);
     156            0 :                         force_need_reset = false;
     157            0 :                         ret = ipu6_isys_queue_restart_streams(av);
     158              : 
     159            0 :                         mutex_lock(&isys->mutex);
     160            0 :                         isys->resetting = false;
     161            0 :                         if (ret)
     162            0 :                                 dev_err(dev, "ipu6_isys_queue_restart_streams failed: %d\n",
     163              :                                         ret);
     164              :                 }
     165              : 
     166            0 :                 if (ret || !silent_reset_enable) {
     167              :                         // Keeping original log message below,
     168              :                         // since it is widely known
     169            0 :                         dev_warn(dev, "isys power cycle required\n");
     170            0 :                         mutex_unlock(&isys->mutex);
     171            0 :                         return -EIO;
     172              :                 }
     173            0 :                 dev_info(dev, "restarting other streams done: %d\n", ret);
     174              :         }
     175            1 :         mutex_unlock(&isys->mutex);
     176              : 
     177            1 :         ret = ipu6_buttress_authenticate(adev->isp);
     178            1 :         if (ret) {
     179            0 :                 dev_err(dev, "%s: FW authentication failed: %d\n",
     180              :                         __func__,
     181              :                         ret);
     182            0 :                 return ret;
     183              :         }
     184              : 
     185            1 :         ret = v4l2_fh_open(file);
     186            1 :         if (ret)
     187            0 :                 dev_err(dev, "%s: v4l2_fh_open failed: %d\n", __func__, ret);
     188              : 
     189              :         return ret;
     190              : }
     191              : 
     192              : const struct ipu6_isys_pixelformat *
     193           65 : ipu6_isys_get_isys_format(u32 pixelformat, u32 type)
     194              : {
     195              :         const struct ipu6_isys_pixelformat *default_pfmt = NULL;
     196              :         unsigned int i;
     197              : 
     198         2412 :         for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
     199         2350 :                 const struct ipu6_isys_pixelformat *pfmt = &ipu6_isys_pfmts[i];
     200              : 
     201         2260 :                 if (type && ((!pfmt->is_meta &&
     202         1239 :                               type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
     203          248 :                              (pfmt->is_meta &&
     204              :                               type != V4L2_BUF_TYPE_META_CAPTURE)))
     205         1085 :                         continue;
     206              : 
     207         1265 :                 if (!default_pfmt)
     208              :                         default_pfmt = pfmt;
     209              : 
     210         1265 :                 if (pfmt->pixelformat != pixelformat)
     211         1172 :                         continue;
     212              : 
     213              :                 return pfmt;
     214              :         }
     215              : 
     216              :         return default_pfmt;
     217              : }
     218              : EXPORT_SYMBOL_NS_GPL(ipu6_isys_get_isys_format, INTEL_IPU6);
     219              : 
     220            1 : static int ipu6_isys_vidioc_querycap(struct file *file, void *fh,
     221              :                                      struct v4l2_capability *cap)
     222              : {
     223              :         struct ipu6_isys_video *av = video_drvdata(file);
     224              : 
     225            1 :         strscpy(cap->driver, IPU6_ISYS_NAME, sizeof(cap->driver));
     226            1 :         strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card));
     227              : 
     228            1 :         return 0;
     229              : }
     230              : 
     231            0 : static int ipu6_isys_vidioc_enum_fmt(struct file *file, void *fh,
     232              :                                      struct v4l2_fmtdesc *f)
     233              : {
     234              :         unsigned int i, num_found;
     235              : 
     236            0 :         for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
     237            0 :                 if ((ipu6_isys_pfmts[i].is_meta &&
     238            0 :                      f->type != V4L2_BUF_TYPE_META_CAPTURE) ||
     239            0 :                     (!ipu6_isys_pfmts[i].is_meta &&
     240            0 :                      f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
     241            0 :                         continue;
     242              : 
     243            0 :                 if (f->mbus_code && f->mbus_code != ipu6_isys_pfmts[i].code)
     244            0 :                         continue;
     245              : 
     246            0 :                 if (num_found < f->index) {
     247            0 :                         num_found++;
     248            0 :                         continue;
     249              :                 }
     250              : 
     251            0 :                 f->flags = 0;
     252            0 :                 f->pixelformat = ipu6_isys_pfmts[i].pixelformat;
     253              : 
     254            0 :                 return 0;
     255              :         }
     256              : 
     257              :         return -EINVAL;
     258              : }
     259              : 
     260            0 : static int ipu6_isys_vidioc_enum_framesizes(struct file *file, void *fh,
     261              :                                             struct v4l2_frmsizeenum *fsize)
     262              : {
     263              :         unsigned int i;
     264              : 
     265            0 :         if (fsize->index > 0)
     266              :                 return -EINVAL;
     267              : 
     268            0 :         for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
     269            0 :                 if (fsize->pixel_format != ipu6_isys_pfmts[i].pixelformat)
     270              :                         continue;
     271              : 
     272            0 :                 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
     273            0 :                 fsize->stepwise.min_width = IPU6_ISYS_MIN_WIDTH;
     274            0 :                 fsize->stepwise.max_width = IPU6_ISYS_MAX_WIDTH;
     275            0 :                 fsize->stepwise.min_height = IPU6_ISYS_MIN_HEIGHT;
     276            0 :                 fsize->stepwise.max_height = IPU6_ISYS_MAX_HEIGHT;
     277            0 :                 fsize->stepwise.step_width = 2;
     278            0 :                 fsize->stepwise.step_height = 2;
     279              : 
     280            0 :                 return 0;
     281              :         }
     282              : 
     283              :         return -EINVAL;
     284              : }
     285              : 
     286            0 : static int ipu6_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
     287              :                                       struct v4l2_format *f)
     288              : {
     289              :         struct ipu6_isys_video *av = video_drvdata(file);
     290              : 
     291            0 :         f->fmt.pix = av->pix_fmt;
     292              : 
     293            0 :         return 0;
     294              : }
     295              : 
     296              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     297            0 : static int ipu6_isys_vidioc_g_fmt_meta_cap(struct file *file, void *fh,
     298              :                                            struct v4l2_format *f)
     299              : {
     300              :         struct ipu6_isys_video *av = video_drvdata(file);
     301              : 
     302            0 :         f->fmt.meta = av->meta_fmt;
     303              : 
     304            0 :         return 0;
     305              : }
     306              : #endif
     307              : 
     308           63 : static void ipu6_isys_try_fmt_cap(struct ipu6_isys_video *av, u32 type,
     309              :                                   u32 *format, u32 *width, u32 *height,
     310              :                                   u32 *bytesperline, u32 *sizeimage)
     311              : {
     312              :         const struct ipu6_isys_pixelformat *pfmt =
     313           63 :                 ipu6_isys_get_isys_format(*format, type);
     314              : 
     315           63 :         *format = pfmt->pixelformat;
     316           63 :         *width = clamp(*width, IPU6_ISYS_MIN_WIDTH, IPU6_ISYS_MAX_WIDTH);
     317           63 :         *height = clamp(*height, IPU6_ISYS_MIN_HEIGHT, IPU6_ISYS_MAX_HEIGHT);
     318              : 
     319           63 :         if (pfmt->bpp != pfmt->bpp_packed)
     320           31 :                 *bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
     321              :         else
     322           32 :                 *bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
     323              : 
     324           63 :         *bytesperline = ALIGN(*bytesperline, 64);
     325              : 
     326              :         /*
     327              :          * (height + 1) * bytesperline due to a hardware issue: the DMA unit
     328              :          * is a power of two, and a line should be transferred as few units
     329              :          * as possible. The result is that up to line length more data than
     330              :          * the image size may be transferred to memory after the image.
     331              :          * Another limitation is the GDA allocation unit size. For low
     332              :          * resolution it gives a bigger number. Use larger one to avoid
     333              :          * memory corruption.
     334              :          */
     335           63 :         *sizeimage = *bytesperline * *height +
     336           63 :                 max(*bytesperline,
     337              :                     av->isys->pdata->ipdata->isys_dma_overshoot);
     338           63 : }
     339              : 
     340           32 : static void __ipu6_isys_vidioc_try_fmt_vid_cap(struct ipu6_isys_video *av,
     341              :                                                struct v4l2_format *f)
     342              : {
     343           32 :         ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
     344           32 :                               &f->fmt.pix.width, &f->fmt.pix.height,
     345           32 :                               &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
     346              : 
     347           32 :         f->fmt.pix.field = V4L2_FIELD_NONE;
     348           32 :         f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
     349           32 :         f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
     350           32 :         f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
     351           32 :         f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
     352           32 : }
     353              : 
     354            1 : static int ipu6_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
     355              :                                             struct v4l2_format *f)
     356              : {
     357              :         struct ipu6_isys_video *av = video_drvdata(file);
     358              : 
     359            1 :         if (vb2_is_busy(&av->aq.vbq))
     360              :                 return -EBUSY;
     361              : 
     362            1 :         __ipu6_isys_vidioc_try_fmt_vid_cap(av, f);
     363              : 
     364            1 :         return 0;
     365              : }
     366              : 
     367              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     368           31 : static int __ipu6_isys_vidioc_try_fmt_meta_cap(struct ipu6_isys_video *av,
     369              :                                                struct v4l2_format *f)
     370              : {
     371           31 :         ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.meta.dataformat,
     372           31 :                               &f->fmt.meta.width, &f->fmt.meta.height,
     373           31 :                               &f->fmt.meta.bytesperline,
     374           31 :                               &f->fmt.meta.buffersize);
     375              : 
     376           31 :         return 0;
     377              : }
     378              : 
     379            0 : static int ipu6_isys_vidioc_try_fmt_meta_cap(struct file *file, void *fh,
     380              :                                              struct v4l2_format *f)
     381              : {
     382              :         struct ipu6_isys_video *av = video_drvdata(file);
     383              : 
     384            0 :         __ipu6_isys_vidioc_try_fmt_meta_cap(av, f);
     385              : 
     386            0 :         return 0;
     387              : }
     388              : #endif
     389              : 
     390            1 : static int ipu6_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
     391              :                                       struct v4l2_format *f)
     392              : {
     393              :         struct ipu6_isys_video *av = video_drvdata(file);
     394              : 
     395            1 :         ipu6_isys_vidioc_try_fmt_vid_cap(file, fh, f);
     396            1 :         av->pix_fmt = f->fmt.pix;
     397              : 
     398            1 :         return 0;
     399              : }
     400              : 
     401              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
     402            0 : static int ipu6_isys_vidioc_s_fmt_meta_cap(struct file *file, void *fh,
     403              :                                            struct v4l2_format *f)
     404              : {
     405              :         struct ipu6_isys_video *av = video_drvdata(file);
     406              : 
     407            0 :         if (vb2_is_busy(&av->aq.vbq))
     408              :                 return -EBUSY;
     409              : 
     410            0 :         ipu6_isys_vidioc_try_fmt_meta_cap(file, fh, f);
     411            0 :         av->meta_fmt = f->fmt.meta;
     412              : 
     413            0 :         return 0;
     414              : }
     415              : #endif
     416              : 
     417            1 : static int ipu6_isys_vidioc_reqbufs(struct file *file, void *priv,
     418              :                                     struct v4l2_requestbuffers *p)
     419              : {
     420              :         struct ipu6_isys_video *av = video_drvdata(file);
     421              :         int ret;
     422              : 
     423            1 :         av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
     424            1 :         av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
     425              : 
     426            1 :         ret = vb2_queue_change_type(&av->aq.vbq, p->type);
     427            1 :         if (ret)
     428              :                 return ret;
     429              : 
     430            1 :         return vb2_ioctl_reqbufs(file, priv, p);
     431              : }
     432              : 
     433            0 : static int ipu6_isys_vidioc_create_bufs(struct file *file, void *priv,
     434              :                                         struct v4l2_create_buffers *p)
     435              : {
     436              :         struct ipu6_isys_video *av = video_drvdata(file);
     437              :         int ret;
     438              : 
     439            0 :         av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
     440            0 :         av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
     441              : 
     442            0 :         ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
     443            0 :         if (ret)
     444              :                 return ret;
     445              : 
     446            0 :         return vb2_ioctl_create_bufs(file, priv, p);
     447              : }
     448              : 
     449            1 : static int link_validate(struct media_link *link)
     450              : {
     451              :         struct ipu6_isys_video *av =
     452            1 :                 container_of(link->sink, struct ipu6_isys_video, pad);
     453            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
     454              :         struct v4l2_subdev_state *s_state;
     455              :         struct v4l2_subdev *s_sd;
     456              :         struct v4l2_mbus_framefmt *s_fmt;
     457              :         struct media_pad *s_pad;
     458              :         u32 s_stream, code;
     459              :         int ret = -EPIPE;
     460              : 
     461            1 :         if (!link->source->entity)
     462              :                 return ret;
     463              : 
     464              :         s_sd = media_entity_to_v4l2_subdev(link->source->entity);
     465              :         s_state = v4l2_subdev_get_unlocked_active_state(s_sd);
     466            1 :         if (!s_state)
     467              :                 return ret;
     468              : 
     469            1 :         dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n",
     470              :                 link->source->entity->name, link->source->index,
     471              :                 link->sink->entity->name);
     472              : 
     473            1 :         s_pad = media_pad_remote_pad_first(&av->pad);
     474            1 :         s_stream = ipu6_isys_get_src_stream_by_src_pad(s_sd, s_pad->index);
     475              : 
     476              :         v4l2_subdev_lock_state(s_state);
     477              : 
     478            1 :         s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream);
     479            1 :         if (!s_fmt) {
     480            0 :                 dev_err(dev, "failed to get source pad format\n");
     481            0 :                 goto unlock;
     482              :         }
     483              : 
     484            1 :         code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
     485              : 
     486            2 :         if (s_fmt->width != ipu6_isys_get_frame_width(av) ||
     487            2 :             s_fmt->height != ipu6_isys_get_frame_height(av) ||
     488            1 :             s_fmt->code != code) {
     489            0 :                 dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
     490              :                         s_fmt->width, s_fmt->height, s_fmt->code,
     491              :                         ipu6_isys_get_frame_width(av),
     492              :                         ipu6_isys_get_frame_height(av), code);
     493            0 :                 goto unlock;
     494              :         }
     495              : 
     496              :         v4l2_subdev_unlock_state(s_state);
     497              : 
     498            1 :         return 0;
     499            0 : unlock:
     500              :         v4l2_subdev_unlock_state(s_state);
     501              : 
     502            0 :         return ret;
     503              : }
     504              : 
     505            1 : static void get_stream_opened(struct ipu6_isys_video *av)
     506              : {
     507              :         unsigned long flags;
     508              : 
     509            1 :         spin_lock_irqsave(&av->isys->streams_lock, flags);
     510            1 :         av->isys->stream_opened++;
     511            1 :         spin_unlock_irqrestore(&av->isys->streams_lock, flags);
     512            1 : }
     513              : 
     514            1 : static void put_stream_opened(struct ipu6_isys_video *av)
     515              : {
     516              :         unsigned long flags;
     517              : 
     518            1 :         spin_lock_irqsave(&av->isys->streams_lock, flags);
     519            1 :         av->isys->stream_opened--;
     520            1 :         spin_unlock_irqrestore(&av->isys->streams_lock, flags);
     521            1 : }
     522              : 
     523            1 : static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
     524              :                                 struct ipu4_fw_isys_stream_cfg_data_abi *cfg)
     525              : {
     526            1 :         struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
     527            1 :         struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
     528              :         struct ipu4_fw_isys_input_pin_info_abi *input_pin;
     529              :         struct ipu4_fw_isys_output_pin_info_abi *output_pin;
     530            1 :         struct ipu6_isys_stream *stream = av->stream;
     531            1 :         struct ipu6_isys_queue *aq = &av->aq;
     532            1 :         struct v4l2_mbus_framefmt fmt;
     533              :         const struct ipu6_isys_pixelformat *pfmt =
     534              :                 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
     535            1 :         struct v4l2_rect v4l2_crop;
     536            1 :         struct ipu6_isys *isys = av->isys;
     537            1 :         struct device *dev = &isys->adev->auxdev.dev;
     538            1 :         int input_pins = cfg->nof_input_pins++;
     539              :         int output_pins;
     540              :         u32 src_stream;
     541              :         int ret;
     542              : 
     543            1 :         src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
     544            1 :         ret = ipu6_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
     545              :                                            &fmt);
     546            1 :         if (ret < 0) {
     547            0 :                 dev_err(dev, "can't get stream format (%d)\n", ret);
     548            0 :                 return ret;
     549              :         }
     550              : 
     551            1 :         ret = ipu6_isys_get_stream_pad_crop(sd, src_pad->index, src_stream,
     552              :                                             &v4l2_crop);
     553            1 :         if (ret < 0) {
     554            0 :                 dev_err(dev, "can't get stream crop (%d)\n", ret);
     555            0 :                 return ret;
     556              :         }
     557              : 
     558              :         input_pin = &cfg->input_pins[input_pins];
     559            1 :         input_pin->input_res.width = fmt.width;
     560            1 :         input_pin->input_res.height = fmt.height;
     561            1 :         input_pin->dt = av->dt;
     562            1 :         input_pin->bits_per_pix = pfmt->bpp_packed;
     563            1 :         input_pin->mapped_dt = 0x40; /* invalid mipi data type */
     564              : #ifdef IPU6 // Disabled for IPU4
     565              :         input_pin->mipi_decompression = 0;
     566              :         input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
     567              : #endif
     568            1 :         input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
     569            1 :                 IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
     570              :                 IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
     571              : #ifdef IPU6 // Disabled for IPU4
     572              :         input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
     573              : #endif
     574            1 :         output_pins = cfg->nof_output_pins++;
     575            1 :         aq->fw_output = output_pins;
     576            1 :         stream->output_pins_queue[output_pins] = aq;
     577              : 
     578              :         output_pin = &cfg->output_pins[output_pins];
     579            1 :         output_pin->input_pin_id = input_pins;
     580            1 :         output_pin->output_res.width = ipu6_isys_get_frame_width(av);
     581            1 :         output_pin->output_res.height = ipu6_isys_get_frame_height(av);
     582              : 
     583            1 :         output_pin->stride = ipu6_isys_get_bytes_per_line(av);
     584            1 :         if (pfmt->bpp != pfmt->bpp_packed)
     585            0 :                 output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
     586              :         else
     587            1 :                 output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
     588            1 :         output_pin->ft = pfmt->css_pixelformat;
     589            1 :         output_pin->send_irq = 1;
     590              : #ifdef IPU6 // Disabled for IPU4
     591              :         memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
     592              :         output_pin->s2m_pixel_soc_pixel_remapping =
     593              :                 S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
     594              :         output_pin->csi_be_soc_pixel_remapping =
     595              :                 CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
     596              : 
     597              :         output_pin->snoopable = true;
     598              :         output_pin->error_handling_enable = false;
     599              :         output_pin->sensor_type = isys->sensor_type++;
     600              :         if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
     601              :                 isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
     602              : #endif
     603              :         /* Though payload_buf_size was added for compression, set sane value for
     604              :          * payload_buf_size, just in case...
     605              :          */
     606            1 :         output_pin->payload_buf_size = output_pin->stride *
     607              :                                        output_pin->output_res.height;
     608              : 
     609            1 :         return 0;
     610              : }
     611              : 
     612            1 : static int start_stream_firmware(struct ipu6_isys_video *av,
     613              :                                  struct ipu6_isys_buffer_list *bl)
     614              : {
     615              :         struct ipu4_fw_isys_stream_cfg_data_abi *stream_cfg;
     616              :         struct ipu4_fw_isys_frame_buff_set_abi *buf = NULL;
     617            1 :         struct ipu6_isys_stream *stream = av->stream;
     618            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
     619              :         struct isys_fw_msgs *msg = NULL;
     620              :         struct ipu6_isys_queue *aq;
     621              :         int ret, retout, tout;
     622              :         u16 send_type;
     623              : 
     624            1 :         msg = ipu6_get_fw_msg_buf(stream);
     625            1 :         if (!msg)
     626              :                 return -ENOMEM;
     627              : 
     628            1 :         stream_cfg = &msg->fw_msg.stream;
     629            1 :         stream_cfg->src = stream->stream_source;
     630            1 :         stream_cfg->vc = stream->vc;
     631            1 :         stream_cfg->isl_use = 0;
     632              : #ifdef IPU6 // Disabled for IPU4
     633              :         stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
     634              : #endif
     635              : 
     636            2 :         list_for_each_entry(aq, &stream->queues, node) {
     637              :                 struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
     638              : 
     639            1 :                 ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
     640            1 :                 if (ret < 0) {
     641            0 :                         ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
     642            0 :                         return ret;
     643              :                 }
     644              :         }
     645              : 
     646            1 :         ipu4_fw_isys_dump_stream_cfg(dev, stream_cfg);
     647              : 
     648            1 :         stream->nr_output_pins = stream_cfg->nof_output_pins;
     649              : 
     650              :         reinit_completion(&stream->stream_open_completion);
     651              : 
     652            1 :         ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
     653              :                                        stream_cfg, msg->dma_addr,
     654              :                                        sizeof(*stream_cfg),
     655              :                                        IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
     656            1 :         if (ret < 0) {
     657            0 :                 dev_err(dev, "can't open stream (%d)\n", ret);
     658            0 :                 ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
     659            0 :                 return ret;
     660              :         }
     661              : 
     662            1 :         get_stream_opened(av);
     663              : 
     664            1 :         tout = wait_for_completion_timeout(&stream->stream_open_completion,
     665              :                                            IPU6_FW_CALL_TIMEOUT_JIFFIES);
     666              : 
     667            1 :         ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
     668              : 
     669            1 :         if (!tout) {
     670            0 :                 dev_err(dev, "stream open time out\n");
     671              :                 ret = -ETIMEDOUT;
     672            0 :                 goto out_put_stream_opened;
     673              :         }
     674            1 :         if (stream->error) {
     675            0 :                 dev_err(dev, "stream open error: %d\n", stream->error);
     676              :                 ret = -EIO;
     677            0 :                 goto out_put_stream_opened;
     678              :         }
     679            1 :         dev_dbg(dev, "start stream: open complete\n");
     680              : 
     681            1 :         if (bl) {
     682            1 :                 msg = ipu6_get_fw_msg_buf(stream);
     683            1 :                 if (!msg) {
     684              :                         ret = -ENOMEM;
     685            0 :                         goto out_put_stream_opened;
     686              :                 }
     687            1 :                 buf = &msg->fw_msg.frame;
     688            1 :                 ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
     689            1 :                 ipu6_isys_buffer_list_queue(bl,
     690              :                                             IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
     691              :         }
     692              : 
     693              :         reinit_completion(&stream->stream_start_completion);
     694              : 
     695            1 :         if (bl) {
     696              :                 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
     697            1 :                 ipu4_fw_isys_dump_frame_buff_set(dev, buf,
     698            1 :                                                  stream_cfg->nof_output_pins);
     699            1 :                 ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
     700              :                                                buf, msg->dma_addr,
     701              :                                                sizeof(*buf), send_type);
     702              :         } else {
     703              :                 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
     704            0 :                 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
     705              :                                               send_type);
     706              :         }
     707              : 
     708            1 :         if (ret < 0) {
     709            0 :                 dev_err(dev, "can't start streaming (%d)\n", ret);
     710            0 :                 goto out_stream_close;
     711              :         }
     712              : 
     713            1 :         tout = wait_for_completion_timeout(&stream->stream_start_completion,
     714              :                                            IPU6_FW_CALL_TIMEOUT_JIFFIES);
     715            1 :         if (!tout) {
     716            0 :                 dev_err(dev, "stream start time out\n");
     717              :                 ret = -ETIMEDOUT;
     718            0 :                 goto out_stream_close;
     719              :         }
     720            1 :         if (stream->error) {
     721            0 :                 dev_err(dev, "stream start error: %d\n", stream->error);
     722              :                 ret = -EIO;
     723            0 :                 goto out_stream_close;
     724              :         }
     725            1 :         dev_dbg(dev, "start stream: complete\n");
     726              : 
     727              :         return 0;
     728              : 
     729            0 : out_stream_close:
     730              :         reinit_completion(&stream->stream_close_completion);
     731              : 
     732            0 :         retout = ipu6_fw_isys_simple_cmd(av->isys,
     733            0 :                                          stream->stream_handle,
     734              :                                          IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
     735            0 :         if (retout < 0) {
     736            0 :                 dev_dbg(dev, "can't close stream (%d)\n", retout);
     737            0 :                 goto out_put_stream_opened;
     738              :         }
     739              : 
     740            0 :         tout = wait_for_completion_timeout(&stream->stream_close_completion,
     741              :                                            IPU6_FW_CALL_TIMEOUT_JIFFIES);
     742            0 :         if (!tout)
     743            0 :                 dev_err(dev, "stream close time out\n");
     744            0 :         else if (stream->error)
     745            0 :                 dev_err(dev, "stream close error: %d\n", stream->error);
     746              :         else
     747            0 :                 dev_dbg(dev, "stream close complete\n");
     748              : 
     749            0 : out_put_stream_opened:
     750            0 :         put_stream_opened(av);
     751              : 
     752            0 :         return ret;
     753              : }
     754              : 
     755            1 : static void stop_streaming_firmware(struct ipu6_isys_video *av)
     756              : {
     757            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
     758            1 :         struct ipu6_isys_stream *stream = av->stream;
     759              :         int ret, tout;
     760              : 
     761              :         reinit_completion(&stream->stream_stop_completion);
     762              : 
     763            1 :         ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
     764              :                                       IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
     765              : 
     766            1 :         if (ret < 0) {
     767            0 :                 dev_err(dev, "can't stop stream (%d)\n", ret);
     768            0 :                 return;
     769              :         }
     770              : 
     771            1 :         tout = wait_for_completion_timeout(&stream->stream_stop_completion,
     772              :                                            IPU6_FW_CALL_TIMEOUT_JIFFIES);
     773            1 :         if (!tout)
     774            0 :                 dev_warn(dev, "stream stop time out\n");
     775            1 :         else if (stream->error)
     776            0 :                 dev_warn(dev, "stream stop error: %d\n", stream->error);
     777              :         else
     778            1 :                 dev_dbg(dev, "stop stream: complete\n");
     779              : }
     780              : 
     781            1 : static void close_streaming_firmware(struct ipu6_isys_video *av)
     782              : {
     783            1 :         struct ipu6_isys_stream *stream = av->stream;
     784            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
     785              :         int ret, tout;
     786              : 
     787              :         reinit_completion(&stream->stream_close_completion);
     788              : 
     789            1 :         ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
     790              :                                       IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
     791            1 :         if (ret < 0) {
     792            0 :                 dev_err(dev, "can't close stream (%d)\n", ret);
     793            0 :                 return;
     794              :         }
     795              : 
     796            1 :         tout = wait_for_completion_timeout(&stream->stream_close_completion,
     797              :                                            IPU6_FW_CALL_TIMEOUT_JIFFIES);
     798            1 :         if (!tout)
     799            0 :                 dev_warn(dev, "stream close time out\n");
     800            1 :         else if (stream->error)
     801            0 :                 dev_warn(dev, "stream close error: %d\n", stream->error);
     802              :         else
     803            1 :                 dev_dbg(dev, "close stream: complete\n");
     804              : 
     805            1 :         put_stream_opened(av);
     806              : }
     807              : 
     808            1 : int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
     809              :                                    struct media_entity *source_entity,
     810              :                                    int nr_queues)
     811              : {
     812            1 :         struct ipu6_isys_stream *stream = av->stream;
     813              :         struct ipu6_isys_csi2 *csi2;
     814              : 
     815            1 :         if (WARN_ON(stream->nr_streaming))
     816            0 :                 return -EINVAL;
     817              : 
     818            1 :         stream->nr_queues = nr_queues;
     819              :         atomic_set(&stream->sequence, 0);
     820              : 
     821            1 :         stream->seq_index = 0;
     822            1 :         memset(stream->seq, 0, sizeof(stream->seq));
     823              : 
     824            1 :         if (WARN_ON(!list_empty(&stream->queues)))
     825              :                 return -EINVAL;
     826              : 
     827            1 :         stream->stream_source = stream->asd->source;
     828              :         csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
     829            1 :         csi2->receiver_errors = 0;
     830            1 :         stream->source_entity = source_entity;
     831              : 
     832            1 :         dev_dbg(&av->isys->adev->auxdev.dev,
     833              :                 "prepare stream: external entity %s\n",
     834              :                 stream->source_entity->name);
     835              : 
     836              :         return 0;
     837              : }
     838              : 
     839              : #ifdef IPU6 // Disabled for IPU4
     840              : void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
     841              :                                           bool state)
     842              : {
     843              :         struct ipu6_isys *isys = av->isys;
     844              :         struct ipu6_isys_csi2 *csi2 = NULL;
     845              :         struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
     846              :         struct device *dev = &isys->adev->auxdev.dev;
     847              :         struct v4l2_mbus_framefmt format;
     848              :         struct v4l2_subdev *esd;
     849              :         struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 };
     850              :         unsigned int bpp, lanes;
     851              :         s64 link_freq = 0;
     852              :         u64 pixel_rate = 0;
     853              :         int ret;
     854              : 
     855              :         if (!state)
     856              :                 return;
     857              : 
     858              :         esd = media_entity_to_v4l2_subdev(av->stream->source_entity);
     859              : 
     860              :         av->watermark.width = ipu6_isys_get_frame_width(av);
     861              :         av->watermark.height = ipu6_isys_get_frame_height(av);
     862              :         av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift;
     863              :         av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size;
     864              : 
     865              :         ret = v4l2_g_ctrl(esd->ctrl_handler, &hb);
     866              :         if (!ret && hb.value >= 0)
     867              :                 av->watermark.hblank = hb.value;
     868              :         else
     869              :                 av->watermark.hblank = 0;
     870              : 
     871              :         csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd);
     872              :         link_freq = ipu6_isys_csi2_get_link_freq(csi2);
     873              :         if (link_freq > 0) {
     874              :                 lanes = csi2->nlanes;
     875              :                 ret = ipu6_isys_get_stream_pad_fmt(&csi2->asd.sd, 0,
     876              :                                                    av->source_stream, &format);
     877              :                 if (!ret) {
     878              :                         bpp = ipu6_isys_mbus_code_to_bpp(format.code);
     879              :                         pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
     880              :                 }
     881              :         }
     882              : 
     883              :         av->watermark.pixel_rate = pixel_rate;
     884              : 
     885              :         if (!pixel_rate) {
     886              :                 mutex_lock(&iwake_watermark->mutex);
     887              :                 iwake_watermark->force_iwake_disable = true;
     888              :                 mutex_unlock(&iwake_watermark->mutex);
     889              :                 dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n",
     890              :                          av->stream->source_entity->name);
     891              :         }
     892              : }
     893              : 
     894              : static void calculate_stream_datarate(struct ipu6_isys_video *av)
     895              : {
     896              :         struct video_stream_watermark *watermark = &av->watermark;
     897              :         const struct ipu6_isys_pixelformat *pfmt =
     898              :                 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
     899              :         u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line;
     900              :         u64 line_time_ns, stream_data_rate;
     901              :         u16 shift, size;
     902              : 
     903              :         shift = watermark->sram_gran_shift;
     904              :         size = watermark->sram_gran_size;
     905              : 
     906              :         pixels_per_line = watermark->width + watermark->hblank;
     907              :         line_time_ns =  div_u64(pixels_per_line * NSEC_PER_SEC,
     908              :                                 watermark->pixel_rate);
     909              :         bytes_per_line = watermark->width * pfmt->bpp / 8;
     910              :         pages_per_line = DIV_ROUND_UP(bytes_per_line, size);
     911              :         pb_bytes_per_line = pages_per_line << shift;
     912              :         stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns);
     913              : 
     914              :         watermark->stream_data_rate = stream_data_rate;
     915              : }
     916              : 
     917              : void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
     918              : {
     919              :         struct isys_iwake_watermark *iwake_watermark =
     920              :                 &av->isys->iwake_watermark;
     921              : 
     922              :         if (!av->watermark.pixel_rate)
     923              :                 return;
     924              : 
     925              :         if (state) {
     926              :                 calculate_stream_datarate(av);
     927              :                 mutex_lock(&iwake_watermark->mutex);
     928              :                 list_add(&av->watermark.stream_node,
     929              :                          &iwake_watermark->video_list);
     930              :                 mutex_unlock(&iwake_watermark->mutex);
     931              :         } else {
     932              :                 av->watermark.stream_data_rate = 0;
     933              :                 mutex_lock(&iwake_watermark->mutex);
     934              :                 list_del(&av->watermark.stream_node);
     935              :                 mutex_unlock(&iwake_watermark->mutex);
     936              :         }
     937              : 
     938              :         update_watermark_setting(av->isys);
     939              : }
     940              : #endif
     941              : 
     942            9 : void ipu6_isys_put_stream(struct ipu6_isys_stream *stream)
     943              : {
     944              :         struct device *dev;
     945              :         unsigned int i;
     946              :         unsigned long flags;
     947              : 
     948            9 :         if (!stream) {
     949            0 :                 pr_err("ipu6-isys: no available stream\n");
     950            0 :                 return;
     951              :         }
     952              : 
     953            9 :         dev = &stream->isys->adev->auxdev.dev;
     954              : 
     955            9 :         spin_lock_irqsave(&stream->isys->streams_lock, flags);
     956            9 :         for (i = 0; i < IPU4_ISYS_MAX_STREAMS; i++) {
     957            9 :                 if (&stream->isys->streams[i] == stream) {
     958            9 :                         if (stream->isys->streams_ref_count[i] > 0)
     959            9 :                                 stream->isys->streams_ref_count[i]--;
     960              :                         else
     961            0 :                                 dev_warn(dev, "invalid stream %d\n", i);
     962              : 
     963              :                         break;
     964              :                 }
     965              :         }
     966            9 :         spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
     967              : }
     968              : 
     969              : static struct ipu6_isys_stream *
     970            1 : ipu6_isys_get_stream(struct ipu6_isys_video *av, struct ipu6_isys_subdev *asd)
     971              : {
     972              :         struct ipu6_isys_stream *stream = NULL;
     973            1 :         struct ipu6_isys *isys = av->isys;
     974              :         unsigned long flags;
     975              :         unsigned int i;
     976            1 :         u8 vc = av->vc;
     977              : 
     978            1 :         if (!isys)
     979              :                 return NULL;
     980              : 
     981            1 :         spin_lock_irqsave(&isys->streams_lock, flags);
     982            9 :         for (i = 0; i < IPU4_ISYS_MAX_STREAMS; i++) {
     983            8 :                 if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
     984            0 :                     isys->streams[i].asd == asd) {
     985            0 :                         isys->streams_ref_count[i]++;
     986            0 :                         stream = &isys->streams[i];
     987            0 :                         break;
     988              :                 }
     989              :         }
     990              : 
     991            1 :         if (!stream) {
     992            1 :                 for (i = 0; i < IPU4_ISYS_MAX_STREAMS; i++) {
     993            1 :                         if (!isys->streams_ref_count[i]) {
     994            1 :                                 isys->streams_ref_count[i]++;
     995            1 :                                 stream = &isys->streams[i];
     996            1 :                                 stream->vc = vc;
     997            1 :                                 stream->asd = asd;
     998            1 :                                 break;
     999              :                         }
    1000              :                 }
    1001              :         }
    1002              :         spin_unlock_irqrestore(&isys->streams_lock, flags);
    1003              : 
    1004            1 :         return stream;
    1005              : }
    1006              : 
    1007              : struct ipu6_isys_stream *
    1008            8 : ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle)
    1009              : {
    1010              :         unsigned long flags;
    1011              :         struct ipu6_isys_stream *stream = NULL;
    1012              : 
    1013            8 :         if (!isys)
    1014              :                 return NULL;
    1015              : 
    1016            8 :         if (stream_handle >= IPU4_ISYS_MAX_STREAMS) {
    1017            0 :                 dev_err(&isys->adev->auxdev.dev,
    1018              :                         "stream_handle %d is invalid\n", stream_handle);
    1019            0 :                 return NULL;
    1020              :         }
    1021              : 
    1022            8 :         spin_lock_irqsave(&isys->streams_lock, flags);
    1023            8 :         if (isys->streams_ref_count[stream_handle] > 0) {
    1024            8 :                 isys->streams_ref_count[stream_handle]++;
    1025            8 :                 stream = &isys->streams[stream_handle];
    1026              :         }
    1027              :         spin_unlock_irqrestore(&isys->streams_lock, flags);
    1028              : 
    1029            8 :         return stream;
    1030              : }
    1031              : 
    1032              : struct ipu6_isys_stream *
    1033            0 : ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc)
    1034              : {
    1035              :         struct ipu6_isys_stream *stream = NULL;
    1036              :         unsigned long flags;
    1037              :         unsigned int i;
    1038              : 
    1039            0 :         if (!isys)
    1040              :                 return NULL;
    1041              : 
    1042            0 :         if (source < 0) {
    1043            0 :                 dev_err(&isys->adev->auxdev.dev,
    1044              :                         "query stream with invalid port number\n");
    1045            0 :                 return NULL;
    1046              :         }
    1047              : 
    1048            0 :         spin_lock_irqsave(&isys->streams_lock, flags);
    1049            0 :         for (i = 0; i < IPU4_ISYS_MAX_STREAMS; i++) {
    1050            0 :                 if (!isys->streams_ref_count[i])
    1051            0 :                         continue;
    1052              : 
    1053            0 :                 if (isys->streams[i].stream_source == source &&
    1054            0 :                     isys->streams[i].vc == vc) {
    1055            0 :                         stream = &isys->streams[i];
    1056            0 :                         isys->streams_ref_count[i]++;
    1057            0 :                         break;
    1058              :                 }
    1059              :         }
    1060              :         spin_unlock_irqrestore(&isys->streams_lock, flags);
    1061              : 
    1062            0 :         return stream;
    1063              : }
    1064              : 
    1065            2 : static u64 get_stream_mask_by_pipeline(struct ipu6_isys_video *__av)
    1066              : {
    1067              :         struct media_pipeline *pipeline =
    1068            2 :                 media_entity_pipeline(&__av->vdev.entity);
    1069              :         struct media_entity *entity;
    1070              :         unsigned int i;
    1071              :         u64 stream_mask = 0;
    1072              : 
    1073           64 :         for (i = 0; i < NR_OF_VIDEO_DEVICE; i++) {
    1074           62 :                 entity = &__av->isys->av[i].vdev.entity;
    1075           62 :                 if (pipeline == media_entity_pipeline(entity))
    1076            2 :                         stream_mask |= BIT_ULL(__av->isys->av[i].source_stream);
    1077              :         }
    1078              : 
    1079            2 :         return stream_mask;
    1080              : }
    1081              : 
    1082            2 : int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
    1083              :                                   struct ipu6_isys_buffer_list *bl)
    1084              : {
    1085              :         struct v4l2_subdev_krouting *routing;
    1086            2 :         struct ipu6_isys_stream *stream = av->stream;
    1087              :         struct v4l2_subdev_state *subdev_state;
    1088            2 :         struct device *dev = &av->isys->adev->auxdev.dev;
    1089              :         struct v4l2_subdev *sd;
    1090              :         struct media_pad *r_pad;
    1091            2 :         u32 sink_pad, sink_stream;
    1092              :         u64 r_stream;
    1093              :         u64 stream_mask = 0;
    1094              :         int ret = 0;
    1095              : 
    1096            2 :         dev_dbg(dev, "set stream: %d\n", state);
    1097              : 
    1098            2 :         if (WARN(!stream->source_entity, "No source entity for stream\n"))
    1099            0 :                 return -ENODEV;
    1100              : 
    1101            2 :         sd = &stream->asd->sd;
    1102            2 :         r_pad = media_pad_remote_pad_first(&av->pad);
    1103            2 :         r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
    1104              : 
    1105              :         subdev_state = v4l2_subdev_lock_and_get_active_state(sd);
    1106            2 :         routing = &subdev_state->routing;
    1107            2 :         ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index,
    1108              :                                                     r_stream, &sink_pad,
    1109              :                                                     &sink_stream);
    1110              :         v4l2_subdev_unlock_state(subdev_state);
    1111            2 :         if (ret)
    1112              :                 return ret;
    1113              : 
    1114            2 :         stream_mask = get_stream_mask_by_pipeline(av);
    1115            2 :         if (!state) {
    1116            1 :                 stop_streaming_firmware(av);
    1117              : 
    1118              :                 /* stop sub-device which connects with video */
    1119            1 :                 dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",
    1120              :                         sd->name, r_pad->index, stream_mask);
    1121            1 :                 ret = v4l2_subdev_disable_streams(sd, r_pad->index,
    1122              :                                                   stream_mask);
    1123            1 :                 if (ret) {
    1124            0 :                         dev_err(dev, "stream off %s failed with %d\n", sd->name,
    1125              :                                 ret);
    1126            0 :                         return ret;
    1127              :                 }
    1128            1 :                 close_streaming_firmware(av);
    1129              :         } else {
    1130            1 :                 ret = start_stream_firmware(av, bl);
    1131            1 :                 if (ret) {
    1132            0 :                         dev_err(dev, "start stream of firmware failed\n");
    1133            0 :                         return ret;
    1134              :                 }
    1135              : 
    1136              :                 /* start sub-device which connects with video */
    1137            1 :                 dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,
    1138              :                         r_pad->index, stream_mask);
    1139            1 :                 ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);
    1140            1 :                 if (ret) {
    1141            0 :                         dev_err(dev, "stream on %s failed with %d\n", sd->name,
    1142              :                                 ret);
    1143            0 :                         goto out_media_entity_stop_streaming_firmware;
    1144              :                 }
    1145              :         }
    1146              : 
    1147            2 :         av->streaming = state;
    1148              : 
    1149            2 :         return 0;
    1150              : 
    1151              : out_media_entity_stop_streaming_firmware:
    1152            0 :         stop_streaming_firmware(av);
    1153              : 
    1154            0 :         return ret;
    1155              : }
    1156              : 
    1157              : static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = {
    1158              :         .vidioc_querycap = ipu6_isys_vidioc_querycap,
    1159              :         .vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt,
    1160              :         .vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt,
    1161              :         .vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes,
    1162              :         .vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap,
    1163              :         .vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap,
    1164              :         .vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap,
    1165              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1166              :         .vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap,
    1167              :         .vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap,
    1168              :         .vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap,
    1169              : #endif
    1170              :         .vidioc_reqbufs = ipu6_isys_vidioc_reqbufs,
    1171              :         .vidioc_create_bufs = ipu6_isys_vidioc_create_bufs,
    1172              :         .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
    1173              :         .vidioc_querybuf = vb2_ioctl_querybuf,
    1174              :         .vidioc_qbuf = vb2_ioctl_qbuf,
    1175              :         .vidioc_dqbuf = vb2_ioctl_dqbuf,
    1176              :         .vidioc_streamon = vb2_ioctl_streamon,
    1177              :         .vidioc_streamoff = vb2_ioctl_streamoff,
    1178              :         .vidioc_expbuf = vb2_ioctl_expbuf,
    1179              : };
    1180              : 
    1181              : static const struct media_entity_operations entity_ops = {
    1182              :         .link_validate = link_validate,
    1183              : };
    1184              : 
    1185              : static const struct v4l2_file_operations isys_fops = {
    1186              :         .owner = THIS_MODULE,
    1187              :         .poll = vb2_fop_poll,
    1188              :         .unlocked_ioctl = video_ioctl2,
    1189              :         .mmap = vb2_fop_mmap,
    1190              :         .open = video_open,
    1191              :         .release = vb2_fop_release,
    1192              : };
    1193              : 
    1194            1 : int ipu6_isys_fw_get(struct ipu6_isys *isys)
    1195              : {
    1196            1 :         struct ipu6_bus_device *adev = isys->adev;
    1197              :         int ret;
    1198              : 
    1199            1 :         ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
    1200            1 :         if (ret < 0)
    1201              :                 return ret;
    1202              : 
    1203            1 :         mutex_lock(&isys->mutex);
    1204            1 :         wait_for_not_resetting(isys, __func__);
    1205              : 
    1206            1 :         if (isys->ref_count++)
    1207            0 :                 goto unlock;
    1208              : 
    1209            1 :         ret = ipu6_fw_isys_open(isys);
    1210            1 :         if (ret < 0)
    1211            0 :                 goto out;
    1212              : 
    1213            1 : unlock:
    1214            1 :         mutex_unlock(&isys->mutex);
    1215              : 
    1216            1 :         return 0;
    1217              : 
    1218              : out:
    1219            0 :         isys->ref_count--;
    1220            0 :         mutex_unlock(&isys->mutex);
    1221              :         pm_runtime_put(&adev->auxdev.dev);
    1222              : 
    1223            0 :         return ret;
    1224              : }
    1225              : 
    1226            1 : void ipu6_isys_fw_put(struct ipu6_isys *isys)
    1227              : {
    1228            1 :         struct device *dev = &isys->adev->auxdev.dev;
    1229              : 
    1230            1 :         mutex_lock(&isys->mutex);
    1231            1 :         wait_for_not_resetting(isys, __func__);
    1232              : 
    1233            1 :         isys->ref_count--;
    1234            1 :         if (!isys->ref_count) {
    1235            1 :                 ipu6_fw_isys_close(isys);
    1236            1 :                 if (isys->fwcom) {
    1237            0 :                         dev_info(dev, "%s: Setting need_reset\n", __func__);
    1238            0 :                         isys->need_reset = true;
    1239            0 :                         dev_warn(&isys->adev->auxdev.dev,
    1240              :                                  "failed to close fw isys\n");
    1241              :                 }
    1242              :         }
    1243              : 
    1244            1 :         mutex_unlock(&isys->mutex);
    1245              : 
    1246            1 :         if (isys->need_reset)
    1247            0 :                 pm_runtime_put_sync(&isys->adev->auxdev.dev);
    1248              :         else
    1249            1 :                 pm_runtime_put(&isys->adev->auxdev.dev);
    1250            1 : }
    1251              : 
    1252            1 : int ipu6_isys_setup_video(struct ipu6_isys_video *av,
    1253              :                           struct media_entity **source_entity, int *nr_queues)
    1254              : {
    1255              :         const struct ipu6_isys_pixelformat *pfmt =
    1256              :                 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
    1257            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
    1258            1 :         struct v4l2_mbus_frame_desc_entry entry;
    1259              :         struct v4l2_subdev_route *route = NULL;
    1260              :         struct v4l2_subdev_route *r;
    1261              :         struct v4l2_subdev_state *state;
    1262              :         struct ipu6_isys_subdev *asd;
    1263              :         struct v4l2_subdev *remote_sd;
    1264              :         struct media_pipeline *pipeline;
    1265              :         struct media_pad *source_pad, *remote_pad;
    1266              :         int ret = -EINVAL;
    1267              : 
    1268            1 :         *nr_queues = 0;
    1269              : 
    1270            1 :         remote_pad = media_pad_remote_pad_unique(&av->pad);
    1271            1 :         if (IS_ERR(remote_pad)) {
    1272            0 :                 dev_dbg(dev, "failed to get remote pad\n");
    1273            0 :                 return PTR_ERR(remote_pad);
    1274              :         }
    1275              : 
    1276            1 :         remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
    1277              :         asd = to_ipu6_isys_subdev(remote_sd);
    1278            1 :         source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
    1279            1 :         if (!source_pad) {
    1280            0 :                 dev_dbg(dev, "No external source entity\n");
    1281            0 :                 return -ENODEV;
    1282              :         }
    1283              : 
    1284            1 :         *source_entity = source_pad->entity;
    1285              : 
    1286              :         /* Find the root */
    1287              :         state = v4l2_subdev_lock_and_get_active_state(remote_sd);
    1288            2 :         for_each_active_route(&state->routing, r) {
    1289            1 :                 (*nr_queues)++;
    1290              : 
    1291            1 :                 if (r->source_pad == remote_pad->index)
    1292              :                         route = r;
    1293              :         }
    1294              : 
    1295            1 :         if (!route) {
    1296              :                 v4l2_subdev_unlock_state(state);
    1297            0 :                 dev_dbg(dev, "Failed to find route\n");
    1298            0 :                 return -ENODEV;
    1299              :         }
    1300            1 :         av->source_stream = route->sink_stream;
    1301              :         v4l2_subdev_unlock_state(state);
    1302              : 
    1303            1 :         ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,
    1304              :                                              to_ipu6_isys_csi2(asd),
    1305              :                                              *source_entity, &entry);
    1306            1 :         if (ret == -ENOIOCTLCMD) {
    1307            1 :                 av->vc = 0;
    1308            1 :                 av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
    1309            0 :         } else if (!ret) {
    1310            0 :                 dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
    1311              :                         entry.stream, entry.length, entry.bus.csi2.vc,
    1312              :                         entry.bus.csi2.dt);
    1313              : 
    1314            0 :                 av->vc = entry.bus.csi2.vc;
    1315            0 :                 av->dt = entry.bus.csi2.dt;
    1316              :         } else {
    1317            0 :                 dev_err(dev, "failed to get remote frame desc\n");
    1318            0 :                 return ret;
    1319              :         }
    1320              : 
    1321            1 :         pipeline = media_entity_pipeline(&av->vdev.entity);
    1322            1 :         if (!pipeline)
    1323            1 :                 ret = video_device_pipeline_alloc_start(&av->vdev);
    1324              :         else
    1325            0 :                 ret = video_device_pipeline_start(&av->vdev, pipeline);
    1326            1 :         if (ret < 0) {
    1327            0 :                 dev_dbg(dev, "media pipeline start failed\n");
    1328            0 :                 return ret;
    1329              :         }
    1330              : 
    1331            1 :         av->stream = ipu6_isys_get_stream(av, asd);
    1332            1 :         if (!av->stream) {
    1333            0 :                 video_device_pipeline_stop(&av->vdev);
    1334            0 :                 dev_err(dev, "no available stream for firmware\n");
    1335            0 :                 return -EINVAL;
    1336              :         }
    1337              : 
    1338              :         return 0;
    1339              : }
    1340              : 
    1341              : /*
    1342              :  * Do everything that's needed to initialise things related to video
    1343              :  * buffer queue, video node, and the related media entity. The caller
    1344              :  * is expected to assign isys field and set the name of the video
    1345              :  * device.
    1346              :  */
    1347           31 : int ipu6_isys_video_init(struct ipu6_isys_video *av)
    1348              : {
    1349           31 :         struct v4l2_format format = {
    1350              :                 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
    1351              :                 .fmt.pix = {
    1352              :                         .width = 1920,
    1353              :                         .height = 1080,
    1354              :                 },
    1355              :         };
    1356              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1357           31 :         struct v4l2_format format_meta = {
    1358              :                 .type = V4L2_BUF_TYPE_META_CAPTURE,
    1359              :                 .fmt.meta = {
    1360              :                         .width = 1920,
    1361              :                         .height = 4,
    1362              :                 },
    1363              :         };
    1364              : #endif
    1365              :         int ret;
    1366              : 
    1367           31 :         mutex_init(&av->mutex);
    1368           31 :         av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
    1369              :                                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
    1370           31 :         av->vdev.vfl_dir = VFL_DIR_RX;
    1371              : 
    1372           31 :         ret = ipu6_isys_queue_init(&av->aq);
    1373           31 :         if (ret)
    1374            0 :                 goto out_free_watermark;
    1375              : 
    1376           31 :         av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
    1377           31 :         ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
    1378           31 :         if (ret)
    1379            0 :                 goto out_vb2_queue_release;
    1380              : 
    1381           31 :         av->vdev.entity.ops = &entity_ops;
    1382           31 :         av->vdev.release = video_device_release_empty;
    1383           31 :         av->vdev.fops = &isys_fops;
    1384           31 :         av->vdev.v4l2_dev = &av->isys->v4l2_dev;
    1385           31 :         av->vdev.dev_parent = &av->isys->adev->isp->pdev->dev;
    1386           31 :         if (!av->vdev.ioctl_ops)
    1387           31 :                 av->vdev.ioctl_ops = &ipu6_v4l2_ioctl_ops;
    1388           31 :         av->vdev.queue = &av->aq.vbq;
    1389           31 :         av->vdev.lock = &av->mutex;
    1390              : 
    1391           31 :         __ipu6_isys_vidioc_try_fmt_vid_cap(av, &format);
    1392           31 :         av->pix_fmt = format.fmt.pix;
    1393              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1394           31 :         __ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta);
    1395           31 :         av->meta_fmt = format_meta.fmt.meta;
    1396              : #endif
    1397              : 
    1398              :         video_set_drvdata(&av->vdev, av);
    1399              : 
    1400           31 :         ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);
    1401           31 :         if (ret)
    1402            0 :                 goto out_media_entity_cleanup;
    1403              : 
    1404              :         return ret;
    1405              : 
    1406              : out_media_entity_cleanup:
    1407            0 :         vb2_video_unregister_device(&av->vdev);
    1408              :         media_entity_cleanup(&av->vdev.entity);
    1409              : 
    1410            0 : out_vb2_queue_release:
    1411            0 :         vb2_queue_release(&av->aq.vbq);
    1412              : 
    1413              : out_free_watermark:
    1414              :         mutex_destroy(&av->mutex);
    1415              : 
    1416              :         return ret;
    1417              : }
    1418              : 
    1419            0 : void ipu6_isys_video_cleanup(struct ipu6_isys_video *av)
    1420              : {
    1421            0 :         vb2_video_unregister_device(&av->vdev);
    1422              :         media_entity_cleanup(&av->vdev.entity);
    1423              :         mutex_destroy(&av->mutex);
    1424            0 : }
    1425              : 
    1426            2 : u32 ipu6_isys_get_format(struct ipu6_isys_video *av)
    1427              : {
    1428            5 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1429            5 :                 return av->pix_fmt.pixelformat;
    1430              : 
    1431            0 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
    1432            0 :                 return av->meta_fmt.dataformat;
    1433              : 
    1434              :         return 0;
    1435              : }
    1436              : 
    1437            3 : u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av)
    1438              : {
    1439            3 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1440            3 :                 return av->pix_fmt.sizeimage;
    1441              : 
    1442            0 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
    1443            0 :                 return av->meta_fmt.buffersize;
    1444              : 
    1445              :         return 0;
    1446              : }
    1447              : 
    1448            2 : u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av)
    1449              : {
    1450            3 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1451            3 :                 return av->pix_fmt.bytesperline;
    1452              : 
    1453              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1454            0 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
    1455            0 :                 return av->meta_fmt.bytesperline;
    1456              : #endif
    1457              : 
    1458              :         return 0;
    1459              : }
    1460              : 
    1461            2 : u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av)
    1462              : {
    1463            4 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1464            4 :                 return av->pix_fmt.width;
    1465              : 
    1466              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1467            0 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
    1468            0 :                 return av->meta_fmt.width;
    1469              : #endif
    1470              : 
    1471              :         return 0;
    1472              : }
    1473              : 
    1474            4 : u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av)
    1475              : {
    1476            6 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
    1477            6 :                 return av->pix_fmt.height;
    1478              : 
    1479              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1480            0 :         if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
    1481            0 :                 return av->meta_fmt.height;
    1482              : #endif
    1483              : 
    1484              :         return 0;
    1485              : }
        

Generated by: LCOV version 2.0-1