cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mtk_mdp_m2m.c (32802B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015-2016 MediaTek Inc.
      4 * Author: Houlong Wei <houlong.wei@mediatek.com>
      5 *         Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
      6 */
      7
      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>
     16
     17#include "mtk_mdp_core.h"
     18#include "mtk_mdp_m2m.h"
     19#include "mtk_mdp_regs.h"
     20#include "mtk_vpu.h"
     21
     22
     23/**
     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
     31 */
     32struct mtk_mdp_pix_limit {
     33	u16 org_w;
     34	u16 org_h;
     35	u16 target_rot_dis_w;
     36	u16 target_rot_dis_h;
     37	u16 target_rot_en_w;
     38	u16 target_rot_en_h;
     39};
     40
     41static struct mtk_mdp_pix_align mtk_mdp_size_align = {
     42	.org_w			= 16,
     43	.org_h			= 16,
     44	.target_w		= 2,
     45	.target_h		= 2,
     46};
     47
     48static const struct mtk_mdp_fmt mtk_mdp_formats[] = {
     49	{
     50		.pixelformat	= V4L2_PIX_FMT_MT21C,
     51		.depth		= { 8, 4 },
     52		.row_depth	= { 8, 8 },
     53		.num_planes	= 2,
     54		.num_comp	= 2,
     55		.align		= &mtk_mdp_size_align,
     56		.flags		= MTK_MDP_FMT_FLAG_OUTPUT,
     57	}, {
     58		.pixelformat	= V4L2_PIX_FMT_NV12M,
     59		.depth		= { 8, 4 },
     60		.row_depth	= { 8, 8 },
     61		.num_planes	= 2,
     62		.num_comp	= 2,
     63		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
     64				  MTK_MDP_FMT_FLAG_CAPTURE,
     65	}, {
     66		.pixelformat	= V4L2_PIX_FMT_YUV420M,
     67		.depth		= { 8, 2, 2 },
     68		.row_depth	= { 8, 4, 4 },
     69		.num_planes	= 3,
     70		.num_comp	= 3,
     71		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
     72				  MTK_MDP_FMT_FLAG_CAPTURE,
     73	}, {
     74		.pixelformat	= V4L2_PIX_FMT_YVU420,
     75		.depth		= { 12 },
     76		.row_depth	= { 8 },
     77		.num_planes	= 1,
     78		.num_comp	= 3,
     79		.flags		= MTK_MDP_FMT_FLAG_OUTPUT |
     80				  MTK_MDP_FMT_FLAG_CAPTURE,
     81	}
     82};
     83
     84static 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,
     89};
     90
     91static struct mtk_mdp_pix_limit mtk_mdp_size_min = {
     92	.org_w			= 16,
     93	.org_h			= 16,
     94	.target_rot_dis_w	= 16,
     95	.target_rot_dis_h	= 16,
     96	.target_rot_en_w	= 16,
     97	.target_rot_en_h	= 16,
     98};
     99
    100/* align size for normal raster scan pixel format */
    101static struct mtk_mdp_pix_align mtk_mdp_rs_align = {
    102	.org_w			= 2,
    103	.org_h			= 2,
    104	.target_w		= 2,
    105	.target_h		= 2,
    106};
    107
    108static 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,
    116};
    117
    118static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type)
    119{
    120	u32 i, flag;
    121
    122	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
    123					   MTK_MDP_FMT_FLAG_CAPTURE;
    124
    125	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
    126		if (!(mtk_mdp_formats[i].flags & flag))
    127			continue;
    128		if (mtk_mdp_formats[i].pixelformat == pixelformat)
    129			return &mtk_mdp_formats[i];
    130	}
    131	return NULL;
    132}
    133
    134static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type)
    135{
    136	u32 i, flag, num = 0;
    137
    138	flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
    139					   MTK_MDP_FMT_FLAG_CAPTURE;
    140
    141	for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
    142		if (!(mtk_mdp_formats[i].flags & flag))
    143			continue;
    144		if (index == num)
    145			return &mtk_mdp_formats[i];
    146		num++;
    147	}
    148	return NULL;
    149}
    150
    151static 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)
    155{
    156	int org_w, org_h, step_w, step_h;
    157	int walign, halign;
    158
    159	org_w = *w;
    160	org_h = *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);
    164
    165	step_w = 1 << walign;
    166	step_h = 1 << halign;
    167	if (*w < org_w && (*w + step_w) <= wmax)
    168		*w += step_w;
    169	if (*h < org_h && (*h + step_h) <= hmax)
    170		*h += step_h;
    171}
    172
    173static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx,
    174							struct v4l2_format *f)
    175{
    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;
    182	int i;
    183
    184	fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type);
    185	if (!fmt)
    186		fmt = mtk_mdp_find_fmt_by_index(0, f->type);
    187	if (!fmt) {
    188		dev_dbg(&ctx->mdp_dev->pdev->dev,
    189			"pixelformat format 0x%X invalid\n",
    190			pix_mp->pixelformat);
    191		return NULL;
    192	}
    193
    194	pix_mp->field = V4L2_FIELD_NONE;
    195	pix_mp->pixelformat = fmt->pixelformat;
    196	if (V4L2_TYPE_IS_CAPTURE(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;
    201	}
    202
    203	max_w = variant->pix_max->target_rot_dis_w;
    204	max_h = variant->pix_max->target_rot_dis_h;
    205
    206	if (fmt->align == NULL) {
    207		/* use default alignment */
    208		align_w = variant->pix_align->org_w;
    209		align_h = variant->pix_align->org_h;
    210	} else {
    211		align_w = fmt->align->org_w;
    212		align_h = fmt->align->org_h;
    213	}
    214
    215	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
    216		min_w = variant->pix_min->org_w;
    217		min_h = variant->pix_min->org_h;
    218	} else {
    219		min_w = variant->pix_min->target_rot_dis_w;
    220		min_h = variant->pix_min->target_rot_dis_h;
    221	}
    222
    223	mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
    224		    ctx->id, f->type, pix_mp->width, pix_mp->height,
    225		    align_w, align_h, max_w, max_h);
    226	/*
    227	 * To check if image size is modified to adjust parameter against
    228	 * hardware abilities
    229	 */
    230	org_w = pix_mp->width;
    231	org_h = pix_mp->height;
    232
    233	mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w,
    234				  &pix_mp->height, min_h, max_h, align_h);
    235
    236	if (org_w != pix_mp->width || org_h != pix_mp->height)
    237		mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id,
    238			    org_w, org_h, pix_mp->width, pix_mp->height);
    239	pix_mp->num_planes = fmt->num_planes;
    240
    241	for (i = 0; i < pix_mp->num_planes; ++i) {
    242		int bpl = (pix_mp->width * fmt->row_depth[i]) / 8;
    243		int sizeimage = (pix_mp->width * pix_mp->height *
    244			fmt->depth[i]) / 8;
    245
    246		pix_mp->plane_fmt[i].bytesperline = bpl;
    247		if (pix_mp->plane_fmt[i].sizeimage < sizeimage)
    248			pix_mp->plane_fmt[i].sizeimage = sizeimage;
    249		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id,
    250			    i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage);
    251	}
    252
    253	return fmt;
    254}
    255
    256static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx,
    257					    enum v4l2_buf_type type)
    258{
    259	if (V4L2_TYPE_IS_OUTPUT(type))
    260		return &ctx->s_frame;
    261	return &ctx->d_frame;
    262}
    263
    264static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h)
    265{
    266	if (new_w != *w || new_h != *h) {
    267		mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
    268			    *w, *h, new_w, new_h);
    269
    270		*w = new_w;
    271		*h = new_h;
    272	}
    273}
    274
    275static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type,
    276			    struct v4l2_rect *r)
    277{
    278	struct mtk_mdp_frame *frame;
    279	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
    280	struct mtk_mdp_variant *variant = mdp->variant;
    281	u32 align_w, align_h, new_w, new_h;
    282	u32 min_w, min_h, max_w, max_h;
    283
    284	if (r->top < 0 || r->left < 0) {
    285		dev_err(&ctx->mdp_dev->pdev->dev,
    286			"doesn't support negative values for top & left\n");
    287		return -EINVAL;
    288	}
    289
    290	mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, type,
    291		    r->width, r->height);
    292
    293	frame = mtk_mdp_ctx_get_frame(ctx, type);
    294	max_w = frame->width;
    295	max_h = frame->height;
    296	new_w = r->width;
    297	new_h = r->height;
    298
    299	if (V4L2_TYPE_IS_OUTPUT(type)) {
    300		align_w = 1;
    301		align_h = 1;
    302		min_w = 64;
    303		min_h = 32;
    304	} else {
    305		align_w = variant->pix_align->target_w;
    306		align_h = variant->pix_align->target_h;
    307		if (ctx->ctrls.rotate->val == 90 ||
    308		    ctx->ctrls.rotate->val == 270) {
    309			max_w = frame->height;
    310			max_h = frame->width;
    311			min_w = variant->pix_min->target_rot_en_w;
    312			min_h = variant->pix_min->target_rot_en_h;
    313			new_w = r->height;
    314			new_h = r->width;
    315		} else {
    316			min_w = variant->pix_min->target_rot_dis_w;
    317			min_h = variant->pix_min->target_rot_dis_h;
    318		}
    319	}
    320
    321	mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id,
    322		    align_w, align_h, min_w, min_h, new_w, new_h);
    323
    324	mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w,
    325				  &new_h, min_h, max_h, align_h);
    326
    327	if (V4L2_TYPE_IS_CAPTURE(type) &&
    328	    (ctx->ctrls.rotate->val == 90 || ctx->ctrls.rotate->val == 270))
    329		mtk_mdp_check_crop_change(new_h, new_w,
    330					  &r->width, &r->height);
    331	else
    332		mtk_mdp_check_crop_change(new_w, new_h,
    333					  &r->width, &r->height);
    334
    335	/* adjust left/top if cropping rectangle is out of bounds */
    336	/* Need to add code to algin left value with 2's multiple */
    337	if (r->left + new_w > max_w)
    338		r->left = max_w - new_w;
    339	if (r->top + new_h > max_h)
    340		r->top = max_h - new_h;
    341
    342	if (r->left & 1)
    343		r->left -= 1;
    344
    345	mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id,
    346		    r->left, r->top, r->width,
    347		    r->height, max_w, max_h);
    348	return 0;
    349}
    350
    351static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh)
    352{
    353	return container_of(fh, struct mtk_mdp_ctx, fh);
    354}
    355
    356static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
    357{
    358	return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler);
    359}
    360
    361void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state)
    362{
    363	mutex_lock(&ctx->slock);
    364	ctx->state |= state;
    365	mutex_unlock(&ctx->slock);
    366}
    367
    368static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask)
    369{
    370	bool ret;
    371
    372	mutex_lock(&ctx->slock);
    373	ret = (ctx->state & mask) == mask;
    374	mutex_unlock(&ctx->slock);
    375	return ret;
    376}
    377
    378static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width,
    379				   int height)
    380{
    381	frame->width = width;
    382	frame->height = height;
    383	frame->crop.width = width;
    384	frame->crop.height = height;
    385	frame->crop.left = 0;
    386	frame->crop.top = 0;
    387}
    388
    389static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
    390{
    391	struct mtk_mdp_ctx *ctx = q->drv_priv;
    392	int ret;
    393
    394	ret = pm_runtime_resume_and_get(&ctx->mdp_dev->pdev->dev);
    395	if (ret < 0)
    396		mtk_mdp_dbg(1, "[%d] pm_runtime_resume_and_get failed:%d",
    397			    ctx->id, ret);
    398
    399	return ret;
    400}
    401
    402static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
    403				    enum v4l2_buf_type type)
    404{
    405	if (V4L2_TYPE_IS_OUTPUT(type))
    406		return v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
    407	else
    408		return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
    409}
    410
    411static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q)
    412{
    413	struct mtk_mdp_ctx *ctx = q->drv_priv;
    414	struct vb2_buffer *vb;
    415
    416	vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
    417	while (vb != NULL) {
    418		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
    419		vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
    420	}
    421
    422	pm_runtime_put(&ctx->mdp_dev->pdev->dev);
    423}
    424
    425/* The color format (num_planes) must be already configured. */
    426static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx,
    427				 struct vb2_buffer *vb,
    428				 struct mtk_mdp_frame *frame,
    429				 struct mtk_mdp_addr *addr)
    430{
    431	u32 pix_size, planes, i;
    432
    433	pix_size = frame->width * frame->height;
    434	planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr));
    435	for (i = 0; i < planes; i++)
    436		addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
    437
    438	if (planes == 1) {
    439		if (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) {
    440			addr->addr[1] = (dma_addr_t)(addr->addr[0] + pix_size);
    441			addr->addr[2] = (dma_addr_t)(addr->addr[1] +
    442					(pix_size >> 2));
    443		} else {
    444			dev_err(&ctx->mdp_dev->pdev->dev,
    445				"Invalid pixelformat:0x%x\n",
    446				frame->fmt->pixelformat);
    447		}
    448	}
    449	mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
    450		    ctx->id, planes, pix_size, (void *)addr->addr[0],
    451		    (void *)addr->addr[1], (void *)addr->addr[2]);
    452}
    453
    454static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx)
    455{
    456	struct mtk_mdp_frame *s_frame, *d_frame;
    457	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
    458
    459	s_frame = &ctx->s_frame;
    460	d_frame = &ctx->d_frame;
    461
    462	src_vbuf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
    463	mtk_mdp_prepare_addr(ctx, &src_vbuf->vb2_buf, s_frame, &s_frame->addr);
    464
    465	dst_vbuf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
    466	mtk_mdp_prepare_addr(ctx, &dst_vbuf->vb2_buf, d_frame, &d_frame->addr);
    467
    468	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
    469}
    470
    471static void mtk_mdp_process_done(void *priv, int vb_state)
    472{
    473	struct mtk_mdp_dev *mdp = priv;
    474	struct mtk_mdp_ctx *ctx;
    475	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
    476
    477	ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev);
    478	if (!ctx)
    479		return;
    480
    481	src_vbuf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
    482	dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
    483
    484	dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
    485	dst_vbuf->timecode = src_vbuf->timecode;
    486	dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
    487	dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
    488
    489	v4l2_m2m_buf_done(src_vbuf, vb_state);
    490	v4l2_m2m_buf_done(dst_vbuf, vb_state);
    491	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
    492}
    493
    494static void mtk_mdp_m2m_worker(struct work_struct *work)
    495{
    496	struct mtk_mdp_ctx *ctx =
    497				container_of(work, struct mtk_mdp_ctx, work);
    498	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
    499	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
    500	int ret;
    501
    502	if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) {
    503		dev_err(&mdp->pdev->dev, "ctx is in error state");
    504		goto worker_end;
    505	}
    506
    507	mtk_mdp_m2m_get_bufs(ctx);
    508
    509	mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr);
    510	mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr);
    511
    512	mtk_mdp_hw_set_in_size(ctx);
    513	mtk_mdp_hw_set_in_image_format(ctx);
    514
    515	mtk_mdp_hw_set_out_size(ctx);
    516	mtk_mdp_hw_set_out_image_format(ctx);
    517
    518	mtk_mdp_hw_set_rotation(ctx);
    519	mtk_mdp_hw_set_global_alpha(ctx);
    520
    521	ret = mtk_mdp_vpu_process(&ctx->vpu);
    522	if (ret) {
    523		dev_err(&mdp->pdev->dev, "processing failed: %d", ret);
    524		goto worker_end;
    525	}
    526
    527	buf_state = VB2_BUF_STATE_DONE;
    528
    529worker_end:
    530	mtk_mdp_process_done(mdp, buf_state);
    531}
    532
    533static void mtk_mdp_m2m_device_run(void *priv)
    534{
    535	struct mtk_mdp_ctx *ctx = priv;
    536
    537	queue_work(ctx->mdp_dev->job_wq, &ctx->work);
    538}
    539
    540static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq,
    541			unsigned int *num_buffers, unsigned int *num_planes,
    542			unsigned int sizes[], struct device *alloc_devs[])
    543{
    544	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
    545	struct mtk_mdp_frame *frame;
    546	int i;
    547
    548	frame = mtk_mdp_ctx_get_frame(ctx, vq->type);
    549	*num_planes = frame->fmt->num_planes;
    550	for (i = 0; i < frame->fmt->num_planes; i++)
    551		sizes[i] = frame->payload[i];
    552	mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
    553		    ctx->id, vq->type, *num_planes, *num_buffers,
    554		    sizes[0], sizes[1]);
    555	return 0;
    556}
    557
    558static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb)
    559{
    560	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
    561	struct mtk_mdp_frame *frame;
    562	int i;
    563
    564	frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type);
    565
    566	if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
    567		for (i = 0; i < frame->fmt->num_planes; i++)
    568			vb2_set_plane_payload(vb, i, frame->payload[i]);
    569	}
    570
    571	return 0;
    572}
    573
    574static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb)
    575{
    576	struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
    577
    578	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
    579}
    580
    581static const struct vb2_ops mtk_mdp_m2m_qops = {
    582	.queue_setup	 = mtk_mdp_m2m_queue_setup,
    583	.buf_prepare	 = mtk_mdp_m2m_buf_prepare,
    584	.buf_queue	 = mtk_mdp_m2m_buf_queue,
    585	.stop_streaming	 = mtk_mdp_m2m_stop_streaming,
    586	.start_streaming = mtk_mdp_m2m_start_streaming,
    587	.wait_prepare	 = vb2_ops_wait_prepare,
    588	.wait_finish	 = vb2_ops_wait_finish,
    589};
    590
    591static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
    592				struct v4l2_capability *cap)
    593{
    594	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    595	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
    596
    597	strscpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
    598	strscpy(cap->card, mdp->pdev->name, sizeof(cap->card));
    599	strscpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
    600
    601	return 0;
    602}
    603
    604static int mtk_mdp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
    605{
    606	const struct mtk_mdp_fmt *fmt;
    607
    608	fmt = mtk_mdp_find_fmt_by_index(f->index, type);
    609	if (!fmt)
    610		return -EINVAL;
    611
    612	f->pixelformat = fmt->pixelformat;
    613
    614	return 0;
    615}
    616
    617static int mtk_mdp_m2m_enum_fmt_vid_cap(struct file *file, void *priv,
    618					struct v4l2_fmtdesc *f)
    619{
    620	return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
    621}
    622
    623static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv,
    624					struct v4l2_fmtdesc *f)
    625{
    626	return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
    627}
    628
    629static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
    630				    struct v4l2_format *f)
    631{
    632	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    633	struct mtk_mdp_frame *frame;
    634	struct v4l2_pix_format_mplane *pix_mp;
    635	int i;
    636
    637	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
    638
    639	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
    640	pix_mp = &f->fmt.pix_mp;
    641
    642	pix_mp->width = frame->width;
    643	pix_mp->height = frame->height;
    644	pix_mp->field = V4L2_FIELD_NONE;
    645	pix_mp->pixelformat = frame->fmt->pixelformat;
    646	pix_mp->num_planes = frame->fmt->num_planes;
    647	pix_mp->colorspace = ctx->colorspace;
    648	pix_mp->xfer_func = ctx->xfer_func;
    649	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
    650	pix_mp->quantization = ctx->quant;
    651	mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id,
    652		    pix_mp->width, pix_mp->height);
    653
    654	for (i = 0; i < pix_mp->num_planes; ++i) {
    655		pix_mp->plane_fmt[i].bytesperline = (frame->width *
    656			frame->fmt->row_depth[i]) / 8;
    657		pix_mp->plane_fmt[i].sizeimage = (frame->width *
    658			frame->height * frame->fmt->depth[i]) / 8;
    659
    660		mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i,
    661			    pix_mp->plane_fmt[i].bytesperline,
    662			    pix_mp->plane_fmt[i].sizeimage);
    663	}
    664
    665	return 0;
    666}
    667
    668static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
    669				      struct v4l2_format *f)
    670{
    671	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    672
    673	if (!mtk_mdp_try_fmt_mplane(ctx, f))
    674		return -EINVAL;
    675	return 0;
    676}
    677
    678static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
    679				    struct v4l2_format *f)
    680{
    681	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    682	struct vb2_queue *vq;
    683	struct mtk_mdp_frame *frame;
    684	struct v4l2_pix_format_mplane *pix_mp;
    685	const struct mtk_mdp_fmt *fmt;
    686	int i;
    687
    688	mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
    689
    690	frame = mtk_mdp_ctx_get_frame(ctx, f->type);
    691	fmt = mtk_mdp_try_fmt_mplane(ctx, f);
    692	if (!fmt) {
    693		mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
    694		return -EINVAL;
    695	}
    696	frame->fmt = fmt;
    697
    698	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
    699	if (vb2_is_streaming(vq)) {
    700		dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type);
    701		return -EBUSY;
    702	}
    703
    704	pix_mp = &f->fmt.pix_mp;
    705	for (i = 0; i < frame->fmt->num_planes; i++) {
    706		frame->payload[i] = pix_mp->plane_fmt[i].sizeimage;
    707		frame->pitch[i] = pix_mp->plane_fmt[i].bytesperline;
    708	}
    709
    710	mtk_mdp_set_frame_size(frame, pix_mp->width, pix_mp->height);
    711	if (V4L2_TYPE_IS_OUTPUT(f->type)) {
    712		ctx->colorspace = pix_mp->colorspace;
    713		ctx->xfer_func = pix_mp->xfer_func;
    714		ctx->ycbcr_enc = pix_mp->ycbcr_enc;
    715		ctx->quant = pix_mp->quantization;
    716	}
    717
    718	mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type,
    719		    frame->width, frame->height);
    720
    721	return 0;
    722}
    723
    724static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh,
    725			       struct v4l2_requestbuffers *reqbufs)
    726{
    727	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    728
    729	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
    730}
    731
    732static int mtk_mdp_m2m_streamon(struct file *file, void *fh,
    733				enum v4l2_buf_type type)
    734{
    735	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    736	int ret;
    737
    738	if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) {
    739		ret = mtk_mdp_vpu_init(&ctx->vpu);
    740		if (ret < 0) {
    741			dev_err(&ctx->mdp_dev->pdev->dev,
    742				"vpu init failed %d\n",
    743				ret);
    744			return -EINVAL;
    745		}
    746		mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_VPU_INIT);
    747	}
    748
    749	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
    750}
    751
    752static inline bool mtk_mdp_is_target_compose(u32 target)
    753{
    754	if (target == V4L2_SEL_TGT_COMPOSE_DEFAULT
    755	    || target == V4L2_SEL_TGT_COMPOSE_BOUNDS
    756	    || target == V4L2_SEL_TGT_COMPOSE)
    757		return true;
    758	return false;
    759}
    760
    761static inline bool mtk_mdp_is_target_crop(u32 target)
    762{
    763	if (target == V4L2_SEL_TGT_CROP_DEFAULT
    764	    || target == V4L2_SEL_TGT_CROP_BOUNDS
    765	    || target == V4L2_SEL_TGT_CROP)
    766		return true;
    767	return false;
    768}
    769
    770static int mtk_mdp_m2m_g_selection(struct file *file, void *fh,
    771				       struct v4l2_selection *s)
    772{
    773	struct mtk_mdp_frame *frame;
    774	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    775	bool valid = false;
    776
    777	if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
    778		if (mtk_mdp_is_target_compose(s->target))
    779			valid = true;
    780	} else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
    781		if (mtk_mdp_is_target_crop(s->target))
    782			valid = true;
    783	}
    784	if (!valid) {
    785		mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx->id, s->type,
    786			    s->target);
    787		return -EINVAL;
    788	}
    789
    790	frame = mtk_mdp_ctx_get_frame(ctx, s->type);
    791
    792	switch (s->target) {
    793	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
    794	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
    795	case V4L2_SEL_TGT_CROP_BOUNDS:
    796	case V4L2_SEL_TGT_CROP_DEFAULT:
    797		s->r.left = 0;
    798		s->r.top = 0;
    799		s->r.width = frame->width;
    800		s->r.height = frame->height;
    801		return 0;
    802
    803	case V4L2_SEL_TGT_COMPOSE:
    804	case V4L2_SEL_TGT_CROP:
    805		s->r.left = frame->crop.left;
    806		s->r.top = frame->crop.top;
    807		s->r.width = frame->crop.width;
    808		s->r.height = frame->crop.height;
    809		return 0;
    810	}
    811
    812	return -EINVAL;
    813}
    814
    815static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w,
    816				      int src_h, int dst_w, int dst_h, int rot)
    817{
    818	int tmp_w, tmp_h;
    819
    820	if (rot == 90 || rot == 270) {
    821		tmp_w = dst_h;
    822		tmp_h = dst_w;
    823	} else {
    824		tmp_w = dst_w;
    825		tmp_h = dst_h;
    826	}
    827
    828	if ((src_w / tmp_w) > var->h_scale_down_max ||
    829	    (src_h / tmp_h) > var->v_scale_down_max ||
    830	    (tmp_w / src_w) > var->h_scale_up_max ||
    831	    (tmp_h / src_h) > var->v_scale_up_max)
    832		return -EINVAL;
    833
    834	return 0;
    835}
    836
    837static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
    838				   struct v4l2_selection *s)
    839{
    840	struct mtk_mdp_frame *frame;
    841	struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
    842	struct v4l2_rect new_r;
    843	struct mtk_mdp_variant *variant = ctx->mdp_dev->variant;
    844	int ret;
    845	bool valid = false;
    846
    847	if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
    848		if (s->target == V4L2_SEL_TGT_COMPOSE)
    849			valid = true;
    850	} else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
    851		if (s->target == V4L2_SEL_TGT_CROP)
    852			valid = true;
    853	}
    854	if (!valid) {
    855		mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx->id, s->type,
    856			    s->target);
    857		return -EINVAL;
    858	}
    859
    860	new_r = s->r;
    861	ret = mtk_mdp_try_crop(ctx, s->type, &new_r);
    862	if (ret)
    863		return ret;
    864
    865	if (mtk_mdp_is_target_crop(s->target))
    866		frame = &ctx->s_frame;
    867	else
    868		frame = &ctx->d_frame;
    869
    870	/* Check to see if scaling ratio is within supported range */
    871	if (V4L2_TYPE_IS_OUTPUT(s->type))
    872		ret = mtk_mdp_check_scaler_ratio(variant, new_r.width,
    873			new_r.height, ctx->d_frame.crop.width,
    874			ctx->d_frame.crop.height,
    875			ctx->ctrls.rotate->val);
    876	else
    877		ret = mtk_mdp_check_scaler_ratio(variant,
    878			ctx->s_frame.crop.width,
    879			ctx->s_frame.crop.height, new_r.width,
    880			new_r.height, ctx->ctrls.rotate->val);
    881
    882	if (ret) {
    883		dev_info(&ctx->mdp_dev->pdev->dev,
    884			"Out of scaler range");
    885		return -EINVAL;
    886	}
    887
    888	s->r = new_r;
    889	frame->crop = new_r;
    890
    891	return 0;
    892}
    893
    894static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
    895	.vidioc_querycap		= mtk_mdp_m2m_querycap,
    896	.vidioc_enum_fmt_vid_cap	= mtk_mdp_m2m_enum_fmt_vid_cap,
    897	.vidioc_enum_fmt_vid_out	= mtk_mdp_m2m_enum_fmt_vid_out,
    898	.vidioc_g_fmt_vid_cap_mplane	= mtk_mdp_m2m_g_fmt_mplane,
    899	.vidioc_g_fmt_vid_out_mplane	= mtk_mdp_m2m_g_fmt_mplane,
    900	.vidioc_try_fmt_vid_cap_mplane	= mtk_mdp_m2m_try_fmt_mplane,
    901	.vidioc_try_fmt_vid_out_mplane	= mtk_mdp_m2m_try_fmt_mplane,
    902	.vidioc_s_fmt_vid_cap_mplane	= mtk_mdp_m2m_s_fmt_mplane,
    903	.vidioc_s_fmt_vid_out_mplane	= mtk_mdp_m2m_s_fmt_mplane,
    904	.vidioc_reqbufs			= mtk_mdp_m2m_reqbufs,
    905	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
    906	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
    907	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
    908	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
    909	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
    910	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
    911	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
    912	.vidioc_streamon		= mtk_mdp_m2m_streamon,
    913	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
    914	.vidioc_g_selection		= mtk_mdp_m2m_g_selection,
    915	.vidioc_s_selection		= mtk_mdp_m2m_s_selection
    916};
    917
    918static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
    919				  struct vb2_queue *dst_vq)
    920{
    921	struct mtk_mdp_ctx *ctx = priv;
    922	int ret;
    923
    924	memset(src_vq, 0, sizeof(*src_vq));
    925	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    926	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
    927	src_vq->drv_priv = ctx;
    928	src_vq->ops = &mtk_mdp_m2m_qops;
    929	src_vq->mem_ops = &vb2_dma_contig_memops;
    930	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
    931	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
    932	src_vq->dev = &ctx->mdp_dev->pdev->dev;
    933	src_vq->lock = &ctx->mdp_dev->lock;
    934
    935	ret = vb2_queue_init(src_vq);
    936	if (ret)
    937		return ret;
    938
    939	memset(dst_vq, 0, sizeof(*dst_vq));
    940	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    941	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
    942	dst_vq->drv_priv = ctx;
    943	dst_vq->ops = &mtk_mdp_m2m_qops;
    944	dst_vq->mem_ops = &vb2_dma_contig_memops;
    945	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
    946	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
    947	dst_vq->dev = &ctx->mdp_dev->pdev->dev;
    948	dst_vq->lock = &ctx->mdp_dev->lock;
    949
    950	return vb2_queue_init(dst_vq);
    951}
    952
    953static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl)
    954{
    955	struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl);
    956	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
    957	struct mtk_mdp_variant *variant = mdp->variant;
    958	int ret = 0;
    959
    960	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
    961		return 0;
    962
    963	switch (ctrl->id) {
    964	case V4L2_CID_HFLIP:
    965		ctx->hflip = ctrl->val;
    966		break;
    967	case V4L2_CID_VFLIP:
    968		ctx->vflip = ctrl->val;
    969		break;
    970	case V4L2_CID_ROTATE:
    971		ret = mtk_mdp_check_scaler_ratio(variant,
    972				ctx->s_frame.crop.width,
    973				ctx->s_frame.crop.height,
    974				ctx->d_frame.crop.width,
    975				ctx->d_frame.crop.height,
    976				ctx->ctrls.rotate->val);
    977
    978		if (ret)
    979			return -EINVAL;
    980
    981		ctx->rotation = ctrl->val;
    982		break;
    983	case V4L2_CID_ALPHA_COMPONENT:
    984		ctx->d_frame.alpha = ctrl->val;
    985		break;
    986	}
    987
    988	return 0;
    989}
    990
    991static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = {
    992	.s_ctrl = mtk_mdp_s_ctrl,
    993};
    994
    995static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx)
    996{
    997	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM);
    998
    999	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
   1000			&mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
   1001	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
   1002					     &mtk_mdp_ctrl_ops,
   1003					     V4L2_CID_HFLIP,
   1004					     0, 1, 1, 0);
   1005	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
   1006					     &mtk_mdp_ctrl_ops,
   1007					     V4L2_CID_VFLIP,
   1008					     0, 1, 1, 0);
   1009	ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
   1010						    &mtk_mdp_ctrl_ops,
   1011						    V4L2_CID_ALPHA_COMPONENT,
   1012						    0, 255, 1, 0);
   1013	ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
   1014
   1015	if (ctx->ctrl_handler.error) {
   1016		int err = ctx->ctrl_handler.error;
   1017
   1018		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
   1019		dev_err(&ctx->mdp_dev->pdev->dev,
   1020			"Failed to create control handlers\n");
   1021		return err;
   1022	}
   1023
   1024	return 0;
   1025}
   1026
   1027static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx)
   1028{
   1029	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
   1030	struct mtk_mdp_frame *frame;
   1031
   1032	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
   1033	frame->fmt = mtk_mdp_find_fmt_by_index(0,
   1034					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
   1035	frame->width = mdp->variant->pix_min->org_w;
   1036	frame->height = mdp->variant->pix_min->org_h;
   1037	frame->payload[0] = frame->width * frame->height;
   1038	frame->payload[1] = frame->payload[0] / 2;
   1039
   1040	frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
   1041	frame->fmt = mtk_mdp_find_fmt_by_index(0,
   1042					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
   1043	frame->width = mdp->variant->pix_min->target_rot_dis_w;
   1044	frame->height = mdp->variant->pix_min->target_rot_dis_h;
   1045	frame->payload[0] = frame->width * frame->height;
   1046	frame->payload[1] = frame->payload[0] / 2;
   1047
   1048}
   1049
   1050static int mtk_mdp_m2m_open(struct file *file)
   1051{
   1052	struct mtk_mdp_dev *mdp = video_drvdata(file);
   1053	struct video_device *vfd = video_devdata(file);
   1054	struct mtk_mdp_ctx *ctx = NULL;
   1055	int ret;
   1056	struct v4l2_format default_format;
   1057
   1058	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
   1059	if (!ctx)
   1060		return -ENOMEM;
   1061
   1062	if (mutex_lock_interruptible(&mdp->lock)) {
   1063		ret = -ERESTARTSYS;
   1064		goto err_lock;
   1065	}
   1066
   1067	mutex_init(&ctx->slock);
   1068	ctx->id = mdp->id_counter++;
   1069	v4l2_fh_init(&ctx->fh, vfd);
   1070	file->private_data = &ctx->fh;
   1071	ret = mtk_mdp_ctrls_create(ctx);
   1072	if (ret)
   1073		goto error_ctrls;
   1074
   1075	/* Use separate control handler per file handle */
   1076	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
   1077	v4l2_fh_add(&ctx->fh);
   1078	INIT_LIST_HEAD(&ctx->list);
   1079
   1080	ctx->mdp_dev = mdp;
   1081	mtk_mdp_set_default_params(ctx);
   1082
   1083	INIT_WORK(&ctx->work, mtk_mdp_m2m_worker);
   1084	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx,
   1085					 mtk_mdp_m2m_queue_init);
   1086	if (IS_ERR(ctx->m2m_ctx)) {
   1087		dev_err(&mdp->pdev->dev, "Failed to initialize m2m context");
   1088		ret = PTR_ERR(ctx->m2m_ctx);
   1089		goto error_m2m_ctx;
   1090	}
   1091	ctx->fh.m2m_ctx = ctx->m2m_ctx;
   1092	if (mdp->ctx_num++ == 0) {
   1093		ret = vpu_load_firmware(mdp->vpu_dev);
   1094		if (ret < 0) {
   1095			dev_err(&mdp->pdev->dev,
   1096				"vpu_load_firmware failed %d\n", ret);
   1097			goto err_load_vpu;
   1098		}
   1099
   1100		ret = mtk_mdp_vpu_register(mdp->pdev);
   1101		if (ret < 0) {
   1102			dev_err(&mdp->pdev->dev,
   1103				"mdp_vpu register failed %d\n", ret);
   1104			goto err_load_vpu;
   1105		}
   1106	}
   1107
   1108	list_add(&ctx->list, &mdp->ctx_list);
   1109	mutex_unlock(&mdp->lock);
   1110
   1111	/* Default format */
   1112	memset(&default_format, 0, sizeof(default_format));
   1113	default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
   1114	default_format.fmt.pix_mp.width = 32;
   1115	default_format.fmt.pix_mp.height = 32;
   1116	default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
   1117	mtk_mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
   1118	default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
   1119	mtk_mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
   1120
   1121	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
   1122
   1123	return 0;
   1124
   1125err_load_vpu:
   1126	mdp->ctx_num--;
   1127	v4l2_m2m_ctx_release(ctx->m2m_ctx);
   1128error_m2m_ctx:
   1129	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
   1130error_ctrls:
   1131	v4l2_fh_del(&ctx->fh);
   1132	v4l2_fh_exit(&ctx->fh);
   1133	mutex_unlock(&mdp->lock);
   1134err_lock:
   1135	kfree(ctx);
   1136
   1137	return ret;
   1138}
   1139
   1140static int mtk_mdp_m2m_release(struct file *file)
   1141{
   1142	struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
   1143	struct mtk_mdp_dev *mdp = ctx->mdp_dev;
   1144
   1145	flush_workqueue(mdp->job_wq);
   1146	mutex_lock(&mdp->lock);
   1147	v4l2_m2m_ctx_release(ctx->m2m_ctx);
   1148	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
   1149	v4l2_fh_del(&ctx->fh);
   1150	v4l2_fh_exit(&ctx->fh);
   1151	mtk_mdp_vpu_deinit(&ctx->vpu);
   1152	mdp->ctx_num--;
   1153	list_del_init(&ctx->list);
   1154
   1155	mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
   1156
   1157	mutex_unlock(&mdp->lock);
   1158	kfree(ctx);
   1159
   1160	return 0;
   1161}
   1162
   1163static const struct v4l2_file_operations mtk_mdp_m2m_fops = {
   1164	.owner		= THIS_MODULE,
   1165	.open		= mtk_mdp_m2m_open,
   1166	.release	= mtk_mdp_m2m_release,
   1167	.poll		= v4l2_m2m_fop_poll,
   1168	.unlocked_ioctl	= video_ioctl2,
   1169	.mmap		= v4l2_m2m_fop_mmap,
   1170};
   1171
   1172static const struct v4l2_m2m_ops mtk_mdp_m2m_ops = {
   1173	.device_run	= mtk_mdp_m2m_device_run,
   1174};
   1175
   1176int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
   1177{
   1178	struct device *dev = &mdp->pdev->dev;
   1179	int ret;
   1180
   1181	mdp->variant = &mtk_mdp_default_variant;
   1182	mdp->vdev = video_device_alloc();
   1183	if (!mdp->vdev) {
   1184		dev_err(dev, "failed to allocate video device\n");
   1185		ret = -ENOMEM;
   1186		goto err_video_alloc;
   1187	}
   1188	mdp->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
   1189	mdp->vdev->fops = &mtk_mdp_m2m_fops;
   1190	mdp->vdev->ioctl_ops = &mtk_mdp_m2m_ioctl_ops;
   1191	mdp->vdev->release = video_device_release;
   1192	mdp->vdev->lock = &mdp->lock;
   1193	mdp->vdev->vfl_dir = VFL_DIR_M2M;
   1194	mdp->vdev->v4l2_dev = &mdp->v4l2_dev;
   1195	snprintf(mdp->vdev->name, sizeof(mdp->vdev->name), "%s:m2m",
   1196		 MTK_MDP_MODULE_NAME);
   1197	video_set_drvdata(mdp->vdev, mdp);
   1198
   1199	mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
   1200	if (IS_ERR(mdp->m2m_dev)) {
   1201		dev_err(dev, "failed to initialize v4l2-m2m device\n");
   1202		ret = PTR_ERR(mdp->m2m_dev);
   1203		goto err_m2m_init;
   1204	}
   1205
   1206	ret = video_register_device(mdp->vdev, VFL_TYPE_VIDEO, 2);
   1207	if (ret) {
   1208		dev_err(dev, "failed to register video device\n");
   1209		goto err_vdev_register;
   1210	}
   1211
   1212	v4l2_info(&mdp->v4l2_dev, "driver registered as /dev/video%d",
   1213		  mdp->vdev->num);
   1214	return 0;
   1215
   1216err_vdev_register:
   1217	v4l2_m2m_release(mdp->m2m_dev);
   1218err_m2m_init:
   1219	video_device_release(mdp->vdev);
   1220err_video_alloc:
   1221
   1222	return ret;
   1223}
   1224
   1225void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
   1226{
   1227	video_unregister_device(mdp->vdev);
   1228	v4l2_m2m_release(mdp->m2m_dev);
   1229}