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 
iris_allow_inst_state_change(struct iris_inst * inst,enum iris_inst_state req_state)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 
iris_inst_change_state(struct iris_inst * inst,enum iris_inst_state request_state)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 
iris_inst_state_change_streamon(struct iris_inst * inst,u32 plane)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 
iris_inst_state_change_streamoff(struct iris_inst * inst,u32 plane)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 
iris_inst_allow_sub_state(struct iris_inst * inst,enum iris_inst_sub_state sub_state)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 			return true;
127 		return false;
128 	case IRIS_INST_STREAMING:
129 		if (sub_state & (IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRAIN |
130 			IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_DRAIN_LAST |
131 			IRIS_INST_SUB_INPUT_PAUSE | IRIS_INST_SUB_OUTPUT_PAUSE))
132 			return true;
133 		return false;
134 	case IRIS_INST_DEINIT:
135 		if (sub_state & (IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRAIN |
136 			IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_DRAIN_LAST |
137 			IRIS_INST_SUB_INPUT_PAUSE | IRIS_INST_SUB_OUTPUT_PAUSE))
138 			return true;
139 		return false;
140 	default:
141 		return false;
142 	}
143 }
144 
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)145 int iris_inst_change_sub_state(struct iris_inst *inst,
146 			       enum iris_inst_sub_state clear_sub_state,
147 			       enum iris_inst_sub_state set_sub_state)
148 {
149 	enum iris_inst_sub_state prev_sub_state;
150 
151 	if (inst->state == IRIS_INST_ERROR)
152 		return 0;
153 
154 	if (!clear_sub_state && !set_sub_state)
155 		return 0;
156 
157 	if ((clear_sub_state & set_sub_state) ||
158 	    set_sub_state > IRIS_INST_MAX_SUB_STATE_VALUE ||
159 	    clear_sub_state > IRIS_INST_MAX_SUB_STATE_VALUE)
160 		return -EINVAL;
161 
162 	prev_sub_state = inst->sub_state;
163 
164 	if (!iris_inst_allow_sub_state(inst, set_sub_state))
165 		return -EINVAL;
166 
167 	inst->sub_state |= set_sub_state;
168 	inst->sub_state &= ~clear_sub_state;
169 
170 	if (inst->sub_state != prev_sub_state)
171 		dev_dbg(inst->core->dev, "sub_state changed from %x to %x\n",
172 			prev_sub_state, inst->sub_state);
173 
174 	return 0;
175 }
176 
iris_inst_sub_state_change_drc(struct iris_inst * inst)177 int iris_inst_sub_state_change_drc(struct iris_inst *inst)
178 {
179 	enum iris_inst_sub_state set_sub_state = 0;
180 
181 	if (inst->sub_state & IRIS_INST_SUB_DRC)
182 		return -EINVAL;
183 
184 	if (inst->state == IRIS_INST_INPUT_STREAMING ||
185 	    inst->state == IRIS_INST_INIT)
186 		set_sub_state = IRIS_INST_SUB_FIRST_IPSC | IRIS_INST_SUB_INPUT_PAUSE;
187 	else
188 		set_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_INPUT_PAUSE;
189 
190 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
191 }
192 
iris_inst_sub_state_change_drain_last(struct iris_inst * inst)193 int iris_inst_sub_state_change_drain_last(struct iris_inst *inst)
194 {
195 	enum iris_inst_sub_state set_sub_state;
196 
197 	if (inst->sub_state & IRIS_INST_SUB_DRAIN_LAST)
198 		return -EINVAL;
199 
200 	if (!(inst->sub_state & IRIS_INST_SUB_DRAIN))
201 		return -EINVAL;
202 
203 	set_sub_state = IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE;
204 
205 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
206 }
207 
iris_inst_sub_state_change_drc_last(struct iris_inst * inst)208 int iris_inst_sub_state_change_drc_last(struct iris_inst *inst)
209 {
210 	enum iris_inst_sub_state set_sub_state;
211 
212 	if (inst->sub_state & IRIS_INST_SUB_DRC_LAST)
213 		return -EINVAL;
214 
215 	if (!(inst->sub_state & IRIS_INST_SUB_DRC) ||
216 	    !(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE))
217 		return -EINVAL;
218 
219 	if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)
220 		return 0;
221 
222 	set_sub_state = IRIS_INST_SUB_DRC_LAST | IRIS_INST_SUB_OUTPUT_PAUSE;
223 
224 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
225 }
226 
iris_inst_sub_state_change_pause(struct iris_inst * inst,u32 plane)227 int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane)
228 {
229 	enum iris_inst_sub_state set_sub_state;
230 
231 	if (V4L2_TYPE_IS_OUTPUT(plane)) {
232 		if (inst->sub_state & IRIS_INST_SUB_DRC &&
233 		    !(inst->sub_state & IRIS_INST_SUB_DRC_LAST))
234 			return -EINVAL;
235 
236 		if (inst->sub_state & IRIS_INST_SUB_DRAIN &&
237 		    !(inst->sub_state & IRIS_INST_SUB_DRAIN_LAST))
238 			return -EINVAL;
239 
240 		set_sub_state = IRIS_INST_SUB_INPUT_PAUSE;
241 	} else {
242 		set_sub_state = IRIS_INST_SUB_OUTPUT_PAUSE;
243 	}
244 
245 	return iris_inst_change_sub_state(inst, 0, set_sub_state);
246 }
247 
iris_drc_pending(struct iris_inst * inst)248 static inline bool iris_drc_pending(struct iris_inst *inst)
249 {
250 	return inst->sub_state & IRIS_INST_SUB_DRC &&
251 		inst->sub_state & IRIS_INST_SUB_DRC_LAST;
252 }
253 
iris_drain_pending(struct iris_inst * inst)254 static inline bool iris_drain_pending(struct iris_inst *inst)
255 {
256 	return inst->sub_state & IRIS_INST_SUB_DRAIN &&
257 		inst->sub_state & IRIS_INST_SUB_DRAIN_LAST;
258 }
259 
iris_allow_cmd(struct iris_inst * inst,u32 cmd)260 bool iris_allow_cmd(struct iris_inst *inst, u32 cmd)
261 {
262 	struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx);
263 	struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
264 
265 	if (cmd == V4L2_DEC_CMD_START) {
266 		if (vb2_is_streaming(src_q) || vb2_is_streaming(dst_q))
267 			if (iris_drc_pending(inst) || iris_drain_pending(inst))
268 				return true;
269 	} else if (cmd == V4L2_DEC_CMD_STOP) {
270 		if (vb2_is_streaming(src_q))
271 			if (inst->sub_state != IRIS_INST_SUB_DRAIN)
272 				return true;
273 	}
274 
275 	return false;
276 }
277