xref: /linux/drivers/media/platform/qcom/iris/iris_state.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5 
6 #include <media/v4l2-mem2mem.h>
7 
8 #include "iris_instance.h"
9 
10 static bool iris_allow_inst_state_change(struct iris_inst *inst,
11 					 enum iris_inst_state req_state)
12 {
13 	switch (inst->state) {
14 	case IRIS_INST_INIT:
15 		if (req_state == IRIS_INST_INPUT_STREAMING ||
16 		    req_state == IRIS_INST_OUTPUT_STREAMING ||
17 		    req_state == IRIS_INST_DEINIT)
18 			return true;
19 		return false;
20 	case IRIS_INST_INPUT_STREAMING:
21 		if (req_state == IRIS_INST_INIT ||
22 		    req_state == IRIS_INST_STREAMING ||
23 		    req_state == IRIS_INST_DEINIT)
24 			return true;
25 		return false;
26 	case IRIS_INST_OUTPUT_STREAMING:
27 		if (req_state == IRIS_INST_INIT ||
28 		    req_state == IRIS_INST_STREAMING ||
29 		    req_state == IRIS_INST_DEINIT)
30 			return true;
31 		return false;
32 	case IRIS_INST_STREAMING:
33 		if (req_state == IRIS_INST_INPUT_STREAMING ||
34 		    req_state == IRIS_INST_OUTPUT_STREAMING ||
35 		    req_state == IRIS_INST_DEINIT)
36 			return true;
37 		return false;
38 	case IRIS_INST_DEINIT:
39 		if (req_state == IRIS_INST_INIT)
40 			return true;
41 		return false;
42 	default:
43 		return false;
44 	}
45 }
46 
47 int iris_inst_change_state(struct iris_inst *inst,
48 			   enum iris_inst_state request_state)
49 {
50 	if (inst->state == IRIS_INST_ERROR)
51 		return 0;
52 
53 	if (inst->state == request_state)
54 		return 0;
55 
56 	if (request_state == IRIS_INST_ERROR)
57 		goto change_state;
58 
59 	if (!iris_allow_inst_state_change(inst, request_state))
60 		return -EINVAL;
61 
62 change_state:
63 	inst->state = request_state;
64 	dev_dbg(inst->core->dev, "state changed from %x to %x\n",
65 		inst->state, request_state);
66 
67 	return 0;
68 }
69 
70 int iris_inst_state_change_streamon(struct iris_inst *inst, u32 plane)
71 {
72 	enum iris_inst_state new_state = IRIS_INST_ERROR;
73 
74 	if (V4L2_TYPE_IS_OUTPUT(plane)) {
75 		if (inst->state == IRIS_INST_INIT)
76 			new_state = IRIS_INST_INPUT_STREAMING;
77 		else if (inst->state == IRIS_INST_OUTPUT_STREAMING)
78 			new_state = IRIS_INST_STREAMING;
79 	} else if (V4L2_TYPE_IS_CAPTURE(plane)) {
80 		if (inst->state == IRIS_INST_INIT)
81 			new_state = IRIS_INST_OUTPUT_STREAMING;
82 		else if (inst->state == IRIS_INST_INPUT_STREAMING)
83 			new_state = IRIS_INST_STREAMING;
84 	}
85 
86 	return iris_inst_change_state(inst, new_state);
87 }
88 
89 int iris_inst_state_change_streamoff(struct iris_inst *inst, u32 plane)
90 {
91 	enum iris_inst_state new_state = IRIS_INST_ERROR;
92 
93 	if (V4L2_TYPE_IS_OUTPUT(plane)) {
94 		if (inst->state == IRIS_INST_INPUT_STREAMING)
95 			new_state = IRIS_INST_INIT;
96 		else if (inst->state == IRIS_INST_STREAMING)
97 			new_state = IRIS_INST_OUTPUT_STREAMING;
98 	} else if (V4L2_TYPE_IS_CAPTURE(plane)) {
99 		if (inst->state == IRIS_INST_OUTPUT_STREAMING)
100 			new_state = IRIS_INST_INIT;
101 		else if (inst->state == IRIS_INST_STREAMING)
102 			new_state = IRIS_INST_INPUT_STREAMING;
103 	}
104 
105 	return iris_inst_change_state(inst, new_state);
106 }
107 
108 static bool iris_inst_allow_sub_state(struct iris_inst *inst, enum iris_inst_sub_state sub_state)
109 {
110 	if (!sub_state)
111 		return true;
112 
113 	switch (inst->state) {
114 	case IRIS_INST_INIT:
115 		if (sub_state & IRIS_INST_SUB_LOAD_RESOURCES)
116 			return true;
117 		return false;
118 	case IRIS_INST_INPUT_STREAMING:
119 		if (sub_state & (IRIS_INST_SUB_FIRST_IPSC | IRIS_INST_SUB_DRC |
120 			IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_INPUT_PAUSE))
121 			return true;
122 		return false;
123 	case IRIS_INST_OUTPUT_STREAMING:
124 		if (sub_state & (IRIS_INST_SUB_DRC_LAST |
125 			IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE |
126 			IRIS_INST_SUB_LOAD_RESOURCES))
127 			return true;
128 		return false;
129 	case IRIS_INST_STREAMING:
130 		if (sub_state & (IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRAIN |
131 			IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_DRAIN_LAST |
132 			IRIS_INST_SUB_INPUT_PAUSE | IRIS_INST_SUB_OUTPUT_PAUSE))
133 			return true;
134 		return false;
135 	case IRIS_INST_DEINIT:
136 		if (sub_state & (IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRAIN |
137 			IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_DRAIN_LAST |
138 			IRIS_INST_SUB_INPUT_PAUSE | IRIS_INST_SUB_OUTPUT_PAUSE))
139 			return true;
140 		return false;
141 	default:
142 		return false;
143 	}
144 }
145 
146 int iris_inst_change_sub_state(struct iris_inst *inst,
147 			       enum iris_inst_sub_state clear_sub_state,
148 			       enum iris_inst_sub_state set_sub_state)
149 {
150 	enum iris_inst_sub_state prev_sub_state;
151 
152 	if (inst->state == IRIS_INST_ERROR)
153 		return 0;
154 
155 	if (!clear_sub_state && !set_sub_state)
156 		return 0;
157 
158 	if ((clear_sub_state & set_sub_state) ||
159 	    set_sub_state > IRIS_INST_MAX_SUB_STATE_VALUE ||
160 	    clear_sub_state > IRIS_INST_MAX_SUB_STATE_VALUE)
161 		return -EINVAL;
162 
163 	prev_sub_state = inst->sub_state;
164 
165 	if (!iris_inst_allow_sub_state(inst, set_sub_state))
166 		return -EINVAL;
167 
168 	inst->sub_state |= set_sub_state;
169 	inst->sub_state &= ~clear_sub_state;
170 
171 	if (inst->sub_state != prev_sub_state)
172 		dev_dbg(inst->core->dev, "sub_state changed from %x to %x\n",
173 			prev_sub_state, inst->sub_state);
174 
175 	return 0;
176 }
177 
178 int iris_inst_sub_state_change_drc(struct iris_inst *inst)
179 {
180 	enum iris_inst_sub_state set_sub_state = 0;
181 
182 	if (inst->sub_state & IRIS_INST_SUB_DRC)
183 		return -EINVAL;
184 
185 	if (inst->state == IRIS_INST_INPUT_STREAMING ||
186 	    inst->state == IRIS_INST_INIT)
187 		set_sub_state = IRIS_INST_SUB_FIRST_IPSC | IRIS_INST_SUB_INPUT_PAUSE;
188 	else
189 		set_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_INPUT_PAUSE;
190 
191 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
192 }
193 
194 int iris_inst_sub_state_change_drain_last(struct iris_inst *inst)
195 {
196 	enum iris_inst_sub_state set_sub_state;
197 
198 	if (inst->sub_state & IRIS_INST_SUB_DRAIN_LAST)
199 		return -EINVAL;
200 
201 	if (!(inst->sub_state & IRIS_INST_SUB_DRAIN))
202 		return -EINVAL;
203 
204 	set_sub_state = IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE;
205 
206 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
207 }
208 
209 int iris_inst_sub_state_change_drc_last(struct iris_inst *inst)
210 {
211 	enum iris_inst_sub_state set_sub_state;
212 
213 	if (inst->sub_state & IRIS_INST_SUB_DRC_LAST)
214 		return -EINVAL;
215 
216 	if (!(inst->sub_state & IRIS_INST_SUB_DRC) ||
217 	    !(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE))
218 		return -EINVAL;
219 
220 	if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)
221 		return 0;
222 
223 	set_sub_state = IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_OUTPUT_PAUSE;
224 
225 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
226 }
227 
228 int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane)
229 {
230 	enum iris_inst_sub_state set_sub_state;
231 
232 	if (V4L2_TYPE_IS_OUTPUT(plane)) {
233 		if (inst->sub_state & IRIS_INST_SUB_DRC &&
234 		    !(inst->sub_state & IRIS_INST_SUB_DRC_LAST))
235 			return -EINVAL;
236 
237 		if (inst->sub_state & IRIS_INST_SUB_DRAIN &&
238 		    !(inst->sub_state & IRIS_INST_SUB_DRAIN_LAST))
239 			return -EINVAL;
240 
241 		set_sub_state = IRIS_INST_SUB_INPUT_PAUSE;
242 	} else {
243 		set_sub_state = IRIS_INST_SUB_OUTPUT_PAUSE;
244 	}
245 
246 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
247 }
248 
249 bool iris_drc_pending(struct iris_inst *inst)
250 {
251 	return inst->sub_state & IRIS_INST_SUB_DRC &&
252 		inst->sub_state & IRIS_INST_SUB_DRC_LAST;
253 }
254 
255 bool iris_drain_pending(struct iris_inst *inst)
256 {
257 	return inst->sub_state & IRIS_INST_SUB_DRAIN &&
258 		inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
259 }
260 
261 bool iris_allow_cmd(struct iris_inst *inst, u32 cmd)
262 {
263 	struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx);
264 	struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
265 
266 	if (cmd == V4L2_DEC_CMD_START || cmd == V4L2_ENC_CMD_START) {
267 		if (vb2_is_streaming(src_q) || vb2_is_streaming(dst_q))
268 			if (iris_drc_pending(inst) || iris_drain_pending(inst))
269 				return true;
270 	} else if (cmd == V4L2_DEC_CMD_STOP || cmd == V4L2_ENC_CMD_STOP) {
271 		if (vb2_is_streaming(src_q))
272 			if (inst->sub_state != IRIS_INST_SUB_DRAIN)
273 				return true;
274 	}
275 
276 	return false;
277 }
278