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