2 * Copyright (c) 2015-2016 MediaTek Inc.
3 * Author: Houlong Wei <houlong.wei@mediatek.com>
4 * Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/device.h>
17 #include <linux/errno.h>
18 #include <linux/kernel.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/slab.h>
21 #include <linux/workqueue.h>
22 #include <media/v4l2-event.h>
23 #include <media/v4l2-ioctl.h>
25 #include "mtk_mdp_core.h"
26 #include "mtk_mdp_m2m.h"
27 #include "mtk_mdp_regs.h"
32 * struct mtk_mdp_pix_limit - image pixel size limits
33 * @org_w: source pixel width
34 * @org_h: source pixel height
35 * @target_rot_dis_w: pixel dst scaled width with the rotator is off
36 * @target_rot_dis_h: pixel dst scaled height with the rotator is off
37 * @target_rot_en_w: pixel dst scaled width with the rotator is on
38 * @target_rot_en_h: pixel dst scaled height with the rotator is on
40 struct mtk_mdp_pix_limit
{
49 static struct mtk_mdp_pix_align mtk_mdp_size_align
= {
56 static const struct mtk_mdp_fmt mtk_mdp_formats
[] = {
58 .pixelformat
= V4L2_PIX_FMT_MT21C
,
60 .row_depth
= { 8, 8 },
63 .align
= &mtk_mdp_size_align
,
64 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
,
66 .pixelformat
= V4L2_PIX_FMT_NV12M
,
68 .row_depth
= { 8, 8 },
71 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
|
72 MTK_MDP_FMT_FLAG_CAPTURE
,
74 .pixelformat
= V4L2_PIX_FMT_YUV420M
,
76 .row_depth
= { 8, 4, 4 },
79 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
|
80 MTK_MDP_FMT_FLAG_CAPTURE
,
82 .pixelformat
= V4L2_PIX_FMT_YVU420
,
87 .flags
= MTK_MDP_FMT_FLAG_OUTPUT
|
88 MTK_MDP_FMT_FLAG_CAPTURE
,
92 static struct mtk_mdp_pix_limit mtk_mdp_size_max
= {
93 .target_rot_dis_w
= 4096,
94 .target_rot_dis_h
= 4096,
95 .target_rot_en_w
= 4096,
96 .target_rot_en_h
= 4096,
99 static struct mtk_mdp_pix_limit mtk_mdp_size_min
= {
102 .target_rot_dis_w
= 16,
103 .target_rot_dis_h
= 16,
104 .target_rot_en_w
= 16,
105 .target_rot_en_h
= 16,
108 /* align size for normal raster scan pixel format */
109 static struct mtk_mdp_pix_align mtk_mdp_rs_align
= {
116 static struct mtk_mdp_variant mtk_mdp_default_variant
= {
117 .pix_max
= &mtk_mdp_size_max
,
118 .pix_min
= &mtk_mdp_size_min
,
119 .pix_align
= &mtk_mdp_rs_align
,
120 .h_scale_up_max
= 32,
121 .v_scale_up_max
= 32,
122 .h_scale_down_max
= 32,
123 .v_scale_down_max
= 128,
126 static const struct mtk_mdp_fmt
*mtk_mdp_find_fmt(u32 pixelformat
, u32 type
)
130 flag
= V4L2_TYPE_IS_OUTPUT(type
) ? MTK_MDP_FMT_FLAG_OUTPUT
:
131 MTK_MDP_FMT_FLAG_CAPTURE
;
133 for (i
= 0; i
< ARRAY_SIZE(mtk_mdp_formats
); ++i
) {
134 if (!(mtk_mdp_formats
[i
].flags
& flag
))
136 if (mtk_mdp_formats
[i
].pixelformat
== pixelformat
)
137 return &mtk_mdp_formats
[i
];
142 static const struct mtk_mdp_fmt
*mtk_mdp_find_fmt_by_index(u32 index
, u32 type
)
144 u32 i
, flag
, num
= 0;
146 flag
= V4L2_TYPE_IS_OUTPUT(type
) ? MTK_MDP_FMT_FLAG_OUTPUT
:
147 MTK_MDP_FMT_FLAG_CAPTURE
;
149 for (i
= 0; i
< ARRAY_SIZE(mtk_mdp_formats
); ++i
) {
150 if (!(mtk_mdp_formats
[i
].flags
& flag
))
153 return &mtk_mdp_formats
[i
];
159 static void mtk_mdp_bound_align_image(u32
*w
, unsigned int wmin
,
160 unsigned int wmax
, unsigned int align_w
,
161 u32
*h
, unsigned int hmin
,
162 unsigned int hmax
, unsigned int align_h
)
164 int org_w
, org_h
, step_w
, step_h
;
169 walign
= ffs(align_w
) - 1;
170 halign
= ffs(align_h
) - 1;
171 v4l_bound_align_image(w
, wmin
, wmax
, walign
, h
, hmin
, hmax
, halign
, 0);
173 step_w
= 1 << walign
;
174 step_h
= 1 << halign
;
175 if (*w
< org_w
&& (*w
+ step_w
) <= wmax
)
177 if (*h
< org_h
&& (*h
+ step_h
) <= hmax
)
181 static const struct mtk_mdp_fmt
*mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx
*ctx
,
182 struct v4l2_format
*f
)
184 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
185 struct mtk_mdp_variant
*variant
= mdp
->variant
;
186 struct v4l2_pix_format_mplane
*pix_mp
= &f
->fmt
.pix_mp
;
187 const struct mtk_mdp_fmt
*fmt
;
188 u32 max_w
, max_h
, align_w
, align_h
;
189 u32 min_w
, min_h
, org_w
, org_h
;
192 fmt
= mtk_mdp_find_fmt(pix_mp
->pixelformat
, f
->type
);
194 fmt
= mtk_mdp_find_fmt_by_index(0, f
->type
);
196 dev_dbg(&ctx
->mdp_dev
->pdev
->dev
,
197 "pixelformat format 0x%X invalid\n",
198 pix_mp
->pixelformat
);
202 pix_mp
->field
= V4L2_FIELD_NONE
;
203 pix_mp
->pixelformat
= fmt
->pixelformat
;
204 if (!V4L2_TYPE_IS_OUTPUT(f
->type
)) {
205 pix_mp
->colorspace
= ctx
->colorspace
;
206 pix_mp
->xfer_func
= ctx
->xfer_func
;
207 pix_mp
->ycbcr_enc
= ctx
->ycbcr_enc
;
208 pix_mp
->quantization
= ctx
->quant
;
210 memset(pix_mp
->reserved
, 0, sizeof(pix_mp
->reserved
));
212 max_w
= variant
->pix_max
->target_rot_dis_w
;
213 max_h
= variant
->pix_max
->target_rot_dis_h
;
215 if (fmt
->align
== NULL
) {
216 /* use default alignment */
217 align_w
= variant
->pix_align
->org_w
;
218 align_h
= variant
->pix_align
->org_h
;
220 align_w
= fmt
->align
->org_w
;
221 align_h
= fmt
->align
->org_h
;
224 if (V4L2_TYPE_IS_OUTPUT(f
->type
)) {
225 min_w
= variant
->pix_min
->org_w
;
226 min_h
= variant
->pix_min
->org_h
;
228 min_w
= variant
->pix_min
->target_rot_dis_w
;
229 min_h
= variant
->pix_min
->target_rot_dis_h
;
232 mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
233 ctx
->id
, f
->type
, pix_mp
->width
, pix_mp
->height
,
234 align_w
, align_h
, max_w
, max_h
);
236 * To check if image size is modified to adjust parameter against
239 org_w
= pix_mp
->width
;
240 org_h
= pix_mp
->height
;
242 mtk_mdp_bound_align_image(&pix_mp
->width
, min_w
, max_w
, align_w
,
243 &pix_mp
->height
, min_h
, max_h
, align_h
);
245 if (org_w
!= pix_mp
->width
|| org_h
!= pix_mp
->height
)
246 mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx
->id
,
247 org_w
, org_h
, pix_mp
->width
, pix_mp
->height
);
248 pix_mp
->num_planes
= fmt
->num_planes
;
250 for (i
= 0; i
< pix_mp
->num_planes
; ++i
) {
251 int bpl
= (pix_mp
->width
* fmt
->row_depth
[i
]) / 8;
252 int sizeimage
= (pix_mp
->width
* pix_mp
->height
*
255 pix_mp
->plane_fmt
[i
].bytesperline
= bpl
;
256 if (pix_mp
->plane_fmt
[i
].sizeimage
< sizeimage
)
257 pix_mp
->plane_fmt
[i
].sizeimage
= sizeimage
;
258 memset(pix_mp
->plane_fmt
[i
].reserved
, 0,
259 sizeof(pix_mp
->plane_fmt
[i
].reserved
));
260 mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx
->id
,
261 i
, bpl
, pix_mp
->plane_fmt
[i
].sizeimage
, sizeimage
);
267 static struct mtk_mdp_frame
*mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx
*ctx
,
268 enum v4l2_buf_type type
)
270 if (V4L2_TYPE_IS_OUTPUT(type
))
271 return &ctx
->s_frame
;
272 return &ctx
->d_frame
;
275 static void mtk_mdp_check_crop_change(u32 new_w
, u32 new_h
, u32
*w
, u32
*h
)
277 if (new_w
!= *w
|| new_h
!= *h
) {
278 mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
279 *w
, *h
, new_w
, new_h
);
286 static int mtk_mdp_try_crop(struct mtk_mdp_ctx
*ctx
, u32 type
,
289 struct mtk_mdp_frame
*frame
;
290 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
291 struct mtk_mdp_variant
*variant
= mdp
->variant
;
292 u32 align_w
, align_h
, new_w
, new_h
;
293 u32 min_w
, min_h
, max_w
, max_h
;
295 if (r
->top
< 0 || r
->left
< 0) {
296 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
297 "doesn't support negative values for top & left\n");
301 mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx
->id
, type
,
302 r
->width
, r
->height
);
304 frame
= mtk_mdp_ctx_get_frame(ctx
, type
);
305 max_w
= frame
->width
;
306 max_h
= frame
->height
;
310 if (V4L2_TYPE_IS_OUTPUT(type
)) {
316 align_w
= variant
->pix_align
->target_w
;
317 align_h
= variant
->pix_align
->target_h
;
318 if (ctx
->ctrls
.rotate
->val
== 90 ||
319 ctx
->ctrls
.rotate
->val
== 270) {
320 max_w
= frame
->height
;
321 max_h
= frame
->width
;
322 min_w
= variant
->pix_min
->target_rot_en_w
;
323 min_h
= variant
->pix_min
->target_rot_en_h
;
327 min_w
= variant
->pix_min
->target_rot_dis_w
;
328 min_h
= variant
->pix_min
->target_rot_dis_h
;
332 mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx
->id
,
333 align_w
, align_h
, min_w
, min_h
, new_w
, new_h
);
335 mtk_mdp_bound_align_image(&new_w
, min_w
, max_w
, align_w
,
336 &new_h
, min_h
, max_h
, align_h
);
338 if (!V4L2_TYPE_IS_OUTPUT(type
) &&
339 (ctx
->ctrls
.rotate
->val
== 90 ||
340 ctx
->ctrls
.rotate
->val
== 270))
341 mtk_mdp_check_crop_change(new_h
, new_w
,
342 &r
->width
, &r
->height
);
344 mtk_mdp_check_crop_change(new_w
, new_h
,
345 &r
->width
, &r
->height
);
347 /* adjust left/top if cropping rectangle is out of bounds */
348 /* Need to add code to algin left value with 2's multiple */
349 if (r
->left
+ new_w
> max_w
)
350 r
->left
= max_w
- new_w
;
351 if (r
->top
+ new_h
> max_h
)
352 r
->top
= max_h
- new_h
;
357 mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx
->id
,
358 r
->left
, r
->top
, r
->width
,
359 r
->height
, max_w
, max_h
);
363 static inline struct mtk_mdp_ctx
*fh_to_ctx(struct v4l2_fh
*fh
)
365 return container_of(fh
, struct mtk_mdp_ctx
, fh
);
368 static inline struct mtk_mdp_ctx
*ctrl_to_ctx(struct v4l2_ctrl
*ctrl
)
370 return container_of(ctrl
->handler
, struct mtk_mdp_ctx
, ctrl_handler
);
373 void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx
*ctx
, u32 state
)
375 mutex_lock(&ctx
->slock
);
377 mutex_unlock(&ctx
->slock
);
380 static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx
*ctx
, u32 state
)
382 mutex_lock(&ctx
->slock
);
383 ctx
->state
&= ~state
;
384 mutex_unlock(&ctx
->slock
);
387 static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx
*ctx
, u32 mask
)
391 mutex_lock(&ctx
->slock
);
392 ret
= (ctx
->state
& mask
) == mask
;
393 mutex_unlock(&ctx
->slock
);
397 static void mtk_mdp_ctx_lock(struct vb2_queue
*vq
)
399 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vq
);
401 mutex_lock(&ctx
->mdp_dev
->lock
);
404 static void mtk_mdp_ctx_unlock(struct vb2_queue
*vq
)
406 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vq
);
408 mutex_unlock(&ctx
->mdp_dev
->lock
);
411 static void mtk_mdp_set_frame_size(struct mtk_mdp_frame
*frame
, int width
,
414 frame
->width
= width
;
415 frame
->height
= height
;
416 frame
->crop
.width
= width
;
417 frame
->crop
.height
= height
;
418 frame
->crop
.left
= 0;
422 static int mtk_mdp_m2m_start_streaming(struct vb2_queue
*q
, unsigned int count
)
424 struct mtk_mdp_ctx
*ctx
= q
->drv_priv
;
427 ret
= pm_runtime_get_sync(&ctx
->mdp_dev
->pdev
->dev
);
429 mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
435 static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx
*ctx
,
436 enum v4l2_buf_type type
)
438 if (V4L2_TYPE_IS_OUTPUT(type
))
439 return v4l2_m2m_src_buf_remove(ctx
->m2m_ctx
);
441 return v4l2_m2m_dst_buf_remove(ctx
->m2m_ctx
);
444 static void mtk_mdp_m2m_stop_streaming(struct vb2_queue
*q
)
446 struct mtk_mdp_ctx
*ctx
= q
->drv_priv
;
447 struct vb2_buffer
*vb
;
449 vb
= mtk_mdp_m2m_buf_remove(ctx
, q
->type
);
451 v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb
), VB2_BUF_STATE_ERROR
);
452 vb
= mtk_mdp_m2m_buf_remove(ctx
, q
->type
);
455 pm_runtime_put(&ctx
->mdp_dev
->pdev
->dev
);
458 static void mtk_mdp_m2m_job_abort(void *priv
)
462 /* The color format (num_planes) must be already configured. */
463 static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx
*ctx
,
464 struct vb2_buffer
*vb
,
465 struct mtk_mdp_frame
*frame
,
466 struct mtk_mdp_addr
*addr
)
468 u32 pix_size
, planes
, i
;
470 pix_size
= frame
->width
* frame
->height
;
471 planes
= min_t(u32
, frame
->fmt
->num_planes
, ARRAY_SIZE(addr
->addr
));
472 for (i
= 0; i
< planes
; i
++)
473 addr
->addr
[i
] = vb2_dma_contig_plane_dma_addr(vb
, i
);
476 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_YVU420
) {
477 addr
->addr
[1] = (dma_addr_t
)(addr
->addr
[0] + pix_size
);
478 addr
->addr
[2] = (dma_addr_t
)(addr
->addr
[1] +
481 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
482 "Invalid pixelformat:0x%x\n",
483 frame
->fmt
->pixelformat
);
486 mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
487 ctx
->id
, planes
, pix_size
, (void *)addr
->addr
[0],
488 (void *)addr
->addr
[1], (void *)addr
->addr
[2]);
491 static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx
*ctx
)
493 struct mtk_mdp_frame
*s_frame
, *d_frame
;
494 struct vb2_buffer
*src_vb
, *dst_vb
;
495 struct vb2_v4l2_buffer
*src_vbuf
, *dst_vbuf
;
497 s_frame
= &ctx
->s_frame
;
498 d_frame
= &ctx
->d_frame
;
500 src_vb
= v4l2_m2m_next_src_buf(ctx
->m2m_ctx
);
501 mtk_mdp_prepare_addr(ctx
, src_vb
, s_frame
, &s_frame
->addr
);
503 dst_vb
= v4l2_m2m_next_dst_buf(ctx
->m2m_ctx
);
504 mtk_mdp_prepare_addr(ctx
, dst_vb
, d_frame
, &d_frame
->addr
);
506 src_vbuf
= to_vb2_v4l2_buffer(src_vb
);
507 dst_vbuf
= to_vb2_v4l2_buffer(dst_vb
);
508 dst_vbuf
->vb2_buf
.timestamp
= src_vbuf
->vb2_buf
.timestamp
;
511 static void mtk_mdp_process_done(void *priv
, int vb_state
)
513 struct mtk_mdp_dev
*mdp
= priv
;
514 struct mtk_mdp_ctx
*ctx
;
515 struct vb2_buffer
*src_vb
, *dst_vb
;
516 struct vb2_v4l2_buffer
*src_vbuf
= NULL
, *dst_vbuf
= NULL
;
518 ctx
= v4l2_m2m_get_curr_priv(mdp
->m2m_dev
);
522 src_vb
= v4l2_m2m_src_buf_remove(ctx
->m2m_ctx
);
523 src_vbuf
= to_vb2_v4l2_buffer(src_vb
);
524 dst_vb
= v4l2_m2m_dst_buf_remove(ctx
->m2m_ctx
);
525 dst_vbuf
= to_vb2_v4l2_buffer(dst_vb
);
527 dst_vbuf
->vb2_buf
.timestamp
= src_vbuf
->vb2_buf
.timestamp
;
528 dst_vbuf
->timecode
= src_vbuf
->timecode
;
529 dst_vbuf
->flags
&= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
530 dst_vbuf
->flags
|= src_vbuf
->flags
& V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
532 v4l2_m2m_buf_done(src_vbuf
, vb_state
);
533 v4l2_m2m_buf_done(dst_vbuf
, vb_state
);
534 v4l2_m2m_job_finish(ctx
->mdp_dev
->m2m_dev
, ctx
->m2m_ctx
);
537 static void mtk_mdp_m2m_worker(struct work_struct
*work
)
539 struct mtk_mdp_ctx
*ctx
=
540 container_of(work
, struct mtk_mdp_ctx
, work
);
541 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
542 enum vb2_buffer_state buf_state
= VB2_BUF_STATE_ERROR
;
545 if (mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_CTX_ERROR
)) {
546 dev_err(&mdp
->pdev
->dev
, "ctx is in error state");
550 mtk_mdp_m2m_get_bufs(ctx
);
552 mtk_mdp_hw_set_input_addr(ctx
, &ctx
->s_frame
.addr
);
553 mtk_mdp_hw_set_output_addr(ctx
, &ctx
->d_frame
.addr
);
555 mtk_mdp_hw_set_in_size(ctx
);
556 mtk_mdp_hw_set_in_image_format(ctx
);
558 mtk_mdp_hw_set_out_size(ctx
);
559 mtk_mdp_hw_set_out_image_format(ctx
);
561 mtk_mdp_hw_set_rotation(ctx
);
562 mtk_mdp_hw_set_global_alpha(ctx
);
564 ret
= mtk_mdp_vpu_process(&ctx
->vpu
);
566 dev_err(&mdp
->pdev
->dev
, "processing failed: %d", ret
);
570 buf_state
= VB2_BUF_STATE_DONE
;
573 mtk_mdp_process_done(mdp
, buf_state
);
576 static void mtk_mdp_m2m_device_run(void *priv
)
578 struct mtk_mdp_ctx
*ctx
= priv
;
580 queue_work(ctx
->mdp_dev
->job_wq
, &ctx
->work
);
583 static int mtk_mdp_m2m_queue_setup(struct vb2_queue
*vq
,
584 unsigned int *num_buffers
, unsigned int *num_planes
,
585 unsigned int sizes
[], struct device
*alloc_devs
[])
587 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vq
);
588 struct mtk_mdp_frame
*frame
;
591 frame
= mtk_mdp_ctx_get_frame(ctx
, vq
->type
);
592 *num_planes
= frame
->fmt
->num_planes
;
593 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
594 sizes
[i
] = frame
->payload
[i
];
595 mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
596 ctx
->id
, vq
->type
, *num_planes
, *num_buffers
,
601 static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer
*vb
)
603 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
604 struct mtk_mdp_frame
*frame
;
607 frame
= mtk_mdp_ctx_get_frame(ctx
, vb
->vb2_queue
->type
);
609 if (!V4L2_TYPE_IS_OUTPUT(vb
->vb2_queue
->type
)) {
610 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
611 vb2_set_plane_payload(vb
, i
, frame
->payload
[i
]);
617 static void mtk_mdp_m2m_buf_queue(struct vb2_buffer
*vb
)
619 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
621 v4l2_m2m_buf_queue(ctx
->m2m_ctx
, to_vb2_v4l2_buffer(vb
));
624 static const struct vb2_ops mtk_mdp_m2m_qops
= {
625 .queue_setup
= mtk_mdp_m2m_queue_setup
,
626 .buf_prepare
= mtk_mdp_m2m_buf_prepare
,
627 .buf_queue
= mtk_mdp_m2m_buf_queue
,
628 .wait_prepare
= mtk_mdp_ctx_unlock
,
629 .wait_finish
= mtk_mdp_ctx_lock
,
630 .stop_streaming
= mtk_mdp_m2m_stop_streaming
,
631 .start_streaming
= mtk_mdp_m2m_start_streaming
,
634 static int mtk_mdp_m2m_querycap(struct file
*file
, void *fh
,
635 struct v4l2_capability
*cap
)
637 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
638 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
640 strlcpy(cap
->driver
, MTK_MDP_MODULE_NAME
, sizeof(cap
->driver
));
641 strlcpy(cap
->card
, mdp
->pdev
->name
, sizeof(cap
->card
));
642 strlcpy(cap
->bus_info
, "platform:mt8173", sizeof(cap
->bus_info
));
647 static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc
*f
, u32 type
)
649 const struct mtk_mdp_fmt
*fmt
;
651 fmt
= mtk_mdp_find_fmt_by_index(f
->index
, type
);
655 f
->pixelformat
= fmt
->pixelformat
;
660 static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file
*file
, void *priv
,
661 struct v4l2_fmtdesc
*f
)
663 return mtk_mdp_enum_fmt_mplane(f
, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
666 static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file
*file
, void *priv
,
667 struct v4l2_fmtdesc
*f
)
669 return mtk_mdp_enum_fmt_mplane(f
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
672 static int mtk_mdp_m2m_g_fmt_mplane(struct file
*file
, void *fh
,
673 struct v4l2_format
*f
)
675 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
676 struct mtk_mdp_frame
*frame
;
677 struct v4l2_pix_format_mplane
*pix_mp
;
680 mtk_mdp_dbg(2, "[%d] type:%d", ctx
->id
, f
->type
);
682 frame
= mtk_mdp_ctx_get_frame(ctx
, f
->type
);
683 pix_mp
= &f
->fmt
.pix_mp
;
685 pix_mp
->width
= frame
->width
;
686 pix_mp
->height
= frame
->height
;
687 pix_mp
->field
= V4L2_FIELD_NONE
;
688 pix_mp
->pixelformat
= frame
->fmt
->pixelformat
;
689 pix_mp
->num_planes
= frame
->fmt
->num_planes
;
690 pix_mp
->colorspace
= ctx
->colorspace
;
691 pix_mp
->xfer_func
= ctx
->xfer_func
;
692 pix_mp
->ycbcr_enc
= ctx
->ycbcr_enc
;
693 pix_mp
->quantization
= ctx
->quant
;
694 mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx
->id
,
695 pix_mp
->width
, pix_mp
->height
);
697 for (i
= 0; i
< pix_mp
->num_planes
; ++i
) {
698 pix_mp
->plane_fmt
[i
].bytesperline
= (frame
->width
*
699 frame
->fmt
->row_depth
[i
]) / 8;
700 pix_mp
->plane_fmt
[i
].sizeimage
= (frame
->width
*
701 frame
->height
* frame
->fmt
->depth
[i
]) / 8;
703 mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx
->id
, i
,
704 pix_mp
->plane_fmt
[i
].bytesperline
,
705 pix_mp
->plane_fmt
[i
].sizeimage
);
711 static int mtk_mdp_m2m_try_fmt_mplane(struct file
*file
, void *fh
,
712 struct v4l2_format
*f
)
714 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
716 if (!mtk_mdp_try_fmt_mplane(ctx
, f
))
721 static int mtk_mdp_m2m_s_fmt_mplane(struct file
*file
, void *fh
,
722 struct v4l2_format
*f
)
724 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
725 struct vb2_queue
*vq
;
726 struct mtk_mdp_frame
*frame
;
727 struct v4l2_pix_format_mplane
*pix_mp
;
728 const struct mtk_mdp_fmt
*fmt
;
731 mtk_mdp_dbg(2, "[%d] type:%d", ctx
->id
, f
->type
);
733 frame
= mtk_mdp_ctx_get_frame(ctx
, f
->type
);
734 fmt
= mtk_mdp_try_fmt_mplane(ctx
, f
);
736 mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx
->id
, f
->type
);
741 vq
= v4l2_m2m_get_vq(ctx
->m2m_ctx
, f
->type
);
742 if (vb2_is_streaming(vq
)) {
743 dev_info(&ctx
->mdp_dev
->pdev
->dev
, "queue %d busy", f
->type
);
747 pix_mp
= &f
->fmt
.pix_mp
;
748 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++) {
749 frame
->payload
[i
] = pix_mp
->plane_fmt
[i
].sizeimage
;
750 frame
->pitch
[i
] = pix_mp
->plane_fmt
[i
].bytesperline
;
753 mtk_mdp_set_frame_size(frame
, pix_mp
->width
, pix_mp
->height
);
754 if (V4L2_TYPE_IS_OUTPUT(f
->type
)) {
755 ctx
->colorspace
= pix_mp
->colorspace
;
756 ctx
->xfer_func
= pix_mp
->xfer_func
;
757 ctx
->ycbcr_enc
= pix_mp
->ycbcr_enc
;
758 ctx
->quant
= pix_mp
->quantization
;
761 if (V4L2_TYPE_IS_OUTPUT(f
->type
))
762 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_SRC_FMT
);
764 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_DST_FMT
);
766 mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx
->id
, f
->type
,
767 frame
->width
, frame
->height
);
772 static int mtk_mdp_m2m_reqbufs(struct file
*file
, void *fh
,
773 struct v4l2_requestbuffers
*reqbufs
)
775 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
777 if (reqbufs
->count
== 0) {
778 if (reqbufs
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
779 mtk_mdp_ctx_state_lock_clear(ctx
, MTK_MDP_SRC_FMT
);
781 mtk_mdp_ctx_state_lock_clear(ctx
, MTK_MDP_DST_FMT
);
784 return v4l2_m2m_reqbufs(file
, ctx
->m2m_ctx
, reqbufs
);
787 static int mtk_mdp_m2m_streamon(struct file
*file
, void *fh
,
788 enum v4l2_buf_type type
)
790 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
793 /* The source and target color format need to be set */
794 if (V4L2_TYPE_IS_OUTPUT(type
)) {
795 if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_SRC_FMT
))
797 } else if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_DST_FMT
)) {
801 if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_VPU_INIT
)) {
802 ret
= mtk_mdp_vpu_init(&ctx
->vpu
);
804 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
805 "vpu init failed %d\n",
809 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_VPU_INIT
);
812 return v4l2_m2m_streamon(file
, ctx
->m2m_ctx
, type
);
815 static inline bool mtk_mdp_is_target_compose(u32 target
)
817 if (target
== V4L2_SEL_TGT_COMPOSE_DEFAULT
818 || target
== V4L2_SEL_TGT_COMPOSE_BOUNDS
819 || target
== V4L2_SEL_TGT_COMPOSE
)
824 static inline bool mtk_mdp_is_target_crop(u32 target
)
826 if (target
== V4L2_SEL_TGT_CROP_DEFAULT
827 || target
== V4L2_SEL_TGT_CROP_BOUNDS
828 || target
== V4L2_SEL_TGT_CROP
)
833 static int mtk_mdp_m2m_g_selection(struct file
*file
, void *fh
,
834 struct v4l2_selection
*s
)
836 struct mtk_mdp_frame
*frame
;
837 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
840 if (s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
841 if (mtk_mdp_is_target_compose(s
->target
))
843 } else if (s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
844 if (mtk_mdp_is_target_crop(s
->target
))
848 mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx
->id
, s
->type
,
853 frame
= mtk_mdp_ctx_get_frame(ctx
, s
->type
);
856 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
857 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
858 case V4L2_SEL_TGT_CROP_BOUNDS
:
859 case V4L2_SEL_TGT_CROP_DEFAULT
:
862 s
->r
.width
= frame
->width
;
863 s
->r
.height
= frame
->height
;
866 case V4L2_SEL_TGT_COMPOSE
:
867 case V4L2_SEL_TGT_CROP
:
868 s
->r
.left
= frame
->crop
.left
;
869 s
->r
.top
= frame
->crop
.top
;
870 s
->r
.width
= frame
->crop
.width
;
871 s
->r
.height
= frame
->crop
.height
;
878 static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant
*var
, int src_w
,
879 int src_h
, int dst_w
, int dst_h
, int rot
)
883 if (rot
== 90 || rot
== 270) {
891 if ((src_w
/ tmp_w
) > var
->h_scale_down_max
||
892 (src_h
/ tmp_h
) > var
->v_scale_down_max
||
893 (tmp_w
/ src_w
) > var
->h_scale_up_max
||
894 (tmp_h
/ src_h
) > var
->v_scale_up_max
)
900 static int mtk_mdp_m2m_s_selection(struct file
*file
, void *fh
,
901 struct v4l2_selection
*s
)
903 struct mtk_mdp_frame
*frame
;
904 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
905 struct v4l2_rect new_r
;
906 struct mtk_mdp_variant
*variant
= ctx
->mdp_dev
->variant
;
910 if (s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
911 if (s
->target
== V4L2_SEL_TGT_COMPOSE
)
913 } else if (s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
914 if (s
->target
== V4L2_SEL_TGT_CROP
)
918 mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx
->id
, s
->type
,
924 ret
= mtk_mdp_try_crop(ctx
, s
->type
, &new_r
);
928 if (mtk_mdp_is_target_crop(s
->target
))
929 frame
= &ctx
->s_frame
;
931 frame
= &ctx
->d_frame
;
933 /* Check to see if scaling ratio is within supported range */
934 if (mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_DST_FMT
| MTK_MDP_SRC_FMT
)) {
935 if (V4L2_TYPE_IS_OUTPUT(s
->type
)) {
936 ret
= mtk_mdp_check_scaler_ratio(variant
, new_r
.width
,
937 new_r
.height
, ctx
->d_frame
.crop
.width
,
938 ctx
->d_frame
.crop
.height
,
939 ctx
->ctrls
.rotate
->val
);
941 ret
= mtk_mdp_check_scaler_ratio(variant
,
942 ctx
->s_frame
.crop
.width
,
943 ctx
->s_frame
.crop
.height
, new_r
.width
,
944 new_r
.height
, ctx
->ctrls
.rotate
->val
);
948 dev_info(&ctx
->mdp_dev
->pdev
->dev
,
949 "Out of scaler range");
960 static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops
= {
961 .vidioc_querycap
= mtk_mdp_m2m_querycap
,
962 .vidioc_enum_fmt_vid_cap_mplane
= mtk_mdp_m2m_enum_fmt_mplane_vid_cap
,
963 .vidioc_enum_fmt_vid_out_mplane
= mtk_mdp_m2m_enum_fmt_mplane_vid_out
,
964 .vidioc_g_fmt_vid_cap_mplane
= mtk_mdp_m2m_g_fmt_mplane
,
965 .vidioc_g_fmt_vid_out_mplane
= mtk_mdp_m2m_g_fmt_mplane
,
966 .vidioc_try_fmt_vid_cap_mplane
= mtk_mdp_m2m_try_fmt_mplane
,
967 .vidioc_try_fmt_vid_out_mplane
= mtk_mdp_m2m_try_fmt_mplane
,
968 .vidioc_s_fmt_vid_cap_mplane
= mtk_mdp_m2m_s_fmt_mplane
,
969 .vidioc_s_fmt_vid_out_mplane
= mtk_mdp_m2m_s_fmt_mplane
,
970 .vidioc_reqbufs
= mtk_mdp_m2m_reqbufs
,
971 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
972 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
973 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
974 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
975 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
976 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
977 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
978 .vidioc_streamon
= mtk_mdp_m2m_streamon
,
979 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
980 .vidioc_g_selection
= mtk_mdp_m2m_g_selection
,
981 .vidioc_s_selection
= mtk_mdp_m2m_s_selection
984 static int mtk_mdp_m2m_queue_init(void *priv
, struct vb2_queue
*src_vq
,
985 struct vb2_queue
*dst_vq
)
987 struct mtk_mdp_ctx
*ctx
= priv
;
990 memset(src_vq
, 0, sizeof(*src_vq
));
991 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
992 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
993 src_vq
->drv_priv
= ctx
;
994 src_vq
->ops
= &mtk_mdp_m2m_qops
;
995 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
996 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
997 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
998 src_vq
->dev
= &ctx
->mdp_dev
->pdev
->dev
;
1000 ret
= vb2_queue_init(src_vq
);
1004 memset(dst_vq
, 0, sizeof(*dst_vq
));
1005 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1006 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
1007 dst_vq
->drv_priv
= ctx
;
1008 dst_vq
->ops
= &mtk_mdp_m2m_qops
;
1009 dst_vq
->mem_ops
= &vb2_dma_contig_memops
;
1010 dst_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
1011 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
1012 dst_vq
->dev
= &ctx
->mdp_dev
->pdev
->dev
;
1014 return vb2_queue_init(dst_vq
);
1017 static int mtk_mdp_s_ctrl(struct v4l2_ctrl
*ctrl
)
1019 struct mtk_mdp_ctx
*ctx
= ctrl_to_ctx(ctrl
);
1020 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1021 struct mtk_mdp_variant
*variant
= mdp
->variant
;
1022 u32 state
= MTK_MDP_DST_FMT
| MTK_MDP_SRC_FMT
;
1025 if (ctrl
->flags
& V4L2_CTRL_FLAG_INACTIVE
)
1029 case V4L2_CID_HFLIP
:
1030 ctx
->hflip
= ctrl
->val
;
1032 case V4L2_CID_VFLIP
:
1033 ctx
->vflip
= ctrl
->val
;
1035 case V4L2_CID_ROTATE
:
1036 if (mtk_mdp_ctx_state_is_set(ctx
, state
)) {
1037 ret
= mtk_mdp_check_scaler_ratio(variant
,
1038 ctx
->s_frame
.crop
.width
,
1039 ctx
->s_frame
.crop
.height
,
1040 ctx
->d_frame
.crop
.width
,
1041 ctx
->d_frame
.crop
.height
,
1042 ctx
->ctrls
.rotate
->val
);
1048 ctx
->rotation
= ctrl
->val
;
1050 case V4L2_CID_ALPHA_COMPONENT
:
1051 ctx
->d_frame
.alpha
= ctrl
->val
;
1058 static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops
= {
1059 .s_ctrl
= mtk_mdp_s_ctrl
,
1062 static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx
*ctx
)
1064 v4l2_ctrl_handler_init(&ctx
->ctrl_handler
, MTK_MDP_MAX_CTRL_NUM
);
1066 ctx
->ctrls
.rotate
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1067 &mtk_mdp_ctrl_ops
, V4L2_CID_ROTATE
, 0, 270, 90, 0);
1068 ctx
->ctrls
.hflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1072 ctx
->ctrls
.vflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1076 ctx
->ctrls
.global_alpha
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1078 V4L2_CID_ALPHA_COMPONENT
,
1080 ctx
->ctrls_rdy
= ctx
->ctrl_handler
.error
== 0;
1082 if (ctx
->ctrl_handler
.error
) {
1083 int err
= ctx
->ctrl_handler
.error
;
1085 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1086 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
1087 "Failed to create control handlers\n");
1094 static void mtk_mdp_set_default_params(struct mtk_mdp_ctx
*ctx
)
1096 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1097 struct mtk_mdp_frame
*frame
;
1099 frame
= mtk_mdp_ctx_get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
1100 frame
->fmt
= mtk_mdp_find_fmt_by_index(0,
1101 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
1102 frame
->width
= mdp
->variant
->pix_min
->org_w
;
1103 frame
->height
= mdp
->variant
->pix_min
->org_h
;
1104 frame
->payload
[0] = frame
->width
* frame
->height
;
1105 frame
->payload
[1] = frame
->payload
[0] / 2;
1107 frame
= mtk_mdp_ctx_get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
1108 frame
->fmt
= mtk_mdp_find_fmt_by_index(0,
1109 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
1110 frame
->width
= mdp
->variant
->pix_min
->target_rot_dis_w
;
1111 frame
->height
= mdp
->variant
->pix_min
->target_rot_dis_h
;
1112 frame
->payload
[0] = frame
->width
* frame
->height
;
1113 frame
->payload
[1] = frame
->payload
[0] / 2;
1117 static int mtk_mdp_m2m_open(struct file
*file
)
1119 struct mtk_mdp_dev
*mdp
= video_drvdata(file
);
1120 struct video_device
*vfd
= video_devdata(file
);
1121 struct mtk_mdp_ctx
*ctx
= NULL
;
1124 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
1128 if (mutex_lock_interruptible(&mdp
->lock
)) {
1133 mutex_init(&ctx
->slock
);
1134 ctx
->id
= mdp
->id_counter
++;
1135 v4l2_fh_init(&ctx
->fh
, vfd
);
1136 file
->private_data
= &ctx
->fh
;
1137 ret
= mtk_mdp_ctrls_create(ctx
);
1141 /* Use separate control handler per file handle */
1142 ctx
->fh
.ctrl_handler
= &ctx
->ctrl_handler
;
1143 v4l2_fh_add(&ctx
->fh
);
1144 INIT_LIST_HEAD(&ctx
->list
);
1147 mtk_mdp_set_default_params(ctx
);
1149 INIT_WORK(&ctx
->work
, mtk_mdp_m2m_worker
);
1150 ctx
->m2m_ctx
= v4l2_m2m_ctx_init(mdp
->m2m_dev
, ctx
,
1151 mtk_mdp_m2m_queue_init
);
1152 if (IS_ERR(ctx
->m2m_ctx
)) {
1153 dev_err(&mdp
->pdev
->dev
, "Failed to initialize m2m context");
1154 ret
= PTR_ERR(ctx
->m2m_ctx
);
1157 ctx
->fh
.m2m_ctx
= ctx
->m2m_ctx
;
1158 if (mdp
->ctx_num
++ == 0) {
1159 ret
= vpu_load_firmware(mdp
->vpu_dev
);
1161 dev_err(&mdp
->pdev
->dev
,
1162 "vpu_load_firmware failed %d\n", ret
);
1166 ret
= mtk_mdp_vpu_register(mdp
->pdev
);
1168 dev_err(&mdp
->pdev
->dev
,
1169 "mdp_vpu register failed %d\n", ret
);
1174 list_add(&ctx
->list
, &mdp
->ctx_list
);
1175 mutex_unlock(&mdp
->lock
);
1177 mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp
->pdev
->dev
), ctx
->id
);
1183 v4l2_m2m_ctx_release(ctx
->m2m_ctx
);
1185 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1187 v4l2_fh_del(&ctx
->fh
);
1188 v4l2_fh_exit(&ctx
->fh
);
1189 mutex_unlock(&mdp
->lock
);
1196 static int mtk_mdp_m2m_release(struct file
*file
)
1198 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(file
->private_data
);
1199 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1201 flush_workqueue(mdp
->job_wq
);
1202 mutex_lock(&mdp
->lock
);
1203 v4l2_m2m_ctx_release(ctx
->m2m_ctx
);
1204 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1205 v4l2_fh_del(&ctx
->fh
);
1206 v4l2_fh_exit(&ctx
->fh
);
1207 mtk_mdp_vpu_deinit(&ctx
->vpu
);
1209 list_del_init(&ctx
->list
);
1211 mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp
->pdev
->dev
), ctx
->id
);
1213 mutex_unlock(&mdp
->lock
);
1219 static const struct v4l2_file_operations mtk_mdp_m2m_fops
= {
1220 .owner
= THIS_MODULE
,
1221 .open
= mtk_mdp_m2m_open
,
1222 .release
= mtk_mdp_m2m_release
,
1223 .poll
= v4l2_m2m_fop_poll
,
1224 .unlocked_ioctl
= video_ioctl2
,
1225 .mmap
= v4l2_m2m_fop_mmap
,
1228 static const struct v4l2_m2m_ops mtk_mdp_m2m_ops
= {
1229 .device_run
= mtk_mdp_m2m_device_run
,
1230 .job_abort
= mtk_mdp_m2m_job_abort
,
1233 int mtk_mdp_register_m2m_device(struct mtk_mdp_dev
*mdp
)
1235 struct device
*dev
= &mdp
->pdev
->dev
;
1238 mdp
->variant
= &mtk_mdp_default_variant
;
1239 mdp
->vdev
= video_device_alloc();
1241 dev_err(dev
, "failed to allocate video device\n");
1243 goto err_video_alloc
;
1245 mdp
->vdev
->device_caps
= V4L2_CAP_VIDEO_M2M_MPLANE
| V4L2_CAP_STREAMING
;
1246 mdp
->vdev
->fops
= &mtk_mdp_m2m_fops
;
1247 mdp
->vdev
->ioctl_ops
= &mtk_mdp_m2m_ioctl_ops
;
1248 mdp
->vdev
->release
= video_device_release
;
1249 mdp
->vdev
->lock
= &mdp
->lock
;
1250 mdp
->vdev
->vfl_dir
= VFL_DIR_M2M
;
1251 mdp
->vdev
->v4l2_dev
= &mdp
->v4l2_dev
;
1252 snprintf(mdp
->vdev
->name
, sizeof(mdp
->vdev
->name
), "%s:m2m",
1253 MTK_MDP_MODULE_NAME
);
1254 video_set_drvdata(mdp
->vdev
, mdp
);
1256 mdp
->m2m_dev
= v4l2_m2m_init(&mtk_mdp_m2m_ops
);
1257 if (IS_ERR(mdp
->m2m_dev
)) {
1258 dev_err(dev
, "failed to initialize v4l2-m2m device\n");
1259 ret
= PTR_ERR(mdp
->m2m_dev
);
1263 ret
= video_register_device(mdp
->vdev
, VFL_TYPE_GRABBER
, 2);
1265 dev_err(dev
, "failed to register video device\n");
1266 goto err_vdev_register
;
1269 v4l2_info(&mdp
->v4l2_dev
, "driver registered as /dev/video%d",
1274 v4l2_m2m_release(mdp
->m2m_dev
);
1276 video_device_release(mdp
->vdev
);
1282 void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev
*mdp
)
1284 video_unregister_device(mdp
->vdev
);
1285 v4l2_m2m_release(mdp
->m2m_dev
);