Re: [PATCH v6 23/28] media: iris: add support for drain sequence

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 20/11/2024 15:46, Dikshita Agarwal wrote:
> handle the V4L2_DEC_CMD_STOP by initiating drain sequence to firmware.
> Process and decode all OUTPUT buffers queued by the client before the
> VIDIOC_DECODER_CMD() was issued and mark the last buffer with
> V4L2_BUF_FLAG_LAST flag. Decoder is stopped after processing the last
> buffer.
> 
> Resume the decoder when one of below are issued by client:
> - V4L2_DEC_CMD_START
> - pair of VIDIOC_STREAMOFF() and VIDIOC_STREAMON() on the CAPTURE queue
> - pair of VIDIOC_STREAMOFF() and VIDIOC_STREAMON() on the OUTPUT queue
> 
> Add the handling to resume decoding when client issues
> V4L2_DEC_CMD_START to resume decoding after source change is detected.
> 
> Signed-off-by: Dikshita Agarwal <quic_dikshita@xxxxxxxxxxx>
> ---
>  drivers/media/platform/qcom/iris/iris_hfi_common.h |  2 +
>  .../platform/qcom/iris/iris_hfi_gen1_command.c     | 13 ++++
>  .../platform/qcom/iris/iris_hfi_gen1_defines.h     |  1 +
>  .../platform/qcom/iris/iris_hfi_gen1_response.c    | 15 ++++
>  .../platform/qcom/iris/iris_hfi_gen2_command.c     | 43 ++++++++++
>  .../platform/qcom/iris/iris_hfi_gen2_defines.h     |  2 +
>  .../platform/qcom/iris/iris_hfi_gen2_response.c    | 46 ++++++++++-
>  drivers/media/platform/qcom/iris/iris_state.c      | 68 ++++++++++++++++
>  drivers/media/platform/qcom/iris/iris_state.h      | 13 +++-
>  drivers/media/platform/qcom/iris/iris_vb2.c        |  6 +-
>  drivers/media/platform/qcom/iris/iris_vdec.c       | 91 +++++++++++++++++++++-
>  drivers/media/platform/qcom/iris/iris_vdec.h       |  2 +
>  drivers/media/platform/qcom/iris/iris_vidc.c       | 37 +++++++++
>  13 files changed, 331 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h
> index 8e14a61c9be4..b2c541367fc6 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h
> @@ -121,6 +121,8 @@ struct iris_hfi_command_ops {
>  	int (*session_pause)(struct iris_inst *inst, u32 plane);
>  	int (*session_resume_drc)(struct iris_inst *inst, u32 plane);
>  	int (*session_stop)(struct iris_inst *inst, u32 plane);
> +	int (*session_drain)(struct iris_inst *inst, u32 plane);
> +	int (*session_resume_drain)(struct iris_inst *inst, u32 plane);
>  	int (*session_close)(struct iris_inst *inst);
>  };
>  
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> index e0cb75a112e3..e1fbbb3c196d 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> @@ -368,6 +368,18 @@ static int iris_hfi_gen1_session_unset_buffers(struct iris_inst *inst, struct ir
>  	return ret;
>  }
>  
> +static int iris_hfi_gen1_session_drain(struct iris_inst *inst, u32 plane)
> +{
> +	struct hfi_session_empty_buffer_compressed_pkt ip_pkt = {0};
> +
> +	ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt);
> +	ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER;
> +	ip_pkt.shdr.session_id = inst->session_id;
> +	ip_pkt.flags = HFI_BUFFERFLAG_EOS;
> +
> +	return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size);
> +}
> +
>  static int
>  iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *packet,
>  					  struct iris_inst *inst, u32 ptype, void *pdata)
> @@ -789,6 +801,7 @@ static const struct iris_hfi_command_ops iris_hfi_gen1_command_ops = {
>  	.session_release_buf = iris_hfi_gen1_session_unset_buffers,
>  	.session_resume_drc = iris_hfi_gen1_session_continue,
>  	.session_stop = iris_hfi_gen1_session_stop,
> +	.session_drain = iris_hfi_gen1_session_drain,
>  	.session_close = iris_hfi_gen1_session_close,
>  };
>  
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
> index c40e0a28b21f..9f246816a286 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
> @@ -49,6 +49,7 @@
>  #define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES 0x1000002
>  #define HFI_EVENT_SESSION_SEQUENCE_CHANGED			   0x1000003
>  
> +#define HFI_BUFFERFLAG_EOS				0x00000001
>  #define HFI_BUFFERFLAG_TIMESTAMPINVALID			0x00000100
>  
>  #define HFI_FLUSH_OUTPUT				0x1000002
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> index 3a47d9f39695..b72d503dd740 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> @@ -386,6 +386,7 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet)
>  	struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt = packet;
>  	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
>  	struct v4l2_m2m_buffer *m2m_buffer, *n;
> +	struct hfi_session_flush_pkt flush_pkt;
>  	u32 timestamp_hi = pkt->time_stamp_hi;
>  	u32 timestamp_lo = pkt->time_stamp_lo;
>  	struct iris_core *core = inst->core;
> @@ -394,11 +395,25 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet)
>  	u32 output_tag = pkt->output_tag;
>  	struct iris_buffer *buf, *iter;
>  	struct iris_buffers *buffers;
> +	u32 hfi_flags = pkt->flags;
>  	u32 offset = pkt->offset;
>  	u64 timestamp_us = 0;
>  	bool found = false;
>  	u32 flags = 0;
>  
> +	if ((hfi_flags & HFI_BUFFERFLAG_EOS) && !filled_len) {
> +		reinit_completion(&inst->flush_completion);
> +
> +		flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt);
> +		flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH;
> +		flush_pkt.shdr.session_id = inst->session_id;
> +		flush_pkt.flush_type = HFI_FLUSH_OUTPUT;
> +		iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size);
> +		iris_inst_sub_state_change_drain_last(inst);
> +
> +		return;
> +	}
> +
>  	if (iris_split_mode_enabled(inst) && pkt->stream_id == 0) {
>  		buffers = &inst->buffers[BUF_DPB];
>  		if (!buffers)
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
> index 8efc6a70a57a..a908b41e2868 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
> @@ -774,6 +774,47 @@ static int iris_hfi_gen2_session_resume_drc(struct iris_inst *inst, u32 plane)
>  					inst_hfi_gen2->packet->size);
>  }
>  
> +static int iris_hfi_gen2_session_resume_drain(struct iris_inst *inst, u32 plane)
> +{
> +	struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
> +	u32 payload = HFI_CMD_DRAIN;
> +
> +	iris_hfi_gen2_packet_session_command(inst,
> +					     HFI_CMD_RESUME,
> +					     (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
> +					     HFI_HOST_FLAGS_INTR_REQUIRED),
> +					     iris_hfi_gen2_get_port(plane),
> +					     inst->session_id,
> +					     HFI_PAYLOAD_U32,
> +					     &payload,
> +					     sizeof(u32));
> +
> +	return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
> +					inst_hfi_gen2->packet->size);
> +}
> +
> +static int iris_hfi_gen2_session_drain(struct iris_inst *inst, u32 plane)
> +{
> +	struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
> +
> +	if (!V4L2_TYPE_IS_OUTPUT(plane))
> +		return 0;
> +
> +	iris_hfi_gen2_packet_session_command(inst,
> +					     HFI_CMD_DRAIN,
> +					     (HFI_HOST_FLAGS_RESPONSE_REQUIRED |
> +					     HFI_HOST_FLAGS_INTR_REQUIRED |
> +					     HFI_HOST_FLAGS_NON_DISCARDABLE),
> +					     iris_hfi_gen2_get_port(plane),
> +					     inst->session_id,
> +					     HFI_PAYLOAD_NONE,
> +					     NULL,
> +					     0);
> +
> +	return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
> +					inst_hfi_gen2->packet->size);
> +}
> +
>  static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type buffer_type)
>  {
>  	switch (buffer_type) {
> @@ -900,6 +941,8 @@ static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = {
>  	.session_pause = iris_hfi_gen2_session_pause,
>  	.session_resume_drc = iris_hfi_gen2_session_resume_drc,
>  	.session_stop = iris_hfi_gen2_session_stop,
> +	.session_drain = iris_hfi_gen2_session_drain,
> +	.session_resume_drain = iris_hfi_gen2_session_resume_drain,
>  	.session_close = iris_hfi_gen2_session_close,
>  };
>  
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
> index d759b7355711..214e2a579b8e 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
> @@ -17,6 +17,7 @@
>  #define HFI_CMD_CLOSE				0x01000004
>  #define HFI_CMD_START				0x01000005
>  #define HFI_CMD_STOP				0x01000006
> +#define HFI_CMD_DRAIN				0x01000007
>  #define HFI_CMD_RESUME				0x01000008
>  #define HFI_CMD_BUFFER				0x01000009
>  #define HFI_CMD_SUBSCRIBE_MODE			0x0100000B
> @@ -79,6 +80,7 @@
>  #define HFI_INFO_UNSUPPORTED			0x06000001
>  #define HFI_INFO_DATA_CORRUPT			0x06000002
>  #define HFI_INFO_BUFFER_OVERFLOW		0x06000004
> +#define HFI_INFO_HFI_FLAG_DRAIN_LAST		0x06000006
>  #define HFI_INFO_HFI_FLAG_PSC_LAST		0x06000007
>  #define HFI_INFORMATION_END			0x06FFFFFF
>  
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
> index 28857a7a5112..f043e74866bc 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c
> @@ -201,6 +201,10 @@ static int iris_hfi_gen2_handle_session_info(struct iris_inst *inst,
>  		info = "buffer overflow";
>  		inst_hfi_gen2->hfi_frame_info.overflow = 1;
>  		break;
> +	case HFI_INFO_HFI_FLAG_DRAIN_LAST:
> +		info = "drain last flag";
> +		ret = iris_inst_sub_state_change_drain_last(inst);
> +		break;
>  	case HFI_INFO_HFI_FLAG_PSC_LAST:
>  		info = "drc last flag";
>  		ret = iris_inst_sub_state_change_drc_last(inst);
> @@ -334,6 +338,12 @@ static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst,
>  	bool found = false;
>  	int ret;
>  
> +	if (hfi_buffer->flags & HFI_BUF_FW_FLAG_LAST) {
> +		ret = iris_inst_sub_state_change_drain_last(inst);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	if (hfi_buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) {
>  		ret = iris_inst_sub_state_change_drc_last(inst);
>  		if (ret)
> @@ -422,6 +432,21 @@ static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst,
>  	return ret;
>  }
>  
> +static int iris_hfi_gen2_handle_session_stop(struct iris_inst *inst,
> +					     struct iris_hfi_packet *pkt)
> +{
> +	int ret = 0;
> +
> +	if (pkt->port == HFI_PORT_RAW)
> +		ret = iris_inst_sub_state_change_pause(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +	else if (pkt->port == HFI_PORT_BITSTREAM)
> +		ret = iris_inst_sub_state_change_pause(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +
> +	complete(&inst->completion);
> +
> +	return ret;
> +}
> +
>  static int iris_hfi_gen2_handle_session_buffer(struct iris_inst *inst,
>  					       struct iris_hfi_packet *pkt)
>  {
> @@ -450,6 +475,22 @@ static int iris_hfi_gen2_handle_session_buffer(struct iris_inst *inst,
>  		return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer);
>  }
>  
> +static int iris_hfi_gen2_handle_session_drain(struct iris_inst *inst,
> +					      struct iris_hfi_packet *pkt)
> +{
> +	int ret = 0;
> +
> +	if (!(pkt->flags & HFI_FW_FLAGS_SUCCESS)) {
> +		iris_inst_change_state(inst, IRIS_INST_ERROR);
> +		return 0;
> +	}
> +
> +	if (inst->sub_state & IRIS_INST_SUB_DRAIN)
> +		ret = iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_INPUT_PAUSE);
> +
> +	return ret;
> +}
> +
>  static void iris_hfi_gen2_read_input_subcr_params(struct iris_inst *inst)
>  {
>  	struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
> @@ -569,7 +610,7 @@ static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst,
>  		iris_hfi_gen2_handle_session_close(inst, pkt);
>  		break;
>  	case HFI_CMD_STOP:
> -		complete(&inst->completion);
> +		iris_hfi_gen2_handle_session_stop(inst, pkt);
>  		break;
>  	case HFI_CMD_BUFFER:
>  		ret = iris_hfi_gen2_handle_session_buffer(inst, pkt);
> @@ -577,6 +618,9 @@ static int iris_hfi_gen2_handle_session_command(struct iris_inst *inst,
>  	case HFI_CMD_SETTINGS_CHANGE:
>  		ret = iris_hfi_gen2_handle_src_change(inst, pkt);
>  		break;
> +	case HFI_CMD_DRAIN:
> +		ret = iris_hfi_gen2_handle_session_drain(inst, pkt);
> +		break;
>  	default:
>  		break;
>  	}
> diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c
> index aad7e734d5c8..f12306e735ec 100644
> --- a/drivers/media/platform/qcom/iris/iris_state.c
> +++ b/drivers/media/platform/qcom/iris/iris_state.c
> @@ -3,6 +3,8 @@
>   * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
>   */
>  
> +#include <media/v4l2-mem2mem.h>
> +
>  #include "iris_instance.h"
>  
>  static bool iris_allow_inst_state_change(struct iris_inst *inst,
> @@ -148,6 +150,21 @@ int iris_inst_sub_state_change_drc(struct iris_inst *inst)
>  	return iris_inst_change_sub_state(inst, 0, set_sub_state);
>  }
>  
> +int iris_inst_sub_state_change_drain_last(struct iris_inst *inst)
> +{
> +	enum iris_inst_sub_state set_sub_state;
> +
> +	if (inst->sub_state & IRIS_INST_SUB_DRAIN_LAST)
> +		return -EINVAL;
> +
> +	if (!(inst->sub_state & IRIS_INST_SUB_DRAIN))
> +		return -EINVAL;
> +
> +	set_sub_state = IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE;
> +
> +	return iris_inst_change_sub_state(inst, 0, set_sub_state);
> +}
> +
>  int iris_inst_sub_state_change_drc_last(struct iris_inst *inst)
>  {
>  	enum iris_inst_sub_state set_sub_state;
> @@ -166,3 +183,54 @@ int iris_inst_sub_state_change_drc_last(struct iris_inst *inst)
>  
>  	return iris_inst_change_sub_state(inst, 0, set_sub_state);
>  }
> +
> +int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane)
> +{
> +	enum iris_inst_sub_state set_sub_state;
> +
> +	if (V4L2_TYPE_IS_OUTPUT(plane)) {
> +		if (inst->sub_state & IRIS_INST_SUB_DRC &&
> +		    !(inst->sub_state & IRIS_INST_SUB_DRC_LAST))
> +			return -EINVAL;
> +
> +		if (inst->sub_state & IRIS_INST_SUB_DRAIN &&
> +		    !(inst->sub_state & IRIS_INST_SUB_DRAIN_LAST))
> +			return -EINVAL;
> +
> +		set_sub_state = IRIS_INST_SUB_INPUT_PAUSE;
> +	} else {
> +		set_sub_state = IRIS_INST_SUB_OUTPUT_PAUSE;
> +	}
> +
> +	return iris_inst_change_sub_state(inst, 0, set_sub_state);
> +}
> +
> +static inline bool iris_drc_pending(struct iris_inst *inst)
> +{
> +	return inst->sub_state & IRIS_INST_SUB_DRC &&
> +		inst->sub_state & IRIS_INST_SUB_DRC_LAST;
> +}
> +
> +static inline bool iris_drain_pending(struct iris_inst *inst)
> +{
> +	return inst->sub_state & IRIS_INST_SUB_DRAIN &&
> +		inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
> +}
> +
> +bool iris_allow_cmd(struct iris_inst *inst, u32 cmd)
> +{
> +	struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx);
> +	struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
> +
> +	if (cmd == V4L2_DEC_CMD_START) {
> +		if (vb2_is_streaming(src_q) || vb2_is_streaming(dst_q))
> +			if (iris_drc_pending(inst) || iris_drain_pending(inst))
> +				return true;
> +	} else if (cmd == V4L2_DEC_CMD_STOP) {
> +		if (vb2_is_streaming(src_q))
> +			if (inst->sub_state != IRIS_INST_SUB_DRAIN)
> +				return true;
> +	}
> +
> +	return false;
> +}
> diff --git a/drivers/media/platform/qcom/iris/iris_state.h b/drivers/media/platform/qcom/iris/iris_state.h
> index 11236001c1cc..bf645f6f879c 100644
> --- a/drivers/media/platform/qcom/iris/iris_state.h
> +++ b/drivers/media/platform/qcom/iris/iris_state.h
> @@ -104,6 +104,9 @@ enum iris_inst_state {
>   *		      sent to client.
>   * IRIS_INST_SUB_DRC_LAST: indicates last buffer is received from firmware
>   *                         as part of source change.
> + * IRIS_INST_SUB_DRAIN: indicates drain is in progress.
> + * IRIS_INST_SUB_DRAIN_LAST: indicates last buffer is received from firmware
> + *                           as part of drain sequence.
>   * IRIS_INST_SUB_INPUT_PAUSE: source change is received form firmware. This
>   *                            indicates that firmware is paused to process
>   *                            any further input frames.
> @@ -115,8 +118,10 @@ enum iris_inst_sub_state {
>  	IRIS_INST_SUB_FIRST_IPSC	= BIT(0),
>  	IRIS_INST_SUB_DRC		= BIT(1),
>  	IRIS_INST_SUB_DRC_LAST		= BIT(2),
> -	IRIS_INST_SUB_INPUT_PAUSE	= BIT(3),
> -	IRIS_INST_SUB_OUTPUT_PAUSE	= BIT(4),
> +	IRIS_INST_SUB_DRAIN		= BIT(3),
> +	IRIS_INST_SUB_DRAIN_LAST	= BIT(4),
> +	IRIS_INST_SUB_INPUT_PAUSE	= BIT(5),
> +	IRIS_INST_SUB_OUTPUT_PAUSE	= BIT(6),
>  };
>  
>  int iris_inst_change_state(struct iris_inst *inst,
> @@ -124,9 +129,13 @@ int iris_inst_change_state(struct iris_inst *inst,
>  int iris_inst_change_sub_state(struct iris_inst *inst,
>  			       enum iris_inst_sub_state clear_sub_state,
>  			       enum iris_inst_sub_state set_sub_state);
> +
>  int iris_inst_state_change_streamon(struct iris_inst *inst, u32 plane);
>  int iris_inst_state_change_streamoff(struct iris_inst *inst, u32 plane);
>  int iris_inst_sub_state_change_drc(struct iris_inst *inst);
> +int iris_inst_sub_state_change_drain_last(struct iris_inst *inst);
>  int iris_inst_sub_state_change_drc_last(struct iris_inst *inst);
> +int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane);
> +bool iris_allow_cmd(struct iris_inst *inst, u32 cmd);
>  
>  #endif
> diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c
> index 1ff2017673ed..f51fd6929f64 100644
> --- a/drivers/media/platform/qcom/iris/iris_vb2.c
> +++ b/drivers/media/platform/qcom/iris/iris_vb2.c
> @@ -206,8 +206,10 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2)
>  	}
>  
>  	if (V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) {
> -		if (inst->sub_state & IRIS_INST_SUB_DRC &&
> -		    inst->sub_state & IRIS_INST_SUB_DRC_LAST) {
> +		if ((inst->sub_state & IRIS_INST_SUB_DRC &&
> +		     inst->sub_state & IRIS_INST_SUB_DRC_LAST) ||
> +		    (inst->sub_state & IRIS_INST_SUB_DRAIN &&
> +		     inst->sub_state & IRIS_INST_SUB_DRAIN_LAST)) {
>  			vbuf->flags |= V4L2_BUF_FLAG_LAST;
>  			vbuf->sequence = inst->sequence_cap++;
>  			vbuf->field = V4L2_FIELD_NONE;
> diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c
> index 012ae9f7f9a8..1ae0bb4830de 100644
> --- a/drivers/media/platform/qcom/iris/iris_vdec.c
> +++ b/drivers/media/platform/qcom/iris/iris_vdec.c
> @@ -374,6 +374,7 @@ static int iris_vdec_process_streamon_input(struct iris_inst *inst)
>  	}
>  
>  	if (inst->sub_state & IRIS_INST_SUB_DRC ||
> +	    inst->sub_state & IRIS_INST_SUB_DRAIN ||
>  	    inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) {
>  		if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) {
>  			if (hfi_ops->session_pause) {
> @@ -425,15 +426,20 @@ int iris_vdec_streamon_input(struct iris_inst *inst)
>  static int iris_vdec_process_streamon_output(struct iris_inst *inst)
>  {
>  	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
> +	bool drain_active = false, drc_active = false;
>  	enum iris_inst_sub_state clear_sub_state = 0;
> -	bool drc_active = false;
>  	int ret = 0;
>  
> +	drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN &&
> +		inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
> +
>  	drc_active = inst->sub_state & IRIS_INST_SUB_DRC &&
>  		inst->sub_state & IRIS_INST_SUB_DRC_LAST;
>  
>  	if (drc_active)
>  		clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
> +	else if (drain_active)
> +		clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
>  
>  	if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
>  		ret = iris_alloc_and_queue_input_int_bufs(inst);
> @@ -449,8 +455,12 @@ static int iris_vdec_process_streamon_output(struct iris_inst *inst)
>  
>  	if (inst->state == IRIS_INST_INPUT_STREAMING &&
>  	    inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
> -		ret = hfi_ops->session_resume_drc(inst,
> -						  V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +		if (!drain_active)
> +			ret = hfi_ops->session_resume_drc(inst,
> +							  V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +		else if (hfi_ops->session_resume_drain)
> +			ret = hfi_ops->session_resume_drain(inst,
> +							    V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
>  		if (ret)
>  			return ret;
>  		clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
> @@ -568,3 +578,78 @@ int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf)
>  
>  	return iris_queue_buffer(inst, buf);
>  }
> +
> +int iris_vdec_start_cmd(struct iris_inst *inst)
> +{
> +	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
> +	enum iris_inst_sub_state clear_sub_state = 0;
> +	struct vb2_queue *dst_vq;
> +	int ret;
> +
> +	dst_vq = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
> +
> +	if (inst->sub_state & IRIS_INST_SUB_DRC &&
> +	    inst->sub_state & IRIS_INST_SUB_DRC_LAST) {
> +		vb2_clear_last_buffer_dequeued(dst_vq);
> +		clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
> +
> +		if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
> +			ret = hfi_ops->session_resume_drc(inst,
> +							  V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +			if (ret)
> +				return ret;
> +			clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
> +		}
> +		if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) {
> +			ret = hfi_ops->session_resume_drc(inst,
> +							  V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +			if (ret)
> +				return ret;
> +			clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
> +		}
> +	} else if (inst->sub_state & IRIS_INST_SUB_DRAIN &&
> +		   inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) {
> +		vb2_clear_last_buffer_dequeued(dst_vq);
> +		clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
> +		if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
> +			if (hfi_ops->session_resume_drain) {
> +				ret =
> +				hfi_ops->session_resume_drain(inst,
> +							      V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +				if (ret)
> +					return ret;
> +			}
> +
> +			clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
> +		}
> +		if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) {
> +			if (hfi_ops->session_resume_drain) {
> +				ret =
> +				hfi_ops->session_resume_drain(inst,
> +							      V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +				if (ret)
> +					return ret;
> +			}
> +
> +			clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
> +		}
> +	} else {
> +		dev_err(inst->core->dev, "start called before receiving last_flag\n");
> +		iris_inst_change_state(inst, IRIS_INST_ERROR);
> +		return -EBUSY;
> +	}
> +
> +	return iris_inst_change_sub_state(inst, clear_sub_state, 0);
> +}
> +
> +int iris_vdec_stop_cmd(struct iris_inst *inst)
> +{
> +	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
> +	int ret;
> +
> +	ret = hfi_ops->session_drain(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +	if (ret)
> +		return ret;
> +
> +	return iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_DRAIN);
> +}
> diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h
> index dfcc2089a1ef..b24932dc511a 100644
> --- a/drivers/media/platform/qcom/iris/iris_vdec.h
> +++ b/drivers/media/platform/qcom/iris/iris_vdec.h
> @@ -18,6 +18,8 @@ void iris_vdec_src_change(struct iris_inst *inst);
>  int iris_vdec_streamon_input(struct iris_inst *inst);
>  int iris_vdec_streamon_output(struct iris_inst *inst);
>  int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf);
> +int iris_vdec_start_cmd(struct iris_inst *inst);
> +int iris_vdec_stop_cmd(struct iris_inst *inst);
>  int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane);
>  
>  #endif
> diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
> index 8a1c35f99538..2281b291b736 100644
> --- a/drivers/media/platform/qcom/iris/iris_vidc.c
> +++ b/drivers/media/platform/qcom/iris/iris_vidc.c
> @@ -365,6 +365,41 @@ static int iris_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs
>  	return iris_vdec_subscribe_event(inst, sub);
>  }
>  
> +static int iris_dec_cmd(struct file *filp, void *fh,
> +			struct v4l2_decoder_cmd *dec)
> +{
> +	struct iris_inst *inst = iris_get_inst(filp, NULL);
> +	int ret = 0;
> +
> +	mutex_lock(&inst->lock);
> +

I would expect to see a call to v4l2_m2m_ioctl_decoder_cmd here since
that deals with some of the LAST flag handling and internal m2m state.

It could be that you handle this manually elsewhere, but I am not certain
about that.

Regards,

	Hans

> +	if (dec->cmd != V4L2_DEC_CMD_START &&
> +	    dec->cmd != V4L2_DEC_CMD_STOP) {
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
> +
> +	if (inst->state == IRIS_INST_DEINIT)
> +		goto unlock;
> +
> +	if (!iris_allow_cmd(inst, dec->cmd)) {
> +		ret = -EBUSY;
> +		goto unlock;
> +	}
> +
> +	if (dec->cmd == V4L2_DEC_CMD_START)
> +		ret = iris_vdec_start_cmd(inst);
> +	else if (dec->cmd == V4L2_DEC_CMD_STOP)
> +		ret = iris_vdec_stop_cmd(inst);
> +	else
> +		ret = -EINVAL;
> +
> +unlock:
> +	mutex_unlock(&inst->lock);
> +
> +	return ret;
> +}
> +
>  static struct v4l2_file_operations iris_v4l2_file_ops = {
>  	.owner                          = THIS_MODULE,
>  	.open                           = iris_open,
> @@ -408,6 +443,8 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = {
>  	.vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
>  	.vidioc_streamon                = v4l2_m2m_ioctl_streamon,
>  	.vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
> +	.vidioc_try_decoder_cmd         = v4l2_m2m_ioctl_try_decoder_cmd,
> +	.vidioc_decoder_cmd             = iris_dec_cmd,
>  };
>  
>  void iris_init_ops(struct iris_core *core)
> 





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux