File Index
Files and directories
Sign in
FILE

iris_state.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/qcom/iris/iris_state.c C
  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
 10static 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
 47int 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
 62change_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
 70int 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
 89int 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
108static 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
146int 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
178int 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
194int 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
209int 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
228int 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
249bool 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
255bool 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
261bool 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}
~/ Read-only file preview.