13cd08451SMing Qian // SPDX-License-Identifier: GPL-2.0
23cd08451SMing Qian /*
33cd08451SMing Qian * Copyright 2020-2021 NXP
43cd08451SMing Qian */
53cd08451SMing Qian
63cd08451SMing Qian #include <linux/init.h>
73cd08451SMing Qian #include <linux/interconnect.h>
83cd08451SMing Qian #include <linux/ioctl.h>
93cd08451SMing Qian #include <linux/list.h>
103cd08451SMing Qian #include <linux/kernel.h>
113cd08451SMing Qian #include <linux/module.h>
123cd08451SMing Qian #include <linux/pm_runtime.h>
133cd08451SMing Qian #include <linux/videodev2.h>
143cd08451SMing Qian #include <media/v4l2-device.h>
153cd08451SMing Qian #include <media/v4l2-event.h>
163cd08451SMing Qian #include <media/v4l2-mem2mem.h>
173cd08451SMing Qian #include <media/v4l2-ioctl.h>
183cd08451SMing Qian #include <media/videobuf2-v4l2.h>
193cd08451SMing Qian #include <media/videobuf2-dma-contig.h>
203cd08451SMing Qian #include <media/videobuf2-vmalloc.h>
213cd08451SMing Qian #include "vpu.h"
223cd08451SMing Qian #include "vpu_core.h"
233cd08451SMing Qian #include "vpu_v4l2.h"
243cd08451SMing Qian #include "vpu_msgs.h"
253cd08451SMing Qian #include "vpu_helpers.h"
263cd08451SMing Qian
vpu_inst_lock(struct vpu_inst * inst)273cd08451SMing Qian void vpu_inst_lock(struct vpu_inst *inst)
283cd08451SMing Qian {
293cd08451SMing Qian mutex_lock(&inst->lock);
303cd08451SMing Qian }
313cd08451SMing Qian
vpu_inst_unlock(struct vpu_inst * inst)323cd08451SMing Qian void vpu_inst_unlock(struct vpu_inst *inst)
333cd08451SMing Qian {
343cd08451SMing Qian mutex_unlock(&inst->lock);
353cd08451SMing Qian }
363cd08451SMing Qian
vpu_get_vb_phy_addr(struct vb2_buffer * vb,u32 plane_no)373cd08451SMing Qian dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no)
383cd08451SMing Qian {
393cd08451SMing Qian if (plane_no >= vb->num_planes)
403cd08451SMing Qian return 0;
413cd08451SMing Qian return vb2_dma_contig_plane_dma_addr(vb, plane_no) +
423cd08451SMing Qian vb->planes[plane_no].data_offset;
433cd08451SMing Qian }
443cd08451SMing Qian
vpu_get_vb_length(struct vb2_buffer * vb,u32 plane_no)453cd08451SMing Qian unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no)
463cd08451SMing Qian {
473cd08451SMing Qian if (plane_no >= vb->num_planes)
483cd08451SMing Qian return 0;
493cd08451SMing Qian return vb2_plane_size(vb, plane_no) - vb->planes[plane_no].data_offset;
503cd08451SMing Qian }
513cd08451SMing Qian
vpu_set_buffer_state(struct vb2_v4l2_buffer * vbuf,unsigned int state)523cd08451SMing Qian void vpu_set_buffer_state(struct vb2_v4l2_buffer *vbuf, unsigned int state)
533cd08451SMing Qian {
543cd08451SMing Qian struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf);
553cd08451SMing Qian
563cd08451SMing Qian vpu_buf->state = state;
573cd08451SMing Qian }
583cd08451SMing Qian
vpu_get_buffer_state(struct vb2_v4l2_buffer * vbuf)593cd08451SMing Qian unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf)
603cd08451SMing Qian {
613cd08451SMing Qian struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf);
623cd08451SMing Qian
633cd08451SMing Qian return vpu_buf->state;
643cd08451SMing Qian }
653cd08451SMing Qian
vpu_v4l2_set_error(struct vpu_inst * inst)663cd08451SMing Qian void vpu_v4l2_set_error(struct vpu_inst *inst)
673cd08451SMing Qian {
683cd08451SMing Qian vpu_inst_lock(inst);
693cd08451SMing Qian dev_err(inst->dev, "some error occurs in codec\n");
703cd08451SMing Qian if (inst->fh.m2m_ctx) {
71ae2caf39SMing Qian vb2_queue_error(v4l2_m2m_get_src_vq(inst->fh.m2m_ctx));
72ae2caf39SMing Qian vb2_queue_error(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
733cd08451SMing Qian }
743cd08451SMing Qian vpu_inst_unlock(inst);
753cd08451SMing Qian }
763cd08451SMing Qian
vpu_notify_eos(struct vpu_inst * inst)773cd08451SMing Qian int vpu_notify_eos(struct vpu_inst *inst)
783cd08451SMing Qian {
793cd08451SMing Qian static const struct v4l2_event ev = {
803cd08451SMing Qian .id = 0,
813cd08451SMing Qian .type = V4L2_EVENT_EOS
823cd08451SMing Qian };
833cd08451SMing Qian
843cd08451SMing Qian vpu_trace(inst->dev, "[%d]\n", inst->id);
853cd08451SMing Qian v4l2_event_queue_fh(&inst->fh, &ev);
863cd08451SMing Qian
873cd08451SMing Qian return 0;
883cd08451SMing Qian }
893cd08451SMing Qian
vpu_notify_source_change(struct vpu_inst * inst)903cd08451SMing Qian int vpu_notify_source_change(struct vpu_inst *inst)
913cd08451SMing Qian {
923cd08451SMing Qian static const struct v4l2_event ev = {
933cd08451SMing Qian .id = 0,
943cd08451SMing Qian .type = V4L2_EVENT_SOURCE_CHANGE,
953cd08451SMing Qian .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
963cd08451SMing Qian };
973cd08451SMing Qian
983cd08451SMing Qian vpu_trace(inst->dev, "[%d]\n", inst->id);
993cd08451SMing Qian v4l2_event_queue_fh(&inst->fh, &ev);
1003cd08451SMing Qian return 0;
1013cd08451SMing Qian }
1023cd08451SMing Qian
vpu_set_last_buffer_dequeued(struct vpu_inst * inst,bool eos)103076b6289SMing Qian int vpu_set_last_buffer_dequeued(struct vpu_inst *inst, bool eos)
1043cd08451SMing Qian {
1053cd08451SMing Qian struct vb2_queue *q;
1063cd08451SMing Qian
1073cd08451SMing Qian if (!inst || !inst->fh.m2m_ctx)
1083cd08451SMing Qian return -EINVAL;
1093cd08451SMing Qian
1103cd08451SMing Qian q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
1113cd08451SMing Qian if (!list_empty(&q->done_list))
1123cd08451SMing Qian return -EINVAL;
1133cd08451SMing Qian
1143cd08451SMing Qian if (q->last_buffer_dequeued)
1153cd08451SMing Qian return 0;
1163cd08451SMing Qian vpu_trace(inst->dev, "last buffer dequeued\n");
1173cd08451SMing Qian q->last_buffer_dequeued = true;
1183cd08451SMing Qian wake_up(&q->done_wq);
119076b6289SMing Qian if (eos)
1203cd08451SMing Qian vpu_notify_eos(inst);
1213cd08451SMing Qian return 0;
1223cd08451SMing Qian }
1233cd08451SMing Qian
vpu_is_source_empty(struct vpu_inst * inst)124a4dca209SMing Qian bool vpu_is_source_empty(struct vpu_inst *inst)
125a4dca209SMing Qian {
126a4dca209SMing Qian struct v4l2_m2m_buffer *buf = NULL;
127a4dca209SMing Qian
128a4dca209SMing Qian if (!inst->fh.m2m_ctx)
129a4dca209SMing Qian return true;
130a4dca209SMing Qian v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) {
131a4dca209SMing Qian if (vpu_get_buffer_state(&buf->vb) == VPU_BUF_STATE_IDLE)
132a4dca209SMing Qian return false;
133a4dca209SMing Qian }
134a4dca209SMing Qian return true;
135a4dca209SMing Qian }
136a4dca209SMing Qian
vpu_init_format(struct vpu_inst * inst,struct vpu_format * fmt)137d21ce554SMing Qian static int vpu_init_format(struct vpu_inst *inst, struct vpu_format *fmt)
138d21ce554SMing Qian {
139d21ce554SMing Qian const struct vpu_format *info;
140d21ce554SMing Qian
141d21ce554SMing Qian info = vpu_helper_find_format(inst, fmt->type, fmt->pixfmt);
142d21ce554SMing Qian if (!info) {
143d21ce554SMing Qian info = vpu_helper_enum_format(inst, fmt->type, 0);
144d21ce554SMing Qian if (!info)
145d21ce554SMing Qian return -EINVAL;
146d21ce554SMing Qian }
147d21ce554SMing Qian memcpy(fmt, info, sizeof(*fmt));
148d21ce554SMing Qian
149d21ce554SMing Qian return 0;
150d21ce554SMing Qian }
151d21ce554SMing Qian
vpu_calc_fmt_bytesperline(struct v4l2_format * f,struct vpu_format * fmt)152d21ce554SMing Qian static int vpu_calc_fmt_bytesperline(struct v4l2_format *f, struct vpu_format *fmt)
1533cd08451SMing Qian {
1543cd08451SMing Qian struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
1553cd08451SMing Qian int i;
1563cd08451SMing Qian
157d21ce554SMing Qian if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
158d21ce554SMing Qian for (i = 0; i < fmt->comp_planes; i++)
159d21ce554SMing Qian fmt->bytesperline[i] = 0;
160d21ce554SMing Qian return 0;
161d21ce554SMing Qian }
162d21ce554SMing Qian if (pixmp->num_planes == fmt->comp_planes) {
163d21ce554SMing Qian for (i = 0; i < fmt->comp_planes; i++)
164d21ce554SMing Qian fmt->bytesperline[i] = pixmp->plane_fmt[i].bytesperline;
165d21ce554SMing Qian return 0;
166d21ce554SMing Qian }
167d21ce554SMing Qian if (pixmp->num_planes > 1)
168d21ce554SMing Qian return -EINVAL;
169d21ce554SMing Qian
170d21ce554SMing Qian /*amphion vpu only support nv12 and nv12 tiled,
171d21ce554SMing Qian * so the bytesperline of luma and chroma should be same
172d21ce554SMing Qian */
173d21ce554SMing Qian for (i = 0; i < fmt->comp_planes; i++)
174d21ce554SMing Qian fmt->bytesperline[i] = pixmp->plane_fmt[0].bytesperline;
175d21ce554SMing Qian
176d21ce554SMing Qian return 0;
1773cd08451SMing Qian }
1783cd08451SMing Qian
vpu_calc_fmt_sizeimage(struct vpu_inst * inst,struct vpu_format * fmt)179d21ce554SMing Qian static int vpu_calc_fmt_sizeimage(struct vpu_inst *inst, struct vpu_format *fmt)
180d21ce554SMing Qian {
181d21ce554SMing Qian u32 stride = 1;
182d21ce554SMing Qian int i;
183d21ce554SMing Qian
184d21ce554SMing Qian if (!(fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) {
185d21ce554SMing Qian const struct vpu_core_resources *res = vpu_get_resource(inst);
186d21ce554SMing Qian
1873cd08451SMing Qian if (res)
1883cd08451SMing Qian stride = res->stride;
1893cd08451SMing Qian }
1903cd08451SMing Qian
191d21ce554SMing Qian for (i = 0; i < fmt->comp_planes; i++) {
192d21ce554SMing Qian fmt->sizeimage[i] = vpu_helper_get_plane_size(fmt->pixfmt,
193d21ce554SMing Qian fmt->width,
194d21ce554SMing Qian fmt->height,
195d21ce554SMing Qian i,
196d21ce554SMing Qian stride,
197d21ce554SMing Qian fmt->field != V4L2_FIELD_NONE ? 1 : 0,
198d21ce554SMing Qian &fmt->bytesperline[i]);
199d21ce554SMing Qian fmt->sizeimage[i] = max_t(u32, fmt->sizeimage[i], PAGE_SIZE);
200d21ce554SMing Qian if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
201d21ce554SMing Qian fmt->sizeimage[i] = clamp_val(fmt->sizeimage[i], SZ_128K, SZ_8M);
202d21ce554SMing Qian fmt->bytesperline[i] = 0;
203d21ce554SMing Qian }
204d21ce554SMing Qian }
205d21ce554SMing Qian
206d21ce554SMing Qian return 0;
207d21ce554SMing Qian }
208d21ce554SMing Qian
vpu_get_fmt_plane_size(struct vpu_format * fmt,u32 plane_no)209d21ce554SMing Qian u32 vpu_get_fmt_plane_size(struct vpu_format *fmt, u32 plane_no)
210d21ce554SMing Qian {
211d21ce554SMing Qian u32 size;
212d21ce554SMing Qian int i;
213d21ce554SMing Qian
214d21ce554SMing Qian if (plane_no >= fmt->mem_planes)
215d21ce554SMing Qian return 0;
216d21ce554SMing Qian
217d21ce554SMing Qian if (fmt->comp_planes == fmt->mem_planes)
218d21ce554SMing Qian return fmt->sizeimage[plane_no];
219d21ce554SMing Qian if (plane_no < fmt->mem_planes - 1)
220d21ce554SMing Qian return fmt->sizeimage[plane_no];
221d21ce554SMing Qian
222d21ce554SMing Qian size = fmt->sizeimage[plane_no];
223d21ce554SMing Qian for (i = fmt->mem_planes; i < fmt->comp_planes; i++)
224d21ce554SMing Qian size += fmt->sizeimage[i];
225d21ce554SMing Qian
226d21ce554SMing Qian return size;
227d21ce554SMing Qian }
228d21ce554SMing Qian
vpu_try_fmt_common(struct vpu_inst * inst,struct v4l2_format * f,struct vpu_format * fmt)229d21ce554SMing Qian int vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f, struct vpu_format *fmt)
230d21ce554SMing Qian {
231d21ce554SMing Qian struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
232d21ce554SMing Qian int i;
233d21ce554SMing Qian int ret;
234d21ce554SMing Qian
235d21ce554SMing Qian fmt->pixfmt = pixmp->pixelformat;
236d21ce554SMing Qian fmt->type = f->type;
237d21ce554SMing Qian ret = vpu_init_format(inst, fmt);
238d21ce554SMing Qian if (ret < 0)
239d21ce554SMing Qian return ret;
240d21ce554SMing Qian
241d21ce554SMing Qian fmt->width = pixmp->width;
242d21ce554SMing Qian fmt->height = pixmp->height;
243d21ce554SMing Qian if (fmt->width)
244d21ce554SMing Qian fmt->width = vpu_helper_valid_frame_width(inst, fmt->width);
245d21ce554SMing Qian if (fmt->height)
246d21ce554SMing Qian fmt->height = vpu_helper_valid_frame_height(inst, fmt->height);
247d21ce554SMing Qian fmt->field = pixmp->field == V4L2_FIELD_ANY ? V4L2_FIELD_NONE : pixmp->field;
248d21ce554SMing Qian vpu_calc_fmt_bytesperline(f, fmt);
249d21ce554SMing Qian vpu_calc_fmt_sizeimage(inst, fmt);
250d21ce554SMing Qian if ((fmt->flags & V4L2_FMT_FLAG_COMPRESSED) && pixmp->plane_fmt[0].sizeimage)
251d21ce554SMing Qian fmt->sizeimage[0] = clamp_val(pixmp->plane_fmt[0].sizeimage, SZ_128K, SZ_8M);
252d21ce554SMing Qian
253d21ce554SMing Qian pixmp->pixelformat = fmt->pixfmt;
254d21ce554SMing Qian pixmp->width = fmt->width;
255d21ce554SMing Qian pixmp->height = fmt->height;
256d21ce554SMing Qian pixmp->flags = fmt->flags;
257d21ce554SMing Qian pixmp->num_planes = fmt->mem_planes;
258d21ce554SMing Qian pixmp->field = fmt->field;
259d21ce554SMing Qian memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
260d21ce554SMing Qian for (i = 0; i < pixmp->num_planes; i++) {
261d21ce554SMing Qian pixmp->plane_fmt[i].bytesperline = fmt->bytesperline[i];
262d21ce554SMing Qian pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(fmt, i);
263d21ce554SMing Qian memset(pixmp->plane_fmt[i].reserved, 0, sizeof(pixmp->plane_fmt[i].reserved));
264d21ce554SMing Qian }
265d21ce554SMing Qian
266d21ce554SMing Qian return 0;
2673cd08451SMing Qian }
2683cd08451SMing Qian
vpu_check_ready(struct vpu_inst * inst,u32 type)2693cd08451SMing Qian static bool vpu_check_ready(struct vpu_inst *inst, u32 type)
2703cd08451SMing Qian {
2713cd08451SMing Qian if (!inst)
2723cd08451SMing Qian return false;
2733cd08451SMing Qian if (inst->state == VPU_CODEC_STATE_DEINIT || inst->id < 0)
2743cd08451SMing Qian return false;
2753cd08451SMing Qian if (!inst->ops->check_ready)
2763cd08451SMing Qian return true;
2773cd08451SMing Qian return call_vop(inst, check_ready, type);
2783cd08451SMing Qian }
2793cd08451SMing Qian
vpu_process_output_buffer(struct vpu_inst * inst)2803cd08451SMing Qian int vpu_process_output_buffer(struct vpu_inst *inst)
2813cd08451SMing Qian {
2823cd08451SMing Qian struct v4l2_m2m_buffer *buf = NULL;
2833cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = NULL;
2843cd08451SMing Qian
2853cd08451SMing Qian if (!inst || !inst->fh.m2m_ctx)
2863cd08451SMing Qian return -EINVAL;
2873cd08451SMing Qian
2883cd08451SMing Qian if (!vpu_check_ready(inst, inst->out_format.type))
2893cd08451SMing Qian return -EINVAL;
2903cd08451SMing Qian
2913cd08451SMing Qian v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) {
2923cd08451SMing Qian vbuf = &buf->vb;
2933cd08451SMing Qian if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_IDLE)
2943cd08451SMing Qian break;
2953cd08451SMing Qian vbuf = NULL;
2963cd08451SMing Qian }
2973cd08451SMing Qian
2983cd08451SMing Qian if (!vbuf)
2993cd08451SMing Qian return -EINVAL;
3003cd08451SMing Qian
3013cd08451SMing Qian dev_dbg(inst->dev, "[%d]frame id = %d / %d\n",
3023cd08451SMing Qian inst->id, vbuf->sequence, inst->sequence);
3033cd08451SMing Qian return call_vop(inst, process_output, &vbuf->vb2_buf);
3043cd08451SMing Qian }
3053cd08451SMing Qian
vpu_process_capture_buffer(struct vpu_inst * inst)3063cd08451SMing Qian int vpu_process_capture_buffer(struct vpu_inst *inst)
3073cd08451SMing Qian {
3083cd08451SMing Qian struct v4l2_m2m_buffer *buf = NULL;
3093cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = NULL;
3103cd08451SMing Qian
3113cd08451SMing Qian if (!inst || !inst->fh.m2m_ctx)
3123cd08451SMing Qian return -EINVAL;
3133cd08451SMing Qian
3143cd08451SMing Qian if (!vpu_check_ready(inst, inst->cap_format.type))
3153cd08451SMing Qian return -EINVAL;
3163cd08451SMing Qian
3173cd08451SMing Qian v4l2_m2m_for_each_dst_buf(inst->fh.m2m_ctx, buf) {
3183cd08451SMing Qian vbuf = &buf->vb;
3193cd08451SMing Qian if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_IDLE)
3203cd08451SMing Qian break;
3213cd08451SMing Qian vbuf = NULL;
3223cd08451SMing Qian }
3233cd08451SMing Qian if (!vbuf)
3243cd08451SMing Qian return -EINVAL;
3253cd08451SMing Qian
3263cd08451SMing Qian return call_vop(inst, process_capture, &vbuf->vb2_buf);
3273cd08451SMing Qian }
3283cd08451SMing Qian
vpu_next_src_buf(struct vpu_inst * inst)329a4dca209SMing Qian struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst)
330a4dca209SMing Qian {
3311ade3f3fSMing Qian struct vb2_v4l2_buffer *src_buf = NULL;
332a4dca209SMing Qian
3331ade3f3fSMing Qian if (!inst->fh.m2m_ctx)
3341ade3f3fSMing Qian return NULL;
3351ade3f3fSMing Qian
3361ade3f3fSMing Qian src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
337a4dca209SMing Qian if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
338a4dca209SMing Qian return NULL;
339a4dca209SMing Qian
340a4dca209SMing Qian while (vpu_vb_is_codecconfig(src_buf)) {
341a4dca209SMing Qian v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
342a4dca209SMing Qian vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
343a4dca209SMing Qian v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
344a4dca209SMing Qian
345a4dca209SMing Qian src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
346a4dca209SMing Qian if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
347a4dca209SMing Qian return NULL;
348a4dca209SMing Qian }
349a4dca209SMing Qian
350a4dca209SMing Qian return src_buf;
351a4dca209SMing Qian }
352a4dca209SMing Qian
vpu_skip_frame(struct vpu_inst * inst,int count)353a4dca209SMing Qian void vpu_skip_frame(struct vpu_inst *inst, int count)
354a4dca209SMing Qian {
355a4dca209SMing Qian struct vb2_v4l2_buffer *src_buf;
356a4dca209SMing Qian enum vb2_buffer_state state;
357a4dca209SMing Qian int i = 0;
358a4dca209SMing Qian
3591ade3f3fSMing Qian if (count <= 0 || !inst->fh.m2m_ctx)
360a4dca209SMing Qian return;
361a4dca209SMing Qian
362a4dca209SMing Qian while (i < count) {
363a4dca209SMing Qian src_buf = v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
364a4dca209SMing Qian if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
365a4dca209SMing Qian return;
366a4dca209SMing Qian if (vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_DECODED)
367a4dca209SMing Qian state = VB2_BUF_STATE_DONE;
368a4dca209SMing Qian else
369a4dca209SMing Qian state = VB2_BUF_STATE_ERROR;
370a4dca209SMing Qian i++;
371a4dca209SMing Qian vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
372a4dca209SMing Qian v4l2_m2m_buf_done(src_buf, state);
373a4dca209SMing Qian }
374a4dca209SMing Qian }
375a4dca209SMing Qian
vpu_find_buf_by_sequence(struct vpu_inst * inst,u32 type,u32 sequence)3763cd08451SMing Qian struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence)
3773cd08451SMing Qian {
3783cd08451SMing Qian struct v4l2_m2m_buffer *buf = NULL;
3793cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = NULL;
3803cd08451SMing Qian
3813cd08451SMing Qian if (!inst || !inst->fh.m2m_ctx)
3823cd08451SMing Qian return NULL;
3833cd08451SMing Qian
3843cd08451SMing Qian if (V4L2_TYPE_IS_OUTPUT(type)) {
3853cd08451SMing Qian v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) {
3863cd08451SMing Qian vbuf = &buf->vb;
3873cd08451SMing Qian if (vbuf->sequence == sequence)
3883cd08451SMing Qian break;
3893cd08451SMing Qian vbuf = NULL;
3903cd08451SMing Qian }
3913cd08451SMing Qian } else {
3923cd08451SMing Qian v4l2_m2m_for_each_dst_buf(inst->fh.m2m_ctx, buf) {
3933cd08451SMing Qian vbuf = &buf->vb;
3943cd08451SMing Qian if (vbuf->sequence == sequence)
3953cd08451SMing Qian break;
3963cd08451SMing Qian vbuf = NULL;
3973cd08451SMing Qian }
3983cd08451SMing Qian }
3993cd08451SMing Qian
4003cd08451SMing Qian return vbuf;
4013cd08451SMing Qian }
4023cd08451SMing Qian
vpu_find_buf_by_idx(struct vpu_inst * inst,u32 type,u32 idx)4033cd08451SMing Qian struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx)
4043cd08451SMing Qian {
4053cd08451SMing Qian struct v4l2_m2m_buffer *buf = NULL;
4063cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = NULL;
4073cd08451SMing Qian
4083cd08451SMing Qian if (!inst || !inst->fh.m2m_ctx)
4093cd08451SMing Qian return NULL;
4103cd08451SMing Qian
4113cd08451SMing Qian if (V4L2_TYPE_IS_OUTPUT(type)) {
4123cd08451SMing Qian v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) {
4133cd08451SMing Qian vbuf = &buf->vb;
4143cd08451SMing Qian if (vbuf->vb2_buf.index == idx)
4153cd08451SMing Qian break;
4163cd08451SMing Qian vbuf = NULL;
4173cd08451SMing Qian }
4183cd08451SMing Qian } else {
4193cd08451SMing Qian v4l2_m2m_for_each_dst_buf(inst->fh.m2m_ctx, buf) {
4203cd08451SMing Qian vbuf = &buf->vb;
4213cd08451SMing Qian if (vbuf->vb2_buf.index == idx)
4223cd08451SMing Qian break;
4233cd08451SMing Qian vbuf = NULL;
4243cd08451SMing Qian }
4253cd08451SMing Qian }
4263cd08451SMing Qian
4273cd08451SMing Qian return vbuf;
4283cd08451SMing Qian }
4293cd08451SMing Qian
vpu_get_num_buffers(struct vpu_inst * inst,u32 type)4303cd08451SMing Qian int vpu_get_num_buffers(struct vpu_inst *inst, u32 type)
4313cd08451SMing Qian {
4323cd08451SMing Qian struct vb2_queue *q;
4333cd08451SMing Qian
4343cd08451SMing Qian if (!inst || !inst->fh.m2m_ctx)
4353cd08451SMing Qian return -EINVAL;
4363cd08451SMing Qian
4373cd08451SMing Qian if (V4L2_TYPE_IS_OUTPUT(type))
4383cd08451SMing Qian q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
4393cd08451SMing Qian else
4403cd08451SMing Qian q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
4413cd08451SMing Qian
4423cd08451SMing Qian return q->num_buffers;
4433cd08451SMing Qian }
4443cd08451SMing Qian
vpu_m2m_device_run(void * priv)4453cd08451SMing Qian static void vpu_m2m_device_run(void *priv)
4463cd08451SMing Qian {
4473cd08451SMing Qian }
4483cd08451SMing Qian
vpu_m2m_job_abort(void * priv)4493cd08451SMing Qian static void vpu_m2m_job_abort(void *priv)
4503cd08451SMing Qian {
4513cd08451SMing Qian struct vpu_inst *inst = priv;
4523cd08451SMing Qian struct v4l2_m2m_ctx *m2m_ctx = inst->fh.m2m_ctx;
4533cd08451SMing Qian
4543cd08451SMing Qian v4l2_m2m_job_finish(m2m_ctx->m2m_dev, m2m_ctx);
4553cd08451SMing Qian }
4563cd08451SMing Qian
4573cd08451SMing Qian static const struct v4l2_m2m_ops vpu_m2m_ops = {
4583cd08451SMing Qian .device_run = vpu_m2m_device_run,
4593cd08451SMing Qian .job_abort = vpu_m2m_job_abort
4603cd08451SMing Qian };
4613cd08451SMing Qian
vpu_vb2_queue_setup(struct vb2_queue * vq,unsigned int * buf_count,unsigned int * plane_count,unsigned int psize[],struct device * allocators[])4623cd08451SMing Qian static int vpu_vb2_queue_setup(struct vb2_queue *vq,
4633cd08451SMing Qian unsigned int *buf_count,
4643cd08451SMing Qian unsigned int *plane_count,
4653cd08451SMing Qian unsigned int psize[],
4663cd08451SMing Qian struct device *allocators[])
4673cd08451SMing Qian {
4683cd08451SMing Qian struct vpu_inst *inst = vb2_get_drv_priv(vq);
4693cd08451SMing Qian struct vpu_format *cur_fmt;
4703cd08451SMing Qian int i;
4713cd08451SMing Qian
4723cd08451SMing Qian cur_fmt = vpu_get_format(inst, vq->type);
4733cd08451SMing Qian
4743cd08451SMing Qian if (*plane_count) {
475d21ce554SMing Qian if (*plane_count != cur_fmt->mem_planes)
4763cd08451SMing Qian return -EINVAL;
477d21ce554SMing Qian for (i = 0; i < cur_fmt->mem_planes; i++) {
478d21ce554SMing Qian if (psize[i] < vpu_get_fmt_plane_size(cur_fmt, i))
4793cd08451SMing Qian return -EINVAL;
4803cd08451SMing Qian }
4813cd08451SMing Qian return 0;
4823cd08451SMing Qian }
4833cd08451SMing Qian
4847b602069SMing Qian if (V4L2_TYPE_IS_OUTPUT(vq->type))
4857b602069SMing Qian *buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out);
4867b602069SMing Qian else
4877b602069SMing Qian *buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap);
488d21ce554SMing Qian *plane_count = cur_fmt->mem_planes;
489d21ce554SMing Qian for (i = 0; i < cur_fmt->mem_planes; i++)
490d21ce554SMing Qian psize[i] = vpu_get_fmt_plane_size(cur_fmt, i);
4913cd08451SMing Qian
49273e3f092SMing Qian if (V4L2_TYPE_IS_OUTPUT(vq->type) && inst->state == VPU_CODEC_STATE_SEEK) {
49373e3f092SMing Qian vpu_trace(inst->dev, "reinit when VIDIOC_REQBUFS(OUTPUT, 0)\n");
49473e3f092SMing Qian call_void_vop(inst, release);
49573e3f092SMing Qian }
49673e3f092SMing Qian
4973cd08451SMing Qian return 0;
4983cd08451SMing Qian }
4993cd08451SMing Qian
vpu_vb2_buf_init(struct vb2_buffer * vb)5003cd08451SMing Qian static int vpu_vb2_buf_init(struct vb2_buffer *vb)
5013cd08451SMing Qian {
5023cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
5033cd08451SMing Qian
5043cd08451SMing Qian vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
5053cd08451SMing Qian return 0;
5063cd08451SMing Qian }
5073cd08451SMing Qian
vpu_vb2_buf_out_validate(struct vb2_buffer * vb)5083cd08451SMing Qian static int vpu_vb2_buf_out_validate(struct vb2_buffer *vb)
5093cd08451SMing Qian {
5103cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
5113cd08451SMing Qian
5123cd08451SMing Qian vbuf->field = V4L2_FIELD_NONE;
5133cd08451SMing Qian
5143cd08451SMing Qian return 0;
5153cd08451SMing Qian }
5163cd08451SMing Qian
vpu_vb2_buf_prepare(struct vb2_buffer * vb)5173cd08451SMing Qian static int vpu_vb2_buf_prepare(struct vb2_buffer *vb)
5183cd08451SMing Qian {
5193cd08451SMing Qian struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
5203cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
5213cd08451SMing Qian struct vpu_format *cur_fmt;
5223cd08451SMing Qian u32 i;
5233cd08451SMing Qian
5243cd08451SMing Qian cur_fmt = vpu_get_format(inst, vb->type);
525d21ce554SMing Qian for (i = 0; i < cur_fmt->mem_planes; i++) {
526d21ce554SMing Qian if (vpu_get_vb_length(vb, i) < vpu_get_fmt_plane_size(cur_fmt, i)) {
5273cd08451SMing Qian dev_dbg(inst->dev, "[%d] %s buf[%d] is invalid\n",
5283cd08451SMing Qian inst->id, vpu_type_name(vb->type), vb->index);
5293cd08451SMing Qian vpu_set_buffer_state(vbuf, VPU_BUF_STATE_ERROR);
5303cd08451SMing Qian }
5313cd08451SMing Qian }
5323cd08451SMing Qian
5333cd08451SMing Qian return 0;
5343cd08451SMing Qian }
5353cd08451SMing Qian
vpu_vb2_buf_finish(struct vb2_buffer * vb)5363cd08451SMing Qian static void vpu_vb2_buf_finish(struct vb2_buffer *vb)
5373cd08451SMing Qian {
5383cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
5393cd08451SMing Qian struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
5403cd08451SMing Qian struct vb2_queue *q = vb->vb2_queue;
5413cd08451SMing Qian
5423cd08451SMing Qian if (vbuf->flags & V4L2_BUF_FLAG_LAST)
5433cd08451SMing Qian vpu_notify_eos(inst);
5443cd08451SMing Qian
5453cd08451SMing Qian if (list_empty(&q->done_list))
5463cd08451SMing Qian call_void_vop(inst, on_queue_empty, q->type);
5473cd08451SMing Qian }
5483cd08451SMing Qian
vpu_vb2_buffers_return(struct vpu_inst * inst,unsigned int type,enum vb2_buffer_state state)5493cd08451SMing Qian void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state)
5503cd08451SMing Qian {
5513cd08451SMing Qian struct vb2_v4l2_buffer *buf;
5523cd08451SMing Qian
5533cd08451SMing Qian if (V4L2_TYPE_IS_OUTPUT(type)) {
554a9f7224cSMing Qian while ((buf = v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx))) {
555a9f7224cSMing Qian vpu_set_buffer_state(buf, VPU_BUF_STATE_IDLE);
5563cd08451SMing Qian v4l2_m2m_buf_done(buf, state);
557a9f7224cSMing Qian }
5583cd08451SMing Qian } else {
559a9f7224cSMing Qian while ((buf = v4l2_m2m_dst_buf_remove(inst->fh.m2m_ctx))) {
560a9f7224cSMing Qian vpu_set_buffer_state(buf, VPU_BUF_STATE_IDLE);
5613cd08451SMing Qian v4l2_m2m_buf_done(buf, state);
5623cd08451SMing Qian }
5633cd08451SMing Qian }
564a9f7224cSMing Qian }
5653cd08451SMing Qian
vpu_vb2_start_streaming(struct vb2_queue * q,unsigned int count)5663cd08451SMing Qian static int vpu_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
5673cd08451SMing Qian {
5683cd08451SMing Qian struct vpu_inst *inst = vb2_get_drv_priv(q);
5693cd08451SMing Qian struct vpu_format *fmt = vpu_get_format(inst, q->type);
5703cd08451SMing Qian int ret;
5713cd08451SMing Qian
5723cd08451SMing Qian vpu_inst_unlock(inst);
5733cd08451SMing Qian ret = vpu_inst_register(inst);
5743cd08451SMing Qian vpu_inst_lock(inst);
5753cd08451SMing Qian if (ret) {
5763cd08451SMing Qian vpu_vb2_buffers_return(inst, q->type, VB2_BUF_STATE_QUEUED);
5773cd08451SMing Qian return ret;
5783cd08451SMing Qian }
5793cd08451SMing Qian
5803cd08451SMing Qian vpu_trace(inst->dev, "[%d] %s %c%c%c%c %dx%d %u(%u) %u(%u) %u(%u) %d\n",
5813cd08451SMing Qian inst->id, vpu_type_name(q->type),
5823cd08451SMing Qian fmt->pixfmt,
5833cd08451SMing Qian fmt->pixfmt >> 8,
5843cd08451SMing Qian fmt->pixfmt >> 16,
5853cd08451SMing Qian fmt->pixfmt >> 24,
5863cd08451SMing Qian fmt->width, fmt->height,
5873cd08451SMing Qian fmt->sizeimage[0], fmt->bytesperline[0],
5883cd08451SMing Qian fmt->sizeimage[1], fmt->bytesperline[1],
5893cd08451SMing Qian fmt->sizeimage[2], fmt->bytesperline[2],
5903cd08451SMing Qian q->num_buffers);
5913cd08451SMing Qian vb2_clear_last_buffer_dequeued(q);
592afba6e20SMing Qian ret = call_vop(inst, start, q->type);
593a3a2efcaSMing Qian if (ret)
594a3a2efcaSMing Qian vpu_vb2_buffers_return(inst, q->type, VB2_BUF_STATE_QUEUED);
5953cd08451SMing Qian
596a3a2efcaSMing Qian return ret;
5973cd08451SMing Qian }
5983cd08451SMing Qian
vpu_vb2_stop_streaming(struct vb2_queue * q)5993cd08451SMing Qian static void vpu_vb2_stop_streaming(struct vb2_queue *q)
6003cd08451SMing Qian {
6013cd08451SMing Qian struct vpu_inst *inst = vb2_get_drv_priv(q);
6023cd08451SMing Qian
6033cd08451SMing Qian vpu_trace(inst->dev, "[%d] %s\n", inst->id, vpu_type_name(q->type));
6043cd08451SMing Qian
6053cd08451SMing Qian call_void_vop(inst, stop, q->type);
6063cd08451SMing Qian vpu_vb2_buffers_return(inst, q->type, VB2_BUF_STATE_ERROR);
6073cd08451SMing Qian if (V4L2_TYPE_IS_OUTPUT(q->type))
6083cd08451SMing Qian inst->sequence = 0;
6093cd08451SMing Qian }
6103cd08451SMing Qian
vpu_vb2_buf_queue(struct vb2_buffer * vb)6113cd08451SMing Qian static void vpu_vb2_buf_queue(struct vb2_buffer *vb)
6123cd08451SMing Qian {
6133cd08451SMing Qian struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
6143cd08451SMing Qian struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
6153cd08451SMing Qian
61605a03effSMing Qian if (V4L2_TYPE_IS_OUTPUT(vb->type))
6173cd08451SMing Qian vbuf->sequence = inst->sequence++;
6183cd08451SMing Qian
6193cd08451SMing Qian v4l2_m2m_buf_queue(inst->fh.m2m_ctx, vbuf);
6203cd08451SMing Qian vpu_process_output_buffer(inst);
6213cd08451SMing Qian vpu_process_capture_buffer(inst);
6223cd08451SMing Qian }
6233cd08451SMing Qian
6243cd08451SMing Qian static const struct vb2_ops vpu_vb2_ops = {
6253cd08451SMing Qian .queue_setup = vpu_vb2_queue_setup,
6263cd08451SMing Qian .buf_init = vpu_vb2_buf_init,
6273cd08451SMing Qian .buf_out_validate = vpu_vb2_buf_out_validate,
6283cd08451SMing Qian .buf_prepare = vpu_vb2_buf_prepare,
6293cd08451SMing Qian .buf_finish = vpu_vb2_buf_finish,
6303cd08451SMing Qian .start_streaming = vpu_vb2_start_streaming,
6313cd08451SMing Qian .stop_streaming = vpu_vb2_stop_streaming,
6323cd08451SMing Qian .buf_queue = vpu_vb2_buf_queue,
6333cd08451SMing Qian .wait_prepare = vb2_ops_wait_prepare,
6343cd08451SMing Qian .wait_finish = vb2_ops_wait_finish,
6353cd08451SMing Qian };
6363cd08451SMing Qian
vpu_m2m_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)6373cd08451SMing Qian static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
6383cd08451SMing Qian {
6393cd08451SMing Qian struct vpu_inst *inst = priv;
6403cd08451SMing Qian int ret;
6413cd08451SMing Qian
6423cd08451SMing Qian src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
6433cd08451SMing Qian inst->out_format.type = src_vq->type;
6443cd08451SMing Qian src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
6453cd08451SMing Qian src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
6463cd08451SMing Qian src_vq->ops = &vpu_vb2_ops;
6473cd08451SMing Qian src_vq->mem_ops = &vb2_dma_contig_memops;
6483cd08451SMing Qian if (inst->type == VPU_CORE_TYPE_DEC && inst->use_stream_buffer)
6493cd08451SMing Qian src_vq->mem_ops = &vb2_vmalloc_memops;
6503cd08451SMing Qian src_vq->drv_priv = inst;
6513cd08451SMing Qian src_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
6523cd08451SMing Qian src_vq->min_buffers_needed = 1;
6533cd08451SMing Qian src_vq->dev = inst->vpu->dev;
6543cd08451SMing Qian src_vq->lock = &inst->lock;
6553cd08451SMing Qian ret = vb2_queue_init(src_vq);
6563cd08451SMing Qian if (ret)
6573cd08451SMing Qian return ret;
6583cd08451SMing Qian
6593cd08451SMing Qian dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
6603cd08451SMing Qian inst->cap_format.type = dst_vq->type;
6613cd08451SMing Qian dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
6623cd08451SMing Qian dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
6633cd08451SMing Qian dst_vq->ops = &vpu_vb2_ops;
6643cd08451SMing Qian dst_vq->mem_ops = &vb2_dma_contig_memops;
6653cd08451SMing Qian if (inst->type == VPU_CORE_TYPE_ENC && inst->use_stream_buffer)
6663cd08451SMing Qian dst_vq->mem_ops = &vb2_vmalloc_memops;
6673cd08451SMing Qian dst_vq->drv_priv = inst;
6683cd08451SMing Qian dst_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
6693cd08451SMing Qian dst_vq->min_buffers_needed = 1;
6703cd08451SMing Qian dst_vq->dev = inst->vpu->dev;
6713cd08451SMing Qian dst_vq->lock = &inst->lock;
6723cd08451SMing Qian ret = vb2_queue_init(dst_vq);
6733cd08451SMing Qian if (ret) {
6743cd08451SMing Qian vb2_queue_release(src_vq);
6753cd08451SMing Qian return ret;
6763cd08451SMing Qian }
6773cd08451SMing Qian
6783cd08451SMing Qian return 0;
6793cd08451SMing Qian }
6803cd08451SMing Qian
vpu_v4l2_release(struct vpu_inst * inst)6813cd08451SMing Qian static int vpu_v4l2_release(struct vpu_inst *inst)
6823cd08451SMing Qian {
6833cd08451SMing Qian vpu_trace(inst->vpu->dev, "%p\n", inst);
6843cd08451SMing Qian
6853cd08451SMing Qian vpu_release_core(inst->core);
6863cd08451SMing Qian put_device(inst->dev);
6873cd08451SMing Qian
6883cd08451SMing Qian if (inst->workqueue) {
6893cd08451SMing Qian cancel_work_sync(&inst->msg_work);
6903cd08451SMing Qian destroy_workqueue(inst->workqueue);
6913cd08451SMing Qian inst->workqueue = NULL;
6923cd08451SMing Qian }
6933cd08451SMing Qian
6943cd08451SMing Qian v4l2_ctrl_handler_free(&inst->ctrl_handler);
6953cd08451SMing Qian mutex_destroy(&inst->lock);
6963cd08451SMing Qian v4l2_fh_del(&inst->fh);
6973cd08451SMing Qian v4l2_fh_exit(&inst->fh);
6983cd08451SMing Qian
6993cd08451SMing Qian call_void_vop(inst, cleanup);
7003cd08451SMing Qian
7013cd08451SMing Qian return 0;
7023cd08451SMing Qian }
7033cd08451SMing Qian
vpu_v4l2_open(struct file * file,struct vpu_inst * inst)7043cd08451SMing Qian int vpu_v4l2_open(struct file *file, struct vpu_inst *inst)
7053cd08451SMing Qian {
7063cd08451SMing Qian struct vpu_dev *vpu = video_drvdata(file);
7073cd08451SMing Qian struct vpu_func *func;
7083cd08451SMing Qian int ret = 0;
7093cd08451SMing Qian
7103cd08451SMing Qian if (!inst || !inst->ops)
7113cd08451SMing Qian return -EINVAL;
7123cd08451SMing Qian
7133cd08451SMing Qian if (inst->type == VPU_CORE_TYPE_ENC)
7143cd08451SMing Qian func = &vpu->encoder;
7153cd08451SMing Qian else
7163cd08451SMing Qian func = &vpu->decoder;
7173cd08451SMing Qian
7183cd08451SMing Qian atomic_set(&inst->ref_count, 0);
7197c180bf2SMing Qian atomic_long_set(&inst->last_response_cmd, 0);
7203cd08451SMing Qian vpu_inst_get(inst);
7213cd08451SMing Qian inst->vpu = vpu;
7223cd08451SMing Qian inst->core = vpu_request_core(vpu, inst->type);
7233cd08451SMing Qian if (inst->core)
7243cd08451SMing Qian inst->dev = get_device(inst->core->dev);
7253cd08451SMing Qian mutex_init(&inst->lock);
7263cd08451SMing Qian INIT_LIST_HEAD(&inst->cmd_q);
7273cd08451SMing Qian inst->id = VPU_INST_NULL_ID;
7283cd08451SMing Qian inst->release = vpu_v4l2_release;
7293cd08451SMing Qian inst->pid = current->pid;
7303cd08451SMing Qian inst->tgid = current->tgid;
7313cd08451SMing Qian inst->min_buffer_cap = 2;
7323cd08451SMing Qian inst->min_buffer_out = 2;
7333cd08451SMing Qian v4l2_fh_init(&inst->fh, func->vfd);
7343cd08451SMing Qian v4l2_fh_add(&inst->fh);
7353cd08451SMing Qian
7363cd08451SMing Qian ret = call_vop(inst, ctrl_init);
7373cd08451SMing Qian if (ret)
7383cd08451SMing Qian goto error;
7393cd08451SMing Qian
7403cd08451SMing Qian inst->fh.m2m_ctx = v4l2_m2m_ctx_init(func->m2m_dev, inst, vpu_m2m_queue_init);
7413cd08451SMing Qian if (IS_ERR(inst->fh.m2m_ctx)) {
7423cd08451SMing Qian dev_err(vpu->dev, "v4l2_m2m_ctx_init fail\n");
7433cd08451SMing Qian ret = PTR_ERR(inst->fh.m2m_ctx);
7443cd08451SMing Qian goto error;
7453cd08451SMing Qian }
7463cd08451SMing Qian
7473cd08451SMing Qian inst->fh.ctrl_handler = &inst->ctrl_handler;
7483cd08451SMing Qian file->private_data = &inst->fh;
7493cd08451SMing Qian inst->state = VPU_CODEC_STATE_DEINIT;
750bce487a4STejun Heo inst->workqueue = alloc_ordered_workqueue("vpu_inst", WQ_MEM_RECLAIM);
7513cd08451SMing Qian if (inst->workqueue) {
7523cd08451SMing Qian INIT_WORK(&inst->msg_work, vpu_inst_run_work);
7533cd08451SMing Qian ret = kfifo_init(&inst->msg_fifo,
7543cd08451SMing Qian inst->msg_buffer,
7553cd08451SMing Qian rounddown_pow_of_two(sizeof(inst->msg_buffer)));
7563cd08451SMing Qian if (ret) {
7573cd08451SMing Qian destroy_workqueue(inst->workqueue);
7583cd08451SMing Qian inst->workqueue = NULL;
7593cd08451SMing Qian }
7603cd08451SMing Qian }
7613cd08451SMing Qian vpu_trace(vpu->dev, "tgid = %d, pid = %d, type = %s, inst = %p\n",
7623cd08451SMing Qian inst->tgid, inst->pid, vpu_core_type_desc(inst->type), inst);
7633cd08451SMing Qian
7643cd08451SMing Qian return 0;
7653cd08451SMing Qian error:
7663cd08451SMing Qian vpu_inst_put(inst);
7673cd08451SMing Qian return ret;
7683cd08451SMing Qian }
7693cd08451SMing Qian
vpu_v4l2_close(struct file * file)7703cd08451SMing Qian int vpu_v4l2_close(struct file *file)
7713cd08451SMing Qian {
7723cd08451SMing Qian struct vpu_dev *vpu = video_drvdata(file);
7733cd08451SMing Qian struct vpu_inst *inst = to_inst(file);
7743cd08451SMing Qian
7753cd08451SMing Qian vpu_trace(vpu->dev, "tgid = %d, pid = %d, inst = %p\n", inst->tgid, inst->pid, inst);
7763cd08451SMing Qian
777b3dd974aSMing Qian vpu_inst_lock(inst);
778b3dd974aSMing Qian if (inst->fh.m2m_ctx) {
779b3dd974aSMing Qian v4l2_m2m_ctx_release(inst->fh.m2m_ctx);
780b3dd974aSMing Qian inst->fh.m2m_ctx = NULL;
781b3dd974aSMing Qian }
78273e3f092SMing Qian call_void_vop(inst, release);
783b3dd974aSMing Qian vpu_inst_unlock(inst);
784b3dd974aSMing Qian
7853cd08451SMing Qian vpu_inst_unregister(inst);
7863cd08451SMing Qian vpu_inst_put(inst);
7873cd08451SMing Qian
7883cd08451SMing Qian return 0;
7893cd08451SMing Qian }
7903cd08451SMing Qian
vpu_add_func(struct vpu_dev * vpu,struct vpu_func * func)7913cd08451SMing Qian int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func)
7923cd08451SMing Qian {
7933cd08451SMing Qian struct video_device *vfd;
7943cd08451SMing Qian int ret;
7953cd08451SMing Qian
7963cd08451SMing Qian if (!vpu || !func)
7973cd08451SMing Qian return -EINVAL;
7983cd08451SMing Qian
7993cd08451SMing Qian if (func->vfd)
8003cd08451SMing Qian return 0;
8013cd08451SMing Qian
8023cd08451SMing Qian func->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
8033cd08451SMing Qian if (IS_ERR(func->m2m_dev)) {
8043cd08451SMing Qian dev_err(vpu->dev, "v4l2_m2m_init fail\n");
8053cd08451SMing Qian func->vfd = NULL;
8063cd08451SMing Qian return PTR_ERR(func->m2m_dev);
8073cd08451SMing Qian }
8083cd08451SMing Qian
8093cd08451SMing Qian vfd = video_device_alloc();
8103cd08451SMing Qian if (!vfd) {
8113cd08451SMing Qian v4l2_m2m_release(func->m2m_dev);
8123cd08451SMing Qian dev_err(vpu->dev, "alloc vpu decoder video device fail\n");
8133cd08451SMing Qian return -ENOMEM;
8143cd08451SMing Qian }
8153cd08451SMing Qian vfd->release = video_device_release;
8163cd08451SMing Qian vfd->vfl_dir = VFL_DIR_M2M;
8173cd08451SMing Qian vfd->v4l2_dev = &vpu->v4l2_dev;
8183cd08451SMing Qian vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
8193cd08451SMing Qian if (func->type == VPU_CORE_TYPE_ENC) {
8203cd08451SMing Qian strscpy(vfd->name, "amphion-vpu-encoder", sizeof(vfd->name));
8213cd08451SMing Qian vfd->fops = venc_get_fops();
8223cd08451SMing Qian vfd->ioctl_ops = venc_get_ioctl_ops();
8233cd08451SMing Qian } else {
8243cd08451SMing Qian strscpy(vfd->name, "amphion-vpu-decoder", sizeof(vfd->name));
8253cd08451SMing Qian vfd->fops = vdec_get_fops();
8263cd08451SMing Qian vfd->ioctl_ops = vdec_get_ioctl_ops();
8273cd08451SMing Qian }
828*988cc10dSMing Qian video_set_drvdata(vfd, vpu);
8293cd08451SMing Qian
8303cd08451SMing Qian ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
8313cd08451SMing Qian if (ret) {
8323cd08451SMing Qian video_device_release(vfd);
8333cd08451SMing Qian v4l2_m2m_release(func->m2m_dev);
8343cd08451SMing Qian return ret;
8353cd08451SMing Qian }
8363cd08451SMing Qian func->vfd = vfd;
8373cd08451SMing Qian
8383cd08451SMing Qian ret = v4l2_m2m_register_media_controller(func->m2m_dev, func->vfd, func->function);
8393cd08451SMing Qian if (ret) {
8403cd08451SMing Qian v4l2_m2m_release(func->m2m_dev);
8413cd08451SMing Qian func->m2m_dev = NULL;
8423cd08451SMing Qian video_unregister_device(func->vfd);
8433cd08451SMing Qian func->vfd = NULL;
8443cd08451SMing Qian return ret;
8453cd08451SMing Qian }
8463cd08451SMing Qian
8473cd08451SMing Qian return 0;
8483cd08451SMing Qian }
8493cd08451SMing Qian
vpu_remove_func(struct vpu_func * func)8503cd08451SMing Qian void vpu_remove_func(struct vpu_func *func)
8513cd08451SMing Qian {
8523cd08451SMing Qian if (!func)
8533cd08451SMing Qian return;
8543cd08451SMing Qian
8553cd08451SMing Qian if (func->m2m_dev) {
8563cd08451SMing Qian v4l2_m2m_unregister_media_controller(func->m2m_dev);
8573cd08451SMing Qian v4l2_m2m_release(func->m2m_dev);
8583cd08451SMing Qian func->m2m_dev = NULL;
8593cd08451SMing Qian }
8603cd08451SMing Qian if (func->vfd) {
8613cd08451SMing Qian video_unregister_device(func->vfd);
8623cd08451SMing Qian func->vfd = NULL;
8633cd08451SMing Qian }
8643cd08451SMing Qian }
865