brintos

brintos / linux-shallow public Read only

0
0
Text · 21.3 KiB · 03dbb0e Raw
808 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013--2024 Intel Corporation4 */5#include <linux/atomic.h>6#include <linux/bug.h>7#include <linux/device.h>8#include <linux/list.h>9#include <linux/lockdep.h>10#include <linux/mutex.h>11#include <linux/spinlock.h>12#include <linux/types.h>13 14#include <media/media-entity.h>15#include <media/v4l2-subdev.h>16#include <media/videobuf2-dma-contig.h>17#include <media/videobuf2-v4l2.h>18 19#include "ipu6-bus.h"20#include "ipu6-fw-isys.h"21#include "ipu6-isys.h"22#include "ipu6-isys-video.h"23 24static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers,25		       unsigned int *num_planes, unsigned int sizes[],26		       struct device *alloc_devs[])27{28	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);29	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);30	struct device *dev = &av->isys->adev->auxdev.dev;31	u32 size = ipu6_isys_get_data_size(av);32 33	/* num_planes == 0: we're being called through VIDIOC_REQBUFS */34	if (!*num_planes) {35		sizes[0] = size;36	} else if (sizes[0] < size) {37		dev_dbg(dev, "%s: queue setup: size %u < %u\n",38			av->vdev.name, sizes[0], size);39		return -EINVAL;40	}41 42	*num_planes = 1;43 44	return 0;45}46 47static int ipu6_isys_buf_prepare(struct vb2_buffer *vb)48{49	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);50	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);51	struct device *dev = &av->isys->adev->auxdev.dev;52	u32 bytesperline = ipu6_isys_get_bytes_per_line(av);53	u32 height = ipu6_isys_get_frame_height(av);54	u32 size = ipu6_isys_get_data_size(av);55 56	dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n",57		av->vdev.name, size, vb2_plane_size(vb, 0));58 59	if (size > vb2_plane_size(vb, 0))60		return -EINVAL;61 62	vb2_set_plane_payload(vb, 0, bytesperline * height);63 64	return 0;65}66 67/*68 * Queue a buffer list back to incoming or active queues. The buffers69 * are removed from the buffer list.70 */71void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,72				 unsigned long op_flags,73				 enum vb2_buffer_state state)74{75	struct ipu6_isys_buffer *ib, *ib_safe;76	unsigned long flags;77	bool first = true;78 79	if (!bl)80		return;81 82	WARN_ON_ONCE(!bl->nbufs);83	WARN_ON_ONCE(op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE &&84		     op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING);85 86	list_for_each_entry_safe(ib, ib_safe, &bl->head, head) {87		struct ipu6_isys_video *av;88		struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);89		struct ipu6_isys_queue *aq =90			vb2_queue_to_isys_queue(vb->vb2_queue);91		struct device *dev;92 93		av = ipu6_isys_queue_to_video(aq);94		dev = &av->isys->adev->auxdev.dev;95		spin_lock_irqsave(&aq->lock, flags);96		list_del(&ib->head);97		if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE)98			list_add(&ib->head, &aq->active);99		else if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING)100			list_add_tail(&ib->head, &aq->incoming);101		spin_unlock_irqrestore(&aq->lock, flags);102 103		if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_SET_STATE)104			vb2_buffer_done(vb, state);105 106		if (first) {107			dev_dbg(dev,108				"queue buf list %p flags %lx, s %d, %d bufs\n",109				bl, op_flags, state, bl->nbufs);110			first = false;111		}112 113		bl->nbufs--;114	}115 116	WARN_ON(bl->nbufs);117}118 119/*120 * flush_firmware_streamon_fail() - Flush in cases where requests may121 * have been queued to firmware and the *firmware streamon fails for a122 * reason or another.123 */124static void flush_firmware_streamon_fail(struct ipu6_isys_stream *stream)125{126	struct device *dev = &stream->isys->adev->auxdev.dev;127	struct ipu6_isys_queue *aq;128	unsigned long flags;129 130	lockdep_assert_held(&stream->mutex);131 132	list_for_each_entry(aq, &stream->queues, node) {133		struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);134		struct ipu6_isys_buffer *ib, *ib_safe;135 136		spin_lock_irqsave(&aq->lock, flags);137		list_for_each_entry_safe(ib, ib_safe, &aq->active, head) {138			struct vb2_buffer *vb =139				ipu6_isys_buffer_to_vb2_buffer(ib);140 141			list_del(&ib->head);142			if (av->streaming) {143				dev_dbg(dev,144					"%s: queue buffer %u back to incoming\n",145					av->vdev.name, vb->index);146				/* Queue already streaming, return to driver. */147				list_add(&ib->head, &aq->incoming);148				continue;149			}150			/* Queue not yet streaming, return to user. */151			dev_dbg(dev, "%s: return %u back to videobuf2\n",152				av->vdev.name, vb->index);153			vb2_buffer_done(ipu6_isys_buffer_to_vb2_buffer(ib),154					VB2_BUF_STATE_QUEUED);155		}156		spin_unlock_irqrestore(&aq->lock, flags);157	}158}159 160/*161 * Attempt obtaining a buffer list from the incoming queues, a list of buffers162 * that contains one entry from each video buffer queue. If a buffer can't be163 * obtained from every queue, the buffers are returned back to the queue.164 */165static int buffer_list_get(struct ipu6_isys_stream *stream,166			   struct ipu6_isys_buffer_list *bl)167{168	struct device *dev = &stream->isys->adev->auxdev.dev;169	struct ipu6_isys_queue *aq;170	unsigned long flags;171	unsigned long buf_flag = IPU6_ISYS_BUFFER_LIST_FL_INCOMING;172 173	bl->nbufs = 0;174	INIT_LIST_HEAD(&bl->head);175 176	list_for_each_entry(aq, &stream->queues, node) {177		struct ipu6_isys_buffer *ib;178 179		spin_lock_irqsave(&aq->lock, flags);180		if (list_empty(&aq->incoming)) {181			spin_unlock_irqrestore(&aq->lock, flags);182			if (!list_empty(&bl->head))183				ipu6_isys_buffer_list_queue(bl, buf_flag, 0);184			return -ENODATA;185		}186 187		ib = list_last_entry(&aq->incoming,188				     struct ipu6_isys_buffer, head);189 190		dev_dbg(dev, "buffer: %s: buffer %u\n",191			ipu6_isys_queue_to_video(aq)->vdev.name,192			ipu6_isys_buffer_to_vb2_buffer(ib)->index);193		list_del(&ib->head);194		list_add(&ib->head, &bl->head);195		spin_unlock_irqrestore(&aq->lock, flags);196 197		bl->nbufs++;198	}199 200	dev_dbg(dev, "get buffer list %p, %u buffers\n", bl, bl->nbufs);201 202	return 0;203}204 205static void206ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,207				  struct ipu6_fw_isys_frame_buff_set_abi *set)208{209	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);210 211	set->output_pins[aq->fw_output].addr =212		vb2_dma_contig_plane_dma_addr(vb, 0);213	set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;214}215 216/*217 * Convert a buffer list to a isys fw ABI framebuffer set. The218 * buffer list is not modified.219 */220#define IPU6_ISYS_FRAME_NUM_THRESHOLD  (30)221void222ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,223			      struct ipu6_isys_stream *stream,224			      struct ipu6_isys_buffer_list *bl)225{226	struct ipu6_isys_buffer *ib;227 228	WARN_ON(!bl->nbufs);229 230	set->send_irq_sof = 1;231	set->send_resp_sof = 1;232	set->send_irq_eof = 0;233	set->send_resp_eof = 0;234 235	if (stream->streaming)236		set->send_irq_capture_ack = 0;237	else238		set->send_irq_capture_ack = 1;239	set->send_irq_capture_done = 0;240 241	set->send_resp_capture_ack = 1;242	set->send_resp_capture_done = 1;243	if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {244		set->send_resp_capture_ack = 0;245		set->send_resp_capture_done = 0;246	}247 248	list_for_each_entry(ib, &bl->head, head) {249		struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);250 251		ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);252	}253}254 255/* Start streaming for real. The buffer list must be available. */256static int ipu6_isys_stream_start(struct ipu6_isys_video *av,257				  struct ipu6_isys_buffer_list *bl, bool error)258{259	struct ipu6_isys_stream *stream = av->stream;260	struct device *dev = &stream->isys->adev->auxdev.dev;261	struct ipu6_isys_buffer_list __bl;262	int ret;263 264	mutex_lock(&stream->isys->stream_mutex);265	ret = ipu6_isys_video_set_streaming(av, 1, bl);266	mutex_unlock(&stream->isys->stream_mutex);267	if (ret)268		goto out_requeue;269 270	stream->streaming = 1;271 272	bl = &__bl;273 274	do {275		struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;276		struct isys_fw_msgs *msg;277		u16 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE;278 279		ret = buffer_list_get(stream, bl);280		if (ret < 0)281			break;282 283		msg = ipu6_get_fw_msg_buf(stream);284		if (!msg)285			return -ENOMEM;286 287		buf = &msg->fw_msg.frame;288		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);289		ipu6_fw_isys_dump_frame_buff_set(dev, buf,290						 stream->nr_output_pins);291		ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,292					    0);293		ret = ipu6_fw_isys_complex_cmd(stream->isys,294					       stream->stream_handle, buf,295					       msg->dma_addr, sizeof(*buf),296					       send_type);297	} while (!WARN_ON(ret));298 299	return 0;300 301out_requeue:302	if (bl && bl->nbufs)303		ipu6_isys_buffer_list_queue(bl,304					    IPU6_ISYS_BUFFER_LIST_FL_INCOMING |305					    (error ?306					    IPU6_ISYS_BUFFER_LIST_FL_SET_STATE :307					     0), error ? VB2_BUF_STATE_ERROR :308					    VB2_BUF_STATE_QUEUED);309	flush_firmware_streamon_fail(stream);310 311	return ret;312}313 314static void buf_queue(struct vb2_buffer *vb)315{316	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);317	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);318	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);319	struct ipu6_isys_video_buffer *ivb =320		vb2_buffer_to_ipu6_isys_video_buffer(vvb);321	struct ipu6_isys_buffer *ib = &ivb->ib;322	struct device *dev = &av->isys->adev->auxdev.dev;323	struct media_pipeline *media_pipe =324		media_entity_pipeline(&av->vdev.entity);325	struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;326	struct ipu6_isys_stream *stream = av->stream;327	struct ipu6_isys_buffer_list bl;328	struct isys_fw_msgs *msg;329	unsigned long flags;330	dma_addr_t dma;331	int ret;332 333	dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);334 335	dma = vb2_dma_contig_plane_dma_addr(vb, 0);336	dev_dbg(dev, "iova: iova %pad\n", &dma);337 338	spin_lock_irqsave(&aq->lock, flags);339	list_add(&ib->head, &aq->incoming);340	spin_unlock_irqrestore(&aq->lock, flags);341 342	if (!media_pipe || !vb->vb2_queue->start_streaming_called) {343		dev_dbg(dev, "media pipeline is not ready for %s\n",344			av->vdev.name);345		return;346	}347 348	mutex_lock(&stream->mutex);349 350	if (stream->nr_streaming != stream->nr_queues) {351		dev_dbg(dev, "not streaming yet, adding to incoming\n");352		goto out;353	}354 355	/*356	 * We just put one buffer to the incoming list of this queue357	 * (above). Let's see whether all queues in the pipeline would358	 * have a buffer.359	 */360	ret = buffer_list_get(stream, &bl);361	if (ret < 0) {362		dev_dbg(dev, "No buffers available\n");363		goto out;364	}365 366	msg = ipu6_get_fw_msg_buf(stream);367	if (!msg) {368		ret = -ENOMEM;369		goto out;370	}371 372	buf = &msg->fw_msg.frame;373	ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);374	ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);375 376	if (!stream->streaming) {377		ret = ipu6_isys_stream_start(av, &bl, true);378		if (ret)379			dev_err(dev, "stream start failed.\n");380		goto out;381	}382 383	/*384	 * We must queue the buffers in the buffer list to the385	 * appropriate video buffer queues BEFORE passing them to the386	 * firmware since we could get a buffer event back before we387	 * have queued them ourselves to the active queue.388	 */389	ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);390 391	ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,392				       buf, msg->dma_addr, sizeof(*buf),393				       IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);394	if (ret < 0)395		dev_err(dev, "send stream capture failed\n");396 397out:398	mutex_unlock(&stream->mutex);399}400 401static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)402{403	struct v4l2_mbus_framefmt format;404	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);405	struct device *dev = &av->isys->adev->auxdev.dev;406	struct media_pad *remote_pad =407		media_pad_remote_pad_first(av->vdev.entity.pads);408	struct v4l2_subdev *sd;409	u32 r_stream, code;410	int ret;411 412	if (!remote_pad)413		return -ENOTCONN;414 415	sd = media_entity_to_v4l2_subdev(remote_pad->entity);416	r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, remote_pad->index);417 418	ret = ipu6_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream,419					   &format);420 421	if (ret) {422		dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n",423			sd->entity.name, remote_pad->index, r_stream);424		return ret;425	}426 427	if (format.width != ipu6_isys_get_frame_width(av) ||428	    format.height != ipu6_isys_get_frame_height(av)) {429		dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n",430			ipu6_isys_get_frame_width(av),431			ipu6_isys_get_frame_height(av), format.width,432			format.height);433		return -EINVAL;434	}435 436	code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;437	if (format.code != code) {438		dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n",439			code, format.code);440		return -EINVAL;441	}442 443	return 0;444}445 446static void return_buffers(struct ipu6_isys_queue *aq,447			   enum vb2_buffer_state state)448{449	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);450	struct ipu6_isys_buffer *ib;451	bool need_reset = false;452	unsigned long flags;453 454	spin_lock_irqsave(&aq->lock, flags);455	while (!list_empty(&aq->incoming)) {456		struct vb2_buffer *vb;457 458		ib = list_first_entry(&aq->incoming, struct ipu6_isys_buffer,459				      head);460		vb = ipu6_isys_buffer_to_vb2_buffer(ib);461		list_del(&ib->head);462		spin_unlock_irqrestore(&aq->lock, flags);463 464		vb2_buffer_done(vb, state);465 466		spin_lock_irqsave(&aq->lock, flags);467	}468 469	/*470	 * Something went wrong (FW crash / HW hang / not all buffers471	 * returned from isys) if there are still buffers queued in active472	 * queue. We have to clean up places a bit.473	 */474	while (!list_empty(&aq->active)) {475		struct vb2_buffer *vb;476 477		ib = list_first_entry(&aq->active, struct ipu6_isys_buffer,478				      head);479		vb = ipu6_isys_buffer_to_vb2_buffer(ib);480 481		list_del(&ib->head);482		spin_unlock_irqrestore(&aq->lock, flags);483 484		vb2_buffer_done(vb, state);485 486		spin_lock_irqsave(&aq->lock, flags);487		need_reset = true;488	}489 490	spin_unlock_irqrestore(&aq->lock, flags);491 492	if (need_reset) {493		mutex_lock(&av->isys->mutex);494		av->isys->need_reset = true;495		mutex_unlock(&av->isys->mutex);496	}497}498 499static void ipu6_isys_stream_cleanup(struct ipu6_isys_video *av)500{501	video_device_pipeline_stop(&av->vdev);502	ipu6_isys_put_stream(av->stream);503	av->stream = NULL;504}505 506static int start_streaming(struct vb2_queue *q, unsigned int count)507{508	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);509	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);510	struct device *dev = &av->isys->adev->auxdev.dev;511	const struct ipu6_isys_pixelformat *pfmt =512		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);513	struct ipu6_isys_buffer_list __bl, *bl = NULL;514	struct ipu6_isys_stream *stream;515	struct media_entity *source_entity = NULL;516	int nr_queues, ret;517 518	dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",519		av->vdev.name, ipu6_isys_get_frame_width(av),520		ipu6_isys_get_frame_height(av), pfmt->css_pixelformat);521 522	ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues);523	if (ret < 0) {524		dev_dbg(dev, "failed to setup video\n");525		goto out_return_buffers;526	}527 528	ret = ipu6_isys_link_fmt_validate(aq);529	if (ret) {530		dev_dbg(dev,531			"%s: link format validation failed (%d)\n",532			av->vdev.name, ret);533		goto out_pipeline_stop;534	}535 536	ret = ipu6_isys_fw_open(av->isys);537	if (ret)538		goto out_pipeline_stop;539 540	stream = av->stream;541	mutex_lock(&stream->mutex);542	if (!stream->nr_streaming) {543		ret = ipu6_isys_video_prepare_stream(av, source_entity,544						     nr_queues);545		if (ret)546			goto out_fw_close;547	}548 549	stream->nr_streaming++;550	dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,551		stream->nr_queues);552 553	list_add(&aq->node, &stream->queues);554	ipu6_isys_configure_stream_watermark(av, true);555	ipu6_isys_update_stream_watermark(av, true);556 557	if (stream->nr_streaming != stream->nr_queues)558		goto out;559 560	bl = &__bl;561	ret = buffer_list_get(stream, bl);562	if (ret < 0) {563		dev_warn(dev, "no buffer available, DRIVER BUG?\n");564		goto out;565	}566 567	ret = ipu6_isys_stream_start(av, bl, false);568	if (ret)569		goto out_stream_start;570 571out:572	mutex_unlock(&stream->mutex);573 574	return 0;575 576out_stream_start:577	ipu6_isys_update_stream_watermark(av, false);578	list_del(&aq->node);579	stream->nr_streaming--;580 581out_fw_close:582	mutex_unlock(&stream->mutex);583	ipu6_isys_fw_close(av->isys);584 585out_pipeline_stop:586	ipu6_isys_stream_cleanup(av);587 588out_return_buffers:589	return_buffers(aq, VB2_BUF_STATE_QUEUED);590 591	return ret;592}593 594static void stop_streaming(struct vb2_queue *q)595{596	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);597	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);598	struct ipu6_isys_stream *stream = av->stream;599 600	mutex_lock(&stream->mutex);601 602	ipu6_isys_update_stream_watermark(av, false);603 604	mutex_lock(&av->isys->stream_mutex);605	if (stream->nr_streaming == stream->nr_queues && stream->streaming)606		ipu6_isys_video_set_streaming(av, 0, NULL);607	mutex_unlock(&av->isys->stream_mutex);608 609	stream->nr_streaming--;610	list_del(&aq->node);611	stream->streaming = 0;612	mutex_unlock(&stream->mutex);613 614	ipu6_isys_stream_cleanup(av);615 616	return_buffers(aq, VB2_BUF_STATE_ERROR);617 618	ipu6_isys_fw_close(av->isys);619}620 621static unsigned int622get_sof_sequence_by_timestamp(struct ipu6_isys_stream *stream,623			      struct ipu6_fw_isys_resp_info_abi *info)624{625	u64 time = (u64)info->timestamp[1] << 32 | info->timestamp[0];626	struct ipu6_isys *isys = stream->isys;627	struct device *dev = &isys->adev->auxdev.dev;628	unsigned int i;629 630	/*631	 * The timestamp is invalid as no TSC in some FPGA platform,632	 * so get the sequence from pipeline directly in this case.633	 */634	if (time == 0)635		return atomic_read(&stream->sequence) - 1;636 637	for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)638		if (time == stream->seq[i].timestamp) {639			dev_dbg(dev, "sof: using seq nr %u for ts %llu\n",640				stream->seq[i].sequence, time);641			return stream->seq[i].sequence;642		}643 644	for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)645		dev_dbg(dev, "sof: sequence %u, timestamp value %llu\n",646			stream->seq[i].sequence, stream->seq[i].timestamp);647 648	return 0;649}650 651static u64 get_sof_ns_delta(struct ipu6_isys_video *av,652			    struct ipu6_fw_isys_resp_info_abi *info)653{654	struct ipu6_bus_device *adev = av->isys->adev;655	struct ipu6_device *isp = adev->isp;656	u64 delta, tsc_now;657 658	ipu6_buttress_tsc_read(isp, &tsc_now);659	if (!tsc_now)660		return 0;661 662	delta = tsc_now - ((u64)info->timestamp[1] << 32 | info->timestamp[0]);663 664	return ipu6_buttress_tsc_ticks_to_ns(delta, isp);665}666 667void ipu6_isys_buf_calc_sequence_time(struct ipu6_isys_buffer *ib,668				      struct ipu6_fw_isys_resp_info_abi *info)669{670	struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);671	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);672	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);673	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);674	struct device *dev = &av->isys->adev->auxdev.dev;675	struct ipu6_isys_stream *stream = av->stream;676	u64 ns;677	u32 sequence;678 679	ns = ktime_get_ns() - get_sof_ns_delta(av, info);680	sequence = get_sof_sequence_by_timestamp(stream, info);681 682	vbuf->vb2_buf.timestamp = ns;683	vbuf->sequence = sequence;684 685	dev_dbg(dev, "buf: %s: buffer done, CPU-timestamp:%lld, sequence:%d\n",686		av->vdev.name, ktime_get_ns(), sequence);687	dev_dbg(dev, "index:%d, vbuf timestamp:%lld\n", vb->index,688		vbuf->vb2_buf.timestamp);689}690 691void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib)692{693	struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);694 695	if (atomic_read(&ib->str2mmio_flag)) {696		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);697		/*698		 * Operation on buffer is ended with error and will be reported699		 * to the userspace when it is de-queued700		 */701		atomic_set(&ib->str2mmio_flag, 0);702	} else {703		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);704	}705}706 707void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,708			       struct ipu6_fw_isys_resp_info_abi *info)709{710	struct ipu6_isys_queue *aq = stream->output_pins[info->pin_id].aq;711	struct ipu6_isys *isys = stream->isys;712	struct device *dev = &isys->adev->auxdev.dev;713	struct ipu6_isys_buffer *ib;714	struct vb2_buffer *vb;715	unsigned long flags;716	bool first = true;717	struct vb2_v4l2_buffer *buf;718 719	spin_lock_irqsave(&aq->lock, flags);720	if (list_empty(&aq->active)) {721		spin_unlock_irqrestore(&aq->lock, flags);722		dev_err(dev, "active queue empty\n");723		return;724	}725 726	list_for_each_entry_reverse(ib, &aq->active, head) {727		dma_addr_t addr;728 729		vb = ipu6_isys_buffer_to_vb2_buffer(ib);730		addr = vb2_dma_contig_plane_dma_addr(vb, 0);731 732		if (info->pin.addr != addr) {733			if (first)734				dev_err(dev, "Unexpected buffer address %pad\n",735					&addr);736			first = false;737			continue;738		}739 740		if (info->error_info.error ==741		    IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO) {742			/*743			 * Check for error message:744			 * 'IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO'745			 */746			atomic_set(&ib->str2mmio_flag, 1);747		}748		dev_dbg(dev, "buffer: found buffer %pad\n", &addr);749 750		buf = to_vb2_v4l2_buffer(vb);751		buf->field = V4L2_FIELD_NONE;752 753		list_del(&ib->head);754		spin_unlock_irqrestore(&aq->lock, flags);755 756		ipu6_isys_buf_calc_sequence_time(ib, info);757 758		ipu6_isys_queue_buf_done(ib);759 760		return;761	}762 763	dev_err(dev, "Failed to find a matching video buffer");764 765	spin_unlock_irqrestore(&aq->lock, flags);766}767 768static const struct vb2_ops ipu6_isys_queue_ops = {769	.queue_setup = queue_setup,770	.wait_prepare = vb2_ops_wait_prepare,771	.wait_finish = vb2_ops_wait_finish,772	.buf_prepare = ipu6_isys_buf_prepare,773	.start_streaming = start_streaming,774	.stop_streaming = stop_streaming,775	.buf_queue = buf_queue,776};777 778int ipu6_isys_queue_init(struct ipu6_isys_queue *aq)779{780	struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys;781	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);782	int ret;783 784	/* no support for userptr */785	if (!aq->vbq.io_modes)786		aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF;787 788	aq->vbq.drv_priv = aq;789	aq->vbq.ops = &ipu6_isys_queue_ops;790	aq->vbq.lock = &av->mutex;791	aq->vbq.mem_ops = &vb2_dma_contig_memops;792	aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;793	aq->vbq.min_queued_buffers = 1;794	aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;795 796	ret = vb2_queue_init(&aq->vbq);797	if (ret)798		return ret;799 800	aq->dev = &isys->adev->auxdev.dev;801	aq->vbq.dev = &isys->adev->auxdev.dev;802	spin_lock_init(&aq->lock);803	INIT_LIST_HEAD(&aq->active);804	INIT_LIST_HEAD(&aq->incoming);805 806	return 0;807}808