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_set_frame_size(struct mtk_mdp_frame
*frame
, int width
,
400 frame
->width
= width
;
401 frame
->height
= height
;
402 frame
->crop
.width
= width
;
403 frame
->crop
.height
= height
;
404 frame
->crop
.left
= 0;
408 static int mtk_mdp_m2m_start_streaming(struct vb2_queue
*q
, unsigned int count
)
410 struct mtk_mdp_ctx
*ctx
= q
->drv_priv
;
413 ret
= pm_runtime_get_sync(&ctx
->mdp_dev
->pdev
->dev
);
415 mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
421 static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx
*ctx
,
422 enum v4l2_buf_type type
)
424 if (V4L2_TYPE_IS_OUTPUT(type
))
425 return v4l2_m2m_src_buf_remove(ctx
->m2m_ctx
);
427 return v4l2_m2m_dst_buf_remove(ctx
->m2m_ctx
);
430 static void mtk_mdp_m2m_stop_streaming(struct vb2_queue
*q
)
432 struct mtk_mdp_ctx
*ctx
= q
->drv_priv
;
433 struct vb2_buffer
*vb
;
435 vb
= mtk_mdp_m2m_buf_remove(ctx
, q
->type
);
437 v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb
), VB2_BUF_STATE_ERROR
);
438 vb
= mtk_mdp_m2m_buf_remove(ctx
, q
->type
);
441 pm_runtime_put(&ctx
->mdp_dev
->pdev
->dev
);
444 /* The color format (num_planes) must be already configured. */
445 static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx
*ctx
,
446 struct vb2_buffer
*vb
,
447 struct mtk_mdp_frame
*frame
,
448 struct mtk_mdp_addr
*addr
)
450 u32 pix_size
, planes
, i
;
452 pix_size
= frame
->width
* frame
->height
;
453 planes
= min_t(u32
, frame
->fmt
->num_planes
, ARRAY_SIZE(addr
->addr
));
454 for (i
= 0; i
< planes
; i
++)
455 addr
->addr
[i
] = vb2_dma_contig_plane_dma_addr(vb
, i
);
458 if (frame
->fmt
->pixelformat
== V4L2_PIX_FMT_YVU420
) {
459 addr
->addr
[1] = (dma_addr_t
)(addr
->addr
[0] + pix_size
);
460 addr
->addr
[2] = (dma_addr_t
)(addr
->addr
[1] +
463 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
464 "Invalid pixelformat:0x%x\n",
465 frame
->fmt
->pixelformat
);
468 mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
469 ctx
->id
, planes
, pix_size
, (void *)addr
->addr
[0],
470 (void *)addr
->addr
[1], (void *)addr
->addr
[2]);
473 static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx
*ctx
)
475 struct mtk_mdp_frame
*s_frame
, *d_frame
;
476 struct vb2_buffer
*src_vb
, *dst_vb
;
477 struct vb2_v4l2_buffer
*src_vbuf
, *dst_vbuf
;
479 s_frame
= &ctx
->s_frame
;
480 d_frame
= &ctx
->d_frame
;
482 src_vb
= v4l2_m2m_next_src_buf(ctx
->m2m_ctx
);
483 mtk_mdp_prepare_addr(ctx
, src_vb
, s_frame
, &s_frame
->addr
);
485 dst_vb
= v4l2_m2m_next_dst_buf(ctx
->m2m_ctx
);
486 mtk_mdp_prepare_addr(ctx
, dst_vb
, d_frame
, &d_frame
->addr
);
488 src_vbuf
= to_vb2_v4l2_buffer(src_vb
);
489 dst_vbuf
= to_vb2_v4l2_buffer(dst_vb
);
490 dst_vbuf
->vb2_buf
.timestamp
= src_vbuf
->vb2_buf
.timestamp
;
493 static void mtk_mdp_process_done(void *priv
, int vb_state
)
495 struct mtk_mdp_dev
*mdp
= priv
;
496 struct mtk_mdp_ctx
*ctx
;
497 struct vb2_buffer
*src_vb
, *dst_vb
;
498 struct vb2_v4l2_buffer
*src_vbuf
= NULL
, *dst_vbuf
= NULL
;
500 ctx
= v4l2_m2m_get_curr_priv(mdp
->m2m_dev
);
504 src_vb
= v4l2_m2m_src_buf_remove(ctx
->m2m_ctx
);
505 src_vbuf
= to_vb2_v4l2_buffer(src_vb
);
506 dst_vb
= v4l2_m2m_dst_buf_remove(ctx
->m2m_ctx
);
507 dst_vbuf
= to_vb2_v4l2_buffer(dst_vb
);
509 dst_vbuf
->vb2_buf
.timestamp
= src_vbuf
->vb2_buf
.timestamp
;
510 dst_vbuf
->timecode
= src_vbuf
->timecode
;
511 dst_vbuf
->flags
&= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
512 dst_vbuf
->flags
|= src_vbuf
->flags
& V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
514 v4l2_m2m_buf_done(src_vbuf
, vb_state
);
515 v4l2_m2m_buf_done(dst_vbuf
, vb_state
);
516 v4l2_m2m_job_finish(ctx
->mdp_dev
->m2m_dev
, ctx
->m2m_ctx
);
519 static void mtk_mdp_m2m_worker(struct work_struct
*work
)
521 struct mtk_mdp_ctx
*ctx
=
522 container_of(work
, struct mtk_mdp_ctx
, work
);
523 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
524 enum vb2_buffer_state buf_state
= VB2_BUF_STATE_ERROR
;
527 if (mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_CTX_ERROR
)) {
528 dev_err(&mdp
->pdev
->dev
, "ctx is in error state");
532 mtk_mdp_m2m_get_bufs(ctx
);
534 mtk_mdp_hw_set_input_addr(ctx
, &ctx
->s_frame
.addr
);
535 mtk_mdp_hw_set_output_addr(ctx
, &ctx
->d_frame
.addr
);
537 mtk_mdp_hw_set_in_size(ctx
);
538 mtk_mdp_hw_set_in_image_format(ctx
);
540 mtk_mdp_hw_set_out_size(ctx
);
541 mtk_mdp_hw_set_out_image_format(ctx
);
543 mtk_mdp_hw_set_rotation(ctx
);
544 mtk_mdp_hw_set_global_alpha(ctx
);
546 ret
= mtk_mdp_vpu_process(&ctx
->vpu
);
548 dev_err(&mdp
->pdev
->dev
, "processing failed: %d", ret
);
552 buf_state
= VB2_BUF_STATE_DONE
;
555 mtk_mdp_process_done(mdp
, buf_state
);
558 static void mtk_mdp_m2m_device_run(void *priv
)
560 struct mtk_mdp_ctx
*ctx
= priv
;
562 queue_work(ctx
->mdp_dev
->job_wq
, &ctx
->work
);
565 static int mtk_mdp_m2m_queue_setup(struct vb2_queue
*vq
,
566 unsigned int *num_buffers
, unsigned int *num_planes
,
567 unsigned int sizes
[], struct device
*alloc_devs
[])
569 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vq
);
570 struct mtk_mdp_frame
*frame
;
573 frame
= mtk_mdp_ctx_get_frame(ctx
, vq
->type
);
574 *num_planes
= frame
->fmt
->num_planes
;
575 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
576 sizes
[i
] = frame
->payload
[i
];
577 mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
578 ctx
->id
, vq
->type
, *num_planes
, *num_buffers
,
583 static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer
*vb
)
585 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
586 struct mtk_mdp_frame
*frame
;
589 frame
= mtk_mdp_ctx_get_frame(ctx
, vb
->vb2_queue
->type
);
591 if (!V4L2_TYPE_IS_OUTPUT(vb
->vb2_queue
->type
)) {
592 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++)
593 vb2_set_plane_payload(vb
, i
, frame
->payload
[i
]);
599 static void mtk_mdp_m2m_buf_queue(struct vb2_buffer
*vb
)
601 struct mtk_mdp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
603 v4l2_m2m_buf_queue(ctx
->m2m_ctx
, to_vb2_v4l2_buffer(vb
));
606 static const struct vb2_ops mtk_mdp_m2m_qops
= {
607 .queue_setup
= mtk_mdp_m2m_queue_setup
,
608 .buf_prepare
= mtk_mdp_m2m_buf_prepare
,
609 .buf_queue
= mtk_mdp_m2m_buf_queue
,
610 .stop_streaming
= mtk_mdp_m2m_stop_streaming
,
611 .start_streaming
= mtk_mdp_m2m_start_streaming
,
612 .wait_prepare
= vb2_ops_wait_prepare
,
613 .wait_finish
= vb2_ops_wait_finish
,
616 static int mtk_mdp_m2m_querycap(struct file
*file
, void *fh
,
617 struct v4l2_capability
*cap
)
619 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
620 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
622 strlcpy(cap
->driver
, MTK_MDP_MODULE_NAME
, sizeof(cap
->driver
));
623 strlcpy(cap
->card
, mdp
->pdev
->name
, sizeof(cap
->card
));
624 strlcpy(cap
->bus_info
, "platform:mt8173", sizeof(cap
->bus_info
));
629 static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc
*f
, u32 type
)
631 const struct mtk_mdp_fmt
*fmt
;
633 fmt
= mtk_mdp_find_fmt_by_index(f
->index
, type
);
637 f
->pixelformat
= fmt
->pixelformat
;
642 static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file
*file
, void *priv
,
643 struct v4l2_fmtdesc
*f
)
645 return mtk_mdp_enum_fmt_mplane(f
, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
648 static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file
*file
, void *priv
,
649 struct v4l2_fmtdesc
*f
)
651 return mtk_mdp_enum_fmt_mplane(f
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
654 static int mtk_mdp_m2m_g_fmt_mplane(struct file
*file
, void *fh
,
655 struct v4l2_format
*f
)
657 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
658 struct mtk_mdp_frame
*frame
;
659 struct v4l2_pix_format_mplane
*pix_mp
;
662 mtk_mdp_dbg(2, "[%d] type:%d", ctx
->id
, f
->type
);
664 frame
= mtk_mdp_ctx_get_frame(ctx
, f
->type
);
665 pix_mp
= &f
->fmt
.pix_mp
;
667 pix_mp
->width
= frame
->width
;
668 pix_mp
->height
= frame
->height
;
669 pix_mp
->field
= V4L2_FIELD_NONE
;
670 pix_mp
->pixelformat
= frame
->fmt
->pixelformat
;
671 pix_mp
->num_planes
= frame
->fmt
->num_planes
;
672 pix_mp
->colorspace
= ctx
->colorspace
;
673 pix_mp
->xfer_func
= ctx
->xfer_func
;
674 pix_mp
->ycbcr_enc
= ctx
->ycbcr_enc
;
675 pix_mp
->quantization
= ctx
->quant
;
676 mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx
->id
,
677 pix_mp
->width
, pix_mp
->height
);
679 for (i
= 0; i
< pix_mp
->num_planes
; ++i
) {
680 pix_mp
->plane_fmt
[i
].bytesperline
= (frame
->width
*
681 frame
->fmt
->row_depth
[i
]) / 8;
682 pix_mp
->plane_fmt
[i
].sizeimage
= (frame
->width
*
683 frame
->height
* frame
->fmt
->depth
[i
]) / 8;
685 mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx
->id
, i
,
686 pix_mp
->plane_fmt
[i
].bytesperline
,
687 pix_mp
->plane_fmt
[i
].sizeimage
);
693 static int mtk_mdp_m2m_try_fmt_mplane(struct file
*file
, void *fh
,
694 struct v4l2_format
*f
)
696 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
698 if (!mtk_mdp_try_fmt_mplane(ctx
, f
))
703 static int mtk_mdp_m2m_s_fmt_mplane(struct file
*file
, void *fh
,
704 struct v4l2_format
*f
)
706 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
707 struct vb2_queue
*vq
;
708 struct mtk_mdp_frame
*frame
;
709 struct v4l2_pix_format_mplane
*pix_mp
;
710 const struct mtk_mdp_fmt
*fmt
;
713 mtk_mdp_dbg(2, "[%d] type:%d", ctx
->id
, f
->type
);
715 frame
= mtk_mdp_ctx_get_frame(ctx
, f
->type
);
716 fmt
= mtk_mdp_try_fmt_mplane(ctx
, f
);
718 mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx
->id
, f
->type
);
723 vq
= v4l2_m2m_get_vq(ctx
->m2m_ctx
, f
->type
);
724 if (vb2_is_streaming(vq
)) {
725 dev_info(&ctx
->mdp_dev
->pdev
->dev
, "queue %d busy", f
->type
);
729 pix_mp
= &f
->fmt
.pix_mp
;
730 for (i
= 0; i
< frame
->fmt
->num_planes
; i
++) {
731 frame
->payload
[i
] = pix_mp
->plane_fmt
[i
].sizeimage
;
732 frame
->pitch
[i
] = pix_mp
->plane_fmt
[i
].bytesperline
;
735 mtk_mdp_set_frame_size(frame
, pix_mp
->width
, pix_mp
->height
);
736 if (V4L2_TYPE_IS_OUTPUT(f
->type
)) {
737 ctx
->colorspace
= pix_mp
->colorspace
;
738 ctx
->xfer_func
= pix_mp
->xfer_func
;
739 ctx
->ycbcr_enc
= pix_mp
->ycbcr_enc
;
740 ctx
->quant
= pix_mp
->quantization
;
743 if (V4L2_TYPE_IS_OUTPUT(f
->type
))
744 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_SRC_FMT
);
746 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_DST_FMT
);
748 mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx
->id
, f
->type
,
749 frame
->width
, frame
->height
);
754 static int mtk_mdp_m2m_reqbufs(struct file
*file
, void *fh
,
755 struct v4l2_requestbuffers
*reqbufs
)
757 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
759 if (reqbufs
->count
== 0) {
760 if (reqbufs
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
761 mtk_mdp_ctx_state_lock_clear(ctx
, MTK_MDP_SRC_FMT
);
763 mtk_mdp_ctx_state_lock_clear(ctx
, MTK_MDP_DST_FMT
);
766 return v4l2_m2m_reqbufs(file
, ctx
->m2m_ctx
, reqbufs
);
769 static int mtk_mdp_m2m_streamon(struct file
*file
, void *fh
,
770 enum v4l2_buf_type type
)
772 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
775 /* The source and target color format need to be set */
776 if (V4L2_TYPE_IS_OUTPUT(type
)) {
777 if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_SRC_FMT
))
779 } else if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_DST_FMT
)) {
783 if (!mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_VPU_INIT
)) {
784 ret
= mtk_mdp_vpu_init(&ctx
->vpu
);
786 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
787 "vpu init failed %d\n",
791 mtk_mdp_ctx_state_lock_set(ctx
, MTK_MDP_VPU_INIT
);
794 return v4l2_m2m_streamon(file
, ctx
->m2m_ctx
, type
);
797 static inline bool mtk_mdp_is_target_compose(u32 target
)
799 if (target
== V4L2_SEL_TGT_COMPOSE_DEFAULT
800 || target
== V4L2_SEL_TGT_COMPOSE_BOUNDS
801 || target
== V4L2_SEL_TGT_COMPOSE
)
806 static inline bool mtk_mdp_is_target_crop(u32 target
)
808 if (target
== V4L2_SEL_TGT_CROP_DEFAULT
809 || target
== V4L2_SEL_TGT_CROP_BOUNDS
810 || target
== V4L2_SEL_TGT_CROP
)
815 static int mtk_mdp_m2m_g_selection(struct file
*file
, void *fh
,
816 struct v4l2_selection
*s
)
818 struct mtk_mdp_frame
*frame
;
819 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
822 if (s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
823 if (mtk_mdp_is_target_compose(s
->target
))
825 } else if (s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
826 if (mtk_mdp_is_target_crop(s
->target
))
830 mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx
->id
, s
->type
,
835 frame
= mtk_mdp_ctx_get_frame(ctx
, s
->type
);
838 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
839 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
840 case V4L2_SEL_TGT_CROP_BOUNDS
:
841 case V4L2_SEL_TGT_CROP_DEFAULT
:
844 s
->r
.width
= frame
->width
;
845 s
->r
.height
= frame
->height
;
848 case V4L2_SEL_TGT_COMPOSE
:
849 case V4L2_SEL_TGT_CROP
:
850 s
->r
.left
= frame
->crop
.left
;
851 s
->r
.top
= frame
->crop
.top
;
852 s
->r
.width
= frame
->crop
.width
;
853 s
->r
.height
= frame
->crop
.height
;
860 static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant
*var
, int src_w
,
861 int src_h
, int dst_w
, int dst_h
, int rot
)
865 if (rot
== 90 || rot
== 270) {
873 if ((src_w
/ tmp_w
) > var
->h_scale_down_max
||
874 (src_h
/ tmp_h
) > var
->v_scale_down_max
||
875 (tmp_w
/ src_w
) > var
->h_scale_up_max
||
876 (tmp_h
/ src_h
) > var
->v_scale_up_max
)
882 static int mtk_mdp_m2m_s_selection(struct file
*file
, void *fh
,
883 struct v4l2_selection
*s
)
885 struct mtk_mdp_frame
*frame
;
886 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(fh
);
887 struct v4l2_rect new_r
;
888 struct mtk_mdp_variant
*variant
= ctx
->mdp_dev
->variant
;
892 if (s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
893 if (s
->target
== V4L2_SEL_TGT_COMPOSE
)
895 } else if (s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
896 if (s
->target
== V4L2_SEL_TGT_CROP
)
900 mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx
->id
, s
->type
,
906 ret
= mtk_mdp_try_crop(ctx
, s
->type
, &new_r
);
910 if (mtk_mdp_is_target_crop(s
->target
))
911 frame
= &ctx
->s_frame
;
913 frame
= &ctx
->d_frame
;
915 /* Check to see if scaling ratio is within supported range */
916 if (mtk_mdp_ctx_state_is_set(ctx
, MTK_MDP_DST_FMT
| MTK_MDP_SRC_FMT
)) {
917 if (V4L2_TYPE_IS_OUTPUT(s
->type
)) {
918 ret
= mtk_mdp_check_scaler_ratio(variant
, new_r
.width
,
919 new_r
.height
, ctx
->d_frame
.crop
.width
,
920 ctx
->d_frame
.crop
.height
,
921 ctx
->ctrls
.rotate
->val
);
923 ret
= mtk_mdp_check_scaler_ratio(variant
,
924 ctx
->s_frame
.crop
.width
,
925 ctx
->s_frame
.crop
.height
, new_r
.width
,
926 new_r
.height
, ctx
->ctrls
.rotate
->val
);
930 dev_info(&ctx
->mdp_dev
->pdev
->dev
,
931 "Out of scaler range");
942 static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops
= {
943 .vidioc_querycap
= mtk_mdp_m2m_querycap
,
944 .vidioc_enum_fmt_vid_cap_mplane
= mtk_mdp_m2m_enum_fmt_mplane_vid_cap
,
945 .vidioc_enum_fmt_vid_out_mplane
= mtk_mdp_m2m_enum_fmt_mplane_vid_out
,
946 .vidioc_g_fmt_vid_cap_mplane
= mtk_mdp_m2m_g_fmt_mplane
,
947 .vidioc_g_fmt_vid_out_mplane
= mtk_mdp_m2m_g_fmt_mplane
,
948 .vidioc_try_fmt_vid_cap_mplane
= mtk_mdp_m2m_try_fmt_mplane
,
949 .vidioc_try_fmt_vid_out_mplane
= mtk_mdp_m2m_try_fmt_mplane
,
950 .vidioc_s_fmt_vid_cap_mplane
= mtk_mdp_m2m_s_fmt_mplane
,
951 .vidioc_s_fmt_vid_out_mplane
= mtk_mdp_m2m_s_fmt_mplane
,
952 .vidioc_reqbufs
= mtk_mdp_m2m_reqbufs
,
953 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
954 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
955 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
956 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
957 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
958 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
959 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
960 .vidioc_streamon
= mtk_mdp_m2m_streamon
,
961 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
962 .vidioc_g_selection
= mtk_mdp_m2m_g_selection
,
963 .vidioc_s_selection
= mtk_mdp_m2m_s_selection
966 static int mtk_mdp_m2m_queue_init(void *priv
, struct vb2_queue
*src_vq
,
967 struct vb2_queue
*dst_vq
)
969 struct mtk_mdp_ctx
*ctx
= priv
;
972 memset(src_vq
, 0, sizeof(*src_vq
));
973 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
974 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
975 src_vq
->drv_priv
= ctx
;
976 src_vq
->ops
= &mtk_mdp_m2m_qops
;
977 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
978 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
979 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
980 src_vq
->dev
= &ctx
->mdp_dev
->pdev
->dev
;
981 src_vq
->lock
= &ctx
->mdp_dev
->lock
;
983 ret
= vb2_queue_init(src_vq
);
987 memset(dst_vq
, 0, sizeof(*dst_vq
));
988 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
989 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
990 dst_vq
->drv_priv
= ctx
;
991 dst_vq
->ops
= &mtk_mdp_m2m_qops
;
992 dst_vq
->mem_ops
= &vb2_dma_contig_memops
;
993 dst_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
994 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
995 dst_vq
->dev
= &ctx
->mdp_dev
->pdev
->dev
;
996 dst_vq
->lock
= &ctx
->mdp_dev
->lock
;
998 return vb2_queue_init(dst_vq
);
1001 static int mtk_mdp_s_ctrl(struct v4l2_ctrl
*ctrl
)
1003 struct mtk_mdp_ctx
*ctx
= ctrl_to_ctx(ctrl
);
1004 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1005 struct mtk_mdp_variant
*variant
= mdp
->variant
;
1006 u32 state
= MTK_MDP_DST_FMT
| MTK_MDP_SRC_FMT
;
1009 if (ctrl
->flags
& V4L2_CTRL_FLAG_INACTIVE
)
1013 case V4L2_CID_HFLIP
:
1014 ctx
->hflip
= ctrl
->val
;
1016 case V4L2_CID_VFLIP
:
1017 ctx
->vflip
= ctrl
->val
;
1019 case V4L2_CID_ROTATE
:
1020 if (mtk_mdp_ctx_state_is_set(ctx
, state
)) {
1021 ret
= mtk_mdp_check_scaler_ratio(variant
,
1022 ctx
->s_frame
.crop
.width
,
1023 ctx
->s_frame
.crop
.height
,
1024 ctx
->d_frame
.crop
.width
,
1025 ctx
->d_frame
.crop
.height
,
1026 ctx
->ctrls
.rotate
->val
);
1032 ctx
->rotation
= ctrl
->val
;
1034 case V4L2_CID_ALPHA_COMPONENT
:
1035 ctx
->d_frame
.alpha
= ctrl
->val
;
1042 static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops
= {
1043 .s_ctrl
= mtk_mdp_s_ctrl
,
1046 static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx
*ctx
)
1048 v4l2_ctrl_handler_init(&ctx
->ctrl_handler
, MTK_MDP_MAX_CTRL_NUM
);
1050 ctx
->ctrls
.rotate
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1051 &mtk_mdp_ctrl_ops
, V4L2_CID_ROTATE
, 0, 270, 90, 0);
1052 ctx
->ctrls
.hflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1056 ctx
->ctrls
.vflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1060 ctx
->ctrls
.global_alpha
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
1062 V4L2_CID_ALPHA_COMPONENT
,
1064 ctx
->ctrls_rdy
= ctx
->ctrl_handler
.error
== 0;
1066 if (ctx
->ctrl_handler
.error
) {
1067 int err
= ctx
->ctrl_handler
.error
;
1069 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1070 dev_err(&ctx
->mdp_dev
->pdev
->dev
,
1071 "Failed to create control handlers\n");
1078 static void mtk_mdp_set_default_params(struct mtk_mdp_ctx
*ctx
)
1080 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1081 struct mtk_mdp_frame
*frame
;
1083 frame
= mtk_mdp_ctx_get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
1084 frame
->fmt
= mtk_mdp_find_fmt_by_index(0,
1085 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
1086 frame
->width
= mdp
->variant
->pix_min
->org_w
;
1087 frame
->height
= mdp
->variant
->pix_min
->org_h
;
1088 frame
->payload
[0] = frame
->width
* frame
->height
;
1089 frame
->payload
[1] = frame
->payload
[0] / 2;
1091 frame
= mtk_mdp_ctx_get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
1092 frame
->fmt
= mtk_mdp_find_fmt_by_index(0,
1093 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
1094 frame
->width
= mdp
->variant
->pix_min
->target_rot_dis_w
;
1095 frame
->height
= mdp
->variant
->pix_min
->target_rot_dis_h
;
1096 frame
->payload
[0] = frame
->width
* frame
->height
;
1097 frame
->payload
[1] = frame
->payload
[0] / 2;
1101 static int mtk_mdp_m2m_open(struct file
*file
)
1103 struct mtk_mdp_dev
*mdp
= video_drvdata(file
);
1104 struct video_device
*vfd
= video_devdata(file
);
1105 struct mtk_mdp_ctx
*ctx
= NULL
;
1108 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
1112 if (mutex_lock_interruptible(&mdp
->lock
)) {
1117 mutex_init(&ctx
->slock
);
1118 ctx
->id
= mdp
->id_counter
++;
1119 v4l2_fh_init(&ctx
->fh
, vfd
);
1120 file
->private_data
= &ctx
->fh
;
1121 ret
= mtk_mdp_ctrls_create(ctx
);
1125 /* Use separate control handler per file handle */
1126 ctx
->fh
.ctrl_handler
= &ctx
->ctrl_handler
;
1127 v4l2_fh_add(&ctx
->fh
);
1128 INIT_LIST_HEAD(&ctx
->list
);
1131 mtk_mdp_set_default_params(ctx
);
1133 INIT_WORK(&ctx
->work
, mtk_mdp_m2m_worker
);
1134 ctx
->m2m_ctx
= v4l2_m2m_ctx_init(mdp
->m2m_dev
, ctx
,
1135 mtk_mdp_m2m_queue_init
);
1136 if (IS_ERR(ctx
->m2m_ctx
)) {
1137 dev_err(&mdp
->pdev
->dev
, "Failed to initialize m2m context");
1138 ret
= PTR_ERR(ctx
->m2m_ctx
);
1141 ctx
->fh
.m2m_ctx
= ctx
->m2m_ctx
;
1142 if (mdp
->ctx_num
++ == 0) {
1143 ret
= vpu_load_firmware(mdp
->vpu_dev
);
1145 dev_err(&mdp
->pdev
->dev
,
1146 "vpu_load_firmware failed %d\n", ret
);
1150 ret
= mtk_mdp_vpu_register(mdp
->pdev
);
1152 dev_err(&mdp
->pdev
->dev
,
1153 "mdp_vpu register failed %d\n", ret
);
1158 list_add(&ctx
->list
, &mdp
->ctx_list
);
1159 mutex_unlock(&mdp
->lock
);
1161 mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp
->pdev
->dev
), ctx
->id
);
1167 v4l2_m2m_ctx_release(ctx
->m2m_ctx
);
1169 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1171 v4l2_fh_del(&ctx
->fh
);
1172 v4l2_fh_exit(&ctx
->fh
);
1173 mutex_unlock(&mdp
->lock
);
1180 static int mtk_mdp_m2m_release(struct file
*file
)
1182 struct mtk_mdp_ctx
*ctx
= fh_to_ctx(file
->private_data
);
1183 struct mtk_mdp_dev
*mdp
= ctx
->mdp_dev
;
1185 flush_workqueue(mdp
->job_wq
);
1186 mutex_lock(&mdp
->lock
);
1187 v4l2_m2m_ctx_release(ctx
->m2m_ctx
);
1188 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
1189 v4l2_fh_del(&ctx
->fh
);
1190 v4l2_fh_exit(&ctx
->fh
);
1191 mtk_mdp_vpu_deinit(&ctx
->vpu
);
1193 list_del_init(&ctx
->list
);
1195 mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp
->pdev
->dev
), ctx
->id
);
1197 mutex_unlock(&mdp
->lock
);
1203 static const struct v4l2_file_operations mtk_mdp_m2m_fops
= {
1204 .owner
= THIS_MODULE
,
1205 .open
= mtk_mdp_m2m_open
,
1206 .release
= mtk_mdp_m2m_release
,
1207 .poll
= v4l2_m2m_fop_poll
,
1208 .unlocked_ioctl
= video_ioctl2
,
1209 .mmap
= v4l2_m2m_fop_mmap
,
1212 static const struct v4l2_m2m_ops mtk_mdp_m2m_ops
= {
1213 .device_run
= mtk_mdp_m2m_device_run
,
1216 int mtk_mdp_register_m2m_device(struct mtk_mdp_dev
*mdp
)
1218 struct device
*dev
= &mdp
->pdev
->dev
;
1221 mdp
->variant
= &mtk_mdp_default_variant
;
1222 mdp
->vdev
= video_device_alloc();
1224 dev_err(dev
, "failed to allocate video device\n");
1226 goto err_video_alloc
;
1228 mdp
->vdev
->device_caps
= V4L2_CAP_VIDEO_M2M_MPLANE
| V4L2_CAP_STREAMING
;
1229 mdp
->vdev
->fops
= &mtk_mdp_m2m_fops
;
1230 mdp
->vdev
->ioctl_ops
= &mtk_mdp_m2m_ioctl_ops
;
1231 mdp
->vdev
->release
= video_device_release
;
1232 mdp
->vdev
->lock
= &mdp
->lock
;
1233 mdp
->vdev
->vfl_dir
= VFL_DIR_M2M
;
1234 mdp
->vdev
->v4l2_dev
= &mdp
->v4l2_dev
;
1235 snprintf(mdp
->vdev
->name
, sizeof(mdp
->vdev
->name
), "%s:m2m",
1236 MTK_MDP_MODULE_NAME
);
1237 video_set_drvdata(mdp
->vdev
, mdp
);
1239 mdp
->m2m_dev
= v4l2_m2m_init(&mtk_mdp_m2m_ops
);
1240 if (IS_ERR(mdp
->m2m_dev
)) {
1241 dev_err(dev
, "failed to initialize v4l2-m2m device\n");
1242 ret
= PTR_ERR(mdp
->m2m_dev
);
1246 ret
= video_register_device(mdp
->vdev
, VFL_TYPE_GRABBER
, 2);
1248 dev_err(dev
, "failed to register video device\n");
1249 goto err_vdev_register
;
1252 v4l2_info(&mdp
->v4l2_dev
, "driver registered as /dev/video%d",
1257 v4l2_m2m_release(mdp
->m2m_dev
);
1259 video_device_release(mdp
->vdev
);
1265 void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev
*mdp
)
1267 video_unregister_device(mdp
->vdev
);
1268 v4l2_m2m_release(mdp
->m2m_dev
);