LCOV - code coverage report
Current view: top level - ipu4 - ipu6-isys-queue.c (source / functions) Coverage Total Hit
Test: ipu4.info Lines: 58.1 % 415 241
Test Date: 2026-05-12 04:57:36 Functions: 80.8 % 26 21

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-only
       2              : /*
       3              :  * Copyright (C) 2013--2024 Intel Corporation
       4              :  */
       5              : #include <linux/atomic.h>
       6              : #include <linux/bug.h>
       7              : #include <linux/delay.h>
       8              : #include <linux/device.h>
       9              : #include <linux/ktime.h>
      10              : #include <linux/list.h>
      11              : #include <linux/lockdep.h>
      12              : #include <linux/mutex.h>
      13              : #include <linux/spinlock.h>
      14              : #include <linux/types.h>
      15              : 
      16              : #include <media/media-entity.h>
      17              : #include <media/v4l2-subdev.h>
      18              : #include <media/videobuf2-dma-sg.h>
      19              : #include <media/videobuf2-v4l2.h>
      20              : 
      21              : #include "ipu6-bus.h"
      22              : #include "ipu6-dma.h"
      23              : #include "ipu6-fw-isys.h"
      24              : #include "ipu6-isys.h"
      25              : #include "ipu6-isys-video.h"
      26              : 
      27            2 : static int ipu6_isys_buf_init(struct vb2_buffer *vb)
      28              : {
      29            2 :         struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue);
      30              :         struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
      31              :         struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
      32              :         struct ipu6_isys_video_buffer *ivb =
      33              :                 vb2_buffer_to_ipu6_isys_video_buffer(vvb);
      34              :         int ret;
      35              : 
      36            2 :         ret = ipu6_dma_map_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0);
      37            2 :         if (ret)
      38              :                 return ret;
      39              : 
      40            2 :         ivb->dma_addr = sg_dma_address(sg->sgl);
      41              : 
      42            2 :         return 0;
      43              : }
      44              : 
      45            2 : static void ipu6_isys_buf_cleanup(struct vb2_buffer *vb)
      46              : {
      47            2 :         struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue);
      48              :         struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
      49              :         struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
      50              :         struct ipu6_isys_video_buffer *ivb =
      51              :                 vb2_buffer_to_ipu6_isys_video_buffer(vvb);
      52              : 
      53            2 :         ivb->dma_addr = 0;
      54            2 :         ipu6_dma_unmap_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0);
      55            2 : }
      56              : 
      57            1 : static int ipu6_isys_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
      58              :                                  unsigned int *num_planes, unsigned int sizes[],
      59              :                                  struct device *alloc_devs[])
      60              : {
      61              :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
      62              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
      63            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
      64            1 :         u32 size = ipu6_isys_get_data_size(av);
      65              : 
      66              :         /* num_planes == 0: we're being called through VIDIOC_REQBUFS */
      67            1 :         if (!*num_planes) {
      68            1 :                 sizes[0] = size;
      69            0 :         } else if (sizes[0] < size) {
      70            0 :                 dev_dbg(dev, "%s: queue setup: size %u < %u\n",
      71              :                         av->vdev.name, sizes[0], size);
      72            0 :                 return -EINVAL;
      73              :         }
      74              : 
      75            1 :         *num_planes = 1;
      76              : 
      77            1 :         return 0;
      78              : }
      79              : 
      80            2 : static int ipu6_isys_buf_prepare(struct vb2_buffer *vb)
      81              : {
      82            2 :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
      83              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
      84            2 :         struct device *dev = &av->isys->adev->auxdev.dev;
      85            2 :         u32 bytesperline = ipu6_isys_get_bytes_per_line(av);
      86            2 :         u32 height = ipu6_isys_get_frame_height(av);
      87            2 :         u32 size = ipu6_isys_get_data_size(av);
      88              : 
      89            2 :         dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n",
      90              :                 av->vdev.name, size, vb2_plane_size(vb, 0));
      91              : 
      92            4 :         if (size > vb2_plane_size(vb, 0))
      93              :                 return -EINVAL;
      94              : 
      95            2 :         vb2_set_plane_payload(vb, 0, bytesperline * height);
      96              : 
      97            2 :         return 0;
      98              : }
      99              : 
     100            0 : static void _dump_queue_info(struct ipu6_isys_queue *aq, const char *context)
     101              : {
     102              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     103              :         struct ipu6_isys_buffer *ib;
     104            0 :         char active_buffer[64] = {0};
     105            0 :         char incoming_buffer[64] = {0};
     106              :         size_t len = 0;
     107              : 
     108              :         lockdep_assert_held(&aq->lock);
     109              : 
     110            0 :         list_for_each_entry(ib, &aq->incoming, head) {
     111              :                 struct vb2_buffer *vb =
     112              :                         ipu6_isys_buffer_to_vb2_buffer(ib);
     113            0 :                 len += snprintf(incoming_buffer + len,
     114              :                                 sizeof(incoming_buffer) - len,
     115              :                                 "%d, ",
     116              :                                 vb->index);
     117              :         }
     118              : 
     119            0 :         if (len > 2)
     120            0 :                 incoming_buffer[len - 2] = '\0';
     121              : 
     122              :         len = 0;
     123            0 :         list_for_each_entry(ib, &aq->active, head) {
     124              :                 struct vb2_buffer *vb =
     125              :                         ipu6_isys_buffer_to_vb2_buffer(ib);
     126            0 :                 len += snprintf(active_buffer + len,
     127              :                                 sizeof(active_buffer) - len,
     128              :                                 "%d, ",
     129              :                                 vb->index);
     130              :         }
     131            0 :         if (len > 2)
     132            0 :                 active_buffer[len - 2] = '\0';
     133              : 
     134            0 :         dev_info(&av->isys->adev->auxdev.dev,
     135              :                  "%s: %s: active: [%s], incoming: [%s]",
     136              :                  context,
     137              :                  av->vdev.name,
     138              :                  active_buffer,
     139              :                  incoming_buffer);
     140            0 : }
     141              : 
     142              : #define dump_queue_info(AQ, FMT, ...)                                          \
     143              :         do {                                                                   \
     144              :                 char _msg_buffer[128];                                         \
     145              :                                                                                \
     146              :                 snprintf(_msg_buffer, sizeof(_msg_buffer), FMT, ##__VA_ARGS__);\
     147              :                 _dump_queue_info(AQ, _msg_buffer);                             \
     148              :         } while (0)
     149              : 
     150              : /*
     151              :  * Queue a buffer list back to incoming or active queues. The buffers
     152              :  * are removed from the buffer list.
     153              :  */
     154            2 : void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
     155              :                                  unsigned long op_flags,
     156              :                                  enum vb2_buffer_state state)
     157              : {
     158              :         struct ipu6_isys_buffer *ib, *ib_safe;
     159              :         unsigned long flags;
     160              :         bool first = true;
     161              : 
     162            2 :         if (!bl)
     163              :                 return;
     164              : 
     165            2 :         WARN_ON_ONCE(!bl->nbufs);
     166            2 :         WARN_ON_ONCE(op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE &&
     167              :                      op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING);
     168              : 
     169            4 :         list_for_each_entry_safe(ib, ib_safe, &bl->head, head) {
     170              :                 struct ipu6_isys_video *av;
     171            2 :                 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     172              :                 struct ipu6_isys_queue *aq =
     173            2 :                         vb2_queue_to_isys_queue(vb->vb2_queue);
     174              :                 struct device *dev;
     175              : 
     176              :                 av = ipu6_isys_queue_to_video(aq);
     177            2 :                 dev = &av->isys->adev->auxdev.dev;
     178            2 :                 spin_lock_irqsave(&aq->lock, flags);
     179              :                 list_del(&ib->head);
     180            2 :                 if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE)
     181            2 :                         list_add(&ib->head, &aq->active);
     182            0 :                 else if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING)
     183            0 :                         list_add_tail(&ib->head, &aq->incoming);
     184              :                 spin_unlock_irqrestore(&aq->lock, flags);
     185              : 
     186            2 :                 if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_SET_STATE)
     187            0 :                         vb2_buffer_done(vb, state);
     188              : 
     189            2 :                 if (first) {
     190            2 :                         dev_dbg(dev,
     191              :                                 "queue buf list %p flags %lx, s %d, %d bufs\n",
     192              :                                 bl, op_flags, state, bl->nbufs);
     193              :                         first = false;
     194              :                 }
     195              : 
     196            2 :                 bl->nbufs--;
     197              :         }
     198              : 
     199            2 :         WARN_ON(bl->nbufs);
     200              : }
     201              : 
     202              : /*
     203              :  * When we're stopping the stream, wait for all buffers to be returned from
     204              :  * the firmware.
     205              :  */
     206            0 : static bool wait_for_no_active_buffers(struct ipu6_isys_video *av)
     207              : {
     208              :         struct ipu6_isys_queue *aq;
     209            0 :         unsigned long start = jiffies;
     210              :         const unsigned long timeout = msecs_to_jiffies(1000);
     211              : 
     212              :         lockdep_assert_held(&av->stream->mutex);
     213              : 
     214            0 :         while (time_is_after_jiffies(start + timeout)) {
     215              :                 bool all_empty = true;
     216              : 
     217            0 :                 list_for_each_entry(aq, &av->stream->queues, node) {
     218              :                         unsigned long flags;
     219              : 
     220            0 :                         spin_lock_irqsave(&aq->lock, flags);
     221            0 :                         all_empty &= list_empty(&aq->active);
     222            0 :                         dump_queue_info(aq, __func__);
     223              :                         spin_unlock_irqrestore(&aq->lock, flags);
     224              :                 }
     225              : 
     226            0 :                 if (all_empty)
     227              :                         return true;
     228              : 
     229            0 :                 msleep_interruptible(10);
     230              :         }
     231            0 :         dev_err(&av->vdev.dev, "%s timed out\n", __func__);
     232            0 :         return false;
     233              : }
     234              : 
     235              : /*
     236              :  * flush_firmware_streamon_fail() - Flush in cases where requests may
     237              :  * have been queued to firmware and the *firmware streamon fails for a
     238              :  * reason or another.
     239              :  */
     240            0 : static void flush_firmware_streamon_fail(struct ipu6_isys_stream *stream)
     241              : {
     242            0 :         struct device *dev = &stream->isys->adev->auxdev.dev;
     243              :         struct ipu6_isys_queue *aq;
     244              :         unsigned long flags;
     245              : 
     246              :         lockdep_assert_held(&stream->mutex);
     247              : 
     248            0 :         list_for_each_entry(aq, &stream->queues, node) {
     249              :                 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     250              :                 struct ipu6_isys_buffer *ib, *ib_safe;
     251              : 
     252            0 :                 spin_lock_irqsave(&aq->lock, flags);
     253            0 :                 list_for_each_entry_safe(ib, ib_safe, &aq->active, head) {
     254              :                         struct vb2_buffer *vb =
     255              :                                 ipu6_isys_buffer_to_vb2_buffer(ib);
     256              : 
     257              :                         list_del(&ib->head);
     258            0 :                         if (av->streaming) {
     259            0 :                                 dev_dbg(dev,
     260              :                                         "%s: queue buffer %u back to incoming\n",
     261              :                                         av->vdev.name, vb->index);
     262              :                                 /* Queue already streaming, return to driver. */
     263            0 :                                 list_add(&ib->head, &aq->incoming);
     264            0 :                                 continue;
     265              :                         }
     266              :                         /* Queue not yet streaming, return to user. */
     267            0 :                         dev_dbg(dev, "%s: return %u back to videobuf2\n",
     268              :                                 av->vdev.name, vb->index);
     269            0 :                         vb2_buffer_done(ipu6_isys_buffer_to_vb2_buffer(ib),
     270              :                                         VB2_BUF_STATE_QUEUED);
     271              :                 }
     272              :                 spin_unlock_irqrestore(&aq->lock, flags);
     273              :         }
     274            0 : }
     275              : 
     276              : /*
     277              :  * Attempt obtaining a buffer list from the incoming queues, a list of buffers
     278              :  * that contains one entry from each video buffer queue. If a buffer can't be
     279              :  * obtained from every queue, the buffers are returned back to the queue.
     280              :  */
     281            3 : static int buffer_list_get(struct ipu6_isys_stream *stream,
     282              :                            struct ipu6_isys_buffer_list *bl)
     283              : {
     284            3 :         struct device *dev = &stream->isys->adev->auxdev.dev;
     285              :         struct ipu6_isys_queue *aq;
     286              :         unsigned long flags;
     287              :         unsigned long buf_flag = IPU6_ISYS_BUFFER_LIST_FL_INCOMING;
     288              : 
     289            3 :         bl->nbufs = 0;
     290            3 :         INIT_LIST_HEAD(&bl->head);
     291              : 
     292            5 :         list_for_each_entry(aq, &stream->queues, node) {
     293              :                 struct ipu6_isys_buffer *ib;
     294              : 
     295            3 :                 spin_lock_irqsave(&aq->lock, flags);
     296            3 :                 if (list_empty(&aq->incoming)) {
     297              :                         spin_unlock_irqrestore(&aq->lock, flags);
     298            1 :                         if (!list_empty(&bl->head))
     299            0 :                                 ipu6_isys_buffer_list_queue(bl, buf_flag, 0);
     300            1 :                         return -ENODATA;
     301              :                 }
     302              : 
     303            2 :                 ib = list_last_entry(&aq->incoming,
     304              :                                      struct ipu6_isys_buffer, head);
     305              : 
     306            2 :                 dev_dbg(dev, "buffer: %s: buffer %u\n",
     307              :                         ipu6_isys_queue_to_video(aq)->vdev.name,
     308              :                         ipu6_isys_buffer_to_vb2_buffer(ib)->index);
     309              :                 list_del(&ib->head);
     310            2 :                 list_add(&ib->head, &bl->head);
     311              :                 spin_unlock_irqrestore(&aq->lock, flags);
     312              : 
     313            2 :                 bl->nbufs++;
     314              :         }
     315              : 
     316            2 :         dev_dbg(dev, "get buffer list %p, %u buffers\n", bl, bl->nbufs);
     317              : 
     318              :         return 0;
     319              : }
     320              : 
     321              : static void
     322              : ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
     323              :                                   struct ipu4_fw_isys_frame_buff_set_abi *set)
     324              : {
     325            2 :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
     326              :         struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
     327              :         struct ipu6_isys_video_buffer *ivb =
     328              :                 vb2_buffer_to_ipu6_isys_video_buffer(vvb);
     329              : 
     330            2 :         set->output_pins[aq->fw_output].addr = ivb->dma_addr;
     331            2 :         set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
     332              : }
     333              : 
     334              : /*
     335              :  * Convert a buffer list to a isys fw ABI framebuffer set. The
     336              :  * buffer list is not modified.
     337              :  */
     338              : #define IPU6_ISYS_FRAME_NUM_THRESHOLD  (30)
     339              : void
     340            2 : ipu6_isys_buf_to_fw_frame_buf(struct ipu4_fw_isys_frame_buff_set_abi *set,
     341              :                               struct ipu6_isys_stream *stream,
     342              :                               struct ipu6_isys_buffer_list *bl)
     343              : {
     344              :         struct ipu6_isys_buffer *ib;
     345              : 
     346            2 :         WARN_ON(!bl->nbufs);
     347              : 
     348            2 :         set->send_irq_sof = 1;
     349            2 :         set->send_resp_sof = 1;
     350              : 
     351            2 :         set->send_irq_capture_ack = 1;
     352            2 :         set->send_irq_capture_done = 1;
     353            2 :         set->send_irq_eof = 1;
     354            2 :         set->send_resp_eof = 1;
     355              : 
     356            4 :         list_for_each_entry(ib, &bl->head, head) {
     357              :                 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     358              : 
     359              :                 ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
     360              :         }
     361            2 : }
     362              : 
     363              : /* Start streaming for real. The buffer list must be available. */
     364            1 : static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
     365              :                                   struct ipu6_isys_buffer_list *bl, bool error)
     366              : {
     367            1 :         struct ipu6_isys_stream *stream = av->stream;
     368            1 :         struct device *dev = &stream->isys->adev->auxdev.dev;
     369            1 :         struct ipu6_isys_buffer_list __bl;
     370              :         int ret;
     371              : 
     372            1 :         mutex_lock(&stream->isys->stream_mutex);
     373            1 :         ret = ipu6_isys_video_set_streaming(av, 1, bl);
     374            1 :         mutex_unlock(&stream->isys->stream_mutex);
     375            1 :         if (ret)
     376            0 :                 goto out_requeue;
     377              : 
     378            1 :         stream->streaming = 1;
     379              : 
     380              :         bl = &__bl;
     381              : 
     382              :         do {
     383              :                 struct ipu4_fw_isys_frame_buff_set_abi *buf = NULL;
     384              :                 struct isys_fw_msgs *msg;
     385              :                 u16 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE;
     386              : 
     387            2 :                 ret = buffer_list_get(stream, bl);
     388            2 :                 if (ret < 0)
     389              :                         break;
     390              : 
     391            1 :                 msg = ipu6_get_fw_msg_buf(stream);
     392            1 :                 if (!msg)
     393              :                         return -ENOMEM;
     394              : 
     395            1 :                 buf = &msg->fw_msg.frame;
     396            1 :                 ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
     397            1 :                 ipu4_fw_isys_dump_frame_buff_set(dev, buf,
     398              :                                                  stream->nr_output_pins);
     399            1 :                 ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,
     400              :                                             0);
     401            1 :                 ret = ipu6_fw_isys_complex_cmd(stream->isys,
     402            1 :                                                stream->stream_handle, buf,
     403              :                                                msg->dma_addr, sizeof(*buf),
     404              :                                                send_type);
     405            1 :         } while (!WARN_ON(ret));
     406              : 
     407              :         return 0;
     408              : 
     409              : out_requeue:
     410            0 :         if (bl && bl->nbufs)
     411            0 :                 ipu6_isys_buffer_list_queue(bl,
     412              :                                             IPU6_ISYS_BUFFER_LIST_FL_INCOMING |
     413              :                                             (error ?
     414              :                                             IPU6_ISYS_BUFFER_LIST_FL_SET_STATE :
     415              :                                              0), error ? VB2_BUF_STATE_ERROR :
     416              :                                             VB2_BUF_STATE_QUEUED);
     417            0 :         flush_firmware_streamon_fail(stream);
     418              : 
     419            0 :         return ret;
     420              : }
     421              : 
     422            2 : static void buf_queue(struct vb2_buffer *vb)
     423              : {
     424            2 :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
     425              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     426              :         struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
     427              :         struct ipu6_isys_video_buffer *ivb =
     428              :                 vb2_buffer_to_ipu6_isys_video_buffer(vvb);
     429              :         struct ipu6_isys_buffer *ib = &ivb->ib;
     430            2 :         struct device *dev = &av->isys->adev->auxdev.dev;
     431              :         struct media_pipeline *media_pipe =
     432            2 :                 media_entity_pipeline(&av->vdev.entity);
     433              :         struct ipu4_fw_isys_frame_buff_set_abi *buf = NULL;
     434            2 :         struct ipu6_isys_stream *stream = av->stream;
     435            2 :         struct ipu6_isys_buffer_list bl;
     436              :         struct isys_fw_msgs *msg;
     437              :         unsigned long flags;
     438            2 :         dma_addr_t dma;
     439              :         int ret;
     440              : 
     441            2 :         dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);
     442              : 
     443            2 :         dma = ivb->dma_addr;
     444            2 :         dev_dbg(dev, "iova: iova %pad\n", &dma);
     445              : 
     446            2 :         spin_lock_irqsave(&aq->lock, flags);
     447            2 :         list_add(&ib->head, &aq->incoming);
     448              :         spin_unlock_irqrestore(&aq->lock, flags);
     449              : 
     450            2 :         if (!media_pipe || !vb->vb2_queue->start_streaming_called) {
     451            2 :                 dev_dbg(dev, "media pipeline is not ready for %s\n",
     452              :                         av->vdev.name);
     453            2 :                 return;
     454              :         }
     455              : 
     456            0 :         mutex_lock(&stream->mutex);
     457              : 
     458            0 :         if (stream->nr_streaming != stream->nr_queues) {
     459            0 :                 dev_dbg(dev, "not streaming yet, adding to incoming\n");
     460            0 :                 goto out;
     461              :         }
     462              : 
     463              :         /*
     464              :          * We just put one buffer to the incoming list of this queue
     465              :          * (above). Let's see whether all queues in the pipeline would
     466              :          * have a buffer.
     467              :          */
     468            0 :         ret = buffer_list_get(stream, &bl);
     469            0 :         if (ret < 0) {
     470            0 :                 dev_dbg(dev, "No buffers available\n");
     471            0 :                 goto out;
     472              :         }
     473              : 
     474            0 :         msg = ipu6_get_fw_msg_buf(stream);
     475            0 :         if (!msg) {
     476              :                 ret = -ENOMEM;
     477            0 :                 goto out;
     478              :         }
     479              : 
     480            0 :         buf = &msg->fw_msg.frame;
     481            0 :         ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
     482            0 :         ipu4_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
     483              : 
     484            0 :         if (!stream->streaming) {
     485            0 :                 ret = ipu6_isys_stream_start(av, &bl, true);
     486            0 :                 if (ret)
     487            0 :                         dev_err(dev, "stream start failed.\n");
     488            0 :                 goto out;
     489              :         }
     490              : 
     491              :         /*
     492              :          * We must queue the buffers in the buffer list to the
     493              :          * appropriate video buffer queues BEFORE passing them to the
     494              :          * firmware since we could get a buffer event back before we
     495              :          * have queued them ourselves to the active queue.
     496              :          */
     497            0 :         ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
     498              : 
     499            0 :         ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,
     500              :                                        buf, msg->dma_addr, sizeof(*buf),
     501              :                                        IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
     502            0 :         if (ret < 0)
     503            0 :                 dev_err(dev, "send stream capture failed\n");
     504              : 
     505            0 : out:
     506            0 :         mutex_unlock(&stream->mutex);
     507              : }
     508              : 
     509            1 : static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)
     510              : {
     511            1 :         struct v4l2_mbus_framefmt format;
     512              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     513            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
     514              :         struct media_pad *remote_pad =
     515            1 :                 media_pad_remote_pad_first(av->vdev.entity.pads);
     516              :         struct v4l2_subdev *sd;
     517              :         u32 r_stream, code;
     518              :         int ret;
     519              : 
     520            1 :         if (!remote_pad)
     521              :                 return -ENOTCONN;
     522              : 
     523            1 :         sd = media_entity_to_v4l2_subdev(remote_pad->entity);
     524            1 :         r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, remote_pad->index);
     525              : 
     526            1 :         ret = ipu6_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream,
     527              :                                            &format);
     528              : 
     529            1 :         if (ret) {
     530            0 :                 dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n",
     531              :                         sd->entity.name, remote_pad->index, r_stream);
     532            0 :                 return ret;
     533              :         }
     534              : 
     535            2 :         if (format.width != ipu6_isys_get_frame_width(av) ||
     536            1 :             format.height != ipu6_isys_get_frame_height(av)) {
     537            0 :                 dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n",
     538              :                         ipu6_isys_get_frame_width(av),
     539              :                         ipu6_isys_get_frame_height(av), format.width,
     540              :                         format.height);
     541            0 :                 return -EINVAL;
     542              :         }
     543              : 
     544            1 :         code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
     545            1 :         if (format.code != code) {
     546            0 :                 dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n",
     547              :                         code, format.code);
     548            0 :                 return -EINVAL;
     549              :         }
     550              : 
     551              :         return 0;
     552              : }
     553              : 
     554            1 : static void return_buffers(struct ipu6_isys_queue *aq,
     555              :                            enum vb2_buffer_state state)
     556              : {
     557              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     558              :         struct ipu6_isys_buffer *ib;
     559              :         bool need_reset = false;
     560              :         unsigned long flags;
     561              : 
     562            1 :         spin_lock_irqsave(&aq->lock, flags);
     563            1 :         while (!list_empty(&aq->incoming)) {
     564              :                 struct vb2_buffer *vb;
     565              : 
     566            0 :                 ib = list_first_entry(&aq->incoming, struct ipu6_isys_buffer,
     567              :                                       head);
     568            0 :                 vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     569              :                 list_del(&ib->head);
     570              :                 spin_unlock_irqrestore(&aq->lock, flags);
     571              : 
     572            0 :                 vb2_buffer_done(vb, state);
     573              : 
     574            0 :                 dev_dbg(&av->isys->adev->auxdev.dev, "%s: stop_streaming incoming %u\n",
     575              :                         ipu6_isys_queue_to_video(vb2_queue_to_isys_queue
     576              :                                                  (vb->vb2_queue))->vdev.name,
     577              :                         vb->index);
     578              : 
     579            0 :                 spin_lock_irqsave(&aq->lock, flags);
     580              :         }
     581              : 
     582              :         /*
     583              :          * Something went wrong (FW crash / HW hang / not all buffers
     584              :          * returned from isys) if there are still buffers queued in active
     585              :          * queue. We have to clean up places a bit.
     586              :          */
     587            1 :         while (!list_empty(&aq->active)) {
     588              :                 struct vb2_buffer *vb;
     589              : 
     590            0 :                 ib = list_first_entry(&aq->active, struct ipu6_isys_buffer,
     591              :                                       head);
     592            0 :                 vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     593              : 
     594              :                 list_del(&ib->head);
     595              :                 spin_unlock_irqrestore(&aq->lock, flags);
     596              : 
     597            0 :                 vb2_buffer_done(vb, state);
     598              : 
     599            0 :                 dev_warn(&av->isys->adev->auxdev.dev, "%s: cleaning active queue %u\n",
     600              :                          ipu6_isys_queue_to_video(vb2_queue_to_isys_queue
     601              :                                                   (vb->vb2_queue))->vdev.name,
     602              :                          vb->index);
     603              : 
     604            0 :                 spin_lock_irqsave(&aq->lock, flags);
     605              :                 need_reset = true;
     606              :         }
     607              : 
     608              :         spin_unlock_irqrestore(&aq->lock, flags);
     609              : 
     610            1 :         if (need_reset) {
     611            0 :                 mutex_lock(&av->isys->mutex);
     612            0 :                 av->isys->need_reset = true;
     613            0 :                 mutex_unlock(&av->isys->mutex);
     614              :         }
     615            1 : }
     616              : 
     617            1 : static void ipu6_isys_stream_cleanup(struct ipu6_isys_video *av)
     618              : {
     619            1 :         video_device_pipeline_stop(&av->vdev);
     620            1 :         ipu6_isys_put_stream(av->stream);
     621            1 :         av->stream = NULL;
     622            1 : }
     623              : 
     624            1 : static int start_streaming(struct vb2_queue *q, unsigned int count)
     625              : {
     626              :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
     627              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     628            1 :         struct device *dev = &av->isys->adev->auxdev.dev;
     629              :         const struct ipu6_isys_pixelformat *pfmt =
     630            1 :                 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
     631            1 :         struct ipu6_isys_buffer_list __bl, *bl = NULL;
     632              :         struct ipu6_isys_stream *stream;
     633            1 :         struct media_entity *source_entity = NULL;
     634            1 :         int nr_queues, ret;
     635              : 
     636            1 :         dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",
     637              :                 av->vdev.name, ipu6_isys_get_frame_width(av),
     638              :                 ipu6_isys_get_frame_height(av), pfmt->css_pixelformat);
     639              : 
     640            1 :         ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues);
     641            1 :         if (ret < 0) {
     642            0 :                 dev_dbg(dev, "failed to setup video\n");
     643            0 :                 goto out_return_buffers;
     644              :         }
     645              : 
     646            1 :         ret = ipu6_isys_link_fmt_validate(aq);
     647            1 :         if (ret) {
     648            0 :                 dev_dbg(dev,
     649              :                         "%s: link format validation failed (%d)\n",
     650              :                         av->vdev.name, ret);
     651            0 :                 goto out_pipeline_stop;
     652              :         }
     653              : 
     654            1 :         ret = ipu6_isys_fw_get(av->isys);
     655            1 :         if (ret)
     656            0 :                 goto out_pipeline_stop;
     657              : 
     658            1 :         stream = av->stream;
     659            1 :         mutex_lock(&stream->mutex);
     660            1 :         if (!stream->nr_streaming) {
     661            1 :                 ret = ipu6_isys_video_prepare_stream(av, source_entity,
     662              :                                                      nr_queues);
     663            1 :                 if (ret)
     664            0 :                         goto out_fw_close;
     665              :         }
     666              : 
     667            1 :         stream->nr_streaming++;
     668            1 :         dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,
     669              :                 stream->nr_queues);
     670              : 
     671            1 :         list_add(&aq->node, &stream->queues);
     672              : #ifdef IPU6 // Disabled for IPU4
     673              :         ipu6_isys_configure_stream_watermark(av, true);
     674              :         ipu6_isys_update_stream_watermark(av, true);
     675              : #endif
     676              : 
     677            1 :         if (stream->nr_streaming != stream->nr_queues)
     678            0 :                 goto out;
     679              : 
     680              :         bl = &__bl;
     681            1 :         ret = buffer_list_get(stream, bl);
     682            1 :         if (ret < 0) {
     683            0 :                 dev_dbg(dev,
     684              :                         "no buffer available, postponing streamon\n");
     685            0 :                 goto out;
     686              :         }
     687              : 
     688            1 :         ret = ipu6_isys_stream_start(av, bl, false);
     689            1 :         if (ret)
     690            0 :                 goto out_stream_start;
     691              : 
     692            1 : out:
     693            1 :         mutex_unlock(&stream->mutex);
     694              : 
     695            1 :         return 0;
     696              : 
     697              : out_stream_start:
     698              : #ifdef IPU6 // Disabled for IPU4
     699              :         ipu6_isys_update_stream_watermark(av, false);
     700              : #endif
     701              :         list_del(&aq->node);
     702            0 :         stream->nr_streaming--;
     703              : 
     704            0 : out_fw_close:
     705            0 :         mutex_unlock(&stream->mutex);
     706            0 :         ipu6_isys_fw_put(av->isys);
     707              : 
     708            0 : out_pipeline_stop:
     709            0 :         ipu6_isys_stream_cleanup(av);
     710              : 
     711            0 : out_return_buffers:
     712            0 :         return_buffers(aq, VB2_BUF_STATE_QUEUED);
     713              : 
     714            0 :         return ret;
     715              : }
     716              : 
     717            0 : static int restart_stream(struct ipu6_isys_video *av)
     718              : {
     719            0 :         struct device *dev = &av->isys->adev->auxdev.dev;
     720              :         struct ipu6_isys *isys = av->isys;
     721              :         int ret = 0;
     722            0 :         struct ipu6_isys_buffer_list bl;
     723              :         struct ipu6_isys_buffer_list *bl_ptr = &bl;
     724              : 
     725            0 :         dev_info(dev, "Restarting %s", av->vdev.name);
     726              : 
     727              :         lockdep_assert_held(&av->stream->mutex);
     728              : 
     729            0 :         mutex_lock(&isys->stream_mutex);
     730            0 :         if (!wait_for_no_active_buffers(av)) {
     731              :                 // When stream buffers are lost,
     732              :                 // restarting would break the existing stream
     733            0 :                 dev_err(dev, "%s stream buffers lost during restart\n",
     734              :                         av->vdev.name);
     735              :                 ret = -EIO;
     736            0 :                 goto err_unlock;
     737              :         }
     738              : 
     739            0 :         ret = ipu6_isys_video_set_streaming(av, 0, NULL);
     740            0 :         if (ret) {
     741            0 :                 dev_err(dev, "ipu6_isys_video_set_streaming(%s, 0, NULL) failed: %d\n",
     742              :                         av->vdev.name,
     743              :                         ret);
     744            0 :                 goto err_unlock;
     745              :         }
     746              : 
     747            0 :         ret = ipu6_fw_isys_close(isys);
     748            0 :         if (ret) {
     749            0 :                 dev_err(dev, "%s: fw close failed: %d", av->vdev.name, ret);
     750            0 :                 goto err_unlock;
     751              :         }
     752              : 
     753            0 :         ret = ipu6_bus_reset_device(isys->adev);
     754              : 
     755            0 :         if (ret) {
     756            0 :                 dev_err(dev, "%s: bus reset failed: %d\n", av->vdev.name, ret);
     757            0 :                 goto err_unlock;
     758              :         }
     759              : 
     760            0 :         ret = ipu6_fw_isys_open(isys);
     761            0 :         if (ret) {
     762            0 :                 dev_err(dev, "%s: fw re-open failed: %d", av->vdev.name, ret);
     763            0 :                 goto err_unlock;
     764              :         }
     765              : 
     766            0 :         ret = buffer_list_get(av->stream, &bl);
     767            0 :         if (ret < 0) {
     768            0 :                 dev_warn(&av->vdev.dev, "no buffer available, postponing streamon\n");
     769              :                 bl_ptr = NULL;
     770              :         }
     771            0 :         ret = ipu6_isys_video_set_streaming(av, 1, bl_ptr);
     772            0 :         if (ret) {
     773            0 :                 dev_err(dev, "ipu6_isys_video_set_streaming(%s, 1, %p) failed: %d\n",
     774              :                         av->vdev.name,
     775              :                         bl_ptr,
     776              :                         ret);
     777            0 :                 goto err_unlock;
     778              :         }
     779              : 
     780            0 : err_unlock:
     781              :         if (ret)
     782            0 :                 dev_info(dev, "Restarting %s failed: %d\n", av->vdev.name, ret);
     783              :         else
     784            0 :                 dev_info(dev, "Restarting %s done\n", av->vdev.name);
     785              : 
     786            0 :         mutex_unlock(&isys->stream_mutex);
     787            0 :         return ret;
     788              : }
     789              : 
     790            0 : int ipu6_isys_queue_restart_streams(struct ipu6_isys_video *av)
     791              : {
     792            0 :         struct ipu6_isys *isys = av->isys;
     793              :         int i;
     794              :         int ret = 0;
     795              :         bool stream_restarted = false;
     796              : 
     797            0 :         for (i = 0; i < NR_OF_VIDEO_DEVICE; i++) {
     798            0 :                 struct ipu6_isys_video *other_av = &isys->av[i];
     799              : 
     800            0 :                 if (av == other_av || !other_av->stream)
     801            0 :                         continue;
     802              : 
     803            0 :                 mutex_lock(&other_av->stream->mutex);
     804            0 :                 if (other_av->streaming) {
     805            0 :                         dev_info(&other_av->vdev.dev, "Restarting stream\n");
     806            0 :                         if (!WARN(stream_restarted,
     807              :                                   "Restarting > one stream not supported!"))
     808            0 :                                 ret = restart_stream(other_av);
     809              : 
     810              :                         stream_restarted = true;
     811              :                 }
     812            0 :                 mutex_unlock(&other_av->stream->mutex);
     813              : 
     814            0 :                 if (ret != 0)
     815              :                         break;
     816              :         }
     817            0 :         return ret;
     818              : }
     819              : 
     820            1 : static void stop_streaming(struct vb2_queue *q)
     821              : {
     822              :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
     823              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     824            1 :         struct ipu6_isys_stream *stream = av->stream;
     825              : 
     826            1 :         mutex_lock(&stream->mutex);
     827              : 
     828              : #ifdef IPU6 // Disabled for IPU4
     829              :         ipu6_isys_update_stream_watermark(av, false);
     830              : #endif
     831              : 
     832            1 :         mutex_lock(&av->isys->stream_mutex);
     833            1 :         if (stream->nr_streaming == stream->nr_queues && stream->streaming)
     834            1 :                 ipu6_isys_video_set_streaming(av, 0, NULL);
     835            1 :         mutex_unlock(&av->isys->stream_mutex);
     836              : 
     837            1 :         stream->nr_streaming--;
     838              :         list_del(&aq->node);
     839            1 :         stream->streaming = 0;
     840            1 :         mutex_unlock(&stream->mutex);
     841              : 
     842            1 :         ipu6_isys_stream_cleanup(av);
     843              : 
     844            1 :         return_buffers(aq, VB2_BUF_STATE_ERROR);
     845              : 
     846            1 :         ipu6_isys_fw_put(av->isys);
     847            1 : }
     848              : 
     849              : static unsigned int
     850            2 : get_sof_sequence_by_timestamp(struct ipu6_isys_stream *stream, u64 time)
     851              : {
     852            2 :         struct ipu6_isys *isys = stream->isys;
     853            2 :         struct device *dev = &isys->adev->auxdev.dev;
     854              :         unsigned int i;
     855              : 
     856              :         /*
     857              :          * The timestamp is invalid as no TSC in some FPGA platform,
     858              :          * so get the sequence from pipeline directly in this case.
     859              :          */
     860            2 :         if (time == 0)
     861            2 :                 return atomic_read(&stream->sequence) - 1;
     862              : 
     863            0 :         for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)
     864            0 :                 if (time == stream->seq[i].timestamp) {
     865            0 :                         dev_dbg(dev, "sof: using seq nr %u for ts %llu\n",
     866              :                                 stream->seq[i].sequence, time);
     867            0 :                         return stream->seq[i].sequence;
     868              :                 }
     869              : 
     870            0 :         for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)
     871            0 :                 dev_dbg(dev, "sof: sequence %u, timestamp value %llu\n",
     872              :                         stream->seq[i].sequence, stream->seq[i].timestamp);
     873              : 
     874              :         return 0;
     875              : }
     876              : 
     877            2 : static u64 get_sof_ns_delta(struct ipu6_isys_video *av, u64 timestamp)
     878              : {
     879            2 :         struct ipu6_bus_device *adev = av->isys->adev;
     880            2 :         struct ipu6_device *isp = adev->isp;
     881            2 :         u64 delta, tsc_now;
     882              : 
     883            2 :         ipu6_buttress_tsc_read(isp, &tsc_now);
     884            2 :         if (!tsc_now)
     885              :                 return 0;
     886              : 
     887            2 :         delta = tsc_now - timestamp;
     888              : 
     889            2 :         return ipu6_buttress_tsc_ticks_to_ns(delta, isp);
     890              : }
     891              : 
     892              : static void
     893            2 : ipu6_isys_buf_calc_sequence_time(struct ipu6_isys_buffer *ib, u64 time)
     894              : {
     895              :         struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     896              :         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
     897            2 :         struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
     898              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
     899            2 :         struct device *dev = &av->isys->adev->auxdev.dev;
     900            2 :         struct ipu6_isys_stream *stream = av->stream;
     901              :         u64 ns;
     902              :         u32 sequence;
     903              : 
     904            2 :         ns = ktime_get_ns() - get_sof_ns_delta(av, time);
     905            2 :         sequence = get_sof_sequence_by_timestamp(stream, time);
     906              : 
     907            2 :         vbuf->vb2_buf.timestamp = ns;
     908            2 :         vbuf->sequence = sequence;
     909              : 
     910            2 :         dev_dbg(dev, "buf: %s: buffer done, CPU-timestamp:%lld, sequence:%d\n",
     911              :                 av->vdev.name, ktime_get_ns(), sequence);
     912            2 :         dev_dbg(dev, "index:%d, vbuf timestamp:%lld\n", vb->index,
     913              :                 vbuf->vb2_buf.timestamp);
     914            2 : }
     915              : 
     916            2 : static void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib)
     917              : {
     918            2 :         struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     919              : 
     920            2 :         if (atomic_read(&ib->str2mmio_flag)) {
     921            0 :                 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
     922              :                 /*
     923              :                  * Operation on buffer is ended with error and will be reported
     924              :                  * to the userspace when it is de-queued
     925              :                  */
     926              :                 atomic_set(&ib->str2mmio_flag, 0);
     927              :         } else {
     928            2 :                 vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
     929              :         }
     930            2 : }
     931              : 
     932              : static void
     933            2 : ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id, u32 pin_addr,
     934              :                       u64 time, bool error_check)
     935              : {
     936            2 :         struct ipu6_isys_queue *aq = stream->output_pins_queue[pin_id];
     937            2 :         struct ipu6_isys *isys = stream->isys;
     938            2 :         struct device *dev = &isys->adev->auxdev.dev;
     939              :         struct ipu6_isys_buffer *ib;
     940              :         struct vb2_buffer *vb;
     941              :         unsigned long flags;
     942              :         bool first = true;
     943              :         struct vb2_v4l2_buffer *buf;
     944              : 
     945            2 :         spin_lock_irqsave(&aq->lock, flags);
     946            2 :         if (list_empty(&aq->active)) {
     947              :                 spin_unlock_irqrestore(&aq->lock, flags);
     948            0 :                 dev_err(dev, "active queue empty\n");
     949            0 :                 return;
     950              :         }
     951              : 
     952            2 :         list_for_each_entry_reverse(ib, &aq->active, head) {
     953              :                 struct ipu6_isys_video_buffer *ivb;
     954              :                 struct vb2_v4l2_buffer *vvb;
     955              :                 dma_addr_t addr;
     956              : 
     957              :                 vb = ipu6_isys_buffer_to_vb2_buffer(ib);
     958              :                 vvb = to_vb2_v4l2_buffer(vb);
     959              :                 ivb = vb2_buffer_to_ipu6_isys_video_buffer(vvb);
     960            2 :                 addr = ivb->dma_addr;
     961              : 
     962            2 :                 if (pin_addr != addr) {
     963            0 :                         if (first)
     964            0 :                                 dev_err(dev, "Unexpected buffer address %pad\n",
     965              :                                         &addr);
     966              :                         first = false;
     967            0 :                         continue;
     968              :                 }
     969              : 
     970            2 :                 if (error_check) {
     971              :                         /*
     972              :                          * Check for error message:
     973              :                          * 'IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO'
     974              :                          */
     975              :                         atomic_set(&ib->str2mmio_flag, 1);
     976              :                 }
     977            2 :                 dev_dbg(dev, "buffer: found buffer %pad\n", &addr);
     978              : 
     979              :                 buf = to_vb2_v4l2_buffer(vb);
     980            2 :                 buf->field = V4L2_FIELD_NONE;
     981              : 
     982              :                 list_del(&ib->head);
     983              :                 spin_unlock_irqrestore(&aq->lock, flags);
     984              : 
     985            2 :                 ipu6_isys_buf_calc_sequence_time(ib, time);
     986              : 
     987            2 :                 ipu6_isys_queue_buf_done(ib);
     988              : 
     989            2 :                 return;
     990              :         }
     991              : 
     992            0 :         dev_err(dev, "Failed to find a matching video buffer\n");
     993              : 
     994              :         spin_unlock_irqrestore(&aq->lock, flags);
     995              : }
     996              : 
     997            2 : void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
     998              :                                struct ipu6_fw_isys_resp_info_abi *info)
     999              : {
    1000            2 :         u64 time = (u64)info->timestamp[1] << 32 | info->timestamp[0];
    1001            2 :         bool err = info->error_info.error == IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO;
    1002              : 
    1003            2 :         ipu6_stream_buf_ready(stream, info->pin_id, info->pin.addr, time, err);
    1004            2 : }
    1005              : 
    1006              : static const struct vb2_ops ipu6_isys_queue_ops = {
    1007              :         .queue_setup = ipu6_isys_queue_setup,
    1008              :         .buf_init = ipu6_isys_buf_init,
    1009              :         .buf_prepare = ipu6_isys_buf_prepare,
    1010              :         .buf_cleanup = ipu6_isys_buf_cleanup,
    1011              :         .start_streaming = start_streaming,
    1012              :         .stop_streaming = stop_streaming,
    1013              :         .buf_queue = buf_queue,
    1014              : };
    1015              : 
    1016           31 : int ipu6_isys_queue_init(struct ipu6_isys_queue *aq)
    1017              : {
    1018           31 :         struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys;
    1019              :         struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
    1020           31 :         struct ipu6_bus_device *adev = isys->adev;
    1021              :         int ret;
    1022              : 
    1023              :         /* no support for userptr */
    1024           31 :         if (!aq->vbq.io_modes)
    1025           31 :                 aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF;
    1026              : 
    1027           31 :         aq->vbq.drv_priv = isys;
    1028           31 :         aq->vbq.ops = &ipu6_isys_queue_ops;
    1029           31 :         aq->vbq.lock = &av->mutex;
    1030           31 :         aq->vbq.mem_ops = &vb2_dma_sg_memops;
    1031           31 :         aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    1032              : #if KERNEL_VERSION(6, 10, 0) <= LINUX_VERSION_CODE
    1033           31 :         aq->vbq.min_queued_buffers = 1;
    1034              : #endif
    1035           31 :         aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
    1036              : 
    1037           31 :         ret = vb2_queue_init(&aq->vbq);
    1038           31 :         if (ret)
    1039              :                 return ret;
    1040              : 
    1041           31 :         aq->vbq.dev = &adev->isp->pdev->dev;
    1042           31 :         spin_lock_init(&aq->lock);
    1043           31 :         INIT_LIST_HEAD(&aq->active);
    1044           31 :         INIT_LIST_HEAD(&aq->incoming);
    1045              : 
    1046           31 :         return 0;
    1047              : }
        

Generated by: LCOV version 2.0-1