xref: /linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
143ecec16SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-or-later
243ecec16SMauro Carvalho Chehab /*
343ecec16SMauro Carvalho Chehab  * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
443ecec16SMauro Carvalho Chehab  *
543ecec16SMauro Carvalho Chehab  * Copyright (C) 2011 Samsung Electronics Co., Ltd.
643ecec16SMauro Carvalho Chehab  *		http://www.samsung.com/
743ecec16SMauro Carvalho Chehab  * Kamil Debski, <k.debski@samsung.com>
843ecec16SMauro Carvalho Chehab  */
943ecec16SMauro Carvalho Chehab 
1043ecec16SMauro Carvalho Chehab #include <linux/clk.h>
1143ecec16SMauro Carvalho Chehab #include <linux/interrupt.h>
1243ecec16SMauro Carvalho Chehab #include <linux/io.h>
1343ecec16SMauro Carvalho Chehab #include <linux/module.h>
1443ecec16SMauro Carvalho Chehab #include <linux/platform_device.h>
1543ecec16SMauro Carvalho Chehab #include <linux/sched.h>
1643ecec16SMauro Carvalho Chehab #include <linux/slab.h>
1743ecec16SMauro Carvalho Chehab #include <linux/videodev2.h>
1843ecec16SMauro Carvalho Chehab #include <linux/workqueue.h>
1943ecec16SMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
2043ecec16SMauro Carvalho Chehab #include <media/v4l2-event.h>
2143ecec16SMauro Carvalho Chehab #include <media/videobuf2-v4l2.h>
2243ecec16SMauro Carvalho Chehab #include "s5p_mfc_common.h"
2343ecec16SMauro Carvalho Chehab #include "s5p_mfc_ctrl.h"
2443ecec16SMauro Carvalho Chehab #include "s5p_mfc_debug.h"
2543ecec16SMauro Carvalho Chehab #include "s5p_mfc_dec.h"
2643ecec16SMauro Carvalho Chehab #include "s5p_mfc_intr.h"
2743ecec16SMauro Carvalho Chehab #include "s5p_mfc_opr.h"
2843ecec16SMauro Carvalho Chehab #include "s5p_mfc_pm.h"
2943ecec16SMauro Carvalho Chehab 
30028111b3SKrzysztof Kozlowski static const struct s5p_mfc_fmt formats[] = {
3143ecec16SMauro Carvalho Chehab 	{
3243ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_NV12MT_16X16,
3343ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_NONE,
3443ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_RAW,
3543ecec16SMauro Carvalho Chehab 		.num_planes	= 2,
3643ecec16SMauro Carvalho Chehab 		.versions	= MFC_V6_BIT | MFC_V7_BIT,
3743ecec16SMauro Carvalho Chehab 	},
3843ecec16SMauro Carvalho Chehab 	{
3943ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_NV12MT,
4043ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_NONE,
4143ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_RAW,
4243ecec16SMauro Carvalho Chehab 		.num_planes	= 2,
4343ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5_BIT,
4443ecec16SMauro Carvalho Chehab 	},
4543ecec16SMauro Carvalho Chehab 	{
4643ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_NV12M,
4743ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_NONE,
4843ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_RAW,
4943ecec16SMauro Carvalho Chehab 		.num_planes	= 2,
5043ecec16SMauro Carvalho Chehab 		.versions	= MFC_V6PLUS_BITS,
5143ecec16SMauro Carvalho Chehab 	},
5243ecec16SMauro Carvalho Chehab 	{
5343ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_NV21M,
5443ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_NONE,
5543ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_RAW,
5643ecec16SMauro Carvalho Chehab 		.num_planes	= 2,
5743ecec16SMauro Carvalho Chehab 		.versions	= MFC_V6PLUS_BITS,
5843ecec16SMauro Carvalho Chehab 	},
5943ecec16SMauro Carvalho Chehab 	{
606f146612SAakarsh Jain 		.fourcc         = V4L2_PIX_FMT_YUV420M,
616f146612SAakarsh Jain 		.codec_mode     = S5P_MFC_CODEC_NONE,
626f146612SAakarsh Jain 		.type           = MFC_FMT_RAW,
636f146612SAakarsh Jain 		.num_planes     = 3,
646f146612SAakarsh Jain 		.versions       = MFC_V12_BIT,
656f146612SAakarsh Jain 	},
666f146612SAakarsh Jain 	{
676f146612SAakarsh Jain 		.fourcc         = V4L2_PIX_FMT_YVU420M,
686f146612SAakarsh Jain 		.codec_mode     = S5P_MFC_CODEC_NONE,
696f146612SAakarsh Jain 		.type           = MFC_FMT_RAW,
706f146612SAakarsh Jain 		.num_planes     = 3,
716f146612SAakarsh Jain 		.versions       = MFC_V12_BIT
726f146612SAakarsh Jain 	},
736f146612SAakarsh Jain 	{
7443ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_H264,
7543ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_H264_DEC,
7643ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
7743ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
7843ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
7943ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION |
8043ecec16SMauro Carvalho Chehab 				  V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
8143ecec16SMauro Carvalho Chehab 	},
8243ecec16SMauro Carvalho Chehab 	{
8343ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_H264_MVC,
8443ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_H264_MVC_DEC,
8543ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
8643ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
8743ecec16SMauro Carvalho Chehab 		.versions	= MFC_V6PLUS_BITS,
8843ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION |
8943ecec16SMauro Carvalho Chehab 				  V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
9043ecec16SMauro Carvalho Chehab 	},
9143ecec16SMauro Carvalho Chehab 	{
9243ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_H263,
9343ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_H263_DEC,
9443ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
9543ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
9643ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
9743ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION,
9843ecec16SMauro Carvalho Chehab 	},
9943ecec16SMauro Carvalho Chehab 	{
10043ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_MPEG1,
10143ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_MPEG2_DEC,
10243ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
10343ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
10443ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
10543ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION |
10643ecec16SMauro Carvalho Chehab 				  V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
10743ecec16SMauro Carvalho Chehab 	},
10843ecec16SMauro Carvalho Chehab 	{
10943ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_MPEG2,
11043ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_MPEG2_DEC,
11143ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
11243ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
11343ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
11443ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION |
11543ecec16SMauro Carvalho Chehab 				  V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
11643ecec16SMauro Carvalho Chehab 	},
11743ecec16SMauro Carvalho Chehab 	{
11843ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_MPEG4,
11943ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_MPEG4_DEC,
12043ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
12143ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
12243ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
12343ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION |
12443ecec16SMauro Carvalho Chehab 				  V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
12543ecec16SMauro Carvalho Chehab 	},
12643ecec16SMauro Carvalho Chehab 	{
12743ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_XVID,
12843ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_MPEG4_DEC,
12943ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
13043ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
13143ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
13243ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION,
13343ecec16SMauro Carvalho Chehab 	},
13443ecec16SMauro Carvalho Chehab 	{
13543ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_VC1_ANNEX_G,
13643ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_VC1_DEC,
13743ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
13843ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
13943ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
14043ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION,
14143ecec16SMauro Carvalho Chehab 	},
14243ecec16SMauro Carvalho Chehab 	{
14343ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_VC1_ANNEX_L,
14443ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_VC1RCV_DEC,
14543ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
14643ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
14743ecec16SMauro Carvalho Chehab 		.versions	= MFC_V5PLUS_BITS,
14843ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION,
14943ecec16SMauro Carvalho Chehab 	},
15043ecec16SMauro Carvalho Chehab 	{
15143ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_VP8,
15243ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_MFC_CODEC_VP8_DEC,
15343ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
15443ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
15543ecec16SMauro Carvalho Chehab 		.versions	= MFC_V6PLUS_BITS,
15643ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION,
15743ecec16SMauro Carvalho Chehab 	},
15843ecec16SMauro Carvalho Chehab 	{
15943ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_HEVC,
16043ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_FIMV_CODEC_HEVC_DEC,
16143ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
16243ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
163e57b6d32SAakarsh Jain 		.versions	= MFC_V10PLUS_BITS,
16443ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION |
16543ecec16SMauro Carvalho Chehab 				  V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
16643ecec16SMauro Carvalho Chehab 	},
16743ecec16SMauro Carvalho Chehab 	{
16843ecec16SMauro Carvalho Chehab 		.fourcc		= V4L2_PIX_FMT_VP9,
16943ecec16SMauro Carvalho Chehab 		.codec_mode	= S5P_FIMV_CODEC_VP9_DEC,
17043ecec16SMauro Carvalho Chehab 		.type		= MFC_FMT_DEC,
17143ecec16SMauro Carvalho Chehab 		.num_planes	= 1,
172e57b6d32SAakarsh Jain 		.versions	= MFC_V10PLUS_BITS,
17343ecec16SMauro Carvalho Chehab 		.flags		= V4L2_FMT_FLAG_DYN_RESOLUTION,
17443ecec16SMauro Carvalho Chehab 	},
17543ecec16SMauro Carvalho Chehab };
17643ecec16SMauro Carvalho Chehab 
17743ecec16SMauro Carvalho Chehab #define NUM_FORMATS ARRAY_SIZE(formats)
17843ecec16SMauro Carvalho Chehab 
17943ecec16SMauro Carvalho Chehab /* Find selected format description */
find_format(struct v4l2_format * f,unsigned int t)180028111b3SKrzysztof Kozlowski static const struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
18143ecec16SMauro Carvalho Chehab {
18243ecec16SMauro Carvalho Chehab 	unsigned int i;
18343ecec16SMauro Carvalho Chehab 
18443ecec16SMauro Carvalho Chehab 	for (i = 0; i < NUM_FORMATS; i++) {
18543ecec16SMauro Carvalho Chehab 		if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
18643ecec16SMauro Carvalho Chehab 		    formats[i].type == t)
18743ecec16SMauro Carvalho Chehab 			return &formats[i];
18843ecec16SMauro Carvalho Chehab 	}
18943ecec16SMauro Carvalho Chehab 	return NULL;
19043ecec16SMauro Carvalho Chehab }
19143ecec16SMauro Carvalho Chehab 
19243ecec16SMauro Carvalho Chehab static struct mfc_control controls[] = {
19343ecec16SMauro Carvalho Chehab 	{
19443ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
19543ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_INTEGER,
19643ecec16SMauro Carvalho Chehab 		.name = "H264 Display Delay",
19743ecec16SMauro Carvalho Chehab 		.minimum = 0,
19843ecec16SMauro Carvalho Chehab 		.maximum = 16383,
19943ecec16SMauro Carvalho Chehab 		.step = 1,
20043ecec16SMauro Carvalho Chehab 		.default_value = 0,
20143ecec16SMauro Carvalho Chehab 	},
20243ecec16SMauro Carvalho Chehab 	{
20343ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
20443ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_INTEGER,
20543ecec16SMauro Carvalho Chehab 		.minimum = 0,
20643ecec16SMauro Carvalho Chehab 		.maximum = 16383,
20743ecec16SMauro Carvalho Chehab 		.step = 1,
20843ecec16SMauro Carvalho Chehab 		.default_value = 0,
20943ecec16SMauro Carvalho Chehab 	},
21043ecec16SMauro Carvalho Chehab 	{
21143ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE,
21243ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_BOOLEAN,
21343ecec16SMauro Carvalho Chehab 		.name = "H264 Display Delay Enable",
21443ecec16SMauro Carvalho Chehab 		.minimum = 0,
21543ecec16SMauro Carvalho Chehab 		.maximum = 1,
21643ecec16SMauro Carvalho Chehab 		.step = 1,
21743ecec16SMauro Carvalho Chehab 		.default_value = 0,
21843ecec16SMauro Carvalho Chehab 	},
21943ecec16SMauro Carvalho Chehab 	{
22043ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
22143ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_BOOLEAN,
22243ecec16SMauro Carvalho Chehab 		.minimum = 0,
22343ecec16SMauro Carvalho Chehab 		.maximum = 1,
22443ecec16SMauro Carvalho Chehab 		.default_value = 0,
22543ecec16SMauro Carvalho Chehab 	},
22643ecec16SMauro Carvalho Chehab 	{
22743ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
22843ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_BOOLEAN,
22943ecec16SMauro Carvalho Chehab 		.name = "Mpeg4 Loop Filter Enable",
23043ecec16SMauro Carvalho Chehab 		.minimum = 0,
23143ecec16SMauro Carvalho Chehab 		.maximum = 1,
23243ecec16SMauro Carvalho Chehab 		.step = 1,
23343ecec16SMauro Carvalho Chehab 		.default_value = 0,
23443ecec16SMauro Carvalho Chehab 	},
23543ecec16SMauro Carvalho Chehab 	{
23643ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
23743ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_BOOLEAN,
23843ecec16SMauro Carvalho Chehab 		.name = "Slice Interface Enable",
23943ecec16SMauro Carvalho Chehab 		.minimum = 0,
24043ecec16SMauro Carvalho Chehab 		.maximum = 1,
24143ecec16SMauro Carvalho Chehab 		.step = 1,
24243ecec16SMauro Carvalho Chehab 		.default_value = 0,
24343ecec16SMauro Carvalho Chehab 	},
24443ecec16SMauro Carvalho Chehab 	{
24543ecec16SMauro Carvalho Chehab 		.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
24643ecec16SMauro Carvalho Chehab 		.type = V4L2_CTRL_TYPE_INTEGER,
24743ecec16SMauro Carvalho Chehab 		.name = "Minimum number of cap bufs",
24843ecec16SMauro Carvalho Chehab 		.minimum = 1,
24943ecec16SMauro Carvalho Chehab 		.maximum = 32,
25043ecec16SMauro Carvalho Chehab 		.step = 1,
25143ecec16SMauro Carvalho Chehab 		.default_value = 1,
25243ecec16SMauro Carvalho Chehab 		.is_volatile = 1,
25343ecec16SMauro Carvalho Chehab 	},
25443ecec16SMauro Carvalho Chehab };
25543ecec16SMauro Carvalho Chehab 
25643ecec16SMauro Carvalho Chehab #define NUM_CTRLS ARRAY_SIZE(controls)
25743ecec16SMauro Carvalho Chehab 
25843ecec16SMauro Carvalho Chehab /* Check whether a context should be run on hardware */
s5p_mfc_ctx_ready(struct s5p_mfc_ctx * ctx)25943ecec16SMauro Carvalho Chehab static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
26043ecec16SMauro Carvalho Chehab {
26143ecec16SMauro Carvalho Chehab 	/* Context is to parse header */
26243ecec16SMauro Carvalho Chehab 	if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
26343ecec16SMauro Carvalho Chehab 		return 1;
26443ecec16SMauro Carvalho Chehab 	/* Context is to decode a frame */
26543ecec16SMauro Carvalho Chehab 	if (ctx->src_queue_cnt >= 1 &&
26643ecec16SMauro Carvalho Chehab 	    ctx->state == MFCINST_RUNNING &&
26743ecec16SMauro Carvalho Chehab 	    ctx->dst_queue_cnt >= ctx->pb_count)
26843ecec16SMauro Carvalho Chehab 		return 1;
26943ecec16SMauro Carvalho Chehab 	/* Context is to return last frame */
27043ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_FINISHING &&
27143ecec16SMauro Carvalho Chehab 	    ctx->dst_queue_cnt >= ctx->pb_count)
27243ecec16SMauro Carvalho Chehab 		return 1;
27343ecec16SMauro Carvalho Chehab 	/* Context is to set buffers */
27443ecec16SMauro Carvalho Chehab 	if (ctx->src_queue_cnt >= 1 &&
27543ecec16SMauro Carvalho Chehab 	    ctx->state == MFCINST_HEAD_PARSED &&
27643ecec16SMauro Carvalho Chehab 	    ctx->capture_state == QUEUE_BUFS_MMAPED)
27743ecec16SMauro Carvalho Chehab 		return 1;
27843ecec16SMauro Carvalho Chehab 	/* Resolution change */
27943ecec16SMauro Carvalho Chehab 	if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
28043ecec16SMauro Carvalho Chehab 		ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
28143ecec16SMauro Carvalho Chehab 		ctx->dst_queue_cnt >= ctx->pb_count)
28243ecec16SMauro Carvalho Chehab 		return 1;
28343ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_RES_CHANGE_END &&
28443ecec16SMauro Carvalho Chehab 		ctx->src_queue_cnt >= 1)
28543ecec16SMauro Carvalho Chehab 		return 1;
28643ecec16SMauro Carvalho Chehab 	mfc_debug(2, "ctx is not ready\n");
28743ecec16SMauro Carvalho Chehab 	return 0;
28843ecec16SMauro Carvalho Chehab }
28943ecec16SMauro Carvalho Chehab 
29043ecec16SMauro Carvalho Chehab static const struct s5p_mfc_codec_ops decoder_codec_ops = {
29143ecec16SMauro Carvalho Chehab 	.pre_seq_start		= NULL,
29243ecec16SMauro Carvalho Chehab 	.post_seq_start		= NULL,
29343ecec16SMauro Carvalho Chehab 	.pre_frame_start	= NULL,
29443ecec16SMauro Carvalho Chehab 	.post_frame_start	= NULL,
29543ecec16SMauro Carvalho Chehab };
29643ecec16SMauro Carvalho Chehab 
29743ecec16SMauro Carvalho Chehab /* Query capabilities of the device */
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)29843ecec16SMauro Carvalho Chehab static int vidioc_querycap(struct file *file, void *priv,
29943ecec16SMauro Carvalho Chehab 			   struct v4l2_capability *cap)
30043ecec16SMauro Carvalho Chehab {
30143ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = video_drvdata(file);
30243ecec16SMauro Carvalho Chehab 
30343ecec16SMauro Carvalho Chehab 	strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver));
30443ecec16SMauro Carvalho Chehab 	strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card));
30543ecec16SMauro Carvalho Chehab 	return 0;
30643ecec16SMauro Carvalho Chehab }
30743ecec16SMauro Carvalho Chehab 
30843ecec16SMauro Carvalho Chehab /* Enumerate format */
vidioc_enum_fmt(struct file * file,struct v4l2_fmtdesc * f,bool out)30943ecec16SMauro Carvalho Chehab static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
31043ecec16SMauro Carvalho Chehab 							bool out)
31143ecec16SMauro Carvalho Chehab {
31243ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = video_drvdata(file);
31343ecec16SMauro Carvalho Chehab 	int i, j = 0;
31443ecec16SMauro Carvalho Chehab 
31543ecec16SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
31643ecec16SMauro Carvalho Chehab 		if (out && formats[i].type != MFC_FMT_DEC)
31743ecec16SMauro Carvalho Chehab 			continue;
31843ecec16SMauro Carvalho Chehab 		else if (!out && formats[i].type != MFC_FMT_RAW)
31943ecec16SMauro Carvalho Chehab 			continue;
32043ecec16SMauro Carvalho Chehab 		else if ((dev->variant->version_bit & formats[i].versions) == 0)
32143ecec16SMauro Carvalho Chehab 			continue;
32243ecec16SMauro Carvalho Chehab 
32343ecec16SMauro Carvalho Chehab 		if (j == f->index)
32443ecec16SMauro Carvalho Chehab 			break;
32543ecec16SMauro Carvalho Chehab 		++j;
32643ecec16SMauro Carvalho Chehab 	}
32743ecec16SMauro Carvalho Chehab 	if (i == ARRAY_SIZE(formats))
32843ecec16SMauro Carvalho Chehab 		return -EINVAL;
32943ecec16SMauro Carvalho Chehab 	f->pixelformat = formats[i].fourcc;
33043ecec16SMauro Carvalho Chehab 	return 0;
33143ecec16SMauro Carvalho Chehab }
33243ecec16SMauro Carvalho Chehab 
vidioc_enum_fmt_vid_cap(struct file * file,void * pirv,struct v4l2_fmtdesc * f)33343ecec16SMauro Carvalho Chehab static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
33443ecec16SMauro Carvalho Chehab 				   struct v4l2_fmtdesc *f)
33543ecec16SMauro Carvalho Chehab {
33643ecec16SMauro Carvalho Chehab 	return vidioc_enum_fmt(file, f, false);
33743ecec16SMauro Carvalho Chehab }
33843ecec16SMauro Carvalho Chehab 
vidioc_enum_fmt_vid_out(struct file * file,void * priv,struct v4l2_fmtdesc * f)33943ecec16SMauro Carvalho Chehab static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
34043ecec16SMauro Carvalho Chehab 				   struct v4l2_fmtdesc *f)
34143ecec16SMauro Carvalho Chehab {
34243ecec16SMauro Carvalho Chehab 	return vidioc_enum_fmt(file, f, true);
34343ecec16SMauro Carvalho Chehab }
34443ecec16SMauro Carvalho Chehab 
34543ecec16SMauro Carvalho Chehab /* Get format */
vidioc_g_fmt(struct file * file,void * priv,struct v4l2_format * f)34643ecec16SMauro Carvalho Chehab static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
34743ecec16SMauro Carvalho Chehab {
34843ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
34943ecec16SMauro Carvalho Chehab 	struct v4l2_pix_format_mplane *pix_mp;
35043ecec16SMauro Carvalho Chehab 
35143ecec16SMauro Carvalho Chehab 	mfc_debug_enter();
35243ecec16SMauro Carvalho Chehab 	pix_mp = &f->fmt.pix_mp;
35343ecec16SMauro Carvalho Chehab 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
35443ecec16SMauro Carvalho Chehab 	    (ctx->state == MFCINST_GOT_INST || ctx->state ==
35543ecec16SMauro Carvalho Chehab 						MFCINST_RES_CHANGE_END)) {
35643ecec16SMauro Carvalho Chehab 		/* If the MFC is parsing the header,
35743ecec16SMauro Carvalho Chehab 		 * so wait until it is finished */
35843ecec16SMauro Carvalho Chehab 		s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET,
35943ecec16SMauro Carvalho Chehab 									0);
36043ecec16SMauro Carvalho Chehab 	}
36143ecec16SMauro Carvalho Chehab 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
36243ecec16SMauro Carvalho Chehab 	    ctx->state >= MFCINST_HEAD_PARSED &&
36343ecec16SMauro Carvalho Chehab 	    ctx->state < MFCINST_ABORT) {
36443ecec16SMauro Carvalho Chehab 		/* This is run on CAPTURE (decode output) */
36543ecec16SMauro Carvalho Chehab 		/* Width and height are set to the dimensions
36643ecec16SMauro Carvalho Chehab 		   of the movie, the buffer is bigger and
36743ecec16SMauro Carvalho Chehab 		   further processing stages should crop to this
36843ecec16SMauro Carvalho Chehab 		   rectangle. */
36943ecec16SMauro Carvalho Chehab 		pix_mp->width = ctx->buf_width;
37043ecec16SMauro Carvalho Chehab 		pix_mp->height = ctx->buf_height;
37143ecec16SMauro Carvalho Chehab 		pix_mp->field = V4L2_FIELD_NONE;
372e57b6d32SAakarsh Jain 		pix_mp->num_planes = ctx->dst_fmt->num_planes;
37343ecec16SMauro Carvalho Chehab 		/* Set pixelformat to the format in which MFC
37443ecec16SMauro Carvalho Chehab 		   outputs the decoded frame */
37543ecec16SMauro Carvalho Chehab 		pix_mp->pixelformat = ctx->dst_fmt->fourcc;
3766f146612SAakarsh Jain 		pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
37743ecec16SMauro Carvalho Chehab 		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
3786f146612SAakarsh Jain 		pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
37943ecec16SMauro Carvalho Chehab 		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
3806f146612SAakarsh Jain 		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
3816f146612SAakarsh Jain 				V4L2_PIX_FMT_YVU420M) {
3826f146612SAakarsh Jain 			pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
3836f146612SAakarsh Jain 			pix_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
3846f146612SAakarsh Jain 		}
38543ecec16SMauro Carvalho Chehab 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
38643ecec16SMauro Carvalho Chehab 		/* This is run on OUTPUT
38743ecec16SMauro Carvalho Chehab 		   The buffer contains compressed image
38843ecec16SMauro Carvalho Chehab 		   so width and height have no meaning */
38943ecec16SMauro Carvalho Chehab 		pix_mp->width = 0;
39043ecec16SMauro Carvalho Chehab 		pix_mp->height = 0;
39143ecec16SMauro Carvalho Chehab 		pix_mp->field = V4L2_FIELD_NONE;
39243ecec16SMauro Carvalho Chehab 		pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size;
39343ecec16SMauro Carvalho Chehab 		pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size;
39443ecec16SMauro Carvalho Chehab 		pix_mp->pixelformat = ctx->src_fmt->fourcc;
39543ecec16SMauro Carvalho Chehab 		pix_mp->num_planes = ctx->src_fmt->num_planes;
39643ecec16SMauro Carvalho Chehab 	} else {
39743ecec16SMauro Carvalho Chehab 		mfc_err("Format could not be read\n");
39843ecec16SMauro Carvalho Chehab 		mfc_debug(2, "%s-- with error\n", __func__);
39943ecec16SMauro Carvalho Chehab 		return -EINVAL;
40043ecec16SMauro Carvalho Chehab 	}
40143ecec16SMauro Carvalho Chehab 	mfc_debug_leave();
40243ecec16SMauro Carvalho Chehab 	return 0;
40343ecec16SMauro Carvalho Chehab }
40443ecec16SMauro Carvalho Chehab 
40543ecec16SMauro Carvalho Chehab /* Try format */
vidioc_try_fmt(struct file * file,void * priv,struct v4l2_format * f)40643ecec16SMauro Carvalho Chehab static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
40743ecec16SMauro Carvalho Chehab {
40843ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = video_drvdata(file);
409028111b3SKrzysztof Kozlowski 	const struct s5p_mfc_fmt *fmt;
41043ecec16SMauro Carvalho Chehab 
41143ecec16SMauro Carvalho Chehab 	mfc_debug(2, "Type is %d\n", f->type);
41243ecec16SMauro Carvalho Chehab 	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
41343ecec16SMauro Carvalho Chehab 		fmt = find_format(f, MFC_FMT_DEC);
41443ecec16SMauro Carvalho Chehab 		if (!fmt) {
41543ecec16SMauro Carvalho Chehab 			mfc_err("Unsupported format for source.\n");
41643ecec16SMauro Carvalho Chehab 			return -EINVAL;
41743ecec16SMauro Carvalho Chehab 		}
41843ecec16SMauro Carvalho Chehab 		if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
41943ecec16SMauro Carvalho Chehab 			mfc_err("Unknown codec\n");
42043ecec16SMauro Carvalho Chehab 			return -EINVAL;
42143ecec16SMauro Carvalho Chehab 		}
42243ecec16SMauro Carvalho Chehab 		if ((dev->variant->version_bit & fmt->versions) == 0) {
42343ecec16SMauro Carvalho Chehab 			mfc_err("Unsupported format by this MFC version.\n");
42443ecec16SMauro Carvalho Chehab 			return -EINVAL;
42543ecec16SMauro Carvalho Chehab 		}
42643ecec16SMauro Carvalho Chehab 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
42743ecec16SMauro Carvalho Chehab 		fmt = find_format(f, MFC_FMT_RAW);
42843ecec16SMauro Carvalho Chehab 		if (!fmt) {
42943ecec16SMauro Carvalho Chehab 			mfc_err("Unsupported format for destination.\n");
43043ecec16SMauro Carvalho Chehab 			return -EINVAL;
43143ecec16SMauro Carvalho Chehab 		}
43243ecec16SMauro Carvalho Chehab 		if ((dev->variant->version_bit & fmt->versions) == 0) {
43343ecec16SMauro Carvalho Chehab 			mfc_err("Unsupported format by this MFC version.\n");
43443ecec16SMauro Carvalho Chehab 			return -EINVAL;
43543ecec16SMauro Carvalho Chehab 		}
43643ecec16SMauro Carvalho Chehab 	}
43743ecec16SMauro Carvalho Chehab 
43843ecec16SMauro Carvalho Chehab 	return 0;
43943ecec16SMauro Carvalho Chehab }
44043ecec16SMauro Carvalho Chehab 
44143ecec16SMauro Carvalho Chehab /* Set format */
vidioc_s_fmt(struct file * file,void * priv,struct v4l2_format * f)44243ecec16SMauro Carvalho Chehab static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
44343ecec16SMauro Carvalho Chehab {
44443ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = video_drvdata(file);
44543ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
44643ecec16SMauro Carvalho Chehab 	int ret = 0;
44743ecec16SMauro Carvalho Chehab 	struct v4l2_pix_format_mplane *pix_mp;
448e8cc4c0bSKrzysztof Kozlowski 	const struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size;
44943ecec16SMauro Carvalho Chehab 
45043ecec16SMauro Carvalho Chehab 	mfc_debug_enter();
45143ecec16SMauro Carvalho Chehab 	ret = vidioc_try_fmt(file, priv, f);
45243ecec16SMauro Carvalho Chehab 	pix_mp = &f->fmt.pix_mp;
45343ecec16SMauro Carvalho Chehab 	if (ret)
45443ecec16SMauro Carvalho Chehab 		return ret;
45543ecec16SMauro Carvalho Chehab 	if (vb2_is_streaming(&ctx->vq_src) || vb2_is_streaming(&ctx->vq_dst)) {
45643ecec16SMauro Carvalho Chehab 		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
45743ecec16SMauro Carvalho Chehab 		ret = -EBUSY;
45843ecec16SMauro Carvalho Chehab 		goto out;
45943ecec16SMauro Carvalho Chehab 	}
46043ecec16SMauro Carvalho Chehab 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
46143ecec16SMauro Carvalho Chehab 		/* dst_fmt is validated by call to vidioc_try_fmt */
46243ecec16SMauro Carvalho Chehab 		ctx->dst_fmt = find_format(f, MFC_FMT_RAW);
46343ecec16SMauro Carvalho Chehab 		ret = 0;
46443ecec16SMauro Carvalho Chehab 		goto out;
46543ecec16SMauro Carvalho Chehab 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
46643ecec16SMauro Carvalho Chehab 		/* src_fmt is validated by call to vidioc_try_fmt */
46743ecec16SMauro Carvalho Chehab 		ctx->src_fmt = find_format(f, MFC_FMT_DEC);
46843ecec16SMauro Carvalho Chehab 		ctx->codec_mode = ctx->src_fmt->codec_mode;
46943ecec16SMauro Carvalho Chehab 		mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
47043ecec16SMauro Carvalho Chehab 		pix_mp->height = 0;
47143ecec16SMauro Carvalho Chehab 		pix_mp->width = 0;
47243ecec16SMauro Carvalho Chehab 		if (pix_mp->plane_fmt[0].sizeimage == 0)
47343ecec16SMauro Carvalho Chehab 			pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
47443ecec16SMauro Carvalho Chehab 								DEF_CPB_SIZE;
47543ecec16SMauro Carvalho Chehab 		else if (pix_mp->plane_fmt[0].sizeimage > buf_size->cpb)
47643ecec16SMauro Carvalho Chehab 			ctx->dec_src_buf_size = buf_size->cpb;
47743ecec16SMauro Carvalho Chehab 		else
47843ecec16SMauro Carvalho Chehab 			ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
47943ecec16SMauro Carvalho Chehab 		pix_mp->plane_fmt[0].bytesperline = 0;
48043ecec16SMauro Carvalho Chehab 		ctx->state = MFCINST_INIT;
48143ecec16SMauro Carvalho Chehab 		ret = 0;
48243ecec16SMauro Carvalho Chehab 		goto out;
48343ecec16SMauro Carvalho Chehab 	} else {
48443ecec16SMauro Carvalho Chehab 		mfc_err("Wrong type error for S_FMT : %d", f->type);
48543ecec16SMauro Carvalho Chehab 		ret = -EINVAL;
48643ecec16SMauro Carvalho Chehab 		goto out;
48743ecec16SMauro Carvalho Chehab 	}
48843ecec16SMauro Carvalho Chehab 
48943ecec16SMauro Carvalho Chehab out:
49043ecec16SMauro Carvalho Chehab 	mfc_debug_leave();
49143ecec16SMauro Carvalho Chehab 	return ret;
49243ecec16SMauro Carvalho Chehab }
49343ecec16SMauro Carvalho Chehab 
reqbufs_output(struct s5p_mfc_dev * dev,struct s5p_mfc_ctx * ctx,struct v4l2_requestbuffers * reqbufs)49443ecec16SMauro Carvalho Chehab static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
49543ecec16SMauro Carvalho Chehab 				struct v4l2_requestbuffers *reqbufs)
49643ecec16SMauro Carvalho Chehab {
49743ecec16SMauro Carvalho Chehab 	int ret = 0;
49843ecec16SMauro Carvalho Chehab 
499*c007ae83SKrzysztof Kozlowski 	s5p_mfc_clock_on(dev);
50043ecec16SMauro Carvalho Chehab 
50143ecec16SMauro Carvalho Chehab 	if (reqbufs->count == 0) {
50243ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Freeing buffers\n");
50343ecec16SMauro Carvalho Chehab 		ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
50443ecec16SMauro Carvalho Chehab 		if (ret)
50543ecec16SMauro Carvalho Chehab 			goto out;
50643ecec16SMauro Carvalho Chehab 		ctx->src_bufs_cnt = 0;
50743ecec16SMauro Carvalho Chehab 		ctx->output_state = QUEUE_FREE;
50843ecec16SMauro Carvalho Chehab 	} else if (ctx->output_state == QUEUE_FREE) {
50943ecec16SMauro Carvalho Chehab 		/* Can only request buffers when we have a valid format set. */
51043ecec16SMauro Carvalho Chehab 		WARN_ON(ctx->src_bufs_cnt != 0);
51143ecec16SMauro Carvalho Chehab 		if (ctx->state != MFCINST_INIT) {
51243ecec16SMauro Carvalho Chehab 			mfc_err("Reqbufs called in an invalid state\n");
51343ecec16SMauro Carvalho Chehab 			ret = -EINVAL;
51443ecec16SMauro Carvalho Chehab 			goto out;
51543ecec16SMauro Carvalho Chehab 		}
51643ecec16SMauro Carvalho Chehab 
51743ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n",
51843ecec16SMauro Carvalho Chehab 				reqbufs->count);
51943ecec16SMauro Carvalho Chehab 		ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
52043ecec16SMauro Carvalho Chehab 		if (ret)
52143ecec16SMauro Carvalho Chehab 			goto out;
52243ecec16SMauro Carvalho Chehab 
52343ecec16SMauro Carvalho Chehab 		ret = s5p_mfc_open_mfc_inst(dev, ctx);
52443ecec16SMauro Carvalho Chehab 		if (ret) {
52543ecec16SMauro Carvalho Chehab 			reqbufs->count = 0;
52643ecec16SMauro Carvalho Chehab 			vb2_reqbufs(&ctx->vq_src, reqbufs);
52743ecec16SMauro Carvalho Chehab 			goto out;
52843ecec16SMauro Carvalho Chehab 		}
52943ecec16SMauro Carvalho Chehab 
53043ecec16SMauro Carvalho Chehab 		ctx->output_state = QUEUE_BUFS_REQUESTED;
53143ecec16SMauro Carvalho Chehab 	} else {
53243ecec16SMauro Carvalho Chehab 		mfc_err("Buffers have already been requested\n");
53343ecec16SMauro Carvalho Chehab 		ret = -EINVAL;
53443ecec16SMauro Carvalho Chehab 	}
53543ecec16SMauro Carvalho Chehab out:
536*c007ae83SKrzysztof Kozlowski 	s5p_mfc_clock_off(dev);
53743ecec16SMauro Carvalho Chehab 	if (ret)
53843ecec16SMauro Carvalho Chehab 		mfc_err("Failed allocating buffers for OUTPUT queue\n");
53943ecec16SMauro Carvalho Chehab 	return ret;
54043ecec16SMauro Carvalho Chehab }
54143ecec16SMauro Carvalho Chehab 
reqbufs_capture(struct s5p_mfc_dev * dev,struct s5p_mfc_ctx * ctx,struct v4l2_requestbuffers * reqbufs)54243ecec16SMauro Carvalho Chehab static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
54343ecec16SMauro Carvalho Chehab 				struct v4l2_requestbuffers *reqbufs)
54443ecec16SMauro Carvalho Chehab {
54543ecec16SMauro Carvalho Chehab 	int ret = 0;
54643ecec16SMauro Carvalho Chehab 
547*c007ae83SKrzysztof Kozlowski 	s5p_mfc_clock_on(dev);
54843ecec16SMauro Carvalho Chehab 
54943ecec16SMauro Carvalho Chehab 	if (reqbufs->count == 0) {
55043ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Freeing buffers\n");
55143ecec16SMauro Carvalho Chehab 		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
55243ecec16SMauro Carvalho Chehab 		if (ret)
55343ecec16SMauro Carvalho Chehab 			goto out;
55443ecec16SMauro Carvalho Chehab 		s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
55543ecec16SMauro Carvalho Chehab 		ctx->dst_bufs_cnt = 0;
55643ecec16SMauro Carvalho Chehab 	} else if (ctx->capture_state == QUEUE_FREE) {
55743ecec16SMauro Carvalho Chehab 		WARN_ON(ctx->dst_bufs_cnt != 0);
55843ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n",
55943ecec16SMauro Carvalho Chehab 				reqbufs->count);
56043ecec16SMauro Carvalho Chehab 		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
56143ecec16SMauro Carvalho Chehab 		if (ret)
56243ecec16SMauro Carvalho Chehab 			goto out;
56343ecec16SMauro Carvalho Chehab 
56443ecec16SMauro Carvalho Chehab 		ctx->capture_state = QUEUE_BUFS_REQUESTED;
56543ecec16SMauro Carvalho Chehab 		ctx->total_dpb_count = reqbufs->count;
56643ecec16SMauro Carvalho Chehab 
56743ecec16SMauro Carvalho Chehab 		ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx);
56843ecec16SMauro Carvalho Chehab 		if (ret) {
56943ecec16SMauro Carvalho Chehab 			mfc_err("Failed to allocate decoding buffers\n");
57043ecec16SMauro Carvalho Chehab 			reqbufs->count = 0;
57143ecec16SMauro Carvalho Chehab 			vb2_reqbufs(&ctx->vq_dst, reqbufs);
57243ecec16SMauro Carvalho Chehab 			ret = -ENOMEM;
57343ecec16SMauro Carvalho Chehab 			ctx->capture_state = QUEUE_FREE;
57443ecec16SMauro Carvalho Chehab 			goto out;
57543ecec16SMauro Carvalho Chehab 		}
57643ecec16SMauro Carvalho Chehab 
57743ecec16SMauro Carvalho Chehab 		WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count);
57843ecec16SMauro Carvalho Chehab 		ctx->capture_state = QUEUE_BUFS_MMAPED;
57943ecec16SMauro Carvalho Chehab 
58043ecec16SMauro Carvalho Chehab 		if (s5p_mfc_ctx_ready(ctx))
58143ecec16SMauro Carvalho Chehab 			set_work_bit_irqsave(ctx);
58243ecec16SMauro Carvalho Chehab 		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
58343ecec16SMauro Carvalho Chehab 		s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
58443ecec16SMauro Carvalho Chehab 					  0);
58543ecec16SMauro Carvalho Chehab 	} else {
58643ecec16SMauro Carvalho Chehab 		mfc_err("Buffers have already been requested\n");
58743ecec16SMauro Carvalho Chehab 		ret = -EINVAL;
58843ecec16SMauro Carvalho Chehab 	}
58943ecec16SMauro Carvalho Chehab out:
590*c007ae83SKrzysztof Kozlowski 	s5p_mfc_clock_off(dev);
59143ecec16SMauro Carvalho Chehab 	if (ret)
59243ecec16SMauro Carvalho Chehab 		mfc_err("Failed allocating buffers for CAPTURE queue\n");
59343ecec16SMauro Carvalho Chehab 	return ret;
59443ecec16SMauro Carvalho Chehab }
59543ecec16SMauro Carvalho Chehab 
59643ecec16SMauro Carvalho Chehab /* Request buffers */
vidioc_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * reqbufs)59743ecec16SMauro Carvalho Chehab static int vidioc_reqbufs(struct file *file, void *priv,
59843ecec16SMauro Carvalho Chehab 					  struct v4l2_requestbuffers *reqbufs)
59943ecec16SMauro Carvalho Chehab {
60043ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = video_drvdata(file);
60143ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
60243ecec16SMauro Carvalho Chehab 
60343ecec16SMauro Carvalho Chehab 	if (reqbufs->memory != V4L2_MEMORY_MMAP) {
60443ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Only V4L2_MEMORY_MMAP is supported\n");
60543ecec16SMauro Carvalho Chehab 		return -EINVAL;
60643ecec16SMauro Carvalho Chehab 	}
60743ecec16SMauro Carvalho Chehab 
60843ecec16SMauro Carvalho Chehab 	if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
60943ecec16SMauro Carvalho Chehab 		return reqbufs_output(dev, ctx, reqbufs);
61043ecec16SMauro Carvalho Chehab 	} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
61143ecec16SMauro Carvalho Chehab 		return reqbufs_capture(dev, ctx, reqbufs);
61243ecec16SMauro Carvalho Chehab 	} else {
61343ecec16SMauro Carvalho Chehab 		mfc_err("Invalid type requested\n");
61443ecec16SMauro Carvalho Chehab 		return -EINVAL;
61543ecec16SMauro Carvalho Chehab 	}
61643ecec16SMauro Carvalho Chehab }
61743ecec16SMauro Carvalho Chehab 
61843ecec16SMauro Carvalho Chehab /* Query buffer */
vidioc_querybuf(struct file * file,void * priv,struct v4l2_buffer * buf)61943ecec16SMauro Carvalho Chehab static int vidioc_querybuf(struct file *file, void *priv,
62043ecec16SMauro Carvalho Chehab 						   struct v4l2_buffer *buf)
62143ecec16SMauro Carvalho Chehab {
62243ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
62343ecec16SMauro Carvalho Chehab 	int ret;
62443ecec16SMauro Carvalho Chehab 	int i;
62543ecec16SMauro Carvalho Chehab 
62643ecec16SMauro Carvalho Chehab 	if (buf->memory != V4L2_MEMORY_MMAP) {
62743ecec16SMauro Carvalho Chehab 		mfc_err("Only mmapped buffers can be used\n");
62843ecec16SMauro Carvalho Chehab 		return -EINVAL;
62943ecec16SMauro Carvalho Chehab 	}
63043ecec16SMauro Carvalho Chehab 	mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
63143ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_GOT_INST &&
63243ecec16SMauro Carvalho Chehab 			buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
63343ecec16SMauro Carvalho Chehab 		ret = vb2_querybuf(&ctx->vq_src, buf);
63443ecec16SMauro Carvalho Chehab 	} else if (ctx->state == MFCINST_RUNNING &&
63543ecec16SMauro Carvalho Chehab 			buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
63643ecec16SMauro Carvalho Chehab 		ret = vb2_querybuf(&ctx->vq_dst, buf);
63743ecec16SMauro Carvalho Chehab 		for (i = 0; i < buf->length; i++)
63843ecec16SMauro Carvalho Chehab 			buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
63943ecec16SMauro Carvalho Chehab 	} else {
64043ecec16SMauro Carvalho Chehab 		mfc_err("vidioc_querybuf called in an inappropriate state\n");
64143ecec16SMauro Carvalho Chehab 		ret = -EINVAL;
64243ecec16SMauro Carvalho Chehab 	}
64343ecec16SMauro Carvalho Chehab 	mfc_debug_leave();
64443ecec16SMauro Carvalho Chehab 	return ret;
64543ecec16SMauro Carvalho Chehab }
64643ecec16SMauro Carvalho Chehab 
64743ecec16SMauro Carvalho Chehab /* Queue a buffer */
vidioc_qbuf(struct file * file,void * priv,struct v4l2_buffer * buf)64843ecec16SMauro Carvalho Chehab static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
64943ecec16SMauro Carvalho Chehab {
65043ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
65143ecec16SMauro Carvalho Chehab 
65243ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_ERROR) {
65343ecec16SMauro Carvalho Chehab 		mfc_err("Call on QBUF after unrecoverable error\n");
65443ecec16SMauro Carvalho Chehab 		return -EIO;
65543ecec16SMauro Carvalho Chehab 	}
65643ecec16SMauro Carvalho Chehab 	if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
65743ecec16SMauro Carvalho Chehab 		return vb2_qbuf(&ctx->vq_src, NULL, buf);
65843ecec16SMauro Carvalho Chehab 	else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
65943ecec16SMauro Carvalho Chehab 		return vb2_qbuf(&ctx->vq_dst, NULL, buf);
66043ecec16SMauro Carvalho Chehab 	return -EINVAL;
66143ecec16SMauro Carvalho Chehab }
66243ecec16SMauro Carvalho Chehab 
66343ecec16SMauro Carvalho Chehab /* Dequeue a buffer */
vidioc_dqbuf(struct file * file,void * priv,struct v4l2_buffer * buf)66443ecec16SMauro Carvalho Chehab static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
66543ecec16SMauro Carvalho Chehab {
66643ecec16SMauro Carvalho Chehab 	const struct v4l2_event ev = {
66743ecec16SMauro Carvalho Chehab 		.type = V4L2_EVENT_EOS
66843ecec16SMauro Carvalho Chehab 	};
66943ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
67043ecec16SMauro Carvalho Chehab 	int ret;
67143ecec16SMauro Carvalho Chehab 
67243ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_ERROR) {
67343ecec16SMauro Carvalho Chehab 		mfc_err_limited("Call on DQBUF after unrecoverable error\n");
67443ecec16SMauro Carvalho Chehab 		return -EIO;
67543ecec16SMauro Carvalho Chehab 	}
67643ecec16SMauro Carvalho Chehab 
67743ecec16SMauro Carvalho Chehab 	switch (buf->type) {
67843ecec16SMauro Carvalho Chehab 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
67943ecec16SMauro Carvalho Chehab 		return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
68043ecec16SMauro Carvalho Chehab 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
68143ecec16SMauro Carvalho Chehab 		ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
68243ecec16SMauro Carvalho Chehab 		if (ret)
68343ecec16SMauro Carvalho Chehab 			return ret;
68443ecec16SMauro Carvalho Chehab 
68543ecec16SMauro Carvalho Chehab 		if (ctx->state == MFCINST_FINISHED &&
68643ecec16SMauro Carvalho Chehab 		    (ctx->dst_bufs[buf->index].flags & MFC_BUF_FLAG_EOS))
68743ecec16SMauro Carvalho Chehab 			v4l2_event_queue_fh(&ctx->fh, &ev);
68843ecec16SMauro Carvalho Chehab 		return 0;
68943ecec16SMauro Carvalho Chehab 	default:
69043ecec16SMauro Carvalho Chehab 		return -EINVAL;
69143ecec16SMauro Carvalho Chehab 	}
69243ecec16SMauro Carvalho Chehab }
69343ecec16SMauro Carvalho Chehab 
69443ecec16SMauro Carvalho Chehab /* Export DMA buffer */
vidioc_expbuf(struct file * file,void * priv,struct v4l2_exportbuffer * eb)69543ecec16SMauro Carvalho Chehab static int vidioc_expbuf(struct file *file, void *priv,
69643ecec16SMauro Carvalho Chehab 	struct v4l2_exportbuffer *eb)
69743ecec16SMauro Carvalho Chehab {
69843ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
69943ecec16SMauro Carvalho Chehab 
70043ecec16SMauro Carvalho Chehab 	if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
70143ecec16SMauro Carvalho Chehab 		return vb2_expbuf(&ctx->vq_src, eb);
70243ecec16SMauro Carvalho Chehab 	if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
70343ecec16SMauro Carvalho Chehab 		return vb2_expbuf(&ctx->vq_dst, eb);
70443ecec16SMauro Carvalho Chehab 	return -EINVAL;
70543ecec16SMauro Carvalho Chehab }
70643ecec16SMauro Carvalho Chehab 
70743ecec16SMauro Carvalho Chehab /* Stream on */
vidioc_streamon(struct file * file,void * priv,enum v4l2_buf_type type)70843ecec16SMauro Carvalho Chehab static int vidioc_streamon(struct file *file, void *priv,
70943ecec16SMauro Carvalho Chehab 			   enum v4l2_buf_type type)
71043ecec16SMauro Carvalho Chehab {
71143ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
71243ecec16SMauro Carvalho Chehab 	int ret = -EINVAL;
71343ecec16SMauro Carvalho Chehab 
71443ecec16SMauro Carvalho Chehab 	mfc_debug_enter();
71543ecec16SMauro Carvalho Chehab 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
71643ecec16SMauro Carvalho Chehab 		ret = vb2_streamon(&ctx->vq_src, type);
71743ecec16SMauro Carvalho Chehab 	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
71843ecec16SMauro Carvalho Chehab 		ret = vb2_streamon(&ctx->vq_dst, type);
71943ecec16SMauro Carvalho Chehab 	mfc_debug_leave();
72043ecec16SMauro Carvalho Chehab 	return ret;
72143ecec16SMauro Carvalho Chehab }
72243ecec16SMauro Carvalho Chehab 
72343ecec16SMauro Carvalho Chehab /* Stream off, which equals to a pause */
vidioc_streamoff(struct file * file,void * priv,enum v4l2_buf_type type)72443ecec16SMauro Carvalho Chehab static int vidioc_streamoff(struct file *file, void *priv,
72543ecec16SMauro Carvalho Chehab 			    enum v4l2_buf_type type)
72643ecec16SMauro Carvalho Chehab {
72743ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
72843ecec16SMauro Carvalho Chehab 
72943ecec16SMauro Carvalho Chehab 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
73043ecec16SMauro Carvalho Chehab 		return vb2_streamoff(&ctx->vq_src, type);
73143ecec16SMauro Carvalho Chehab 	else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
73243ecec16SMauro Carvalho Chehab 		return vb2_streamoff(&ctx->vq_dst, type);
73343ecec16SMauro Carvalho Chehab 	return -EINVAL;
73443ecec16SMauro Carvalho Chehab }
73543ecec16SMauro Carvalho Chehab 
73643ecec16SMauro Carvalho Chehab /* Set controls - v4l2 control framework */
s5p_mfc_dec_s_ctrl(struct v4l2_ctrl * ctrl)73743ecec16SMauro Carvalho Chehab static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
73843ecec16SMauro Carvalho Chehab {
73943ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
74043ecec16SMauro Carvalho Chehab 
74143ecec16SMauro Carvalho Chehab 	switch (ctrl->id) {
74243ecec16SMauro Carvalho Chehab 	case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
74343ecec16SMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
74443ecec16SMauro Carvalho Chehab 		ctx->display_delay = ctrl->val;
74543ecec16SMauro Carvalho Chehab 		break;
74643ecec16SMauro Carvalho Chehab 	case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
74743ecec16SMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
74843ecec16SMauro Carvalho Chehab 		ctx->display_delay_enable = ctrl->val;
74943ecec16SMauro Carvalho Chehab 		break;
75043ecec16SMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
75143ecec16SMauro Carvalho Chehab 		ctx->loop_filter_mpeg4 = ctrl->val;
75243ecec16SMauro Carvalho Chehab 		break;
75343ecec16SMauro Carvalho Chehab 	case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
75443ecec16SMauro Carvalho Chehab 		ctx->slice_interface = ctrl->val;
75543ecec16SMauro Carvalho Chehab 		break;
75643ecec16SMauro Carvalho Chehab 	default:
75743ecec16SMauro Carvalho Chehab 		mfc_err("Invalid control 0x%08x\n", ctrl->id);
75843ecec16SMauro Carvalho Chehab 		return -EINVAL;
75943ecec16SMauro Carvalho Chehab 	}
76043ecec16SMauro Carvalho Chehab 	return 0;
76143ecec16SMauro Carvalho Chehab }
76243ecec16SMauro Carvalho Chehab 
s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl * ctrl)76343ecec16SMauro Carvalho Chehab static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
76443ecec16SMauro Carvalho Chehab {
76543ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
76643ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
76743ecec16SMauro Carvalho Chehab 
76843ecec16SMauro Carvalho Chehab 	switch (ctrl->id) {
76943ecec16SMauro Carvalho Chehab 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
77043ecec16SMauro Carvalho Chehab 		if (ctx->state >= MFCINST_HEAD_PARSED &&
77143ecec16SMauro Carvalho Chehab 		    ctx->state < MFCINST_ABORT) {
77243ecec16SMauro Carvalho Chehab 			ctrl->val = ctx->pb_count;
77343ecec16SMauro Carvalho Chehab 			break;
77443ecec16SMauro Carvalho Chehab 		} else if (ctx->state != MFCINST_INIT &&
77543ecec16SMauro Carvalho Chehab 				ctx->state != MFCINST_RES_CHANGE_END) {
77643ecec16SMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
77743ecec16SMauro Carvalho Chehab 			return -EINVAL;
77843ecec16SMauro Carvalho Chehab 		}
77943ecec16SMauro Carvalho Chehab 		/* Should wait for the header to be parsed */
78043ecec16SMauro Carvalho Chehab 		s5p_mfc_wait_for_done_ctx(ctx,
78143ecec16SMauro Carvalho Chehab 				S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0);
78243ecec16SMauro Carvalho Chehab 		if (ctx->state >= MFCINST_HEAD_PARSED &&
78343ecec16SMauro Carvalho Chehab 		    ctx->state < MFCINST_ABORT) {
78443ecec16SMauro Carvalho Chehab 			ctrl->val = ctx->pb_count;
78543ecec16SMauro Carvalho Chehab 		} else {
78643ecec16SMauro Carvalho Chehab 			v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
78743ecec16SMauro Carvalho Chehab 			return -EINVAL;
78843ecec16SMauro Carvalho Chehab 		}
78943ecec16SMauro Carvalho Chehab 		break;
79043ecec16SMauro Carvalho Chehab 	}
79143ecec16SMauro Carvalho Chehab 	return 0;
79243ecec16SMauro Carvalho Chehab }
79343ecec16SMauro Carvalho Chehab 
79443ecec16SMauro Carvalho Chehab 
79543ecec16SMauro Carvalho Chehab static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
79643ecec16SMauro Carvalho Chehab 	.s_ctrl = s5p_mfc_dec_s_ctrl,
79743ecec16SMauro Carvalho Chehab 	.g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
79843ecec16SMauro Carvalho Chehab };
79943ecec16SMauro Carvalho Chehab 
80043ecec16SMauro Carvalho Chehab /* Get compose information */
vidioc_g_selection(struct file * file,void * priv,struct v4l2_selection * s)80143ecec16SMauro Carvalho Chehab static int vidioc_g_selection(struct file *file, void *priv,
80243ecec16SMauro Carvalho Chehab 			      struct v4l2_selection *s)
80343ecec16SMauro Carvalho Chehab {
80443ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
80543ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
80643ecec16SMauro Carvalho Chehab 	u32 left, right, top, bottom;
80743ecec16SMauro Carvalho Chehab 	u32 width, height;
80843ecec16SMauro Carvalho Chehab 
80943ecec16SMauro Carvalho Chehab 	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
81043ecec16SMauro Carvalho Chehab 		return -EINVAL;
81143ecec16SMauro Carvalho Chehab 
81243ecec16SMauro Carvalho Chehab 	if (ctx->state != MFCINST_HEAD_PARSED &&
81343ecec16SMauro Carvalho Chehab 	    ctx->state != MFCINST_RUNNING &&
81443ecec16SMauro Carvalho Chehab 	    ctx->state != MFCINST_FINISHING &&
81543ecec16SMauro Carvalho Chehab 	    ctx->state != MFCINST_FINISHED) {
81643ecec16SMauro Carvalho Chehab 		mfc_err("Can not get compose information\n");
81743ecec16SMauro Carvalho Chehab 		return -EINVAL;
81843ecec16SMauro Carvalho Chehab 	}
81943ecec16SMauro Carvalho Chehab 	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
82043ecec16SMauro Carvalho Chehab 		left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx);
82143ecec16SMauro Carvalho Chehab 		right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
82243ecec16SMauro Carvalho Chehab 		left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
82343ecec16SMauro Carvalho Chehab 		top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx);
82443ecec16SMauro Carvalho Chehab 		bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
82543ecec16SMauro Carvalho Chehab 		top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
82643ecec16SMauro Carvalho Chehab 		width = ctx->img_width - left - right;
82743ecec16SMauro Carvalho Chehab 		height = ctx->img_height - top - bottom;
82843ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Composing info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n",
82943ecec16SMauro Carvalho Chehab 			  left, top, s->r.width, s->r.height, right, bottom,
83043ecec16SMauro Carvalho Chehab 			  ctx->buf_width, ctx->buf_height);
83143ecec16SMauro Carvalho Chehab 	} else {
83243ecec16SMauro Carvalho Chehab 		left = 0;
83343ecec16SMauro Carvalho Chehab 		top = 0;
83443ecec16SMauro Carvalho Chehab 		width = ctx->img_width;
83543ecec16SMauro Carvalho Chehab 		height = ctx->img_height;
83643ecec16SMauro Carvalho Chehab 		mfc_debug(2, "Composing info: w=%d h=%d fw=%d fh=%d\n",
83743ecec16SMauro Carvalho Chehab 			  s->r.width, s->r.height, ctx->buf_width,
83843ecec16SMauro Carvalho Chehab 			  ctx->buf_height);
83943ecec16SMauro Carvalho Chehab 	}
84043ecec16SMauro Carvalho Chehab 
84143ecec16SMauro Carvalho Chehab 	switch (s->target) {
84243ecec16SMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE:
84343ecec16SMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
84443ecec16SMauro Carvalho Chehab 	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
84543ecec16SMauro Carvalho Chehab 		s->r.left = left;
84643ecec16SMauro Carvalho Chehab 		s->r.top = top;
84743ecec16SMauro Carvalho Chehab 		s->r.width = width;
84843ecec16SMauro Carvalho Chehab 		s->r.height = height;
84943ecec16SMauro Carvalho Chehab 		break;
85043ecec16SMauro Carvalho Chehab 	default:
85143ecec16SMauro Carvalho Chehab 		return -EINVAL;
85243ecec16SMauro Carvalho Chehab 	}
85343ecec16SMauro Carvalho Chehab 	return 0;
85443ecec16SMauro Carvalho Chehab }
85543ecec16SMauro Carvalho Chehab 
vidioc_decoder_cmd(struct file * file,void * priv,struct v4l2_decoder_cmd * cmd)85643ecec16SMauro Carvalho Chehab static int vidioc_decoder_cmd(struct file *file, void *priv,
85743ecec16SMauro Carvalho Chehab 			      struct v4l2_decoder_cmd *cmd)
85843ecec16SMauro Carvalho Chehab {
85943ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
86043ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
86143ecec16SMauro Carvalho Chehab 	struct s5p_mfc_buf *buf;
86243ecec16SMauro Carvalho Chehab 	unsigned long flags;
86343ecec16SMauro Carvalho Chehab 
86443ecec16SMauro Carvalho Chehab 	switch (cmd->cmd) {
86543ecec16SMauro Carvalho Chehab 	case V4L2_DEC_CMD_STOP:
86643ecec16SMauro Carvalho Chehab 		if (cmd->flags != 0)
86743ecec16SMauro Carvalho Chehab 			return -EINVAL;
86843ecec16SMauro Carvalho Chehab 
86943ecec16SMauro Carvalho Chehab 		if (!vb2_is_streaming(&ctx->vq_src))
87043ecec16SMauro Carvalho Chehab 			return -EINVAL;
87143ecec16SMauro Carvalho Chehab 
87243ecec16SMauro Carvalho Chehab 		spin_lock_irqsave(&dev->irqlock, flags);
87343ecec16SMauro Carvalho Chehab 		if (list_empty(&ctx->src_queue)) {
87443ecec16SMauro Carvalho Chehab 			mfc_err("EOS: empty src queue, entering finishing state");
87543ecec16SMauro Carvalho Chehab 			ctx->state = MFCINST_FINISHING;
87643ecec16SMauro Carvalho Chehab 			if (s5p_mfc_ctx_ready(ctx))
87743ecec16SMauro Carvalho Chehab 				set_work_bit_irqsave(ctx);
87843ecec16SMauro Carvalho Chehab 			spin_unlock_irqrestore(&dev->irqlock, flags);
87943ecec16SMauro Carvalho Chehab 			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
88043ecec16SMauro Carvalho Chehab 		} else {
88143ecec16SMauro Carvalho Chehab 			mfc_err("EOS: marking last buffer of stream");
88243ecec16SMauro Carvalho Chehab 			buf = list_entry(ctx->src_queue.prev,
88343ecec16SMauro Carvalho Chehab 						struct s5p_mfc_buf, list);
88443ecec16SMauro Carvalho Chehab 			if (buf->flags & MFC_BUF_FLAG_USED)
88543ecec16SMauro Carvalho Chehab 				ctx->state = MFCINST_FINISHING;
88643ecec16SMauro Carvalho Chehab 			else
88743ecec16SMauro Carvalho Chehab 				buf->flags |= MFC_BUF_FLAG_EOS;
88843ecec16SMauro Carvalho Chehab 			spin_unlock_irqrestore(&dev->irqlock, flags);
88943ecec16SMauro Carvalho Chehab 		}
89043ecec16SMauro Carvalho Chehab 		break;
89143ecec16SMauro Carvalho Chehab 	default:
89243ecec16SMauro Carvalho Chehab 		return -EINVAL;
89343ecec16SMauro Carvalho Chehab 	}
89443ecec16SMauro Carvalho Chehab 	return 0;
89543ecec16SMauro Carvalho Chehab }
89643ecec16SMauro Carvalho Chehab 
vidioc_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)89743ecec16SMauro Carvalho Chehab static int vidioc_subscribe_event(struct v4l2_fh *fh,
89843ecec16SMauro Carvalho Chehab 				const struct  v4l2_event_subscription *sub)
89943ecec16SMauro Carvalho Chehab {
90043ecec16SMauro Carvalho Chehab 	switch (sub->type) {
90143ecec16SMauro Carvalho Chehab 	case V4L2_EVENT_EOS:
90243ecec16SMauro Carvalho Chehab 		return v4l2_event_subscribe(fh, sub, 2, NULL);
90343ecec16SMauro Carvalho Chehab 	case V4L2_EVENT_SOURCE_CHANGE:
90443ecec16SMauro Carvalho Chehab 		return v4l2_src_change_event_subscribe(fh, sub);
90543ecec16SMauro Carvalho Chehab 	default:
90643ecec16SMauro Carvalho Chehab 		return -EINVAL;
90743ecec16SMauro Carvalho Chehab 	}
90843ecec16SMauro Carvalho Chehab }
90943ecec16SMauro Carvalho Chehab 
91043ecec16SMauro Carvalho Chehab 
91143ecec16SMauro Carvalho Chehab /* v4l2_ioctl_ops */
91243ecec16SMauro Carvalho Chehab static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
91343ecec16SMauro Carvalho Chehab 	.vidioc_querycap = vidioc_querycap,
91443ecec16SMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
91543ecec16SMauro Carvalho Chehab 	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
91643ecec16SMauro Carvalho Chehab 	.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
91743ecec16SMauro Carvalho Chehab 	.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
91843ecec16SMauro Carvalho Chehab 	.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
91943ecec16SMauro Carvalho Chehab 	.vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
92043ecec16SMauro Carvalho Chehab 	.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
92143ecec16SMauro Carvalho Chehab 	.vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
92243ecec16SMauro Carvalho Chehab 	.vidioc_reqbufs = vidioc_reqbufs,
92343ecec16SMauro Carvalho Chehab 	.vidioc_querybuf = vidioc_querybuf,
92443ecec16SMauro Carvalho Chehab 	.vidioc_qbuf = vidioc_qbuf,
92543ecec16SMauro Carvalho Chehab 	.vidioc_dqbuf = vidioc_dqbuf,
92643ecec16SMauro Carvalho Chehab 	.vidioc_expbuf = vidioc_expbuf,
92743ecec16SMauro Carvalho Chehab 	.vidioc_streamon = vidioc_streamon,
92843ecec16SMauro Carvalho Chehab 	.vidioc_streamoff = vidioc_streamoff,
92943ecec16SMauro Carvalho Chehab 	.vidioc_g_selection = vidioc_g_selection,
93043ecec16SMauro Carvalho Chehab 	.vidioc_decoder_cmd = vidioc_decoder_cmd,
93143ecec16SMauro Carvalho Chehab 	.vidioc_subscribe_event = vidioc_subscribe_event,
93243ecec16SMauro Carvalho Chehab 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
93343ecec16SMauro Carvalho Chehab };
93443ecec16SMauro Carvalho Chehab 
s5p_mfc_queue_setup(struct vb2_queue * vq,unsigned int * buf_count,unsigned int * plane_count,unsigned int psize[],struct device * alloc_devs[])93543ecec16SMauro Carvalho Chehab static int s5p_mfc_queue_setup(struct vb2_queue *vq,
93643ecec16SMauro Carvalho Chehab 			unsigned int *buf_count,
93743ecec16SMauro Carvalho Chehab 			unsigned int *plane_count, unsigned int psize[],
93843ecec16SMauro Carvalho Chehab 			struct device *alloc_devs[])
93943ecec16SMauro Carvalho Chehab {
94043ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
94143ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
9426f146612SAakarsh Jain 	const struct v4l2_format_info *format;
94343ecec16SMauro Carvalho Chehab 
94443ecec16SMauro Carvalho Chehab 	/* Video output for decoding (source)
94543ecec16SMauro Carvalho Chehab 	 * this can be set after getting an instance */
94643ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_INIT &&
94743ecec16SMauro Carvalho Chehab 	    vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
94843ecec16SMauro Carvalho Chehab 		/* A single plane is required for input */
94943ecec16SMauro Carvalho Chehab 		*plane_count = 1;
95043ecec16SMauro Carvalho Chehab 		if (*buf_count < 1)
95143ecec16SMauro Carvalho Chehab 			*buf_count = 1;
95243ecec16SMauro Carvalho Chehab 		if (*buf_count > MFC_MAX_BUFFERS)
95343ecec16SMauro Carvalho Chehab 			*buf_count = MFC_MAX_BUFFERS;
95443ecec16SMauro Carvalho Chehab 	/* Video capture for decoding (destination)
95543ecec16SMauro Carvalho Chehab 	 * this can be set after the header was parsed */
95643ecec16SMauro Carvalho Chehab 	} else if (ctx->state == MFCINST_HEAD_PARSED &&
95743ecec16SMauro Carvalho Chehab 		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
95843ecec16SMauro Carvalho Chehab 		/* Output plane count is 2 - one for Y and one for CbCr */
9596f146612SAakarsh Jain 		format = v4l2_format_info(ctx->dst_fmt->fourcc);
9606f146612SAakarsh Jain 		if (!format) {
9616f146612SAakarsh Jain 			mfc_err("invalid format\n");
9626f146612SAakarsh Jain 			return -EINVAL;
9636f146612SAakarsh Jain 		}
9646f146612SAakarsh Jain 		*plane_count = format->comp_planes;
9656f146612SAakarsh Jain 
96643ecec16SMauro Carvalho Chehab 		/* Setup buffer count */
96743ecec16SMauro Carvalho Chehab 		if (*buf_count < ctx->pb_count)
96843ecec16SMauro Carvalho Chehab 			*buf_count = ctx->pb_count;
96943ecec16SMauro Carvalho Chehab 		if (*buf_count > ctx->pb_count + MFC_MAX_EXTRA_DPB)
97043ecec16SMauro Carvalho Chehab 			*buf_count = ctx->pb_count + MFC_MAX_EXTRA_DPB;
97143ecec16SMauro Carvalho Chehab 		if (*buf_count > MFC_MAX_BUFFERS)
97243ecec16SMauro Carvalho Chehab 			*buf_count = MFC_MAX_BUFFERS;
97343ecec16SMauro Carvalho Chehab 	} else {
97443ecec16SMauro Carvalho Chehab 		mfc_err("State seems invalid. State = %d, vq->type = %d\n",
97543ecec16SMauro Carvalho Chehab 							ctx->state, vq->type);
97643ecec16SMauro Carvalho Chehab 		return -EINVAL;
97743ecec16SMauro Carvalho Chehab 	}
97843ecec16SMauro Carvalho Chehab 	mfc_debug(2, "Buffer count=%d, plane count=%d\n",
97943ecec16SMauro Carvalho Chehab 						*buf_count, *plane_count);
98043ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_HEAD_PARSED &&
98143ecec16SMauro Carvalho Chehab 	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
98243ecec16SMauro Carvalho Chehab 		psize[0] = ctx->luma_size;
98343ecec16SMauro Carvalho Chehab 		psize[1] = ctx->chroma_size;
9846f146612SAakarsh Jain 		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
9856f146612SAakarsh Jain 				V4L2_PIX_FMT_YVU420M)
9866f146612SAakarsh Jain 			psize[2] = ctx->chroma_size_1;
98743ecec16SMauro Carvalho Chehab 		if (IS_MFCV6_PLUS(dev))
98843ecec16SMauro Carvalho Chehab 			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
98943ecec16SMauro Carvalho Chehab 		else
99043ecec16SMauro Carvalho Chehab 			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
99143ecec16SMauro Carvalho Chehab 		alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
9926f146612SAakarsh Jain 		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
9936f146612SAakarsh Jain 				V4L2_PIX_FMT_YVU420M)
9946f146612SAakarsh Jain 			alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
9956f146612SAakarsh Jain 	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state == MFCINST_INIT) {
99643ecec16SMauro Carvalho Chehab 		psize[0] = ctx->dec_src_buf_size;
99743ecec16SMauro Carvalho Chehab 		alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
99843ecec16SMauro Carvalho Chehab 	} else {
99943ecec16SMauro Carvalho Chehab 		mfc_err("This video node is dedicated to decoding. Decoding not initialized\n");
100043ecec16SMauro Carvalho Chehab 		return -EINVAL;
100143ecec16SMauro Carvalho Chehab 	}
100243ecec16SMauro Carvalho Chehab 	return 0;
100343ecec16SMauro Carvalho Chehab }
100443ecec16SMauro Carvalho Chehab 
s5p_mfc_buf_init(struct vb2_buffer * vb)100543ecec16SMauro Carvalho Chehab static int s5p_mfc_buf_init(struct vb2_buffer *vb)
100643ecec16SMauro Carvalho Chehab {
100743ecec16SMauro Carvalho Chehab 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
100843ecec16SMauro Carvalho Chehab 	struct vb2_queue *vq = vb->vb2_queue;
100943ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
101043ecec16SMauro Carvalho Chehab 	unsigned int i;
101143ecec16SMauro Carvalho Chehab 
101243ecec16SMauro Carvalho Chehab 	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
101343ecec16SMauro Carvalho Chehab 		if (ctx->capture_state == QUEUE_BUFS_MMAPED)
101443ecec16SMauro Carvalho Chehab 			return 0;
101543ecec16SMauro Carvalho Chehab 		for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
101643ecec16SMauro Carvalho Chehab 			if (IS_ERR_OR_NULL(ERR_PTR(
101743ecec16SMauro Carvalho Chehab 					vb2_dma_contig_plane_dma_addr(vb, i)))) {
101843ecec16SMauro Carvalho Chehab 				mfc_err("Plane mem not allocated\n");
101943ecec16SMauro Carvalho Chehab 				return -EINVAL;
102043ecec16SMauro Carvalho Chehab 			}
102143ecec16SMauro Carvalho Chehab 		}
102243ecec16SMauro Carvalho Chehab 		if (vb2_plane_size(vb, 0) < ctx->luma_size ||
102343ecec16SMauro Carvalho Chehab 			vb2_plane_size(vb, 1) < ctx->chroma_size) {
102443ecec16SMauro Carvalho Chehab 			mfc_err("Plane buffer (CAPTURE) is too small\n");
102543ecec16SMauro Carvalho Chehab 			return -EINVAL;
102643ecec16SMauro Carvalho Chehab 		}
10276f146612SAakarsh Jain 		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
10286f146612SAakarsh Jain 				V4L2_PIX_FMT_YVU420M) {
10296f146612SAakarsh Jain 			if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
10306f146612SAakarsh Jain 				mfc_err("Plane buffer (CAPTURE) is too small\n");
10316f146612SAakarsh Jain 				return -EINVAL;
10326f146612SAakarsh Jain 			}
10336f146612SAakarsh Jain 		}
103443ecec16SMauro Carvalho Chehab 		i = vb->index;
103543ecec16SMauro Carvalho Chehab 		ctx->dst_bufs[i].b = vbuf;
103643ecec16SMauro Carvalho Chehab 		ctx->dst_bufs[i].cookie.raw.luma =
103743ecec16SMauro Carvalho Chehab 					vb2_dma_contig_plane_dma_addr(vb, 0);
103843ecec16SMauro Carvalho Chehab 		ctx->dst_bufs[i].cookie.raw.chroma =
103943ecec16SMauro Carvalho Chehab 					vb2_dma_contig_plane_dma_addr(vb, 1);
10406f146612SAakarsh Jain 		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
10416f146612SAakarsh Jain 				V4L2_PIX_FMT_YVU420M) {
10426f146612SAakarsh Jain 			ctx->dst_bufs[i].cookie.raw.chroma_1 =
10436f146612SAakarsh Jain 					vb2_dma_contig_plane_dma_addr(vb, 2);
10446f146612SAakarsh Jain 		}
104543ecec16SMauro Carvalho Chehab 		ctx->dst_bufs_cnt++;
104643ecec16SMauro Carvalho Chehab 	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
104743ecec16SMauro Carvalho Chehab 		if (IS_ERR_OR_NULL(ERR_PTR(
104843ecec16SMauro Carvalho Chehab 					vb2_dma_contig_plane_dma_addr(vb, 0)))) {
104943ecec16SMauro Carvalho Chehab 			mfc_err("Plane memory not allocated\n");
105043ecec16SMauro Carvalho Chehab 			return -EINVAL;
105143ecec16SMauro Carvalho Chehab 		}
105243ecec16SMauro Carvalho Chehab 		if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) {
105343ecec16SMauro Carvalho Chehab 			mfc_err("Plane buffer (OUTPUT) is too small\n");
105443ecec16SMauro Carvalho Chehab 			return -EINVAL;
105543ecec16SMauro Carvalho Chehab 		}
105643ecec16SMauro Carvalho Chehab 
105743ecec16SMauro Carvalho Chehab 		i = vb->index;
105843ecec16SMauro Carvalho Chehab 		ctx->src_bufs[i].b = vbuf;
105943ecec16SMauro Carvalho Chehab 		ctx->src_bufs[i].cookie.stream =
106043ecec16SMauro Carvalho Chehab 					vb2_dma_contig_plane_dma_addr(vb, 0);
106143ecec16SMauro Carvalho Chehab 		ctx->src_bufs_cnt++;
106243ecec16SMauro Carvalho Chehab 	} else {
106343ecec16SMauro Carvalho Chehab 		mfc_err("s5p_mfc_buf_init: unknown queue type\n");
106443ecec16SMauro Carvalho Chehab 		return -EINVAL;
106543ecec16SMauro Carvalho Chehab 	}
106643ecec16SMauro Carvalho Chehab 	return 0;
106743ecec16SMauro Carvalho Chehab }
106843ecec16SMauro Carvalho Chehab 
s5p_mfc_start_streaming(struct vb2_queue * q,unsigned int count)106943ecec16SMauro Carvalho Chehab static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
107043ecec16SMauro Carvalho Chehab {
107143ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
107243ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
107343ecec16SMauro Carvalho Chehab 
107443ecec16SMauro Carvalho Chehab 	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
107543ecec16SMauro Carvalho Chehab 	if (ctx->state == MFCINST_FINISHING ||
107643ecec16SMauro Carvalho Chehab 		ctx->state == MFCINST_FINISHED)
107743ecec16SMauro Carvalho Chehab 		ctx->state = MFCINST_RUNNING;
107843ecec16SMauro Carvalho Chehab 	/* If context is ready then dev = work->data;schedule it to run */
107943ecec16SMauro Carvalho Chehab 	if (s5p_mfc_ctx_ready(ctx))
108043ecec16SMauro Carvalho Chehab 		set_work_bit_irqsave(ctx);
108143ecec16SMauro Carvalho Chehab 	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
108243ecec16SMauro Carvalho Chehab 	return 0;
108343ecec16SMauro Carvalho Chehab }
108443ecec16SMauro Carvalho Chehab 
s5p_mfc_stop_streaming(struct vb2_queue * q)108543ecec16SMauro Carvalho Chehab static void s5p_mfc_stop_streaming(struct vb2_queue *q)
108643ecec16SMauro Carvalho Chehab {
108743ecec16SMauro Carvalho Chehab 	unsigned long flags;
108843ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
108943ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
109043ecec16SMauro Carvalho Chehab 	int aborted = 0;
109143ecec16SMauro Carvalho Chehab 
109243ecec16SMauro Carvalho Chehab 	spin_lock_irqsave(&dev->irqlock, flags);
109343ecec16SMauro Carvalho Chehab 	if ((ctx->state == MFCINST_FINISHING ||
109443ecec16SMauro Carvalho Chehab 		ctx->state ==  MFCINST_RUNNING) &&
109543ecec16SMauro Carvalho Chehab 		dev->curr_ctx == ctx->num && dev->hw_lock) {
109643ecec16SMauro Carvalho Chehab 		ctx->state = MFCINST_ABORT;
109743ecec16SMauro Carvalho Chehab 		spin_unlock_irqrestore(&dev->irqlock, flags);
109843ecec16SMauro Carvalho Chehab 		s5p_mfc_wait_for_done_ctx(ctx,
109943ecec16SMauro Carvalho Chehab 					S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0);
110043ecec16SMauro Carvalho Chehab 		aborted = 1;
110143ecec16SMauro Carvalho Chehab 		spin_lock_irqsave(&dev->irqlock, flags);
110243ecec16SMauro Carvalho Chehab 	}
110343ecec16SMauro Carvalho Chehab 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
110443ecec16SMauro Carvalho Chehab 		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
110543ecec16SMauro Carvalho Chehab 		INIT_LIST_HEAD(&ctx->dst_queue);
110643ecec16SMauro Carvalho Chehab 		ctx->dst_queue_cnt = 0;
110743ecec16SMauro Carvalho Chehab 		ctx->dpb_flush_flag = 1;
110843ecec16SMauro Carvalho Chehab 		ctx->dec_dst_flag = 0;
110943ecec16SMauro Carvalho Chehab 		if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) {
111043ecec16SMauro Carvalho Chehab 			ctx->state = MFCINST_FLUSH;
111143ecec16SMauro Carvalho Chehab 			set_work_bit_irqsave(ctx);
111243ecec16SMauro Carvalho Chehab 			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
111343ecec16SMauro Carvalho Chehab 			spin_unlock_irqrestore(&dev->irqlock, flags);
111443ecec16SMauro Carvalho Chehab 			if (s5p_mfc_wait_for_done_ctx(ctx,
111543ecec16SMauro Carvalho Chehab 				S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
111643ecec16SMauro Carvalho Chehab 				mfc_err("Err flushing buffers\n");
111743ecec16SMauro Carvalho Chehab 			spin_lock_irqsave(&dev->irqlock, flags);
111843ecec16SMauro Carvalho Chehab 		}
111943ecec16SMauro Carvalho Chehab 	} else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
112043ecec16SMauro Carvalho Chehab 		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
112143ecec16SMauro Carvalho Chehab 		INIT_LIST_HEAD(&ctx->src_queue);
112243ecec16SMauro Carvalho Chehab 		ctx->src_queue_cnt = 0;
112343ecec16SMauro Carvalho Chehab 	}
112443ecec16SMauro Carvalho Chehab 	if (aborted)
112543ecec16SMauro Carvalho Chehab 		ctx->state = MFCINST_RUNNING;
112643ecec16SMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->irqlock, flags);
112743ecec16SMauro Carvalho Chehab }
112843ecec16SMauro Carvalho Chehab 
112943ecec16SMauro Carvalho Chehab 
s5p_mfc_buf_queue(struct vb2_buffer * vb)113043ecec16SMauro Carvalho Chehab static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
113143ecec16SMauro Carvalho Chehab {
113243ecec16SMauro Carvalho Chehab 	struct vb2_queue *vq = vb->vb2_queue;
113343ecec16SMauro Carvalho Chehab 	struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
113443ecec16SMauro Carvalho Chehab 	struct s5p_mfc_dev *dev = ctx->dev;
113543ecec16SMauro Carvalho Chehab 	unsigned long flags;
113643ecec16SMauro Carvalho Chehab 	struct s5p_mfc_buf *mfc_buf;
113743ecec16SMauro Carvalho Chehab 
113843ecec16SMauro Carvalho Chehab 	if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
113943ecec16SMauro Carvalho Chehab 		mfc_buf = &ctx->src_bufs[vb->index];
114043ecec16SMauro Carvalho Chehab 		mfc_buf->flags &= ~MFC_BUF_FLAG_USED;
114143ecec16SMauro Carvalho Chehab 		spin_lock_irqsave(&dev->irqlock, flags);
114243ecec16SMauro Carvalho Chehab 		list_add_tail(&mfc_buf->list, &ctx->src_queue);
114343ecec16SMauro Carvalho Chehab 		ctx->src_queue_cnt++;
114443ecec16SMauro Carvalho Chehab 		spin_unlock_irqrestore(&dev->irqlock, flags);
114543ecec16SMauro Carvalho Chehab 	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
114643ecec16SMauro Carvalho Chehab 		mfc_buf = &ctx->dst_bufs[vb->index];
114743ecec16SMauro Carvalho Chehab 		mfc_buf->flags &= ~MFC_BUF_FLAG_USED;
114843ecec16SMauro Carvalho Chehab 		/* Mark destination as available for use by MFC */
114943ecec16SMauro Carvalho Chehab 		spin_lock_irqsave(&dev->irqlock, flags);
115043ecec16SMauro Carvalho Chehab 		set_bit(vb->index, &ctx->dec_dst_flag);
115143ecec16SMauro Carvalho Chehab 		list_add_tail(&mfc_buf->list, &ctx->dst_queue);
115243ecec16SMauro Carvalho Chehab 		ctx->dst_queue_cnt++;
115343ecec16SMauro Carvalho Chehab 		spin_unlock_irqrestore(&dev->irqlock, flags);
115443ecec16SMauro Carvalho Chehab 	} else {
115543ecec16SMauro Carvalho Chehab 		mfc_err("Unsupported buffer type (%d)\n", vq->type);
115643ecec16SMauro Carvalho Chehab 	}
115743ecec16SMauro Carvalho Chehab 	if (s5p_mfc_ctx_ready(ctx))
115843ecec16SMauro Carvalho Chehab 		set_work_bit_irqsave(ctx);
115943ecec16SMauro Carvalho Chehab 	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
116043ecec16SMauro Carvalho Chehab }
116143ecec16SMauro Carvalho Chehab 
11624b9f9109SKrzysztof Kozlowski static const struct vb2_ops s5p_mfc_dec_qops = {
116343ecec16SMauro Carvalho Chehab 	.queue_setup		= s5p_mfc_queue_setup,
116443ecec16SMauro Carvalho Chehab 	.wait_prepare		= vb2_ops_wait_prepare,
116543ecec16SMauro Carvalho Chehab 	.wait_finish		= vb2_ops_wait_finish,
116643ecec16SMauro Carvalho Chehab 	.buf_init		= s5p_mfc_buf_init,
116743ecec16SMauro Carvalho Chehab 	.start_streaming	= s5p_mfc_start_streaming,
116843ecec16SMauro Carvalho Chehab 	.stop_streaming		= s5p_mfc_stop_streaming,
116943ecec16SMauro Carvalho Chehab 	.buf_queue		= s5p_mfc_buf_queue,
117043ecec16SMauro Carvalho Chehab };
117143ecec16SMauro Carvalho Chehab 
get_dec_codec_ops(void)117243ecec16SMauro Carvalho Chehab const struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
117343ecec16SMauro Carvalho Chehab {
117443ecec16SMauro Carvalho Chehab 	return &decoder_codec_ops;
117543ecec16SMauro Carvalho Chehab }
117643ecec16SMauro Carvalho Chehab 
get_dec_queue_ops(void)11774b9f9109SKrzysztof Kozlowski const struct vb2_ops *get_dec_queue_ops(void)
117843ecec16SMauro Carvalho Chehab {
117943ecec16SMauro Carvalho Chehab 	return &s5p_mfc_dec_qops;
118043ecec16SMauro Carvalho Chehab }
118143ecec16SMauro Carvalho Chehab 
get_dec_v4l2_ioctl_ops(void)118243ecec16SMauro Carvalho Chehab const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
118343ecec16SMauro Carvalho Chehab {
118443ecec16SMauro Carvalho Chehab 	return &s5p_mfc_dec_ioctl_ops;
118543ecec16SMauro Carvalho Chehab }
118643ecec16SMauro Carvalho Chehab 
118743ecec16SMauro Carvalho Chehab #define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \
118843ecec16SMauro Carvalho Chehab 						&& V4L2_CTRL_DRIVER_PRIV(x))
118943ecec16SMauro Carvalho Chehab 
s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx * ctx)119043ecec16SMauro Carvalho Chehab int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
119143ecec16SMauro Carvalho Chehab {
119243ecec16SMauro Carvalho Chehab 	struct v4l2_ctrl_config cfg;
119343ecec16SMauro Carvalho Chehab 	int i;
119443ecec16SMauro Carvalho Chehab 
119543ecec16SMauro Carvalho Chehab 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
119643ecec16SMauro Carvalho Chehab 	if (ctx->ctrl_handler.error) {
119743ecec16SMauro Carvalho Chehab 		mfc_err("v4l2_ctrl_handler_init failed\n");
119843ecec16SMauro Carvalho Chehab 		return ctx->ctrl_handler.error;
119943ecec16SMauro Carvalho Chehab 	}
120043ecec16SMauro Carvalho Chehab 
120143ecec16SMauro Carvalho Chehab 	for (i = 0; i < NUM_CTRLS; i++) {
120243ecec16SMauro Carvalho Chehab 		if (IS_MFC51_PRIV(controls[i].id)) {
120343ecec16SMauro Carvalho Chehab 			memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
120443ecec16SMauro Carvalho Chehab 			cfg.ops = &s5p_mfc_dec_ctrl_ops;
120543ecec16SMauro Carvalho Chehab 			cfg.id = controls[i].id;
120643ecec16SMauro Carvalho Chehab 			cfg.min = controls[i].minimum;
120743ecec16SMauro Carvalho Chehab 			cfg.max = controls[i].maximum;
120843ecec16SMauro Carvalho Chehab 			cfg.def = controls[i].default_value;
120943ecec16SMauro Carvalho Chehab 			cfg.name = controls[i].name;
121043ecec16SMauro Carvalho Chehab 			cfg.type = controls[i].type;
121143ecec16SMauro Carvalho Chehab 
121243ecec16SMauro Carvalho Chehab 			cfg.step = controls[i].step;
121343ecec16SMauro Carvalho Chehab 			cfg.menu_skip_mask = 0;
121443ecec16SMauro Carvalho Chehab 
121543ecec16SMauro Carvalho Chehab 			ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
121643ecec16SMauro Carvalho Chehab 					&cfg, NULL);
121743ecec16SMauro Carvalho Chehab 		} else {
121843ecec16SMauro Carvalho Chehab 			ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler,
121943ecec16SMauro Carvalho Chehab 					&s5p_mfc_dec_ctrl_ops,
122043ecec16SMauro Carvalho Chehab 					controls[i].id, controls[i].minimum,
122143ecec16SMauro Carvalho Chehab 					controls[i].maximum, controls[i].step,
122243ecec16SMauro Carvalho Chehab 					controls[i].default_value);
122343ecec16SMauro Carvalho Chehab 		}
122443ecec16SMauro Carvalho Chehab 		if (ctx->ctrl_handler.error) {
122543ecec16SMauro Carvalho Chehab 			mfc_err("Adding control (%d) failed\n", i);
122643ecec16SMauro Carvalho Chehab 			return ctx->ctrl_handler.error;
122743ecec16SMauro Carvalho Chehab 		}
122843ecec16SMauro Carvalho Chehab 		if (controls[i].is_volatile && ctx->ctrls[i])
122943ecec16SMauro Carvalho Chehab 			ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
123043ecec16SMauro Carvalho Chehab 	}
123143ecec16SMauro Carvalho Chehab 	return 0;
123243ecec16SMauro Carvalho Chehab }
123343ecec16SMauro Carvalho Chehab 
s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx * ctx)123443ecec16SMauro Carvalho Chehab void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
123543ecec16SMauro Carvalho Chehab {
123643ecec16SMauro Carvalho Chehab 	int i;
123743ecec16SMauro Carvalho Chehab 
123843ecec16SMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
123943ecec16SMauro Carvalho Chehab 	for (i = 0; i < NUM_CTRLS; i++)
124043ecec16SMauro Carvalho Chehab 		ctx->ctrls[i] = NULL;
124143ecec16SMauro Carvalho Chehab }
124243ecec16SMauro Carvalho Chehab 
s5p_mfc_dec_init(struct s5p_mfc_ctx * ctx)124343ecec16SMauro Carvalho Chehab void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
124443ecec16SMauro Carvalho Chehab {
124543ecec16SMauro Carvalho Chehab 	struct v4l2_format f;
124643ecec16SMauro Carvalho Chehab 	f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
124743ecec16SMauro Carvalho Chehab 	ctx->src_fmt = find_format(&f, MFC_FMT_DEC);
124843ecec16SMauro Carvalho Chehab 	if (IS_MFCV8_PLUS(ctx->dev))
124943ecec16SMauro Carvalho Chehab 		f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
125043ecec16SMauro Carvalho Chehab 	else if (IS_MFCV6_PLUS(ctx->dev))
125143ecec16SMauro Carvalho Chehab 		f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
125243ecec16SMauro Carvalho Chehab 	else
125343ecec16SMauro Carvalho Chehab 		f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT;
125443ecec16SMauro Carvalho Chehab 	ctx->dst_fmt = find_format(&f, MFC_FMT_RAW);
125543ecec16SMauro Carvalho Chehab 	mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n",
125643ecec16SMauro Carvalho Chehab 			ctx->src_fmt, ctx->dst_fmt);
125743ecec16SMauro Carvalho Chehab }
125843ecec16SMauro Carvalho Chehab 
1259