From nobody Thu Oct 2 02:18:05 2025 Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B19B62773F4 for ; Tue, 30 Sep 2025 03:56:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.33 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759204606; cv=none; b=jyZq8lv6kQDt8yn4/LfVFJkxpMIPXAysPrV9KiNHwB5dbh7Qf7QxvqHgM+PHlYLcuhUOWi8M2ZMLHxtH1EVXY6i1Trq8a/S86HpCHT956aj0dg/fzTO1l8tQO8pEb/695v0V3ukc7N+01WvglcJ7tiTiBgAOzIbyEWzgOAx/06g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759204606; c=relaxed/simple; bh=1hK1xI7Dth2UsfpIjbrY6+XpBHv7/X5AFD2XbxT2Pyw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:MIME-Version: Content-Type:References; b=H0yBKgetc9fiN0uJLbAJy9iXpWy/nH2AkA5bPuE8EUcEsr7iKjsKU8gps+N0ZbNu3M1CR1YWJ+M1NHUpUrOWfnNwcGjuZg/q07bBOGUsZyXRE6nqzPnwmFAB4WYPSzFUltw2H1i4hYLrFsOZqZ3ZWQAZEgBP2pQGreKiNdZnUiY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=RYgGLehD; arc=none smtp.client-ip=203.254.224.33 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="RYgGLehD" Received: from epcas5p3.samsung.com (unknown [182.195.41.41]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250930035640epoutp0366155ce486096d360d0d6a338ff38875~p80NaT6ty3111931119epoutp037 for ; Tue, 30 Sep 2025 03:56:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250930035640epoutp0366155ce486096d360d0d6a338ff38875~p80NaT6ty3111931119epoutp037 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1759204600; bh=iZRhKuwFGLe8CYtxJ0WD69+dHVtPRw6ZjzKWW6B4V8o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RYgGLehDs0Im3C23Ayc26xaL/b/FyIUxfibQMgCHZkr1eIYXNXaRwtGGM75mPZvRl db7dv/wg7xkOMfuwSQzza23TR6y6DwgeIg70kHr/FiWcu/fc2K4xumXoktLQOea1LN SFjwHQgL21EvHXakC3v/mGLpKnrJ2UntrheOaFI8= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPS id 20250930035639epcas5p1f669fafdaa861161b71abc062c3b2570~p80MxvNhf1549615496epcas5p1Q; Tue, 30 Sep 2025 03:56:39 +0000 (GMT) Received: from epcas5p3.samsung.com (unknown [182.195.38.92]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4cbPPf1yGQz6B9mB; Tue, 30 Sep 2025 03:56:38 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas5p4.samsung.com (KnoxPortal) with ESMTPA id 20250930035637epcas5p4d52ed2f59e17862cd7d7a650fa01bf44~p80LLtbhp0713607136epcas5p4E; Tue, 30 Sep 2025 03:56:37 +0000 (GMT) Received: from bose.samsungds.net (unknown [107.108.83.9]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250930035633epsmtip153303c9146034a504efb495bc71277c3~p80HpAp4K2885028850epsmtip1k; Tue, 30 Sep 2025 03:56:33 +0000 (GMT) From: Himanshu Dewangan To: mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, sumit.semwal@linaro.org, christian.koenig@amd.com, alim.akhtar@samsung.com, manjun@samsung.com, nagaraju.s@samsung.com, ih0206.lee@samsung.com, jehyung.lee@samsung.com Cc: linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Himanshu Dewangan Subject: [PATCH 18/29] media: mfc: Add V4L2 decoder driver Date: Tue, 30 Sep 2025 09:33:37 +0530 Message-Id: <20250930040348.3702923-19-h.dewangan@samsung.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250930040348.3702923-1-h.dewangan@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250930035637epcas5p4d52ed2f59e17862cd7d7a650fa01bf44 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-542,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250930035637epcas5p4d52ed2f59e17862cd7d7a650fa01bf44 References: <20250930040348.3702923-1-h.dewangan@samsung.com> From: Nagaraju Siddineni Add a V4L2=E2=80=91based decoder for Exynos MFC. - Implement full decoder V4L2 ioctl, control, buffer, and stream handling. - Provide ioctl getter and default format helper. Move the decoder to the standard V4L2 framework, to enable proper media=E2=80=91device registration and user=E2=80=91space i= nteraction. Signed-off-by: Nagaraju Siddineni Signed-off-by: Himanshu Dewangan --- .../platform/samsung/exynos-mfc/Makefile | 2 +- .../samsung/exynos-mfc/mfc_dec_v4l2.c | 1741 +++++++++++++++++ .../samsung/exynos-mfc/mfc_dec_v4l2.h | 22 + 3 files changed, 1764 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.c create mode 100644 drivers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.h diff --git a/drivers/media/platform/samsung/exynos-mfc/Makefile b/drivers/m= edia/platform/samsung/exynos-mfc/Makefile index 9127f2dc4df6..b6b312ae7f22 100644 --- a/drivers/media/platform/samsung/exynos-mfc/Makefile +++ b/drivers/media/platform/samsung/exynos-mfc/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_VIDEO_EXYNOS_MFC) :=3D exynos_mfc.o ccflags-y +=3D -I$(srctree)/$(src) =20 #Dev interface layer -exynos_mfc-y +=3D mfc.o mfc_dec_vb2.o +exynos_mfc-y +=3D mfc.o mfc_dec_v4l2.o mfc_dec_vb2.o #Dev control layer exynos_mfc-y +=3D mfc_rm.o mfc_ctx_ctrl.o mfc_debugfs.o #Core interface layer diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.c b/dri= vers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.c new file mode 100644 index 000000000000..dd59dc352e34 --- /dev/null +++ b/drivers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.c @@ -0,0 +1,1741 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * mfc_dec_v4l2.c + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include "mfc_dec_v4l2.h" +#include "mfc_dec_vb2.h" +#include "mfc_rm.h" + +#include "mfc_core_hwlock.h" + +#include "base/mfc_format.h" +#include "base/mfc_queue.h" +#include "base/mfc_utils.h" +#include "base/mfc_buf.h" +#include "base/mfc_mem.h" + +#define MAX_FRAME_SIZE (2 * SZ_1K * SZ_1K) +static struct v4l2_queryctrl dec_controls[] =3D { + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "H.264 Display Delay", + .minimum =3D -1, + .maximum =3D 32, + .step =3D 1, + .default_value =3D -1, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Mpeg4 Loop Filter Enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Slice Interface Enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Packed PB Enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Frame Tag", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "CRC enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "CRC data", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "CRC data", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Display status", + .minimum =3D 0, + .maximum =3D 3, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Frame type", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Frame pack sei parse flag", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "I frame decoding mode", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Frames per second in 1000x scale", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 60000, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DECODER_IMMEDIATE_DISPLAY, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Immediate Display Enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DECODER_DECODING_TIMESTAMP_MODE, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Decoding Timestamp Mode Enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DECODER_WAIT_DECODING_START, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Wait until buffer setting done", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_GET_VERSION_INFO, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Get MFC version information", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_SET_DUAL_DPB_MODE, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Set Dual DPB mode", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_QOS_RATIO, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "QoS ratio value", + .minimum =3D 20, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 100, + }, + { + .id =3D V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Set dynamic DPB", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_SET_USER_SHARED_HANDLE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Set dynamic DPB", + .minimum =3D 0, + .maximum =3D U16_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_GET_EXT_INFO, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Get extra information", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_SET_BUF_PROCESS_TYPE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Set buffer process type", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_GET_10BIT_INFO, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "10 bit contents information", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_BLACK_BAR_DETECT, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "Set black bar detection option", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_HDR_USER_SHARED_HANDLE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Dynamic HDR10+ SEI metadata", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_AV1_FILM_GRAIN_USER_SHARED_HANDLE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "AV1 Film Grain SEI metadata", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_AV1_FILM_GRAIN_PRESENT, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "AV1 Film Grain presented", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DECODING_ORDER, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "decoding order enable", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_UNCOMP_FMT, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Uncompressed format", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_GET_DISPLAY_DELAY, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "display delay for first frame", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC51_VIDEO_FRAME_POC, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Frame POC", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_SRC_BUF_FLAG, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Buffer flag", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_DST_BUF_FLAG, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Buffer flag", + .minimum =3D INT_MIN, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_SKIP_LAZY_UNMAP, + .type =3D V4L2_CTRL_TYPE_BOOLEAN, + .name =3D "skip lazy unmap", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_VIDEO_PRIORITY, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "priority", + .minimum =3D 0, + .maximum =3D INT_MAX, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_HEIF_MODE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "heif mode", + .minimum =3D 0, + .maximum =3D 1, + .step =3D 1, + .default_value =3D 0, + }, + { + .id =3D V4L2_CID_MPEG_MFC_MULTI_VIEW_ENABLE, + .type =3D V4L2_CTRL_TYPE_INTEGER, + .name =3D "Multi-View Enable", + .minimum =3D 0, + .maximum =3D 2, + .step =3D 1, + .default_value =3D 0, + }, +}; + +#define DEC_NUM_CTRLS ARRAY_SIZE(dec_controls) +/* Find selected format description */ +VISIBLE_IF_KUNIT struct mfc_fmt *__mfc_dec_find_format(struct mfc_ctx *ctx, + unsigned int pixelformat) +{ + struct mfc_dev *dev =3D ctx->dev; + struct mfc_fmt *fmt =3D NULL; + unsigned long i; + + for (i =3D 0; i < MFC_NUM_FORMATS; i++) { + if ((mfc_formats[i].type & MFC_FMT_STREAM) && + !(mfc_formats[i].type & MFC_FMT_DEC)) { + continue; + } + if (mfc_formats[i].fourcc =3D=3D pixelformat) { + fmt =3D (struct mfc_fmt *)&mfc_formats[i]; + break; + } + } + + if (fmt && !dev->pdata->support_10bit && (fmt->type & MFC_FMT_10BIT)) { + mfc_ctx_err("[FRAME] 10bit is not supported\n"); + fmt =3D NULL; + } + if (fmt && !dev->pdata->support_422 && (fmt->type & MFC_FMT_422)) { + mfc_ctx_err("[FRAME] 422 is not supported\n"); + fmt =3D NULL; + } + if (fmt && (fmt->type & MFC_FMT_RGB)) { + mfc_ctx_err("[FRAME] RGB is not supported by decoder\n"); + fmt =3D NULL; + } + if (fmt && (fmt->type & MFC_FMT_STREAM) && + dev->pdata->mfc_resource[fmt->codec_mode].op_core_type =3D=3D MFC_OP_= CORE_NOT_FIXED) { + mfc_ctx_err("[STREAM] %s is not supported\n", fmt->name); + fmt =3D NULL; + } + + return fmt; +} +EXPORT_SYMBOL_IF_KUNIT(__mfc_dec_find_format); + +static struct v4l2_queryctrl *__mfc_dec_get_ctrl(int id) +{ + unsigned long i; + + for (i =3D 0; i < DEC_NUM_CTRLS; ++i) + if (id =3D=3D dec_controls[i].id) + return &dec_controls[i]; + + return NULL; +} + +/* Check whether a ctrl value if correct */ +static int __mfc_dec_check_ctrl_val(struct mfc_ctx *ctx, struct v4l2_contr= ol *ctrl) +{ + struct v4l2_queryctrl *c; + + c =3D __mfc_dec_get_ctrl(ctrl->id); + if (!c) { + mfc_ctx_err("[CTRLS] not supported control id (%#x)\n", ctrl->id); + return -EINVAL; + } + + if (ctrl->value < c->minimum || ctrl->value > c->maximum || + (c->step !=3D 0 && ctrl->value % c->step !=3D 0)) { + mfc_ctx_err("[CTRLS][%s] id: %#x, invalid value (%d)\n", + c->name, ctrl->id, ctrl->value); + return -ERANGE; + } + + mfc_ctx_debug(5, "[CTRLS][%s] id: %#x, value: %d (%#x)\n", + c->name, ctrl->id, ctrl->value, ctrl->value); + + return 0; +} + +/* Query capabilities of the device */ +static int mfc_dec_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, "MFC", sizeof(cap->driver)); + strscpy(cap->card, "decoder", sizeof(cap->card)); + + return 0; +} + +static int __mfc_dec_enum_fmt(struct mfc_dev *dev, struct v4l2_fmtdesc *f, + unsigned int type) +{ + struct mfc_fmt *fmt; + unsigned long i, j =3D 0; + + for (i =3D 0; i < MFC_NUM_FORMATS; ++i) { + if (!(mfc_formats[i].type & type)) + continue; + if (!dev->pdata->support_10bit && (mfc_formats[i].type & MFC_FMT_10BIT)) + continue; + if (!dev->pdata->support_422 && (mfc_formats[i].type & MFC_FMT_422)) + continue; + + if (j =3D=3D f->index) { + fmt =3D &mfc_formats[i]; + strscpy(f->description, fmt->name, + sizeof(f->description)); + f->pixelformat =3D fmt->fourcc; + + return 0; + } + + ++j; + } + + return -EINVAL; +} + +static int mfc_dec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) +{ + struct mfc_dev *dev =3D video_drvdata(file); + + return __mfc_dec_enum_fmt(dev, f, MFC_FMT_FRAME); +} + +static int mfc_dec_enum_fmt_vid_out_mplane(struct file *file, void *prov, + struct v4l2_fmtdesc *f) +{ + struct mfc_dev *dev =3D video_drvdata(file); + + return __mfc_dec_enum_fmt(dev, f, MFC_FMT_STREAM); +} + +static void __mfc_dec_change_format_8bit(struct mfc_ctx *ctx) +{ + u32 org_fmt =3D ctx->dst_fmt->fourcc; + + switch (org_fmt) { + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + /* It is right format */ + break; + case V4L2_PIX_FMT_NV61M: + /* change to CrCb order format */ + ctx->dst_fmt =3D __mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV21M); + break; + default: + ctx->dst_fmt =3D __mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M); + break; + } +} + +static void __mfc_dec_change_format_8bit_422(struct mfc_ctx *ctx) +{ + u32 org_fmt =3D ctx->dst_fmt->fourcc; + + switch (org_fmt) { + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_NV61M: + /* It is right format */ + break; + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_YVU420M: + /* change to CrCb order format */ + ctx->dst_fmt =3D __mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV61M); + break; + default: + ctx->dst_fmt =3D __mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M); + break; + } +} + +static void __mfc_dec_change_format(struct mfc_ctx *ctx) +{ + u32 org_fmt =3D ctx->dst_fmt->fourcc; + + if (ctx->is_422) + __mfc_dec_change_format_8bit_422(ctx); + else + __mfc_dec_change_format_8bit(ctx); + + ctx->raw_buf.num_planes =3D ctx->dst_fmt->num_planes; + if (org_fmt !=3D ctx->dst_fmt->fourcc) + mfc_ctx_info("[FRAME] format is changed to %s\n", ctx->dst_fmt->name); +} + +static void __mfc_dec_set_num_fd_frame(struct mfc_ctx *ctx, + struct v4l2_pix_format_mplane *pix_fmt_mp) +{ + int calc_num_planes; + int num_fd_depth_map =3D 0; + int num_view =3D 1; + int num_fd_sub_view_meta =3D 0; + + if (ctx->multi_view_enable) { + pix_fmt_mp->flags |=3D MFC_FMT_FLAG_MULTI_VIEW; + num_view =3D MFC_NUM_MULTI_VIEW; + num_fd_sub_view_meta =3D MFC_NUM_FD_SUB_VIEW_META; + + // ToDo: Depth is not supported yet. + pix_fmt_mp->flags &=3D ~MFC_FMT_FLAG_DEPTH_MAP; + num_fd_depth_map =3D 0; + + calc_num_planes =3D + (ctx->dst_fmt->mem_planes + num_fd_depth_map) * num_view + + num_fd_sub_view_meta; + } else { + pix_fmt_mp->flags &=3D ~MFC_FMT_FLAG_MULTI_VIEW; + calc_num_planes =3D ctx->dst_fmt->mem_planes; + } + + mfc_set_view_buf_info(ctx, ctx->dst_fmt->mem_planes, + num_fd_depth_map, num_fd_sub_view_meta); + + ctx->num_fd_frame =3D calc_num_planes; + pix_fmt_mp->num_planes =3D calc_num_planes; +} + +static void __mfc_dec_update_pix_format(struct mfc_ctx *ctx, struct v4l2_f= ormat *f) +{ + struct mfc_dec *dec =3D ctx->dec_priv; + struct v4l2_pix_format_mplane *pix_fmt_mp =3D &f->fmt.pix_mp; + struct mfc_raw_info *raw; + int i; + + raw =3D &ctx->raw_buf; + + pix_fmt_mp->width =3D ctx->img_width; + pix_fmt_mp->height =3D ctx->img_height; + __mfc_dec_set_num_fd_frame(ctx, pix_fmt_mp); + + if (dec->is_interlaced) + pix_fmt_mp->field =3D V4L2_FIELD_INTERLACED; + else + pix_fmt_mp->field =3D V4L2_FIELD_NONE; + + /* Set pixelformat to the format in which MFC outputs the decoded frame */ + pix_fmt_mp->pixelformat =3D ctx->dst_fmt->fourcc; + for (i =3D 0; i < ctx->dst_fmt->mem_planes; i++) { + pix_fmt_mp->plane_fmt[i].bytesperline =3D raw->stride[i]; + if (ctx->dst_fmt->mem_planes =3D=3D 1) + pix_fmt_mp->plane_fmt[i].sizeimage =3D raw->total_plane_size; + else + pix_fmt_mp->plane_fmt[i].sizeimage =3D raw->plane_size[i]; + } +} + +/* Get format */ +static int mfc_dec_g_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dev *dev =3D ctx->dev; + struct mfc_core *core; + struct mfc_core_ctx *core_ctx; + struct mfc_dec *dec =3D ctx->dec_priv; + int ret; + + mfc_ctx_debug_enter(); + + /* During g_fmt, context information is need to for only main core */ + core =3D mfc_get_main_core_lock(dev, ctx); + core_ctx =3D core->core_ctx[ctx->num]; + + mfc_debug(2, "dec dst g_fmt, state: %d wait_state: %d\n", + core_ctx->state, ctx->wait_state); + MFC_TRACE_CTX("** DEC g_fmt(state:%d wait_state:%d)\n", + core_ctx->state, ctx->wait_state); + + mutex_lock(&ctx->drc_wait_mutex); + if (dec->disp_drc.disp_res_change) { + __mfc_dec_update_pix_format(ctx, f); + mutex_unlock(&ctx->drc_wait_mutex); + return 0; + } + mutex_unlock(&ctx->drc_wait_mutex); + + if (core_ctx->state =3D=3D MFCINST_GOT_INST || + core_ctx->state =3D=3D MFCINST_RES_CHANGE_INIT || + core_ctx->state =3D=3D MFCINST_RES_CHANGE_FLUSH || + core_ctx->state =3D=3D MFCINST_RES_CHANGE_FLUSH_FINISHED || + core_ctx->state =3D=3D MFCINST_RES_CHANGE_END) { + /* If there is no source buffer to parsing, we can't SEQ_START */ + mutex_lock(&ctx->drc_wait_mutex); + if (((ctx->wait_state & WAIT_G_FMT) !=3D 0) && + mfc_is_queue_count_same(&ctx->buf_queue_lock, + &ctx->src_buf_ready_queue, 0) && + mfc_is_queue_count_same(&ctx->buf_queue_lock, + &core_ctx->src_buf_queue, 0)) { + mfc_err("There is no source buffer to parsing, keep previous resolution= \n"); + mutex_unlock(&ctx->drc_wait_mutex); + return -EAGAIN; + } + mutex_unlock(&ctx->drc_wait_mutex); + + /* + * If the MFC is parsing the header, + * so wait until it is finished. + */ + ret =3D mfc_wait_for_done_core_ctx(core_ctx, MFC_REG_R2H_CMD_SEQ_DONE_RE= T); + if (ret) { + if (core_ctx->int_err =3D=3D MFC_REG_ERR_UNSUPPORTED_FEATURE) { + mfc_err("header parsing failed by unsupported feature\n"); + return -EINVAL; + } + mfc_err("header parsing failed\n"); + return -EAGAIN; + } + } + + if (core_ctx->state >=3D MFCINST_HEAD_PARSED && + core_ctx->state < MFCINST_ABORT) { + if (mfc_check_resolution(ctx)) { + mfc_ctx_err("Unsupported product resolution\n"); + return -EAGAIN; + } + + /* This is run on CAPTURE (decode output) */ + if (ctx->stream_op_mode =3D=3D MFC_OP_TWO_MODE1 || + ctx->stream_op_mode =3D=3D MFC_OP_TWO_MODE2) { + mfc_info("[2CORE] start the sub core\n"); + if (mfc_rm_instance_setup(dev, ctx)) { + mfc_err("[2CORE] failed to setup sub core\n"); + return -EAGAIN; + } + } + + /* + * The format should be changed according to various conditions. + * 1. bit depth (8bit or 10bit) + * 2. chroma order (CbCr or CrCb) + * 3. component in memory (multi or single) + */ + + __mfc_dec_change_format(ctx); + + /* Width and height are set to the dimensions + * of the movie, the buffer is bigger and + * further processing stages should crop to this + * rectangle. + */ + mfc_dec_calc_dpb_size(ctx, &ctx->raw_buf, ctx->dst_fmt); + + if (IS_LOW_MEM) { + unsigned int dpb_size; + /* + * If total memory requirement is too big for this device, + * then it returns error. + * DPB size : Total plane size * the number of DPBs + * 5: the number of extra DPBs + * 3: the number of DPBs for Android framework + * 600MB: being used to return an error, + * when 8K resolution video clip is being tried to be decoded + */ + dpb_size =3D (ctx->raw_buf.total_plane_size * + (ctx->dpb_count + MFC_EXTRA_DPB + 3)); + if (dpb_size > SZ_6M) { + mfc_info("required memory size is too big (%dx%d, dpb: %d)\n", + ctx->img_width, ctx->img_height, ctx->dpb_count); + return -EINVAL; + } + } + + __mfc_dec_update_pix_format(ctx, f); + } + + mutex_lock(&ctx->drc_wait_mutex); + if ((ctx->wait_state & WAIT_G_FMT) !=3D 0) { + ctx->wait_state &=3D ~(WAIT_G_FMT); + mfc_debug(2, "clear WAIT_G_FMT %d\n", ctx->wait_state); + MFC_TRACE_CTX("** DEC clear WAIT_G_FMT(wait_state %d)\n", ctx->wait_stat= e); + } + mutex_unlock(&ctx->drc_wait_mutex); + + mfc_ctx_debug_leave(); + + return 0; +} + +static int mfc_dec_g_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dec *dec =3D ctx->dec_priv; + struct v4l2_pix_format_mplane *pix_fmt_mp =3D &f->fmt.pix_mp; + + mfc_ctx_debug_enter(); + + mfc_ctx_debug(4, "dec src g_fmt\n"); + + /* This is run on OUTPUT + * The buffer contains compressed image + * so width and height have no meaning + */ + pix_fmt_mp->width =3D 0; + pix_fmt_mp->height =3D 0; + pix_fmt_mp->field =3D V4L2_FIELD_NONE; + pix_fmt_mp->plane_fmt[0].bytesperline =3D dec->src_buf_size; + pix_fmt_mp->plane_fmt[0].sizeimage =3D dec->src_buf_size; + pix_fmt_mp->pixelformat =3D ctx->src_fmt->fourcc; + pix_fmt_mp->num_planes =3D ctx->src_fmt->mem_planes; + + mfc_ctx_debug_leave(); + + return 0; +} + +/* Try format */ +static int mfc_dec_try_fmt(struct file *file, void *priv, struct v4l2_form= at *f) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_fmt *fmt; + struct v4l2_pix_format_mplane *pix_fmt_mp =3D &f->fmt.pix_mp; + + fmt =3D __mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat); + if (!fmt) { + mfc_ctx_err("Unsupported format for %s\n", + V4L2_TYPE_IS_OUTPUT(f->type) ? "source" : "destination"); + return -EINVAL; + } + if (f->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && + fmt->codec_mode =3D=3D MFC_FORMATS_NO_CODEC) { + mfc_ctx_err("MFC_FORMATS_NO_CODEC is invalid to src(fmt is %s)\n", + fmt->name); + return -EINVAL; + } + + /* For resource reservation */ + ctx->img_width =3D pix_fmt_mp->width; + ctx->img_height =3D pix_fmt_mp->height; + + if (f->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ctx->src_fmt =3D fmt; + ctx->codec_mode =3D ctx->src_fmt->codec_mode; + ctx->op_core_type =3D ctx->dev->pdata->mfc_resource[ctx->codec_mode].op_= core_type; + } + + mfc_ctx_debug(2, "[%s] resolution %dx%d, %s : %s\n", + V4L2_TYPE_IS_OUTPUT(f->type) ? "STREAM" : "FRAME", + ctx->img_width, ctx->img_height, + V4L2_TYPE_IS_OUTPUT(f->type) ? "codectype" : "pixelformat", fmt->n= ame); + + return 0; +} + +/* Set format */ +static int mfc_dec_s_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct v4l2_pix_format_mplane *pix_fmt_mp =3D &f->fmt.pix_mp; + struct mfc_fmt *fmt =3D NULL; + + mfc_ctx_debug_enter(); + + if (ctx->vq_dst.streaming) { + mfc_ctx_err("queue busy\n"); + return -EBUSY; + } + + fmt =3D __mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat); + if (!fmt) { + mfc_ctx_err("Unsupported format for destination\n"); + return -EINVAL; + } + ctx->dst_fmt =3D fmt; + + if ((!ctx->img_width && !ctx->img_height) && + pix_fmt_mp->width > 0 && pix_fmt_mp->height > 0) { + ctx->img_width =3D pix_fmt_mp->width; + ctx->img_height =3D pix_fmt_mp->height; + } + + ctx->raw_buf.num_planes =3D ctx->dst_fmt->num_planes; + mfc_ctx_info("[FRAME] dec dst pixelformat : %s (%d x %d)\n", + ctx->dst_fmt->name, ctx->img_width, ctx->img_height); + + mfc_ctx_debug_leave(); + + return 0; +} + +static int mfc_dec_s_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mfc_dev *dev =3D video_drvdata(file); + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dec *dec =3D ctx->dec_priv; + struct v4l2_pix_format_mplane *pix_fmt_mp =3D &f->fmt.pix_mp; + struct mfc_fmt *fmt =3D NULL; + int ret =3D 0; + + mfc_ctx_debug_enter(); + + if (ctx->vq_src.streaming) { + mfc_ctx_err("queue busy\n"); + return -EBUSY; + } + + fmt =3D __mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat); + if (!fmt) { + mfc_ctx_err("Unsupported format for source\n"); + return -EINVAL; + } + ctx->src_fmt =3D fmt; + + ctx->codec_mode =3D ctx->src_fmt->codec_mode; + mfc_ctx_info("[STREAM] codectype: %s(%d)\n", + ctx->src_fmt->name, ctx->codec_mode); + + ctx->pix_format =3D pix_fmt_mp->pixelformat; + if (pix_fmt_mp->width > 0 && pix_fmt_mp->height > 0) { + ctx->img_height =3D pix_fmt_mp->height; + ctx->img_width =3D pix_fmt_mp->width; + } + + /* As this buffer will contain compressed data, the size is set + * to the maximum size. + */ + if (pix_fmt_mp->plane_fmt[0].sizeimage) + dec->src_buf_size =3D pix_fmt_mp->plane_fmt[0].sizeimage; + else + dec->src_buf_size =3D MAX_FRAME_SIZE; + mfc_ctx_debug(2, "[STREAM] sizeimage: %d\n", pix_fmt_mp->plane_fmt[0].siz= eimage); + pix_fmt_mp->plane_fmt[0].bytesperline =3D 0; + + ret =3D mfc_rm_instance_open(dev, ctx); + if (ret) + mfc_ctx_err("Failed to instance open\n"); + + mfc_ctx_debug_leave(); + + return ret; +} + +/* Request buffers */ +static int mfc_dec_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct mfc_dev *dev =3D video_drvdata(file); + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dec *dec =3D ctx->dec_priv; + struct mfc_core *core; + struct mfc_core_ctx *core_ctx; + int i, ret =3D 0; + + mfc_ctx_debug_enter(); + + if (reqbufs->memory =3D=3D V4L2_MEMORY_MMAP) { + mfc_ctx_err("Not supported memory type (%d)\n", reqbufs->memory); + return -EINVAL; + } + + if (reqbufs->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_ctx_debug(4, "dec src reqbuf(%d)\n", reqbufs->count); + /* Can only request buffers after + * an instance has been opened. + */ + if (mfc_rm_query_state(ctx, EQUAL, MFCINST_GOT_INST)) { + if (reqbufs->count =3D=3D 0) { + ret =3D vb2_reqbufs(&ctx->vq_src, reqbufs); + ctx->output_state =3D QUEUE_FREE; + return ret; + } + + /* Decoding */ + if (ctx->output_state !=3D QUEUE_FREE) { + mfc_ctx_err("Bufs have already been requested\n"); + return -EINVAL; + } + + ret =3D vb2_reqbufs(&ctx->vq_src, reqbufs); + if (ret) { + mfc_ctx_err("vb2_reqbufs on src failed\n"); + return ret; + } + + ctx->output_state =3D QUEUE_BUFS_REQUESTED; + } + } else if (reqbufs->type =3D=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + mfc_ctx_debug(4, "dec dst reqbuf(%d)\n", reqbufs->count); + if (reqbufs->count =3D=3D 0) { + ret =3D vb2_reqbufs(&ctx->vq_dst, reqbufs); + + if (!dec->inter_res_change) { + for (i =3D 0; i < MFC_CORE_TYPE_NUM; i++) { + if (ctx->op_core_num[i] =3D=3D MFC_CORE_INVALID) + break; + core =3D dev->core[ctx->op_core_num[i]]; + + core_ctx =3D core->core_ctx[ctx->num]; + mfc_release_codec_buffers(core_ctx); + } + } + ctx->capture_state =3D QUEUE_FREE; + return ret; + } + + if (ctx->capture_state !=3D QUEUE_FREE) { + mfc_ctx_err("Bufs have already been requested\n"); + return -EINVAL; + } + + ret =3D vb2_reqbufs(&ctx->vq_dst, reqbufs); + if (ret) { + mfc_ctx_err("vb2_reqbufs on capture failed\n"); + return ret; + } + + if (reqbufs->count < ctx->dpb_count) { + mfc_ctx_err("Not enough buffers allocated\n"); + reqbufs->count =3D 0; + vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; + } + + dec->total_dpb_count =3D reqbufs->count; + + if (!dec->inter_res_change) { + for (i =3D 0; i < MFC_CORE_TYPE_NUM; i++) { + if (ctx->op_core_num[i] =3D=3D MFC_CORE_INVALID) + break; + + core =3D dev->core[ctx->op_core_num[i]]; + core_ctx =3D core->core_ctx[ctx->num]; + ret =3D mfc_alloc_codec_buffers(core_ctx); + if (ret) { + mfc_err("Failed to allocate decoding buffers\n"); + reqbufs->count =3D 0; + vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; + } + } + } + + ctx->capture_state =3D QUEUE_BUFS_REQUESTED; + + mfc_rm_request_work(dev, MFC_WORK_TRY, ctx); + } + + mfc_ctx_debug_leave(); + + return ret; +} + +/* Query buffer */ +static int mfc_dec_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + int ret; + + mfc_ctx_debug_enter(); + + if (buf->type =3D=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + mfc_ctx_debug(4, "dec dst querybuf\n"); + ret =3D vb2_querybuf(&ctx->vq_dst, buf); + if (ret !=3D 0) { + mfc_ctx_err("dec dst: error in vb2_querybuf()\n"); + return ret; + } + } else if (buf->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_ctx_debug(4, "dec src querybuf\n"); + ret =3D vb2_querybuf(&ctx->vq_src, buf); + if (ret !=3D 0) { + mfc_ctx_err("dec src: error in vb2_querybuf()\n"); + return ret; + } + } else { + mfc_ctx_err("invalid buf type (%d)\n", buf->type); + return -EINVAL; + } + + mfc_ctx_debug_leave(); + + return ret; +} + +/* Queue a buffer */ +static int mfc_dec_qbuf(struct file *file, void *priv, struct v4l2_buffer = *buf) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dev *dev =3D ctx->dev; + int ret =3D -EINVAL; + + mfc_ctx_debug_enter(); + + if (mfc_rm_query_state(ctx, EQUAL_OR, MFCINST_ERROR)) { + mfc_ctx_err("Call on QBUF after unrecoverable error\n"); + return -EIO; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) { + mfc_ctx_err("Invalid V4L2 Buffer for driver: type(%d)\n", buf->type); + return -EINVAL; + } + + if (!buf->length) { + mfc_ctx_err("multiplanar but length is zero\n"); + return -EIO; + } + + if (buf->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_ctx_debug(4, "dec src buf[%d] Q\n", buf->index); + if (buf->m.planes[0].bytesused > buf->m.planes[0].length) { + mfc_ctx_err("data size (%d) %s(%d)\n", + buf->m.planes[0].bytesused, + "must be less than buffer size", + buf->m.planes[0].length); + return -EIO; + } + + mfc_idle_update_queued(dev, ctx); + mfc_rate_update_bitrate(ctx, buf->m.planes[0].bytesused); + mfc_rate_update_bufq_framerate(ctx, MFC_TS_SRC_Q); + mfc_rate_update_framerate(ctx); + mfc_rm_qos_control(ctx, MFC_QOS_TRIGGER); + + if (!buf->m.planes[0].bytesused) { + buf->m.planes[0].bytesused =3D buf->m.planes[0].length; + mfc_ctx_debug(2, "Src size zero, changed to buf size %d\n", + buf->m.planes[0].bytesused); + } else { + mfc_ctx_debug(2, "Src size, %d, buf length, %d\n", + buf->m.planes[0].bytesused, + buf->m.planes[0].length); + } + + ret =3D vb2_qbuf(&ctx->vq_src, NULL, buf); + } else { + mfc_ctx_debug(4, "dec dst buf[%d] Q\n", buf->index); + mfc_idle_update_queued(dev, ctx); + mfc_rate_update_bufq_framerate(ctx, MFC_TS_DST_Q); + mfc_rate_update_framerate(ctx); + mfc_rm_qos_control(ctx, MFC_QOS_TRIGGER); + ret =3D vb2_qbuf(&ctx->vq_dst, NULL, buf); + } + + mfc_ctx_debug_leave(); + return ret; +} + +/* Dequeue a buffer */ +static int mfc_dec_dqbuf(struct file *file, void *priv, struct v4l2_buffer= *buf) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dec *dec =3D ctx->dec_priv; + struct dec_dpb_ref_info *dst_buf, *src_buf; + int ret; + int ncount =3D 0; + + mfc_ctx_debug_enter(); + + if (mfc_rm_query_state(ctx, EQUAL, MFCINST_ERROR)) { + mfc_ctx_err("Call on DQBUF after unrecoverable error\n"); + return -EIO; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) { + mfc_ctx_err("Invalid V4L2 Buffer for driver: type(%d)\n", buf->type); + return -EINVAL; + } + + if (buf->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret =3D vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); + mfc_ctx_debug(4, "dec src buf[%d] DQ\n", buf->index); + } else { + ret =3D vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); + mfc_ctx_debug(4, "dec dst buf[%d] DQ\n", buf->index); + + if (buf->index >=3D MFC_MAX_BUFFERS) { + mfc_ctx_err("buffer index[%d] range over\n", buf->index); + return -EINVAL; + } + + /* Memcpy from dec->ref_info to shared memory */ + if (dec->ref_info) { + src_buf =3D &dec->ref_info[buf->index]; + for (ncount =3D 0; ncount < MFC_MAX_BUFFERS; ncount++) { + if (src_buf->dpb[ncount].fd[0] =3D=3D MFC_INFO_INIT_FD) + break; + mfc_ctx_debug(2, "[REFINFO] DQ index[%d] Released FD =3D %d\n", + buf->index, src_buf->dpb[ncount].fd[0]); + } + + if (dec->sh_handle_dpb.vaddr) { + dst_buf =3D (struct dec_dpb_ref_info *) + dec->sh_handle_dpb.vaddr + buf->index; + memcpy(dst_buf, src_buf, sizeof(struct dec_dpb_ref_info)); + dst_buf->index =3D buf->index; + } + } + } + mfc_ctx_debug_leave(); + return ret; +} + +/* Stream on */ +static int mfc_dec_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + int ret =3D -EINVAL; + + mfc_ctx_debug_enter(); + + if (type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_ctx_debug(4, "dec src streamon\n"); + ret =3D vb2_streamon(&ctx->vq_src, type); + } else if (type =3D=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + mfc_ctx_debug(4, "dec dst streamon\n"); + ret =3D vb2_streamon(&ctx->vq_dst, type); + if (!ret) + mfc_rm_qos_control(ctx, MFC_QOS_ON); + } else { + mfc_ctx_err("unknown v4l2 buffer type\n"); + } + + mfc_ctx_debug(2, "src: %d, dst: %d, dpb_count =3D %d\n", + mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_ready_queu= e), + mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue), + ctx->dpb_count); + + mfc_ctx_debug_leave(); + + return ret; +} + +/* Stream off, which equals to a pause */ +static int mfc_dec_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + int ret =3D -EINVAL; + + mfc_ctx_debug_enter(); + + if (type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_ctx_debug(4, "dec src streamoff\n"); + ret =3D vb2_streamoff(&ctx->vq_src, type); + } else if (type =3D=3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + mfc_ctx_debug(4, "dec dst streamoff\n"); + mfc_rate_reset_bufq_framerate(ctx); + ret =3D vb2_streamoff(&ctx->vq_dst, type); + if (!ret) + mfc_rm_qos_control(ctx, MFC_QOS_OFF); + } else { + mfc_ctx_err("unknown v4l2 buffer type\n"); + } + + mfc_ctx_debug_leave(); + + return ret; +} + +static int __mfc_dec_ext_info(struct mfc_ctx *ctx) +{ + struct mfc_dev *dev =3D ctx->dev; + int val =3D 0; + + val |=3D DEC_SET_DYNAMIC_DPB; + val |=3D DEC_SET_C2_INTERFACE; + val |=3D DEC_SET_BUF_FLAG_CTRL; + val |=3D DEC_SET_FRAME_ERR_TYPE; + val |=3D DEC_SET_OPERATING_FPS; + val |=3D DEC_SET_PRIORITY; + + if (MFC_FEATURE_SUPPORT(dev, dev->pdata->skype)) + val |=3D DEC_SET_SKYPE_FLAG; + + mfc_ctx_debug(5, "[CTRLS] ext info val: %#x\n", val); + + return val; +} + +/* Get ctrl */ +static int __mfc_dec_get_ctrl_val(struct mfc_ctx *ctx, struct v4l2_control= *ctrl) +{ + struct mfc_dev *dev =3D ctx->dev; + struct mfc_core *core; + struct mfc_core_ctx *core_ctx; + struct mfc_dec *dec =3D ctx->dec_priv; + struct mfc_ctx_ctrl *ctx_ctrl; + int found =3D 0; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: + ctrl->value =3D dec->loop_filter_mpeg4; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: + ctrl->value =3D dec->display_delay; + break; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + /* These context information is need to for only main core */ + core =3D mfc_get_main_core_lock(dev, ctx); + core_ctx =3D core->core_ctx[ctx->num]; + + if (core_ctx->state >=3D MFCINST_HEAD_PARSED && + core_ctx->state < MFCINST_ABORT) { + ctrl->value =3D ctx->dpb_count; + break; + } else if (core_ctx->state !=3D MFCINST_INIT) { + mfc_err("Decoding not initialised\n"); + return -EINVAL; + } + + /* Should wait for the header to be parsed */ + if (mfc_wait_for_done_core_ctx(core_ctx, + MFC_REG_R2H_CMD_SEQ_DONE_RET)) { + core->sched->yield_work(core, core_ctx); + return -EIO; + } + + if (core_ctx->state >=3D MFCINST_HEAD_PARSED && + core_ctx->state < MFCINST_ABORT) { + ctrl->value =3D ctx->dpb_count; + } else { + mfc_err("Decoding not initialised\n"); + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: + ctrl->value =3D dec->slice_enable; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB: + /* Not used */ + break; + case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE: + ctrl->value =3D dec->crc_enable; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE: + core =3D mfc_get_main_core_lock(dev, ctx); + core_ctx =3D core->core_ctx[ctx->num]; + if (ctx->is_dpb_realloc && + mfc_rm_query_state(ctx, EQUAL, MFCINST_HEAD_PARSED)) + ctrl->value =3D MFCSTATE_DEC_S3D_REALLOC; + else if (core_ctx->state =3D=3D MFCINST_RES_CHANGE_FLUSH || + core_ctx->state =3D=3D MFCINST_RES_CHANGE_END || + core_ctx->state =3D=3D MFCINST_HEAD_PARSED || + dec->inter_res_change) + ctrl->value =3D MFCSTATE_DEC_RES_DETECT; + else if (mfc_rm_query_state(ctx, EQUAL, MFCINST_FINISHING)) + ctrl->value =3D MFCSTATE_DEC_TERMINATING; + else + ctrl->value =3D MFCSTATE_PROCESSING; + break; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: + ctrl->value =3D dec->sei_parse; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING: + ctrl->value =3D dec->idr_decoding; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE: + ctrl->value =3D mfc_rate_get_framerate(ctx); + break; + case V4L2_CID_MPEG_MFC_GET_VERSION_INFO: + ctrl->value =3D dev->pdata->ip_ver; + break; + case V4L2_CID_MPEG_VIDEO_QOS_RATIO: + ctrl->value =3D ctx->qos_ratio; + break; + case V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE: + ctrl->value =3D dec->is_dynamic_dpb; + break; + case V4L2_CID_MPEG_MFC_GET_EXT_INFO: + ctrl->value =3D __mfc_dec_ext_info(ctx); + break; + case V4L2_CID_MPEG_MFC_GET_DRIVER_INFO: + ctrl->value =3D MFC_DRIVER_INFO; + break; + case V4L2_CID_MPEG_VIDEO_UNCOMP_FMT: + if (dec->uncomp_fmt) + ctrl->value =3D dec->uncomp_fmt->fourcc; + else + ctrl->value =3D 0; + break; + case V4L2_CID_MPEG_VIDEO_GET_DISPLAY_DELAY: + /* These context information is need to for only main core */ + core =3D mfc_get_main_core_lock(dev, ctx); + core_ctx =3D core->core_ctx[ctx->num]; + if (core_ctx->state >=3D MFCINST_HEAD_PARSED) { + ctrl->value =3D dec->frame_display_delay; + } else { + mfc_err("display delay information not parsed yet\n"); + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_PRIORITY: + ctrl->value =3D ctx->prio; + mfc_ctx_debug(2, "[PRIO] user get priority: %d (%d)\n", + ctrl->value, ctx->user_prio); + break; + case V4L2_CID_MPEG_MFC_MULTI_VIEW_ENABLE: + ctrl->value =3D (ctx->multi_view_enable || ctx->ready_to_be_multi_view_e= nable); + break; + default: + list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) { + if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET)) + continue; + + if (ctx_ctrl->id =3D=3D ctrl->id) { + if (ctx_ctrl->get.has_new) { + ctx_ctrl->get.has_new =3D 0; + ctrl->value =3D ctx_ctrl->get.val; + } else { + mfc_ctx_debug(5, "[CTRLS] %s: 0x%08x\n", + "Control value is not up to date", + ctrl->id); + return -EINVAL; + } + + found =3D 1; + break; + } + } + + if (!found) { + mfc_ctx_err("Invalid control: 0x%08x\n", ctrl->id); + return -EINVAL; + } + break; + } + + mfc_ctx_debug(5, "[CTRLS] get id: %#x, value: %d\n", ctrl->id, ctrl->valu= e); + + return 0; +} + +/* Set a ctrl */ +static int mfc_dec_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dec *dec =3D ctx->dec_priv; + struct mfc_ctx_ctrl *ctx_ctrl; + int ret =3D 0; + int found =3D 0; + + mfc_ctx_debug_enter(); + + ret =3D __mfc_dec_check_ctrl_val(ctx, ctrl); + if (ret) + return ret; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: + dec->loop_filter_mpeg4 =3D ctrl->value; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: + dec->display_delay =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: + dec->slice_enable =3D ctrl->value; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB: + /* Not used */ + break; + case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE: + dec->crc_enable =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: + dec->sei_parse =3D ctrl->value; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING: + dec->idr_decoding =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_DECODER_IMMEDIATE_DISPLAY: + dec->immediate_display =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_DECODER_DECODING_TIMESTAMP_MODE: + dec->is_dts_mode =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_DECODER_WAIT_DECODING_START: + mutex_lock(&ctx->drc_wait_mutex); + ctx->wait_state =3D ctrl->value; + mutex_unlock(&ctx->drc_wait_mutex); + break; + case V4L2_CID_MPEG_MFC_SET_DUAL_DPB_MODE: + mfc_ctx_err("[DPB] not supported CID: 0x%x\n", ctrl->id); + break; + case V4L2_CID_MPEG_VIDEO_QOS_RATIO: + ctx->qos_ratio =3D ctrl->value; + mfc_ctx_info("[QoS] set %d qos_ratio\n", ctrl->value); + break; + case V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE: + /* is_dynamic_dpb is controlled by driver */ + if (dec->is_dynamic_dpb =3D=3D 0) + mfc_ctx_debug(2, "[PLUGIN] is_dynamic_dpb is disabled by driver\n"); + if (!ctrl->value) + mfc_ctx_err("[DPB] user has to enable is_dynamic_dpb by default\n"); + break; + case V4L2_CID_MPEG_MFC_SET_USER_SHARED_HANDLE: + if (dec->sh_handle_dpb.fd =3D=3D -1) { + dec->sh_handle_dpb.fd =3D ctrl->value; + if (mfc_mem_get_user_shared_handle(ctx, &dec->sh_handle_dpb, "DPB")) + return -EINVAL; + } + break; + case V4L2_CID_MPEG_MFC_SET_BUF_PROCESS_TYPE: + ctx->buf_process_type =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_BLACK_BAR_DETECT: + dec->detect_black_bar =3D ctrl->value; + if (IS_BLACKBAR_OFF(ctx)) { + mfc_ctx_info("[BLACKBAR] black bar detection doesn't work\n"); + dec->detect_black_bar =3D 0; + } + break; + case V4L2_CID_MPEG_VIDEO_DECODING_ORDER: + dec->decoding_order =3D ctrl->value; + break; + case V4L2_CID_MPEG_VIDEO_SKIP_LAZY_UNMAP: + ctx->skip_lazy_unmap =3D ctrl->value; + mfc_ctx_debug(2, "[LAZY_UNMAP] lazy unmap %s\n", + ctx->skip_lazy_unmap ? "disable" : "enable"); + break; + case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE: + mfc_ctx_debug(2, "[QoS] user set the operating frame rate: %d\n", ctrl->= value); + ctx->operating_framerate =3D ctrl->value; + mfc_rm_update_real_time(ctx); + break; + case V4L2_CID_MPEG_VIDEO_PRIORITY: + mfc_ctx_debug(2, "[PRIO] user set priority: %d\n", ctrl->value); + ctx->user_prio =3D ctrl->value; + mfc_rm_update_real_time(ctx); + break; + case V4L2_CID_MPEG_MFC_HEIF_MODE: + mfc_ctx_debug(2, "[HEIF] heif mode: %d\n", ctrl->value); + ctx->is_heif_mode =3D ctrl->value; + break; + default: + list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) { + if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET)) + continue; + + if (ctx_ctrl->id =3D=3D ctrl->id) { + ctx_ctrl->set.has_new =3D 1; + ctx_ctrl->set.val =3D ctrl->value; + + found =3D 1; + break; + } + } + + if (!found) { + mfc_ctx_err("Invalid control: 0x%08x\n", ctrl->id); + return -EINVAL; + } + break; + } + + mfc_ctx_debug_leave(); + + return 0; +} + +static int mfc_dec_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct v4l2_ext_control *ext_ctrl; + struct v4l2_control ctrl; + int i; + int ret =3D 0; + + if (f->which !=3D V4L2_CTRL_CLASS_CODEC && f->which !=3D V4L2_CTRL_CLASS_= USER) + return -EINVAL; + + for (i =3D 0; i < f->count; i++) { + ext_ctrl =3D (f->controls + i); + + ctrl.id =3D ext_ctrl->id; + ctrl.value =3D ext_ctrl->value; + + ret =3D mfc_dec_s_ctrl(file, priv, &ctrl); + if (ret !=3D 0) { + f->error_idx =3D i; + break; + } + mfc_ctx_debug(5, "[CTRLS] set id: %#x, value: %d\n", ctrl.id, ctrl.value= ); + } + + return 0; +} + +static void __mfc_dec_update_disp_res(struct mfc_ctx *ctx, struct v4l2_sel= ection *s) +{ + struct mfc_dec *dec =3D ctx->dec_priv; + + s->r.left =3D 0; + s->r.top =3D 0; + s->r.width =3D dec->disp_drc.width[dec->disp_drc.pop_idx]; + s->r.height =3D dec->disp_drc.height[dec->disp_drc.pop_idx]; + mfc_ctx_debug(2, "[FRAME] Composing info: w=3D%d h=3D%d\n", s->r.width, s= ->r.height); + + dec->disp_drc.disp_res_change--; + mfc_ctx_debug(3, "[DRC] disp_res_change[%d] count %d\n", + dec->disp_drc.pop_idx, dec->disp_drc.disp_res_change); + dec->disp_drc.pop_idx =3D (dec->disp_drc.pop_idx + 1) % MFC_MAX_DRC_FRAME; + + if (!dec->disp_drc.disp_res_change) { + dec->disp_drc.push_idx =3D 0; + dec->disp_drc.pop_idx =3D 0; + } + + /* + * Do not clear WAIT_G_FMT except RUNNING state + * because the resolution change (DRC) case uses WAIT_G_FMT + */ + if (mfc_rm_query_state(ctx, EQUAL, MFCINST_RUNNING) && + (ctx->wait_state & WAIT_G_FMT) !=3D 0) { + ctx->wait_state &=3D ~(WAIT_G_FMT); + mfc_ctx_debug(2, "clear WAIT_G_FMT %d\n", ctx->wait_state); + MFC_TRACE_CTX("** DEC clear WAIT_G_FMT(wait_state %d)\n", ctx->wait_stat= e); + } +} + +/* Get cropping information */ +static int mfc_dec_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct mfc_dev *dev =3D ctx->dev; + struct mfc_core *core; + struct mfc_core_ctx *core_ctx; + struct mfc_dec *dec =3D ctx->dec_priv; + + mfc_ctx_debug_enter(); + + if (s->type !=3D V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + core =3D mfc_get_main_core_lock(dev, ctx); + core_ctx =3D core->core_ctx[ctx->num]; + + mutex_lock(&ctx->drc_wait_mutex); + if (dec->disp_drc.disp_res_change) { + __mfc_dec_update_disp_res(ctx, s); + mutex_unlock(&ctx->drc_wait_mutex); + return 0; + } + mutex_unlock(&ctx->drc_wait_mutex); + + if (!NEED_TO_GET_CROP(core_ctx)) { + mfc_err("ready to get compose failed\n"); + return -EINVAL; + } + + if (mfc_rm_query_state(ctx, EQUAL, MFCINST_RUNNING) && + dec->detect_black_bar && dec->black_bar_updated) { + s->r.left =3D dec->black_bar.left; + s->r.top =3D dec->black_bar.top; + s->r.width =3D dec->black_bar.width; + s->r.height =3D dec->black_bar.height; + mfc_debug(2, "[FRAME][BLACKBAR] Cropping info: l=3D%d t=3D%d w=3D%d h=3D= %d\n", + dec->black_bar.left, + dec->black_bar.top, + dec->black_bar.width, + dec->black_bar.height); + } else { + if (ctx->src_fmt->fourcc =3D=3D V4L2_PIX_FMT_H264 || + ctx->src_fmt->fourcc =3D=3D V4L2_PIX_FMT_HEVC) { + s->r.left =3D dec->cr_left; + s->r.top =3D dec->cr_top; + s->r.width =3D ctx->img_width - dec->cr_left - dec->cr_right; + s->r.height =3D ctx->img_height - dec->cr_top - dec->cr_bot; + mfc_debug(2, "[FRAME] %s: l=3D%d t=3D%d w=3D%d h=3D%d (r=3D%d b=3D%d fw= =3D%d fh=3D%d)\n", + "Composing info", s->r.left, s->r.top, s->r.width, s->r.height, + dec->cr_right, dec->cr_bot, ctx->img_width, ctx->img_height); + } else { + s->r.left =3D 0; + s->r.top =3D 0; + s->r.width =3D ctx->img_width; + s->r.height =3D ctx->img_height; + mfc_debug(2, "[FRAME] Composing info: w=3D%d h=3D%d fw=3D%d fh=3D%d\n", + s->r.width, s->r.height, + ctx->img_width, ctx->img_height); + } + } + + mfc_ctx_debug_leave(); + return 0; +} + +static int mfc_dec_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *f) +{ + struct mfc_ctx *ctx =3D fh_to_mfc_ctx(file->private_data); + struct v4l2_ext_control *ext_ctrl; + struct v4l2_control ctrl; + int i; + int ret =3D 0; + + if (f->which !=3D V4L2_CTRL_CLASS_CODEC && f->which !=3D V4L2_CTRL_CLASS_= USER) + return -EINVAL; + + for (i =3D 0; i < f->count; i++) { + ext_ctrl =3D (f->controls + i); + + ctrl.id =3D ext_ctrl->id; + + ret =3D __mfc_dec_get_ctrl_val(ctx, &ctrl); + if (ret =3D=3D 0) { + ext_ctrl->value =3D ctrl.value; + } else { + f->error_idx =3D i; + break; + } + + mfc_ctx_debug(5, "[CTRLS][%d] id: %#x, value: %d\n", + i, ext_ctrl->id, ext_ctrl->value); + } + + return ret; +} + +/* Initialize for default format */ +void mfc_dec_set_default_format(struct mfc_ctx *ctx) +{ + struct mfc_fmt *fmt =3D NULL; + + /* Set default format for source */ + fmt =3D __mfc_dec_find_format(ctx, V4L2_PIX_FMT_H264); + if (!fmt) { + /* NEVER come here */ + mfc_ctx_err("Wrong memory access. Set fmt by mfc_formats[0]\n"); + fmt =3D &mfc_formats[0]; + } + ctx->src_fmt =3D fmt; + + /* Set default format for destination */ + fmt =3D __mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M); + if (!fmt) { + /* NEVER come here */ + mfc_ctx_err("Wrong memory access. Set fmt by mfc_formats[0]\n"); + fmt =3D &mfc_formats[0]; + } + ctx->dst_fmt =3D fmt; +} + +/* v4l2_ioctl_ops */ +static const struct v4l2_ioctl_ops mfc_dec_ioctl_ops =3D { + .vidioc_querycap =3D mfc_dec_querycap, + .vidioc_enum_fmt_vid_cap =3D mfc_dec_enum_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_out =3D mfc_dec_enum_fmt_vid_out_mplane, + .vidioc_g_fmt_vid_cap_mplane =3D mfc_dec_g_fmt_vid_cap_mplane, + .vidioc_g_fmt_vid_out_mplane =3D mfc_dec_g_fmt_vid_out_mplane, + .vidioc_try_fmt_vid_cap_mplane =3D mfc_dec_try_fmt, + .vidioc_try_fmt_vid_out_mplane =3D mfc_dec_try_fmt, + .vidioc_s_fmt_vid_cap_mplane =3D mfc_dec_s_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_out_mplane =3D mfc_dec_s_fmt_vid_out_mplane, + .vidioc_reqbufs =3D mfc_dec_reqbufs, + .vidioc_querybuf =3D mfc_dec_querybuf, + .vidioc_qbuf =3D mfc_dec_qbuf, + .vidioc_dqbuf =3D mfc_dec_dqbuf, + .vidioc_streamon =3D mfc_dec_streamon, + .vidioc_streamoff =3D mfc_dec_streamoff, + .vidioc_s_ext_ctrls =3D mfc_dec_s_ext_ctrls, + .vidioc_g_selection =3D mfc_dec_g_selection, + .vidioc_g_ext_ctrls =3D mfc_dec_g_ext_ctrls, +}; + +const struct v4l2_ioctl_ops *mfc_get_dec_v4l2_ioctl_ops(void) +{ + return &mfc_dec_ioctl_ops; +} diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.h b/dri= vers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.h new file mode 100644 index 000000000000..04652a71cd23 --- /dev/null +++ b/drivers/media/platform/samsung/exynos-mfc/mfc_dec_v4l2.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * + * mfc_dec_v4l2.h + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __MFC_DEC_V4L2_H +#define __MFC_DEC_V4L2_H __FILE__ + +#include "base/mfc_common.h" + +const struct v4l2_ioctl_ops *mfc_get_dec_v4l2_ioctl_ops(void); +void mfc_dec_set_default_format(struct mfc_ctx *ctx); + +#endif /* __MFC_DEC_V4L2_H */ --=20 2.34.1