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

fimc-m2m.c (19432B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
      4 *
      5 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
      6 * Sylwester Nawrocki <s.nawrocki@samsung.com>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/kernel.h>
     11#include <linux/types.h>
     12#include <linux/errno.h>
     13#include <linux/bug.h>
     14#include <linux/interrupt.h>
     15#include <linux/device.h>
     16#include <linux/platform_device.h>
     17#include <linux/pm_runtime.h>
     18#include <linux/list.h>
     19#include <linux/io.h>
     20#include <linux/slab.h>
     21#include <linux/clk.h>
     22#include <media/v4l2-ioctl.h>
     23#include <media/videobuf2-v4l2.h>
     24#include <media/videobuf2-dma-contig.h>
     25
     26#include "common.h"
     27#include "fimc-core.h"
     28#include "fimc-reg.h"
     29#include "media-dev.h"
     30
     31static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
     32{
     33	if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
     34		return FMT_FLAGS_M2M_IN;
     35	else
     36		return FMT_FLAGS_M2M_OUT;
     37}
     38
     39void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
     40{
     41	struct vb2_v4l2_buffer *src_vb, *dst_vb;
     42
     43	if (!ctx || !ctx->fh.m2m_ctx)
     44		return;
     45
     46	src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
     47	dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
     48
     49	if (src_vb)
     50		v4l2_m2m_buf_done(src_vb, vb_state);
     51	if (dst_vb)
     52		v4l2_m2m_buf_done(dst_vb, vb_state);
     53	if (src_vb && dst_vb)
     54		v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
     55				    ctx->fh.m2m_ctx);
     56}
     57
     58/* Complete the transaction which has been scheduled for execution. */
     59static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
     60{
     61	struct fimc_dev *fimc = ctx->fimc_dev;
     62
     63	if (!fimc_m2m_pending(fimc))
     64		return;
     65
     66	fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
     67
     68	wait_event_timeout(fimc->irq_queue,
     69			!fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
     70			FIMC_SHUTDOWN_TIMEOUT);
     71}
     72
     73static int start_streaming(struct vb2_queue *q, unsigned int count)
     74{
     75	struct fimc_ctx *ctx = q->drv_priv;
     76
     77	return pm_runtime_resume_and_get(&ctx->fimc_dev->pdev->dev);
     78}
     79
     80static void stop_streaming(struct vb2_queue *q)
     81{
     82	struct fimc_ctx *ctx = q->drv_priv;
     83
     84	fimc_m2m_shutdown(ctx);
     85	fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
     86	pm_runtime_put(&ctx->fimc_dev->pdev->dev);
     87}
     88
     89static void fimc_device_run(void *priv)
     90{
     91	struct vb2_v4l2_buffer *src_vb, *dst_vb;
     92	struct fimc_ctx *ctx = priv;
     93	struct fimc_frame *sf, *df;
     94	struct fimc_dev *fimc;
     95	unsigned long flags;
     96	int ret;
     97
     98	if (WARN(!ctx, "Null context\n"))
     99		return;
    100
    101	fimc = ctx->fimc_dev;
    102	spin_lock_irqsave(&fimc->slock, flags);
    103
    104	set_bit(ST_M2M_PEND, &fimc->state);
    105	sf = &ctx->s_frame;
    106	df = &ctx->d_frame;
    107
    108	if (ctx->state & FIMC_PARAMS) {
    109		/* Prepare the DMA offsets for scaler */
    110		fimc_prepare_dma_offset(ctx, sf);
    111		fimc_prepare_dma_offset(ctx, df);
    112	}
    113
    114	src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
    115	ret = fimc_prepare_addr(ctx, &src_vb->vb2_buf, sf, &sf->addr);
    116	if (ret)
    117		goto dma_unlock;
    118
    119	dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
    120	ret = fimc_prepare_addr(ctx, &dst_vb->vb2_buf, df, &df->addr);
    121	if (ret)
    122		goto dma_unlock;
    123
    124	dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
    125	dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
    126	dst_vb->flags |=
    127		src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
    128
    129	/* Reconfigure hardware if the context has changed. */
    130	if (fimc->m2m.ctx != ctx) {
    131		ctx->state |= FIMC_PARAMS;
    132		fimc->m2m.ctx = ctx;
    133	}
    134
    135	if (ctx->state & FIMC_PARAMS) {
    136		fimc_set_yuv_order(ctx);
    137		fimc_hw_set_input_path(ctx);
    138		fimc_hw_set_in_dma(ctx);
    139		ret = fimc_set_scaler_info(ctx);
    140		if (ret)
    141			goto dma_unlock;
    142		fimc_hw_set_prescaler(ctx);
    143		fimc_hw_set_mainscaler(ctx);
    144		fimc_hw_set_target_format(ctx);
    145		fimc_hw_set_rotation(ctx);
    146		fimc_hw_set_effect(ctx);
    147		fimc_hw_set_out_dma(ctx);
    148		if (fimc->drv_data->alpha_color)
    149			fimc_hw_set_rgb_alpha(ctx);
    150		fimc_hw_set_output_path(ctx);
    151	}
    152	fimc_hw_set_input_addr(fimc, &sf->addr);
    153	fimc_hw_set_output_addr(fimc, &df->addr, -1);
    154
    155	fimc_activate_capture(ctx);
    156	ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
    157	fimc_hw_activate_input_dma(fimc, true);
    158
    159dma_unlock:
    160	spin_unlock_irqrestore(&fimc->slock, flags);
    161}
    162
    163static void fimc_job_abort(void *priv)
    164{
    165	fimc_m2m_shutdown(priv);
    166}
    167
    168static int fimc_queue_setup(struct vb2_queue *vq,
    169			    unsigned int *num_buffers, unsigned int *num_planes,
    170			    unsigned int sizes[], struct device *alloc_devs[])
    171{
    172	struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
    173	struct fimc_frame *f;
    174	int i;
    175
    176	f = ctx_get_frame(ctx, vq->type);
    177	if (IS_ERR(f))
    178		return PTR_ERR(f);
    179	/*
    180	 * Return number of non-contiguous planes (plane buffers)
    181	 * depending on the configured color format.
    182	 */
    183	if (!f->fmt)
    184		return -EINVAL;
    185
    186	*num_planes = f->fmt->memplanes;
    187	for (i = 0; i < f->fmt->memplanes; i++)
    188		sizes[i] = f->payload[i];
    189	return 0;
    190}
    191
    192static int fimc_buf_prepare(struct vb2_buffer *vb)
    193{
    194	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
    195	struct fimc_frame *frame;
    196	int i;
    197
    198	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
    199	if (IS_ERR(frame))
    200		return PTR_ERR(frame);
    201
    202	for (i = 0; i < frame->fmt->memplanes; i++)
    203		vb2_set_plane_payload(vb, i, frame->payload[i]);
    204
    205	return 0;
    206}
    207
    208static void fimc_buf_queue(struct vb2_buffer *vb)
    209{
    210	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
    211	struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
    212	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
    213}
    214
    215static const struct vb2_ops fimc_qops = {
    216	.queue_setup	 = fimc_queue_setup,
    217	.buf_prepare	 = fimc_buf_prepare,
    218	.buf_queue	 = fimc_buf_queue,
    219	.wait_prepare	 = vb2_ops_wait_prepare,
    220	.wait_finish	 = vb2_ops_wait_finish,
    221	.stop_streaming	 = stop_streaming,
    222	.start_streaming = start_streaming,
    223};
    224
    225/*
    226 * V4L2 ioctl handlers
    227 */
    228static int fimc_m2m_querycap(struct file *file, void *fh,
    229				     struct v4l2_capability *cap)
    230{
    231	struct fimc_dev *fimc = video_drvdata(file);
    232
    233	__fimc_vidioc_querycap(&fimc->pdev->dev, cap);
    234	return 0;
    235}
    236
    237static int fimc_m2m_enum_fmt(struct file *file, void *priv,
    238			     struct v4l2_fmtdesc *f)
    239{
    240	struct fimc_fmt *fmt;
    241
    242	fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
    243			       f->index);
    244	if (!fmt)
    245		return -EINVAL;
    246
    247	f->pixelformat = fmt->fourcc;
    248	return 0;
    249}
    250
    251static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
    252				 struct v4l2_format *f)
    253{
    254	struct fimc_ctx *ctx = fh_to_ctx(fh);
    255	struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
    256
    257	if (IS_ERR(frame))
    258		return PTR_ERR(frame);
    259
    260	__fimc_get_format(frame, f);
    261	return 0;
    262}
    263
    264static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
    265{
    266	struct fimc_dev *fimc = ctx->fimc_dev;
    267	const struct fimc_variant *variant = fimc->variant;
    268	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
    269	struct fimc_fmt *fmt;
    270	u32 max_w, mod_x, mod_y;
    271
    272	if (!IS_M2M(f->type))
    273		return -EINVAL;
    274
    275	fmt = fimc_find_format(&pix->pixelformat, NULL,
    276			       get_m2m_fmt_flags(f->type), 0);
    277	if (WARN(fmt == NULL, "Pixel format lookup failed"))
    278		return -EINVAL;
    279
    280	if (pix->field == V4L2_FIELD_ANY)
    281		pix->field = V4L2_FIELD_NONE;
    282	else if (pix->field != V4L2_FIELD_NONE)
    283		return -EINVAL;
    284
    285	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
    286		max_w = variant->pix_limit->scaler_dis_w;
    287		mod_x = ffs(variant->min_inp_pixsize) - 1;
    288	} else {
    289		max_w = variant->pix_limit->out_rot_dis_w;
    290		mod_x = ffs(variant->min_out_pixsize) - 1;
    291	}
    292
    293	if (tiled_fmt(fmt)) {
    294		mod_x = 6; /* 64 x 32 pixels tile */
    295		mod_y = 5;
    296	} else {
    297		if (variant->min_vsize_align == 1)
    298			mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
    299		else
    300			mod_y = ffs(variant->min_vsize_align) - 1;
    301	}
    302
    303	v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
    304		&pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
    305
    306	fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
    307	return 0;
    308}
    309
    310static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
    311				   struct v4l2_format *f)
    312{
    313	struct fimc_ctx *ctx = fh_to_ctx(fh);
    314	return fimc_try_fmt_mplane(ctx, f);
    315}
    316
    317static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt,
    318			       struct v4l2_pix_format_mplane *pixm)
    319{
    320	int i;
    321
    322	for (i = 0; i < fmt->memplanes; i++) {
    323		frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline;
    324		frame->payload[i] = pixm->plane_fmt[i].sizeimage;
    325	}
    326
    327	frame->f_width = pixm->width;
    328	frame->f_height	= pixm->height;
    329	frame->o_width = pixm->width;
    330	frame->o_height = pixm->height;
    331	frame->width = pixm->width;
    332	frame->height = pixm->height;
    333	frame->offs_h = 0;
    334	frame->offs_v = 0;
    335	frame->fmt = fmt;
    336}
    337
    338static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
    339				 struct v4l2_format *f)
    340{
    341	struct fimc_ctx *ctx = fh_to_ctx(fh);
    342	struct fimc_dev *fimc = ctx->fimc_dev;
    343	struct fimc_fmt *fmt;
    344	struct vb2_queue *vq;
    345	struct fimc_frame *frame;
    346	int ret;
    347
    348	ret = fimc_try_fmt_mplane(ctx, f);
    349	if (ret)
    350		return ret;
    351
    352	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
    353
    354	if (vb2_is_busy(vq)) {
    355		v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
    356		return -EBUSY;
    357	}
    358
    359	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
    360		frame = &ctx->s_frame;
    361	else
    362		frame = &ctx->d_frame;
    363
    364	fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL,
    365			       get_m2m_fmt_flags(f->type), 0);
    366	if (!fmt)
    367		return -EINVAL;
    368
    369	__set_frame_format(frame, fmt, &f->fmt.pix_mp);
    370
    371	/* Update RGB Alpha control state and value range */
    372	fimc_alpha_ctrl_update(ctx);
    373
    374	return 0;
    375}
    376
    377static int fimc_m2m_g_selection(struct file *file, void *fh,
    378				struct v4l2_selection *s)
    379{
    380	struct fimc_ctx *ctx = fh_to_ctx(fh);
    381	struct fimc_frame *frame;
    382
    383	frame = ctx_get_frame(ctx, s->type);
    384	if (IS_ERR(frame))
    385		return PTR_ERR(frame);
    386
    387	switch (s->target) {
    388	case V4L2_SEL_TGT_CROP:
    389	case V4L2_SEL_TGT_CROP_DEFAULT:
    390	case V4L2_SEL_TGT_CROP_BOUNDS:
    391		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
    392			return -EINVAL;
    393		break;
    394	case V4L2_SEL_TGT_COMPOSE:
    395	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
    396	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
    397		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
    398			return -EINVAL;
    399		break;
    400	default:
    401		return -EINVAL;
    402	}
    403
    404	switch (s->target) {
    405	case V4L2_SEL_TGT_CROP:
    406	case V4L2_SEL_TGT_COMPOSE:
    407		s->r.left = frame->offs_h;
    408		s->r.top = frame->offs_v;
    409		s->r.width = frame->width;
    410		s->r.height = frame->height;
    411		break;
    412	case V4L2_SEL_TGT_CROP_DEFAULT:
    413	case V4L2_SEL_TGT_CROP_BOUNDS:
    414	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
    415	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
    416		s->r.left = 0;
    417		s->r.top = 0;
    418		s->r.width = frame->o_width;
    419		s->r.height = frame->o_height;
    420		break;
    421	default:
    422		return -EINVAL;
    423	}
    424	return 0;
    425}
    426
    427static int fimc_m2m_try_selection(struct fimc_ctx *ctx,
    428				  struct v4l2_selection *s)
    429{
    430	struct fimc_dev *fimc = ctx->fimc_dev;
    431	struct fimc_frame *f;
    432	u32 min_size, halign, depth = 0;
    433	int i;
    434
    435	if (s->r.top < 0 || s->r.left < 0) {
    436		v4l2_err(&fimc->m2m.vfd,
    437			"doesn't support negative values for top & left\n");
    438		return -EINVAL;
    439	}
    440	if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
    441		f = &ctx->d_frame;
    442		if (s->target != V4L2_SEL_TGT_COMPOSE)
    443			return -EINVAL;
    444	} else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
    445		f = &ctx->s_frame;
    446		if (s->target != V4L2_SEL_TGT_CROP)
    447			return -EINVAL;
    448	} else {
    449		return -EINVAL;
    450	}
    451
    452	min_size = (f == &ctx->s_frame) ?
    453		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
    454
    455	/* Get pixel alignment constraints. */
    456	if (fimc->variant->min_vsize_align == 1)
    457		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
    458	else
    459		halign = ffs(fimc->variant->min_vsize_align) - 1;
    460
    461	for (i = 0; i < f->fmt->memplanes; i++)
    462		depth += f->fmt->depth[i];
    463
    464	v4l_bound_align_image(&s->r.width, min_size, f->o_width,
    465			      ffs(min_size) - 1,
    466			      &s->r.height, min_size, f->o_height,
    467			      halign, 64/(ALIGN(depth, 8)));
    468
    469	/* adjust left/top if cropping rectangle is out of bounds */
    470	if (s->r.left + s->r.width > f->o_width)
    471		s->r.left = f->o_width - s->r.width;
    472	if (s->r.top + s->r.height > f->o_height)
    473		s->r.top = f->o_height - s->r.height;
    474
    475	s->r.left = round_down(s->r.left, min_size);
    476	s->r.top  = round_down(s->r.top, fimc->variant->hor_offs_align);
    477
    478	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
    479	    s->r.left, s->r.top, s->r.width, s->r.height,
    480	    f->f_width, f->f_height);
    481
    482	return 0;
    483}
    484
    485static int fimc_m2m_s_selection(struct file *file, void *fh,
    486				struct v4l2_selection *s)
    487{
    488	struct fimc_ctx *ctx = fh_to_ctx(fh);
    489	struct fimc_dev *fimc = ctx->fimc_dev;
    490	struct fimc_frame *f;
    491	int ret;
    492
    493	ret = fimc_m2m_try_selection(ctx, s);
    494	if (ret)
    495		return ret;
    496
    497	f = (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
    498		&ctx->s_frame : &ctx->d_frame;
    499
    500	/* Check to see if scaling ratio is within supported range */
    501	if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
    502		ret = fimc_check_scaler_ratio(ctx, s->r.width,
    503				s->r.height, ctx->d_frame.width,
    504				ctx->d_frame.height, ctx->rotation);
    505	} else {
    506		ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
    507				ctx->s_frame.height, s->r.width,
    508				s->r.height, ctx->rotation);
    509	}
    510	if (ret) {
    511		v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
    512		return -EINVAL;
    513	}
    514
    515	f->offs_h = s->r.left;
    516	f->offs_v = s->r.top;
    517	f->width  = s->r.width;
    518	f->height = s->r.height;
    519
    520	fimc_ctx_state_set(FIMC_PARAMS, ctx);
    521
    522	return 0;
    523}
    524
    525static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
    526	.vidioc_querycap		= fimc_m2m_querycap,
    527	.vidioc_enum_fmt_vid_cap	= fimc_m2m_enum_fmt,
    528	.vidioc_enum_fmt_vid_out	= fimc_m2m_enum_fmt,
    529	.vidioc_g_fmt_vid_cap_mplane	= fimc_m2m_g_fmt_mplane,
    530	.vidioc_g_fmt_vid_out_mplane	= fimc_m2m_g_fmt_mplane,
    531	.vidioc_try_fmt_vid_cap_mplane	= fimc_m2m_try_fmt_mplane,
    532	.vidioc_try_fmt_vid_out_mplane	= fimc_m2m_try_fmt_mplane,
    533	.vidioc_s_fmt_vid_cap_mplane	= fimc_m2m_s_fmt_mplane,
    534	.vidioc_s_fmt_vid_out_mplane	= fimc_m2m_s_fmt_mplane,
    535	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
    536	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
    537	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
    538	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
    539	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
    540	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
    541	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
    542	.vidioc_g_selection		= fimc_m2m_g_selection,
    543	.vidioc_s_selection		= fimc_m2m_s_selection,
    544
    545};
    546
    547static int queue_init(void *priv, struct vb2_queue *src_vq,
    548		      struct vb2_queue *dst_vq)
    549{
    550	struct fimc_ctx *ctx = priv;
    551	int ret;
    552
    553	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    554	src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
    555	src_vq->drv_priv = ctx;
    556	src_vq->ops = &fimc_qops;
    557	src_vq->mem_ops = &vb2_dma_contig_memops;
    558	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
    559	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
    560	src_vq->lock = &ctx->fimc_dev->lock;
    561	src_vq->dev = &ctx->fimc_dev->pdev->dev;
    562
    563	ret = vb2_queue_init(src_vq);
    564	if (ret)
    565		return ret;
    566
    567	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    568	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
    569	dst_vq->drv_priv = ctx;
    570	dst_vq->ops = &fimc_qops;
    571	dst_vq->mem_ops = &vb2_dma_contig_memops;
    572	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
    573	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
    574	dst_vq->lock = &ctx->fimc_dev->lock;
    575	dst_vq->dev = &ctx->fimc_dev->pdev->dev;
    576
    577	return vb2_queue_init(dst_vq);
    578}
    579
    580static int fimc_m2m_set_default_format(struct fimc_ctx *ctx)
    581{
    582	struct v4l2_pix_format_mplane pixm = {
    583		.pixelformat	= V4L2_PIX_FMT_RGB32,
    584		.width		= 800,
    585		.height		= 600,
    586		.plane_fmt[0]	= {
    587			.bytesperline = 800 * 4,
    588			.sizeimage = 800 * 4 * 600,
    589		},
    590	};
    591	struct fimc_fmt *fmt;
    592
    593	fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0);
    594	if (!fmt)
    595		return -EINVAL;
    596
    597	__set_frame_format(&ctx->s_frame, fmt, &pixm);
    598	__set_frame_format(&ctx->d_frame, fmt, &pixm);
    599
    600	return 0;
    601}
    602
    603static int fimc_m2m_open(struct file *file)
    604{
    605	struct fimc_dev *fimc = video_drvdata(file);
    606	struct fimc_ctx *ctx;
    607	int ret = -EBUSY;
    608
    609	pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state);
    610
    611	if (mutex_lock_interruptible(&fimc->lock))
    612		return -ERESTARTSYS;
    613	/*
    614	 * Don't allow simultaneous open() of the mem-to-mem and the
    615	 * capture video node that belong to same FIMC IP instance.
    616	 */
    617	if (test_bit(ST_CAPT_BUSY, &fimc->state))
    618		goto unlock;
    619
    620	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
    621	if (!ctx) {
    622		ret = -ENOMEM;
    623		goto unlock;
    624	}
    625	v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd);
    626	ctx->fimc_dev = fimc;
    627
    628	/* Default color format */
    629	ctx->s_frame.fmt = fimc_get_format(0);
    630	ctx->d_frame.fmt = fimc_get_format(0);
    631
    632	ret = fimc_ctrls_create(ctx);
    633	if (ret)
    634		goto error_fh;
    635
    636	/* Use separate control handler per file handle */
    637	ctx->fh.ctrl_handler = &ctx->ctrls.handler;
    638	file->private_data = &ctx->fh;
    639	v4l2_fh_add(&ctx->fh);
    640
    641	/* Setup the device context for memory-to-memory mode */
    642	ctx->state = FIMC_CTX_M2M;
    643	ctx->flags = 0;
    644	ctx->in_path = FIMC_IO_DMA;
    645	ctx->out_path = FIMC_IO_DMA;
    646	ctx->scaler.enabled = 1;
    647
    648	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
    649	if (IS_ERR(ctx->fh.m2m_ctx)) {
    650		ret = PTR_ERR(ctx->fh.m2m_ctx);
    651		goto error_c;
    652	}
    653
    654	if (fimc->m2m.refcnt++ == 0)
    655		set_bit(ST_M2M_RUN, &fimc->state);
    656
    657	ret = fimc_m2m_set_default_format(ctx);
    658	if (ret < 0)
    659		goto error_m2m_ctx;
    660
    661	mutex_unlock(&fimc->lock);
    662	return 0;
    663
    664error_m2m_ctx:
    665	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
    666error_c:
    667	fimc_ctrls_delete(ctx);
    668	v4l2_fh_del(&ctx->fh);
    669error_fh:
    670	v4l2_fh_exit(&ctx->fh);
    671	kfree(ctx);
    672unlock:
    673	mutex_unlock(&fimc->lock);
    674	return ret;
    675}
    676
    677static int fimc_m2m_release(struct file *file)
    678{
    679	struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
    680	struct fimc_dev *fimc = ctx->fimc_dev;
    681
    682	dbg("pid: %d, state: 0x%lx, refcnt= %d",
    683		task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
    684
    685	mutex_lock(&fimc->lock);
    686
    687	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
    688	fimc_ctrls_delete(ctx);
    689	v4l2_fh_del(&ctx->fh);
    690	v4l2_fh_exit(&ctx->fh);
    691
    692	if (--fimc->m2m.refcnt <= 0)
    693		clear_bit(ST_M2M_RUN, &fimc->state);
    694	kfree(ctx);
    695
    696	mutex_unlock(&fimc->lock);
    697	return 0;
    698}
    699
    700static const struct v4l2_file_operations fimc_m2m_fops = {
    701	.owner		= THIS_MODULE,
    702	.open		= fimc_m2m_open,
    703	.release	= fimc_m2m_release,
    704	.poll		= v4l2_m2m_fop_poll,
    705	.unlocked_ioctl	= video_ioctl2,
    706	.mmap		= v4l2_m2m_fop_mmap,
    707};
    708
    709static const struct v4l2_m2m_ops m2m_ops = {
    710	.device_run	= fimc_device_run,
    711	.job_abort	= fimc_job_abort,
    712};
    713
    714int fimc_register_m2m_device(struct fimc_dev *fimc,
    715			     struct v4l2_device *v4l2_dev)
    716{
    717	struct video_device *vfd = &fimc->m2m.vfd;
    718	int ret;
    719
    720	fimc->v4l2_dev = v4l2_dev;
    721
    722	memset(vfd, 0, sizeof(*vfd));
    723	vfd->fops = &fimc_m2m_fops;
    724	vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
    725	vfd->v4l2_dev = v4l2_dev;
    726	vfd->minor = -1;
    727	vfd->release = video_device_release_empty;
    728	vfd->lock = &fimc->lock;
    729	vfd->vfl_dir = VFL_DIR_M2M;
    730	vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
    731	set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
    732
    733	snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
    734	video_set_drvdata(vfd, fimc);
    735
    736	fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
    737	if (IS_ERR(fimc->m2m.m2m_dev)) {
    738		v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
    739		return PTR_ERR(fimc->m2m.m2m_dev);
    740	}
    741
    742	ret = media_entity_pads_init(&vfd->entity, 0, NULL);
    743	if (ret)
    744		goto err_me;
    745
    746	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
    747	if (ret)
    748		goto err_vd;
    749
    750	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
    751		  vfd->name, video_device_node_name(vfd));
    752	return 0;
    753
    754err_vd:
    755	media_entity_cleanup(&vfd->entity);
    756err_me:
    757	v4l2_m2m_release(fimc->m2m.m2m_dev);
    758	return ret;
    759}
    760
    761void fimc_unregister_m2m_device(struct fimc_dev *fimc)
    762{
    763	if (!fimc)
    764		return;
    765
    766	if (fimc->m2m.m2m_dev)
    767		v4l2_m2m_release(fimc->m2m.m2m_dev);
    768
    769	if (video_is_registered(&fimc->m2m.vfd)) {
    770		video_unregister_device(&fimc->m2m.vfd);
    771		media_entity_cleanup(&fimc->m2m.vfd.entity);
    772	}
    773}