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 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
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)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
iris_inst_sub_state_change_drc(struct iris_inst * inst)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
iris_inst_sub_state_change_drain_last(struct iris_inst * inst)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
iris_inst_sub_state_change_drc_last(struct iris_inst * inst)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
iris_inst_sub_state_change_pause(struct iris_inst * inst,u32 plane)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
iris_drc_pending(struct iris_inst * inst)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
iris_drain_pending(struct iris_inst * inst)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
iris_allow_cmd(struct iris_inst * inst,u32 cmd)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