brintos

brintos / linux-shallow public Read only

0
0
Text · 19.9 KiB · 0e69128 Raw
742 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2022 MediaTek Inc.4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>5 */6 7#include <linux/platform_device.h>8#include <media/v4l2-ioctl.h>9#include <media/v4l2-event.h>10#include <media/videobuf2-dma-contig.h>11#include "mtk-mdp3-m2m.h"12 13static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh)14{15	return container_of(fh, struct mdp_m2m_ctx, fh);16}17 18static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)19{20	return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler);21}22 23static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx,24					      enum v4l2_buf_type type)25{26	if (V4L2_TYPE_IS_OUTPUT(type))27		return &ctx->curr_param.output;28	else29		return &ctx->curr_param.captures[0];30}31 32static inline void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state)33{34	atomic_or(state, &ctx->curr_param.state);35}36 37static inline bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask)38{39	return ((atomic_read(&ctx->curr_param.state) & mask) == mask);40}41 42static void mdp_m2m_process_done(void *priv, int vb_state)43{44	struct mdp_m2m_ctx *ctx = priv;45	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;46 47	src_vbuf = (struct vb2_v4l2_buffer *)48			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);49	dst_vbuf = (struct vb2_v4l2_buffer *)50			v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);51	ctx->curr_param.frame_no = ctx->frame_count[MDP_M2M_SRC];52	src_vbuf->sequence = ctx->frame_count[MDP_M2M_SRC]++;53	dst_vbuf->sequence = ctx->frame_count[MDP_M2M_DST]++;54	v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true);55 56	v4l2_m2m_buf_done(src_vbuf, vb_state);57	v4l2_m2m_buf_done(dst_vbuf, vb_state);58	v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);59}60 61static void mdp_m2m_device_run(void *priv)62{63	struct mdp_m2m_ctx *ctx = priv;64	struct mdp_frame *frame;65	struct vb2_v4l2_buffer *src_vb, *dst_vb;66	struct img_ipi_frameparam param = {};67	struct mdp_cmdq_param task = {};68	enum vb2_buffer_state vb_state = VB2_BUF_STATE_ERROR;69	int ret;70 71	if (mdp_m2m_ctx_is_state_set(ctx, MDP_M2M_CTX_ERROR)) {72		dev_err(&ctx->mdp_dev->pdev->dev,73			"mdp_m2m_ctx is in error state\n");74		goto worker_end;75	}76 77	param.frame_no = ctx->curr_param.frame_no;78	param.type = ctx->curr_param.type;79	param.num_inputs = 1;80	param.num_outputs = 1;81 82	frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);83	src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);84	mdp_set_src_config(&param.inputs[0], frame, &src_vb->vb2_buf);85 86	frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);87	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);88	mdp_set_dst_config(&param.outputs[0], frame, &dst_vb->vb2_buf);89 90	if (mdp_check_pp_enable(ctx->mdp_dev, frame))91		param.type = MDP_STREAM_TYPE_DUAL_BITBLT;92 93	ret = mdp_vpu_process(&ctx->mdp_dev->vpu, &param);94	if (ret) {95		dev_err(&ctx->mdp_dev->pdev->dev,96			"VPU MDP process failed: %d\n", ret);97		goto worker_end;98	}99 100	task.config = ctx->mdp_dev->vpu.config;101	task.param = &param;102	task.composes[0] = &frame->compose;103	task.cmdq_cb = NULL;104	task.cb_data = NULL;105	task.mdp_ctx = ctx;106 107	if (refcount_read(&ctx->mdp_dev->job_count)) {108		ret = wait_event_timeout(ctx->mdp_dev->callback_wq,109					 !refcount_read(&ctx->mdp_dev->job_count),110					 2 * HZ);111		if (ret == 0) {112			dev_err(&ctx->mdp_dev->pdev->dev,113				"%d jobs not yet done\n",114				refcount_read(&ctx->mdp_dev->job_count));115			goto worker_end;116		}117	}118 119	ret = mdp_cmdq_send(ctx->mdp_dev, &task);120	if (ret) {121		dev_err(&ctx->mdp_dev->pdev->dev,122			"CMDQ sendtask failed: %d\n", ret);123		goto worker_end;124	}125 126	return;127 128worker_end:129	mdp_m2m_process_done(ctx, vb_state);130}131 132static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)133{134	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);135	struct mdp_frame *capture;136	struct vb2_queue *vq;137	int ret;138	bool out_streaming, cap_streaming;139 140	if (V4L2_TYPE_IS_OUTPUT(q->type))141		ctx->frame_count[MDP_M2M_SRC] = 0;142 143	if (V4L2_TYPE_IS_CAPTURE(q->type))144		ctx->frame_count[MDP_M2M_DST] = 0;145 146	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);147	vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);148	out_streaming = vb2_is_streaming(vq);149	vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);150	cap_streaming = vb2_is_streaming(vq);151 152	/* Check to see if scaling ratio is within supported range */153	if ((V4L2_TYPE_IS_OUTPUT(q->type) && cap_streaming) ||154	    (V4L2_TYPE_IS_CAPTURE(q->type) && out_streaming)) {155		ret = mdp_check_scaling_ratio(&capture->crop.c,156					      &capture->compose,157					      capture->rotation,158					      ctx->curr_param.limit);159		if (ret) {160			dev_err(&ctx->mdp_dev->pdev->dev,161				"Out of scaling range\n");162			return ret;163		}164	}165 166	if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {167		ret = mdp_vpu_get_locked(ctx->mdp_dev);168		if (ret) {169			dev_err(&ctx->mdp_dev->pdev->dev,170				"VPU init failed %d\n", ret);171			return -EINVAL;172		}173		mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT);174	}175 176	return 0;177}178 179static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx,180						  unsigned int type)181{182	if (V4L2_TYPE_IS_OUTPUT(type))183		return (struct vb2_v4l2_buffer *)184			v4l2_m2m_src_buf_remove(ctx->m2m_ctx);185	else186		return (struct vb2_v4l2_buffer *)187			v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);188}189 190static void mdp_m2m_stop_streaming(struct vb2_queue *q)191{192	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);193	struct vb2_v4l2_buffer *vb;194 195	vb = mdp_m2m_buf_remove(ctx, q->type);196	while (vb) {197		v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);198		vb = mdp_m2m_buf_remove(ctx, q->type);199	}200}201 202static int mdp_m2m_queue_setup(struct vb2_queue *q,203			       unsigned int *num_buffers,204			       unsigned int *num_planes, unsigned int sizes[],205			       struct device *alloc_devs[])206{207	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);208	struct v4l2_pix_format_mplane *pix_mp;209	u32 i;210 211	pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp;212 213	/* from VIDIOC_CREATE_BUFS */214	if (*num_planes) {215		if (*num_planes != pix_mp->num_planes)216			return -EINVAL;217		for (i = 0; i < pix_mp->num_planes; ++i)218			if (sizes[i] < pix_mp->plane_fmt[i].sizeimage)219				return -EINVAL;220	} else {/* from VIDIOC_REQBUFS */221		*num_planes = pix_mp->num_planes;222		for (i = 0; i < pix_mp->num_planes; ++i)223			sizes[i] = pix_mp->plane_fmt[i].sizeimage;224	}225 226	return 0;227}228 229static int mdp_m2m_buf_prepare(struct vb2_buffer *vb)230{231	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);232	struct v4l2_pix_format_mplane *pix_mp;233	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);234	u32 i;235 236	v4l2_buf->field = V4L2_FIELD_NONE;237 238	if (V4L2_TYPE_IS_CAPTURE(vb->type)) {239		pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp;240		for (i = 0; i < pix_mp->num_planes; ++i) {241			vb2_set_plane_payload(vb, i,242					      pix_mp->plane_fmt[i].sizeimage);243		}244	}245	return 0;246}247 248static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb)249{250	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);251 252	v4l2_buf->field = V4L2_FIELD_NONE;253 254	return 0;255}256 257static void mdp_m2m_buf_queue(struct vb2_buffer *vb)258{259	struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);260	struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);261 262	v4l2_buf->field = V4L2_FIELD_NONE;263 264	v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));265}266 267static const struct vb2_ops mdp_m2m_qops = {268	.queue_setup	= mdp_m2m_queue_setup,269	.wait_prepare	= vb2_ops_wait_prepare,270	.wait_finish	= vb2_ops_wait_finish,271	.buf_prepare	= mdp_m2m_buf_prepare,272	.start_streaming = mdp_m2m_start_streaming,273	.stop_streaming	= mdp_m2m_stop_streaming,274	.buf_queue	= mdp_m2m_buf_queue,275	.buf_out_validate = mdp_m2m_buf_out_validate,276};277 278static int mdp_m2m_querycap(struct file *file, void *fh,279			    struct v4l2_capability *cap)280{281	strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));282	strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card));283 284	return 0;285}286 287static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,288				   struct v4l2_fmtdesc *f)289{290	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);291 292	return mdp_enum_fmt_mplane(ctx->mdp_dev, f);293}294 295static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,296				struct v4l2_format *f)297{298	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);299	struct mdp_frame *frame;300	struct v4l2_pix_format_mplane *pix_mp;301 302	frame = ctx_get_frame(ctx, f->type);303	*f = frame->format;304	pix_mp = &f->fmt.pix_mp;305	pix_mp->colorspace = ctx->curr_param.colorspace;306	pix_mp->xfer_func = ctx->curr_param.xfer_func;307	pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc;308	pix_mp->quantization = ctx->curr_param.quant;309 310	return 0;311}312 313static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,314				struct v4l2_format *f)315{316	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);317	struct mdp_frame *frame = ctx_get_frame(ctx, f->type);318	struct mdp_frame *capture;319	const struct mdp_format *fmt;320	struct vb2_queue *vq;321 322	fmt = mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id);323	if (!fmt)324		return -EINVAL;325 326	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);327	if (vb2_is_busy(vq))328		return -EBUSY;329 330	frame->format = *f;331	frame->mdp_fmt = fmt;332	frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color);333	frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ?334		MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP;335 336	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);337	if (V4L2_TYPE_IS_OUTPUT(f->type)) {338		capture->crop.c.left = 0;339		capture->crop.c.top = 0;340		capture->crop.c.width = f->fmt.pix_mp.width;341		capture->crop.c.height = f->fmt.pix_mp.height;342		ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace;343		ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;344		ctx->curr_param.quant = f->fmt.pix_mp.quantization;345		ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func;346	} else {347		capture->compose.left = 0;348		capture->compose.top = 0;349		capture->compose.width = f->fmt.pix_mp.width;350		capture->compose.height = f->fmt.pix_mp.height;351	}352 353	return 0;354}355 356static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,357				  struct v4l2_format *f)358{359	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);360 361	if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id))362		return -EINVAL;363 364	return 0;365}366 367static int mdp_m2m_g_selection(struct file *file, void *fh,368			       struct v4l2_selection *s)369{370	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);371	struct mdp_frame *frame;372	bool valid = false;373 374	if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)375		valid = mdp_target_is_crop(s->target);376	else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)377		valid = mdp_target_is_compose(s->target);378 379	if (!valid)380		return -EINVAL;381 382	switch (s->target) {383	case V4L2_SEL_TGT_CROP:384		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)385			return -EINVAL;386		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);387		s->r = frame->crop.c;388		return 0;389	case V4L2_SEL_TGT_COMPOSE:390		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)391			return -EINVAL;392		frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);393		s->r = frame->compose;394		return 0;395	case V4L2_SEL_TGT_CROP_DEFAULT:396	case V4L2_SEL_TGT_CROP_BOUNDS:397		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)398			return -EINVAL;399		frame = ctx_get_frame(ctx, s->type);400		s->r.left = 0;401		s->r.top = 0;402		s->r.width = frame->format.fmt.pix_mp.width;403		s->r.height = frame->format.fmt.pix_mp.height;404		return 0;405	case V4L2_SEL_TGT_COMPOSE_DEFAULT:406	case V4L2_SEL_TGT_COMPOSE_BOUNDS:407		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)408			return -EINVAL;409		frame = ctx_get_frame(ctx, s->type);410		s->r.left = 0;411		s->r.top = 0;412		s->r.width = frame->format.fmt.pix_mp.width;413		s->r.height = frame->format.fmt.pix_mp.height;414		return 0;415	}416	return -EINVAL;417}418 419static int mdp_m2m_s_selection(struct file *file, void *fh,420			       struct v4l2_selection *s)421{422	struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);423	struct mdp_frame *frame = ctx_get_frame(ctx, s->type);424	struct mdp_frame *capture;425	struct v4l2_rect r;426	struct device *dev = &ctx->mdp_dev->pdev->dev;427	bool valid = false;428	int ret;429 430	if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)431		valid = (s->target == V4L2_SEL_TGT_CROP);432	else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)433		valid = (s->target == V4L2_SEL_TGT_COMPOSE);434 435	if (!valid) {436		dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__,437			ctx->id, s->type, s->target);438		return -EINVAL;439	}440 441	ret = mdp_try_crop(ctx, &r, s, frame);442	if (ret)443		return ret;444	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);445 446	if (mdp_target_is_crop(s->target))447		capture->crop.c = r;448	else449		capture->compose = r;450 451	s->r = r;452 453	return 0;454}455 456static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = {457	.vidioc_querycap		= mdp_m2m_querycap,458	.vidioc_enum_fmt_vid_cap	= mdp_m2m_enum_fmt_mplane,459	.vidioc_enum_fmt_vid_out	= mdp_m2m_enum_fmt_mplane,460	.vidioc_g_fmt_vid_cap_mplane	= mdp_m2m_g_fmt_mplane,461	.vidioc_g_fmt_vid_out_mplane	= mdp_m2m_g_fmt_mplane,462	.vidioc_s_fmt_vid_cap_mplane	= mdp_m2m_s_fmt_mplane,463	.vidioc_s_fmt_vid_out_mplane	= mdp_m2m_s_fmt_mplane,464	.vidioc_try_fmt_vid_cap_mplane	= mdp_m2m_try_fmt_mplane,465	.vidioc_try_fmt_vid_out_mplane	= mdp_m2m_try_fmt_mplane,466	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,467	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,468	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,469	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,470	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,471	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,472	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,473	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,474	.vidioc_g_selection		= mdp_m2m_g_selection,475	.vidioc_s_selection		= mdp_m2m_s_selection,476	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,477	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,478};479 480static int mdp_m2m_queue_init(void *priv,481			      struct vb2_queue *src_vq,482			      struct vb2_queue *dst_vq)483{484	struct mdp_m2m_ctx *ctx = priv;485	int ret;486 487	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;488	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;489	src_vq->ops = &mdp_m2m_qops;490	src_vq->mem_ops = &vb2_dma_contig_memops;491	src_vq->drv_priv = ctx;492	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);493	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;494	src_vq->dev = &ctx->mdp_dev->pdev->dev;495	src_vq->lock = &ctx->ctx_lock;496 497	ret = vb2_queue_init(src_vq);498	if (ret)499		return ret;500 501	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;502	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;503	dst_vq->ops = &mdp_m2m_qops;504	dst_vq->mem_ops = &vb2_dma_contig_memops;505	dst_vq->drv_priv = ctx;506	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);507	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;508	dst_vq->dev = &ctx->mdp_dev->pdev->dev;509	dst_vq->lock = &ctx->ctx_lock;510 511	return vb2_queue_init(dst_vq);512}513 514static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)515{516	struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);517	struct mdp_frame *capture;518 519	capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);520	switch (ctrl->id) {521	case V4L2_CID_HFLIP:522		capture->hflip = ctrl->val;523		break;524	case V4L2_CID_VFLIP:525		capture->vflip = ctrl->val;526		break;527	case V4L2_CID_ROTATE:528		capture->rotation = ctrl->val;529		break;530	}531 532	return 0;533}534 535static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {536	.s_ctrl	= mdp_m2m_s_ctrl,537};538 539static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)540{541	v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS);542	ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,543					     &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP,544					     0, 1, 1, 0);545	ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,546					     &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,547					     0, 1, 1, 0);548	ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,549					      &mdp_m2m_ctrl_ops,550					      V4L2_CID_ROTATE, 0, 270, 90, 0);551 552	if (ctx->ctrl_handler.error) {553		int err = ctx->ctrl_handler.error;554 555		v4l2_ctrl_handler_free(&ctx->ctrl_handler);556		dev_err(&ctx->mdp_dev->pdev->dev,557			"Failed to register controls\n");558		return err;559	}560	return 0;561}562 563static int mdp_m2m_open(struct file *file)564{565	struct video_device *vdev = video_devdata(file);566	struct mdp_dev *mdp = video_get_drvdata(vdev);567	struct mdp_m2m_ctx *ctx;568	struct device *dev = &mdp->pdev->dev;569	int ret;570	struct v4l2_format default_format = {};571	const struct mdp_limit *limit = mdp->mdp_data->def_limit;572 573	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);574	if (!ctx)575		return -ENOMEM;576 577	if (mutex_lock_interruptible(&mdp->m2m_lock)) {578		ret = -ERESTARTSYS;579		goto err_free_ctx;580	}581 582	ret = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);583	if (ret < 0)584		goto err_unlock_mutex;585	ctx->id = ret;586 587	ctx->mdp_dev = mdp;588 589	v4l2_fh_init(&ctx->fh, vdev);590	file->private_data = &ctx->fh;591	ret = mdp_m2m_ctrls_create(ctx);592	if (ret)593		goto err_exit_fh;594 595	/* Use separate control handler per file handle */596	ctx->fh.ctrl_handler = &ctx->ctrl_handler;597	v4l2_fh_add(&ctx->fh);598 599	mutex_init(&ctx->ctx_lock);600	ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init);601	if (IS_ERR(ctx->m2m_ctx)) {602		dev_err(dev, "Failed to initialize m2m context\n");603		ret = PTR_ERR(ctx->m2m_ctx);604		goto err_release_handler;605	}606	ctx->fh.m2m_ctx = ctx->m2m_ctx;607 608	ctx->curr_param.ctx = ctx;609	ret = mdp_frameparam_init(mdp, &ctx->curr_param);610	if (ret) {611		dev_err(dev, "Failed to initialize mdp parameter\n");612		goto err_release_m2m_ctx;613	}614 615	mutex_unlock(&mdp->m2m_lock);616 617	/* Default format */618	default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;619	default_format.fmt.pix_mp.width = limit->out_limit.wmin;620	default_format.fmt.pix_mp.height = limit->out_limit.hmin;621	default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;622	mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);623	default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;624	mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);625 626	dev_dbg(dev, "%s:[%d]", __func__, ctx->id);627 628	return 0;629 630err_release_m2m_ctx:631	v4l2_m2m_ctx_release(ctx->m2m_ctx);632err_release_handler:633	v4l2_ctrl_handler_free(&ctx->ctrl_handler);634	v4l2_fh_del(&ctx->fh);635err_exit_fh:636	v4l2_fh_exit(&ctx->fh);637	ida_free(&mdp->mdp_ida, ctx->id);638err_unlock_mutex:639	mutex_unlock(&mdp->m2m_lock);640err_free_ctx:641	kfree(ctx);642 643	return ret;644}645 646static int mdp_m2m_release(struct file *file)647{648	struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data);649	struct mdp_dev *mdp = video_drvdata(file);650	struct device *dev = &mdp->pdev->dev;651 652	mutex_lock(&mdp->m2m_lock);653	v4l2_m2m_ctx_release(ctx->m2m_ctx);654	if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT))655		mdp_vpu_put_locked(mdp);656 657	v4l2_ctrl_handler_free(&ctx->ctrl_handler);658	v4l2_fh_del(&ctx->fh);659	v4l2_fh_exit(&ctx->fh);660	ida_free(&mdp->mdp_ida, ctx->id);661	mutex_unlock(&mdp->m2m_lock);662 663	dev_dbg(dev, "%s:[%d]", __func__, ctx->id);664	kfree(ctx);665 666	return 0;667}668 669static const struct v4l2_file_operations mdp_m2m_fops = {670	.owner		= THIS_MODULE,671	.poll		= v4l2_m2m_fop_poll,672	.unlocked_ioctl	= video_ioctl2,673	.mmap		= v4l2_m2m_fop_mmap,674	.open		= mdp_m2m_open,675	.release	= mdp_m2m_release,676};677 678static const struct v4l2_m2m_ops mdp_m2m_ops = {679	.device_run	= mdp_m2m_device_run,680};681 682int mdp_m2m_device_register(struct mdp_dev *mdp)683{684	struct device *dev = &mdp->pdev->dev;685	int ret = 0;686 687	mdp->m2m_vdev = video_device_alloc();688	if (!mdp->m2m_vdev) {689		dev_err(dev, "Failed to allocate video device\n");690		ret = -ENOMEM;691		goto err_video_alloc;692	}693	mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |694		V4L2_CAP_STREAMING;695	mdp->m2m_vdev->fops = &mdp_m2m_fops;696	mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops;697	mdp->m2m_vdev->release = mdp_video_device_release;698	mdp->m2m_vdev->lock = &mdp->m2m_lock;699	mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M;700	mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev;701	snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m",702		 MDP_MODULE_NAME);703	video_set_drvdata(mdp->m2m_vdev, mdp);704 705	mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops);706	if (IS_ERR(mdp->m2m_dev)) {707		dev_err(dev, "Failed to initialize v4l2-m2m device\n");708		ret = PTR_ERR(mdp->m2m_dev);709		goto err_m2m_init;710	}711 712	ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1);713	if (ret) {714		dev_err(dev, "Failed to register video device\n");715		goto err_video_register;716	}717 718	v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",719		  mdp->m2m_vdev->num);720	return 0;721 722err_video_register:723	v4l2_m2m_release(mdp->m2m_dev);724err_m2m_init:725	video_device_release(mdp->m2m_vdev);726err_video_alloc:727 728	return ret;729}730 731void mdp_m2m_device_unregister(struct mdp_dev *mdp)732{733	video_unregister_device(mdp->m2m_vdev);734}735 736void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)737{738	enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;739 740	mdp_m2m_process_done(ctx, vb_state);741}742