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 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 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 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 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 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 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 248 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 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 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