1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
2 | /* |
3 | * Wave5 series multi-standard codec IP - encoder interface |
4 | * |
5 | * Copyright (C) 2021-2023 CHIPS&MEDIA INC |
6 | */ |
7 | |
8 | #include <linux/pm_runtime.h> |
9 | #include "wave5-helper.h" |
10 | |
11 | #define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder" |
12 | #define VPU_ENC_DRV_NAME "wave5-enc" |
13 | |
14 | static const struct v4l2_frmsize_stepwise enc_frmsize[FMT_TYPES] = { |
15 | [VPU_FMT_TYPE_CODEC] = { |
16 | .min_width = W5_MIN_ENC_PIC_WIDTH, |
17 | .max_width = W5_MAX_ENC_PIC_WIDTH, |
18 | .step_width = W5_ENC_CODEC_STEP_WIDTH, |
19 | .min_height = W5_MIN_ENC_PIC_HEIGHT, |
20 | .max_height = W5_MAX_ENC_PIC_HEIGHT, |
21 | .step_height = W5_ENC_CODEC_STEP_HEIGHT, |
22 | }, |
23 | [VPU_FMT_TYPE_RAW] = { |
24 | .min_width = W5_MIN_ENC_PIC_WIDTH, |
25 | .max_width = W5_MAX_ENC_PIC_WIDTH, |
26 | .step_width = W5_ENC_RAW_STEP_WIDTH, |
27 | .min_height = W5_MIN_ENC_PIC_HEIGHT, |
28 | .max_height = W5_MAX_ENC_PIC_HEIGHT, |
29 | .step_height = W5_ENC_RAW_STEP_HEIGHT, |
30 | }, |
31 | }; |
32 | |
33 | static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = { |
34 | [VPU_FMT_TYPE_CODEC] = { |
35 | { |
36 | .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, |
37 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], |
38 | }, |
39 | { |
40 | .v4l2_pix_fmt = V4L2_PIX_FMT_H264, |
41 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], |
42 | }, |
43 | }, |
44 | [VPU_FMT_TYPE_RAW] = { |
45 | { |
46 | .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, |
47 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
48 | }, |
49 | { |
50 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, |
51 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
52 | }, |
53 | { |
54 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, |
55 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
56 | }, |
57 | { |
58 | .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, |
59 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
60 | }, |
61 | { |
62 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, |
63 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
64 | }, |
65 | { |
66 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, |
67 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
68 | }, |
69 | { |
70 | .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, |
71 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
72 | }, |
73 | { |
74 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, |
75 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
76 | }, |
77 | { |
78 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, |
79 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
80 | }, |
81 | { |
82 | .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, |
83 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
84 | }, |
85 | { |
86 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, |
87 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
88 | }, |
89 | { |
90 | .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, |
91 | .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], |
92 | }, |
93 | } |
94 | }; |
95 | |
96 | static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state) |
97 | { |
98 | switch (state) { |
99 | case VPU_INST_STATE_NONE: |
100 | goto invalid_state_switch; |
101 | case VPU_INST_STATE_OPEN: |
102 | if (inst->state != VPU_INST_STATE_NONE) |
103 | goto invalid_state_switch; |
104 | break; |
105 | case VPU_INST_STATE_INIT_SEQ: |
106 | if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP) |
107 | goto invalid_state_switch; |
108 | break; |
109 | case VPU_INST_STATE_PIC_RUN: |
110 | if (inst->state != VPU_INST_STATE_INIT_SEQ) |
111 | goto invalid_state_switch; |
112 | break; |
113 | case VPU_INST_STATE_STOP: |
114 | break; |
115 | } |
116 | |
117 | dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n" , |
118 | state_to_str(inst->state), state_to_str(state)); |
119 | inst->state = state; |
120 | return 0; |
121 | |
122 | invalid_state_switch: |
123 | WARN(1, "Invalid state switch from %s to %s.\n" , |
124 | state_to_str(inst->state), state_to_str(state)); |
125 | return -EINVAL; |
126 | } |
127 | |
128 | static int start_encode(struct vpu_instance *inst, u32 *fail_res) |
129 | { |
130 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
131 | int ret; |
132 | struct vb2_v4l2_buffer *src_buf; |
133 | struct vb2_v4l2_buffer *dst_buf; |
134 | struct frame_buffer frame_buf; |
135 | struct enc_param pic_param; |
136 | const struct v4l2_format_info *info; |
137 | u32 stride = inst->src_fmt.plane_fmt[0].bytesperline; |
138 | u32 luma_size = 0; |
139 | u32 chroma_size = 0; |
140 | |
141 | memset(&pic_param, 0, sizeof(struct enc_param)); |
142 | memset(&frame_buf, 0, sizeof(struct frame_buffer)); |
143 | |
144 | info = v4l2_format_info(format: inst->src_fmt.pixelformat); |
145 | if (!info) |
146 | return -EINVAL; |
147 | |
148 | if (info->mem_planes == 1) { |
149 | luma_size = stride * inst->dst_fmt.height; |
150 | chroma_size = luma_size / (info->hdiv * info->vdiv); |
151 | } else { |
152 | luma_size = inst->src_fmt.plane_fmt[0].sizeimage; |
153 | chroma_size = inst->src_fmt.plane_fmt[1].sizeimage; |
154 | } |
155 | |
156 | dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx); |
157 | if (!dst_buf) { |
158 | dev_dbg(inst->dev->dev, "%s: No destination buffer found\n" , __func__); |
159 | return -EAGAIN; |
160 | } |
161 | |
162 | pic_param.pic_stream_buffer_addr = |
163 | vb2_dma_contig_plane_dma_addr(vb: &dst_buf->vb2_buf, plane_no: 0); |
164 | pic_param.pic_stream_buffer_size = |
165 | vb2_plane_size(vb: &dst_buf->vb2_buf, plane_no: 0); |
166 | |
167 | src_buf = v4l2_m2m_next_src_buf(m2m_ctx); |
168 | if (!src_buf) { |
169 | dev_dbg(inst->dev->dev, "%s: No source buffer found\n" , __func__); |
170 | if (m2m_ctx->is_draining) |
171 | pic_param.src_end_flag = 1; |
172 | else |
173 | return -EAGAIN; |
174 | } else { |
175 | if (inst->src_fmt.num_planes == 1) { |
176 | frame_buf.buf_y = |
177 | vb2_dma_contig_plane_dma_addr(vb: &src_buf->vb2_buf, plane_no: 0); |
178 | frame_buf.buf_cb = frame_buf.buf_y + luma_size; |
179 | frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; |
180 | } else if (inst->src_fmt.num_planes == 2) { |
181 | frame_buf.buf_y = |
182 | vb2_dma_contig_plane_dma_addr(vb: &src_buf->vb2_buf, plane_no: 0); |
183 | frame_buf.buf_cb = |
184 | vb2_dma_contig_plane_dma_addr(vb: &src_buf->vb2_buf, plane_no: 1); |
185 | frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; |
186 | } else if (inst->src_fmt.num_planes == 3) { |
187 | frame_buf.buf_y = |
188 | vb2_dma_contig_plane_dma_addr(vb: &src_buf->vb2_buf, plane_no: 0); |
189 | frame_buf.buf_cb = |
190 | vb2_dma_contig_plane_dma_addr(vb: &src_buf->vb2_buf, plane_no: 1); |
191 | frame_buf.buf_cr = |
192 | vb2_dma_contig_plane_dma_addr(vb: &src_buf->vb2_buf, plane_no: 2); |
193 | } |
194 | frame_buf.stride = stride; |
195 | pic_param.src_idx = src_buf->vb2_buf.index; |
196 | } |
197 | |
198 | pic_param.source_frame = &frame_buf; |
199 | pic_param.code_option.implicit_header_encode = 1; |
200 | pic_param.code_option.encode_aud = inst->encode_aud; |
201 | ret = wave5_vpu_enc_start_one_frame(inst, param: &pic_param, fail_res); |
202 | if (ret) { |
203 | if (*fail_res == WAVE5_SYSERR_QUEUEING_FAIL) |
204 | return -EINVAL; |
205 | |
206 | dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame fail: %d\n" , |
207 | __func__, ret); |
208 | src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); |
209 | if (!src_buf) { |
210 | dev_dbg(inst->dev->dev, |
211 | "%s: Removing src buf failed, the queue is empty\n" , |
212 | __func__); |
213 | return -EINVAL; |
214 | } |
215 | dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); |
216 | if (!dst_buf) { |
217 | dev_dbg(inst->dev->dev, |
218 | "%s: Removing dst buf failed, the queue is empty\n" , |
219 | __func__); |
220 | return -EINVAL; |
221 | } |
222 | switch_state(inst, state: VPU_INST_STATE_STOP); |
223 | dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; |
224 | v4l2_m2m_buf_done(buf: src_buf, state: VB2_BUF_STATE_ERROR); |
225 | v4l2_m2m_buf_done(buf: dst_buf, state: VB2_BUF_STATE_ERROR); |
226 | } else { |
227 | dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n" , |
228 | __func__); |
229 | /* |
230 | * Remove the source buffer from the ready-queue now and finish |
231 | * it in the videobuf2 framework once the index is returned by the |
232 | * firmware in finish_encode |
233 | */ |
234 | if (src_buf) |
235 | v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, idx: src_buf->vb2_buf.index); |
236 | } |
237 | |
238 | return 0; |
239 | } |
240 | |
241 | static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst) |
242 | { |
243 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
244 | int ret; |
245 | struct enc_output_info enc_output_info; |
246 | struct vb2_v4l2_buffer *src_buf = NULL; |
247 | struct vb2_v4l2_buffer *dst_buf = NULL; |
248 | |
249 | ret = wave5_vpu_enc_get_output_info(inst, info: &enc_output_info); |
250 | if (ret) { |
251 | dev_dbg(inst->dev->dev, |
252 | "%s: vpu_enc_get_output_info fail: %d reason: %u | info: %u\n" , |
253 | __func__, ret, enc_output_info.error_reason, enc_output_info.warn_info); |
254 | return; |
255 | } |
256 | |
257 | dev_dbg(inst->dev->dev, |
258 | "%s: pic_type %i recon_idx %i src_idx %i pic_byte %u pts %llu\n" , |
259 | __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index, |
260 | enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts); |
261 | |
262 | /* |
263 | * The source buffer will not be found in the ready-queue as it has been |
264 | * dropped after sending of the encode firmware command, locate it in |
265 | * the videobuf2 queue directly |
266 | */ |
267 | if (enc_output_info.enc_src_idx >= 0) { |
268 | struct vb2_buffer *vb = vb2_get_buffer(q: v4l2_m2m_get_src_vq(m2m_ctx), |
269 | index: enc_output_info.enc_src_idx); |
270 | if (vb->state != VB2_BUF_STATE_ACTIVE) |
271 | dev_warn(inst->dev->dev, |
272 | "%s: encoded buffer (%d) was not in ready queue %i." , |
273 | __func__, enc_output_info.enc_src_idx, vb->state); |
274 | else |
275 | src_buf = to_vb2_v4l2_buffer(vb); |
276 | |
277 | if (src_buf) { |
278 | inst->timestamp = src_buf->vb2_buf.timestamp; |
279 | v4l2_m2m_buf_done(buf: src_buf, state: VB2_BUF_STATE_DONE); |
280 | } else { |
281 | dev_warn(inst->dev->dev, "%s: no source buffer with index: %d found\n" , |
282 | __func__, enc_output_info.enc_src_idx); |
283 | } |
284 | } |
285 | |
286 | dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); |
287 | if (enc_output_info.recon_frame_index == RECON_IDX_FLAG_ENC_END) { |
288 | static const struct v4l2_event vpu_event_eos = { |
289 | .type = V4L2_EVENT_EOS |
290 | }; |
291 | |
292 | if (!WARN_ON(!dst_buf)) { |
293 | vb2_set_plane_payload(vb: &dst_buf->vb2_buf, plane_no: 0, size: 0); |
294 | dst_buf->field = V4L2_FIELD_NONE; |
295 | v4l2_m2m_last_buffer_done(m2m_ctx, vbuf: dst_buf); |
296 | } |
297 | |
298 | v4l2_event_queue_fh(fh: &inst->v4l2_fh, ev: &vpu_event_eos); |
299 | |
300 | v4l2_m2m_job_finish(m2m_dev: inst->v4l2_m2m_dev, m2m_ctx); |
301 | } else { |
302 | if (!dst_buf) { |
303 | dev_warn(inst->dev->dev, "No bitstream buffer." ); |
304 | v4l2_m2m_job_finish(m2m_dev: inst->v4l2_m2m_dev, m2m_ctx); |
305 | return; |
306 | } |
307 | |
308 | vb2_set_plane_payload(vb: &dst_buf->vb2_buf, plane_no: 0, size: enc_output_info.bitstream_size); |
309 | |
310 | dst_buf->vb2_buf.timestamp = inst->timestamp; |
311 | dst_buf->field = V4L2_FIELD_NONE; |
312 | if (enc_output_info.pic_type == PIC_TYPE_I) { |
313 | if (enc_output_info.enc_vcl_nut == 19 || |
314 | enc_output_info.enc_vcl_nut == 20) |
315 | dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; |
316 | else |
317 | dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; |
318 | } else if (enc_output_info.pic_type == PIC_TYPE_P) { |
319 | dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; |
320 | } else if (enc_output_info.pic_type == PIC_TYPE_B) { |
321 | dst_buf->flags |= V4L2_BUF_FLAG_BFRAME; |
322 | } |
323 | |
324 | v4l2_m2m_buf_done(buf: dst_buf, state: VB2_BUF_STATE_DONE); |
325 | |
326 | dev_dbg(inst->dev->dev, "%s: frame_cycle %8u\n" , |
327 | __func__, enc_output_info.frame_cycle); |
328 | |
329 | v4l2_m2m_job_finish(m2m_dev: inst->v4l2_m2m_dev, m2m_ctx); |
330 | } |
331 | } |
332 | |
333 | static int wave5_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) |
334 | { |
335 | strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver)); |
336 | strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card)); |
337 | |
338 | return 0; |
339 | } |
340 | |
341 | static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) |
342 | { |
343 | const struct vpu_format *vpu_fmt; |
344 | |
345 | if (fsize->index) |
346 | return -EINVAL; |
347 | |
348 | vpu_fmt = wave5_find_vpu_fmt(v4l2_pix_fmt: fsize->pixel_format, fmt_list: enc_fmt_list[VPU_FMT_TYPE_CODEC]); |
349 | if (!vpu_fmt) { |
350 | vpu_fmt = wave5_find_vpu_fmt(v4l2_pix_fmt: fsize->pixel_format, fmt_list: enc_fmt_list[VPU_FMT_TYPE_RAW]); |
351 | if (!vpu_fmt) |
352 | return -EINVAL; |
353 | } |
354 | |
355 | fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; |
356 | fsize->stepwise = enc_frmsize[VPU_FMT_TYPE_CODEC]; |
357 | |
358 | return 0; |
359 | } |
360 | |
361 | static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) |
362 | { |
363 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
364 | const struct vpu_format *vpu_fmt; |
365 | |
366 | dev_dbg(inst->dev->dev, "%s: index: %u\n" , __func__, f->index); |
367 | |
368 | vpu_fmt = wave5_find_vpu_fmt_by_idx(idx: f->index, fmt_list: enc_fmt_list[VPU_FMT_TYPE_CODEC]); |
369 | if (!vpu_fmt) |
370 | return -EINVAL; |
371 | |
372 | f->pixelformat = vpu_fmt->v4l2_pix_fmt; |
373 | f->flags = 0; |
374 | |
375 | return 0; |
376 | } |
377 | |
378 | static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) |
379 | { |
380 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
381 | const struct v4l2_frmsize_stepwise *frmsize; |
382 | const struct vpu_format *vpu_fmt; |
383 | int width, height; |
384 | |
385 | dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n" , |
386 | __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, |
387 | f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); |
388 | |
389 | vpu_fmt = wave5_find_vpu_fmt(v4l2_pix_fmt: f->fmt.pix_mp.pixelformat, fmt_list: enc_fmt_list[VPU_FMT_TYPE_CODEC]); |
390 | if (!vpu_fmt) { |
391 | width = inst->dst_fmt.width; |
392 | height = inst->dst_fmt.height; |
393 | f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; |
394 | frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC]; |
395 | } else { |
396 | width = f->fmt.pix_mp.width; |
397 | height = f->fmt.pix_mp.height; |
398 | f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; |
399 | frmsize = vpu_fmt->v4l2_frmsize; |
400 | } |
401 | |
402 | wave5_update_pix_fmt(pix_mp: &f->fmt.pix_mp, pix_fmt_type: VPU_FMT_TYPE_CODEC, |
403 | width, height, frmsize); |
404 | f->fmt.pix_mp.colorspace = inst->colorspace; |
405 | f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; |
406 | f->fmt.pix_mp.quantization = inst->quantization; |
407 | f->fmt.pix_mp.xfer_func = inst->xfer_func; |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) |
413 | { |
414 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
415 | int i, ret; |
416 | |
417 | dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n" , |
418 | __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, |
419 | f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); |
420 | |
421 | ret = wave5_vpu_enc_try_fmt_cap(file, fh, f); |
422 | if (ret) |
423 | return ret; |
424 | |
425 | inst->std = wave5_to_vpu_std(v4l2_pix_fmt: f->fmt.pix_mp.pixelformat, type: inst->type); |
426 | if (inst->std == STD_UNKNOWN) { |
427 | dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n" , |
428 | (char *)&f->fmt.pix_mp.pixelformat); |
429 | return -EINVAL; |
430 | } |
431 | |
432 | inst->dst_fmt.width = f->fmt.pix_mp.width; |
433 | inst->dst_fmt.height = f->fmt.pix_mp.height; |
434 | inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat; |
435 | inst->dst_fmt.field = f->fmt.pix_mp.field; |
436 | inst->dst_fmt.flags = f->fmt.pix_mp.flags; |
437 | inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes; |
438 | for (i = 0; i < inst->dst_fmt.num_planes; i++) { |
439 | inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; |
440 | inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; |
441 | } |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) |
447 | { |
448 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
449 | int i; |
450 | |
451 | f->fmt.pix_mp.width = inst->dst_fmt.width; |
452 | f->fmt.pix_mp.height = inst->dst_fmt.height; |
453 | f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; |
454 | f->fmt.pix_mp.field = inst->dst_fmt.field; |
455 | f->fmt.pix_mp.flags = inst->dst_fmt.flags; |
456 | f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; |
457 | for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { |
458 | f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; |
459 | f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; |
460 | } |
461 | |
462 | f->fmt.pix_mp.colorspace = inst->colorspace; |
463 | f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; |
464 | f->fmt.pix_mp.quantization = inst->quantization; |
465 | f->fmt.pix_mp.xfer_func = inst->xfer_func; |
466 | |
467 | return 0; |
468 | } |
469 | |
470 | static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) |
471 | { |
472 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
473 | const struct vpu_format *vpu_fmt; |
474 | |
475 | dev_dbg(inst->dev->dev, "%s: index: %u\n" , __func__, f->index); |
476 | |
477 | vpu_fmt = wave5_find_vpu_fmt_by_idx(idx: f->index, fmt_list: enc_fmt_list[VPU_FMT_TYPE_RAW]); |
478 | if (!vpu_fmt) |
479 | return -EINVAL; |
480 | |
481 | f->pixelformat = vpu_fmt->v4l2_pix_fmt; |
482 | f->flags = 0; |
483 | |
484 | return 0; |
485 | } |
486 | |
487 | static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) |
488 | { |
489 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
490 | const struct v4l2_frmsize_stepwise *frmsize; |
491 | const struct vpu_format *vpu_fmt; |
492 | int width, height; |
493 | |
494 | dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n" , |
495 | __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, |
496 | f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); |
497 | |
498 | vpu_fmt = wave5_find_vpu_fmt(v4l2_pix_fmt: f->fmt.pix_mp.pixelformat, fmt_list: enc_fmt_list[VPU_FMT_TYPE_RAW]); |
499 | if (!vpu_fmt) { |
500 | width = inst->src_fmt.width; |
501 | height = inst->src_fmt.height; |
502 | f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; |
503 | frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW]; |
504 | } else { |
505 | width = f->fmt.pix_mp.width; |
506 | height = f->fmt.pix_mp.height; |
507 | f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; |
508 | frmsize = vpu_fmt->v4l2_frmsize; |
509 | } |
510 | |
511 | wave5_update_pix_fmt(pix_mp: &f->fmt.pix_mp, pix_fmt_type: VPU_FMT_TYPE_RAW, |
512 | width, height, frmsize); |
513 | return 0; |
514 | } |
515 | |
516 | static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) |
517 | { |
518 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
519 | const struct vpu_format *vpu_fmt; |
520 | const struct v4l2_format_info *info; |
521 | int i, ret; |
522 | |
523 | dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n" , |
524 | __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, |
525 | f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field); |
526 | |
527 | ret = wave5_vpu_enc_try_fmt_out(file, fh, f); |
528 | if (ret) |
529 | return ret; |
530 | |
531 | inst->src_fmt.width = f->fmt.pix_mp.width; |
532 | inst->src_fmt.height = f->fmt.pix_mp.height; |
533 | inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat; |
534 | inst->src_fmt.field = f->fmt.pix_mp.field; |
535 | inst->src_fmt.flags = f->fmt.pix_mp.flags; |
536 | inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes; |
537 | for (i = 0; i < inst->src_fmt.num_planes; i++) { |
538 | inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline; |
539 | inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; |
540 | } |
541 | |
542 | info = v4l2_format_info(format: inst->src_fmt.pixelformat); |
543 | if (!info) |
544 | return -EINVAL; |
545 | |
546 | inst->cbcr_interleave = (info->comp_planes == 2) ? true : false; |
547 | |
548 | switch (inst->src_fmt.pixelformat) { |
549 | case V4L2_PIX_FMT_NV21: |
550 | case V4L2_PIX_FMT_NV21M: |
551 | case V4L2_PIX_FMT_NV61: |
552 | case V4L2_PIX_FMT_NV61M: |
553 | inst->nv21 = true; |
554 | break; |
555 | default: |
556 | inst->nv21 = false; |
557 | } |
558 | |
559 | inst->colorspace = f->fmt.pix_mp.colorspace; |
560 | inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; |
561 | inst->quantization = f->fmt.pix_mp.quantization; |
562 | inst->xfer_func = f->fmt.pix_mp.xfer_func; |
563 | |
564 | vpu_fmt = wave5_find_vpu_fmt(v4l2_pix_fmt: inst->dst_fmt.pixelformat, fmt_list: enc_fmt_list[VPU_FMT_TYPE_CODEC]); |
565 | if (!vpu_fmt) |
566 | return -EINVAL; |
567 | |
568 | wave5_update_pix_fmt(pix_mp: &inst->dst_fmt, pix_fmt_type: VPU_FMT_TYPE_CODEC, |
569 | width: f->fmt.pix_mp.width, height: f->fmt.pix_mp.height, |
570 | frmsize: vpu_fmt->v4l2_frmsize); |
571 | inst->conf_win.width = inst->dst_fmt.width; |
572 | inst->conf_win.height = inst->dst_fmt.height; |
573 | |
574 | return 0; |
575 | } |
576 | |
577 | static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) |
578 | { |
579 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
580 | |
581 | dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n" , __func__, s->type, s->target); |
582 | |
583 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) |
584 | return -EINVAL; |
585 | switch (s->target) { |
586 | case V4L2_SEL_TGT_CROP_DEFAULT: |
587 | case V4L2_SEL_TGT_CROP_BOUNDS: |
588 | s->r.left = 0; |
589 | s->r.top = 0; |
590 | s->r.width = inst->dst_fmt.width; |
591 | s->r.height = inst->dst_fmt.height; |
592 | break; |
593 | case V4L2_SEL_TGT_CROP: |
594 | s->r.left = 0; |
595 | s->r.top = 0; |
596 | s->r.width = inst->conf_win.width; |
597 | s->r.height = inst->conf_win.height; |
598 | break; |
599 | default: |
600 | return -EINVAL; |
601 | } |
602 | |
603 | return 0; |
604 | } |
605 | |
606 | static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) |
607 | { |
608 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
609 | |
610 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) |
611 | return -EINVAL; |
612 | |
613 | if (s->target != V4L2_SEL_TGT_CROP) |
614 | return -EINVAL; |
615 | |
616 | dev_dbg(inst->dev->dev, "%s: V4L2_SEL_TGT_CROP width: %u | height: %u\n" , |
617 | __func__, s->r.width, s->r.height); |
618 | |
619 | s->r.left = 0; |
620 | s->r.top = 0; |
621 | s->r.width = min(s->r.width, inst->dst_fmt.width); |
622 | s->r.height = min(s->r.height, inst->dst_fmt.height); |
623 | |
624 | inst->conf_win = s->r; |
625 | |
626 | return 0; |
627 | } |
628 | |
629 | static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) |
630 | { |
631 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
632 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
633 | int ret; |
634 | |
635 | ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); |
636 | if (ret) |
637 | return ret; |
638 | |
639 | if (!wave5_vpu_both_queues_are_streaming(inst)) |
640 | return 0; |
641 | |
642 | switch (ec->cmd) { |
643 | case V4L2_ENC_CMD_STOP: |
644 | if (m2m_ctx->is_draining) |
645 | return -EBUSY; |
646 | |
647 | if (m2m_ctx->has_stopped) |
648 | return 0; |
649 | |
650 | m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx); |
651 | m2m_ctx->is_draining = true; |
652 | break; |
653 | case V4L2_ENC_CMD_START: |
654 | break; |
655 | default: |
656 | return -EINVAL; |
657 | } |
658 | |
659 | return 0; |
660 | } |
661 | |
662 | static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) |
663 | { |
664 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
665 | |
666 | dev_dbg(inst->dev->dev, "%s: type: %u\n" , __func__, a->type); |
667 | |
668 | if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) |
669 | return -EINVAL; |
670 | |
671 | a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; |
672 | a->parm.output.timeperframe.numerator = 1; |
673 | a->parm.output.timeperframe.denominator = inst->frame_rate; |
674 | |
675 | dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n" , |
676 | __func__, a->parm.output.timeperframe.numerator, |
677 | a->parm.output.timeperframe.denominator); |
678 | |
679 | return 0; |
680 | } |
681 | |
682 | static int wave5_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) |
683 | { |
684 | struct vpu_instance *inst = wave5_to_vpu_inst(vfh: fh); |
685 | |
686 | dev_dbg(inst->dev->dev, "%s: type: %u\n" , __func__, a->type); |
687 | |
688 | if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) |
689 | return -EINVAL; |
690 | |
691 | a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; |
692 | if (a->parm.output.timeperframe.denominator && a->parm.output.timeperframe.numerator) { |
693 | inst->frame_rate = a->parm.output.timeperframe.denominator / |
694 | a->parm.output.timeperframe.numerator; |
695 | } else { |
696 | a->parm.output.timeperframe.numerator = 1; |
697 | a->parm.output.timeperframe.denominator = inst->frame_rate; |
698 | } |
699 | |
700 | dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n" , |
701 | __func__, a->parm.output.timeperframe.numerator, |
702 | a->parm.output.timeperframe.denominator); |
703 | |
704 | return 0; |
705 | } |
706 | |
707 | static const struct v4l2_ioctl_ops wave5_vpu_enc_ioctl_ops = { |
708 | .vidioc_querycap = wave5_vpu_enc_querycap, |
709 | .vidioc_enum_framesizes = wave5_vpu_enc_enum_framesizes, |
710 | |
711 | .vidioc_enum_fmt_vid_cap = wave5_vpu_enc_enum_fmt_cap, |
712 | .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_enc_s_fmt_cap, |
713 | .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_enc_g_fmt_cap, |
714 | .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_enc_try_fmt_cap, |
715 | |
716 | .vidioc_enum_fmt_vid_out = wave5_vpu_enc_enum_fmt_out, |
717 | .vidioc_s_fmt_vid_out_mplane = wave5_vpu_enc_s_fmt_out, |
718 | .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out, |
719 | .vidioc_try_fmt_vid_out_mplane = wave5_vpu_enc_try_fmt_out, |
720 | |
721 | .vidioc_g_selection = wave5_vpu_enc_g_selection, |
722 | .vidioc_s_selection = wave5_vpu_enc_s_selection, |
723 | |
724 | .vidioc_g_parm = wave5_vpu_enc_g_parm, |
725 | .vidioc_s_parm = wave5_vpu_enc_s_parm, |
726 | |
727 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
728 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
729 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, |
730 | .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, |
731 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, |
732 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
733 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
734 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
735 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
736 | |
737 | .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, |
738 | .vidioc_encoder_cmd = wave5_vpu_enc_encoder_cmd, |
739 | |
740 | .vidioc_subscribe_event = wave5_vpu_subscribe_event, |
741 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
742 | }; |
743 | |
744 | static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) |
745 | { |
746 | struct vpu_instance *inst = wave5_ctrl_to_vpu_inst(vctrl: ctrl); |
747 | |
748 | dev_dbg(inst->dev->dev, "%s: name: %s | value: %d\n" , __func__, ctrl->name, ctrl->val); |
749 | |
750 | switch (ctrl->id) { |
751 | case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: |
752 | inst->encode_aud = ctrl->val; |
753 | break; |
754 | case V4L2_CID_HFLIP: |
755 | inst->mirror_direction |= (ctrl->val << 1); |
756 | break; |
757 | case V4L2_CID_VFLIP: |
758 | inst->mirror_direction |= ctrl->val; |
759 | break; |
760 | case V4L2_CID_ROTATE: |
761 | inst->rot_angle = ctrl->val; |
762 | break; |
763 | case V4L2_CID_MPEG_VIDEO_VBV_SIZE: |
764 | inst->vbv_buf_size = ctrl->val; |
765 | break; |
766 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: |
767 | switch (ctrl->val) { |
768 | case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: |
769 | inst->rc_mode = 0; |
770 | break; |
771 | case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: |
772 | inst->rc_mode = 1; |
773 | break; |
774 | default: |
775 | return -EINVAL; |
776 | } |
777 | break; |
778 | case V4L2_CID_MPEG_VIDEO_BITRATE: |
779 | inst->bit_rate = ctrl->val; |
780 | break; |
781 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: |
782 | inst->enc_param.avc_idr_period = ctrl->val; |
783 | break; |
784 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: |
785 | inst->enc_param.independ_slice_mode = ctrl->val; |
786 | inst->enc_param.avc_slice_mode = ctrl->val; |
787 | break; |
788 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: |
789 | inst->enc_param.independ_slice_mode_arg = ctrl->val; |
790 | inst->enc_param.avc_slice_arg = ctrl->val; |
791 | break; |
792 | case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: |
793 | inst->rc_enable = ctrl->val; |
794 | break; |
795 | case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: |
796 | inst->enc_param.mb_level_rc_enable = ctrl->val; |
797 | inst->enc_param.cu_level_rc_enable = ctrl->val; |
798 | inst->enc_param.hvs_qp_enable = ctrl->val; |
799 | break; |
800 | case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: |
801 | switch (ctrl->val) { |
802 | case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: |
803 | inst->enc_param.profile = HEVC_PROFILE_MAIN; |
804 | inst->bit_depth = 8; |
805 | break; |
806 | case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: |
807 | inst->enc_param.profile = HEVC_PROFILE_STILLPICTURE; |
808 | inst->enc_param.en_still_picture = 1; |
809 | inst->bit_depth = 8; |
810 | break; |
811 | case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: |
812 | inst->enc_param.profile = HEVC_PROFILE_MAIN10; |
813 | inst->bit_depth = 10; |
814 | break; |
815 | default: |
816 | return -EINVAL; |
817 | } |
818 | break; |
819 | case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: |
820 | switch (ctrl->val) { |
821 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: |
822 | inst->enc_param.level = 10 * 3; |
823 | break; |
824 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: |
825 | inst->enc_param.level = 20 * 3; |
826 | break; |
827 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: |
828 | inst->enc_param.level = 21 * 3; |
829 | break; |
830 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: |
831 | inst->enc_param.level = 30 * 3; |
832 | break; |
833 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: |
834 | inst->enc_param.level = 31 * 3; |
835 | break; |
836 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: |
837 | inst->enc_param.level = 40 * 3; |
838 | break; |
839 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: |
840 | inst->enc_param.level = 41 * 3; |
841 | break; |
842 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: |
843 | inst->enc_param.level = 50 * 3; |
844 | break; |
845 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: |
846 | inst->enc_param.level = 51 * 3; |
847 | break; |
848 | case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: |
849 | inst->enc_param.level = 52 * 3; |
850 | break; |
851 | default: |
852 | return -EINVAL; |
853 | } |
854 | break; |
855 | case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: |
856 | inst->enc_param.min_qp_i = ctrl->val; |
857 | inst->enc_param.min_qp_p = ctrl->val; |
858 | inst->enc_param.min_qp_b = ctrl->val; |
859 | break; |
860 | case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: |
861 | inst->enc_param.max_qp_i = ctrl->val; |
862 | inst->enc_param.max_qp_p = ctrl->val; |
863 | inst->enc_param.max_qp_b = ctrl->val; |
864 | break; |
865 | case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: |
866 | inst->enc_param.intra_qp = ctrl->val; |
867 | break; |
868 | case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: |
869 | switch (ctrl->val) { |
870 | case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: |
871 | inst->enc_param.disable_deblk = 1; |
872 | inst->enc_param.sao_enable = 0; |
873 | inst->enc_param.lf_cross_slice_boundary_enable = 0; |
874 | break; |
875 | case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: |
876 | inst->enc_param.disable_deblk = 0; |
877 | inst->enc_param.sao_enable = 1; |
878 | inst->enc_param.lf_cross_slice_boundary_enable = 1; |
879 | break; |
880 | case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: |
881 | inst->enc_param.disable_deblk = 0; |
882 | inst->enc_param.sao_enable = 1; |
883 | inst->enc_param.lf_cross_slice_boundary_enable = 0; |
884 | break; |
885 | default: |
886 | return -EINVAL; |
887 | } |
888 | break; |
889 | case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: |
890 | inst->enc_param.beta_offset_div2 = ctrl->val; |
891 | break; |
892 | case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: |
893 | inst->enc_param.tc_offset_div2 = ctrl->val; |
894 | break; |
895 | case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: |
896 | switch (ctrl->val) { |
897 | case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE: |
898 | inst->enc_param.decoding_refresh_type = 0; |
899 | break; |
900 | case V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA: |
901 | inst->enc_param.decoding_refresh_type = 1; |
902 | break; |
903 | case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR: |
904 | inst->enc_param.decoding_refresh_type = 2; |
905 | break; |
906 | default: |
907 | return -EINVAL; |
908 | } |
909 | break; |
910 | case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: |
911 | inst->enc_param.intra_period = ctrl->val; |
912 | break; |
913 | case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: |
914 | inst->enc_param.lossless_enable = ctrl->val; |
915 | break; |
916 | case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: |
917 | inst->enc_param.const_intra_pred_flag = ctrl->val; |
918 | break; |
919 | case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: |
920 | inst->enc_param.wpp_enable = ctrl->val; |
921 | break; |
922 | case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: |
923 | inst->enc_param.strong_intra_smooth_enable = ctrl->val; |
924 | break; |
925 | case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: |
926 | inst->enc_param.max_num_merge = ctrl->val; |
927 | break; |
928 | case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: |
929 | inst->enc_param.tmvp_enable = ctrl->val; |
930 | break; |
931 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: |
932 | switch (ctrl->val) { |
933 | case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: |
934 | case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: |
935 | inst->enc_param.profile = H264_PROFILE_BP; |
936 | inst->bit_depth = 8; |
937 | break; |
938 | case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: |
939 | inst->enc_param.profile = H264_PROFILE_MP; |
940 | inst->bit_depth = 8; |
941 | break; |
942 | case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: |
943 | inst->enc_param.profile = H264_PROFILE_EXTENDED; |
944 | inst->bit_depth = 8; |
945 | break; |
946 | case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: |
947 | inst->enc_param.profile = H264_PROFILE_HP; |
948 | inst->bit_depth = 8; |
949 | break; |
950 | case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: |
951 | inst->enc_param.profile = H264_PROFILE_HIGH10; |
952 | inst->bit_depth = 10; |
953 | break; |
954 | case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: |
955 | inst->enc_param.profile = H264_PROFILE_HIGH422; |
956 | inst->bit_depth = 10; |
957 | break; |
958 | case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: |
959 | inst->enc_param.profile = H264_PROFILE_HIGH444; |
960 | inst->bit_depth = 10; |
961 | break; |
962 | default: |
963 | return -EINVAL; |
964 | } |
965 | break; |
966 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: |
967 | switch (ctrl->val) { |
968 | case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: |
969 | inst->enc_param.level = 10; |
970 | break; |
971 | case V4L2_MPEG_VIDEO_H264_LEVEL_1B: |
972 | inst->enc_param.level = 9; |
973 | break; |
974 | case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: |
975 | inst->enc_param.level = 11; |
976 | break; |
977 | case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: |
978 | inst->enc_param.level = 12; |
979 | break; |
980 | case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: |
981 | inst->enc_param.level = 13; |
982 | break; |
983 | case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: |
984 | inst->enc_param.level = 20; |
985 | break; |
986 | case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: |
987 | inst->enc_param.level = 21; |
988 | break; |
989 | case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: |
990 | inst->enc_param.level = 22; |
991 | break; |
992 | case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: |
993 | inst->enc_param.level = 30; |
994 | break; |
995 | case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: |
996 | inst->enc_param.level = 31; |
997 | break; |
998 | case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: |
999 | inst->enc_param.level = 32; |
1000 | break; |
1001 | case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: |
1002 | inst->enc_param.level = 40; |
1003 | break; |
1004 | case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: |
1005 | inst->enc_param.level = 41; |
1006 | break; |
1007 | case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: |
1008 | inst->enc_param.level = 42; |
1009 | break; |
1010 | case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: |
1011 | inst->enc_param.level = 50; |
1012 | break; |
1013 | case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: |
1014 | inst->enc_param.level = 51; |
1015 | break; |
1016 | default: |
1017 | return -EINVAL; |
1018 | } |
1019 | break; |
1020 | case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: |
1021 | inst->enc_param.min_qp_i = ctrl->val; |
1022 | inst->enc_param.min_qp_p = ctrl->val; |
1023 | inst->enc_param.min_qp_b = ctrl->val; |
1024 | break; |
1025 | case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: |
1026 | inst->enc_param.max_qp_i = ctrl->val; |
1027 | inst->enc_param.max_qp_p = ctrl->val; |
1028 | inst->enc_param.max_qp_b = ctrl->val; |
1029 | break; |
1030 | case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: |
1031 | inst->enc_param.intra_qp = ctrl->val; |
1032 | break; |
1033 | case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: |
1034 | switch (ctrl->val) { |
1035 | case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: |
1036 | inst->enc_param.disable_deblk = 1; |
1037 | inst->enc_param.lf_cross_slice_boundary_enable = 1; |
1038 | break; |
1039 | case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: |
1040 | inst->enc_param.disable_deblk = 0; |
1041 | inst->enc_param.lf_cross_slice_boundary_enable = 1; |
1042 | break; |
1043 | case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: |
1044 | inst->enc_param.disable_deblk = 0; |
1045 | inst->enc_param.lf_cross_slice_boundary_enable = 0; |
1046 | break; |
1047 | default: |
1048 | return -EINVAL; |
1049 | } |
1050 | break; |
1051 | case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: |
1052 | inst->enc_param.beta_offset_div2 = ctrl->val; |
1053 | break; |
1054 | case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: |
1055 | inst->enc_param.tc_offset_div2 = ctrl->val; |
1056 | break; |
1057 | case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: |
1058 | inst->enc_param.transform8x8_enable = ctrl->val; |
1059 | break; |
1060 | case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: |
1061 | inst->enc_param.const_intra_pred_flag = ctrl->val; |
1062 | break; |
1063 | case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: |
1064 | inst->enc_param.chroma_cb_qp_offset = ctrl->val; |
1065 | inst->enc_param.chroma_cr_qp_offset = ctrl->val; |
1066 | break; |
1067 | case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: |
1068 | inst->enc_param.intra_period = ctrl->val; |
1069 | break; |
1070 | case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: |
1071 | inst->enc_param.entropy_coding_mode = ctrl->val; |
1072 | break; |
1073 | case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: |
1074 | inst->enc_param.forced_idr_header_enable = ctrl->val; |
1075 | break; |
1076 | case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: |
1077 | break; |
1078 | default: |
1079 | return -EINVAL; |
1080 | } |
1081 | |
1082 | return 0; |
1083 | } |
1084 | |
1085 | static const struct v4l2_ctrl_ops wave5_vpu_enc_ctrl_ops = { |
1086 | .s_ctrl = wave5_vpu_enc_s_ctrl, |
1087 | }; |
1088 | |
1089 | static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, |
1090 | unsigned int *num_planes, unsigned int sizes[], |
1091 | struct device *alloc_devs[]) |
1092 | { |
1093 | struct vpu_instance *inst = vb2_get_drv_priv(q); |
1094 | struct v4l2_pix_format_mplane inst_format = |
1095 | (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; |
1096 | unsigned int i; |
1097 | |
1098 | dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n" , __func__, |
1099 | *num_buffers, *num_planes, q->type); |
1100 | |
1101 | if (*num_planes) { |
1102 | if (inst_format.num_planes != *num_planes) |
1103 | return -EINVAL; |
1104 | |
1105 | for (i = 0; i < *num_planes; i++) { |
1106 | if (sizes[i] < inst_format.plane_fmt[i].sizeimage) |
1107 | return -EINVAL; |
1108 | } |
1109 | } else { |
1110 | *num_planes = inst_format.num_planes; |
1111 | for (i = 0; i < *num_planes; i++) { |
1112 | sizes[i] = inst_format.plane_fmt[i].sizeimage; |
1113 | dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n" , __func__, i, sizes[i]); |
1114 | } |
1115 | } |
1116 | |
1117 | dev_dbg(inst->dev->dev, "%s: size: %u\n" , __func__, sizes[0]); |
1118 | |
1119 | return 0; |
1120 | } |
1121 | |
1122 | static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb) |
1123 | { |
1124 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
1125 | struct vpu_instance *inst = vb2_get_drv_priv(q: vb->vb2_queue); |
1126 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
1127 | |
1128 | dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n" , |
1129 | __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), |
1130 | vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); |
1131 | |
1132 | if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) |
1133 | vbuf->sequence = inst->queued_src_buf_num++; |
1134 | else |
1135 | vbuf->sequence = inst->queued_dst_buf_num++; |
1136 | |
1137 | v4l2_m2m_buf_queue(m2m_ctx, vbuf); |
1138 | } |
1139 | |
1140 | static int wave5_set_enc_openparam(struct enc_open_param *open_param, |
1141 | struct vpu_instance *inst) |
1142 | { |
1143 | struct enc_wave_param input = inst->enc_param; |
1144 | const struct v4l2_format_info *info; |
1145 | u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64; |
1146 | u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16; |
1147 | |
1148 | info = v4l2_format_info(format: inst->src_fmt.pixelformat); |
1149 | if (!info) |
1150 | return -EINVAL; |
1151 | |
1152 | if (info->hdiv == 2 && info->vdiv == 1) |
1153 | open_param->src_format = FORMAT_422; |
1154 | else |
1155 | open_param->src_format = FORMAT_420; |
1156 | |
1157 | open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE; |
1158 | open_param->wave_param.hvs_qp_scale = 2; |
1159 | open_param->wave_param.hvs_max_delta_qp = 10; |
1160 | open_param->wave_param.skip_intra_trans = 1; |
1161 | open_param->wave_param.intra_nx_n_enable = 1; |
1162 | open_param->wave_param.nr_intra_weight_y = 7; |
1163 | open_param->wave_param.nr_intra_weight_cb = 7; |
1164 | open_param->wave_param.nr_intra_weight_cr = 7; |
1165 | open_param->wave_param.nr_inter_weight_y = 4; |
1166 | open_param->wave_param.nr_inter_weight_cb = 4; |
1167 | open_param->wave_param.nr_inter_weight_cr = 4; |
1168 | open_param->wave_param.rdo_skip = 1; |
1169 | open_param->wave_param.lambda_scaling_enable = 1; |
1170 | |
1171 | open_param->line_buf_int_en = true; |
1172 | open_param->pic_width = inst->conf_win.width; |
1173 | open_param->pic_height = inst->conf_win.height; |
1174 | open_param->frame_rate_info = inst->frame_rate; |
1175 | open_param->rc_enable = inst->rc_enable; |
1176 | if (inst->rc_enable) { |
1177 | open_param->wave_param.initial_rc_qp = -1; |
1178 | open_param->wave_param.rc_weight_param = 16; |
1179 | open_param->wave_param.rc_weight_buf = 128; |
1180 | } |
1181 | open_param->wave_param.mb_level_rc_enable = input.mb_level_rc_enable; |
1182 | open_param->wave_param.cu_level_rc_enable = input.cu_level_rc_enable; |
1183 | open_param->wave_param.hvs_qp_enable = input.hvs_qp_enable; |
1184 | open_param->bit_rate = inst->bit_rate; |
1185 | open_param->vbv_buffer_size = inst->vbv_buf_size; |
1186 | if (inst->rc_mode == 0) |
1187 | open_param->vbv_buffer_size = 3000; |
1188 | open_param->wave_param.profile = input.profile; |
1189 | open_param->wave_param.en_still_picture = input.en_still_picture; |
1190 | open_param->wave_param.level = input.level; |
1191 | open_param->wave_param.internal_bit_depth = inst->bit_depth; |
1192 | open_param->wave_param.intra_qp = input.intra_qp; |
1193 | open_param->wave_param.min_qp_i = input.min_qp_i; |
1194 | open_param->wave_param.max_qp_i = input.max_qp_i; |
1195 | open_param->wave_param.min_qp_p = input.min_qp_p; |
1196 | open_param->wave_param.max_qp_p = input.max_qp_p; |
1197 | open_param->wave_param.min_qp_b = input.min_qp_b; |
1198 | open_param->wave_param.max_qp_b = input.max_qp_b; |
1199 | open_param->wave_param.disable_deblk = input.disable_deblk; |
1200 | open_param->wave_param.lf_cross_slice_boundary_enable = |
1201 | input.lf_cross_slice_boundary_enable; |
1202 | open_param->wave_param.tc_offset_div2 = input.tc_offset_div2; |
1203 | open_param->wave_param.beta_offset_div2 = input.beta_offset_div2; |
1204 | open_param->wave_param.decoding_refresh_type = input.decoding_refresh_type; |
1205 | open_param->wave_param.intra_period = input.intra_period; |
1206 | if (inst->std == W_HEVC_ENC) { |
1207 | if (input.intra_period == 0) { |
1208 | open_param->wave_param.decoding_refresh_type = DEC_REFRESH_TYPE_IDR; |
1209 | open_param->wave_param.intra_period = input.avc_idr_period; |
1210 | } |
1211 | } else { |
1212 | open_param->wave_param.avc_idr_period = input.avc_idr_period; |
1213 | } |
1214 | open_param->wave_param.entropy_coding_mode = input.entropy_coding_mode; |
1215 | open_param->wave_param.lossless_enable = input.lossless_enable; |
1216 | open_param->wave_param.const_intra_pred_flag = input.const_intra_pred_flag; |
1217 | open_param->wave_param.wpp_enable = input.wpp_enable; |
1218 | open_param->wave_param.strong_intra_smooth_enable = input.strong_intra_smooth_enable; |
1219 | open_param->wave_param.max_num_merge = input.max_num_merge; |
1220 | open_param->wave_param.tmvp_enable = input.tmvp_enable; |
1221 | open_param->wave_param.transform8x8_enable = input.transform8x8_enable; |
1222 | open_param->wave_param.chroma_cb_qp_offset = input.chroma_cb_qp_offset; |
1223 | open_param->wave_param.chroma_cr_qp_offset = input.chroma_cr_qp_offset; |
1224 | open_param->wave_param.independ_slice_mode = input.independ_slice_mode; |
1225 | open_param->wave_param.independ_slice_mode_arg = input.independ_slice_mode_arg; |
1226 | open_param->wave_param.avc_slice_mode = input.avc_slice_mode; |
1227 | open_param->wave_param.avc_slice_arg = input.avc_slice_arg; |
1228 | open_param->wave_param.intra_mb_refresh_mode = input.intra_mb_refresh_mode; |
1229 | if (input.intra_mb_refresh_mode != REFRESH_MB_MODE_NONE) { |
1230 | if (num_mb_row >= input.intra_mb_refresh_arg) |
1231 | open_param->wave_param.intra_mb_refresh_arg = |
1232 | num_mb_row / input.intra_mb_refresh_arg; |
1233 | else |
1234 | open_param->wave_param.intra_mb_refresh_arg = num_mb_row; |
1235 | } |
1236 | open_param->wave_param.intra_refresh_mode = input.intra_refresh_mode; |
1237 | if (input.intra_refresh_mode != 0) { |
1238 | if (num_ctu_row >= input.intra_refresh_arg) |
1239 | open_param->wave_param.intra_refresh_arg = |
1240 | num_ctu_row / input.intra_refresh_arg; |
1241 | else |
1242 | open_param->wave_param.intra_refresh_arg = num_ctu_row; |
1243 | } |
1244 | open_param->wave_param.forced_idr_header_enable = input.forced_idr_header_enable; |
1245 | |
1246 | return 0; |
1247 | } |
1248 | |
1249 | static int initialize_sequence(struct vpu_instance *inst) |
1250 | { |
1251 | struct enc_initial_info initial_info; |
1252 | struct v4l2_ctrl *ctrl; |
1253 | int ret; |
1254 | |
1255 | ret = wave5_vpu_enc_issue_seq_init(inst); |
1256 | if (ret) { |
1257 | dev_err(inst->dev->dev, "%s: wave5_vpu_enc_issue_seq_init, fail: %d\n" , |
1258 | __func__, ret); |
1259 | return ret; |
1260 | } |
1261 | |
1262 | if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) { |
1263 | dev_err(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n" , __func__); |
1264 | return -EINVAL; |
1265 | } |
1266 | |
1267 | ret = wave5_vpu_enc_complete_seq_init(inst, info: &initial_info); |
1268 | if (ret) |
1269 | return ret; |
1270 | |
1271 | dev_dbg(inst->dev->dev, "%s: min_frame_buffer: %u | min_source_buffer: %u\n" , |
1272 | __func__, initial_info.min_frame_buffer_count, |
1273 | initial_info.min_src_frame_count); |
1274 | inst->min_src_buf_count = initial_info.min_src_frame_count + |
1275 | WAVE521_COMMAND_QUEUE_DEPTH; |
1276 | |
1277 | ctrl = v4l2_ctrl_find(hdl: &inst->v4l2_ctrl_hdl, |
1278 | V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); |
1279 | if (ctrl) |
1280 | v4l2_ctrl_s_ctrl(ctrl, val: inst->min_src_buf_count); |
1281 | |
1282 | inst->fbc_buf_count = initial_info.min_frame_buffer_count; |
1283 | |
1284 | return 0; |
1285 | } |
1286 | |
1287 | static int prepare_fb(struct vpu_instance *inst) |
1288 | { |
1289 | u32 fb_stride = ALIGN(inst->dst_fmt.width, 32); |
1290 | u32 fb_height = ALIGN(inst->dst_fmt.height, 32); |
1291 | int i, ret = 0; |
1292 | |
1293 | for (i = 0; i < inst->fbc_buf_count; i++) { |
1294 | u32 luma_size = fb_stride * fb_height; |
1295 | u32 chroma_size = ALIGN(fb_stride / 2, 16) * fb_height; |
1296 | |
1297 | inst->frame_vbuf[i].size = luma_size + chroma_size; |
1298 | ret = wave5_vdi_allocate_dma_memory(vpu_dev: inst->dev, vb: &inst->frame_vbuf[i]); |
1299 | if (ret < 0) { |
1300 | dev_err(inst->dev->dev, "%s: failed to allocate FBC buffer %zu\n" , |
1301 | __func__, inst->frame_vbuf[i].size); |
1302 | goto free_buffers; |
1303 | } |
1304 | |
1305 | inst->frame_buf[i].buf_y = inst->frame_vbuf[i].daddr; |
1306 | inst->frame_buf[i].buf_cb = (dma_addr_t)-1; |
1307 | inst->frame_buf[i].buf_cr = (dma_addr_t)-1; |
1308 | inst->frame_buf[i].update_fb_info = true; |
1309 | inst->frame_buf[i].size = inst->frame_vbuf[i].size; |
1310 | } |
1311 | |
1312 | ret = wave5_vpu_enc_register_frame_buffer(inst, num: inst->fbc_buf_count, stride: fb_stride, |
1313 | height: fb_height, map_type: COMPRESSED_FRAME_MAP); |
1314 | if (ret) { |
1315 | dev_err(inst->dev->dev, |
1316 | "%s: wave5_vpu_enc_register_frame_buffer, fail: %d\n" , |
1317 | __func__, ret); |
1318 | goto free_buffers; |
1319 | } |
1320 | |
1321 | return 0; |
1322 | free_buffers: |
1323 | for (i = 0; i < inst->fbc_buf_count; i++) |
1324 | wave5_vpu_dec_reset_framebuffer(inst, index: i); |
1325 | return ret; |
1326 | } |
1327 | |
1328 | static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count) |
1329 | { |
1330 | struct vpu_instance *inst = vb2_get_drv_priv(q); |
1331 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
1332 | int ret = 0; |
1333 | |
1334 | pm_runtime_resume_and_get(dev: inst->dev->dev); |
1335 | v4l2_m2m_update_start_streaming_state(m2m_ctx, q); |
1336 | |
1337 | if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1338 | struct enc_open_param open_param; |
1339 | |
1340 | memset(&open_param, 0, sizeof(struct enc_open_param)); |
1341 | |
1342 | ret = wave5_set_enc_openparam(open_param: &open_param, inst); |
1343 | if (ret) { |
1344 | dev_dbg(inst->dev->dev, "%s: wave5_set_enc_openparam, fail: %d\n" , |
1345 | __func__, ret); |
1346 | goto return_buffers; |
1347 | } |
1348 | |
1349 | ret = wave5_vpu_enc_open(inst, open_param: &open_param); |
1350 | if (ret) { |
1351 | dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_open, fail: %d\n" , |
1352 | __func__, ret); |
1353 | goto return_buffers; |
1354 | } |
1355 | |
1356 | if (inst->mirror_direction) { |
1357 | wave5_vpu_enc_give_command(inst, cmd: ENABLE_MIRRORING, NULL); |
1358 | wave5_vpu_enc_give_command(inst, cmd: SET_MIRROR_DIRECTION, |
1359 | parameter: &inst->mirror_direction); |
1360 | } |
1361 | if (inst->rot_angle) { |
1362 | wave5_vpu_enc_give_command(inst, cmd: ENABLE_ROTATION, NULL); |
1363 | wave5_vpu_enc_give_command(inst, cmd: SET_ROTATION_ANGLE, parameter: &inst->rot_angle); |
1364 | } |
1365 | |
1366 | ret = switch_state(inst, state: VPU_INST_STATE_OPEN); |
1367 | if (ret) |
1368 | goto return_buffers; |
1369 | } |
1370 | if (inst->state == VPU_INST_STATE_OPEN && m2m_ctx->cap_q_ctx.q.streaming) { |
1371 | ret = initialize_sequence(inst); |
1372 | if (ret) { |
1373 | dev_warn(inst->dev->dev, "Sequence not found: %d\n" , ret); |
1374 | goto return_buffers; |
1375 | } |
1376 | ret = switch_state(inst, state: VPU_INST_STATE_INIT_SEQ); |
1377 | if (ret) |
1378 | goto return_buffers; |
1379 | /* |
1380 | * The sequence must be analyzed first to calculate the proper |
1381 | * size of the auxiliary buffers. |
1382 | */ |
1383 | ret = prepare_fb(inst); |
1384 | if (ret) { |
1385 | dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n" , ret); |
1386 | goto return_buffers; |
1387 | } |
1388 | |
1389 | ret = switch_state(inst, state: VPU_INST_STATE_PIC_RUN); |
1390 | } |
1391 | if (ret) |
1392 | goto return_buffers; |
1393 | |
1394 | pm_runtime_mark_last_busy(dev: inst->dev->dev); |
1395 | pm_runtime_put_autosuspend(dev: inst->dev->dev); |
1396 | return 0; |
1397 | return_buffers: |
1398 | wave5_return_bufs(q, state: VB2_BUF_STATE_QUEUED); |
1399 | pm_runtime_mark_last_busy(dev: inst->dev->dev); |
1400 | pm_runtime_put_autosuspend(dev: inst->dev->dev); |
1401 | return ret; |
1402 | } |
1403 | |
1404 | static void streamoff_output(struct vpu_instance *inst, struct vb2_queue *q) |
1405 | { |
1406 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
1407 | struct vb2_v4l2_buffer *buf; |
1408 | |
1409 | while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) { |
1410 | dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n" , |
1411 | __func__, buf->vb2_buf.type, buf->vb2_buf.index); |
1412 | v4l2_m2m_buf_done(buf, state: VB2_BUF_STATE_ERROR); |
1413 | } |
1414 | } |
1415 | |
1416 | static void streamoff_capture(struct vpu_instance *inst, struct vb2_queue *q) |
1417 | { |
1418 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
1419 | struct vb2_v4l2_buffer *buf; |
1420 | |
1421 | while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) { |
1422 | dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n" , |
1423 | __func__, buf->vb2_buf.type, buf->vb2_buf.index); |
1424 | vb2_set_plane_payload(vb: &buf->vb2_buf, plane_no: 0, size: 0); |
1425 | v4l2_m2m_buf_done(buf, state: VB2_BUF_STATE_ERROR); |
1426 | } |
1427 | |
1428 | v4l2_m2m_clear_state(m2m_ctx); |
1429 | } |
1430 | |
1431 | static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) |
1432 | { |
1433 | struct vpu_instance *inst = vb2_get_drv_priv(q); |
1434 | bool check_cmd = true; |
1435 | |
1436 | /* |
1437 | * Note that we don't need m2m_ctx->next_buf_last for this driver, so we |
1438 | * don't call v4l2_m2m_update_stop_streaming_state(). |
1439 | */ |
1440 | |
1441 | dev_dbg(inst->dev->dev, "%s: type: %u\n" , __func__, q->type); |
1442 | pm_runtime_resume_and_get(dev: inst->dev->dev); |
1443 | |
1444 | if (wave5_vpu_both_queues_are_streaming(inst)) |
1445 | switch_state(inst, state: VPU_INST_STATE_STOP); |
1446 | |
1447 | while (check_cmd) { |
1448 | struct queue_status_info q_status; |
1449 | struct enc_output_info enc_output_info; |
1450 | |
1451 | wave5_vpu_enc_give_command(inst, cmd: ENC_GET_QUEUE_STATUS, parameter: &q_status); |
1452 | |
1453 | if (q_status.report_queue_count == 0) |
1454 | break; |
1455 | |
1456 | if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) |
1457 | break; |
1458 | |
1459 | if (wave5_vpu_enc_get_output_info(inst, info: &enc_output_info)) |
1460 | dev_dbg(inst->dev->dev, "Getting encoding results from fw, fail\n" ); |
1461 | } |
1462 | |
1463 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) |
1464 | streamoff_output(inst, q); |
1465 | else |
1466 | streamoff_capture(inst, q); |
1467 | |
1468 | pm_runtime_mark_last_busy(dev: inst->dev->dev); |
1469 | pm_runtime_put_autosuspend(dev: inst->dev->dev); |
1470 | } |
1471 | |
1472 | static const struct vb2_ops wave5_vpu_enc_vb2_ops = { |
1473 | .queue_setup = wave5_vpu_enc_queue_setup, |
1474 | .buf_queue = wave5_vpu_enc_buf_queue, |
1475 | .start_streaming = wave5_vpu_enc_start_streaming, |
1476 | .stop_streaming = wave5_vpu_enc_stop_streaming, |
1477 | }; |
1478 | |
1479 | static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, |
1480 | struct v4l2_pix_format_mplane *dst_fmt) |
1481 | { |
1482 | src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; |
1483 | wave5_update_pix_fmt(pix_mp: src_fmt, pix_fmt_type: VPU_FMT_TYPE_RAW, |
1484 | W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, |
1485 | frmsize: &enc_frmsize[VPU_FMT_TYPE_RAW]); |
1486 | |
1487 | dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; |
1488 | wave5_update_pix_fmt(pix_mp: dst_fmt, pix_fmt_type: VPU_FMT_TYPE_CODEC, |
1489 | W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, |
1490 | frmsize: &enc_frmsize[VPU_FMT_TYPE_CODEC]); |
1491 | } |
1492 | |
1493 | static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) |
1494 | { |
1495 | return wave5_vpu_queue_init(priv, src_vq, dst_vq, ops: &wave5_vpu_enc_vb2_ops); |
1496 | } |
1497 | |
1498 | static const struct vpu_instance_ops wave5_vpu_enc_inst_ops = { |
1499 | .finish_process = wave5_vpu_enc_finish_encode, |
1500 | }; |
1501 | |
1502 | static void wave5_vpu_enc_device_run(void *priv) |
1503 | { |
1504 | struct vpu_instance *inst = priv; |
1505 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
1506 | u32 fail_res = 0; |
1507 | int ret = 0; |
1508 | |
1509 | pm_runtime_resume_and_get(dev: inst->dev->dev); |
1510 | switch (inst->state) { |
1511 | case VPU_INST_STATE_PIC_RUN: |
1512 | ret = start_encode(inst, fail_res: &fail_res); |
1513 | if (ret) { |
1514 | if (ret == -EINVAL) |
1515 | dev_err(inst->dev->dev, |
1516 | "Frame encoding on m2m context (%p), fail: %d (res: %d)\n" , |
1517 | m2m_ctx, ret, fail_res); |
1518 | else if (ret == -EAGAIN) |
1519 | dev_dbg(inst->dev->dev, "Missing buffers for encode, try again\n" ); |
1520 | break; |
1521 | } |
1522 | dev_dbg(inst->dev->dev, "%s: leave with active job" , __func__); |
1523 | pm_runtime_mark_last_busy(dev: inst->dev->dev); |
1524 | pm_runtime_put_autosuspend(dev: inst->dev->dev); |
1525 | return; |
1526 | default: |
1527 | WARN(1, "Execution of a job in state %s is invalid.\n" , |
1528 | state_to_str(inst->state)); |
1529 | break; |
1530 | } |
1531 | dev_dbg(inst->dev->dev, "%s: leave and finish job" , __func__); |
1532 | pm_runtime_mark_last_busy(dev: inst->dev->dev); |
1533 | pm_runtime_put_autosuspend(dev: inst->dev->dev); |
1534 | v4l2_m2m_job_finish(m2m_dev: inst->v4l2_m2m_dev, m2m_ctx); |
1535 | } |
1536 | |
1537 | static int wave5_vpu_enc_job_ready(void *priv) |
1538 | { |
1539 | struct vpu_instance *inst = priv; |
1540 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
1541 | |
1542 | switch (inst->state) { |
1543 | case VPU_INST_STATE_NONE: |
1544 | dev_dbg(inst->dev->dev, "Encoder must be open to start queueing M2M jobs!\n" ); |
1545 | return false; |
1546 | case VPU_INST_STATE_PIC_RUN: |
1547 | if (m2m_ctx->is_draining || v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { |
1548 | dev_dbg(inst->dev->dev, "Encoder ready for a job, state: %s\n" , |
1549 | state_to_str(inst->state)); |
1550 | return true; |
1551 | } |
1552 | fallthrough; |
1553 | default: |
1554 | dev_dbg(inst->dev->dev, |
1555 | "Encoder not ready for a job, state: %s, %s draining, %d src bufs ready\n" , |
1556 | state_to_str(inst->state), m2m_ctx->is_draining ? "is" : "is not" , |
1557 | v4l2_m2m_num_src_bufs_ready(m2m_ctx)); |
1558 | break; |
1559 | } |
1560 | return false; |
1561 | } |
1562 | |
1563 | static const struct v4l2_m2m_ops wave5_vpu_enc_m2m_ops = { |
1564 | .device_run = wave5_vpu_enc_device_run, |
1565 | .job_ready = wave5_vpu_enc_job_ready, |
1566 | }; |
1567 | |
1568 | static int wave5_vpu_open_enc(struct file *filp) |
1569 | { |
1570 | struct video_device *vdev = video_devdata(file: filp); |
1571 | struct vpu_device *dev = video_drvdata(file: filp); |
1572 | struct vpu_instance *inst = NULL; |
1573 | struct v4l2_ctrl_handler *v4l2_ctrl_hdl; |
1574 | int ret = 0; |
1575 | |
1576 | inst = kzalloc(sizeof(*inst), GFP_KERNEL); |
1577 | if (!inst) |
1578 | return -ENOMEM; |
1579 | v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl; |
1580 | |
1581 | inst->dev = dev; |
1582 | inst->type = VPU_INST_TYPE_ENC; |
1583 | inst->ops = &wave5_vpu_enc_inst_ops; |
1584 | |
1585 | inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); |
1586 | if (!inst->codec_info) |
1587 | return -ENOMEM; |
1588 | |
1589 | v4l2_fh_init(fh: &inst->v4l2_fh, vdev); |
1590 | filp->private_data = &inst->v4l2_fh; |
1591 | v4l2_fh_add(fh: &inst->v4l2_fh); |
1592 | |
1593 | INIT_LIST_HEAD(list: &inst->list); |
1594 | |
1595 | inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev; |
1596 | inst->v4l2_fh.m2m_ctx = |
1597 | v4l2_m2m_ctx_init(m2m_dev: inst->v4l2_m2m_dev, drv_priv: inst, queue_init: wave5_vpu_enc_queue_init); |
1598 | if (IS_ERR(ptr: inst->v4l2_fh.m2m_ctx)) { |
1599 | ret = PTR_ERR(ptr: inst->v4l2_fh.m2m_ctx); |
1600 | goto cleanup_inst; |
1601 | } |
1602 | v4l2_m2m_set_src_buffered(m2m_ctx: inst->v4l2_fh.m2m_ctx, buffered: true); |
1603 | |
1604 | v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50); |
1605 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1606 | V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, |
1607 | max: V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, mask: 0, |
1608 | def: V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); |
1609 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1610 | V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, |
1611 | max: V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, mask: 0, |
1612 | def: V4L2_MPEG_VIDEO_HEVC_LEVEL_1); |
1613 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1614 | V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, |
1615 | min: 0, max: 63, step: 1, def: 8); |
1616 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1617 | V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, |
1618 | min: 0, max: 63, step: 1, def: 51); |
1619 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1620 | V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, |
1621 | min: 0, max: 63, step: 1, def: 30); |
1622 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1623 | V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, |
1624 | max: V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, mask: 0, |
1625 | def: V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED); |
1626 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1627 | V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, |
1628 | min: -6, max: 6, step: 1, def: 0); |
1629 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1630 | V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, |
1631 | min: -6, max: 6, step: 1, def: 0); |
1632 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1633 | V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, |
1634 | max: V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, mask: 0, |
1635 | def: V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR); |
1636 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1637 | V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, |
1638 | min: 0, max: 2047, step: 1, def: 0); |
1639 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1640 | V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, |
1641 | min: 0, max: 1, step: 1, def: 0); |
1642 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1643 | V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, |
1644 | min: 0, max: 1, step: 1, def: 0); |
1645 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1646 | V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, |
1647 | min: 0, max: 1, step: 1, def: 0); |
1648 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1649 | V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, |
1650 | min: 0, max: 1, step: 1, def: 1); |
1651 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1652 | V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, |
1653 | min: 1, max: 2, step: 1, def: 2); |
1654 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1655 | V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, |
1656 | min: 0, max: 1, step: 1, def: 1); |
1657 | |
1658 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1659 | V4L2_CID_MPEG_VIDEO_H264_PROFILE, |
1660 | max: V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE, mask: 0, |
1661 | def: V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); |
1662 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1663 | V4L2_CID_MPEG_VIDEO_H264_LEVEL, |
1664 | max: V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask: 0, |
1665 | def: V4L2_MPEG_VIDEO_H264_LEVEL_1_0); |
1666 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1667 | V4L2_CID_MPEG_VIDEO_H264_MIN_QP, |
1668 | min: 0, max: 63, step: 1, def: 8); |
1669 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1670 | V4L2_CID_MPEG_VIDEO_H264_MAX_QP, |
1671 | min: 0, max: 63, step: 1, def: 51); |
1672 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1673 | V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, |
1674 | min: 0, max: 63, step: 1, def: 30); |
1675 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1676 | V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, |
1677 | max: V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, mask: 0, |
1678 | def: V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); |
1679 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1680 | V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, |
1681 | min: -6, max: 6, step: 1, def: 0); |
1682 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1683 | V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, |
1684 | min: -6, max: 6, step: 1, def: 0); |
1685 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1686 | V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, |
1687 | min: 0, max: 1, step: 1, def: 1); |
1688 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1689 | V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, |
1690 | min: 0, max: 1, step: 1, def: 0); |
1691 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1692 | V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, |
1693 | min: -12, max: 12, step: 1, def: 0); |
1694 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1695 | V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, |
1696 | min: 0, max: 2047, step: 1, def: 0); |
1697 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1698 | V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, |
1699 | max: V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, mask: 0, |
1700 | def: V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC); |
1701 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1702 | V4L2_CID_MPEG_VIDEO_AU_DELIMITER, |
1703 | min: 0, max: 1, step: 1, def: 1); |
1704 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1705 | V4L2_CID_HFLIP, |
1706 | min: 0, max: 1, step: 1, def: 0); |
1707 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1708 | V4L2_CID_VFLIP, |
1709 | min: 0, max: 1, step: 1, def: 0); |
1710 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1711 | V4L2_CID_ROTATE, |
1712 | min: 0, max: 270, step: 90, def: 0); |
1713 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1714 | V4L2_CID_MPEG_VIDEO_VBV_SIZE, |
1715 | min: 10, max: 3000, step: 1, def: 1000); |
1716 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1717 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, |
1718 | max: V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, mask: 0, |
1719 | def: V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); |
1720 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1721 | V4L2_CID_MPEG_VIDEO_BITRATE, |
1722 | min: 0, max: 700000000, step: 1, def: 0); |
1723 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1724 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, |
1725 | min: 0, max: 2047, step: 1, def: 0); |
1726 | v4l2_ctrl_new_std_menu(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1727 | V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, |
1728 | max: V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, mask: 0, |
1729 | def: V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); |
1730 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1731 | V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, |
1732 | min: 0, max: 0xFFFF, step: 1, def: 0); |
1733 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1734 | V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, |
1735 | min: 0, max: 1, step: 1, def: 0); |
1736 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1737 | V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, |
1738 | min: 0, max: 1, step: 1, def: 0); |
1739 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1740 | V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, min: 1, max: 32, step: 1, def: 1); |
1741 | v4l2_ctrl_new_std(hdl: v4l2_ctrl_hdl, ops: &wave5_vpu_enc_ctrl_ops, |
1742 | V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, |
1743 | min: 0, max: 1, step: 1, def: 0); |
1744 | |
1745 | if (v4l2_ctrl_hdl->error) { |
1746 | ret = -ENODEV; |
1747 | goto cleanup_inst; |
1748 | } |
1749 | |
1750 | inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl; |
1751 | v4l2_ctrl_handler_setup(hdl: v4l2_ctrl_hdl); |
1752 | |
1753 | wave5_set_default_format(src_fmt: &inst->src_fmt, dst_fmt: &inst->dst_fmt); |
1754 | inst->conf_win.width = inst->dst_fmt.width; |
1755 | inst->conf_win.height = inst->dst_fmt.height; |
1756 | inst->colorspace = V4L2_COLORSPACE_REC709; |
1757 | inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
1758 | inst->quantization = V4L2_QUANTIZATION_DEFAULT; |
1759 | inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; |
1760 | inst->frame_rate = 30; |
1761 | |
1762 | init_completion(x: &inst->irq_done); |
1763 | |
1764 | inst->id = ida_alloc(ida: &inst->dev->inst_ida, GFP_KERNEL); |
1765 | if (inst->id < 0) { |
1766 | dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n" , inst->id); |
1767 | ret = inst->id; |
1768 | goto cleanup_inst; |
1769 | } |
1770 | |
1771 | wave5_vdi_allocate_sram(vpu_dev: inst->dev); |
1772 | |
1773 | ret = mutex_lock_interruptible(&dev->dev_lock); |
1774 | if (ret) |
1775 | goto cleanup_inst; |
1776 | |
1777 | if (list_empty(head: &dev->instances)) |
1778 | pm_runtime_use_autosuspend(dev: inst->dev->dev); |
1779 | |
1780 | list_add_tail(new: &inst->list, head: &dev->instances); |
1781 | |
1782 | mutex_unlock(lock: &dev->dev_lock); |
1783 | |
1784 | return 0; |
1785 | |
1786 | cleanup_inst: |
1787 | wave5_cleanup_instance(inst); |
1788 | return ret; |
1789 | } |
1790 | |
1791 | static int wave5_vpu_enc_release(struct file *filp) |
1792 | { |
1793 | return wave5_vpu_release_device(filp, close_func: wave5_vpu_enc_close, name: "encoder" ); |
1794 | } |
1795 | |
1796 | static const struct v4l2_file_operations wave5_vpu_enc_fops = { |
1797 | .owner = THIS_MODULE, |
1798 | .open = wave5_vpu_open_enc, |
1799 | .release = wave5_vpu_enc_release, |
1800 | .unlocked_ioctl = video_ioctl2, |
1801 | .poll = v4l2_m2m_fop_poll, |
1802 | .mmap = v4l2_m2m_fop_mmap, |
1803 | }; |
1804 | |
1805 | int wave5_vpu_enc_register_device(struct vpu_device *dev) |
1806 | { |
1807 | struct video_device *vdev_enc; |
1808 | int ret; |
1809 | |
1810 | vdev_enc = devm_kzalloc(dev: dev->v4l2_dev.dev, size: sizeof(*vdev_enc), GFP_KERNEL); |
1811 | if (!vdev_enc) |
1812 | return -ENOMEM; |
1813 | |
1814 | dev->v4l2_m2m_enc_dev = v4l2_m2m_init(m2m_ops: &wave5_vpu_enc_m2m_ops); |
1815 | if (IS_ERR(ptr: dev->v4l2_m2m_enc_dev)) { |
1816 | ret = PTR_ERR(ptr: dev->v4l2_m2m_enc_dev); |
1817 | dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n" , ret); |
1818 | return -EINVAL; |
1819 | } |
1820 | |
1821 | dev->video_dev_enc = vdev_enc; |
1822 | |
1823 | strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name)); |
1824 | vdev_enc->fops = &wave5_vpu_enc_fops; |
1825 | vdev_enc->ioctl_ops = &wave5_vpu_enc_ioctl_ops; |
1826 | vdev_enc->release = video_device_release_empty; |
1827 | vdev_enc->v4l2_dev = &dev->v4l2_dev; |
1828 | vdev_enc->vfl_dir = VFL_DIR_M2M; |
1829 | vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
1830 | vdev_enc->lock = &dev->dev_lock; |
1831 | |
1832 | ret = video_register_device(vdev: vdev_enc, type: VFL_TYPE_VIDEO, nr: -1); |
1833 | if (ret) |
1834 | return ret; |
1835 | |
1836 | video_set_drvdata(vdev: vdev_enc, data: dev); |
1837 | |
1838 | return 0; |
1839 | } |
1840 | |
1841 | void wave5_vpu_enc_unregister_device(struct vpu_device *dev) |
1842 | { |
1843 | video_unregister_device(vdev: dev->video_dev_enc); |
1844 | if (dev->v4l2_m2m_enc_dev) |
1845 | v4l2_m2m_release(m2m_dev: dev->v4l2_m2m_enc_dev); |
1846 | } |
1847 | |