xref: /linux/drivers/media/platform/qcom/iris/iris_common.c (revision 92e007ca5ab687b0612accb54acee7ed4adcdb0c)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5 
6 #include <media/v4l2-mem2mem.h>
7 
8 #include "iris_common.h"
9 #include "iris_ctrls.h"
10 #include "iris_instance.h"
11 #include "iris_power.h"
12 
13 int iris_process_streamon_input(struct iris_inst *inst)
14 {
15 	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
16 	enum iris_inst_sub_state set_sub_state = 0;
17 	int ret;
18 
19 	iris_scale_power(inst);
20 
21 	ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
22 	if (ret)
23 		return ret;
24 
25 	if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
26 		ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0);
27 		if (ret)
28 			return ret;
29 	}
30 
31 	if (inst->domain == DECODER &&
32 	    (inst->sub_state & IRIS_INST_SUB_DRC ||
33 	     inst->sub_state & IRIS_INST_SUB_DRAIN ||
34 	     inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) {
35 		if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) {
36 			if (hfi_ops->session_pause) {
37 				ret = hfi_ops->session_pause(inst,
38 							     V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
39 				if (ret)
40 					return ret;
41 			}
42 			set_sub_state = IRIS_INST_SUB_INPUT_PAUSE;
43 		}
44 	}
45 
46 	ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
47 	if (ret)
48 		return ret;
49 
50 	inst->last_buffer_dequeued = false;
51 
52 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
53 }
54 
55 int iris_process_streamon_output(struct iris_inst *inst)
56 {
57 	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
58 	bool drain_active = false, drc_active = false;
59 	enum iris_inst_sub_state clear_sub_state = 0;
60 	int ret = 0;
61 
62 	iris_scale_power(inst);
63 
64 	drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN &&
65 		inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
66 
67 	drc_active = inst->sub_state & IRIS_INST_SUB_DRC &&
68 		inst->sub_state & IRIS_INST_SUB_DRC_LAST;
69 
70 	if (drc_active)
71 		clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST;
72 	else if (drain_active)
73 		clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST;
74 
75 	if (inst->domain == DECODER && inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
76 		ret = iris_alloc_and_queue_input_int_bufs(inst);
77 		if (ret)
78 			return ret;
79 		ret = iris_set_stage(inst, STAGE);
80 		if (ret)
81 			return ret;
82 		ret = iris_set_pipe(inst, PIPE);
83 		if (ret)
84 			return ret;
85 	}
86 
87 	if (inst->state == IRIS_INST_INPUT_STREAMING &&
88 	    inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) {
89 		if (!drain_active)
90 			ret = hfi_ops->session_resume_drc(inst,
91 							  V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
92 		else if (hfi_ops->session_resume_drain)
93 			ret = hfi_ops->session_resume_drain(inst,
94 							    V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
95 		if (ret)
96 			return ret;
97 		clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE;
98 	}
99 
100 	if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)
101 		clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC;
102 
103 	ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
104 	if (ret)
105 		return ret;
106 
107 	if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE)
108 		clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE;
109 
110 	ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
111 	if (ret)
112 		return ret;
113 
114 	inst->last_buffer_dequeued = false;
115 
116 	return iris_inst_change_sub_state(inst, clear_sub_state, 0);
117 }
118 
119 static void iris_flush_deferred_buffers(struct iris_inst *inst,
120 					enum iris_buffer_type type)
121 {
122 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
123 	struct v4l2_m2m_buffer *buffer, *n;
124 	struct iris_buffer *buf;
125 
126 	if (type == BUF_INPUT) {
127 		v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) {
128 			buf = to_iris_buffer(&buffer->vb);
129 			if (buf->attr & BUF_ATTR_DEFERRED) {
130 				if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
131 					buf->attr |= BUF_ATTR_BUFFER_DONE;
132 					buf->data_size = 0;
133 					iris_vb2_buffer_done(inst, buf);
134 				}
135 			}
136 		}
137 	} else {
138 		v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) {
139 			buf = to_iris_buffer(&buffer->vb);
140 			if (buf->attr & BUF_ATTR_DEFERRED) {
141 				if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) {
142 					buf->attr |= BUF_ATTR_BUFFER_DONE;
143 					buf->data_size = 0;
144 					iris_vb2_buffer_done(inst, buf);
145 				}
146 			}
147 		}
148 	}
149 }
150 
151 static void iris_kill_session(struct iris_inst *inst)
152 {
153 	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
154 
155 	if (!inst->session_id)
156 		return;
157 
158 	hfi_ops->session_close(inst);
159 	iris_inst_change_state(inst, IRIS_INST_ERROR);
160 }
161 
162 int iris_session_streamoff(struct iris_inst *inst, u32 plane)
163 {
164 	const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
165 	enum iris_buffer_type buffer_type;
166 	int ret;
167 
168 	switch (plane) {
169 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
170 		buffer_type = BUF_INPUT;
171 		break;
172 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
173 		buffer_type = BUF_OUTPUT;
174 		break;
175 	default:
176 		return -EINVAL;
177 	}
178 
179 	ret = hfi_ops->session_stop(inst, plane);
180 	if (ret)
181 		goto error;
182 
183 	ret = iris_inst_state_change_streamoff(inst, plane);
184 	if (ret)
185 		goto error;
186 
187 	iris_flush_deferred_buffers(inst, buffer_type);
188 
189 	return 0;
190 
191 error:
192 	iris_kill_session(inst);
193 	iris_flush_deferred_buffers(inst, buffer_type);
194 
195 	return ret;
196 }
197