1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2015-2016 MediaTek Inc.
4 * Author: Houlong Wei <houlong.wei@mediatek.com>
5 * Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
8 #include <linux/device.h>
9 #include <linux/errno.h>
10 #include <linux/kernel.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/slab.h>
13 #include <linux/workqueue.h>
14 #include <media/v4l2-event.h>
15 #include <media/v4l2-ioctl.h>
17 #include "mtk_mdp_core.h"
18 #include "mtk_mdp_m2m.h"
19 #include "mtk_mdp_regs.h"
24 * struct mtk_mdp_pix_limit - image pixel size limits
25 * @org_w: source pixel width
26 * @org_h: source pixel height
27 * @target_rot_dis_w: pixel dst scaled width with the rotator is off
28 * @target_rot_dis_h: pixel dst scaled height with the rotator is off
29 * @target_rot_en_w: pixel dst scaled width with the rotator is on
30 * @target_rot_en_h: pixel dst scaled height with the rotator is on
32 struct mtk_mdp_pix_limit
{
41 static struct mtk_mdp_pix_align mtk_mdp_size_align
= {
48 static const struct mtk_mdp_fmt mtk_mdp_formats
[] = {
50 .pixelformat
= V4L2_PIX_FMT_MT21C
,
52 .row_depth
= { 8, 8 },
55 .align
= &mtk_mdp_size_align
,
56 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
,
58 .pixelformat
= V4L2_PIX_FMT_NV12M
,
60 .row_depth
= { 8, 8 },
63 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
|
64 MTK_MDP_FMT_FLAG_CAPTURE
,
66 .pixelformat
= V4L2_PIX_FMT_YUV420M
,
68 .row_depth
= { 8, 4, 4 },
71 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
|
72 MTK_MDP_FMT_FLAG_CAPTURE
,
74 .pixelformat
= V4L2_PIX_FMT_YVU420
,
79 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
|
80 MTK_MDP_FMT_FLAG_CAPTURE
,
84 static struct mtk_mdp_pix_limit mtk_mdp_size_max
= {
85 .target_rot_dis_w
= 4096,
86 .target_rot_dis_h
= 4096,
87 .target_rot_en_w
= 4096,
88 .target_rot_en_h
= 4096,
91 static struct mtk_mdp_pix_limit mtk_mdp_size_min
= {
94 .target_rot_dis_w
= 16,
95 .target_rot_dis_h
= 16,
96 .target_rot_en_w
= 16,
97 .target_rot_en_h
= 16,
100 /* align size for normal raster scan pixel format */
101 static struct mtk_mdp_pix_align mtk_mdp_rs_align
= {
108 static struct mtk_mdp_variant mtk_mdp_default_variant
= {
109 .pix_max
= &mtk_mdp_size_max
,
110 .pix_min
= &mtk_mdp_size_min
,
111 .pix_align
= &mtk_mdp_rs_align
,
112 .h_scale_up_max
= 32,
113 .v_scale_up_max
= 32,
114 .h_scale_down_max
= 32,
115 .v_scale_down_max
= 128,
118 static const struct mtk_mdp_fmt
*mtk_mdp_find_fmt(u32 pixelformat
, u32 type
)
122 flag
= V4L2_TYPE_IS_OUTPUT(type
) ? MTK_MDP_FMT_FLAG_OUTPUT
:
123 MTK_MDP_FMT_FLAG_CAPTURE
;
125 for (i
= 0; i
< ARRAY_SIZE(mtk_mdp_formats
); ++i
) {
126 if (!(mtk_mdp_formats
[i
].flags
& flag
))
128 if (mtk_mdp_formats
[i
].pixelformat
== pixelformat
)
129 return &mtk_mdp_formats
[i
];
134 static const struct mtk_mdp_fmt
*mtk_mdp_find_fmt_by_index(u32 index
, u32 type
)
136 u32 i
, flag
, num
= 0;
138 flag
= V4L2_TYPE_IS_OUTPUT(type
) ? MTK_MDP_FMT_FLAG_OUTPUT
:
139 MTK_MDP_FMT_FLAG_CAPTURE
;
141 for (i
= 0; i
< ARRAY_SIZE(mtk_mdp_formats
); ++i
) {
142 if (!(mtk_mdp_formats
[i
].flags
& flag
))
145 return &mtk_mdp_formats
[i
];
151 static void mtk_mdp_bound_align_image(u32
*w
, unsigned int wmin
,
152 unsigned int wmax
, unsigned int align_w
,
153 u32
*h
, unsigned int hmin
,
154 unsigned int hmax
, unsigned int align_h
)
156 int org_w
, org_h
, step_w
, step_h
;
161 walign
= ffs(align_w
) - 1;
162 halign
= ffs(align_h
) - 1;
163 v4l_bound_align_image(w
, wmin
, wmax
, walign
, h
, hmin
, hmax
, halign
, 0);
165 step_w
= 1 << walign
;
166 step_h
= 1 << halign
;
167 if (*w
< org_w
&& (*w
+ step_w
) <= wmax
)
169 if (*h
< org_h
&& (*h
+ step_h
) <= hmax
)
173 static const struct mtk_mdp_fmt
*mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx
*ctx
,
174 struct v4l2_format
*f
)
176 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
177 struct mtk_mdp_variant
*variant
= mdp
->variant
;
178 struct v4l2_pix_format_mplane
*pix_mp
= &f
->fmt
.pix_mp
;
179 const struct mtk_mdp_fmt
*fmt
;
180 u32 max_w
, max_h
, align_w
, align_h
;
181 u32 min_w
, min_h
, org_w
, org_h
;
184 fmt
= mtk_mdp_find_fmt(pix_mp
->pixelformat
, f
->type
);
186 fmt
= mtk_mdp_find_fmt_by_index(0, f
->type
);
188 dev_dbg(&ctx
->mdp_dev
->pdev
->dev
,
189 "pixelformat format 0x%X invalid\n",
190 pix_mp
->pixelformat
);
194 pix_mp
->field
= V4L2_FIELD_NONE
;
195 pix_mp
->pixelformat
= fmt
->pixelformat
;
196 if (!V4L2_TYPE_IS_OUTPUT(f
->type
)) {
197 pix_mp
->colorspace
= ctx
->colorspace
;
198 pix_mp
->xfer_func
= ctx
->xfer_func
;
199 pix_mp
->ycbcr_enc
= ctx
->ycbcr_enc
;
200 pix_mp
->quantization
= ctx
->quant
;
202 memset(pix_mp
->reserved
, 0, sizeof(pix_mp
->reserved
));
204 max_w
= variant
->pix_max
->target_rot_dis_w
;
205 max_h
= variant
->pix_max
->target_rot_dis_h
;
207 if (fmt
->align
== NULL
) {
208 /* use default alignment */
209 align_w
= variant
->pix_align
->org_w
;
210 align_h
= variant
->pix_align
->org_h
;
212 align_w
= fmt
->align
->org_w
;
213 align_h
= fmt
->align
->org_h
;
216 if (V4L2_TYPE_IS_OUTPUT(f
->type
)) {
217 min_w
= variant
->pix_min
->org_w
;
218 min_h
= variant
->pix_min
->org_h
;
220 min_w
= variant
->pix_min
->target_rot_dis_w
;
221 min_h
= variant
->pix_min
->target_rot_dis_h
;
224 mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
225 ctx
->id
, f
->type
, pix_mp
->width
, pix_mp
->height
,
226 align_w
, align_h
, max_w
, max_h
);
228 * To check if image size is modified to adjust parameter against
231 org_w
= pix_mp
->width
;
232 org_h
= pix_mp
->height
;
234 mtk_mdp_bound_align_image(&pix_mp
->width
, min_w
, max_w
, align_w
,
235 &pix_mp
->height
, min_h
, max_h
, align_h
);
237 if (org_w
!= pix_mp
->width
|| org_h
!= pix_mp
->height
)
238 mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx
->id
,
239 org_w
, org_h
, pix_mp
->width
, pix_mp
->height
);
240 pix_mp
->num_planes
= fmt
->num_planes
;
242 for (i
= 0; i
< pix_mp
->num_planes
; ++i
) {
243 int bpl
= (pix_mp
->width
* fmt
->row_depth
[i
]) / 8;
244 int sizeimage
= (pix_mp
->width
* pix_mp
->height
*
247 pix_mp
->plane_fmt
[i
].bytesperline
= bpl
;
248 if (pix_mp
->plane_fmt
[i
].sizeimage
< sizeimage
)
249 pix_mp
->plane_fmt
[i
].sizeimage
= sizeimage
;
250 memset(pix_mp
->plane_fmt
[i
].reserved
, 0,
251 sizeof(pix_mp
->plane_fmt
[i
].reserved
));
252 mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx
->id
,
253 i
, bpl
, pix_mp
->plane_fmt
[i
].sizeimage
, sizeimage
);
259 static struct mtk_mdp_frame
*mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx
*ctx
,
260 enum v4l2_buf_type type
)
262 if (V4L2_TYPE_IS_OUTPUT(type
))
263 return &ctx
->s_frame
;
264 return &ctx
->d_frame
;
267 static void mtk_mdp_check_crop_change(u32 new_w
, u32 new_h
, u32
*w
, u32
*h
)
269 if (new_w
!= *w
|| new_h
!= *h
) {
270 mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
271 *w
, *h
, new_w
, new_h
);
278 static int mtk_mdp_try_crop(struct mtk_mdp_ctx
*ctx
, u32 type
,
281 struct mtk_mdp_frame
*frame
;
282 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
283 struct mtk_mdp_variant
*variant
= mdp
->variant
;
284 u32 align_w
, align_h
, new_w
, new_h
;
285 u32 min_w
, min_h
, max_w
, max_h
;
287 if (r
->top
< 0 || r
->left
< 0) {
288 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
289 "doesn't support negative values for top & left\n");
293 mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx
->id
, type
,
294 r
->width
, r
->height
);
296 frame
= mtk_mdp_ctx_get_frame(ctx
, type
);
297 max_w
= frame
->width
;
298 max_h
= frame
->height
;
302 if (V4L2_TYPE_IS_OUTPUT(type
)) {
308 align_w
= variant
->pix_align
->target_w
;
309 align_h
= variant
->pix_align
->target_h
;
310 if (ctx
->ctrls
.rotate
->val
== 90 ||
311 ctx
->ctrls
.rotate
->val
== 270) {
312 max_w
= frame
->height
;
313 max_h
= frame
->width
;
314 min_w
= variant
->pix_min
->target_rot_en_w
;
315 min_h
= variant
->pix_min
->target_rot_en_h
;
319 min_w
= variant
->pix_min
->target_rot_dis_w
;
320 min_h
= variant
->pix_min
->target_rot_dis_h
;
324 mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx
->id
,
325 align_w
, align_h
, min_w
, min_h
, new_w
, new_h
);
327 mtk_mdp_bound_align_image(&new_w
, min_w
, max_w
, align_w
,
328 &new_h
, min_h
, max_h
, align_h
);
330 if (!V4L2_TYPE_IS_OUTPUT(type
) &&
331 (ctx
->ctrls
.rotate
->val
== 90 ||
332 ctx
->ctrls
.rotate
->val
== 270))
333 mtk_mdp_check_crop_change(new_h
, new_w
,
334 &r
->width
, &r
->height
);
336 mtk_mdp_check_crop_change(new_w
, new_h
,
337 &r
->width
, &r
->height
);
339 /* adjust left/top if cropping rectangle is out of bounds */
340 /* Need to add code to algin left value with 2's multiple */
341 if (r
->left
+ new_w
> max_w
)
342 r
->left
= max_w
- new_w
;
343 if (r
->top
+ new_h
> max_h
)
344 r
->top
= max_h
- new_h
;
349 mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx
->id
,
350 r
->left
, r
->top
, r
->width
,
351 r
->height
, max_w
, max_h
);
355 static inline struct mtk_mdp_ctx
*fh_to_ctx(struct v4l2_fh
*fh
)
357 return container_of(fh
, struct mtk_mdp_ctx
, fh
);
360 static inline struct mtk_mdp_ctx
*ctrl_to_ctx(struct v4l2_ctrl
*ctrl
)
362 return container_of(ctrl
->handler
, struct mtk_mdp_ctx
, ctrl_handler
);
365 void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx
*ctx
, u32 state
)
367 mutex_lock(&ctx
->slock
);
369 mutex_unlock(&ctx
->slock
);
372 static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx
*ctx
, u32 state
)
374 mutex_lock(&ctx
->slock
);
375 ctx
->state
&= ~state
;
376 mutex_unlock(&ctx
->slock
);
379 static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx
*ctx
, u32 mask
)
383 mutex_lock(&ctx
->slock
);
384 ret
= (ctx
->state
& mask
) == mask
;
385 mutex_unlock(&ctx
->slock
);
389 static void mtk_mdp_set_frame_size(struct mtk_mdp_frame
*frame
, int width
,
392 frame
->width
= width
;
393 frame
->height
= height
;
394 frame
->crop
.width
= width
;
395 frame
->crop
.height
= height
;
396 frame
->crop
.left
= 0;
400 static int mtk_mdp_m2m_start_streaming(struct vb2_queue
*q
, unsigned int count
)
402 struct mtk_mdp_ctx
*ctx
= q
->drv_priv
;
405 ret
= pm_runtime_get_sync(&ctx
->mdp_dev
->pdev
->dev
);
407 mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
413 static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx
*ctx
,
414 enum v4l2_buf_type type
)
416 if (V4L2_TYPE_IS_OUTPUT(type
))
417 return v4l2_m2m_src_buf_remove(ctx
->m2m_ctx
);
419 return v4l2_m2m_dst_buf_remove(ctx
->m2m_ctx
);
422 static void mtk_mdp_m2m_stop_streaming(struct vb2_queue
*q
)
424 struct mtk_mdp_ctx
*ctx
= q
->drv_priv
;
425 struct vb2_buffer
*vb
;
427 vb
= mtk_mdp_m2m_buf_remove(ctx
, q
->type
);
429 v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb
), VB2_BUF_STATE_ERROR
);
430 vb
= mtk_mdp_m2m_buf_remove(ctx
, q
->type
);
433 pm_runtime_put(&ctx
->mdp_dev
->pdev
->dev
);
436 /* The color format (num_planes) must be already configured. */
437 static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx
*ctx
,
438 struct vb2_buffer
*vb
,
439 struct mtk_mdp_frame
*frame
,
440 struct mtk_mdp_addr
*addr
)
442 u32 pix_size
, planes
, i
;
444 pix_size
= frame
->width
* frame
->height
;
445 planes
= min_t(u32
, frame
->fmt
->num_planes
, ARRAY_SIZE(addr
->addr
));
446 for (i
= 0; i
< planes
; i
++)
447 addr
->addr
[i
] = vb2_dma_contig_plane_dma_addr(vb
, i
);
450 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_YVU420
) {
451 addr
->addr
[1] = (dma_addr_t
)(addr
->addr
[0] + pix_size
);
452 addr
->addr
[2] = (dma_addr_t
)(addr
->addr
[1] +
455 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
456 "Invalid pixelformat:0x%x\n",
457 frame
->fmt
->pixelformat
);
460 mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
461 ctx
->id
, planes
, pix_size
, (void *)addr
->addr
[0],
462 (void *)addr
->addr
[1], (void *)addr
->addr
[2]);
465 static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx
*ctx
)
467 struct mtk_mdp_frame
*s_frame
, *d_frame
;
468 struct vb2_v4l2_buffer
*src_vbuf
, *dst_vbuf
;
470 s_frame
= &ctx
->s_frame
;
471 d_frame
= &ctx
->d_frame
;
473 src_vbuf
= v4l2_m2m_next_src_buf(ctx
->m2m_ctx
);
474 mtk_mdp_prepare_addr(ctx
, &src_vbuf
->vb2_buf
, s_frame
, &s_frame
->addr
);
476 dst_vbuf
= v4l2_m2m_next_dst_buf(ctx
->m2m_ctx
);
477 mtk_mdp_prepare_addr(ctx
, &dst_vbuf
->vb2_buf
, d_frame
, &d_frame
->addr
);
479 dst_vbuf
->vb2_buf
.timestamp
= src_vbuf
->vb2_buf
.timestamp
;
482 static void mtk_mdp_process_done(void *priv
, int vb_state
)
484 struct mtk_mdp_dev
*mdp
= priv
;
485 struct mtk_mdp_ctx
*ctx
;
486 struct vb2_v4l2_buffer
*src_vbuf
, *dst_vbuf
;
488 ctx
= v4l2_m2m_get_curr_priv(mdp
->m2m_dev
);
492 src_vbuf
= v4l2_m2m_src_buf_remove(ctx
->m2m_ctx
);
493 dst_vbuf
= v4l2_m2m_dst_buf_remove(ctx
->m2m_ctx
);
495 dst_vbuf
->vb2_buf
.timestamp
= src_vbuf
->vb2_buf
.timestamp
;
496 dst_vbuf
->timecode
= src_vbuf
->timecode
;
497 dst_vbuf
->flags
&= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
498 dst_vbuf
->flags
|= src_vbuf
->flags
& V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
500 v4l2_m2m_buf_done(src_vbuf
, vb_state
);
501 v4l2_m2m_buf_done(dst_vbuf
, vb_state
);
502 v4l2_m2m_job_finish(ctx
->mdp_dev
->m2m_dev
, ctx
->m2m_ctx
);
505 static void mtk_mdp_m2m_worker(struct work_struct
*work
)
507 struct mtk_mdp_ctx
*ctx
=
508 container_of(work
, struct mtk_mdp_ctx
, work
);
509 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
510 enum vb2_buffer_state buf_state
= VB2_BUF_STATE_ERROR
;
513 if (mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_CTX_ERROR
)) {
514 dev_err(&mdp
->pdev
->dev
, "ctx is in error state");
518 mtk_mdp_m2m_get_bufs(ctx
);
520 mtk_mdp_hw_set_input_addr(ctx
, &ctx
->s_frame
.addr
);
521 mtk_mdp_hw_set_output_addr(ctx
, &ctx
->d_frame
.addr
);
523 mtk_mdp_hw_set_in_size(ctx
);
524 mtk_mdp_hw_set_in_image_format(ctx
);
526 mtk_mdp_hw_set_out_size(ctx
);
527 mtk_mdp_hw_set_out_image_format(ctx
);
529 mtk_mdp_hw_set_rotation(ctx
);
530 mtk_mdp_hw_set_global_alpha(ctx
);
532 ret
= mtk_mdp_vpu_process(&ctx
->vpu
);
534 dev_err(&mdp
->pdev
->dev
, "processing failed: %d", ret
);
538 buf_state
= VB2_BUF_STATE_DONE
;
541 mtk_mdp_process_done(mdp
, buf_state
);
544 static void mtk_mdp_m2m_device_run(void *priv
)
546 struct mtk_mdp_ctx
*ctx
= priv
;
548 queue_work(ctx
->mdp_dev
->job_wq
, &ctx
->work
);
551 static int mtk_mdp_m2m_queue_setup(struct vb2_queue
*vq
,
552 unsigned int *num_buffers
, unsigned int *num_planes
,
553 unsigned int sizes
[], struct device
*alloc_devs
[])
555 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vq
);
556 struct mtk_mdp_frame
*frame
;
559 frame
= mtk_mdp_ctx_get_frame(ctx
, vq
->type
);
560 *num_planes
= frame
->fmt
->num_planes
;
561 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
562 sizes
[i
] = frame
->payload
[i
];
563 mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
564 ctx
->id
, vq
->type
, *num_planes
, *num_buffers
,
569 static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer
*vb
)
571 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
572 struct mtk_mdp_frame
*frame
;
575 frame
= mtk_mdp_ctx_get_frame(ctx
, vb
->vb2_queue
->type
);
577 if (!V4L2_TYPE_IS_OUTPUT(vb
->vb2_queue
->type
)) {
578 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
579 vb2_set_plane_payload(vb
, i
, frame
->payload
[i
]);
585 static void mtk_mdp_m2m_buf_queue(struct vb2_buffer
*vb
)
587 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
589 v4l2_m2m_buf_queue(ctx
->m2m_ctx
, to_vb2_v4l2_buffer(vb
));
592 static const struct vb2_ops mtk_mdp_m2m_qops
= {
593 .queue_setup
= mtk_mdp_m2m_queue_setup
,
594 .buf_prepare
= mtk_mdp_m2m_buf_prepare
,
595 .buf_queue
= mtk_mdp_m2m_buf_queue
,
596 .stop_streaming
= mtk_mdp_m2m_stop_streaming
,
597 .start_streaming
= mtk_mdp_m2m_start_streaming
,
598 .wait_prepare
= vb2_ops_wait_prepare
,
599 .wait_finish
= vb2_ops_wait_finish
,
602 static int mtk_mdp_m2m_querycap(struct file
*file
, void *fh
,
603 struct v4l2_capability
*cap
)
605 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
606 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
608 strscpy(cap
->driver
, MTK_MDP_MODULE_NAME
, sizeof(cap
->driver
));
609 strscpy(cap
->card
, mdp
->pdev
->name
, sizeof(cap
->card
));
610 strscpy(cap
->bus_info
, "platform:mt8173", sizeof(cap
->bus_info
));
615 static int mtk_mdp_enum_fmt(struct v4l2_fmtdesc
*f
, u32 type
)
617 const struct mtk_mdp_fmt
*fmt
;
619 fmt
= mtk_mdp_find_fmt_by_index(f
->index
, type
);
623 f
->pixelformat
= fmt
->pixelformat
;
628 static int mtk_mdp_m2m_enum_fmt_vid_cap(struct file
*file
, void *priv
,
629 struct v4l2_fmtdesc
*f
)
631 return mtk_mdp_enum_fmt(f
, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
634 static int mtk_mdp_m2m_enum_fmt_vid_out(struct file
*file
, void *priv
,
635 struct v4l2_fmtdesc
*f
)
637 return mtk_mdp_enum_fmt(f
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
640 static int mtk_mdp_m2m_g_fmt_mplane(struct file
*file
, void *fh
,
641 struct v4l2_format
*f
)
643 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
644 struct mtk_mdp_frame
*frame
;
645 struct v4l2_pix_format_mplane
*pix_mp
;
648 mtk_mdp_dbg(2, "[%d] type:%d", ctx
->id
, f
->type
);
650 frame
= mtk_mdp_ctx_get_frame(ctx
, f
->type
);
651 pix_mp
= &f
->fmt
.pix_mp
;
653 pix_mp
->width
= frame
->width
;
654 pix_mp
->height
= frame
->height
;
655 pix_mp
->field
= V4L2_FIELD_NONE
;
656 pix_mp
->pixelformat
= frame
->fmt
->pixelformat
;
657 pix_mp
->num_planes
= frame
->fmt
->num_planes
;
658 pix_mp
->colorspace
= ctx
->colorspace
;
659 pix_mp
->xfer_func
= ctx
->xfer_func
;
660 pix_mp
->ycbcr_enc
= ctx
->ycbcr_enc
;
661 pix_mp
->quantization
= ctx
->quant
;
662 mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx
->id
,
663 pix_mp
->width
, pix_mp
->height
);
665 for (i
= 0; i
< pix_mp
->num_planes
; ++i
) {
666 pix_mp
->plane_fmt
[i
].bytesperline
= (frame
->width
*
667 frame
->fmt
->row_depth
[i
]) / 8;
668 pix_mp
->plane_fmt
[i
].sizeimage
= (frame
->width
*
669 frame
->height
* frame
->fmt
->depth
[i
]) / 8;
671 mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx
->id
, i
,
672 pix_mp
->plane_fmt
[i
].bytesperline
,
673 pix_mp
->plane_fmt
[i
].sizeimage
);
679 static int mtk_mdp_m2m_try_fmt_mplane(struct file
*file
, void *fh
,
680 struct v4l2_format
*f
)
682 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
684 if (!mtk_mdp_try_fmt_mplane(ctx
, f
))
689 static int mtk_mdp_m2m_s_fmt_mplane(struct file
*file
, void *fh
,
690 struct v4l2_format
*f
)
692 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
693 struct vb2_queue
*vq
;
694 struct mtk_mdp_frame
*frame
;
695 struct v4l2_pix_format_mplane
*pix_mp
;
696 const struct mtk_mdp_fmt
*fmt
;
699 mtk_mdp_dbg(2, "[%d] type:%d", ctx
->id
, f
->type
);
701 frame
= mtk_mdp_ctx_get_frame(ctx
, f
->type
);
702 fmt
= mtk_mdp_try_fmt_mplane(ctx
, f
);
704 mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx
->id
, f
->type
);
709 vq
= v4l2_m2m_get_vq(ctx
->m2m_ctx
, f
->type
);
710 if (vb2_is_streaming(vq
)) {
711 dev_info(&ctx
->mdp_dev
->pdev
->dev
, "queue %d busy", f
->type
);
715 pix_mp
= &f
->fmt
.pix_mp
;
716 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++) {
717 frame
->payload
[i
] = pix_mp
->plane_fmt
[i
].sizeimage
;
718 frame
->pitch
[i
] = pix_mp
->plane_fmt
[i
].bytesperline
;
721 mtk_mdp_set_frame_size(frame
, pix_mp
->width
, pix_mp
->height
);
722 if (V4L2_TYPE_IS_OUTPUT(f
->type
)) {
723 ctx
->colorspace
= pix_mp
->colorspace
;
724 ctx
->xfer_func
= pix_mp
->xfer_func
;
725 ctx
->ycbcr_enc
= pix_mp
->ycbcr_enc
;
726 ctx
->quant
= pix_mp
->quantization
;
729 if (V4L2_TYPE_IS_OUTPUT(f
->type
))
730 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_SRC_FMT
);
732 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_DST_FMT
);
734 mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx
->id
, f
->type
,
735 frame
->width
, frame
->height
);
740 static int mtk_mdp_m2m_reqbufs(struct file
*file
, void *fh
,
741 struct v4l2_requestbuffers
*reqbufs
)
743 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
745 if (reqbufs
->count
== 0) {
746 if (reqbufs
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
747 mtk_mdp_ctx_state_lock_clear(ctx
, MTK_MDP_SRC_FMT
);
749 mtk_mdp_ctx_state_lock_clear(ctx
, MTK_MDP_DST_FMT
);
752 return v4l2_m2m_reqbufs(file
, ctx
->m2m_ctx
, reqbufs
);
755 static int mtk_mdp_m2m_streamon(struct file
*file
, void *fh
,
756 enum v4l2_buf_type type
)
758 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
761 /* The source and target color format need to be set */
762 if (V4L2_TYPE_IS_OUTPUT(type
)) {
763 if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_SRC_FMT
))
765 } else if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_DST_FMT
)) {
769 if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_VPU_INIT
)) {
770 ret
= mtk_mdp_vpu_init(&ctx
->vpu
);
772 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
773 "vpu init failed %d\n",
777 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_VPU_INIT
);
780 return v4l2_m2m_streamon(file
, ctx
->m2m_ctx
, type
);
783 static inline bool mtk_mdp_is_target_compose(u32 target
)
785 if (target
== V4L2_SEL_TGT_COMPOSE_DEFAULT
786 || target
== V4L2_SEL_TGT_COMPOSE_BOUNDS
787 || target
== V4L2_SEL_TGT_COMPOSE
)
792 static inline bool mtk_mdp_is_target_crop(u32 target
)
794 if (target
== V4L2_SEL_TGT_CROP_DEFAULT
795 || target
== V4L2_SEL_TGT_CROP_BOUNDS
796 || target
== V4L2_SEL_TGT_CROP
)
801 static int mtk_mdp_m2m_g_selection(struct file
*file
, void *fh
,
802 struct v4l2_selection
*s
)
804 struct mtk_mdp_frame
*frame
;
805 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
808 if (s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
809 if (mtk_mdp_is_target_compose(s
->target
))
811 } else if (s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
812 if (mtk_mdp_is_target_crop(s
->target
))
816 mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx
->id
, s
->type
,
821 frame
= mtk_mdp_ctx_get_frame(ctx
, s
->type
);
824 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
825 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
826 case V4L2_SEL_TGT_CROP_BOUNDS
:
827 case V4L2_SEL_TGT_CROP_DEFAULT
:
830 s
->r
.width
= frame
->width
;
831 s
->r
.height
= frame
->height
;
834 case V4L2_SEL_TGT_COMPOSE
:
835 case V4L2_SEL_TGT_CROP
:
836 s
->r
.left
= frame
->crop
.left
;
837 s
->r
.top
= frame
->crop
.top
;
838 s
->r
.width
= frame
->crop
.width
;
839 s
->r
.height
= frame
->crop
.height
;
846 static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant
*var
, int src_w
,
847 int src_h
, int dst_w
, int dst_h
, int rot
)
851 if (rot
== 90 || rot
== 270) {
859 if ((src_w
/ tmp_w
) > var
->h_scale_down_max
||
860 (src_h
/ tmp_h
) > var
->v_scale_down_max
||
861 (tmp_w
/ src_w
) > var
->h_scale_up_max
||
862 (tmp_h
/ src_h
) > var
->v_scale_up_max
)
868 static int mtk_mdp_m2m_s_selection(struct file
*file
, void *fh
,
869 struct v4l2_selection
*s
)
871 struct mtk_mdp_frame
*frame
;
872 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
873 struct v4l2_rect new_r
;
874 struct mtk_mdp_variant
*variant
= ctx
->mdp_dev
->variant
;
878 if (s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
879 if (s
->target
== V4L2_SEL_TGT_COMPOSE
)
881 } else if (s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
882 if (s
->target
== V4L2_SEL_TGT_CROP
)
886 mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx
->id
, s
->type
,
892 ret
= mtk_mdp_try_crop(ctx
, s
->type
, &new_r
);
896 if (mtk_mdp_is_target_crop(s
->target
))
897 frame
= &ctx
->s_frame
;
899 frame
= &ctx
->d_frame
;
901 /* Check to see if scaling ratio is within supported range */
902 if (mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_DST_FMT
| MTK_MDP_SRC_FMT
)) {
903 if (V4L2_TYPE_IS_OUTPUT(s
->type
)) {
904 ret
= mtk_mdp_check_scaler_ratio(variant
, new_r
.width
,
905 new_r
.height
, ctx
->d_frame
.crop
.width
,
906 ctx
->d_frame
.crop
.height
,
907 ctx
->ctrls
.rotate
->val
);
909 ret
= mtk_mdp_check_scaler_ratio(variant
,
910 ctx
->s_frame
.crop
.width
,
911 ctx
->s_frame
.crop
.height
, new_r
.width
,
912 new_r
.height
, ctx
->ctrls
.rotate
->val
);
916 dev_info(&ctx
->mdp_dev
->pdev
->dev
,
917 "Out of scaler range");
928 static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops
= {
929 .vidioc_querycap
= mtk_mdp_m2m_querycap
,
930 .vidioc_enum_fmt_vid_cap
= mtk_mdp_m2m_enum_fmt_vid_cap
,
931 .vidioc_enum_fmt_vid_out
= mtk_mdp_m2m_enum_fmt_vid_out
,
932 .vidioc_g_fmt_vid_cap_mplane
= mtk_mdp_m2m_g_fmt_mplane
,
933 .vidioc_g_fmt_vid_out_mplane
= mtk_mdp_m2m_g_fmt_mplane
,
934 .vidioc_try_fmt_vid_cap_mplane
= mtk_mdp_m2m_try_fmt_mplane
,
935 .vidioc_try_fmt_vid_out_mplane
= mtk_mdp_m2m_try_fmt_mplane
,
936 .vidioc_s_fmt_vid_cap_mplane
= mtk_mdp_m2m_s_fmt_mplane
,
937 .vidioc_s_fmt_vid_out_mplane
= mtk_mdp_m2m_s_fmt_mplane
,
938 .vidioc_reqbufs
= mtk_mdp_m2m_reqbufs
,
939 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
940 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
941 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
942 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
943 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
944 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
945 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
946 .vidioc_streamon
= mtk_mdp_m2m_streamon
,
947 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
948 .vidioc_g_selection
= mtk_mdp_m2m_g_selection
,
949 .vidioc_s_selection
= mtk_mdp_m2m_s_selection
952 static int mtk_mdp_m2m_queue_init(void *priv
, struct vb2_queue
*src_vq
,
953 struct vb2_queue
*dst_vq
)
955 struct mtk_mdp_ctx
*ctx
= priv
;
958 memset(src_vq
, 0, sizeof(*src_vq
));
959 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
960 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
961 src_vq
->drv_priv
= ctx
;
962 src_vq
->ops
= &mtk_mdp_m2m_qops
;
963 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
964 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
965 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
966 src_vq
->dev
= &ctx
->mdp_dev
->pdev
->dev
;
967 src_vq
->lock
= &ctx
->mdp_dev
->lock
;
969 ret
= vb2_queue_init(src_vq
);
973 memset(dst_vq
, 0, sizeof(*dst_vq
));
974 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
975 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
976 dst_vq
->drv_priv
= ctx
;
977 dst_vq
->ops
= &mtk_mdp_m2m_qops
;
978 dst_vq
->mem_ops
= &vb2_dma_contig_memops
;
979 dst_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
980 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
981 dst_vq
->dev
= &ctx
->mdp_dev
->pdev
->dev
;
982 dst_vq
->lock
= &ctx
->mdp_dev
->lock
;
984 return vb2_queue_init(dst_vq
);
987 static int mtk_mdp_s_ctrl(struct v4l2_ctrl
*ctrl
)
989 struct mtk_mdp_ctx
*ctx
= ctrl_to_ctx(ctrl
);
990 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
991 struct mtk_mdp_variant
*variant
= mdp
->variant
;
992 u32 state
= MTK_MDP_DST_FMT
| MTK_MDP_SRC_FMT
;
995 if (ctrl
->flags
& V4L2_CTRL_FLAG_INACTIVE
)
1000 ctx
->hflip
= ctrl
->val
;
1002 case V4L2_CID_VFLIP
:
1003 ctx
->vflip
= ctrl
->val
;
1005 case V4L2_CID_ROTATE
:
1006 if (mtk_mdp_ctx_state_is_set(ctx
, state
)) {
1007 ret
= mtk_mdp_check_scaler_ratio(variant
,
1008 ctx
->s_frame
.crop
.width
,
1009 ctx
->s_frame
.crop
.height
,
1010 ctx
->d_frame
.crop
.width
,
1011 ctx
->d_frame
.crop
.height
,
1012 ctx
->ctrls
.rotate
->val
);
1018 ctx
->rotation
= ctrl
->val
;
1020 case V4L2_CID_ALPHA_COMPONENT
:
1021 ctx
->d_frame
.alpha
= ctrl
->val
;
1028 static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops
= {
1029 .s_ctrl
= mtk_mdp_s_ctrl
,
1032 static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx
*ctx
)
1034 v4l2_ctrl_handler_init(&ctx
->ctrl_handler
, MTK_MDP_MAX_CTRL_NUM
);
1036 ctx
->ctrls
.rotate
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1037 &mtk_mdp_ctrl_ops
, V4L2_CID_ROTATE
, 0, 270, 90, 0);
1038 ctx
->ctrls
.hflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1042 ctx
->ctrls
.vflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1046 ctx
->ctrls
.global_alpha
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1048 V4L2_CID_ALPHA_COMPONENT
,
1050 ctx
->ctrls_rdy
= ctx
->ctrl_handler
.error
== 0;
1052 if (ctx
->ctrl_handler
.error
) {
1053 int err
= ctx
->ctrl_handler
.error
;
1055 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1056 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
1057 "Failed to create control handlers\n");
1064 static void mtk_mdp_set_default_params(struct mtk_mdp_ctx
*ctx
)
1066 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1067 struct mtk_mdp_frame
*frame
;
1069 frame
= mtk_mdp_ctx_get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
1070 frame
->fmt
= mtk_mdp_find_fmt_by_index(0,
1071 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
1072 frame
->width
= mdp
->variant
->pix_min
->org_w
;
1073 frame
->height
= mdp
->variant
->pix_min
->org_h
;
1074 frame
->payload
[0] = frame
->width
* frame
->height
;
1075 frame
->payload
[1] = frame
->payload
[0] / 2;
1077 frame
= mtk_mdp_ctx_get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
1078 frame
->fmt
= mtk_mdp_find_fmt_by_index(0,
1079 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
1080 frame
->width
= mdp
->variant
->pix_min
->target_rot_dis_w
;
1081 frame
->height
= mdp
->variant
->pix_min
->target_rot_dis_h
;
1082 frame
->payload
[0] = frame
->width
* frame
->height
;
1083 frame
->payload
[1] = frame
->payload
[0] / 2;
1087 static int mtk_mdp_m2m_open(struct file
*file
)
1089 struct mtk_mdp_dev
*mdp
= video_drvdata(file
);
1090 struct video_device
*vfd
= video_devdata(file
);
1091 struct mtk_mdp_ctx
*ctx
= NULL
;
1094 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
1098 if (mutex_lock_interruptible(&mdp
->lock
)) {
1103 mutex_init(&ctx
->slock
);
1104 ctx
->id
= mdp
->id_counter
++;
1105 v4l2_fh_init(&ctx
->fh
, vfd
);
1106 file
->private_data
= &ctx
->fh
;
1107 ret
= mtk_mdp_ctrls_create(ctx
);
1111 /* Use separate control handler per file handle */
1112 ctx
->fh
.ctrl_handler
= &ctx
->ctrl_handler
;
1113 v4l2_fh_add(&ctx
->fh
);
1114 INIT_LIST_HEAD(&ctx
->list
);
1117 mtk_mdp_set_default_params(ctx
);
1119 INIT_WORK(&ctx
->work
, mtk_mdp_m2m_worker
);
1120 ctx
->m2m_ctx
= v4l2_m2m_ctx_init(mdp
->m2m_dev
, ctx
,
1121 mtk_mdp_m2m_queue_init
);
1122 if (IS_ERR(ctx
->m2m_ctx
)) {
1123 dev_err(&mdp
->pdev
->dev
, "Failed to initialize m2m context");
1124 ret
= PTR_ERR(ctx
->m2m_ctx
);
1127 ctx
->fh
.m2m_ctx
= ctx
->m2m_ctx
;
1128 if (mdp
->ctx_num
++ == 0) {
1129 ret
= vpu_load_firmware(mdp
->vpu_dev
);
1131 dev_err(&mdp
->pdev
->dev
,
1132 "vpu_load_firmware failed %d\n", ret
);
1136 ret
= mtk_mdp_vpu_register(mdp
->pdev
);
1138 dev_err(&mdp
->pdev
->dev
,
1139 "mdp_vpu register failed %d\n", ret
);
1144 list_add(&ctx
->list
, &mdp
->ctx_list
);
1145 mutex_unlock(&mdp
->lock
);
1147 mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp
->pdev
->dev
), ctx
->id
);
1153 v4l2_m2m_ctx_release(ctx
->m2m_ctx
);
1155 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1157 v4l2_fh_del(&ctx
->fh
);
1158 v4l2_fh_exit(&ctx
->fh
);
1159 mutex_unlock(&mdp
->lock
);
1166 static int mtk_mdp_m2m_release(struct file
*file
)
1168 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(file
->private_data
);
1169 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1171 flush_workqueue(mdp
->job_wq
);
1172 mutex_lock(&mdp
->lock
);
1173 v4l2_m2m_ctx_release(ctx
->m2m_ctx
);
1174 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1175 v4l2_fh_del(&ctx
->fh
);
1176 v4l2_fh_exit(&ctx
->fh
);
1177 mtk_mdp_vpu_deinit(&ctx
->vpu
);
1179 list_del_init(&ctx
->list
);
1181 mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp
->pdev
->dev
), ctx
->id
);
1183 mutex_unlock(&mdp
->lock
);
1189 static const struct v4l2_file_operations mtk_mdp_m2m_fops
= {
1190 .owner
= THIS_MODULE
,
1191 .open
= mtk_mdp_m2m_open
,
1192 .release
= mtk_mdp_m2m_release
,
1193 .poll
= v4l2_m2m_fop_poll
,
1194 .unlocked_ioctl
= video_ioctl2
,
1195 .mmap
= v4l2_m2m_fop_mmap
,
1198 static const struct v4l2_m2m_ops mtk_mdp_m2m_ops
= {
1199 .device_run
= mtk_mdp_m2m_device_run
,
1202 int mtk_mdp_register_m2m_device(struct mtk_mdp_dev
*mdp
)
1204 struct device
*dev
= &mdp
->pdev
->dev
;
1207 mdp
->variant
= &mtk_mdp_default_variant
;
1208 mdp
->vdev
= video_device_alloc();
1210 dev_err(dev
, "failed to allocate video device\n");
1212 goto err_video_alloc
;
1214 mdp
->vdev
->device_caps
= V4L2_CAP_VIDEO_M2M_MPLANE
| V4L2_CAP_STREAMING
;
1215 mdp
->vdev
->fops
= &mtk_mdp_m2m_fops
;
1216 mdp
->vdev
->ioctl_ops
= &mtk_mdp_m2m_ioctl_ops
;
1217 mdp
->vdev
->release
= video_device_release
;
1218 mdp
->vdev
->lock
= &mdp
->lock
;
1219 mdp
->vdev
->vfl_dir
= VFL_DIR_M2M
;
1220 mdp
->vdev
->v4l2_dev
= &mdp
->v4l2_dev
;
1221 snprintf(mdp
->vdev
->name
, sizeof(mdp
->vdev
->name
), "%s:m2m",
1222 MTK_MDP_MODULE_NAME
);
1223 video_set_drvdata(mdp
->vdev
, mdp
);
1225 mdp
->m2m_dev
= v4l2_m2m_init(&mtk_mdp_m2m_ops
);
1226 if (IS_ERR(mdp
->m2m_dev
)) {
1227 dev_err(dev
, "failed to initialize v4l2-m2m device\n");
1228 ret
= PTR_ERR(mdp
->m2m_dev
);
1232 ret
= video_register_device(mdp
->vdev
, VFL_TYPE_GRABBER
, 2);
1234 dev_err(dev
, "failed to register video device\n");
1235 goto err_vdev_register
;
1238 v4l2_info(&mdp
->v4l2_dev
, "driver registered as /dev/video%d",
1243 v4l2_m2m_release(mdp
->m2m_dev
);
1245 video_device_release(mdp
->vdev
);
1251 void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev
*mdp
)
1253 video_unregister_device(mdp
->vdev
);
1254 v4l2_m2m_release(mdp
->m2m_dev
);