1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. 4 */ 5 6 #include <media/v4l2-mem2mem.h> 7 8 #include "iris_common.h" 9 #include "iris_ctrls.h" 10 #include "iris_instance.h" 11 #include "iris_power.h" 12 13 int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf) 14 { 15 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); 16 17 buf->type = iris_v4l2_type_to_driver(vb2->type); 18 buf->index = vb2->index; 19 buf->fd = vb2->planes[0].m.fd; 20 buf->buffer_size = vb2->planes[0].length; 21 buf->data_offset = vb2->planes[0].data_offset; 22 buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset; 23 buf->flags = vbuf->flags; 24 buf->timestamp = vb2->timestamp; 25 buf->attr = 0; 26 27 return 0; 28 } 29 30 void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) 31 { 32 u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 33 struct vb2_buffer *vb = &vbuf->vb2_buf; 34 u64 ts_us = vb->timestamp; 35 36 if (inst->metadata_idx >= ARRAY_SIZE(inst->tss)) 37 inst->metadata_idx = 0; 38 39 do_div(ts_us, NSEC_PER_USEC); 40 41 inst->tss[inst->metadata_idx].flags = vbuf->flags & mask; 42 inst->tss[inst->metadata_idx].tc = vbuf->timecode; 43 inst->tss[inst->metadata_idx].ts_us = ts_us; 44 inst->tss[inst->metadata_idx].ts_ns = vb->timestamp; 45 46 inst->metadata_idx++; 47 } 48 49 int iris_process_streamon_input(struct iris_inst *inst) 50 { 51 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 52 enum iris_inst_sub_state set_sub_state = 0; 53 int ret; 54 55 iris_scale_power(inst); 56 57 ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 58 if (ret) 59 return ret; 60 61 if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { 62 ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0); 63 if (ret) 64 return ret; 65 } 66 67 if (inst->domain == DECODER && 68 (inst->sub_state & IRIS_INST_SUB_DRC || 69 inst->sub_state & IRIS_INST_SUB_DRAIN || 70 inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { 71 if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) { 72 if (hfi_ops->session_pause) { 73 ret = hfi_ops->session_pause(inst, 74 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 75 if (ret) 76 return ret; 77 } 78 set_sub_state = IRIS_INST_SUB_INPUT_PAUSE; 79 } 80 } 81 82 ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 83 if (ret) 84 return ret; 85 86 inst->last_buffer_dequeued = false; 87 88 return iris_inst_change_sub_state(inst, 0, set_sub_state); 89 } 90 91 int iris_process_streamon_output(struct iris_inst *inst) 92 { 93 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 94 bool drain_active = false, drc_active = false; 95 enum iris_inst_sub_state clear_sub_state = 0; 96 int ret = 0; 97 98 iris_scale_power(inst); 99 100 drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && 101 inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; 102 103 drc_active = inst->sub_state & IRIS_INST_SUB_DRC && 104 inst->sub_state & IRIS_INST_SUB_DRC_LAST; 105 106 if (drc_active) 107 clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST; 108 else if (drain_active) 109 clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; 110 111 if (inst->domain == DECODER && inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { 112 ret = iris_alloc_and_queue_input_int_bufs(inst); 113 if (ret) 114 return ret; 115 ret = iris_set_stage(inst, STAGE); 116 if (ret) 117 return ret; 118 ret = iris_set_pipe(inst, PIPE); 119 if (ret) 120 return ret; 121 } 122 123 if (inst->state == IRIS_INST_INPUT_STREAMING && 124 inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { 125 if (!drain_active) 126 ret = hfi_ops->session_resume_drc(inst, 127 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 128 else if (hfi_ops->session_resume_drain) 129 ret = hfi_ops->session_resume_drain(inst, 130 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 131 if (ret) 132 return ret; 133 clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE; 134 } 135 136 if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) 137 clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC; 138 139 ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 140 if (ret) 141 return ret; 142 143 if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) 144 clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE; 145 146 ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 147 if (ret) 148 return ret; 149 150 inst->last_buffer_dequeued = false; 151 152 return iris_inst_change_sub_state(inst, clear_sub_state, 0); 153 } 154 155 static void iris_flush_deferred_buffers(struct iris_inst *inst, 156 enum iris_buffer_type type) 157 { 158 struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; 159 struct v4l2_m2m_buffer *buffer, *n; 160 struct iris_buffer *buf; 161 162 if (type == BUF_INPUT) { 163 v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { 164 buf = to_iris_buffer(&buffer->vb); 165 if (buf->attr & BUF_ATTR_DEFERRED) { 166 if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { 167 buf->attr |= BUF_ATTR_BUFFER_DONE; 168 buf->data_size = 0; 169 iris_vb2_buffer_done(inst, buf); 170 } 171 } 172 } 173 } else { 174 v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { 175 buf = to_iris_buffer(&buffer->vb); 176 if (buf->attr & BUF_ATTR_DEFERRED) { 177 if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { 178 buf->attr |= BUF_ATTR_BUFFER_DONE; 179 buf->data_size = 0; 180 iris_vb2_buffer_done(inst, buf); 181 } 182 } 183 } 184 } 185 } 186 187 static void iris_kill_session(struct iris_inst *inst) 188 { 189 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 190 191 if (!inst->session_id) 192 return; 193 194 hfi_ops->session_close(inst); 195 iris_inst_change_state(inst, IRIS_INST_ERROR); 196 } 197 198 int iris_session_streamoff(struct iris_inst *inst, u32 plane) 199 { 200 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 201 enum iris_buffer_type buffer_type; 202 int ret; 203 204 switch (plane) { 205 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 206 buffer_type = BUF_INPUT; 207 break; 208 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 209 buffer_type = BUF_OUTPUT; 210 break; 211 default: 212 return -EINVAL; 213 } 214 215 ret = hfi_ops->session_stop(inst, plane); 216 if (ret) 217 goto error; 218 219 ret = iris_inst_state_change_streamoff(inst, plane); 220 if (ret) 221 goto error; 222 223 iris_flush_deferred_buffers(inst, buffer_type); 224 225 return 0; 226 227 error: 228 iris_kill_session(inst); 229 iris_flush_deferred_buffers(inst, buffer_type); 230 231 return ret; 232 } 233