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