From patchwork Mon Feb 10 09:07:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967498 Received: from SEVP216CU002.outbound.protection.outlook.com (mail-koreacentralazon11022096.outbound.protection.outlook.com [40.107.43.96]) (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 7633254782; Mon, 10 Feb 2025 09:07:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.43.96 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178460; cv=fail; b=HaoC+d1C0f7yQPf3tdDq9fJWC7GBpnhAKXifYEiywa6sQNY4PVTQgRpxGRqlP7LQNlNpzNb6FkyCr9wJH6GcH0HgxnbaBtVyNpnrTmo8md3CjCwz9hNa+MYomlg//jRyST45nWggFxARYVI3yr/T0LatXg2Xsp97WMloaNM6oXQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178460; c=relaxed/simple; bh=38YHO0ws86KoSyuI9T4FzVJNMaznDBO2GD1MFdDXzEk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=N8v5dZEFnelwM/kuB11QWuTo5h2bEAPxWu46lrymvjCULVOT9plWR5UmNjnuvgyDr3IBxFMvloNtx/TLLaDp15n157oUvUDdzhyzSxbEyYCEOSZs6jLlFwcotwFdh2CeO1ijSw/4IcnGiySoDHIL7HX8kYGdnmikHblNHXw1cvE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=XLQbkgmK; arc=fail smtp.client-ip=40.107.43.96 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="XLQbkgmK" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=xGtUEpigxLqgO9D9HYEIMwLi/EoCesf02wtCJOD9wD1g0NY6rjRSLErmVwYFI1JDdcHItXlYZNVU7RguS92YYWD4rOx0Xw1z/fKhCndMK639icnHZDeS93IPeUHKAZ0l+JSYwbiXrciAKMztcsvAo2pPGrwvyRguywvyO0+72KZZy6fVZcXYXWLbywESqAA4LdAYf0y2kOPoLUfmFLcAFbavvOtgtnEMVMi7dRDH5geTnhU9xhf4qiNtcm0+bkBCwH1OcBfpHtHCNcLFc0nAuAbVdRA8P4PGflV5f05QP92CvCUkyirA+cAhVb9beA7TwquyjW5luDWQS11/XmHelQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=dK/BtXiEDvWm0pigTCDTnLxycfOnIYLDZ82rzRezuBE=; b=ejd7R4v5XWgH4JKDTOIwulQ3+DzccAHjAZK7IfrsxRKsYhAGq8VIi8cX3IdKaOk+2Y18U36WjhK7mNTmaNSjtz/PixSMzZy+aIqj9hQtknI7Lx8n8smwoBmQy7mewasRYBCkY+CvVHLq45Lj4dVlG+Ct9SPr+fEgP5bBIFcgTYvMt5F0JFaaGZpdghQc96tJB2h1+F//u9vOl/42D2QBhMpiE6ab3McCYtyIJOop7tr5CMn8cpR40gxmXVfewNpnUciPjyH8Opkt5Ke6+U5WussijOWAoBpEo1HQxQ1Ij5CLSFWnp3vcUzVDY3NIISudPakhAeksFDrqOppjYM8C2w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=dK/BtXiEDvWm0pigTCDTnLxycfOnIYLDZ82rzRezuBE=; b=XLQbkgmKQMAudsDDZdvRriT+Q/pVN9JsE7vFV8knyQ+wmfsYnebZID7ArZRykkp/ND/uisvbH2tOb7Nw2/KuP/pM426B2a6sCv1mxFeQ95o6crJTMkCXA6GI/HJ8muStx3gOLRg465L8BdmWrrx5QYjeVNft/k+LM0JEATA3bRs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:34 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:34 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 1/8] media: platform: chips-media: wave5: Rename Kconfig parameter Date: Mon, 10 Feb 2025 18:07:18 +0900 Message-Id: <20250210090725.4580-2-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: 4a3ccc61-a884-4b0e-275d-08dd49b25b9a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: BiCIi0uF72IaipvwkPt8mF3R220N9CXRnDSAGHNnqWYVvpOeEkWFtSzbNN+E1s0fmXpqnIp9tbvQAu3swNeNzc5t+MVcm8xhkHZFYriQsdA6mXCqoZAmL1zCVSNRCfshjlW9Di3dDYd7L89vW+wnaY15opJ/cyTqCEjywV5dQpJqtKDZbCoMmb+fMWORxbaGPmw8wxNeKMUiOiLPcq31l3j5ydTQQJakVYNDvVwWTuboxWff52gGBl7kV82GeixBn171Gh2hN0QaQIK9RDLXNk893qkt6z4IRJ1niLLBt5CqeDOsCtyIu7NTceBz8eRE4vBmJPQD4jGYs5bhU8DrHhnszb2yZOjgqUGTT2tII18ihZtVrsv7h6StdCdukuQEOcMOyiWq8eS4K0ME3t257otrJvjbZ3ShswH26uNFDxRIgsw003srv0MewrrqiEEtB2hBQJvuAWAs2FNbSTjHJQYLBKfp0TOefqYV+lsndBDbO7H0AgCPLX2rzpbGkrkGITQVkJaV7z1s60vPxPwMLMOvuSLZQIftZnE6T7g4nYFk7+jflXVF6ygaOVOcfw1xxzCNWzvgqfj1qtX42smWoefoJdAcpzgj1dx/6UfRXZkChmx9og/TUexnUINKKxdZirZZ+zLNhWId0r4HTgsVMcrmPZHddcV5hN/9ezUv3yiTJzq61yjJs92EU3pgAR2i5S6geiznGmylLq/mZy+UbYGxxTv3iFlYgm54KwuAWR4QeJGXgK6IEsbjexf79znqr+NfMTWOfiA4lIHZ0xVeFMfOMYFmFDle4HzPCrrMnhewEqjUWdd6Rz8aS31X72wUT52z64XcP6RXvgkyshZ7eruOlH38x2aKdVagtuwvYhP4HC6QWNGTZ6EAbosyWZTE+825E7y0sSXc2LDIt5+tboyGozu6UdP06mN1wswCeTH+iAsEpa3saa07Sab2xKHhhK4jeibxdk6fVnbOXbJBPhFDOdP4yCxw73ZnlNRGNlgCRmDm+xZjnv7sMBR3etShRQPWSNw/TfF9Flz+e09Qr8V5rpiTdSFd4qqyKA/V4vq8IYzI81aXjw7GWJjR6Nqdqm4Q4s9qodCxyXfa7RdxcbW1yGwfmc2B5TSExj+YqvtTjwZOj7xsJmHjsuD4Ivaz5d6Z0rLM0AO9cUan3tbnMMlGcOgH2QQEPeYYIaaBT+IbWckpMNxZe2xJ+DINAVszV4tnkEfswWNT1kh4qw3WqmJztQq9QXxssQvBKC7WoEcexJT72iaMd6uEs/4eJR0VN+//4l5g25QM0RG2o+onYx3PQ3aqGViQXkzbICxVUkxlkUpW89hDZu15QkKPIkmrelBc+q91Jef0u504k/JJWwBHekQWInak7uYOCRurBuB7XqLhRKzkRRmyIUgDMCnOdLkVIvoe5GSk5AfivEDftxB91VWBJNy6henmCeSQiSy9gWynDy7MCGHg5XETCgD3 X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Sd3MNbeyE1+1YDj7BZBw1BB1W1VPeAgs82kO91gsvhuShDnBTHBPOvXyJIHr21h2UFtoUsrPtBjfey15PzX9m5RxKMyKmUlUZRjz0IS7Cs3YeqQVMBTjFEiABhcxD+em3uM7VvMmK3YkOZEWasBMo9HmeswaDYTbOnApcSM4RxocX62sXH+FtcfeOOsvC+L/DwNtFvIOFjcKBLZBmM8lj20gUKYug9hogj17hsUscXMlNXGIdVi8AJzeDtgjBTAtCTpmE0qsRqKhZUr4FUaXFiTEhmCfIALQfYDj/YQKLwmbJUNmB8gawFSIls5bU7QNIl/8cJRh/kxiL/i1p7z9p2Gh7akMLHeu9p4ALXHDFTR6uEB9/LWIpRG81UQir/hGVSzg5PxwJspbEBERtdpSTGir7apbAozOjM9dogeB5dWIgNo0BkB7wWFl6eVP0noBk6lQhysyeeo/qZ+2UPQnXtNhodSxYopRSbhDnN+xNHzS1xI95Mtyq21KW1m8aH0bF112+efzddDZdX+ij5pJvDdVvGYPMwndSSRL+ptxpk9Nq02PrgiIASeotQOrek5JPOu9U+FhkN1TYnMlNXo4mOzWZqyVJvHCTpVe1hBT1Q/EyTAhnA2BnfOqMT/uK4egwC38ddK32zoGrWyyUuMsYJ732mcCbbj/Qve+Ome9sDzS1qH4h9iLcQHm61ybauZ5M2U0SeRNKCdfgPPRpCVHakM5+8aN2r/1anlPYHUsi60+COhfTVT2kVFWZbxkzp4YUoOQh35puYbsPOjldQdbw2hq319KkluaT8mCnmcNqbLpw3rY7UAvnuZAFJ5tLzfxAq17Hzto/dcZaBTm7tYX9MQkWRtZyRGailUqncBdTgYocsd6zAi8MwcRKRU7SBHEu8wmPZYv9sLCSvAeZgTnhK86/uc2pvjxPcfKnC8TCC+gNdAXZB3FJLqv7KhoaWxYs0a0D+LGg+JlbXyoO60cxAZWnGf3YZE7r34RAXu1ukbf8lp0pP8hU3nPz0UeUXXchpqJ4HxwTd0FongKO4flBv/zsKjNwwGIPiIsH3iZThzHmVSUKTRA3afRv6WBAafh1+bIPQalX9UTOozPvNcx8fxb6I0fjkgJA2qA6oFsfGTADtL1XJsJs36F5dFFHpo5GvS0gnanVdbZZ16Crb2p6HdUOmhJPV9cIU64aw0BiH4uY2VD4UhmXuVD3daTnoW1TY17v5wKajR8xEROZu0ZTm3DiN8I0IM1JTUjnh/C9oS6CdsVWCRgYtz+1q/DcjHMMuthPfIvvspqr5HpzWGSCwUYajLN3dnHJ+caDb9c3hYtqM2QgapQ9G92XV2elicvm+VcMEEWUK5NvV2MIXNvmLQoKt4zWFwgep4prNtzupbFlF6ApEefzdT9wEOfrAg22WRh4eMIQMeiTXO8la80hpYhUrpgFHxgfHyx+sQrzjcKM/MGvx7ABNVJs/kkS1XimViHq9QIA6JbXEwAhV+CWTFvTgFk4GdbO786/ojvFcCeRb4QwQEAxCDK6IC0k/VN9pJqt1BYfH9L3dLDzpjMPOHI01BtxUqMGrFqBI570caMMaWLf2oJ/5FVl9+LVbKqqfI/TXa8agphipkJy5wBpQ== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4a3ccc61-a884-4b0e-275d-08dd49b25b9a X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:34.7737 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: fH/zslY8cXNJDapQpWpKtgAT7wVFM3TSrhzrMH/zCIMPoR7aFjFHs1m7G8mr52KdSOq3Ent0sJJBLXLGKujo5ZguTog0Ic4Mh4/K5l7xbpU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 The existing Kconfig parameter VIDEO_WAVE_VPU is ambiguous, as it does not clearly indicate that it is specific to the Wave5 IP. Rename VIDEO_WAVE_VPU to VIDEO_WAVE5_VPU to make it explicit that the parameter is specific to the Wave5 IP. No functional changes, only the parameter name is updated. Signed-off-by: Nas Chung --- arch/arm64/configs/defconfig | 2 +- drivers/media/platform/chips-media/wave5/Kconfig | 6 +++--- drivers/media/platform/chips-media/wave5/Makefile | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index cb7da4415599..d904d4dc4f0d 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -837,7 +837,7 @@ CONFIG_VIDEO_AMPHION_VPU=m CONFIG_VIDEO_CADENCE_CSI2RX=m CONFIG_VIDEO_MEDIATEK_JPEG=m CONFIG_VIDEO_MEDIATEK_VCODEC=m -CONFIG_VIDEO_WAVE_VPU=m +CONFIG_VIDEO_WAVE5_VPU=m CONFIG_VIDEO_E5010_JPEG_ENC=m CONFIG_VIDEO_IMX7_CSI=m CONFIG_VIDEO_IMX_MIPI_CSIS=m diff --git a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig index f1bcef5177bd..914720a35de8 100644 --- a/drivers/media/platform/chips-media/wave5/Kconfig +++ b/drivers/media/platform/chips-media/wave5/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -config VIDEO_WAVE_VPU - tristate "Chips&Media Wave Codec Driver" +config VIDEO_WAVE5_VPU + tristate "Chips&Media Wave5 Codec Driver" depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV && OF depends on ARCH_K3 || COMPILE_TEST @@ -9,7 +9,7 @@ config VIDEO_WAVE_VPU select V4L2_MEM2MEM_DEV select GENERIC_ALLOCATOR help - Chips&Media stateful encoder and decoder driver. + Chips&Media Wave5 stateful encoder and decoder driver. The driver supports HEVC and H264 formats. To compile this driver as modules, choose M here: the modules will be called wave5. diff --git a/drivers/media/platform/chips-media/wave5/Makefile b/drivers/media/platform/chips-media/wave5/Makefile index 3d738a03bd8e..81be0e1dcebd 100644 --- a/drivers/media/platform/chips-media/wave5/Makefile +++ b/drivers/media/platform/chips-media/wave5/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_WAVE_VPU) += wave5.o +obj-$(CONFIG_VIDEO_WAVE5_VPU) += wave5.o wave5-objs += wave5-hw.o \ wave5-vpuapi.o \ wave5-vdi.o \ From patchwork Mon Feb 10 09:07:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967500 Received: from SEVP216CU002.outbound.protection.outlook.com (mail-koreacentralazon11022096.outbound.protection.outlook.com [40.107.43.96]) (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 2BD031C3F04; Mon, 10 Feb 2025 09:07:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.43.96 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178464; cv=fail; b=b7Gpk5MsbY22F0c/G+fEhgOZiN4Wcw5dxPKQUJQ0fM5K/0s+zOhd4E3cGEJ+BNeEzJpxCbxJm/QAdwtQ6342Y9jlLLJVERoSTLYK1KDvMwLUK2ST4lRvlMITDdEnLNwi5tR6MLiDHNfS7kPQUctsEbj3OmQeN0J4bNA0SHInrWg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178464; c=relaxed/simple; bh=EL6I+B3DQlVYM3bTGatVd+LRQmvjN8xAiOQ7/yD3ixY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=HZjuUhfDq8DK4ug3nvcewxTwRZruhn9VdGdOf9wHvYyCWaHCsqY3z7ypj5JNAo9RH5QvrQ/z00Z8Zf8GYrvyplzM0uz3mXypZXbMIYYKn+Gs3kA3248kLqFu7MiEyMEuGgy+UQpezVatzAF/NALA0T4YWc8rW+tFfyI3sjJj6wo= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=hRUruTpb; arc=fail smtp.client-ip=40.107.43.96 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="hRUruTpb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=VLlAGZgSRWGTBAT0ywlK9erpcgJX/mHCQiDdV/BaxqE6LVUc0bcFte/sK4b5b7PZLzQqBFJEhFtwPB0N0gzLFSW6UD4kNLOr+GY3PaAkqsp9Le9KePt8eEsS9MfpvENPSuVKVN9RoGjGu4laFJu8fXAgxtGFHgAPc19XtmbdK2UKy+wSjia78go7ixLcTMDkSy14HNjeR/995xuLCRAl84RXKRloGw6L48bhy3Bq0PfIwkQMv6upHFK2NtcUJVJWIWNfpNEmdHwAotjTADzjpjiqFtL23eJRpV2+z7lk5/IPf252D91/sDngdvM2lgYtH88DhYdNYrVqJh5b17G7Lg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Z08WkIm2BfVz2YoMz28Gbh0LdZPBv1XGCmRkc78GgF0=; b=lShl4vypofbUxaGoNTlP60e1lT/t7OafWReeb+pBEb1BvkoqVJ7AgKIiddlWN69yQ/qcuuHcwoU6YOmgonhOxQ9/50s34TQ3hEOwngwhYQJh9gkRZUuYDnhT2cYGKJ/CJL1AC0vCvMEWE1O01ImZx0HVZb99XoYA4Q1nxppKkEjf1iqCPheYMyMnKAnvScYqUw8n+0EIXjqb3WnKcFLESUiQCJSoez0dpBKwRoWf3lXDFLke1ODesqeuIijaTzbCfkvEK4PfRTne7UDC2QRcr/SQ5vgHbjGU30dXwy3145jjxodRrs6dI4EPL8btXfnhmDYVUZnEdrw8YVKVdoYBvw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Z08WkIm2BfVz2YoMz28Gbh0LdZPBv1XGCmRkc78GgF0=; b=hRUruTpbNVRBVRj+hdnTa/A8xYXqwgJZqIdTTV2e2NLO95bx2dTqiq5h4+RgY47PPdGFw7GyA9zcXd5UC32FXwU4mniMkWhjQtpkIXDNkmxiPQAudFcuUvZF8hQly8r/4OkyHheaot6wTZz6nSsJwi2dDMQxsRVOe4AVw3J2xo4= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:35 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:35 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 2/8] media: v4l2-common: Add YUV24 format info Date: Mon, 10 Feb 2025 18:07:19 +0900 Message-Id: <20250210090725.4580-3-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: d388269e-077e-44d1-5fb8-08dd49b25c0e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: e3tU15C6nVb6bHs0VSMxwEQIE0gp/sLHRg70dwwV0GabY+9NLwYCbNJ+lcE9OQ8HzNkE3WWxrLWVfnhjMp4NakXYfD9rv9v7WI5Yfhf2011HoU1Mi9Hd0rfw4tmufj3K3i0MRH9xEPNXPwVrcN5hFjLYtRxNAPav95S640AIu8hAYK2PoL2trmVEjxoWrpLn/zOhuha7rLieo9LCYFNM7x1CKUHekk9LqAPoFbpeL9xeI97Ug1dt35LiUocCziJMoW1yNIh9g9pk2ieCCdiHkYdxadd5VJnnRkq+z8uLrqW85OnvohskpTjXH9RGoLx9YD6OvDWB8PgU9UV4UOI9nPH6Zvoj8avncqqKIr6tJZRPZsGrw2jhySFDcgqKeO9nhE/o7ru0HVqcn+iDKKD61gfR/m0XRmFSdWJGWWG/GcIdz1Uzt1cvktKqUgxuk9zWTSFQyqOqXknVZH9yEvjVUk7b2d/z9ZMnvPnDdYJ9gg8JyAR0OKOxwo4vRMeTMU+MPlKDbzjoICPt32jtM8ApD4JOjjhg1qgrqwM8gpKCjvqt6wGN9BwXWZf6by46yp5LEoxqf2TLVJV1K1R4vHOWrx06yCQ6FBB19TkisqrX7CvYZPTQZcEbOmhS05WYnZP5zjkCBxP5QuxIxL6AifQiRKwrPFO3ZyQnagXDv5fUjbLX0D9/TBVAfR+SNWZevpIka+opD882sNVepLsPDj1osgwHMLGumgnIsr4/tX9HID/44zvermiYwkWVFH8xgNkd+OMn1f+ky8A3Bkyd95kzkWuZ1wdOQaZxTFt3clX4UYGT5ArASzVqTq5TCLUph+8RkTp0QYBunXyVMCPiRW8O0eGz69mkotXxN1Iixt2IbO/iYFXyxvzLniha+mBBqZs880XVxvENdMd/FMcZSIbE9IBlz0KOfEYpdIr8DFehaax4/J3T6QgBk3+3tXI35iXPz3LbYF/rg55qMpZihYBIgWHHfZ11XB/e39DqtPvh3VO9Pn48BDr45nSSsAeAbSK00mTEUHWURt0JgNKGPUrCTFSAjt0uJQTbuuGAA02cwf6uwD0hOWAJX3ZNbXRGdz/8gveVAJu/FAgUvL2ktrjikzlBLnp28sFLQoz/CDeCXi4WPUqg/pvu+SH155vwWrF2EB7wmeBpOaL0b/EFuWIocpCNV/76ZbLYrP2fDtbHKjF3bJCnEzfAvZvRNBvG48RtIYc/kdd7sbA+1jyq7B63u4hyLByvlLBM1xvckdsGhwKhyBLoBj8qyZmojbCmK0Bm4V8kOdZ/4rm2hfcevo3Zqbz68TfTNkanMa4nu1VuUBdzuZvhvH9F3/CyJn7ClIXgitIKdCK7D8ViavT1hcE1tU/Bh91/NbvkqDfN5jEutS51BmHhWHmtZhCVdtqwNGH1awg0WcXuwwOcSC1MtH0wkQ5cQl/bmk0/Yz1wxzDnp6i+jHaqGnbZtn2FbK1v1c52 X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: A/l+PZbBOGdOkXTdhD96a+WTPlEEbGwtgo7VDifHezgnMjznQQ5M9hTdGAZMzeQXgblOpvtEUOaNV/5ZE7xnMRqs2gIGolUzJhdfOspJxqncyp08sTMF82nMGZmEUCCSHDDmKlaaFbp4P4N82npdf4xllgGJpgmcDFR9xesIbA4ZDZPWKODm+w9AKUHnN2UpWQRsP6kQVjGyYe0YLaQ9L1+b6efrjT3hOsSqKJ4eNgrlTem8m92jihmsotVmsrkOHBVsccigXKfu/iQ8XCb1JeVYPVegwtcScLOMyP4ez7ZkFXTnMBa46SU+fUBwDskJGy61PVwb/EdIxqCj+WC2U1RpN3PFh4DzntVs5rUy7TpcTS1qf1TccvkQc5s4gEyM4Qv7w+YgmEVQer01CWkKSlgv674b52tXvvb/2Jg89LKl6u/1ROAcQL85xTWW9MZj/EgActkyZdDAmxq/xCANgv6bz0/UwoFpeGOP8xihom6oIgwx50jHVW0MP4jKOVuw/SlE+2NvH4FBLepBptUcYQrhF+5vJehgXozaH+UU0I/8n+aQPJRLc2nVzv9Q93UduhyLtYnx/UoSsLjRou0PrGRSnLw/y8osS7QVqa78UIk0dUEhw43x6bN61+tVhDhN3ATSrDWbs13auv92K5B9EJU2lG2BuMnFWJ4L+EhY8lp6gE9cl4pPi/lFUv2NgG7ql0tfGGY6hHSfFNHMYFVdH3zSfhdfxMWl+ZpWpx6Mz3c2KLobsbX8ZQ/WVgOcifPwory3uHasUNZ9YqAaNF3Tm9FRzlbcFDPTlTB2T4F4Mq7x7yurvGq0a4Lj8Zn/kGxd97ygdfCMLaJAbd/pJrmKxeTQyo6DX7QjCJklls0xJwTDd1/GSrK7pOm0Kw5hA5TORv2N33Vp0fQeFwxtmxY2Z1b6dlp+ijurcDfMs+NAA7MNLlYn2J0WVepe0x1bQ9TDcy7HONoc3zwb1L1WdgWgg4OUT0EO5pdgYituzix+gRnCWNaoZP/dOIY21DZwLwuUhR4JcwPdXFefDhLu4SH8fu2bCE6sm9sEeBpJ5BqBEREmosymtOwfGV13UiduuCq8LGXkKqWhNJfvNM+gOhwuTD0M5HMIunAYNM4KbVQJhpb0z39IO0Az/U7zjanNaytRqzN3CC92iva+PT47d5pdDh+ardrUzV9hugCuJuK0NqWUP3DVFC4EUphmKiw63kGRG9C/PkON5S8tt9j3nsdTICOOAMVjZsecMTUA0toZEu6wVybr+raWJOjqyFnunw2+gCvgxaRd8q14YFVJtbkOQjTrjfyVrTldjeGKLQoI0OjG8lX9hjRb+u5eIz7fgo5a4OYkhavejYPwiya6nHO6n/iktRsdXeaS47jhuQzJEfKMj3toeJmjpKEExEYwsXnmnaamedz6WqaZS5grl8DDn5/otaWLGjKWpn/PsA/pgIv1r6AcmcHJSRS5brRbpKgFVG1HY1FWIGdYLY/tNlkEb1/gjGgd5z0wSG3HHNXm4GtnV87955CbcEdmLY6SUm6JZTb6TNA9bTCBahXLujGgSHy2oNAr+N7qrhr3GrSHUdiyBvElhSB5GC9t/c/C3KdvVuBiycxijgtkuuGsZa+kew== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: d388269e-077e-44d1-5fb8-08dd49b25c0e X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:35.4800 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: CEyG24g57veWVJaNDuEnMQwyYbivMqr1eNM+yH1P2tDTaISw1mwriglCQs15xYuQDckFniRR4Dt3G+XNVaoaRs4guYk2phb0qkhCS1JjM6A= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 The YUV24 format is missing an entry in the v4l2_format_info(). The YUV24 format is the packed YUV 4:4:4 formats with 8 bits per component. Signed-off-by: Nas Chung --- drivers/media/v4l2-core/v4l2-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 0a2f4f0d0a07..de3636f1cdf1 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -269,6 +269,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_Y212, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_Y216, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_YUV48_12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_MT2110T, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2, .block_w = { 16, 8, 0, 0 }, .block_h = { 32, 16, 0, 0 }}, { .format = V4L2_PIX_FMT_MT2110R, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2, From patchwork Mon Feb 10 09:07:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967502 Received: from SE2P216CU007.outbound.protection.outlook.com (mail-koreacentralazon11021140.outbound.protection.outlook.com [40.107.42.140]) (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 167DD1C5D4C; Mon, 10 Feb 2025 09:07:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.42.140 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178467; cv=fail; b=DWIqGF8Bnjba483nWCJy6Eg6SlKnQqKwc+fyjf6/6apBut+qy5VxJYEHA7LckzarJVJezl3FSJ/sCH2f9ohV7mXPZn4d2etDEeXwQInwQLSDzanFE4fuYRYYDhVZ/UeNO0I5DLFe/iyZEwmV4APDvr9Xer+HTO/Bn4VNQbSJkaM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178467; c=relaxed/simple; bh=DianqpdKXUsXSFLPO4PRUcBNHWYu0IR2HAJU+rlWwu0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=KWOaX6sgR5meMBM3b4QXnSExVyF0ZzSULYaDbUY0EIji4lQbMm5QAkXnRoLqllLvT8K0LoTi0uO0NohyuWIyAxkDJ8iLfAdUEYsLWm1unbKO44BBFgDUbHainXlB2bqqQjXWZyjqAFjjAX3GoxJrjrU8Bc+knaPoHdoyXiyRZbs= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=T6s0gX/o; arc=fail smtp.client-ip=40.107.42.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="T6s0gX/o" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=NCGvW/toU5fWM/58HocYabMxGZVIqKGxhp4KUjP5pt6VJWOw8L/0+qaRkMKpxT52nICWCu8vGh0YL3xN2ZFhBbwvPLJ1JZnJVW44K3ieuDME5IJrNptb81d1Id0DkvpjlcunJVqpZoeiA9x8w2GrGs7HHwwolBckD6uypq0aLFb0CcJ4C8xZs6JdTxNa2ob/kFTJ+3AIhWY7l4/Rui9srmXEKM3qsUySq8HT2BoZLoysp8aBwqkeW6+RRCMlinE5N9/si/KMcLalj9MKByu/0DNW6Pqz2KrAK6BE1rM/soKqAC3o+6Ov9ThjfWYAwMige4bx3477XKAYifT57/VTuA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=vC+la9e42yPkXL92NB0L4D/kS7TT+UTGpL/3nZaRX70=; b=WG1M3lfuurfzW6b9LbsI0n+UETwc7KC8+DPCPetGgPPYfkc1sGWDjspClyhZ/DG5V10sIfqvy44SbGHeU5p4JnLGoJLU0G5Z/FqPkR79xW8di+hjKO8UodMHICjpaF8XSU9zR+vyRGdgjaOjV95MNGZWll58ExrMKQV6+Rh5EKnTBTXYTpQwlLyJOFW+8l+gXU0OAClYrPkkOtNN2r7e3rCte27S8z3KJdqwasBFA4BvoZtbZaX4L1VDThdaV8G0O2DQYmLTaRzY0Lf6KEKjFx3fGK7/YmwIjd32L9Xby0FbB068LZPJvqDpNScjFQ9bS8nVAowqHGipdkGzx0fPmA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=vC+la9e42yPkXL92NB0L4D/kS7TT+UTGpL/3nZaRX70=; b=T6s0gX/oB9AwT23gE0qvUXfikMoosZ3851Gyw8qCruqSVYkOsLUi8PGRM6RWZPCE/lK7NGzvjn6Eot7/MTtb1TlOY9cKvAk+5WB070wHq5zOXQrmH3lYVPs2n0ATqWpSdtIUxEF2TD/CgYCtueZLCLQJfiDfzYNsVZ064pvJerU= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:36 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:36 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 3/8] dt-bindings: media: nxp: Add Wave6 video codec device Date: Mon, 10 Feb 2025 18:07:20 +0900 Message-Id: <20250210090725.4580-4-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: 0897e959-f280-4a79-6f8d-08dd49b25c34 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: tps3iHLWl6uRy1hyLrBA+6OzpJeGiuosgNRbuNLKaoNaXLWKGuVoEKJxpJmAzmQFFr/al8m0MIE2igr9vOFsXaNWvHWT88LVjWLBzuEReBgUQrzm9Pm8IqeznSGQ+fu+HWkTwdrJZ+6YUXttFd01pJ71FdAaDLF4K/JxFsYmTLE0MsNXgEbqpyYOBwPKBVGpFjF9RWkimPxvbVdNPMw1edn2RBr/G2wAtSZPGDNo1+8a48c7mQAMYEjnAaWohgqDuVeV6pAvO8OMX4S1PNQT0Xy9eZSXdckHlGmyAJ9siMMHNnnaK/EzC5CT+pWqIZlsZ4iIkVRq9+CfPXYfAI9SSZNx5MUl5mDb7CB08xEuo4TI9trH+3d13WgQ8B52Yr/sUb41HES8rfVQ8d+9H65DFuGLMVhqOGx6dpMGqLPl8KtIq+DTelO44krPtwgmgjpV5ypk/3ktsKzmWd50qi6+eMdNwZURaZ+szk2AIyCK2wO+W5SWFDKCuO4YuhOoOLlMhTfmj3S75Uh8OlhSradQvIEkz4W8XdRdgaKD1PzibWIZ6FzH6fpPErPwM+RvEM0JZcxgcYvxnpT1baHuYQYRhbER79kx3bxhaCI7hWoOCWDyulw3sVIB3Dboyb3qU4mX0UzXoiGE8i5Cgfwuqr3CQ2rhgy1cIrZ7IxwYt5Lb2qt38M5m2NYzXd8OR58tfwPsMtaFnPVcDA/rjHU8IXFvhVZjJJsdWM0TMGm2x2ShsK3koc3Q/Flv42VhbcuUotlMmexOjp0PurHmSFp9SINk95we3W75r1bDM0sOteSxrlcr4LDj3UdfpVPXo/T58AExDTq3AVebgis+acaswHwowDe0Rg78QXQy65DniQ/V4UwlNgV3SrNNAE2CfQbi246Kpq75vBaj27OdlhGXZ4dMNUvnNMXejuI6NTaKHM8ttyqJOZoJFMoHYh3TkOYWxMM2mEGMG2KUOS4N1q/tzO6pknlv0kWvjsFfHNTD9umsPhfz3tmDpUD5YFiQsSpAN13xjCc7Gpno464JtG2T6IDiHfBpHuAVPKu4WaLLd0T4PrD5469qqsCzM4N1jNWjtmT80XtNlPl4K3N4Nyqm5U3rZV19AKAROPb20q6z2RcftaLXaqLy8dXdmWsBC+j03ssxvWkHqZnkaG+PE63gT6o0VQa6D83UFUR47wifQNKx5s9X7vXsH8M+8h9A8ByMZd8ewR3vx29aUk/dgWQ/lWqoHwBXlSaWu/GboQ+w66BS7kU74IkszzPRn1L6MEDkDUYS9AxYJOmRBPdJ/jDRclq0vinaNgRKMiJopsOIbQiQlmBNBO74J3AtPJfpV6xBJAHguHDWlefpZEH1hxW/dI9InH9zjl9zBaeuCmmmB4+N5ihexttUEihTBXcK10erPsVj X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: r4TcN572nr33GTcDNggKwjyQjr7DoZM8WG4GDOxAOrwIxFyftvpTsPsqC69b8PhyeTIYGFWp4zL6jw1iTZacW13tHFk7eru6t/B2640g1rdITnKe4thmKCJUb6hu7FytuO5a+nuphUhLvY7dC6DJQeGXwggdhz9m04ehK3te5f2+FWmqs9bRj54ZIIY4W/6wz8LnvkNwF56losgranGbKkBUOt3niKtE4N2UuT9/UftFUUSR3rDYA6IGf50UNEe5/wI9iEYerObVnKPrdjXpJ4rCfgKwnNOvtcqcghDKDdUtT+Q1PdbVWuc+E/EjXMEo6SjgocHC4STcNZ+M4B+v/vbu3As2Qap4WFbZDgmpMbnvfO7decElhyBGW/PKEL9g8I5Xznsf/TfNjXAq2+bnmVnlooL0wNu+2CItoWkXqMQ0GaqdsDodQseGWVQp5RKjiIrArPqQVS1SYiT34n7EbkDVtwFJ0oSSc7+WUvd2bK60rp13/+NG+CEGX5VKu9y2+DxdWmn4ehKcwsiZC2voUohGUpwseujmvCax3kEoNTsBnWwioo//CkzTIkf1pv6Kcu44I79S9YbVi2eFbuIQdjuo1iXBfVXWs3tUMkUdOarfyhyq5FoyxZy0NaYQ3EiOy8xjVLuxKYMjG5Lzp7fbKKf4VpMiumeDrM2jKJPJxPtORr6M99JHEc2GhIFZroG8LhgZ6vQSfFq/e6HIa2DL7L9KmSvfeaLwuZPpST/d8+aRrNuTo9j1FMzEqdKifICy1G2hQ8CBtUN4dX/KoqcyZJPeHbe9ap/cZF2HDaU7rOep6brnwvWYwI91NBJ4wtubejvWczTFqRhJpXKWVYaAyjTb3VfQM+zNw+0dcIgDDt152ywsxVUxKwjkLheGhuEBXU5wFxy9nte86U66YzELTY1PEkD99wRoE+aNS0fuwlwCx83mvYjcfvJqNbVSBt5dnfrrGjyPUndftclIwWE3M3ZdOrU5PHrSzxRstIdd3ZNlvcDejMVF0BWMHaGJreV+nuujNonAKfeBGZwgwsDqr0icWKYvcg7dJU7AbG8+fUTOItdbtLrDhcSt4rtxKqIhzI6reUL/sRLnAR4mkxot+5VfaDIwLNmUk16autywv18HfOx/mouBe7E26nWQybyQiFOlwnM/yt28YLgd9dfdmUtjRK/J2zikYu5UEobbnZBe0EszPKbEcAHYoGF2IktlQownDnzKwABE1HSKiZT6qPiqOUvpELeBAKqxbMXZqhNvRrinzySUR6d6BpnhRTiQMqIc07LlV8pbB1MjcYTFherNpEg2CV6DnfxQCfie2mKbTUWsXoactlU15G9sPWvVJbKZBfXzLUVE1r4j/eCWF+e9TSovhYxdhIuvW/b+SsU+HzTnqcQFEPR0jjGlyMc9PKmpnJKIrzLFGVfCrLS0TpYb6iYSU/Q6+RKoWKsaEcYNLnRnvRebKkfFDbLAJp3na9OT+PaZ77L4uThMQvnuBJZ+4mEa+i+sSLrv05mLsVWpUc6Ixd2HbkNFzy+kwEMScp8Xi5KkI7BgzP8QFJ/Z44pQSZ/ySeAPqOHpeGziHokM7t9OU4ZqIA3hjZ56ynMi/HIVKV02toktC4ipQoHpaw== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0897e959-f280-4a79-6f8d-08dd49b25c34 X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:36.0536 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: rxf5pco8ivD2o7P/b7NKO8gLJpXSwJCKzhUxM7eVE/0efYwwRLYnrLH7qBRL/Qlni4JJfu2CEOcNC1qfW4CPW8CX0f1mXHeVu51SjeenDTE= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 Add documents for the Wave6 video codec on NXP i.MX SoCs. Signed-off-by: Nas Chung --- .../bindings/media/nxp,wave633c.yaml | 202 ++++++++++++++++++ MAINTAINERS | 8 + 2 files changed, 210 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/nxp,wave633c.yaml diff --git a/Documentation/devicetree/bindings/media/nxp,wave633c.yaml b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml new file mode 100644 index 000000000000..99c3008314c5 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nxp,wave633c.yaml @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nxp,wave633c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Chips&Media Wave6 Series multi-standard codec IP on NXP i.MX SoCs. + +maintainers: + - Nas Chung + - Jackson Lee + +description: + The Chips&Media Wave6 codec IP is a multi-standard video encoder/decoder. + On NXP i.MX SoCs, Wave6 codec IP functionality is split between the VPU control device + (vpu-ctrl) and the VPU device (vpu). The VPU control device manages shared resources + such as firmware access and power domains, while the VPU device provides encoding + and decoding capabilities. The VPU devie cannot operate independently + without the VPU control device. + +properties: + compatible: + items: + - enum: + - nxp,imx95-wave633c-ctrl + - nxp,imx95-wave633c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: VPU clock + - description: VPU associated block clock + + clock-names: + items: + - const: vpu + - const: vpublk_wave + + power-domains: + minItems: 1 + items: + - description: Main VPU power domain + - description: Performance power domain + + power-domain-names: + items: + - const: vpumix + - const: vpuperf + + cnm,ctrl: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle of the VPU control device node. Required for VPU operation. + + boot: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle of the boot memory region node for the VPU control device. + + sram: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle of the SRAM memory region node for the VPU control device. + + '#cooling-cells': + const: 2 + + support-follower: + type: boolean + description: Indicates whether the VPU domain power always on. + +patternProperties: + "^vpu-ctrl@[0-9a-f]+$": + type: object + properties: + compatible: + items: + - enum: + - nxp,imx95-wave633c-ctrl + reg: true + clocks: true + clock-names: true + power-domains: + items: + - description: Main VPU power domain + - description: Performance power domain + power-domain-names: + items: + - const: vpumix + - const: vpuperf + sram: true + boot: true + '#cooling-cells': true + support-follower: true + required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - power-domain-names + - sram + - boot + + additionalProperties: false + + "^vpu@[0-9a-f]+$": + type: object + properties: + compatible: + items: + - enum: + - nxp,imx95-wave633c + reg: true + interrupts: true + clocks: true + clock-names: true + power-domains: + maxItems: 1 + description: Main VPU power domain + cnm,ctrl: true + required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - power-domains + - cnm,ctrl + + additionalProperties: false + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + vpuctrl: vpu-ctrl@4c4c0000 { + compatible = "nxp,imx95-wave633c-ctrl"; + reg = <0x0 0x4c4c0000 0x0 0x10000>; + clocks = <&scmi_clk 115>, + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>; + clock-names = "vpu", "vpublk_wave"; + power-domains = <&scmi_devpd 21>, <&scmi_perf 10>; + power-domain-names = "vpumix", "vpuperf"; + #cooling-cells = <2>; + boot = <&vpu_boot>; + sram = <&sram1>; + }; + + vpu0: vpu@4c480000 { + compatible = "nxp,imx95-wave633c"; + reg = <0x0 0x4c480000 0x0 0x10000>; + interrupts = ; + clocks = <&scmi_clk 115>, + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>; + clock-names = "vpu", "vpublk_wave"; + power-domains = <&scmi_devpd 21>; + cnm,ctrl = <&vpuctrl>; + }; + + vpu1: vpu@4c490000 { + compatible = "nxp,imx95-wave633c"; + reg = <0x0 0x4c490000 0x0 0x10000>; + interrupts = ; + clocks = <&scmi_clk 115>, + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>; + clock-names = "vpu", "vpublk_wave"; + power-domains = <&scmi_devpd 21>; + cnm,ctrl = <&vpuctrl>; + }; + + vpu2: vpu@4c4a0000 { + compatible = "nxp,imx95-wave633c"; + reg = <0x0 0x4c4a0000 0x0 0x10000>; + interrupts = ; + clocks = <&scmi_clk 115>, + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>; + clock-names = "vpu", "vpublk_wave"; + power-domains = <&scmi_devpd 21>; + cnm,ctrl = <&vpuctrl>; + }; + + vpu3: vpu@4c4b0000 { + compatible = "nxp,imx95-wave633c"; + reg = <0x0 0x4c4b0000 0x0 0x10000>; + interrupts = ; + clocks = <&scmi_clk 115>, + <&vpu_blk_ctrl IMX95_CLK_VPUBLK_WAVE>; + clock-names = "vpu", "vpublk_wave"; + power-domains = <&scmi_devpd 21>; + cnm,ctrl = <&vpuctrl>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 896a307fa065..5ff5b1f1ced2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25462,6 +25462,14 @@ S: Maintained F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml F: drivers/media/platform/chips-media/wave5/ +WAVE6 VPU CODEC DRIVER +M: Nas Chung +M: Jackson Lee +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/nxp,wave633c.yaml +F: drivers/media/platform/chips-media/wave6/ + WHISKEYCOVE PMIC GPIO DRIVER M: Kuppuswamy Sathyanarayanan L: linux-gpio@vger.kernel.org From patchwork Mon Feb 10 09:07:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967501 Received: from SEVP216CU002.outbound.protection.outlook.com (mail-koreacentralazon11022096.outbound.protection.outlook.com [40.107.43.96]) (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 048481C54A5; Mon, 10 Feb 2025 09:07:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.43.96 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178467; cv=fail; b=gxYJoJqTty56UhZzjPRGjVGhkDJSNoizUCLXK+IDjqDHUryyIyYOssXPsmZ0CG0T7jYWz+/w/LziZX2jwPm/ip1YCK5BI/4JJqRW26e5wVX2e2tTxTyHjJchdNxyBo/UhI2zMOR0OV3IeL98aMnnPvfUJU5kPO66zloWVWBICRM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178467; c=relaxed/simple; bh=h3p2XDyU4USVA0SY2N/FQeuSct0t53pAC1otzPwwmw4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=Rjjgc3pGxHQnpIanJt+KC9LG4O9+VHF3nsfl025VG56wLGr4NXtLCm0rHYMdqgApurnXAiNgfhPFfsdsoVrM9r49y/7bhkigMZ8d4EMJ6qPFvqG2RTNcW0vadL5KElKpIJO5PQJBE658NgEutlQatWIGtA/PtKbhS4xXp8Sbo5I= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=DA3FvS8d; arc=fail smtp.client-ip=40.107.43.96 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="DA3FvS8d" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=qxZALCldva2HZc0saA1CXh/rlqD0Ir2WH3Ub0FelkZTVXvamVYfNisdiJrZdF3m/+61kbFZKYuTZJ9OhUs4950ps3ckdrO36tms53pMk1AVSX2HeccgYjph5jcFAjcjddUF/pSvkhKY38x5OsUrWnqfPEKf6A46Luo+mDJyemGfTk4vJHYeu+dErZ/5gkUK4fZdOseU/YSYdfDXPllgfsm2KwuS3onHxUvNyEhusO+iHieiwQEKDmGQ4Z1/0EChTNkU5wEglgmqyr0fOPG6Pm2KlI/xhG+yyRm8w84EOrT1sHQUmP66grueF3eHRW2QYoDbdlQ61lJI2btYMV9WQNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=bG0Bzx9qq3ZNshMaoXhZVhMHMFHumahFHkz2dztoDbk=; b=t35rixFscW0Z6agxtfKpGlAfBfr6BUCUGX9l7wqegSVBrn0rzl6x/JbD1d9DgA9nDRUGeap6g7G9+CI5Pv3LWUS3ri/pY9pHCMU0igcicZ4iOcIWSTxqS/5/N0z/ao5Ow1rCpfKWkydXNxPfPPdVSLZ7kMXqSObFBtlw2U23Tit0WhEv6mjq657kEq/FguXrWnkwbdIg2R7w169XDApJ4uyNdsIwOh1hC/HuLCysfuiGcEfIMAKh/Szg/a7gvhuOLN7rRQ8OrPt0k+SdxZ7yaZG8wSFRemUkqqGQDSHNLI7DeL+OXhG1BFEll5KCSxcIx24SLb744ClirjcSihAWgA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bG0Bzx9qq3ZNshMaoXhZVhMHMFHumahFHkz2dztoDbk=; b=DA3FvS8dWqRS0ST6YXbKQILGWb9qWtM8YewZxzF6fdKIO7m85tkPupIrblWqcZUbJZtRo+U3Vd+5Rqaema6NekZkv7L1BCixnZntgUoPIHAiz+ulDQN1OCwiruf+VaWvKtwSjSKv84nLoXekI3v1DU2Judeu4dfuX/g/JFYU8Cw= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:36 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:36 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 4/8] media: chips-media: wave6: Add Wave6 codec driver Date: Mon, 10 Feb 2025 18:07:21 +0900 Message-Id: <20250210090725.4580-5-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: b22e95c6-538c-4611-fe6d-08dd49b25c8d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: 62KkzoexiT+2lr7Cgf6IBGx4Lo/H7FZZyixhrQ7mEnv9gS/JanBysLUjgyRuMbSS8lpj7zGHVsSm5eoMqS8pnECZ3S9ePjNJsTStt+5pwip9GrCfVn10YqSplWkv/kjlYFYWxJ7PBX9Lb9pU3w065pm2jVZrt3sOAj6alfoSjDxg5U8pc7ZVzqFnCfZi/5CC838AVS92/VDFpmKhfvvWUvtG83vEa9KXJqq8X8Q+A3Ej0kOUufdUwn5o75NFOlhnnxdlVc6qRlehtRiUKahZvYsOtlppzBVx6e/iAN2WvHRy1i8WRTLuA4GMYzgQBg7VNJpgvITGqiEDEVVNo/0uNJQf1FxcNMwh43g8U3prsf0PjhrK5bi30XH2PNw5nsJXyDW0vW3tvPkNM4Lw5Tol1AWB5F19YmTumMMe4u+CErTUVBSgcYAVPe/qHe/n78WE4S/pZLwf0QxojkbT24mX88N/0ZSLdYhGPjywCAyzUQCzL1qztLUEkFr1u7QSBVMuvkSXfbdg0ydGAnB6n6fXf9eCIjWar3Gn4GGgzribnp+yNdmW29hyIhtwWXHe29q2hZntett9CasQsJMck8hePjP3O6Ya7DSq/kuLHPqwNC7kYp8dGxmshpZ2HvXN09qGOVRwAzm/+Q6IwNNZYGa/K0Hx89sV/ZCVqNFeB7NsJCfXMkVnvgcSrWiZXv0WYBz1W8yz4KW7gsMw70UDoLZvDP0shYjJ40+061ZyHbUDMTQ31tsm+55oafdB/wQW+TCrTW+WzTYj6X9GHy6ACI354k4uP30dqEGme7r1g5n/9ivRBWYw8td6SFkCYBr07UCCDgF7c5jI8eoxZdSp3pvGaz5PCUIbJChSHnz5RKBjMRgcfIKGMftoIg2oZiRH+iPdiOAEL740GVZyNOqsXtzPFeyKxsW1xz0pB9ZFZOnNOv1Ibsk+pKYw5Ermy8CYBd7VdzvAcaK1X1+WghbwFGrcbbXozwmrRqA2koTEinYevC8iK2hieO2j6i5tRZSQytDl+WlLIx1zlx4J8KpjbTncy6kxjiGVPh+k63blHOiplEXVsf8nhos1bmlIo0uEeDwKyi/xIlfbWJzRzaIlcThqXFfAFkY2yIrlRyzsLQrdgcJq7wQNa7mswyJ3c+1WUEcbaxO2XEuiu1zG6ZEQyTz6z7oYT8Ah4rAoWTeieX4DDZzzRgGXlQWlv3v8qp1IdHXXdH2w+6VRz/4lZrXK+b97/7vGbPjflYBgAw7R5NUUJJHMCns+/GNAqsNC3Qb/v8xeKnITz/tV9HVNKsk359/8C2jEtQyHzLRlwP/FhFIeHr7gu/XFk8FO6DuK88Hh96DCTabsVpMO5w/HhkL7SjcIgN5QpfrAcF2OP6zZqoYcRZ0wFg9cuQ0+4KlPwijqRMFgMpyE62SWIlbbndo4wizJotXyvDLXQx+k0cW8ig4kkUHWcFA1VkEdo+YD9AtCI6xz X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: bQjY/8dtCBCLR8H7FaR7CZTBQpmUHyrFb0PcqrzAnKpGn1rKYc6T9gfN/a6Dekkd2+HIlBZ7Vr4xmWftaJ5vWqX9Q9tIQ3oFmGwkldmD8zLLAuQt3YGANcq9yQZPcjqWO7fDxejGblrfMVSDSV92AOlWmoepj+qfch/JpnMC1E7vmzUDtYqJMGojLqKGNHmjZmRD2kY4mKhoZ+Bco/y4OXvPKiFual7UKemEhCGLVtkEeSsBYMSvcchj+4e4CMC7UKhAojDQbIE6RP5fpLlm7tkLM92trvrBDTo2zqvQV4LVjGvcinpTNKTv/gvTgA5D3XtPa/2ekOP/Gyz0D85+9A719kgBRLGZAuGTowHU4pkgSZGhrWbgigL7Fcqd3PqSjG74eYjV255h9MuKGtqnAYFShM5IVR6cVFfpj31VSmIQsUaclGS2lBrJY6ebo6b34hB+2UtHi+o1xGRx/bah5M8hEKdb0BevZRidb1QK/U+hFzyvn+lD0dwsIzgMZDynAL/VbYaAFhy5UJKhhC+m1X7ypkpa0ZHsdZOakOEQuxSTtuptcygoOTv/Tre2UyUAMI+5TUodzk39w0gMCtdUlPLfj2e4GmIQ/Nl2jvSw3c97zxVpZVpid73BQKRZ18/obiC2n+6CRQIxyCtS0OhUhG7Kte6XWpw+CfyZsFg/71EABVUHR6d7KSi9FsZJPDCLkmjgYgnRsTjnrSou/MyOxBsHnYd7A88Deg95QnbJms5m8RvvwFfh/A/OZw8d+74KP+5Zmvbieo6Pn1ibbK4igMr+VNSBPWp2E23uXUfu3kwzcwWudZvvfp5VscOW4ZMEmE9SBpRxCkuENOY9jQNXzop72H3FYV5w3u90BQXtKmOMpbiT1Amj+hGgSu9TKnQedcBZfVfMwMm8FinPpqxpqvoo94x/x7UCqSA0XKVIeHPCWaZBnF+FNjwJq0mXOxcfyB4ii2PvikJZxj3mIvQqt8KrYwgJ3JmQnjQXFGWg9bzVejnwA5Fp/TcPCl7IOEtU9MTYXlXTftnYS3VGqJxtLdhayvS4Hovx9jBexCiy8rT3OwC49tICw8akZ7jB6qsO0/c/M5xqHSreaEq09Y9IQj6p1aUuvZ5wgRVmAeGOnkZ75/zFl9eqXnB1vJozF2ZCs4wIbEExJLQoPu8h4pBGpwy3mSp5Toxg2e3MOBhUntHjjtDEzoUyLOhCJK1Hk43gEV/ze5jmq1FR2P0qg9Ur0EtloOO0wLU4YoMVfZ8ASlj7B5B8g3pRLVIJRi0NDxtBYi8wKlVYEclgSkkenXJtOJQOqYLrk0YBjYYHdxgTxpv5u5gVoJOdoZln0x76UGRDhhoiT1GY8wGAuLEiUr5jxsZpYkBLcWQb51WrqOtV4tmftznGnaQJpYDM9i7g5Rny12nBXPvlzFXZ/8pCAEdq0J7qyDJMyD+QmI7JKj/2HkI6ozb9mJXSf97OzAbxsB6tyfOLRJ/VHlLSi96AZ0f2qiVDxyRwIq/k9CJYxqGvvb/Oaw/W3E7K96C/zw6/avy0v34X/kXsuguJAq/I6aXP3/BrXY9fY6cX20h/MKZl9Q7LDeS/3RSmRsTPHb20a9Cdjgt9CsXMuXRZMQRoWqcIFQ== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: b22e95c6-538c-4611-fe6d-08dd49b25c8d X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:36.3317 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: X8JohDnrkq4cMbiFoV8H5KW5h3kxvlfQ6Pq5YYTwRU8v8U94WI1PdAO6bOL+tp/nt+823KEfoXK5x4hNJoCVLF2L0kEzIVfowjj9OhHWozY= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 Chips&Media Wave6 stateful codec driver. The codec driver provides encoding and decoding capabilities for H.264, HEVC, and other video formats. Signed-off-by: Nas Chung --- drivers/media/platform/chips-media/Kconfig | 1 + drivers/media/platform/chips-media/Makefile | 1 + .../media/platform/chips-media/wave6/Kconfig | 26 + .../media/platform/chips-media/wave6/Makefile | 17 + .../platform/chips-media/wave6/wave6-vpu.c | 487 ++++++++++++++++++ .../platform/chips-media/wave6/wave6-vpu.h | 106 ++++ 6 files changed, 638 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave6/Kconfig create mode 100644 drivers/media/platform/chips-media/wave6/Makefile create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu.h diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig index ad350eb6b1fc..8ef7fc8029a4 100644 --- a/drivers/media/platform/chips-media/Kconfig +++ b/drivers/media/platform/chips-media/Kconfig @@ -4,3 +4,4 @@ comment "Chips&Media media platform drivers" source "drivers/media/platform/chips-media/coda/Kconfig" source "drivers/media/platform/chips-media/wave5/Kconfig" +source "drivers/media/platform/chips-media/wave6/Kconfig" diff --git a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile index 6b5d99de8b54..b9a07a91c9d6 100644 --- a/drivers/media/platform/chips-media/Makefile +++ b/drivers/media/platform/chips-media/Makefile @@ -2,3 +2,4 @@ obj-y += coda/ obj-y += wave5/ +obj-y += wave6/ diff --git a/drivers/media/platform/chips-media/wave6/Kconfig b/drivers/media/platform/chips-media/wave6/Kconfig new file mode 100644 index 000000000000..0f45581ff273 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/Kconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_WAVE6_VPU + tristate "Chips&Media Wave6 Codec Driver" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV && OF + depends on ARCH_MXC || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + select GENERIC_ALLOCATOR + help + Chips&Media Wave6 stateful codec driver. + The codec driver provides encoding and decoding capabilities + for H.264, HEVC, and other video formats. + To compile this driver as modules, choose M here: the + modules will be called wave6. + +config VIDEO_WAVE6_VPU_CTRL + tristate "Chips&Media Wave6 Codec Control Driver" + depends on VIDEO_WAVE6_VPU + default VIDEO_WAVE6_VPU if ARCH_MXC || COMPILE_TEST + help + Chips&Media Wave6 control driver. + The control driver manages shared resources such as firmware + access and power domains and clock. + To compile this driver as modules, choose M here: the + modules will be called wave6-ctrl. diff --git a/drivers/media/platform/chips-media/wave6/Makefile b/drivers/media/platform/chips-media/wave6/Makefile new file mode 100644 index 000000000000..c2180406c193 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0 + +# tell define_trace.h where to find the trace header +CFLAGS_wave6-vpu.o := -I$(src) + +wave6-ctrl-objs += wave6-vpu-ctrl.o +obj-$(CONFIG_VIDEO_WAVE6_VPU_CTRL) += wave6-ctrl.o + +wave6-objs += wave6-vpu.o \ + wave6-vpu-v4l2.o \ + wave6-vpu-dbg.o \ + wave6-vdi.o \ + wave6-vpuapi.o \ + wave6-vpu-dec.o \ + wave6-vpu-enc.o \ + wave6-hw.o +obj-$(CONFIG_VIDEO_WAVE6_VPU) += wave6.o diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu.c b/drivers/media/platform/chips-media/wave6/wave6-vpu.c new file mode 100644 index 000000000000..470d22489ecc --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - wave6 codec driver + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wave6-vpu.h" +#include "wave6-regdefine.h" +#include "wave6-vpuconfig.h" +#include "wave6-hw.h" +#include "wave6-vpu-ctrl.h" +#include "wave6-vpu-dbg.h" + +#define CREATE_TRACE_POINTS +#include "wave6-trace.h" + +#define VPU_PLATFORM_DEVICE_NAME "wave6-vpu" +#define VPU_CLK_NAME "vcodec" +#define WAVE6_VPU_DEBUGFS_DIR "wave6" + +#define WAVE6_IS_ENC BIT(0) +#define WAVE6_IS_DEC BIT(1) + +static unsigned int debug; +module_param(debug, uint, 0644); + +struct wave6_match_data { + int codec_types; + u32 compatible_fw_version; +}; + +static const struct wave6_match_data wave633c_data = { + .codec_types = WAVE6_IS_ENC | WAVE6_IS_DEC, + .compatible_fw_version = 0x3000000, +}; + +unsigned int wave6_vpu_debug(void) +{ + return debug; +} + +static void wave6_vpu_get_clk(struct vpu_device *vpu_dev) +{ + int i; + + if (!vpu_dev || !vpu_dev->num_clks || vpu_dev->clk_vpu) + return; + + for (i = 0; i < vpu_dev->num_clks; i++) { + if (vpu_dev->clks[i].id && !strcmp(vpu_dev->clks[i].id, "vpu")) { + vpu_dev->clk_vpu = vpu_dev->clks[i].clk; + return; + } + } + + vpu_dev->clk_vpu = vpu_dev->clks[0].clk; +} + +static irqreturn_t wave6_vpu_irq(int irq, void *dev_id) +{ + struct vpu_device *dev = dev_id; + u32 irq_status; + + if (wave6_vdi_readl(dev, W6_VPU_VPU_INT_STS)) { + irq_status = wave6_vdi_readl(dev, W6_VPU_VINT_REASON); + + wave6_vdi_writel(dev, W6_VPU_VINT_REASON_CLR, irq_status); + wave6_vdi_writel(dev, W6_VPU_VINT_CLEAR, 0x1); + + trace_irq(dev, irq_status); + + kfifo_in(&dev->irq_status, &irq_status, sizeof(int)); + + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + +static irqreturn_t wave6_vpu_irq_thread(int irq, void *dev_id) +{ + struct vpu_device *dev = dev_id; + struct vpu_instance *inst; + int irq_status, ret; + + while (kfifo_len(&dev->irq_status)) { + bool error = false; + + ret = kfifo_out(&dev->irq_status, &irq_status, sizeof(int)); + if (!ret) + break; + + if (irq_status & BIT(W6_INT_BIT_REQ_WORK_BUF)) { + if (!dev->ctrl) + continue; + + wave6_vpu_ctrl_require_buffer(dev->ctrl, &dev->entity); + continue; + } + + if ((irq_status & BIT(W6_INT_BIT_INIT_SEQ)) || + (irq_status & BIT(W6_INT_BIT_ENC_SET_PARAM))) { + complete(&dev->irq_done); + continue; + } + + if (irq_status & BIT(W6_INT_BIT_BSBUF_ERROR)) + error = true; + + inst = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (inst) + inst->ops->finish_process(inst, error); + } + + return IRQ_HANDLED; +} + +static u32 wave6_vpu_read_reg(struct device *dev, u32 addr) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + return wave6_vdi_readl(vpu_dev, addr); +} + +static void wave6_vpu_write_reg(struct device *dev, u32 addr, u32 data) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + wave6_vdi_writel(vpu_dev, addr, data); +} + +static void wave6_vpu_on_boot(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + u32 product_code; + u32 version; + u32 revision; + u32 hw_version; + int ret; + + product_code = wave6_vdi_readl(vpu_dev, W6_VPU_RET_PRODUCT_VERSION); + + wave6_vpu_enable_interrupt(vpu_dev); + ret = wave6_vpu_get_version(vpu_dev, &version, &revision); + if (ret) { + dev_err(dev, "wave6_vpu_get_version fail\n"); + return; + } + + hw_version = wave6_vdi_readl(vpu_dev, W6_RET_CONF_REVISION); + + if (vpu_dev->product_code != product_code || + vpu_dev->fw_version != version || + vpu_dev->fw_revision != revision || + vpu_dev->hw_version != hw_version) { + vpu_dev->product_code = product_code; + vpu_dev->fw_version = version; + vpu_dev->fw_revision = revision; + vpu_dev->hw_version = hw_version; + dev_info(dev, "product: %08x, fw_version : %d.%d.%d(r%d), hw_version : 0x%x\n", + vpu_dev->product_code, + (version >> 24) & 0xFF, + (version >> 16) & 0xFF, + (version >> 0) & 0xFFFF, + revision, + vpu_dev->hw_version); + } + + if (vpu_dev->res->compatible_fw_version > version) + dev_err(dev, "compatible firmware version is v%d.%d.%d or higher, but only v%d.%d.%d\n", + (vpu_dev->res->compatible_fw_version >> 24) & 0xFF, + (vpu_dev->res->compatible_fw_version >> 16) & 0xFF, + vpu_dev->res->compatible_fw_version & 0xFFFF, + (version >> 24) & 0xFF, + (version >> 16) & 0xFF, + version & 0xFFFF); + + wave6_vpu_get_clk(vpu_dev); +} + +void wave6_vpu_pause(struct device *dev, int resume) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + mutex_lock(&vpu_dev->pause_lock); + if (resume) { + vpu_dev->pause_request--; + if (!vpu_dev->pause_request) + v4l2_m2m_resume(vpu_dev->m2m_dev); + } else { + if (!vpu_dev->pause_request) + v4l2_m2m_suspend(vpu_dev->m2m_dev); + vpu_dev->pause_request++; + } + mutex_unlock(&vpu_dev->pause_lock); +} + +void wave6_vpu_activate(struct vpu_device *dev) +{ + dev->active = true; +} + +void wave6_vpu_wait_activated(struct vpu_device *dev) +{ + wave6_vpu_check_state(dev); +} + +static int wave6_vpu_probe(struct platform_device *pdev) +{ + int ret; + struct vpu_device *dev; + const struct wave6_match_data *match_data; + struct device_node *np; + struct platform_device *pctrl; + + match_data = device_get_match_data(&pdev->dev); + if (!match_data) { + dev_err(&pdev->dev, "missing match_data\n"); + return -EINVAL; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret < 0) { + dev_err(&pdev->dev, "dma_set_mask_and_coherent failed: %d\n", ret); + return ret; + } + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + mutex_init(&dev->dev_lock); + mutex_init(&dev->hw_lock); + mutex_init(&dev->pause_lock); + init_completion(&dev->irq_done); + dev_set_drvdata(&pdev->dev, dev); + dev->dev = &pdev->dev; + dev->res = match_data; + + dev->entity.dev = dev->dev; + dev->entity.read_reg = wave6_vpu_read_reg; + dev->entity.write_reg = wave6_vpu_write_reg; + dev->entity.on_boot = wave6_vpu_on_boot; + dev->entity.pause = wave6_vpu_pause; + + dev->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->reg_base)) + return PTR_ERR(dev->reg_base); + + np = of_parse_phandle(pdev->dev.of_node, "cnm,ctrl", 0); + if (np) { + pctrl = of_find_device_by_node(np); + of_node_put(np); + if (pctrl) { + dev->ctrl = &pctrl->dev; + if (wave6_vpu_ctrl_get_state(dev->ctrl) < 0) { + dev_info(&pdev->dev, "vpu ctrl is not ready, defer probe\n"); + return -EPROBE_DEFER; + } + } else { + dev_info(&pdev->dev, "vpu ctrl is not found\n"); + return -EINVAL; + } + } + + ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks); + if (ret < 0) { + dev_warn(&pdev->dev, "unable to get clocks: %d\n", ret); + ret = 0; + } + dev->num_clks = ret; + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "v4l2_device_register fail: %d\n", ret); + return ret; + } + + ret = wave6_vpu_init_m2m_dev(dev); + if (ret) + goto err_v4l2_unregister; + + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource\n"); + ret = -ENXIO; + goto err_m2m_dev_release; + } + + if (kfifo_alloc(&dev->irq_status, 16 * sizeof(int), GFP_KERNEL)) { + dev_err(&pdev->dev, "failed to allocate fifo\n"); + goto err_m2m_dev_release; + } + + ret = devm_request_threaded_irq(&pdev->dev, dev->irq, wave6_vpu_irq, + wave6_vpu_irq_thread, 0, "vpu_irq", dev); + if (ret) { + dev_err(&pdev->dev, "fail to register interrupt handler: %d\n", ret); + goto err_kfifo_free; + } + + dev->temp_vbuf.size = ALIGN(WAVE6_TEMPBUF_SIZE, 4096); + ret = wave6_alloc_dma(dev->dev, &dev->temp_vbuf); + if (ret) { + dev_err(&pdev->dev, "alloc temp of size %zu failed\n", + dev->temp_vbuf.size); + goto err_kfifo_free; + } + + dev->debugfs = debugfs_lookup(WAVE6_VPU_DEBUGFS_DIR, NULL); + if (IS_ERR_OR_NULL(dev->debugfs)) + dev->debugfs = debugfs_create_dir(WAVE6_VPU_DEBUGFS_DIR, NULL); + + pm_runtime_enable(&pdev->dev); + + if (dev->res->codec_types & WAVE6_IS_DEC) { + ret = wave6_vpu_dec_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "wave6_vpu_dec_register_device fail: %d\n", ret); + goto err_temp_vbuf_free; + } + } + if (dev->res->codec_types & WAVE6_IS_ENC) { + ret = wave6_vpu_enc_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "wave6_vpu_enc_register_device fail: %d\n", ret); + goto err_dec_unreg; + } + } + + if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) { + wave6_vpu_activate(dev); + ret = pm_runtime_resume_and_get(dev->dev); + if (ret) + goto err_enc_unreg; + } + + dev_dbg(&pdev->dev, "Added wave6 driver with caps %s %s\n", + dev->res->codec_types & WAVE6_IS_ENC ? "'ENCODE'" : "", + dev->res->codec_types & WAVE6_IS_DEC ? "'DECODE'" : ""); + + return 0; + +err_enc_unreg: + if (dev->res->codec_types & WAVE6_IS_ENC) + wave6_vpu_enc_unregister_device(dev); +err_dec_unreg: + if (dev->res->codec_types & WAVE6_IS_DEC) + wave6_vpu_dec_unregister_device(dev); +err_temp_vbuf_free: + wave6_free_dma(&dev->temp_vbuf); +err_kfifo_free: + kfifo_free(&dev->irq_status); +err_m2m_dev_release: + wave6_vpu_release_m2m_dev(dev); +err_v4l2_unregister: + v4l2_device_unregister(&dev->v4l2_dev); + + return ret; +} + +static void wave6_vpu_remove(struct platform_device *pdev) +{ + struct vpu_device *dev = dev_get_drvdata(&pdev->dev); + + if (dev->ctrl && wave6_vpu_ctrl_support_follower(dev->ctrl)) { + if (!pm_runtime_suspended(&pdev->dev)) + pm_runtime_put_sync(&pdev->dev); + } + pm_runtime_disable(&pdev->dev); + + wave6_vpu_enc_unregister_device(dev); + wave6_vpu_dec_unregister_device(dev); + wave6_free_dma(&dev->temp_vbuf); + kfifo_free(&dev->irq_status); + wave6_vpu_release_m2m_dev(dev); + v4l2_device_unregister(&dev->v4l2_dev); +} + +#ifdef CONFIG_PM +static int wave6_vpu_runtime_suspend(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + + if (!vpu_dev) + return -ENODEV; + + dprintk(dev, "runtime suspend\n"); + if (vpu_dev->ctrl && vpu_dev->active) + wave6_vpu_ctrl_put_sync(vpu_dev->ctrl, &vpu_dev->entity); + if (vpu_dev->num_clks) + clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks); + + return 0; +} + +static int wave6_vpu_runtime_resume(struct device *dev) +{ + struct vpu_device *vpu_dev = dev_get_drvdata(dev); + int ret = 0; + + if (!vpu_dev) + return -ENODEV; + + dprintk(dev, "runtime resume\n"); + if (vpu_dev->num_clks) { + ret = clk_bulk_prepare_enable(vpu_dev->num_clks, vpu_dev->clks); + if (ret) { + dev_err(dev, "failed to enable clocks: %d\n", ret); + return ret; + } + } + + if (vpu_dev->ctrl && vpu_dev->active) { + ret = wave6_vpu_ctrl_resume_and_get(vpu_dev->ctrl, &vpu_dev->entity); + if (ret && vpu_dev->num_clks) + clk_bulk_disable_unprepare(vpu_dev->num_clks, vpu_dev->clks); + } else { + wave6_vpu_check_state(vpu_dev); + } + + return ret; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int wave6_vpu_suspend(struct device *dev) +{ + int ret; + + dprintk(dev, "suspend\n"); + wave6_vpu_pause(dev, 0); + + ret = pm_runtime_force_suspend(dev); + if (ret) + wave6_vpu_pause(dev, 1); + + return ret; +} + +static int wave6_vpu_resume(struct device *dev) +{ + int ret; + + dprintk(dev, "resume\n"); + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + wave6_vpu_pause(dev, 1); + return 0; +} +#endif +static const struct dev_pm_ops wave6_vpu_pm_ops = { + SET_RUNTIME_PM_OPS(wave6_vpu_runtime_suspend, wave6_vpu_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_suspend, wave6_vpu_resume) +}; + +static const struct of_device_id wave6_dt_ids[] = { + { .compatible = "nxp,imx95-wave633c", .data = &wave633c_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, wave6_dt_ids); + +static struct platform_driver wave6_vpu_driver = { + .driver = { + .name = VPU_PLATFORM_DEVICE_NAME, + .of_match_table = of_match_ptr(wave6_dt_ids), + .pm = &wave6_vpu_pm_ops, + }, + .probe = wave6_vpu_probe, + .remove = wave6_vpu_remove, +}; + +module_platform_driver(wave6_vpu_driver); +MODULE_DESCRIPTION("chips&media VPU V4L2 driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu.h b/drivers/media/platform/chips-media/wave6/wave6-vpu.h new file mode 100644 index 000000000000..51cda07863a4 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 codec driver + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VPU_H__ +#define __WAVE6_VPU_H__ + +#include +#include +#include +#include +#include +#include +#include "wave6-vpuconfig.h" +#include "wave6-vpuapi.h" + +struct vpu_buffer { + struct v4l2_m2m_buffer v4l2_m2m_buf; + bool consumed; + bool used; + bool error; + bool force_key_frame; + bool force_frame_qp; + u32 force_i_frame_qp; + u32 force_p_frame_qp; + u32 force_b_frame_qp; + ktime_t ts_input; + ktime_t ts_start; + ktime_t ts_finish; + ktime_t ts_output; + u64 hw_time; + u32 average_qp; +}; + +enum vpu_fmt_type { + VPU_FMT_TYPE_CODEC = 0, + VPU_FMT_TYPE_RAW = 1 +}; + +struct vpu_format { + unsigned int v4l2_pix_fmt; + unsigned int max_width; + unsigned int min_width; + unsigned int max_height; + unsigned int min_height; + unsigned int num_planes; +}; + +static inline struct vpu_instance *wave6_to_vpu_inst(struct v4l2_fh *vfh) +{ + return container_of(vfh, struct vpu_instance, v4l2_fh); +} + +static inline struct vpu_instance *wave6_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl) +{ + return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl); +} + +static inline struct vpu_buffer *wave6_to_vpu_buf(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct vpu_buffer, v4l2_m2m_buf.vb); +} + +static inline bool wave6_vpu_both_queues_are_streaming(struct vpu_instance *inst) +{ + struct vb2_queue *vq_cap = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx); + struct vb2_queue *vq_out = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx); + + return vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out); +} + +u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst); +u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst); +void wave6_vpu_pause(struct device *dev, int resume); +void wave6_vpu_activate(struct vpu_device *dev); +void wave6_vpu_wait_activated(struct vpu_device *dev); +void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + unsigned int width, + unsigned int height); +struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct vpu_instance *inst, + dma_addr_t addr); +dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf, + unsigned int plane_no); +enum codec_std wave6_to_codec_std(enum vpu_instance_type type, unsigned int v4l2_pix_fmt); +const char *wave6_vpu_instance_state_name(u32 state); +void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32 state); +u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle); +int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout); +int wave6_vpu_dec_register_device(struct vpu_device *dev); +void wave6_vpu_dec_unregister_device(struct vpu_device *dev); +int wave6_vpu_enc_register_device(struct vpu_device *dev); +void wave6_vpu_enc_unregister_device(struct vpu_device *dev); +void wave6_vpu_finish_job(struct vpu_instance *inst); +void wave6_vpu_handle_performance(struct vpu_instance *inst, struct vpu_buffer *vpu_buf); +void wave6_vpu_reset_performance(struct vpu_instance *inst); +int wave6_vpu_init_m2m_dev(struct vpu_device *dev); +void wave6_vpu_release_m2m_dev(struct vpu_device *dev); +int wave6_vpu_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub); +void wave6_vpu_return_buffers(struct vpu_instance *inst, + unsigned int type, enum vb2_buffer_state state); + +#endif /* __WAVE6_VPU_H__ */ From patchwork Mon Feb 10 09:07:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967504 Received: from SEVP216CU002.outbound.protection.outlook.com (mail-koreacentralazon11022096.outbound.protection.outlook.com [40.107.43.96]) (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 AF87C1C5D6F; Mon, 10 Feb 2025 09:07:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.43.96 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178474; cv=fail; b=sTEGD8FORDtTSsXruLolfVZKhI7/exDTG0COAytWOhWzrwHRNTxo1Kd+NUc1YmLVIVmPVI0wNE1ggTHKNPGcwPjlLDcgUkuXrg+ZAstaDS6rE3aAkR4emZExIM8rUb14vUePOMOt0I8NGVF/zH5ixinPBYbQxkNEGmB8kKRmNTU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178474; c=relaxed/simple; bh=euKQ1VC9zCxnTUPBulYgKuC3W7TR4Hld54nPhGnywZk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=MsXtxk4Ptivk+wj7QBFKxX3/caFVCbuY5nFII7TdSbI9xDXgtT8K231f4yNdVgBXo3WX6DW+Q8oE7nvE/7KmZxpoyg0eqDEnbpPi8TOJW7EC9/iRkyLbhoxbU4muUycnjXM1LjO7+KPriYPsWBvQzCn1SUjYCjfC+1vtvXO8y8o= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=RuNzMicH; arc=fail smtp.client-ip=40.107.43.96 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="RuNzMicH" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=cpr5tU5ihQkj7rztSICvI7zNSHgLGRdYay81fELeWUNCWd8yxijJWpJSW/DIQXyw/WoIlUf/uMi5/HqZq4MDq8RKOnwAwo86ZXbqvafk8nSOW4iibXNYfXf8kOFxwO89A1yOrveYM2IrUtuOYWbeYhfAz1C7Vfv9sLSdRso6DYXmrdtwJTqF5IULgAGAZyysTnBx52DLgLfL3uSt2hAxhUIZxOcjocQK4KjWzt7rQfo53nw4wSp9T/rQDfvWFDuKwlP5MrbcouryjXvB/QbgIPZaCGPF984n80EpQMez4OZClyK6IlZCFhaihfbGNYLGQdh98vYfTI2nPQEbSerODg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=L0H5QFIRX42PTjKvtlysdVphj5ex/6LYnVxJb/AESJc=; b=evxLDLboI+eneYnlzaKdI+FkktppAhh42r+IUXa1KZNIHFCCSmENzM+Tr9ud5DOiG8p9wolRhF6iAqwYCrRyMMJQEGjhtJBvfKxLRcpgo8iXKqJim7Q8o/1uALQ03ruXylouECRMKsB72Sh1cRlFqYLbQIVf5C01tDMh56B8TTxxgcHgmyqVii9ks0xBNys4QL0ULVPEvkR/e8SHSocHU0wj04vjWeYvjuJDWQB2nD31WE895JqrwArMqXCKxWPyuycWoA91jFa5dYs6awJBI6wmSrep2TtRr0L7Hl4xuYbooXGOE8H/o6zGm3NM2xXXEclaMVe5bwTihORPsBjApA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=L0H5QFIRX42PTjKvtlysdVphj5ex/6LYnVxJb/AESJc=; b=RuNzMicHYOZ8K4K1gCOxYRUaFVPAMAp3F/yDbTGIQkhQQ2Bggk/dpdckEhz8Nuj+RXBf13YexXg+Spk01Qd4Qr3j6vzxM6hJdoZeZ/bx6iYxl+tSkC5vPHcd1VtBYXqWXvWmk2QCzfqFu1y6/ZqRfHwyvt9oaJTR/sB3jy0u/AM= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:37 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:37 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 5/8] media: chips-media: wave6: Add v4l2 m2m driver Date: Mon, 10 Feb 2025 18:07:22 +0900 Message-Id: <20250210090725.4580-6-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: ca6131fc-8c72-4b97-e36c-08dd49b25cb7 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|4022899009|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: ZTAoTVg4qJ/8G7u79obCQVBusbop7lNeYPPeIsndcsknFSc/LXcm7n1aEPqBKY9Ix3lgVxH8NVHNVEFEKqS6EkOcskEZVuTJ1RQHO1D7MdoL2dAjcfPMn5VOwMKOzeUrnoxAqJPLv64DWvRxx/lRQxNxW1FpOgiEQ4lsoKZ/tvO+lNFUANKK65xaSpFZBobekm6HoiXt5hLH1Hi45tbODnQtATUOwKc621eJgE3lSbFu/I89ktPxjk+RcKsXtlExRFflgXkpTqG9cJ4a1ursmgHX9Ke3g9ELbf7mko8fLMYbypnyEqZggqJ/NdckMH5sAHx43Fto4ZVN9t2mzbNgdmDpn9gXlxrTrYNEoz/m/wxC7jzVMys94UF3vg1R0LeHe5yh88fNM8qAb+8bgIkgImOh8dtx2wbUkcs5QkbwdlKa54rU/sur6qw+QHZDJxl72X70MJ81DVvRIZfghC+kKiIkll1ZbtfXkVJgCMKqnrhVGA0SG77PIFhpMx1xteaK9HTrGXaZPM4blT4gxnfdKZeTogszoWwyhfdvIrrBkwCFUuDZeRFuQkK//qNBgh4TeCyQhpf8M3eqMFQbzXrBdqpJZ7uz/8NYvSkFjgMRjkyb88SgkK4/SLUpKMVjBRSQhzICxaCew2Zgc8CRHSnoF38E+Mof5dRqcVZ6nYji1cxVHQ7HPINvRi+8D8hSDrJOg+I513W63/40j6YJLuO3zvPszUI4JclwRvUvvZJpR16Ugz0T6knyA9ZhylOkFcCaQYkBHUACCIgzj+ZjEw85v/sHY7niRfFoBZ9CfFVUa/7G5Ka75154P1fLVrgl69KOVBXHLHMP6w7bFkCK0eZZaEbCVbREp10wfw4EjxsqC4Nk3tzIbv6ZblPvQL0xZ6aG4LHujTX3bO8uPgMus0gkhMM7JjozXdWjqqubveFEiYYFzcbgQE01FgiJwDfay4yBQuH2oXvM0ZjmbC1Ky5dXOtQhrtI+3qtA5JvffDVL3YkqxxO+ACiwlYS/dkxk/ymGGUTYvOFWGlYkUaVjr/R1mT/hZZuG/Zme3A0xxa7+yVIOSEoJylPSCxVEeTVNxhouj8R7R+cBZK2NSg03oU9ersBnhKhIVyEUehaTCsjvgW8qIPsWzJBj+l4yBJY40+fx1CLZtsql7IwLs06mvMhhvhKo+auT4r+67Qui7q5+PIEenzYvoRYK7QuAPsmr4X/jHK5edHSk7lJSzX9ExWyRHjwhlxiBW5Wtu27lKf/XMVRqflHvMEL+VlkSf5R9mdBtBizvUZx0kXveeYjhJBb3mKh5TbY8QkkYWiHdiwYq7soylOFnbSzi9cSLOR1Mu0dl5Son6yRSpegH0E7rOt0wl0TqE/d2NRrs3s5BjUsGRT4yRSVLezqVvEsgd3klXVdLCm/rEOLJs4Ngpm0Uc7ZDEZuKHEojjCwOr6pKpMKIzuADe1I7MpCtMuEyHaFQ2nlf X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(4022899009)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 5aFJ4VzennRUkAmYN8bSmdXH/d1Pnh8eolXW0zIH3ehrQFAh++ntn/qr8faZjSfBnhinfgWp733SgEIOfjitJyojIPuXJZKAUcELu73ToIMIn1/FBTsfVNZiDppl67mWd7iq95o9n8UlkpHbG2HFFwdb/HGupHK7MbNXlL9AWP57iiieLDP2sVpK/07GZKpG3kHFsW+VuyoS3jkHTTzT6xPjngk7sGmkE7G4sqPB51F3HnXTwG1dHMwMCBv2pu9Q/NQRoTC3h5N7MalL8mvQih92msQ/EEpzwAdh4vs/AUeixtlzWbe6bFyDO4i5rOKQCMZlI4jUeE7adwVTnl1jy9sxrGOz0jDwPhXaVhKH6RQRTewETA4QEVnRJvVBktYXhGZQHTgdTz2d+q3zg1reYwbQpmKKVcKHSV2uk93PElYV+deUvPgcbbvSs7lMDedYgHSvNulCEBe3/bSru7tJ1AMQ8t2luNG/aE76t2MLBEKzFBqXGzBlmNBEYoyjjD9rYWbPaZ6wxFl2NwDQWAGc2QfqfXzopUSr3wTw+V4J+IvNMGsT7vBYc4Gw9arlHxinOELuZhcR6R0LmoAmNrm5PVL+lFazlyo2q8uuwATKEmxxSGWdl6qQBti8XaQqMlvFlbOPyS+L/WOsWYPQ+T0S+ToEhb4FDp/4DrnBGKA4D63ZUuY8NHowdjLv9cRLizE14lraQ9Fy6HOzGiWWoGCiinzHCqa1zYRZ4GSwPBp3AdtsnPqcPfBXaY57yjwkbMG+S67LdwhAwyC7rBH76P9RkpBjCFbA6kvIiW+19q1o35B5hUX/cf5L8UdDU6ihmVUKe5I0hr8xZKasq/f9uQbMHZzjFJrYdgHYiK5GyjV0uMYYbI0DNEg4tKVhjq5+KLK5N/78Vsxb9yRO3HhrZVOcZ0VfNwK9bkIZE3zEzRL6mqOQ2AtHEFLlErRnCPtBQa3AUEiCUCITjea0o9xuOCNxSA+eGqqA9nEtDePYvvM8ycnkKwCn1Q/db/Dx7j4myWQ//qQoZXSSF1Omi6/h02mWfyFMI/r4lkzHn/mUSpU1d1tUOPKXNVYIgh7bMMEs8GOUV4AQVk3h7snVfNtXvDDkQIvDP1fUS2lwlf4Lefbsk73yD34n/xt0vKjk1bQQs+VZQGXtBmjHg7SiwFRLL4+hdeYABxQTEM44Bj0atZfsywikZ3cZQSSR5gVSTkrsaLA4358APZmxg9yDohgn+l5qlWcQud6vmjkeJQs+gpeqtntSsit4AI359V0FQY35d6cxjq980gxlL7R2quuBNzUls35pcfDMpe71l1eaXcKoLJjjibJ+oKvDgUdYUsfZUNX1FLX+eL9tyt8/FL8BOLmhDA4bwP8InkevQiQbBbzOpe2z6Xr+VXlSJgRTVroruKLqfHxwz/3obqADOYIlyF+EpfAwpFezrp+oU1YmgKdX7iAzyl3R5sUFBjkAFTjrAyjxCfY5kMpGTXDj89/eM2ENNB29XKx1GNiqvOsM2MZvbaoxXE0uac0zFRkBQMq24JiDLTCb2poqGF4Fm+QZkBbv9/z+s/VhkbqIASDMiRPMURGtM+dLeABwBB5zbdmg4+W3y7EqbvmmjQn0G0iEfM7nwg== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: ca6131fc-8c72-4b97-e36c-08dd49b25cb7 X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:37.0390 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 7V81wZk2z3Be5MvjlLfaYJUG6rGFIC515Dwmoci6YE8juSIu8nojwTbbyoqsR2TlfO0xlPfG6dNKlcfErmjWpHQQ9Pcy08MxJWfkeKbrhnA= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 Add v4l2 m2m drivers which support stateful decoder and encoder. Signed-off-by: Nas Chung --- .../chips-media/wave6/wave6-vpu-dec.c | 1883 ++++++++++++ .../chips-media/wave6/wave6-vpu-enc.c | 2698 +++++++++++++++++ .../chips-media/wave6/wave6-vpu-v4l2.c | 381 +++ 3 files changed, 4962 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c new file mode 100644 index 000000000000..f6ed078a2824 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dec.c @@ -0,0 +1,1883 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - v4l2 stateful decoder interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include +#include "wave6-vpu.h" +#include "wave6-vpu-dbg.h" +#include "wave6-trace.h" + +#define VPU_DEC_DEV_NAME "C&M Wave6 VPU decoder" +#define VPU_DEC_DRV_NAME "wave6-dec" +#define V4L2_CID_VPU_THUMBNAIL_MODE (V4L2_CID_USER_BASE + 0x1001) + +static const struct vpu_format wave6_vpu_dec_fmt_list[2][6] = { + [VPU_FMT_TYPE_CODEC] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_H264, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 1, + }, + }, + [VPU_FMT_TYPE_RAW] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 3, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 2, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, + .max_width = W6_MAX_DEC_PIC_WIDTH, + .min_width = W6_MIN_DEC_PIC_WIDTH, + .max_height = W6_MAX_DEC_PIC_HEIGHT, + .min_height = W6_MIN_DEC_PIC_HEIGHT, + .num_planes = 2, + }, + } +}; + +static int wave6_vpu_dec_seek_header(struct vpu_instance *inst); + +static const struct vpu_format *wave6_find_vpu_fmt(unsigned int v4l2_pix_fmt, + enum vpu_fmt_type type) +{ + unsigned int index; + + for (index = 0; index < ARRAY_SIZE(wave6_vpu_dec_fmt_list[type]); index++) { + if (wave6_vpu_dec_fmt_list[type][index].v4l2_pix_fmt == v4l2_pix_fmt) + return &wave6_vpu_dec_fmt_list[type][index]; + } + + return NULL; +} + +static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned int idx, + enum vpu_fmt_type type) +{ + if (idx >= ARRAY_SIZE(wave6_vpu_dec_fmt_list[type])) + return NULL; + + if (!wave6_vpu_dec_fmt_list[type][idx].v4l2_pix_fmt) + return NULL; + + return &wave6_vpu_dec_fmt_list[type][idx]; +} + +static void wave6_vpu_dec_release_fb(struct vpu_instance *inst) +{ + int i; + + for (i = 0; i < WAVE6_MAX_FBS; i++) { + wave6_free_dma(&inst->frame_vbuf[i]); + memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer)); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]); + } +} + +static void wave6_vpu_dec_destroy_instance(struct vpu_instance *inst) +{ + u32 fail_res; + int ret; + + dprintk(inst->dev->dev, "[%d] destroy instance\n", inst->id); + wave6_vpu_remove_dbgfs_file(inst); + + ret = wave6_vpu_dec_close(inst, &fail_res); + if (ret) { + dev_err(inst->dev->dev, "failed destroy instance: %d (%d)\n", + ret, fail_res); + } + + wave6_vpu_dec_release_fb(inst); + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE); + + if (!pm_runtime_suspended(inst->dev->dev)) + pm_runtime_put_sync(inst->dev->dev); +} + +static void wave6_handle_bitstream_buffer(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *src_buf; + u32 src_size = 0; + int ret; + + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx); + if (src_buf) { + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(src_buf); + dma_addr_t rd_ptr = wave6_get_dma_addr(src_buf, 0); + + if (vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "%s: Already consumed buffer\n", + __func__); + return; + } + + vpu_buf->ts_start = ktime_get_raw(); + vpu_buf->consumed = true; + wave6_vpu_dec_set_rd_ptr(inst, rd_ptr, true); + + src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + } + + if (!src_size) { + dma_addr_t rd = 0, wr = 0; + + wave6_vpu_dec_get_bitstream_buffer(inst, &rd, &wr); + wave6_vpu_dec_set_rd_ptr(inst, wr, true); + } + + trace_dec_pic(inst, src_buf ? src_buf->vb2_buf.index : -1, src_size); + + ret = wave6_vpu_dec_update_bitstream_buffer(inst, src_size); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Update bitstream buffer fail %d\n", + __func__, ret); + return; + } +} + +static void wave6_update_pix_fmt_cap(struct v4l2_pix_format_mplane *pix_mp, + unsigned int width, + unsigned int height, + bool new_resolution) +{ + unsigned int aligned_width; + + if (new_resolution) + pix_mp->plane_fmt[0].bytesperline = 0; + + aligned_width = round_up(width, 32); + wave6_update_pix_fmt(pix_mp, aligned_width, height); +} + +static int wave6_allocate_aux_buffer(struct vpu_instance *inst, + enum aux_buffer_type type, + int num) +{ + struct aux_buffer buf[WAVE6_MAX_FBS]; + struct aux_buffer_info buf_info; + struct dec_aux_buffer_size_info size_info; + unsigned int size; + int i, ret; + + memset(buf, 0, sizeof(buf)); + + size_info.width = inst->src_fmt.width; + size_info.height = inst->src_fmt.height; + size_info.type = type; + + ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info, &size); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Get size fail (type %d)\n", __func__, type); + return ret; + } + + num = min_t(u32, num, WAVE6_MAX_FBS); + for (i = 0; i < num; i++) { + inst->aux_vbuf[type][i].size = size; + ret = wave6_alloc_dma(inst->dev->dev, &inst->aux_vbuf[type][i]); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Alloc fail (type %d)\n", __func__, type); + return ret; + } + + buf[i].index = i; + buf[i].addr = inst->aux_vbuf[type][i].daddr; + buf[i].size = inst->aux_vbuf[type][i].size; + } + + buf_info.type = type; + buf_info.num = num; + buf_info.buf_array = buf; + + ret = wave6_vpu_dec_register_aux_buffer(inst, buf_info); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Register fail (type %d)\n", __func__, type); + return ret; + } + + return 0; +} + +static void wave6_vpu_dec_handle_dst_buffer(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *dst_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vpu_buffer *vpu_buf; + dma_addr_t buf_addr_y, buf_addr_cb, buf_addr_cr; + u32 buf_size; + u32 fb_stride = inst->dst_fmt.plane_fmt[0].bytesperline; + u32 luma_size = fb_stride * inst->dst_fmt.height; + u32 chroma_size = (fb_stride / 2) * (inst->dst_fmt.height / 2); + struct frame_buffer disp_buffer = {0}; + struct dec_initial_info initial_info = {0}; + int consumed_num = wave6_vpu_get_consumed_fb_num(inst); + int ret; + + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info); + + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + dst_buf = &v4l2_m2m_buf->vb; + vpu_buf = wave6_to_vpu_buf(dst_buf); + + if (vpu_buf->consumed) + continue; + + if (consumed_num >= WAVE6_MAX_FBS) + break; + + if (inst->dst_fmt.num_planes == 1) { + buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0); + buf_addr_y = wave6_get_dma_addr(dst_buf, 0); + buf_addr_cb = buf_addr_y + luma_size; + buf_addr_cr = buf_addr_cb + chroma_size; + } else if (inst->dst_fmt.num_planes == 2) { + buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0) + + vb2_plane_size(&dst_buf->vb2_buf, 1); + buf_addr_y = wave6_get_dma_addr(dst_buf, 0); + buf_addr_cb = wave6_get_dma_addr(dst_buf, 1); + buf_addr_cr = buf_addr_cb + chroma_size; + } else if (inst->dst_fmt.num_planes == 3) { + buf_size = vb2_plane_size(&dst_buf->vb2_buf, 0) + + vb2_plane_size(&dst_buf->vb2_buf, 1) + + vb2_plane_size(&dst_buf->vb2_buf, 2); + buf_addr_y = wave6_get_dma_addr(dst_buf, 0); + buf_addr_cb = wave6_get_dma_addr(dst_buf, 1); + buf_addr_cr = wave6_get_dma_addr(dst_buf, 2); + } + disp_buffer.buf_y = buf_addr_y; + disp_buffer.buf_cb = buf_addr_cb; + disp_buffer.buf_cr = buf_addr_cr; + disp_buffer.width = inst->src_fmt.width; + disp_buffer.height = inst->src_fmt.height; + disp_buffer.stride = fb_stride; + disp_buffer.map_type = LINEAR_FRAME_MAP; + disp_buffer.luma_bitdepth = initial_info.luma_bitdepth; + disp_buffer.chroma_bitdepth = initial_info.chroma_bitdepth; + disp_buffer.chroma_format_idc = initial_info.chroma_format_idc; + + ret = wave6_vpu_dec_register_display_buffer_ex(inst, disp_buffer); + if (ret) { + dev_err(inst->dev->dev, "fail register display buffer %d", ret); + break; + } + + vpu_buf->consumed = true; + consumed_num++; + } +} + +static enum v4l2_quantization to_v4l2_quantization(u32 video_full_range_flag) +{ + switch (video_full_range_flag) { + case 0: + return V4L2_QUANTIZATION_LIM_RANGE; + case 1: + return V4L2_QUANTIZATION_FULL_RANGE; + default: + return V4L2_QUANTIZATION_DEFAULT; + } +} + +static enum v4l2_colorspace to_v4l2_colorspace(u32 colour_primaries) +{ + switch (colour_primaries) { + case 1: + return V4L2_COLORSPACE_REC709; + case 4: + return V4L2_COLORSPACE_470_SYSTEM_M; + case 5: + return V4L2_COLORSPACE_470_SYSTEM_BG; + case 6: + return V4L2_COLORSPACE_SMPTE170M; + case 7: + return V4L2_COLORSPACE_SMPTE240M; + case 9: + return V4L2_COLORSPACE_BT2020; + case 11: + return V4L2_COLORSPACE_DCI_P3; + default: + return V4L2_COLORSPACE_DEFAULT; + } +} + +static enum v4l2_xfer_func to_v4l2_xfer_func(u32 transfer_characteristics) +{ + switch (transfer_characteristics) { + case 1: + return V4L2_XFER_FUNC_709; + case 6: + return V4L2_XFER_FUNC_709; + case 7: + return V4L2_XFER_FUNC_SMPTE240M; + case 8: + return V4L2_XFER_FUNC_NONE; + case 13: + return V4L2_XFER_FUNC_SRGB; + case 14: + return V4L2_XFER_FUNC_709; + case 16: + return V4L2_XFER_FUNC_SMPTE2084; + default: + return V4L2_XFER_FUNC_DEFAULT; + } +} + +static enum v4l2_ycbcr_encoding to_v4l2_ycbcr_encoding(u32 matrix_coeffs) +{ + switch (matrix_coeffs) { + case 1: + return V4L2_YCBCR_ENC_709; + case 5: + return V4L2_YCBCR_ENC_601; + case 6: + return V4L2_YCBCR_ENC_601; + case 7: + return V4L2_YCBCR_ENC_SMPTE240M; + case 9: + return V4L2_YCBCR_ENC_BT2020; + case 10: + return V4L2_YCBCR_ENC_BT2020_CONST_LUM; + default: + return V4L2_YCBCR_ENC_DEFAULT; + } +} + +static void wave6_update_color_info(struct vpu_instance *inst, + struct dec_initial_info *initial_info) +{ + struct color_param *color = &initial_info->color; + + if (!color->video_signal_type_present) + goto set_default_all; + + inst->quantization = to_v4l2_quantization(color->color_range); + + if (!color->color_description_present) + goto set_default_color; + + inst->colorspace = to_v4l2_colorspace(color->color_primaries); + inst->xfer_func = to_v4l2_xfer_func(color->transfer_characteristics); + inst->ycbcr_enc = to_v4l2_ycbcr_encoding(color->matrix_coefficients); + + return; + +set_default_all: + inst->quantization = V4L2_QUANTIZATION_DEFAULT; +set_default_color: + inst->colorspace = V4L2_COLORSPACE_DEFAULT; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static enum v4l2_mpeg_video_hevc_profile to_v4l2_hevc_profile(u32 profile) +{ + switch (profile) { + case HEVC_PROFILE_MAIN: + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + default: + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + } +} + +static enum v4l2_mpeg_video_h264_profile to_v4l2_h264_profile(u32 profile) +{ + switch (profile) { + case H264_PROFILE_BP: + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + case H264_PROFILE_MP: + return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; + case H264_PROFILE_EXTENDED: + return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; + case H264_PROFILE_HP: + return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + default: + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + } +} + +static void wave6_update_v4l2_ctrls(struct vpu_instance *inst, + struct dec_initial_info *info) +{ + struct v4l2_ctrl *ctrl; + u32 min_disp_cnt; + + min_disp_cnt = info->frame_buf_delay + 1; + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, min_disp_cnt); + + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_HEVC) { + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, to_v4l2_hevc_profile(info->profile)); + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_H264) { + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MPEG_VIDEO_H264_PROFILE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, to_v4l2_h264_profile(info->profile)); + } +} + +static int wave6_vpu_dec_start_decode(struct vpu_instance *inst) +{ + struct dec_param pic_param; + int ret; + u32 fail_res = 0; + + memset(&pic_param, 0, sizeof(struct dec_param)); + + wave6_handle_bitstream_buffer(inst); + if (inst->state == VPU_INST_STATE_OPEN) { + ret = wave6_vpu_dec_seek_header(inst); + if (ret) { + vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx)); + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx)); + } + return -EAGAIN; + } + + wave6_vpu_dec_handle_dst_buffer(inst); + + ret = wave6_vpu_dec_start_one_frame(inst, &pic_param, &fail_res); + if (ret) { + struct vb2_v4l2_buffer *src_buf = NULL; + + dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst->id, __func__, ret); + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP); + + src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx); + if (src_buf) { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + inst->sequence++; + inst->processed_buf_num++; + inst->error_buf_num++; + } + } + + return ret; +} + +static void wave6_handle_decoded_frame(struct vpu_instance *inst, + struct dec_output_info *info) +{ + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct vpu_buffer *vpu_buf; + enum vb2_buffer_state state; + + state = info->decoding_success ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx); + if (!src_buf) { + dev_err(inst->dev->dev, "[%d] decoder can't find src buffer\n", inst->id); + return; + } + + vpu_buf = wave6_to_vpu_buf(src_buf); + if (!vpu_buf || !vpu_buf->consumed) { + dev_err(inst->dev->dev, "[%d] src buffer is not consumed\n", inst->id); + return; + } + + dst_buf = wave6_get_dst_buf_by_addr(inst, info->frame_decoded_addr); + if (dst_buf) { + struct vpu_buffer *dst_vpu_buf = wave6_to_vpu_buf(dst_buf); + + if (wave6_to_vpu_buf(dst_buf)->used) { + dev_warn(inst->dev->dev, "[%d] duplication frame buffer\n", inst->id); + inst->sequence++; + } + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + dst_vpu_buf->used = true; + if (state == VB2_BUF_STATE_ERROR) + dst_vpu_buf->error = true; + dst_vpu_buf->ts_input = vpu_buf->ts_input; + dst_vpu_buf->ts_start = vpu_buf->ts_start; + dst_vpu_buf->ts_finish = ktime_get_raw(); + dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst->dev, info->cycle.frame_cycle); + } + + v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, src_buf); + if (state == VB2_BUF_STATE_ERROR) { + dprintk(inst->dev->dev, "[%d] error frame %d\n", inst->id, inst->sequence); + inst->error_buf_num++; + } + v4l2_m2m_buf_done(src_buf, state); + inst->processed_buf_num++; +} + +static void wave6_handle_skipped_frame(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *src_buf; + struct vpu_buffer *vpu_buf; + + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx); + if (!src_buf) + return; + + vpu_buf = wave6_to_vpu_buf(src_buf); + if (!vpu_buf || !vpu_buf->consumed) + return; + + dprintk(inst->dev->dev, "[%d] skip frame %d\n", inst->id, inst->sequence); + + inst->sequence++; + inst->processed_buf_num++; + inst->error_buf_num++; + v4l2_m2m_src_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, src_buf); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); +} + +static void wave6_handle_display_frame(struct vpu_instance *inst, + dma_addr_t addr, enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *dst_buf; + struct vpu_buffer *vpu_buf; + + dst_buf = wave6_get_dst_buf_by_addr(inst, addr); + if (!dst_buf) + return; + + vpu_buf = wave6_to_vpu_buf(dst_buf); + if (!vpu_buf->used) { + dprintk(inst->dev->dev, "[%d] recycle display buffer\n", inst->id); + vpu_buf->consumed = false; + return; + } + + if (inst->dst_fmt.num_planes == 1) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + } else if (inst->dst_fmt.num_planes == 2) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, + inst->dst_fmt.plane_fmt[1].sizeimage); + } else if (inst->dst_fmt.num_planes == 3) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, + inst->dst_fmt.plane_fmt[0].sizeimage); + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, + inst->dst_fmt.plane_fmt[1].sizeimage); + vb2_set_plane_payload(&dst_buf->vb2_buf, 2, + inst->dst_fmt.plane_fmt[2].sizeimage); + } + + vpu_buf->ts_output = ktime_get_raw(); + wave6_vpu_handle_performance(inst, vpu_buf); + + if (vpu_buf->error) + state = VB2_BUF_STATE_ERROR; + dst_buf->sequence = inst->sequence++; + dst_buf->field = V4L2_FIELD_NONE; + if (state == VB2_BUF_STATE_ERROR) + dprintk(inst->dev->dev, "[%d] discard frame %d\n", inst->id, dst_buf->sequence); + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf); + v4l2_m2m_buf_done(dst_buf, state); +} + +static void wave6_handle_display_frames(struct vpu_instance *inst, + struct dec_output_info *info) +{ + int i; + + for (i = 0; i < info->disp_frame_num; i++) + wave6_handle_display_frame(inst, + info->disp_frame_addr[i], + VB2_BUF_STATE_DONE); +} + +static void wave6_handle_discard_frames(struct vpu_instance *inst, + struct dec_output_info *info) +{ + int i; + + for (i = 0; i < info->release_disp_frame_num; i++) + wave6_handle_display_frame(inst, + info->release_disp_frame_addr[i], + VB2_BUF_STATE_ERROR); +} + +static void wave6_handle_last_frame(struct vpu_instance *inst, + struct vb2_v4l2_buffer *dst_buf) +{ + if (!dst_buf) { + dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx); + if (!dst_buf) { + inst->next_buf_last = true; + return; + } + } + + if (inst->dst_fmt.num_planes == 1) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + } else if (inst->dst_fmt.num_planes == 2) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + } else if (inst->dst_fmt.num_planes == 3) { + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + vb2_set_plane_payload(&dst_buf->vb2_buf, 2, 0); + } + + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + dst_buf->field = V4L2_FIELD_NONE; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + if (inst->state != VPU_INST_STATE_INIT_SEQ) { + dprintk(inst->dev->dev, "[%d] eos\n", inst->id); + inst->eos = true; + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false); + } +} + +static void wave6_vpu_dec_retry_one_frame(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *src_buf; + struct vpu_buffer *vpu_buf; + + src_buf = v4l2_m2m_next_src_buf(inst->v4l2_fh.m2m_ctx); + if (!src_buf) + return; + + vpu_buf = wave6_to_vpu_buf(src_buf); + vpu_buf->consumed = false; +} + +static void wave6_vpu_dec_handle_source_change(struct vpu_instance *inst, + struct dec_initial_info *info) +{ + static const struct v4l2_event vpu_event_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + dprintk(inst->dev->dev, "pic size %dx%d profile %d, min_fb_cnt : %d | min_disp_cnt : %d\n", + info->pic_width, info->pic_height, + info->profile, info->min_frame_buffer_count, info->frame_buf_delay); + + wave6_vpu_dec_retry_one_frame(inst); + wave6_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO, NULL); + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ); + + inst->crop.left = info->pic_crop_rect.left; + inst->crop.top = info->pic_crop_rect.top; + inst->crop.width = info->pic_crop_rect.right - inst->crop.left; + inst->crop.height = info->pic_crop_rect.bottom - inst->crop.top; + + wave6_update_v4l2_ctrls(inst, info); + wave6_update_color_info(inst, info); + wave6_update_pix_fmt(&inst->src_fmt, info->pic_width, info->pic_height); + wave6_update_pix_fmt_cap(&inst->dst_fmt, + info->pic_width, info->pic_height, + true); + + trace_source_change(inst, info); + + v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_src_ch); +} + +static void wave6_vpu_dec_handle_decoding_warn_error(struct vpu_instance *inst, + struct dec_output_info *info) +{ + if (info->warn_info) + dev_dbg(inst->dev->dev, "[%d] decoding %d warning 0x%x\n", + inst->id, inst->processed_buf_num, info->warn_info); + + if (info->error_reason) + dev_err(inst->dev->dev, "[%d] decoding %d error 0x%x\n", + inst->id, inst->processed_buf_num, info->error_reason); +} + +static void wave6_vpu_dec_finish_decode(struct vpu_instance *inst, bool error) +{ + struct dec_output_info info; + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + int ret; + + ret = wave6_vpu_dec_get_output_info(inst, &info); + if (ret) + goto finish_decode; + + trace_dec_done(inst, &info); + + dev_dbg(inst->dev->dev, "dec %d dis %d noti_flag %d stream_end %d\n", + info.frame_decoded, info.frame_display, + info.notification_flags, info.stream_end); + + if (info.notification_flags & DEC_NOTI_FLAG_NO_FB) { + wave6_vpu_dec_retry_one_frame(inst); + goto finish_decode; + } + + if (info.notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) { + struct dec_initial_info initial_info = {0}; + + v4l2_m2m_mark_stopped(m2m_ctx); + + if (info.frame_display) + wave6_handle_display_frames(inst, &info); + + if (info.release_disp_frame_num) + wave6_handle_discard_frames(inst, &info); + + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info); + wave6_vpu_dec_handle_source_change(inst, &initial_info); + + wave6_handle_last_frame(inst, NULL); + + goto finish_decode; + } + + wave6_vpu_dec_handle_decoding_warn_error(inst, &info); + + if (info.frame_decoded) + wave6_handle_decoded_frame(inst, &info); + else + wave6_handle_skipped_frame(inst); + + if (info.frame_display) + wave6_handle_display_frames(inst, &info); + + if (info.release_disp_frame_num) + wave6_handle_discard_frames(inst, &info); + + if (info.stream_end && !inst->eos) + wave6_handle_last_frame(inst, NULL); + +finish_decode: + wave6_vpu_finish_job(inst); +} + +static int wave6_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card)); + strscpy(cap->bus_info, "platform:" VPU_DEC_DRV_NAME, sizeof(cap->bus_info)); + + return 0; +} + +static int wave6_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) +{ + const struct vpu_format *vpu_fmt; + + if (fsize->index) + return -EINVAL; + + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_CODEC); + if (!vpu_fmt) { + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_RAW); + if (!vpu_fmt) + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = vpu_fmt->min_width; + fsize->stepwise.max_width = vpu_fmt->max_width; + fsize->stepwise.step_width = W6_DEC_PIC_SIZE_STEP; + fsize->stepwise.min_height = vpu_fmt->min_height; + fsize->stepwise.max_height = vpu_fmt->max_height; + fsize->stepwise.step_height = W6_DEC_PIC_SIZE_STEP; + + return 0; +} + +static int wave6_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + const struct vpu_format *vpu_fmt; + + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_RAW); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave6_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + if (!V4L2_TYPE_IS_CAPTURE(f->type)) + return -EINVAL; + + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_RAW); + if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + pix_mp->pixelformat = inst->dst_fmt.pixelformat; + pix_mp->num_planes = inst->dst_fmt.num_planes; + } else { + width = clamp(pix_mp->width, + vpu_fmt->min_width, round_up(inst->src_fmt.width, 32)); + height = clamp(pix_mp->height, + vpu_fmt->min_height, inst->src_fmt.height); + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt; + pix_mp->num_planes = vpu_fmt->num_planes; + } + + if (inst->state >= VPU_INST_STATE_INIT_SEQ) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + } + + wave6_update_pix_fmt_cap(pix_mp, width, height, false); + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i, ret; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + ret = wave6_vpu_dec_try_fmt_cap(file, fh, f); + if (ret) + return ret; + + inst->dst_fmt.width = pix_mp->width; + inst->dst_fmt.height = pix_mp->height; + inst->dst_fmt.pixelformat = pix_mp->pixelformat; + inst->dst_fmt.field = pix_mp->field; + inst->dst_fmt.flags = pix_mp->flags; + inst->dst_fmt.num_planes = pix_mp->num_planes; + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline; + inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage; + } + + if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) { + inst->cbcr_interleave = true; + inst->nv21 = false; + } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 || + inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + } else { + inst->cbcr_interleave = false; + inst->nv21 = false; + } + + return 0; +} + +static int wave6_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i; + + pix_mp->width = inst->dst_fmt.width; + pix_mp->height = inst->dst_fmt.height; + pix_mp->pixelformat = inst->dst_fmt.pixelformat; + pix_mp->field = inst->dst_fmt.field; + pix_mp->flags = inst->dst_fmt.flags; + pix_mp->num_planes = inst->dst_fmt.num_planes; + for (i = 0; i < pix_mp->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; + pix_mp->plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; + } + + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f->index); + + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_CODEC); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED; + + return 0; +} + +static int wave6_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + if (!V4L2_TYPE_IS_OUTPUT(f->type)) + return -EINVAL; + + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_CODEC); + if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; + pix_mp->pixelformat = inst->src_fmt.pixelformat; + pix_mp->num_planes = inst->src_fmt.num_planes; + } else { + width = pix_mp->width; + height = pix_mp->height; + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt; + pix_mp->num_planes = vpu_fmt->num_planes; + } + + wave6_update_pix_fmt(pix_mp, width, height); + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane in_pix_mp = f->fmt.pix_mp; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i, ret; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + ret = wave6_vpu_dec_try_fmt_out(file, fh, f); + if (ret) + return ret; + + pix_mp->colorspace = in_pix_mp.colorspace; + pix_mp->ycbcr_enc = in_pix_mp.ycbcr_enc; + pix_mp->quantization = in_pix_mp.quantization; + pix_mp->xfer_func = in_pix_mp.xfer_func; + + inst->src_fmt.width = pix_mp->width; + inst->src_fmt.height = pix_mp->height; + inst->src_fmt.pixelformat = pix_mp->pixelformat; + inst->src_fmt.field = pix_mp->field; + inst->src_fmt.flags = pix_mp->flags; + inst->src_fmt.num_planes = pix_mp->num_planes; + for (i = 0; i < inst->src_fmt.num_planes; i++) { + inst->src_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline; + inst->src_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage; + } + + inst->colorspace = pix_mp->colorspace; + inst->ycbcr_enc = pix_mp->ycbcr_enc; + inst->quantization = pix_mp->quantization; + inst->xfer_func = pix_mp->xfer_func; + + wave6_update_pix_fmt_cap(&inst->dst_fmt, + pix_mp->width, pix_mp->height, + true); + + return 0; +} + +static int wave6_vpu_dec_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i; + + pix_mp->width = inst->src_fmt.width; + pix_mp->height = inst->src_fmt.height; + pix_mp->pixelformat = inst->src_fmt.pixelformat; + pix_mp->field = inst->src_fmt.field; + pix_mp->flags = inst->src_fmt.flags; + pix_mp->num_planes = inst->src_fmt.num_planes; + for (i = 0; i < pix_mp->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline; + pix_mp->plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage; + } + + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type %d target %d\n", + __func__, s->type, s->target); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->dst_fmt.width; + s->r.height = inst->dst_fmt.height; + break; + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE: + s->r.left = 0; + s->r.top = 0; + if (inst->scaler_info.enable) { + s->r.width = inst->scaler_info.width; + s->r.height = inst->scaler_info.height; + } else if (inst->crop.width && inst->crop.height) { + s->r = inst->crop; + } else { + s->r.width = inst->src_fmt.width; + s->r.height = inst->src_fmt.height; + } + break; + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->src_fmt.width; + s->r.height = inst->src_fmt.height; + if (inst->crop.width && inst->crop.height) + s->r = inst->crop; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave6_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + int step = 4; + int scale_width, scale_height; + int min_scale_width, min_scale_height; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + if (s->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE))) + s->flags |= V4L2_SEL_FLAG_LE; + + scale_width = clamp(s->r.width, W6_MIN_DEC_PIC_WIDTH, + round_up(inst->src_fmt.width, 32)); + scale_height = clamp(s->r.height, W6_MIN_DEC_PIC_HEIGHT, + inst->src_fmt.height); + if (s->flags & V4L2_SEL_FLAG_GE) { + scale_width = round_up(scale_width, step); + scale_height = round_up(scale_height, step); + } + if (s->flags & V4L2_SEL_FLAG_LE) { + scale_width = round_down(scale_width, step); + scale_height = round_down(scale_height, step); + } + + if (scale_width < inst->src_fmt.width || + scale_height < inst->src_fmt.height) + inst->scaler_info.enable = true; + + if (inst->scaler_info.enable) { + min_scale_width = ALIGN((inst->src_fmt.width / 8), step); + min_scale_height = ALIGN((inst->src_fmt.height / 8), step); + + if (scale_width < W6_MIN_DEC_PIC_WIDTH) + scale_width = W6_MIN_DEC_PIC_WIDTH; + if (scale_width < min_scale_width) + scale_width = min_scale_width; + if (scale_height < W6_MIN_DEC_PIC_HEIGHT) + scale_height = W6_MIN_DEC_PIC_HEIGHT; + if (scale_height < min_scale_height) + scale_height = min_scale_height; + + inst->scaler_info.width = scale_width; + inst->scaler_info.height = scale_height; + } + + s->r.left = 0; + s->r.top = 0; + s->r.width = scale_width; + s->r.height = scale_height; + + return 0; +} + +static int wave6_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + int ret; + + dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, dc->cmd); + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + if (ret) + return ret; + + switch (dc->cmd) { + case V4L2_DEC_CMD_STOP: + dprintk(inst->dev->dev, "[%d] drain\n", inst->id); + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true); + v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx); + break; + case V4L2_DEC_CMD_START: + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ioctl_ops wave6_vpu_dec_ioctl_ops = { + .vidioc_querycap = wave6_vpu_dec_querycap, + .vidioc_enum_framesizes = wave6_vpu_dec_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = wave6_vpu_dec_enum_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_dec_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_dec_g_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_dec_try_fmt_cap, + + .vidioc_enum_fmt_vid_out = wave6_vpu_dec_enum_fmt_out, + .vidioc_s_fmt_vid_out_mplane = wave6_vpu_dec_s_fmt_out, + .vidioc_g_fmt_vid_out_mplane = wave6_vpu_dec_g_fmt_out, + .vidioc_try_fmt_vid_out_mplane = wave6_vpu_dec_try_fmt_out, + + .vidioc_g_selection = wave6_vpu_dec_g_selection, + .vidioc_s_selection = wave6_vpu_dec_s_selection, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = wave6_vpu_dec_decoder_cmd, + + .vidioc_subscribe_event = wave6_vpu_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int wave6_vpu_dec_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl); + + trace_s_ctrl(inst, ctrl); + + dev_dbg(inst->dev->dev, "%s: name %s value %d\n", + __func__, ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_VPU_THUMBNAIL_MODE: + inst->thumbnail_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: + inst->disp_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops wave6_vpu_dec_ctrl_ops = { + .s_ctrl = wave6_vpu_dec_s_ctrl, +}; + +static const struct v4l2_ctrl_config wave6_vpu_thumbnail_mode = { + .ops = &wave6_vpu_dec_ctrl_ops, + .id = V4L2_CID_VPU_THUMBNAIL_MODE, + .name = "thumbnail mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .def = 0, + .min = 0, + .max = 1, + .step = 1, + .flags = V4L2_CTRL_FLAG_WRITE_ONLY, +}; + +static void wave6_set_dec_openparam(struct dec_open_param *open_param, + struct vpu_instance *inst) +{ + open_param->inst_buffer.temp_base = inst->dev->temp_vbuf.daddr; + open_param->inst_buffer.temp_size = inst->dev->temp_vbuf.size; + open_param->bs_mode = BS_MODE_PIC_END; + open_param->stream_endian = VPU_STREAM_ENDIAN; + open_param->frame_endian = VPU_FRAME_ENDIAN; + open_param->disp_mode = inst->disp_mode; +} + +static int wave6_vpu_dec_create_instance(struct vpu_instance *inst) +{ + int ret; + struct dec_open_param open_param; + + memset(&open_param, 0, sizeof(struct dec_open_param)); + + wave6_vpu_activate(inst->dev); + ret = pm_runtime_resume_and_get(inst->dev->dev); + if (ret) { + dev_err(inst->dev->dev, "runtime_resume failed %d\n", ret); + return ret; + } + + wave6_vpu_wait_activated(inst->dev); + + inst->std = wave6_to_codec_std(inst->type, inst->src_fmt.pixelformat); + if (inst->std == STD_UNKNOWN) { + dev_err(inst->dev->dev, "unsupported pixelformat: %.4s\n", + (char *)&inst->src_fmt.pixelformat); + ret = -EINVAL; + goto error_pm; + } + + wave6_set_dec_openparam(&open_param, inst); + + ret = wave6_vpu_dec_open(inst, &open_param); + if (ret) { + dev_err(inst->dev->dev, "failed create instance : %d\n", ret); + goto error_pm; + } + + dprintk(inst->dev->dev, "[%d] decoder\n", inst->id); + + if (inst->thumbnail_mode) + wave6_vpu_dec_give_command(inst, ENABLE_DEC_THUMBNAIL_MODE, NULL); + + wave6_vpu_create_dbgfs_file(inst); + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN); + inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = true; + v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx, true); + + return 0; + +error_pm: + pm_runtime_put_sync(inst->dev->dev); + + return ret; +} + +static int wave6_vpu_dec_prepare_fb(struct vpu_instance *inst) +{ + int ret; + unsigned int i; + unsigned int fb_num; + unsigned int mv_num; + unsigned int fb_stride; + unsigned int fb_height; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + fb_num = p_dec_info->initial_info.min_frame_buffer_count; + mv_num = p_dec_info->initial_info.req_mv_buffer_count; + + fb_stride = ALIGN(inst->src_fmt.width, 32); + fb_height = ALIGN(inst->src_fmt.height, 32); + + for (i = 0; i < fb_num; i++) { + struct frame_buffer *frame = &inst->frame_buf[i]; + struct vpu_buf *vframe = &inst->frame_vbuf[i]; + unsigned int l_size = fb_stride * fb_height; + unsigned int ch_size = ALIGN(fb_stride / 2, 32) * fb_height; + + vframe->size = l_size + ch_size; + ret = wave6_alloc_dma(inst->dev->dev, vframe); + if (ret) { + dev_err(inst->dev->dev, "alloc FBC buffer fail : %zu\n", + vframe->size); + goto error; + } + + frame->buf_y = vframe->daddr; + frame->buf_cb = vframe->daddr + l_size; + frame->buf_cr = (dma_addr_t)-1; + frame->width = inst->src_fmt.width; + frame->stride = fb_stride; + frame->height = fb_height; + frame->map_type = COMPRESSED_FRAME_MAP; + } + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL, fb_num); + if (ret) + goto error; + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL, fb_num); + if (ret) + goto error; + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL, mv_num); + if (ret) + goto error; + + ret = wave6_vpu_dec_register_frame_buffer_ex(inst, fb_num, fb_stride, + fb_height, + COMPRESSED_FRAME_MAP); + if (ret) { + dev_err(inst->dev->dev, "register frame buffer fail %d\n", ret); + goto error; + } + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN); + + return 0; + +error: + wave6_vpu_dec_release_fb(inst); + return ret; +} + +static int wave6_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane inst_format = + (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; + + dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d type %d\n", + __func__, *num_buffers, *num_planes, q->type); + + if (*num_planes) { + if (inst_format.num_planes != *num_planes) + return -EINVAL; + + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < inst_format.plane_fmt[i].sizeimage) + return -EINVAL; + } + } else { + *num_planes = inst_format.num_planes; + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "size[%d] : %d\n", i, sizes[i]); + } + + if (V4L2_TYPE_IS_CAPTURE(q->type)) { + struct v4l2_ctrl *ctrl; + unsigned int min_disp_cnt = 0; + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE); + if (ctrl) + min_disp_cnt = v4l2_ctrl_g_ctrl(ctrl); + + *num_buffers = max(*num_buffers, min_disp_cnt); + + if (*num_buffers > WAVE6_MAX_FBS) + *num_buffers = min_disp_cnt; + } + } + + if (V4L2_TYPE_IS_OUTPUT(q->type) && + inst->state == VPU_INST_STATE_SEEK) { + wave6_vpu_pause(inst->dev->dev, 0); + wave6_vpu_dec_destroy_instance(inst); + wave6_vpu_pause(inst->dev->dev, 1); + } + + return 0; +} + +static int wave6_vpu_dec_seek_header(struct vpu_instance *inst) +{ + struct dec_initial_info initial_info; + int ret; + + memset(&initial_info, 0, sizeof(struct dec_initial_info)); + + ret = wave6_vpu_dec_issue_seq_init(inst); + if (ret) { + dev_err(inst->dev->dev, "failed wave6_vpu_dec_issue_seq_init %d\n", ret); + return ret; + } + + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) + dev_err(inst->dev->dev, "failed to call vpu_wait_interrupt()\n"); + + ret = wave6_vpu_dec_complete_seq_init(inst, &initial_info); + if (ret) { + dev_err(inst->dev->dev, "vpu_dec_complete_seq_init: %d, reason : 0x%x\n", + ret, initial_info.err_reason); + if ((initial_info.err_reason & WAVE6_SYSERR_NOT_SUPPORT) || + (initial_info.err_reason & WAVE6_SYSERR_NOT_SUPPORT_PROFILE)) { + ret = -EINVAL; + } else if ((initial_info.err_reason & HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND) || + (initial_info.err_reason & AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND)) { + wave6_handle_skipped_frame(inst); + ret = 0; + } + } else { + wave6_vpu_dec_handle_source_change(inst, &initial_info); + inst->v4l2_fh.m2m_ctx->ignore_cap_streaming = false; + v4l2_m2m_set_dst_buffered(inst->v4l2_fh.m2m_ctx, false); + if (vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx))) + wave6_handle_last_frame(inst, NULL); + } + + return ret; +} + +static void wave6_vpu_dec_buf_queue_src(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld size[1] : %4ld | size[2] : %4ld\n", + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + vbuf->sequence = inst->queued_src_buf_num++; + vpu_buf->ts_input = ktime_get_raw(); + + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf); +} + +static void wave6_vpu_dec_buf_queue_dst(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld size[1] : %4ld | size[2] : %4ld\n", + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + inst->queued_dst_buf_num++; + if (inst->next_buf_last) { + wave6_handle_last_frame(inst, vbuf); + inst->next_buf_last = false; + } else { + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf); + } +} + +static void wave6_vpu_dec_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf); + + vpu_buf->consumed = false; + vpu_buf->used = false; + vpu_buf->error = false; + if (V4L2_TYPE_IS_OUTPUT(vb->type)) + wave6_vpu_dec_buf_queue_src(vb); + else + wave6_vpu_dec_buf_queue_dst(vb); +} + +static int wave6_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane *fmt; + int ret = 0; + + trace_start_streaming(inst, q->type); + + wave6_vpu_pause(inst->dev->dev, 0); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + fmt = &inst->src_fmt; + if (inst->state == VPU_INST_STATE_NONE) { + ret = wave6_vpu_dec_create_instance(inst); + if (ret) + goto exit; + } + + if (inst->state == VPU_INST_STATE_SEEK) + wave6_vpu_set_instance_state(inst, inst->state_in_seek); + } else { + fmt = &inst->dst_fmt; + if (inst->state == VPU_INST_STATE_INIT_SEQ) { + ret = wave6_vpu_dec_prepare_fb(inst); + if (ret) + goto exit; + } + } + +exit: + wave6_vpu_pause(inst->dev->dev, 1); + if (ret) + wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_QUEUED); + + dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d buffers, ret = %d\n", + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture", + fmt->pixelformat, + fmt->pixelformat >> 8, + fmt->pixelformat >> 16, + fmt->pixelformat >> 24, + fmt->width, fmt->height, vb2_get_num_buffers(q), ret); + + return ret; +} + +static void wave6_vpu_dec_stop_streaming(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; + + trace_stop_streaming(inst, q->type); + + dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d error %d\n", + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture", + inst->queued_src_buf_num, inst->processed_buf_num, inst->error_buf_num); + + if (inst->state == VPU_INST_STATE_NONE) + goto exit; + + wave6_vpu_pause(inst->dev->dev, 0); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + wave6_vpu_reset_performance(inst); + inst->queued_src_buf_num = 0; + inst->processed_buf_num = 0; + inst->error_buf_num = 0; + inst->state_in_seek = inst->state; + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false); + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_SEEK); + inst->sequence = 0; + } else { + if (v4l2_m2m_has_stopped(m2m_ctx)) + v4l2_m2m_clear_state(m2m_ctx); + + inst->eos = false; + inst->queued_dst_buf_num = 0; + inst->sequence = 0; + wave6_vpu_dec_flush_instance(inst); + } + + wave6_vpu_pause(inst->dev->dev, 1); + +exit: + wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_ERROR); +} + +static int wave6_vpu_dec_buf_init(struct vb2_buffer *vb) +{ + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct dec_initial_info initial_info = {0}; + int i; + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) + return 0; + + wave6_vpu_dec_give_command(inst, DEC_GET_SEQ_INFO, &initial_info); + if (initial_info.chroma_format_idc != YUV400) + return 0; + + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + void *vaddr = vb2_plane_vaddr(vb, i); + + if (vaddr) + memset(vaddr, 0x80, vb2_plane_size(vb, i)); + } + + return 0; +} + +static const struct vb2_ops wave6_vpu_dec_vb2_ops = { + .queue_setup = wave6_vpu_dec_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = wave6_vpu_dec_buf_queue, + .start_streaming = wave6_vpu_dec_start_streaming, + .stop_streaming = wave6_vpu_dec_stop_streaming, + .buf_init = wave6_vpu_dec_buf_init, +}; + +static void wave6_set_default_format(struct v4l2_pix_format_mplane *src_fmt, + struct v4l2_pix_format_mplane *dst_fmt) +{ + const struct vpu_format *vpu_fmt; + + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC); + if (vpu_fmt) { + src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt; + src_fmt->num_planes = vpu_fmt->num_planes; + wave6_update_pix_fmt(src_fmt, + W6_DEF_DEC_PIC_WIDTH, W6_DEF_DEC_PIC_HEIGHT); + } + + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW); + if (vpu_fmt) { + dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt; + dst_fmt->num_planes = vpu_fmt->num_planes; + wave6_update_pix_fmt_cap(dst_fmt, + W6_DEF_DEC_PIC_WIDTH, W6_DEF_DEC_PIC_HEIGHT, + true); + } +} + +static int wave6_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct vpu_instance *inst = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->ops = &wave6_vpu_dec_vb2_ops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->buf_struct_size = sizeof(struct vpu_buffer); + src_vq->min_queued_buffers = 1; + src_vq->drv_priv = inst; + src_vq->lock = &inst->dev->dev_lock; + src_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->ops = &wave6_vpu_dec_vb2_ops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->buf_struct_size = sizeof(struct vpu_buffer); + dst_vq->min_queued_buffers = 1; + dst_vq->drv_priv = inst; + dst_vq->lock = &inst->dev->dev_lock; + dst_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(dst_vq); + if (ret) + return ret; + + return 0; +} + +static const struct vpu_instance_ops wave6_vpu_dec_inst_ops = { + .start_process = wave6_vpu_dec_start_decode, + .finish_process = wave6_vpu_dec_finish_decode, +}; + +static int wave6_vpu_open_dec(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct vpu_device *dev = video_drvdata(filp); + struct vpu_instance *inst = NULL; + int ret; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->dev = dev; + inst->type = VPU_INST_TYPE_DEC; + inst->ops = &wave6_vpu_dec_inst_ops; + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; + v4l2_fh_add(&inst->v4l2_fh); + + inst->v4l2_fh.m2m_ctx = + v4l2_m2m_ctx_init(dev->m2m_dev, inst, wave6_vpu_dec_queue_init); + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) { + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx); + goto free_inst; + } + + v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10); + v4l2_ctrl_new_custom(&inst->v4l2_ctrl_hdl, &wave6_vpu_thumbnail_mode, NULL); + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1); + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + 0, 0, 1, 0); + v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + 0, 1, 1, 0); + v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + v4l2_ctrl_new_std_menu(&inst->v4l2_ctrl_hdl, &wave6_vpu_dec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + + if (inst->v4l2_ctrl_hdl.error) { + ret = -ENODEV; + goto err_m2m_release; + } + + inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl); + + wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->colorspace = V4L2_COLORSPACE_DEFAULT; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->quantization = V4L2_QUANTIZATION_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + return 0; + +err_m2m_release: + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); +free_inst: + kfree(inst); + return ret; +} + +static int wave6_vpu_dec_release(struct file *filp) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(filp->private_data); + + dprintk(inst->dev->dev, "[%d] release\n", inst->id); + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); + + mutex_lock(&inst->dev->dev_lock); + if (inst->state != VPU_INST_STATE_NONE) { + wave6_vpu_pause(inst->dev->dev, 0); + wave6_vpu_dec_destroy_instance(inst); + wave6_vpu_pause(inst->dev->dev, 1); + } + mutex_unlock(&inst->dev->dev_lock); + + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); + v4l2_fh_del(&inst->v4l2_fh); + v4l2_fh_exit(&inst->v4l2_fh); + kfree(inst); + + return 0; +} + +static const struct v4l2_file_operations wave6_vpu_dec_fops = { + .owner = THIS_MODULE, + .open = wave6_vpu_open_dec, + .release = wave6_vpu_dec_release, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +int wave6_vpu_dec_register_device(struct vpu_device *dev) +{ + struct video_device *vdev_dec; + int ret; + + vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL); + if (!vdev_dec) + return -ENOMEM; + + dev->video_dev_dec = vdev_dec; + + strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec->name)); + vdev_dec->fops = &wave6_vpu_dec_fops; + vdev_dec->ioctl_ops = &wave6_vpu_dec_ioctl_ops; + vdev_dec->release = video_device_release_empty; + vdev_dec->v4l2_dev = &dev->v4l2_dev; + vdev_dec->vfl_dir = VFL_DIR_M2M; + vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vdev_dec->lock = &dev->dev_lock; + video_set_drvdata(vdev_dec, dev); + + ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + return 0; +} + +void wave6_vpu_dec_unregister_device(struct vpu_device *dev) +{ + video_unregister_device(dev->video_dev_dec); +} diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c new file mode 100644 index 000000000000..36417a7fef99 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-enc.c @@ -0,0 +1,2698 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - v4l2 stateful encoder interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include "wave6-vpu.h" +#include "wave6-vpu-dbg.h" +#include "wave6-trace.h" + +#define VPU_ENC_DEV_NAME "C&M Wave6 VPU encoder" +#define VPU_ENC_DRV_NAME "wave6-enc" + +static const struct vpu_format wave6_vpu_enc_fmt_list[2][23] = { + [VPU_FMT_TYPE_CODEC] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_H264, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + }, + [VPU_FMT_TYPE_RAW] = { + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUYV, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV24, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV24, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV42, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 3, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 2, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 2, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 3, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 2, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 2, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_RGB24, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_P010, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB32, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_XRGB32, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_RGBA32, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_RGBX32, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_ARGB2101010, + .max_width = W6_MAX_ENC_PIC_WIDTH, + .min_width = W6_MIN_ENC_PIC_WIDTH, + .max_height = W6_MAX_ENC_PIC_HEIGHT, + .min_height = W6_MIN_ENC_PIC_HEIGHT, + .num_planes = 1, + }, + } +}; + +static const struct vpu_format *wave6_find_vpu_fmt(unsigned int v4l2_pix_fmt, + enum vpu_fmt_type type) +{ + unsigned int index; + + for (index = 0; index < ARRAY_SIZE(wave6_vpu_enc_fmt_list[type]); index++) { + if (wave6_vpu_enc_fmt_list[type][index].v4l2_pix_fmt == v4l2_pix_fmt) + return &wave6_vpu_enc_fmt_list[type][index]; + } + + return NULL; +} + +static const struct vpu_format *wave6_find_vpu_fmt_by_idx(unsigned int idx, + enum vpu_fmt_type type) +{ + if (idx >= ARRAY_SIZE(wave6_vpu_enc_fmt_list[type])) + return NULL; + + if (!wave6_vpu_enc_fmt_list[type][idx].v4l2_pix_fmt) + return NULL; + + return &wave6_vpu_enc_fmt_list[type][idx]; +} + +static u32 wave6_cpb_size_msec(u32 cpb_size_kb, u32 bitrate) +{ + u64 cpb_size_bit; + u64 cpb_size_msec; + + cpb_size_bit = (u64)cpb_size_kb * 1000 * BITS_PER_BYTE; + cpb_size_msec = (cpb_size_bit * 1000) / bitrate; + + if (cpb_size_msec < 10 || cpb_size_msec > 100000) + cpb_size_msec = 10000; + + return cpb_size_msec; +} + +static void wave6_vpu_enc_release_fb(struct vpu_instance *inst) +{ + int i; + + for (i = 0; i < WAVE6_MAX_FBS; i++) { + wave6_free_dma(&inst->frame_vbuf[i]); + memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer)); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]); + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_SUB_SAMPLE][i]); + } +} + +static void wave6_vpu_enc_destroy_instance(struct vpu_instance *inst) +{ + u32 fail_res; + int ret; + + dprintk(inst->dev->dev, "[%d] destroy instance\n", inst->id); + wave6_vpu_remove_dbgfs_file(inst); + + ret = wave6_vpu_enc_close(inst, &fail_res); + if (ret) { + dev_err(inst->dev->dev, "failed destroy instance: %d (%d)\n", + ret, fail_res); + } + + wave6_vpu_enc_release_fb(inst); + wave6_free_dma(&inst->ar_vbuf); + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_NONE); + + if (!pm_runtime_suspended(inst->dev->dev)) + pm_runtime_put_sync(inst->dev->dev); +} + +static struct vb2_v4l2_buffer *wave6_get_valid_src_buf(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *vb2_v4l2_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vpu_buffer *vpu_buf = NULL; + + v4l2_m2m_for_each_src_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + vb2_v4l2_buf = &v4l2_m2m_buf->vb; + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf); + + if (!vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "no consumed src idx : %d\n", + vb2_v4l2_buf->vb2_buf.index); + return vb2_v4l2_buf; + } + } + + return NULL; +} + +static struct vb2_v4l2_buffer *wave6_get_valid_dst_buf(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *vb2_v4l2_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vpu_buffer *vpu_buf; + + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + vb2_v4l2_buf = &v4l2_m2m_buf->vb; + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf); + + if (!vpu_buf->consumed) { + dev_dbg(inst->dev->dev, "no consumed dst idx : %d\n", + vb2_v4l2_buf->vb2_buf.index); + return vb2_v4l2_buf; + } + } + + return NULL; +} + +static void wave6_set_csc(struct vpu_instance *inst, struct enc_param *pic_param) +{ + bool is_10bit = false; + + if (!(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24) && + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32) && + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32) && + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32) && + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) && + !(inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010)) + return; + + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) + is_10bit = true; + + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) + pic_param->csc.format_order = 8; + + if (inst->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT || + inst->ycbcr_enc == V4L2_YCBCR_ENC_601) { + if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) { + /* + * Y 0.299(R) 0.587(G) 0.114(B) + * Cb -0.16874(R) -0.33126(G) 0.5(B) + * Cr 0.5(R) -0.41869(G) -0.08131(B) + */ + pic_param->csc.coef_ry = 0x099; + pic_param->csc.coef_gy = 0x12d; + pic_param->csc.coef_by = 0x03a; + pic_param->csc.coef_rcb = 0xffffffaa; + pic_param->csc.coef_gcb = 0xffffff56; + pic_param->csc.coef_bcb = 0x100; + pic_param->csc.coef_rcr = 0x100; + pic_param->csc.coef_gcr = 0xffffff2a; + pic_param->csc.coef_bcr = 0xffffffd6; + pic_param->csc.offset_y = 0x0; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } else { + /* + * Y 0.258(R) 0.504(G) 0.098(B) + * Cb -0.1484(R) -0.2891(G) 0.4375(B) + * Cr 0.4375(R) -0.3672(G) -0.0703(B) + */ + pic_param->csc.coef_ry = 0x084; + pic_param->csc.coef_gy = 0x102; + pic_param->csc.coef_by = 0x032; + pic_param->csc.coef_rcb = 0xffffffb4; + pic_param->csc.coef_gcb = 0xffffff6c; + pic_param->csc.coef_bcb = 0x0e0; + pic_param->csc.coef_rcr = 0x0e0; + pic_param->csc.coef_gcr = 0xffffff44; + pic_param->csc.coef_bcr = 0xffffffdc; + pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_709) { + if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) { + /* + * Y 0.2126(R) 0.7152(G) 0.0722(B) + * Cb -0.11457(R) -0.38543(G) 0.5(B) + * Cr 0.5(R) -0.45415(G) -0.04585(B) + */ + pic_param->csc.coef_ry = 0x06d; + pic_param->csc.coef_gy = 0x16e; + pic_param->csc.coef_by = 0x025; + pic_param->csc.coef_rcb = 0xffffffc5; + pic_param->csc.coef_gcb = 0xffffff3b; + pic_param->csc.coef_bcb = 0x100; + pic_param->csc.coef_rcr = 0x100; + pic_param->csc.coef_gcr = 0xffffff17; + pic_param->csc.coef_bcr = 0xffffffe9; + pic_param->csc.offset_y = 0x0; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } else { + pic_param->csc.coef_ry = 0x05e; + pic_param->csc.coef_gy = 0x13b; + pic_param->csc.coef_by = 0x020; + pic_param->csc.coef_rcb = 0xffffffcc; + pic_param->csc.coef_gcb = 0xffffff53; + pic_param->csc.coef_bcb = 0x0e1; + pic_param->csc.coef_rcr = 0x0e1; + pic_param->csc.coef_gcr = 0xffffff34; + pic_param->csc.coef_bcr = 0xffffffeb; + pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_BT2020) { + if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) { + /* + * Y 0.2627(R) 0.678(G) 0.0593(B) + * Cb -0.13963(R) -0.36037(G) 0.5(B) + * Cr 0.5(R) -0.45979(G) -0.04021(B) + */ + pic_param->csc.coef_ry = 0x087; + pic_param->csc.coef_gy = 0x15b; + pic_param->csc.coef_by = 0x01e; + pic_param->csc.coef_rcb = 0xffffffb9; + pic_param->csc.coef_gcb = 0xffffff47; + pic_param->csc.coef_bcb = 0x100; + pic_param->csc.coef_rcr = 0x100; + pic_param->csc.coef_gcr = 0xffffff15; + pic_param->csc.coef_bcr = 0xffffffeb; + pic_param->csc.offset_y = 0x0; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } else { + pic_param->csc.coef_ry = 0x074; + pic_param->csc.coef_gy = 0x12a; + pic_param->csc.coef_by = 0x01a; + pic_param->csc.coef_rcb = 0xffffffc1; + pic_param->csc.coef_gcb = 0xffffff5e; + pic_param->csc.coef_bcb = 0x0e1; + pic_param->csc.coef_rcr = 0x0e1; + pic_param->csc.coef_gcr = 0xffffff31; + pic_param->csc.coef_bcr = 0xffffffee; + pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_SMPTE240M) { + if (inst->quantization == V4L2_QUANTIZATION_FULL_RANGE) { + /* + * Y 0.2122(R) 0.7013(G) 0.0865(B) + * Cb -0.1161(R) -0.3839(G) 0.5(B) + * Cr 0.5(R) -0.4451(G) -0.0549(B) + */ + pic_param->csc.coef_ry = 0x06d; + pic_param->csc.coef_gy = 0x167; + pic_param->csc.coef_by = 0x02c; + pic_param->csc.coef_rcb = 0xffffffc5; + pic_param->csc.coef_gcb = 0xffffff3b; + pic_param->csc.coef_bcb = 0x100; + pic_param->csc.coef_rcr = 0x100; + pic_param->csc.coef_gcr = 0xffffff1c; + pic_param->csc.coef_bcr = 0xffffffe4; + pic_param->csc.offset_y = 0x0; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } else { + pic_param->csc.coef_ry = 0x05d; + pic_param->csc.coef_gy = 0x134; + pic_param->csc.coef_by = 0x026; + pic_param->csc.coef_rcb = 0xffffffcc; + pic_param->csc.coef_gcb = 0xffffff53; + pic_param->csc.coef_bcb = 0x0e1; + pic_param->csc.coef_rcr = 0x0e1; + pic_param->csc.coef_gcr = 0xffffff38; + pic_param->csc.coef_bcr = 0xffffffe7; + pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10; + pic_param->csc.offset_cb = (is_10bit) ? 0x200 : 0x80; + pic_param->csc.offset_cr = (is_10bit) ? 0x200 : 0x80; + } + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV601) { + if (inst->quantization == V4L2_QUANTIZATION_LIM_RANGE) { + /* + * Y 0.2558(R) 0.5021(G) 0.0975(B) + * Cb -0.1476(R) -0.2899(G) 0.4375(B) + * Cr 0.4375(R) -0.3664(G) -0.0711(B) + */ + pic_param->csc.coef_ry = 0x083; + pic_param->csc.coef_gy = 0x101; + pic_param->csc.coef_by = 0x032; + pic_param->csc.coef_rcb = 0xffffffb4; + pic_param->csc.coef_gcb = 0xffffff6c; + pic_param->csc.coef_bcb = 0x0e0; + pic_param->csc.coef_rcr = 0x0e0; + pic_param->csc.coef_gcr = 0xffffff44; + pic_param->csc.coef_bcr = 0xffffffdc; + pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10; + pic_param->csc.offset_cb = 0x0; + pic_param->csc.offset_cr = 0x0; + } + } else if (inst->ycbcr_enc == V4L2_YCBCR_ENC_XV709) { + if (inst->quantization == V4L2_QUANTIZATION_LIM_RANGE) { + /* + * Y 0.1819(R) 0.6118(G) 0.0618(B) + * Cb -0.1003(R) -0.3372(G) 0.4375(B) + * Cr 0.4375(R) -0.3974(G) -0.0401(B) + */ + pic_param->csc.coef_ry = 0x05d; + pic_param->csc.coef_gy = 0x139; + pic_param->csc.coef_by = 0x020; + pic_param->csc.coef_rcb = 0xffffffcd; + pic_param->csc.coef_gcb = 0xffffff53; + pic_param->csc.coef_bcb = 0x0e0; + pic_param->csc.coef_rcr = 0x0e0; + pic_param->csc.coef_gcr = 0xffffff35; + pic_param->csc.coef_bcr = 0xffffffeb; + pic_param->csc.offset_y = (is_10bit) ? 0x40 : 0x10; + pic_param->csc.offset_cb = 0x0; + pic_param->csc.offset_cr = 0x0; + } + } +} + +static void wave6_update_crop_info(struct vpu_instance *inst, + u32 left, u32 top, u32 width, u32 height) +{ + u32 enc_pic_width, enc_pic_height; + + inst->crop.left = left; + inst->crop.top = top; + inst->crop.width = width; + inst->crop.height = height; + + inst->codec_rect.left = round_down(left, W6_ENC_CROP_X_POS_STEP); + inst->codec_rect.top = round_down(top, W6_ENC_CROP_Y_POS_STEP); + + enc_pic_width = width + left - inst->codec_rect.left; + inst->codec_rect.width = round_up(enc_pic_width, W6_ENC_PIC_SIZE_STEP); + + enc_pic_height = height + top - inst->codec_rect.top; + inst->codec_rect.height = round_up(enc_pic_height, W6_ENC_PIC_SIZE_STEP); +} + +static int wave6_allocate_aux_buffer(struct vpu_instance *inst, + enum aux_buffer_type type, + int num) +{ + struct aux_buffer buf[WAVE6_MAX_FBS]; + struct aux_buffer_info buf_info; + struct enc_aux_buffer_size_info size_info; + unsigned int size; + int i, ret; + + memset(buf, 0, sizeof(buf)); + + size_info.width = inst->codec_rect.width; + size_info.height = inst->codec_rect.height; + size_info.type = type; + size_info.mirror_direction = inst->enc_ctrls.mirror_direction; + size_info.rotation_angle = inst->enc_ctrls.rot_angle; + + ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info, &size); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Get size fail (type %d)\n", __func__, type); + return ret; + } + + for (i = 0; i < num; i++) { + inst->aux_vbuf[type][i].size = size; + ret = wave6_alloc_dma(inst->dev->dev, &inst->aux_vbuf[type][i]); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Alloc fail (type %d)\n", __func__, type); + return ret; + } + + buf[i].index = i; + buf[i].addr = inst->aux_vbuf[type][i].daddr; + buf[i].size = inst->aux_vbuf[type][i].size; + } + + buf_info.type = type; + buf_info.num = num; + buf_info.buf_array = buf; + + ret = wave6_vpu_enc_register_aux_buffer(inst, buf_info); + if (ret) { + dev_dbg(inst->dev->dev, "%s: Register fail (type %d)\n", __func__, type); + return ret; + } + + return 0; +} + +static void wave6_update_frame_buf_addr(struct vpu_instance *inst, + struct frame_buffer *frame_buf) +{ + const struct v4l2_format_info *fmt_info; + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline; + u32 offset; + + fmt_info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!fmt_info) + return; + + offset = inst->codec_rect.top * stride + inst->codec_rect.left * fmt_info->bpp[0]; + frame_buf->buf_y += offset; + + stride = DIV_ROUND_UP(stride, fmt_info->bpp[0]) * fmt_info->bpp[1]; + offset = inst->codec_rect.top * stride / fmt_info->vdiv / fmt_info->hdiv + + inst->codec_rect.left * fmt_info->bpp[1] / fmt_info->hdiv; + frame_buf->buf_cb += offset; + frame_buf->buf_cr += offset; +} + +static int wave6_update_seq_param(struct vpu_instance *inst) +{ + struct enc_initial_info initial_info; + bool changed = false; + int ret; + + ret = wave6_vpu_enc_issue_seq_change(inst, &changed); + if (ret) { + dev_err(inst->dev->dev, "seq change fail %d\n", ret); + return ret; + } + + if (!changed) + return 0; + + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) { + dev_err(inst->dev->dev, "seq change timeout\n"); + return ret; + } + + wave6_vpu_enc_complete_seq_init(inst, &initial_info); + if (ret) { + dev_err(inst->dev->dev, "seq change error\n"); + return ret; + } + + return 0; +} + +static int wave6_vpu_enc_start_encode(struct vpu_instance *inst) +{ + int ret = -EINVAL; + struct vb2_v4l2_buffer *src_buf = NULL; + struct vb2_v4l2_buffer *dst_buf = NULL; + struct vpu_buffer *src_vbuf = NULL; + struct vpu_buffer *dst_vbuf = NULL; + struct frame_buffer frame_buf; + struct enc_param pic_param; + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline; + u32 luma_size = (stride * inst->src_fmt.height); + u32 chroma_size; + u32 fail_res; + + memset(&pic_param, 0, sizeof(struct enc_param)); + memset(&frame_buf, 0, sizeof(struct frame_buffer)); + + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M) + chroma_size = ((stride / 2) * (inst->src_fmt.height / 2)); + else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M) + chroma_size = ((stride) * (inst->src_fmt.height / 2)); + else + chroma_size = 0; + + ret = wave6_update_seq_param(inst); + if (ret) + goto exit; + + src_buf = wave6_get_valid_src_buf(inst); + dst_buf = wave6_get_valid_dst_buf(inst); + + if (!dst_buf) { + dev_dbg(inst->dev->dev, "no valid dst buf\n"); + goto exit; + } + + dst_vbuf = wave6_to_vpu_buf(dst_buf); + pic_param.pic_stream_buffer_addr = wave6_get_dma_addr(dst_buf, 0); + pic_param.pic_stream_buffer_size = vb2_plane_size(&dst_buf->vb2_buf, 0); + if (!src_buf) { + dev_dbg(inst->dev->dev, "no valid src buf\n"); + if (inst->state == VPU_INST_STATE_STOP) + pic_param.src_end = true; + else + goto exit; + } else { + src_vbuf = wave6_to_vpu_buf(src_buf); + if (inst->src_fmt.num_planes == 1) { + frame_buf.buf_y = wave6_get_dma_addr(src_buf, 0); + frame_buf.buf_cb = frame_buf.buf_y + luma_size; + frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; + } else if (inst->src_fmt.num_planes == 2) { + frame_buf.buf_y = wave6_get_dma_addr(src_buf, 0); + frame_buf.buf_cb = wave6_get_dma_addr(src_buf, 1); + frame_buf.buf_cr = frame_buf.buf_cb + chroma_size; + } else if (inst->src_fmt.num_planes == 3) { + frame_buf.buf_y = wave6_get_dma_addr(src_buf, 0); + frame_buf.buf_cb = wave6_get_dma_addr(src_buf, 1); + frame_buf.buf_cr = wave6_get_dma_addr(src_buf, 2); + } + wave6_update_frame_buf_addr(inst, &frame_buf); + frame_buf.stride = stride; + pic_param.src_idx = src_buf->vb2_buf.index; + if (src_vbuf->force_key_frame || inst->error_recovery) { + pic_param.force_pic_type_enable = true; + pic_param.force_pic_type = ENC_FORCE_PIC_TYPE_IDR; + inst->error_recovery = false; + } + if (src_vbuf->force_frame_qp) { + pic_param.force_pic_qp_enable = true; + pic_param.force_pic_qp_i = src_vbuf->force_i_frame_qp; + pic_param.force_pic_qp_p = src_vbuf->force_p_frame_qp; + pic_param.force_pic_qp_b = src_vbuf->force_b_frame_qp; + } + src_vbuf->ts_start = ktime_get_raw(); + } + + pic_param.source_frame = &frame_buf; + wave6_set_csc(inst, &pic_param); + + if (src_vbuf) + src_vbuf->consumed = true; + if (dst_vbuf) { + dst_vbuf->consumed = true; + dst_vbuf->used = true; + } + + trace_enc_pic(inst, &pic_param); + + ret = wave6_vpu_enc_start_one_frame(inst, &pic_param, &fail_res); + if (ret) { + dev_err(inst->dev->dev, "[%d] %s: fail %d\n", inst->id, __func__, ret); + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP); + + dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx); + if (dst_buf) { + dst_buf->sequence = inst->sequence; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + } + + src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx); + if (src_buf) { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + inst->sequence++; + inst->processed_buf_num++; + inst->error_buf_num++; + } + } else { + dev_dbg(inst->dev->dev, "%s: success\n", __func__); + } + +exit: + return ret; +} + +static void wave6_handle_encoded_frame(struct vpu_instance *inst, + struct enc_output_info *info) +{ + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct vpu_buffer *vpu_buf; + struct vpu_buffer *dst_vpu_buf; + enum vb2_buffer_state state; + + state = info->encoding_success ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + src_buf = v4l2_m2m_src_buf_remove_by_idx(inst->v4l2_fh.m2m_ctx, + info->enc_src_idx); + if (!src_buf) { + dev_err(inst->dev->dev, "[%d] encoder can't find src buffer\n", inst->id); + return; + } + + vpu_buf = wave6_to_vpu_buf(src_buf); + if (!vpu_buf || !vpu_buf->consumed) { + dev_err(inst->dev->dev, "[%d] src buffer is not consumed\n", inst->id); + return; + } + + dst_buf = wave6_get_dst_buf_by_addr(inst, info->bitstream_buffer); + if (!dst_buf) { + dev_err(inst->dev->dev, "[%d] encoder can't find dst buffer\n", inst->id); + return; + } + + dst_vpu_buf = wave6_to_vpu_buf(dst_buf); + + dst_vpu_buf->average_qp = info->avg_ctu_qp; + dst_vpu_buf->ts_input = vpu_buf->ts_input; + dst_vpu_buf->ts_start = vpu_buf->ts_start; + dst_vpu_buf->ts_finish = ktime_get_raw(); + dst_vpu_buf->hw_time = wave6_vpu_cycle_to_ns(inst->dev, info->cycle.frame_cycle); + dst_vpu_buf->ts_output = ktime_get_raw(); + wave6_vpu_handle_performance(inst, dst_vpu_buf); + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_done(src_buf, state); + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, info->bitstream_size); + dst_buf->sequence = inst->sequence++; + dst_buf->field = V4L2_FIELD_NONE; + if (info->pic_type == PIC_TYPE_I) + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + else if (info->pic_type == PIC_TYPE_P) + dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; + else if (info->pic_type == PIC_TYPE_B) + dst_buf->flags |= V4L2_BUF_FLAG_BFRAME; + + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf); + if (state == VB2_BUF_STATE_ERROR) { + dprintk(inst->dev->dev, "[%d] error frame %d\n", inst->id, inst->sequence); + inst->error_recovery = true; + inst->error_buf_num++; + } + v4l2_m2m_buf_done(dst_buf, state); + inst->processed_buf_num++; +} + +static void wave6_handle_last_frame(struct vpu_instance *inst, + dma_addr_t addr) +{ + struct vb2_v4l2_buffer *dst_buf; + + dst_buf = wave6_get_dst_buf_by_addr(inst, addr); + if (!dst_buf) + return; + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + dst_buf->field = V4L2_FIELD_NONE; + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_dst_buf_remove_by_buf(inst->v4l2_fh.m2m_ctx, dst_buf); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN); + + dprintk(inst->dev->dev, "[%d] eos\n", inst->id); + inst->eos = true; + + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false); +} + +static void wave6_vpu_enc_finish_encode(struct vpu_instance *inst, bool error) +{ + int ret; + struct enc_output_info info; + + if (error) { + vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx)); + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx)); + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP); + inst->eos = true; + + goto finish_encode; + } + + ret = wave6_vpu_enc_get_output_info(inst, &info); + if (ret) { + dev_dbg(inst->dev->dev, "vpu_enc_get_output_info fail %d reason: %d | info : %d\n", + ret, info.error_reason, info.warn_info); + goto finish_encode; + } + + trace_enc_done(inst, &info); + + if (info.enc_src_idx >= 0 && info.recon_frame_index >= 0) + wave6_handle_encoded_frame(inst, &info); + else if (info.recon_frame_index == RECON_IDX_FLAG_ENC_END) + wave6_handle_last_frame(inst, info.bitstream_buffer); + +finish_encode: + wave6_vpu_finish_job(inst); +} + +static int wave6_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card)); + strscpy(cap->bus_info, "platform:" VPU_ENC_DRV_NAME, sizeof(cap->bus_info)); + + return 0; +} + +static int wave6_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize) +{ + const struct vpu_format *vpu_fmt; + + if (fsize->index) + return -EINVAL; + + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_CODEC); + if (!vpu_fmt) { + vpu_fmt = wave6_find_vpu_fmt(fsize->pixel_format, VPU_FMT_TYPE_RAW); + if (!vpu_fmt) + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = vpu_fmt->min_width; + fsize->stepwise.max_width = vpu_fmt->max_width; + fsize->stepwise.step_width = W6_ENC_PIC_SIZE_STEP; + fsize->stepwise.min_height = vpu_fmt->min_height; + fsize->stepwise.max_height = vpu_fmt->max_height; + fsize->stepwise.step_height = W6_ENC_PIC_SIZE_STEP; + + return 0; +} + +static int wave6_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "index : %d\n", f->index); + + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_CODEC); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave6_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + if (!V4L2_TYPE_IS_CAPTURE(f->type)) + return -EINVAL; + + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_CODEC); + if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; + pix_mp->pixelformat = inst->dst_fmt.pixelformat; + pix_mp->num_planes = inst->dst_fmt.num_planes; + } else { + width = pix_mp->width; + height = pix_mp->height; + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt; + pix_mp->num_planes = vpu_fmt->num_planes; + } + + wave6_update_pix_fmt(pix_mp, width, height); + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i, ret; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + ret = wave6_vpu_enc_try_fmt_cap(file, fh, f); + if (ret) + return ret; + + inst->std = wave6_to_codec_std(inst->type, pix_mp->pixelformat); + if (inst->std == STD_UNKNOWN) { + dev_err(inst->dev->dev, "unsupported pixelformat: %.4s\n", + (char *)&pix_mp->pixelformat); + return -EINVAL; + } + + inst->dst_fmt.width = pix_mp->width; + inst->dst_fmt.height = pix_mp->height; + inst->dst_fmt.pixelformat = pix_mp->pixelformat; + inst->dst_fmt.field = pix_mp->field; + inst->dst_fmt.flags = pix_mp->flags; + inst->dst_fmt.num_planes = pix_mp->num_planes; + for (i = 0; i < inst->dst_fmt.num_planes; i++) { + inst->dst_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline; + inst->dst_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage; + } + + return 0; +} + +static int wave6_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i; + + pix_mp->width = inst->dst_fmt.width; + pix_mp->height = inst->dst_fmt.height; + pix_mp->pixelformat = inst->dst_fmt.pixelformat; + pix_mp->field = inst->dst_fmt.field; + pix_mp->flags = inst->dst_fmt.flags; + pix_mp->num_planes = inst->dst_fmt.num_planes; + for (i = 0; i < pix_mp->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline; + pix_mp->plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage; + } + + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + + dev_dbg(inst->dev->dev, "%s: index %d\n", __func__, f->index); + + vpu_fmt = wave6_find_vpu_fmt_by_idx(f->index, VPU_FMT_TYPE_RAW); + if (!vpu_fmt) + return -EINVAL; + + f->pixelformat = vpu_fmt->v4l2_pix_fmt; + f->flags = 0; + + return 0; +} + +static int wave6_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct vpu_format *vpu_fmt; + int width, height; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + if (!V4L2_TYPE_IS_OUTPUT(f->type)) + return -EINVAL; + + vpu_fmt = wave6_find_vpu_fmt(pix_mp->pixelformat, VPU_FMT_TYPE_RAW); + if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; + pix_mp->pixelformat = inst->src_fmt.pixelformat; + pix_mp->num_planes = inst->src_fmt.num_planes; + } else { + width = clamp(pix_mp->width, + vpu_fmt->min_width, vpu_fmt->max_width); + height = clamp(pix_mp->height, + vpu_fmt->min_height, vpu_fmt->max_height); + + pix_mp->pixelformat = vpu_fmt->v4l2_pix_fmt; + pix_mp->num_planes = vpu_fmt->num_planes; + } + + wave6_update_pix_fmt(pix_mp, width, height); + + if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM) + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_BT2020; + if (pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV601 || + pix_mp->ycbcr_enc == V4L2_YCBCR_ENC_XV709) { + if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) + pix_mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; + } + + return 0; +} + +static int wave6_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i, ret; + + dev_dbg(inst->dev->dev, "%s: 4cc %d w %d h %d plane %d colorspace %d\n", + __func__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, + pix_mp->num_planes, pix_mp->colorspace); + + ret = wave6_vpu_enc_try_fmt_out(file, fh, f); + if (ret) + return ret; + + inst->src_fmt.width = pix_mp->width; + inst->src_fmt.height = pix_mp->height; + inst->src_fmt.pixelformat = pix_mp->pixelformat; + inst->src_fmt.field = pix_mp->field; + inst->src_fmt.flags = pix_mp->flags; + inst->src_fmt.num_planes = pix_mp->num_planes; + for (i = 0; i < inst->src_fmt.num_planes; i++) { + inst->src_fmt.plane_fmt[i].bytesperline = pix_mp->plane_fmt[i].bytesperline; + inst->src_fmt.plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].sizeimage; + } + + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) { + inst->cbcr_interleave = true; + inst->nv21 = false; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M) { + inst->cbcr_interleave = true; + inst->nv21 = true; + } else { + inst->cbcr_interleave = false; + inst->nv21 = false; + } + + inst->colorspace = pix_mp->colorspace; + inst->ycbcr_enc = pix_mp->ycbcr_enc; + inst->quantization = pix_mp->quantization; + inst->xfer_func = pix_mp->xfer_func; + + wave6_update_pix_fmt(&inst->dst_fmt, pix_mp->width, pix_mp->height); + wave6_update_crop_info(inst, 0, 0, pix_mp->width, pix_mp->height); + + return 0; +} + +static int wave6_vpu_enc_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + int i; + + dev_dbg(inst->dev->dev, "\n"); + + pix_mp->width = inst->src_fmt.width; + pix_mp->height = inst->src_fmt.height; + pix_mp->pixelformat = inst->src_fmt.pixelformat; + pix_mp->field = inst->src_fmt.field; + pix_mp->flags = inst->src_fmt.flags; + pix_mp->num_planes = inst->src_fmt.num_planes; + for (i = 0; i < pix_mp->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline; + pix_mp->plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage; + } + + pix_mp->colorspace = inst->colorspace; + pix_mp->ycbcr_enc = inst->ycbcr_enc; + pix_mp->quantization = inst->quantization; + pix_mp->xfer_func = inst->xfer_func; + + return 0; +} + +static int wave6_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type %d target %d\n", + __func__, s->type, s->target); + + if (!V4L2_TYPE_IS_OUTPUT(s->type)) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->src_fmt.width; + s->r.height = inst->src_fmt.height; + break; + case V4L2_SEL_TGT_CROP: + s->r = inst->crop; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave6_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + u32 max_crop_w, max_crop_h; + + if (!V4L2_TYPE_IS_OUTPUT(s->type)) + return -EINVAL; + + if (s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + if (!(s->flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE))) + s->flags |= V4L2_SEL_FLAG_LE; + + if (s->flags & V4L2_SEL_FLAG_GE) { + s->r.left = round_up(s->r.left, W6_ENC_CROP_STEP); + s->r.top = round_up(s->r.top, W6_ENC_CROP_STEP); + s->r.width = round_up(s->r.width, W6_ENC_CROP_STEP); + s->r.height = round_up(s->r.height, W6_ENC_CROP_STEP); + } + if (s->flags & V4L2_SEL_FLAG_LE) { + s->r.left = round_down(s->r.left, W6_ENC_CROP_STEP); + s->r.top = round_down(s->r.top, W6_ENC_CROP_STEP); + s->r.width = round_down(s->r.width, W6_ENC_CROP_STEP); + s->r.height = round_down(s->r.height, W6_ENC_CROP_STEP); + } + + max_crop_w = inst->src_fmt.width - s->r.left; + max_crop_h = inst->src_fmt.height - s->r.top; + + if (!s->r.width || !s->r.height) + return 0; + if (max_crop_w < W6_MIN_ENC_PIC_WIDTH) + return 0; + if (max_crop_h < W6_MIN_ENC_PIC_HEIGHT) + return 0; + + s->r.width = clamp(s->r.width, W6_MIN_ENC_PIC_WIDTH, max_crop_w); + s->r.height = clamp(s->r.height, W6_MIN_ENC_PIC_HEIGHT, max_crop_h); + + wave6_update_pix_fmt(&inst->dst_fmt, s->r.width, s->r.height); + wave6_update_crop_info(inst, s->r.left, s->r.top, s->r.width, s->r.height); + + dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_CROP %dx%dx%dx%d\n", + s->r.left, s->r.top, s->r.width, s->r.height); + + return 0; +} + +static int wave6_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + int ret; + + dev_dbg(inst->dev->dev, "%s: cmd %d\n", __func__, ec->cmd); + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + if (ret) + return ret; + + if (!wave6_vpu_both_queues_are_streaming(inst)) + return 0; + + switch (ec->cmd) { + case V4L2_ENC_CMD_STOP: + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP); + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true); + v4l2_m2m_try_schedule(inst->v4l2_fh.m2m_ctx); + break; + case V4L2_ENC_CMD_START: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wave6_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type); + + if (!V4L2_TYPE_IS_OUTPUT(a->type)) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.output.timeperframe.numerator = 1; + a->parm.output.timeperframe.denominator = inst->frame_rate; + + dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator : %d\n", + __func__, + a->parm.output.timeperframe.numerator, + a->parm.output.timeperframe.denominator); + + return 0; +} + +static int wave6_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + + dev_dbg(inst->dev->dev, "%s: type %d\n", __func__, a->type); + + if (!V4L2_TYPE_IS_OUTPUT(a->type)) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + if (a->parm.output.timeperframe.denominator && a->parm.output.timeperframe.numerator) { + inst->frame_rate = a->parm.output.timeperframe.denominator / + a->parm.output.timeperframe.numerator; + } else { + a->parm.output.timeperframe.numerator = 1; + a->parm.output.timeperframe.denominator = inst->frame_rate; + } + + dev_dbg(inst->dev->dev, "%s: numerator : %d | denominator : %d\n", + __func__, + a->parm.output.timeperframe.numerator, + a->parm.output.timeperframe.denominator); + + return 0; +} + +static const struct v4l2_ioctl_ops wave6_vpu_enc_ioctl_ops = { + .vidioc_querycap = wave6_vpu_enc_querycap, + .vidioc_enum_framesizes = wave6_vpu_enc_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = wave6_vpu_enc_enum_fmt_cap, + .vidioc_s_fmt_vid_cap_mplane = wave6_vpu_enc_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = wave6_vpu_enc_g_fmt_cap, + .vidioc_try_fmt_vid_cap_mplane = wave6_vpu_enc_try_fmt_cap, + + .vidioc_enum_fmt_vid_out = wave6_vpu_enc_enum_fmt_out, + .vidioc_s_fmt_vid_out_mplane = wave6_vpu_enc_s_fmt_out, + .vidioc_g_fmt_vid_out_mplane = wave6_vpu_enc_g_fmt_out, + .vidioc_try_fmt_vid_out_mplane = wave6_vpu_enc_try_fmt_out, + + .vidioc_g_selection = wave6_vpu_enc_g_selection, + .vidioc_s_selection = wave6_vpu_enc_s_selection, + + .vidioc_g_parm = wave6_vpu_enc_g_parm, + .vidioc_s_parm = wave6_vpu_enc_s_parm, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = wave6_vpu_enc_encoder_cmd, + + .vidioc_subscribe_event = wave6_vpu_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int wave6_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vpu_instance *inst = wave6_ctrl_to_vpu_inst(ctrl); + struct enc_controls *p = &inst->enc_ctrls; + + trace_s_ctrl(inst, ctrl); + + dev_dbg(inst->dev->dev, "%s: name %s value %d\n", + __func__, ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + p->mirror_direction |= (ctrl->val << 1); + break; + case V4L2_CID_VFLIP: + p->mirror_direction |= ctrl->val; + break; + case V4L2_CID_ROTATE: + p->rot_angle = ctrl->val; + break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + p->gop_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + p->slice_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + p->slice_max_mb = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + p->bitrate_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + p->bitrate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + p->frame_rc_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + p->mb_rc_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + p->force_key_frame = true; + break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + p->prepend_spspps_to_idr = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: + break; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: + p->intra_refresh_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + p->frame_skip_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + p->hevc.profile = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + p->hevc.level = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + p->hevc.min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + p->hevc.max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + p->hevc.i_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + p->hevc.p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + p->hevc.b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + p->hevc.loop_filter_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + p->hevc.lf_beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + p->hevc.lf_tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + p->hevc.refresh_type = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + p->hevc.refresh_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + p->hevc.const_intra_pred = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + p->hevc.strong_smoothing = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + p->hevc.tmv_prediction = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + p->h264.profile = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + p->h264.level = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + p->h264.min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + p->h264.max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + p->h264.i_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + p->h264.p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: + p->h264.b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + p->h264.loop_filter_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + p->h264.loop_filter_beta = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + p->h264.loop_filter_alpha = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + p->h264._8x8_transform = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + p->h264.constrained_intra_prediction = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + p->h264.chroma_qp_index_offset = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + p->h264.entropy_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: + p->h264.i_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: + p->h264.vui_sar_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + p->h264.vui_sar_idc = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: + p->h264.vui_ext_sar_width = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: + p->h264.vui_ext_sar_height = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: + p->h264.cpb_size = ctrl->val; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops wave6_vpu_enc_ctrl_ops = { + .s_ctrl = wave6_vpu_enc_s_ctrl, +}; + +static u32 to_video_full_range_flag(enum v4l2_quantization quantization) +{ + switch (quantization) { + case V4L2_QUANTIZATION_FULL_RANGE: + return 1; + case V4L2_QUANTIZATION_LIM_RANGE: + default: + return 0; + } +} + +static u32 to_colour_primaries(enum v4l2_colorspace colorspace) +{ + switch (colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + return 6; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + case V4L2_COLORSPACE_JPEG: + return 1; + case V4L2_COLORSPACE_BT2020: + return 9; + case V4L2_COLORSPACE_DCI_P3: + return 11; + case V4L2_COLORSPACE_SMPTE240M: + return 7; + case V4L2_COLORSPACE_470_SYSTEM_M: + return 4; + case V4L2_COLORSPACE_470_SYSTEM_BG: + return 5; + case V4L2_COLORSPACE_RAW: + default: + return 2; + } +} + +static u32 to_transfer_characteristics(enum v4l2_colorspace colorspace, + enum v4l2_xfer_func xfer_func) +{ + if (xfer_func == V4L2_XFER_FUNC_DEFAULT) + xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace); + + switch (xfer_func) { + case V4L2_XFER_FUNC_709: + if (colorspace == V4L2_COLORSPACE_SMPTE170M) + return 6; + else if (colorspace == V4L2_COLORSPACE_BT2020) + return 14; + else + return 1; + case V4L2_XFER_FUNC_SRGB: + return 13; + case V4L2_XFER_FUNC_SMPTE240M: + return 7; + case V4L2_XFER_FUNC_NONE: + return 8; + case V4L2_XFER_FUNC_SMPTE2084: + return 16; + case V4L2_XFER_FUNC_DCI_P3: + default: + return 2; + } +} + +static u32 to_matrix_coeffs(enum v4l2_colorspace colorspace, + enum v4l2_ycbcr_encoding ycbcr_enc) +{ + if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace); + + switch (ycbcr_enc) { + case V4L2_YCBCR_ENC_601: + case V4L2_YCBCR_ENC_XV601: + if (colorspace == V4L2_COLORSPACE_SMPTE170M) + return 6; + else + return 5; + case V4L2_YCBCR_ENC_709: + case V4L2_YCBCR_ENC_XV709: + return 1; + case V4L2_YCBCR_ENC_BT2020: + return 9; + case V4L2_YCBCR_ENC_BT2020_CONST_LUM: + return 10; + case V4L2_YCBCR_ENC_SMPTE240M: + return 7; + default: + return 2; + } +} + +static void wave6_set_enc_h264_param(struct enc_codec_param *output, + struct h264_enc_controls *ctrls) +{ + switch (ctrls->profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + output->profile = H264_PROFILE_BP; + output->internal_bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + output->profile = H264_PROFILE_MP; + output->internal_bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + output->profile = H264_PROFILE_EXTENDED; + output->internal_bit_depth = 8; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + output->profile = H264_PROFILE_HP; + output->internal_bit_depth = 8; + break; + default: + break; + } + switch (ctrls->level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + output->level = 10; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + output->level = 9; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + output->level = 11; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + output->level = 12; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + output->level = 13; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + output->level = 20; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + output->level = 21; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + output->level = 22; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + output->level = 30; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + output->level = 31; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + output->level = 32; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + output->level = 40; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + output->level = 41; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + output->level = 42; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + output->level = 50; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + output->level = 51; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + output->level = 52; + break; + default: + break; + } + output->qp = ctrls->i_frame_qp; + output->min_qp_i = ctrls->min_qp; + output->max_qp_i = ctrls->max_qp; + output->min_qp_p = ctrls->min_qp; + output->max_qp_p = ctrls->max_qp; + output->min_qp_b = ctrls->min_qp; + output->max_qp_b = ctrls->max_qp; + switch (ctrls->loop_filter_mode) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + output->en_dbk = 0; + output->en_lf_cross_slice_boundary = 0; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + output->en_dbk = 1; + output->en_lf_cross_slice_boundary = 1; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + output->en_dbk = 1; + output->en_lf_cross_slice_boundary = 0; + break; + default: + break; + } + output->intra_period = ctrls->i_period; + output->beta_offset_div2 = ctrls->loop_filter_beta; + output->tc_offset_div2 = ctrls->loop_filter_alpha; + if (output->profile >= H264_PROFILE_HP) + output->en_transform8x8 = ctrls->_8x8_transform; + output->en_constrained_intra_pred = ctrls->constrained_intra_prediction; + output->cb_qp_offset = ctrls->chroma_qp_index_offset; + output->cr_qp_offset = ctrls->chroma_qp_index_offset; + if (output->profile >= H264_PROFILE_MP) + output->en_cabac = ctrls->entropy_mode; + output->en_auto_level_adjusting = DEFAULT_EN_AUTO_LEVEL_ADJUSTING; +} + +static void wave6_set_enc_hevc_param(struct enc_codec_param *output, + struct hevc_enc_controls *ctrls) +{ + switch (ctrls->profile) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + output->profile = HEVC_PROFILE_MAIN; + output->internal_bit_depth = 8; + break; + default: + break; + } + switch (ctrls->level) { + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: + output->level = 10 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: + output->level = 20 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: + output->level = 21 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: + output->level = 30 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: + output->level = 31 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: + output->level = 40 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: + output->level = 41 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: + output->level = 50 * 3; + break; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: + output->level = 51 * 3; + break; + default: + break; + } + output->qp = ctrls->i_frame_qp; + output->min_qp_i = ctrls->min_qp; + output->max_qp_i = ctrls->max_qp; + output->min_qp_p = ctrls->min_qp; + output->max_qp_p = ctrls->max_qp; + output->min_qp_b = ctrls->min_qp; + output->max_qp_b = ctrls->max_qp; + switch (ctrls->loop_filter_mode) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + output->en_dbk = 0; + output->en_sao = 0; + output->en_lf_cross_slice_boundary = 0; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + output->en_dbk = 1; + output->en_sao = 1; + output->en_lf_cross_slice_boundary = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + output->en_dbk = 1; + output->en_sao = 1; + output->en_lf_cross_slice_boundary = 0; + break; + default: + break; + } + switch (ctrls->refresh_type) { + case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE: + output->decoding_refresh_type = DEC_REFRESH_TYPE_NON_IRAP; + break; + case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR: + output->decoding_refresh_type = DEC_REFRESH_TYPE_IDR; + break; + default: + break; + } + output->intra_period = ctrls->refresh_period; + if (output->idr_period) { + output->decoding_refresh_type = DEC_REFRESH_TYPE_IDR; + output->intra_period = output->idr_period; + output->idr_period = 0; + } + output->beta_offset_div2 = ctrls->lf_beta_offset_div2; + output->tc_offset_div2 = ctrls->lf_tc_offset_div2; + output->en_constrained_intra_pred = ctrls->const_intra_pred; + output->en_strong_intra_smoothing = ctrls->strong_smoothing; + output->en_temporal_mvp = ctrls->tmv_prediction; + output->num_ticks_poc_diff_one = DEFAULT_NUM_TICKS_POC_DIFF; + output->en_auto_level_adjusting = DEFAULT_EN_AUTO_LEVEL_ADJUSTING; + output->en_intra_trans_skip = DEFAULT_EN_INTRA_TRANS_SKIP; + output->en_me_center = DEFAULT_EN_ME_CENTER; + output->intra_4x4 = DEFAULT_INTRA_4X4; +} + +static void wave6_set_enc_open_param(struct enc_open_param *open_param, + struct vpu_instance *inst) +{ + struct enc_controls *ctrls = &inst->enc_ctrls; + struct enc_codec_param *output = &open_param->codec_param; + u32 ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64; + u32 num_ctu_row = ALIGN(inst->src_fmt.height, ctu_size) / ctu_size; + + open_param->source_endian = VPU_SOURCE_ENDIAN; + if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV420M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { + open_param->src_format = FORMAT_420; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422P || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV422M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV16M || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV61M) { + open_param->src_format = FORMAT_422; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV24 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV42) { + open_param->src_format = FORMAT_YUV444_24BIT; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUV24) { + open_param->src_format = FORMAT_YUV444_24BIT_PACKED; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_YUYV) { + open_param->src_format = FORMAT_YUYV; + open_param->packed_format = PACKED_YUYV; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGB24) { + open_param->src_format = FORMAT_RGB_24BIT_PACKED; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_P010) { + open_param->src_format = FORMAT_420_P10_16BIT_MSB; + open_param->source_endian = VDI_128BIT_LE_BYTE_SWAP; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_XRGB32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBA32 || + inst->src_fmt.pixelformat == V4L2_PIX_FMT_RGBX32) { + open_param->src_format = FORMAT_RGB_32BIT_PACKED; + } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_ARGB2101010) { + open_param->src_format = FORMAT_RGB_P10_32BIT_PACKED; + open_param->source_endian = VDI_128BIT_LE_WORD_BYTE_SWAP; + } + open_param->line_buf_int_en = true; + open_param->stream_endian = VPU_STREAM_ENDIAN; + open_param->inst_buffer.temp_base = inst->dev->temp_vbuf.daddr; + open_param->inst_buffer.temp_size = inst->dev->temp_vbuf.size; + open_param->inst_buffer.ar_base = inst->ar_vbuf.daddr; + open_param->pic_width = inst->codec_rect.width; + open_param->pic_height = inst->codec_rect.height; + + output->custom_map_endian = VPU_USER_DATA_ENDIAN; + output->gop_preset_idx = PRESET_IDX_IPP_SINGLE; + output->temp_layer_cnt = DEFAULT_TEMP_LAYER_CNT; + output->rc_initial_level = DEFAULT_RC_INITIAL_LEVEL; + output->pic_rc_max_dqp = DEFAULT_PIC_RC_MAX_DQP; + output->rc_initial_qp = DEFAULT_RC_INITIAL_QP; + output->en_adaptive_round = DEFAULT_EN_ADAPTIVE_ROUND; + output->q_round_inter = DEFAULT_Q_ROUND_INTER; + output->q_round_intra = DEFAULT_Q_ROUND_INTRA; + + output->frame_rate = inst->frame_rate; + output->idr_period = ctrls->gop_size; + output->rc_mode = ctrls->bitrate_mode; + output->rc_update_speed = (ctrls->bitrate_mode) ? DEFAULT_RC_UPDATE_SPEED_CBR : + DEFAULT_RC_UPDATE_SPEED_VBR; + output->en_rate_control = ctrls->frame_rc_enable; + output->en_cu_level_rate_control = ctrls->mb_rc_enable; + output->max_intra_pic_bit = inst->dst_fmt.plane_fmt[0].sizeimage * 8; + output->max_inter_pic_bit = inst->dst_fmt.plane_fmt[0].sizeimage * 8; + output->bitrate = ctrls->bitrate; + output->cpb_size = wave6_cpb_size_msec(ctrls->h264.cpb_size, ctrls->bitrate); + output->slice_mode = ctrls->slice_mode; + output->slice_arg = ctrls->slice_max_mb; + output->forced_idr_header = ctrls->prepend_spspps_to_idr; + output->en_vbv_overflow_drop_frame = (ctrls->frame_skip_mode) ? 1 : 0; + if (ctrls->intra_refresh_period) { + output->intra_refresh_mode = INTRA_REFRESH_ROW; + if (ctrls->intra_refresh_period < num_ctu_row) { + output->intra_refresh_arg = (num_ctu_row + ctrls->intra_refresh_period - 1) + / ctrls->intra_refresh_period; + } else { + output->intra_refresh_arg = 1; + } + } + output->sar.enable = ctrls->h264.vui_sar_enable; + output->sar.idc = ctrls->h264.vui_sar_idc; + if (output->sar.idc == V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED) + output->sar.idc = H264_VUI_SAR_IDC_EXTENDED; + output->sar.width = ctrls->h264.vui_ext_sar_width; + output->sar.height = ctrls->h264.vui_ext_sar_height; + output->color.video_signal_type_present = DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG; + output->color.color_range = to_video_full_range_flag(inst->quantization); + output->color.color_description_present = DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG; + output->color.color_primaries = to_colour_primaries(inst->colorspace); + output->color.transfer_characteristics = to_transfer_characteristics(inst->colorspace, + inst->xfer_func); + output->color.matrix_coefficients = to_matrix_coeffs(inst->colorspace, inst->ycbcr_enc); + output->conf_win.left = inst->crop.left - inst->codec_rect.left; + output->conf_win.top = inst->crop.top - inst->codec_rect.top; + output->conf_win.right = inst->codec_rect.width + - inst->crop.width - output->conf_win.left; + output->conf_win.bottom = inst->codec_rect.height + - inst->crop.height - output->conf_win.top; + + switch (inst->std) { + case W_AVC_ENC: + wave6_set_enc_h264_param(output, &ctrls->h264); + break; + case W_HEVC_ENC: + wave6_set_enc_hevc_param(output, &ctrls->hevc); + break; + default: + break; + } +} + +static int wave6_vpu_enc_create_instance(struct vpu_instance *inst) +{ + int ret; + struct enc_open_param open_param; + + memset(&open_param, 0, sizeof(struct enc_open_param)); + + wave6_vpu_activate(inst->dev); + ret = pm_runtime_resume_and_get(inst->dev->dev); + if (ret) { + dev_err(inst->dev->dev, "runtime_resume failed %d\n", ret); + return ret; + } + + wave6_vpu_wait_activated(inst->dev); + + inst->ar_vbuf.size = ALIGN(WAVE6_ARBUF_SIZE, 4096); + ret = wave6_alloc_dma(inst->dev->dev, &inst->ar_vbuf); + if (ret) { + dev_err(inst->dev->dev, "alloc ar of size %zu failed\n", + inst->ar_vbuf.size); + goto error_pm; + } + + wave6_set_enc_open_param(&open_param, inst); + + ret = wave6_vpu_enc_open(inst, &open_param); + if (ret) { + dev_err(inst->dev->dev, "failed create instance : %d\n", ret); + goto error_open; + } + + dprintk(inst->dev->dev, "[%d] encoder\n", inst->id); + wave6_vpu_create_dbgfs_file(inst); + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_OPEN); + + return 0; + +error_open: + wave6_free_dma(&inst->ar_vbuf); +error_pm: + pm_runtime_put_sync(inst->dev->dev); + return ret; +} + +static int wave6_vpu_enc_initialize_instance(struct vpu_instance *inst) +{ + int ret; + struct enc_initial_info initial_info; + struct v4l2_ctrl *ctrl; + + if (inst->enc_ctrls.mirror_direction) { + wave6_vpu_enc_give_command(inst, ENABLE_MIRRORING, NULL); + wave6_vpu_enc_give_command(inst, SET_MIRROR_DIRECTION, + &inst->enc_ctrls.mirror_direction); + } + if (inst->enc_ctrls.rot_angle) { + wave6_vpu_enc_give_command(inst, ENABLE_ROTATION, NULL); + wave6_vpu_enc_give_command(inst, SET_ROTATION_ANGLE, + &inst->enc_ctrls.rot_angle); + } + + ret = wave6_vpu_enc_issue_seq_init(inst); + if (ret) { + dev_err(inst->dev->dev, "seq init fail %d\n", ret); + return ret; + } + + if (wave6_vpu_wait_interrupt(inst, W6_VPU_TIMEOUT) < 0) { + dev_err(inst->dev->dev, "seq init timeout\n"); + return ret; + } + + ret = wave6_vpu_enc_complete_seq_init(inst, &initial_info); + if (ret) { + dev_err(inst->dev->dev, "seq init error\n"); + return ret; + } + + dev_dbg(inst->dev->dev, "min_fb_cnt : %d | min_src_cnt : %d\n", + initial_info.min_frame_buffer_count, + initial_info.min_src_frame_count); + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, initial_info.min_src_frame_count); + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_INIT_SEQ); + + return 0; +} + +static int wave6_vpu_enc_prepare_fb(struct vpu_instance *inst) +{ + int ret; + unsigned int i; + unsigned int fb_num; + unsigned int mv_num; + unsigned int fb_stride; + unsigned int fb_height; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + + fb_num = p_enc_info->initial_info.min_frame_buffer_count; + mv_num = p_enc_info->initial_info.req_mv_buffer_count; + + fb_stride = ALIGN(inst->codec_rect.width, 32); + fb_height = ALIGN(inst->codec_rect.height, 32); + + for (i = 0; i < fb_num; i++) { + struct frame_buffer *frame = &inst->frame_buf[i]; + struct vpu_buf *vframe = &inst->frame_vbuf[i]; + unsigned int l_size = fb_stride * fb_height; + unsigned int ch_size = ALIGN(fb_stride / 2, 32) * fb_height; + + vframe->size = l_size + ch_size; + ret = wave6_alloc_dma(inst->dev->dev, vframe); + if (ret) { + dev_err(inst->dev->dev, "alloc FBC buffer fail : %zu\n", + vframe->size); + goto error; + } + + frame->buf_y = vframe->daddr; + frame->buf_cb = vframe->daddr + l_size; + frame->buf_cr = (dma_addr_t)-1; + frame->stride = fb_stride; + frame->height = fb_height; + frame->map_type = COMPRESSED_FRAME_MAP; + } + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_Y_TBL, fb_num); + if (ret) + goto error; + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_FBC_C_TBL, fb_num); + if (ret) + goto error; + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_MV_COL, mv_num); + if (ret) + goto error; + + ret = wave6_allocate_aux_buffer(inst, AUX_BUF_SUB_SAMPLE, fb_num); + if (ret) + goto error; + + ret = wave6_vpu_enc_register_frame_buffer_ex(inst, fb_num, fb_stride, + fb_height, + COMPRESSED_FRAME_MAP); + if (ret) { + dev_err(inst->dev->dev, "register frame buffer fail %d\n", ret); + goto error; + } + + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_PIC_RUN); + + return 0; + +error: + wave6_vpu_enc_release_fb(inst); + return ret; +} + +static int wave6_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane inst_format = + (V4L2_TYPE_IS_OUTPUT(q->type)) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; + + dev_dbg(inst->dev->dev, "%s: num_buffers %d num_planes %d type %d\n", + __func__, *num_buffers, *num_planes, q->type); + + if (*num_planes) { + if (inst_format.num_planes != *num_planes) + return -EINVAL; + + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < inst_format.plane_fmt[i].sizeimage) + return -EINVAL; + } + } else { + *num_planes = inst_format.num_planes; + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "size[%d] : %d\n", i, sizes[i]); + } + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + struct v4l2_ctrl *ctrl; + unsigned int min_src_frame_count = 0; + + ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); + if (ctrl) + min_src_frame_count = v4l2_ctrl_g_ctrl(ctrl); + + *num_buffers = max(*num_buffers, min_src_frame_count); + } + } + + return 0; +} + +static void wave6_vpu_enc_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf); + + dev_dbg(inst->dev->dev, "type %4d index %4d size[0] %4ld size[1] : %4ld | size[2] : %4ld\n", + vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0), + vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2)); + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) { + vbuf->sequence = inst->queued_src_buf_num++; + + vpu_buf->ts_input = ktime_get_raw(); + vpu_buf->force_key_frame = inst->enc_ctrls.force_key_frame; + inst->enc_ctrls.force_key_frame = false; + vpu_buf->force_frame_qp = (!inst->enc_ctrls.frame_rc_enable) ? true : false; + if (vpu_buf->force_frame_qp) { + if (inst->std == W_AVC_ENC) { + vpu_buf->force_i_frame_qp = inst->enc_ctrls.h264.i_frame_qp; + vpu_buf->force_p_frame_qp = inst->enc_ctrls.h264.p_frame_qp; + vpu_buf->force_b_frame_qp = inst->enc_ctrls.h264.b_frame_qp; + } else if (inst->std == W_HEVC_ENC) { + vpu_buf->force_i_frame_qp = inst->enc_ctrls.hevc.i_frame_qp; + vpu_buf->force_p_frame_qp = inst->enc_ctrls.hevc.p_frame_qp; + vpu_buf->force_b_frame_qp = inst->enc_ctrls.hevc.b_frame_qp; + } + } + } else { + inst->queued_dst_buf_num++; + } + + vpu_buf->consumed = false; + vpu_buf->used = false; + v4l2_m2m_buf_queue(inst->v4l2_fh.m2m_ctx, vbuf); +} + +static void wave6_vpu_enc_buf_finish(struct vb2_buffer *vb) +{ + struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vpu_buffer *vpu_buf = wave6_to_vpu_buf(vbuf); + struct v4l2_ctrl *ctrl; + + if (V4L2_TYPE_IS_OUTPUT(vb->type)) + return; + + ctrl = v4l2_ctrl_find(inst->v4l2_fh.ctrl_handler, V4L2_CID_MPEG_VIDEO_AVERAGE_QP); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, vpu_buf->average_qp); +} + +static int wave6_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane *fmt; + struct vb2_queue *vq_peer; + int ret = 0; + + trace_start_streaming(inst, q->type); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + fmt = &inst->src_fmt; + vq_peer = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx); + } else { + fmt = &inst->dst_fmt; + vq_peer = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx); + } + + dprintk(inst->dev->dev, "[%d] %s %c%c%c%c %dx%d, %d buffers\n", + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture", + fmt->pixelformat, + fmt->pixelformat >> 8, + fmt->pixelformat >> 16, + fmt->pixelformat >> 24, + fmt->width, fmt->height, vb2_get_num_buffers(q)); + + if (!vb2_is_streaming(vq_peer)) + return 0; + + wave6_vpu_pause(inst->dev->dev, 0); + + if (inst->state == VPU_INST_STATE_NONE) { + ret = wave6_vpu_enc_create_instance(inst); + if (ret) + goto exit; + } + + if (inst->state == VPU_INST_STATE_OPEN) { + ret = wave6_vpu_enc_initialize_instance(inst); + if (ret) { + wave6_vpu_enc_destroy_instance(inst); + goto exit; + } + } + + if (inst->state == VPU_INST_STATE_INIT_SEQ) { + ret = wave6_vpu_enc_prepare_fb(inst); + if (ret) { + wave6_vpu_enc_destroy_instance(inst); + goto exit; + } + } + +exit: + wave6_vpu_pause(inst->dev->dev, 1); + if (ret) + wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void wave6_vpu_enc_stop_streaming(struct vb2_queue *q) +{ + struct vpu_instance *inst = vb2_get_drv_priv(q); + struct vb2_queue *vq_peer; + + trace_stop_streaming(inst, q->type); + + dprintk(inst->dev->dev, "[%d] %s, input %d, decode %d\n", + inst->id, V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture", + inst->queued_src_buf_num, inst->sequence); + + if (inst->state == VPU_INST_STATE_NONE) + goto exit; + + if (wave6_vpu_both_queues_are_streaming(inst)) + wave6_vpu_set_instance_state(inst, VPU_INST_STATE_STOP); + + wave6_vpu_pause(inst->dev->dev, 0); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + wave6_vpu_reset_performance(inst); + inst->queued_src_buf_num = 0; + inst->processed_buf_num = 0; + inst->error_buf_num = 0; + inst->sequence = 0; + v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, false); + } else { + inst->eos = false; + inst->queued_dst_buf_num = 0; + } + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vq_peer = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx); + else + vq_peer = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx); + + if (!vb2_is_streaming(vq_peer) && inst->state != VPU_INST_STATE_NONE) + wave6_vpu_enc_destroy_instance(inst); + + wave6_vpu_pause(inst->dev->dev, 1); + +exit: + wave6_vpu_return_buffers(inst, q->type, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops wave6_vpu_enc_vb2_ops = { + .queue_setup = wave6_vpu_enc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = wave6_vpu_enc_buf_queue, + .buf_finish = wave6_vpu_enc_buf_finish, + .start_streaming = wave6_vpu_enc_start_streaming, + .stop_streaming = wave6_vpu_enc_stop_streaming, +}; + +static void wave6_set_default_format(struct v4l2_pix_format_mplane *src_fmt, + struct v4l2_pix_format_mplane *dst_fmt) +{ + const struct vpu_format *vpu_fmt; + + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_RAW); + if (vpu_fmt) { + src_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt; + src_fmt->num_planes = vpu_fmt->num_planes; + wave6_update_pix_fmt(src_fmt, + W6_DEF_ENC_PIC_WIDTH, W6_DEF_ENC_PIC_HEIGHT); + } + + vpu_fmt = wave6_find_vpu_fmt_by_idx(0, VPU_FMT_TYPE_CODEC); + if (vpu_fmt) { + dst_fmt->pixelformat = vpu_fmt->v4l2_pix_fmt; + dst_fmt->num_planes = vpu_fmt->num_planes; + wave6_update_pix_fmt(dst_fmt, + W6_DEF_ENC_PIC_WIDTH, W6_DEF_ENC_PIC_HEIGHT); + } +} + +static int wave6_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct vpu_instance *inst = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->ops = &wave6_vpu_enc_vb2_ops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->buf_struct_size = sizeof(struct vpu_buffer); + src_vq->drv_priv = inst; + src_vq->lock = &inst->dev->dev_lock; + src_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->ops = &wave6_vpu_enc_vb2_ops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->buf_struct_size = sizeof(struct vpu_buffer); + dst_vq->drv_priv = inst; + dst_vq->lock = &inst->dev->dev_lock; + dst_vq->dev = inst->dev->v4l2_dev.dev; + ret = vb2_queue_init(dst_vq); + if (ret) + return ret; + + return 0; +} + +static const struct vpu_instance_ops wave6_vpu_enc_inst_ops = { + .start_process = wave6_vpu_enc_start_encode, + .finish_process = wave6_vpu_enc_finish_encode, +}; + +static int wave6_vpu_open_enc(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct vpu_device *dev = video_drvdata(filp); + struct vpu_instance *inst = NULL; + struct v4l2_ctrl_handler *v4l2_ctrl_hdl; + int ret; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl; + + inst->dev = dev; + inst->type = VPU_INST_TYPE_ENC; + inst->ops = &wave6_vpu_enc_inst_ops; + + v4l2_fh_init(&inst->v4l2_fh, vdev); + filp->private_data = &inst->v4l2_fh; + v4l2_fh_add(&inst->v4l2_fh); + + inst->v4l2_fh.m2m_ctx = + v4l2_m2m_ctx_init(dev->m2m_dev, inst, wave6_vpu_enc_queue_init); + if (IS_ERR(inst->v4l2_fh.m2m_ctx)) { + ret = PTR_ERR(inst->v4l2_fh.m2m_ctx); + goto free_inst; + } + + v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, 0, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + 0, 51, 1, 8); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + 0, 51, 1, 51); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + 0, 51, 1, 30); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + 0, 51, 1, 30); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + 0, 51, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + -6, 6, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, + BIT(V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA), + V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + 0, 2047, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + 0, 1, 1, 1); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 0, + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, 0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + 0, 51, 1, 8); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + 0, 51, 1, 51); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + 0, 51, 1, 30); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + 0, 51, 1, 30); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + 0, 51, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, + -6, 6, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + -12, 12, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, + 0, 2047, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, 0, 1, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, 0, + V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, + 0, 0xFFFF, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, + 0, 0xFFFF, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_ROTATE, + 0, 270, 90, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, + 0, 18750000, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 1, 1500000000, 1, 2097152); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, 1, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 0, 2047, 1, 30); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + 0, 0x3FFFF, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + 0, 1, 1, 0); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + 0, 1, 1, 1); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, 2160, 1, 0); + v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave6_vpu_enc_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, NULL, + V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1, 0); + + if (v4l2_ctrl_hdl->error) { + ret = -ENODEV; + goto err_m2m_release; + } + + inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl; + v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); + + wave6_set_default_format(&inst->src_fmt, &inst->dst_fmt); + wave6_update_crop_info(inst, 0, 0, inst->dst_fmt.width, inst->dst_fmt.height); + inst->colorspace = V4L2_COLORSPACE_DEFAULT; + inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->quantization = V4L2_QUANTIZATION_DEFAULT; + inst->xfer_func = V4L2_XFER_FUNC_DEFAULT; + inst->frame_rate = 30; + + return 0; + +err_m2m_release: + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); +free_inst: + kfree(inst); + return ret; +} + +static int wave6_vpu_enc_release(struct file *filp) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(filp->private_data); + + dprintk(inst->dev->dev, "[%d] release\n", inst->id); + v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); + + mutex_lock(&inst->dev->dev_lock); + if (inst->state != VPU_INST_STATE_NONE) { + wave6_vpu_pause(inst->dev->dev, 0); + wave6_vpu_enc_destroy_instance(inst); + wave6_vpu_pause(inst->dev->dev, 1); + } + mutex_unlock(&inst->dev->dev_lock); + + v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); + v4l2_fh_del(&inst->v4l2_fh); + v4l2_fh_exit(&inst->v4l2_fh); + kfree(inst); + + return 0; +} + +static const struct v4l2_file_operations wave6_vpu_enc_fops = { + .owner = THIS_MODULE, + .open = wave6_vpu_open_enc, + .release = wave6_vpu_enc_release, + .unlocked_ioctl = video_ioctl2, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, +}; + +int wave6_vpu_enc_register_device(struct vpu_device *dev) +{ + struct video_device *vdev_enc; + int ret; + + vdev_enc = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_enc), GFP_KERNEL); + if (!vdev_enc) + return -ENOMEM; + + dev->video_dev_enc = vdev_enc; + + strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name)); + vdev_enc->fops = &wave6_vpu_enc_fops; + vdev_enc->ioctl_ops = &wave6_vpu_enc_ioctl_ops; + vdev_enc->release = video_device_release_empty; + vdev_enc->v4l2_dev = &dev->v4l2_dev; + vdev_enc->vfl_dir = VFL_DIR_M2M; + vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vdev_enc->lock = &dev->dev_lock; + video_set_drvdata(vdev_enc, dev); + + ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + return 0; +} + +void wave6_vpu_enc_unregister_device(struct vpu_device *dev) +{ + video_unregister_device(dev->video_dev_enc); +} diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c new file mode 100644 index 000000000000..e614eda01a5a --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-v4l2.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - v4l2 driver helper interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include +#include "wave6-vpu.h" +#include "wave6-vpu-dbg.h" +#include "wave6-trace.h" + +void wave6_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + unsigned int width, + unsigned int height) +{ + const struct v4l2_format_info *fmt_info; + unsigned int stride_y; + int i; + + pix_mp->width = width; + pix_mp->height = height; + pix_mp->flags = 0; + pix_mp->field = V4L2_FIELD_NONE; + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); + + fmt_info = v4l2_format_info(pix_mp->pixelformat); + if (!fmt_info) { + pix_mp->plane_fmt[0].bytesperline = 0; + if (!pix_mp->plane_fmt[0].sizeimage) + pix_mp->plane_fmt[0].sizeimage = width * height; + + return; + } + + stride_y = width * fmt_info->bpp[0]; + if (pix_mp->plane_fmt[0].bytesperline <= W6_MAX_PIC_STRIDE) + stride_y = max(stride_y, pix_mp->plane_fmt[0].bytesperline); + stride_y = round_up(stride_y, 32); + pix_mp->plane_fmt[0].bytesperline = stride_y; + pix_mp->plane_fmt[0].sizeimage = stride_y * height; + + stride_y = DIV_ROUND_UP(stride_y, fmt_info->bpp[0]); + + for (i = 1; i < fmt_info->comp_planes; i++) { + unsigned int stride_c, sizeimage_c; + + stride_c = DIV_ROUND_UP(stride_y, fmt_info->hdiv) * + fmt_info->bpp[i]; + sizeimage_c = stride_c * DIV_ROUND_UP(height, fmt_info->vdiv); + + if (fmt_info->mem_planes == 1) { + pix_mp->plane_fmt[0].sizeimage += sizeimage_c; + } else { + pix_mp->plane_fmt[i].bytesperline = stride_c; + pix_mp->plane_fmt[i].sizeimage = sizeimage_c; + } + } +} + +dma_addr_t wave6_get_dma_addr(struct vb2_v4l2_buffer *buf, unsigned int plane_no) +{ + return vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, plane_no) + + buf->planes[plane_no].data_offset; +} + +struct vb2_v4l2_buffer *wave6_get_dst_buf_by_addr(struct vpu_instance *inst, + dma_addr_t addr) +{ + struct vb2_v4l2_buffer *vb2_v4l2_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vb2_v4l2_buffer *dst_buf = NULL; + + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + vb2_v4l2_buf = &v4l2_m2m_buf->vb; + if (addr == wave6_get_dma_addr(vb2_v4l2_buf, 0)) { + dst_buf = vb2_v4l2_buf; + break; + } + } + + return dst_buf; +} + +enum codec_std wave6_to_codec_std(enum vpu_instance_type type, unsigned int v4l2_pix_fmt) +{ + enum codec_std std = STD_UNKNOWN; + + if (v4l2_pix_fmt == V4L2_PIX_FMT_H264) + std = (type == VPU_INST_TYPE_DEC) ? W_AVC_DEC : W_AVC_ENC; + else if (v4l2_pix_fmt == V4L2_PIX_FMT_HEVC) + std = (type == VPU_INST_TYPE_DEC) ? W_HEVC_DEC : W_HEVC_ENC; + + return std; +} + +const char *wave6_vpu_instance_state_name(u32 state) +{ + switch (state) { + case VPU_INST_STATE_NONE: return "none"; + case VPU_INST_STATE_OPEN: return "open"; + case VPU_INST_STATE_INIT_SEQ: return "init_seq"; + case VPU_INST_STATE_PIC_RUN: return "pic_run"; + case VPU_INST_STATE_SEEK: return "seek"; + case VPU_INST_STATE_STOP: return "stop"; + } + return "unknown"; +} + +void wave6_vpu_set_instance_state(struct vpu_instance *inst, u32 state) +{ + trace_set_state(inst, state); + + dprintk(inst->dev->dev, "[%d] %s -> %s\n", + inst->id, + wave6_vpu_instance_state_name(inst->state), + wave6_vpu_instance_state_name(state)); + + inst->state = state; + if (state == VPU_INST_STATE_PIC_RUN && !inst->performance.ts_first) + inst->performance.ts_first = ktime_get_raw(); +} + +u64 wave6_vpu_cycle_to_ns(struct vpu_device *vpu_dev, u64 cycle) +{ + if (!vpu_dev || !vpu_dev->clk_vpu || !clk_get_rate(vpu_dev->clk_vpu)) + return 0; + + return (cycle * NSEC_PER_SEC) / clk_get_rate(vpu_dev->clk_vpu); +} + +int wave6_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout) +{ + int ret; + + ret = wait_for_completion_timeout(&inst->dev->irq_done, + msecs_to_jiffies(timeout)); + if (!ret) + return -ETIMEDOUT; + + reinit_completion(&inst->dev->irq_done); + + return 0; +} + +int wave6_vpu_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct vpu_instance *inst = wave6_to_vpu_inst(fh); + bool is_decoder = (inst->type == VPU_INST_TYPE_DEC) ? true : false; + + dev_dbg(inst->dev->dev, "%s: [%s] type: %d id: %d | flags: %d\n", + __func__, is_decoder ? "decoder" : "encoder", sub->type, + sub->id, sub->flags); + + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + if (is_decoder) + return v4l2_src_change_event_subscribe(fh, sub); + return -EINVAL; + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +void wave6_vpu_return_buffers(struct vpu_instance *inst, + unsigned int type, enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *buf; + int i; + + if (V4L2_TYPE_IS_OUTPUT(type)) { + while ((buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, state); + } else { + while ((buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx))) { + for (i = 0; i < inst->dst_fmt.num_planes; i++) + vb2_set_plane_payload(&buf->vb2_buf, i, 0); + v4l2_m2m_buf_done(buf, state); + } + } +} + +u32 wave6_vpu_get_consumed_fb_num(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *vb2_v4l2_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vpu_buffer *vpu_buf; + u32 num = 0; + + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + vb2_v4l2_buf = &v4l2_m2m_buf->vb; + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf); + if (vpu_buf->consumed) + num++; + } + + return num; +} + +u32 wave6_vpu_get_used_fb_num(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *vb2_v4l2_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vpu_buffer *vpu_buf; + u32 num = 0; + + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + vb2_v4l2_buf = &v4l2_m2m_buf->vb; + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf); + if (vpu_buf->used) + num++; + } + + return num; +} + +static bool wave6_vpu_check_fb_available(struct vpu_instance *inst) +{ + struct vb2_v4l2_buffer *vb2_v4l2_buf; + struct v4l2_m2m_buffer *v4l2_m2m_buf; + struct vpu_buffer *vpu_buf; + + v4l2_m2m_for_each_dst_buf(inst->v4l2_fh.m2m_ctx, v4l2_m2m_buf) { + vb2_v4l2_buf = &v4l2_m2m_buf->vb; + vpu_buf = wave6_to_vpu_buf(vb2_v4l2_buf); + + if (!vpu_buf->used) + return true; + } + + return false; +} + +static int wave6_vpu_job_ready(void *priv) +{ + struct vpu_instance *inst = priv; + + dev_dbg(inst->dev->dev, "[%d]%s: state %d\n", + inst->id, __func__, inst->state); + + if (inst->type == VPU_INST_TYPE_DEC && inst->state == VPU_INST_STATE_OPEN) + return 1; + if (inst->state < VPU_INST_STATE_PIC_RUN) + return 0; + if (inst->state == VPU_INST_STATE_STOP && inst->eos) + return 0; + if (!wave6_vpu_check_fb_available(inst)) + return 0; + + return 1; +} + +static void wave6_vpu_device_run_timeout(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct vpu_device *dev = container_of(dwork, struct vpu_device, task_timer); + struct vpu_instance *inst = v4l2_m2m_get_curr_priv(dev->m2m_dev); + struct vb2_v4l2_buffer *src_buf = NULL; + struct vb2_v4l2_buffer *dst_buf = NULL; + + if (!inst) + return; + + dev_err(inst->dev->dev, "[%d] sequence %d timeout\n", inst->id, inst->sequence); + src_buf = v4l2_m2m_src_buf_remove(inst->v4l2_fh.m2m_ctx); + if (src_buf) { + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + if (inst->type == VPU_INST_TYPE_DEC) + inst->processed_buf_num++; + inst->error_buf_num++; + } + + dst_buf = v4l2_m2m_dst_buf_remove(inst->v4l2_fh.m2m_ctx); + if (dst_buf) + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + + vb2_queue_error(v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx)); + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx)); + + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst->v4l2_fh.m2m_ctx); +} + +static void wave6_vpu_device_run(void *priv) +{ + struct vpu_instance *inst = priv; + int ret; + + dev_dbg(inst->dev->dev, "[%d]%s: state %d\n", + inst->id, __func__, inst->state); + + ret = inst->ops->start_process(inst); + if (!ret) + schedule_delayed_work(&inst->dev->task_timer, msecs_to_jiffies(W6_VPU_TIMEOUT)); + else + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst->v4l2_fh.m2m_ctx); +} + +void wave6_vpu_finish_job(struct vpu_instance *inst) +{ + cancel_delayed_work(&inst->dev->task_timer); + v4l2_m2m_job_finish(inst->dev->m2m_dev, inst->v4l2_fh.m2m_ctx); +} + +void wave6_vpu_handle_performance(struct vpu_instance *inst, struct vpu_buffer *vpu_buf) +{ + s64 latency, time_spent; + + if (!inst || !vpu_buf) + return; + + inst->performance.ts_last = vpu_buf->ts_output; + + latency = vpu_buf->ts_output - vpu_buf->ts_input; + time_spent = vpu_buf->ts_finish - vpu_buf->ts_start; + + if (!inst->performance.latency_first) + inst->performance.latency_first = latency; + inst->performance.latency_max = max_t(s64, latency, inst->performance.latency_max); + + if (!inst->performance.min_process_time) + inst->performance.min_process_time = time_spent; + else if (inst->performance.min_process_time > time_spent) + inst->performance.min_process_time = time_spent; + + if (inst->performance.max_process_time < time_spent) + inst->performance.max_process_time = time_spent; + + inst->performance.total_sw_time += time_spent; + inst->performance.total_hw_time += vpu_buf->hw_time; +} + +void wave6_vpu_reset_performance(struct vpu_instance *inst) +{ + if (!inst) + return; + + if (inst->processed_buf_num) { + s64 tmp; + s64 fps_act, fps_sw, fps_hw; + struct vpu_performance_info *perf = &inst->performance; + + tmp = MSEC_PER_SEC * inst->processed_buf_num; + fps_act = DIV_ROUND_CLOSEST(tmp, (perf->ts_last - perf->ts_first) / NSEC_PER_MSEC); + fps_sw = DIV_ROUND_CLOSEST(tmp, perf->total_sw_time / NSEC_PER_MSEC); + fps_hw = DIV_ROUND_CLOSEST(tmp, perf->total_hw_time / NSEC_PER_MSEC); + dprintk(inst->dev->dev, + "[%d] fps actual: %lld, sw: %lld, hw: %lld, latency(ms) %llu.%06llu\n", + inst->id, fps_act, fps_sw, fps_hw, + perf->latency_first / NSEC_PER_MSEC, + perf->latency_first % NSEC_PER_MSEC); + } + + memset(&inst->performance, 0, sizeof(inst->performance)); +} + +static const struct v4l2_m2m_ops wave6_vpu_m2m_ops = { + .device_run = wave6_vpu_device_run, + .job_ready = wave6_vpu_job_ready, +}; + +int wave6_vpu_init_m2m_dev(struct vpu_device *dev) +{ + dev->m2m_dev = v4l2_m2m_init(&wave6_vpu_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + dev_err(dev->dev, "v4l2_m2m_init fail: %ld\n", PTR_ERR(dev->m2m_dev)); + return PTR_ERR(dev->m2m_dev); + } + + INIT_DELAYED_WORK(&dev->task_timer, wave6_vpu_device_run_timeout); + + return 0; +} + +void wave6_vpu_release_m2m_dev(struct vpu_device *dev) +{ + v4l2_m2m_release(dev->m2m_dev); +} From patchwork Mon Feb 10 09:07:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967506 Received: from SE2P216CU007.outbound.protection.outlook.com (mail-koreacentralazon11021140.outbound.protection.outlook.com [40.107.42.140]) (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 45F811CAA64; Mon, 10 Feb 2025 09:07:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.42.140 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178480; cv=fail; b=rCAzXKWvCloaGpYiJcjFGrR+0v+vgeeQ3ZjVssdf24EaNA16JDjgY/5PifYIMsYN72N/juo20EURBvJ4oeYcbWhGdhlveo5B7ba/qo8nCfDv7j/uKyKiPrZhxNNgv88LJURTlokrdl/nLpQDca9zkEN2A2yxbS7e7KdPV7nTRKs= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178480; c=relaxed/simple; bh=iWueUynbennQry/qjvIrRHQ5MWvmRO/IsDgB+2SrrRw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=atVzabDMVg1LVcZLH3Wcvkvkqv867B4zHfFn9Tg9V7/VJeylQqqwKpWnCcICbCjd6StccdisAu+Ishz6rKBj3V0VuqCXMYVbGGmMDsTGchZ99GMR8FD0hziLFtwxKt2N86SKGmTdWSWh3gkyFNEiGy7Op60TE5okJxqdgF9zCa4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=jM1Lp1mL; arc=fail smtp.client-ip=40.107.42.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="jM1Lp1mL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=hUWwxHS19ovEKEPcG65xon9g0/ZdwZ7xV0VG2KdmeDz20tQY7MS3qouXoIpD4WBrgnnYGJNJ2iPj3r1UCGpH6gKM+NHQpDZmeyy2fVa34wJy7dPZo7Ku8gH+jOaLaB6EPXsBq1Vd+c8MrljmiY6AHOX8EQiQVMxCqTey24VVOt8svjfq2OW8J97uRh8BSAhixyp8ULQbeNVmYF+TKCo3rvbKlSRQEA7fNP1cRptrAcOs1433wMJ6LMj8tGj8bizWKKcFM/wPoRIJrZTIxjAxA2Y97MmMRxZMc/MhVP3mjmh/Pkrk3oC5HQ41BgbPngA1NR6MAM/MCu2ttJZGH0x3wQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=qbErkU+d0XbmtbWjiwdfe+H+Zl6IGKIIkbCb4wC1fpk=; b=Ncrus81/bNYrl4sEYlRnqjyJ3OMqkiDqBsPuksXlJDYeUWhkd01MUQoaIRhB0UiewHHBW76eZNX7m75MgiQyvokDlk7yjdR5IpUxXaYvIWrLsic0WaZgWe7rffpjbbaoIr9AL2DT1JP7C8aKsNZ9eRYVNewTkaCztiTSD0SQ9Nm1NdTR5mWK6+AB+RcjV8R4/BuTRsdyILe5cNK3zexY1A8nkejOhEYZrNPFMA/VkO6f2fNRnUnJ3OLAmyy9NseSh/0CxT7pNylNV3n+MfEz4CYTL37OezbAR7kZzVZ0YsMK4v07jneWi+JZFeNX6acWmEjitZMM0cseBilPDOhzyA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=qbErkU+d0XbmtbWjiwdfe+H+Zl6IGKIIkbCb4wC1fpk=; b=jM1Lp1mL4IFV7+UJ5+PyALYECEzBgSQ8i4Ko0+11iHg6kL+kE1QQPAWJImY/w0SBYxpp3Cl48FsrM82Gc6DpXuUROHBqkQr9Io/Ab3f3RKU7oa+7C6vK9JgeZzytxxcjj3CeBLDxQrNCHcc/QPpa0v+USmZvMQYRQgYregIf7cs= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:37 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:37 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 6/8] media: chips-media: wave6: Add Wave6 vpu interface Date: Mon, 10 Feb 2025 18:07:23 +0900 Message-Id: <20250210090725.4580-7-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: d4585c38-f0d9-459c-56f8-08dd49b25d23 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: TWvucVW3oO5PMT27I3fegFD5whkqv8j6wilUWMGtsQb12xp+hzPZhxkCChVQfC0da821i9lD+KWK7PiGhch5iZxrZsYAjlc86QRimFnfrzSQVP57hFgt33XwgloswqZDXCBR2ACU+mUci/MZ3hYR9cyOgQz4niHuf9x+H3nT8W0dwzwZPWkV7It+H2+DlYYZFNXFCxpdhGwUB7Wtsid+n2BjlxLLYEGoZ/XhuBesGoMs7CJzj7nVeDi7kSxfKLUJL7VIGkBKYkbnpYb5B6V5aH8qoPtjrnVqXgVqPDCAHGNExTmXWdiyc+gsTYNrX3GsPYkei780hAq2WcBLlroNZQnw9ta7+zEYO0nMVsHiw39LkIQ6s9ZV6tL17gVTvt5r21MleUjxiJobb9f4twvrTMHWj1N/+sT0cXzkp5frqRz2m7gs4adjErzEsHIXUtRtXS07Rgu9LaW0tNMDuaK2/hyBeLLk7axbAcPAF6SiRfMPrf4nAsI9hUNT81T+9i/yU68twCDrKz0wrXu5mGQ5GlZXagp27H+9w7JokMb0uEd2jBTEBjAVqtczFkBwGz4CGMUCGOcB0HfSOI5wl95yCvXvPS0NRtlTfuc+ABO9P2Q4Me0lgRF8EM/bz0nQPa4BF5ACdlzDEb26tH1C8jDJEboRGrDEok7laMd1erPtFjp/Wqyu4JVh6SBI2WrZUDldCYBT+yFr/ncKnNFpExuwJsx36TErj3kV6wZIO4X5SXSeF85JCbAEAMDv/lm26w2yfHUJP6YlIP8Kx0kZ788L6n5GvsmW/2qx3giAH+/cBy48IRHOQDnFXa+T5Ny9MNsp+q8xqTvoRCPwG8Gjpakxle3BKryK+fhpVTRN+QyGaeemTRId1AF07x82B1CaJGFwxcpndhuRPLPv73XIDCCSEzGxVDjf+BXC7E+RaUUBDoKa8a49wjsJVn76pIdaaTnpXf+2/E50WcHjbrzxdzazxCBW9LdaoH7DnLLS/3hkP/cG4LD6es6ThJkZb/14JOsNpmx8nbXbxsqWVhnpnKXvizKcU2qWTGnWTJveivKj52PHkcvGBSK2HkQUWZc/Bf3MjN3SKo1unePYr0l0endGvqMAdUNPSoNTIKbWfeyE7RnWZ+/Ik1o1+3oCEaemHeG7e9e8TXMVENhPkv/vlpOvKyxWhHxAUuThEa+HAINfqs4j/ZwdYjcuB7WRWCkXdkQHfsIvn6QIPuw9CK98smIus4HxDSRiiZckRyU95d9XfcTz/RrLOr9DpJNQ8RQHpJU4gEmJlbjCw260PRivktCV7OXBtbVtEdNxLTFNli2M65ADijx00Qumed4WXkkh2nPoCAas4d5tfPqfskpEscDbXjcvFOqeild6x8vN2eKrzTUWz4FjBU7ccLyiMUi+kjYpTtBR7t1i/mpinTLvSSmb2qTVEoudkfdCn9iunbSkbHpSWrKqWZtKEc5f7jGwfts6 X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: WmTo0O52LTQU6ctraeXEO7dm2uxXZ2Yxj6mUNj+uwoJQCGVWeP3+Dn2SNPsqlujFYBAu/e4PwTsmjTiq2aT9vs20TH5kNZ3iWLeIz0jInRzywEAcMVghi+cdk5vDr+5IQn0DeMyy2b8Upum7fABokjDh4SUZQRN9izWfDRGLCCya6NVgouflYc0dr8rdpLlFC4Z3WTebpHJ59MlLKYwFSoPXHZXuYRCxGGH8Msh+lDnIDtg+daH4t5O6DP0wfI0GQUFnpmjOWs/chvhOAqgXpSQDfH2Fzj/GpmU3nNWA4FF396XUOC7ot0tqhxSkaeIFjYXpurxq76HeYa/DdZxfJWIrUCMuKLMCxR37TmHqSuks2k61jPj4MkBPJwKWYSGqRMie7NauD+ouBDQAPq9LzKErlfGIRRQvaGLnZA+6+MyLUXmD+N5ELb1tVMztTUmCO5pV6v+rD2+RLAkXPSv9HTkTSI2TwiNiOIn+yr2Kuww0jhNcF2GoDUu/ef+fm/ujhay3BJW7MVhU++pFVXklrV113jmegYfVVZhDdJEZJNcvAu43pKz1Q0muWwNmzae+mNaPowc7Qv2wKBF49KU/9cuCngAeDpJW3xc8sorc8uXq7m7/41MeB5hgZEtB+xqDcyEdsuUMKl2g6+awS5RBoywCLE+w3ESm84DVjWDfdSiKU7NubSJxa6Yl0ZX7Ldb9so3JJeQgdAdPDOaX28YfAYoFen0f9Fbk1Ho5hbVBg/jTCfC6shKGSehgWVCg0sn0urgfF7yUNXB5at0eR5t2SYYGHxUJQAEc8iAiZ2qh1fO+/RcyDRwUS7CxghUD+Gc8q0HFyyF1dFJGZU6/ALBrajsRi+QEbcZMMj/JOBprisC0OqxU/XlshIjq+fYUJXFil66vj/Niftv4n86P4nMDpGZnLSwLL6BnBwEhKMpfE+GDl7DVewFm47XzVIAJ3iRrcJM5wQ+MwBOgGMaKyOMUf0GWsSBbqlv3Va9zdfoV683/dh2xltYqP4/yOCyfwDmWEkjMHv/tJc+zMrkOVf2eiVsEpJUN1J2KvTdZYFMKtVJRSa92Yj6PTi6fCObEQX4wAunABZC+Od9TTBJS29zfFn5HntLrE3WCqoXAnkFGfkaOUDzby1dR0nIk4B7caxoHGw7xdzPqLKZr6rBRv3GZZ3LyjKYY4q1huWApOAnIon9Ubq9mdm8K+Zq0Gbj+FNk1lfZLFuop4v+xrik+D1kCbsd6yZCGo+SoTJ+57gYQzPi1822kfMWj8KkzkUOwObOMSWHdkLdppeGNRFlpyHWYN+gT/MHuzD7kLV2xV7C5CrR0vNdpYOB8jgzuGtP/uiwNtoktdgLJ1ro+j1D7jCO/5JY1xxs0kSZjSi0Fpjc4xs8fOPm8kfUg7NM75TBr+6NKBvkd3yuVQpZQ5IHNkNulviqKhSzFqh8kJn+ccChCcoYaL8wrY7UE0FHEi7x2F+U+omNm+50YYQxJ/22N2I8oe9PcDXwLtjMKJEZln1ATx1pl9LKoRu9oDdQHaf4/awgdIXZytzxlUSw9dLoqVwrepFZtcyeTLoYI4SOPRTqW+SAETtpMdgAujOMmEAqcce26Fzxm+nhOXuDdPyId9looWA== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: d4585c38-f0d9-459c-56f8-08dd49b25d23 X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:37.4529 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: N8d1Fuwp1qFpLNz4qnVVcF19vuO54h/ASDYYHrNn0wNa484RhRcnZqpum+UgYZnCAOuUaBh/T5dh5WbKdTum8k3wCkmKc2TbfAnXeybGBko= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 Add control layer to configure hardware registers and manage communication with the Wave6 vpu. Signed-off-by: Nas Chung --- .../platform/chips-media/wave6/wave6-hw.c | 3113 +++++++++++++++++ .../platform/chips-media/wave6/wave6-hw.h | 69 + .../chips-media/wave6/wave6-regdefine.h | 675 ++++ .../platform/chips-media/wave6/wave6-vdi.c | 52 + .../platform/chips-media/wave6/wave6-vdi.h | 59 + .../platform/chips-media/wave6/wave6-vpuapi.c | 1001 ++++++ .../platform/chips-media/wave6/wave6-vpuapi.h | 993 ++++++ .../chips-media/wave6/wave6-vpuconfig.h | 80 + .../chips-media/wave6/wave6-vpuerror.h | 262 ++ 9 files changed, 6304 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-hw.h create mode 100644 drivers/media/platform/chips-media/wave6/wave6-regdefine.h create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vdi.h create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuapi.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuapi.h create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpuerror.h diff --git a/drivers/media/platform/chips-media/wave6/wave6-hw.c b/drivers/media/platform/chips-media/wave6/wave6-hw.c new file mode 100644 index 000000000000..dba08d3451c9 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-hw.c @@ -0,0 +1,3113 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - wave6 backend interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include "wave6-vpu.h" +#include "wave6-hw.h" +#include "wave6-regdefine.h" +#include "wave6-trace.h" + +static void wave6_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason) +{ + char *caller = __builtin_return_address(0); + struct device *dev = vpu_dev->dev; + + switch (reg_fail_reason) { + case WAVE6_SYSERR_QUEUEING_FAIL: + dev_dbg(dev, "%s: queueing failure 0x%x\n", caller, reg_fail_reason); + break; + case WAVE6_SYSERR_RESULT_NOT_READY: + dev_err(dev, "%s: result not ready 0x%x\n", caller, reg_fail_reason); + break; + case WAVE6_SYSERR_ACCESS_VIOLATION_HW: + dev_err(dev, "%s: access violation 0x%x\n", caller, reg_fail_reason); + break; + case WAVE6_SYSERR_WATCHDOG_TIMEOUT: + dev_err(dev, "%s: watchdog timeout 0x%x\n", caller, reg_fail_reason); + break; + case WAVE6_SYSERR_BUS_ERROR: + dev_err(dev, "%s: bus error 0x%x\n", caller, reg_fail_reason); + break; + case WAVE6_SYSERR_DOUBLE_FAULT: + dev_err(dev, "%s: double fault 0x%x\n", caller, reg_fail_reason); + break; + case WAVE6_SYSERR_VPU_STILL_RUNNING: + dev_err(dev, "%s: still running 0x%x\n", caller, reg_fail_reason); + break; + default: + dev_err(dev, "%s: failure: 0x%x\n", caller, reg_fail_reason); + break; + } +} + +static void wave6_dec_set_display_buffer(struct vpu_instance *inst, struct frame_buffer fb) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int index; + + for (index = 0; index < WAVE6_MAX_FBS; index++) { + if (!p_dec_info->disp_buf[index].buf_y) { + p_dec_info->disp_buf[index] = fb; + p_dec_info->disp_buf[index].index = index; + break; + } + } +} + +static struct frame_buffer wave6_dec_get_display_buffer(struct vpu_instance *inst, + dma_addr_t addr, + bool remove) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int i; + struct frame_buffer fb; + + memset(&fb, 0, sizeof(struct frame_buffer)); + + for (i = 0; i < WAVE6_MAX_FBS; i++) { + if (p_dec_info->disp_buf[i].buf_y == addr) { + fb = p_dec_info->disp_buf[i]; + if (remove) + memset(&p_dec_info->disp_buf[i], 0, sizeof(struct frame_buffer)); + break; + } + } + + return fb; +} + +static int wave6_wait_vpu_busy(struct vpu_device *vpu_dev, unsigned int addr) +{ + u32 data; + + return read_poll_timeout(wave6_vdi_readl, data, !data, + 0, W6_VPU_POLL_TIMEOUT, false, vpu_dev, addr); +} + +void wave6_vpu_enable_interrupt(struct vpu_device *vpu_dev) +{ + u32 data; + + data = BIT(W6_INT_BIT_ENC_SET_PARAM); + data |= BIT(W6_INT_BIT_ENC_PIC); + data |= BIT(W6_INT_BIT_INIT_SEQ); + data |= BIT(W6_INT_BIT_DEC_PIC); + data |= BIT(W6_INT_BIT_BSBUF_ERROR); + data |= BIT(W6_INT_BIT_REQ_WORK_BUF); + + vpu_write_reg(vpu_dev, W6_VPU_VINT_ENABLE, data); +} + +void wave6_vpu_check_state(struct vpu_device *vpu_dev) +{ + if (vpu_dev->ctrl) { + int state = wave6_vpu_ctrl_get_state(vpu_dev->ctrl); + + if (state == WAVE6_VPU_STATE_PREPARE) + wave6_vpu_ctrl_wait_done(vpu_dev->ctrl); + } else { + u32 val; + int ret; + + ret = read_poll_timeout(vpu_read_reg, val, val != 0, 0, + W6_VPU_POLL_TIMEOUT, false, + vpu_dev, W6_VPU_VCPU_CUR_PC); + if (!ret) + vpu_dev->entity.on_boot(vpu_dev->dev); + } +} + +bool wave6_vpu_is_init(struct vpu_device *vpu_dev) +{ + return vpu_read_reg(vpu_dev, W6_VPU_VCPU_CUR_PC) != 0; +} + +static int32_t wave6_vpu_get_product_id(struct vpu_device *vpu_dev) +{ + u32 product_id = PRODUCT_ID_NONE; + u32 val; + + val = vpu_read_reg(vpu_dev, W6_VPU_RET_PRODUCT_VERSION); + + switch (val) { + case WAVE617_CODE: + product_id = PRODUCT_ID_617; break; + case WAVE627_CODE: + product_id = PRODUCT_ID_627; break; + case WAVE633_CODE: + case WAVE637_CODE: + case WAVE663_CODE: + case WAVE677_CODE: + product_id = PRODUCT_ID_637; break; + default: + dev_err(vpu_dev->dev, "Invalid product (%x)\n", val); + break; + } + + return product_id; +} + +static void wave6_send_command(struct vpu_device *vpu_dev, u32 id, u32 std, u32 cmd) +{ + if (cmd == W6_CMD_CREATE_INSTANCE) { + vpu_write_reg(vpu_dev, W6_CMD_INSTANCE_INFO, (std << 16)); + + vpu_write_reg(vpu_dev, W6_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W6_COMMAND, cmd); + + vpu_write_reg(vpu_dev, W6_VPU_HOST_INT_REQ, 1); + } else { + vpu_write_reg(vpu_dev, W6_CMD_INSTANCE_INFO, (std << 16) | (id & 0xffff)); + + vpu_write_reg(vpu_dev, W6_VPU_BUSY_STATUS, 1); + vpu_write_reg(vpu_dev, W6_COMMAND, cmd); + + vpu_write_reg(vpu_dev, W6_VPU_HOST_INT_REQ, 1); + } + + trace_send_command(vpu_dev, id, std, cmd); +} + +static int wave6_send_query(struct vpu_device *vpu_dev, u32 id, u32 std, + enum wave6_query_option query_opt) +{ + int ret; + u32 reg_val; + + vpu_write_reg(vpu_dev, W6_QUERY_OPTION, query_opt); + wave6_send_command(vpu_dev, id, std, W6_CMD_QUERY); + + ret = wave6_wait_vpu_busy(vpu_dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(vpu_dev->dev, "query timed out opt=0x%x\n", query_opt); + return ret; + } + + if (!vpu_read_reg(vpu_dev, W6_RET_SUCCESS)) { + reg_val = vpu_read_reg(vpu_dev, W6_RET_FAIL_REASON); + wave6_print_reg_err(vpu_dev, reg_val); + return -EIO; + } + + return 0; +} + +int wave6_vpu_get_version(struct vpu_device *vpu_dev, uint32_t *version_info, + uint32_t *revision) +{ + struct vpu_attr *attr = &vpu_dev->attr; + u32 reg_val; + u8 *str; + int ret; + u32 hw_config_def1, hw_config_feature; + + ret = wave6_send_query(vpu_dev, 0, 0, W6_QUERY_OPT_GET_VPU_INFO); + if (ret) + return ret; + + reg_val = vpu_read_reg(vpu_dev, W6_RET_PRODUCT_NAME); + str = (u8 *)®_val; + attr->product_name[0] = str[3]; + attr->product_name[1] = str[2]; + attr->product_name[2] = str[1]; + attr->product_name[3] = str[0]; + attr->product_name[4] = 0; + + attr->product_id = wave6_vpu_get_product_id(vpu_dev); + attr->product_version = vpu_read_reg(vpu_dev, W6_RET_PRODUCT_VERSION); + attr->fw_version = vpu_read_reg(vpu_dev, W6_RET_FW_API_VERSION); + attr->fw_revision = vpu_read_reg(vpu_dev, W6_RET_FW_VERSION); + hw_config_def1 = vpu_read_reg(vpu_dev, W6_RET_STD_DEF1); + hw_config_feature = vpu_read_reg(vpu_dev, W6_RET_CONF_FEATURE); + + attr->support_hevc10bit_enc = (hw_config_feature >> 3) & 1; + attr->support_avc10bit_enc = (hw_config_feature >> 11) & 1; + + attr->support_decoders = 0; + attr->support_encoders = 0; + if (attr->product_id == PRODUCT_ID_617) { + attr->support_decoders = (((hw_config_def1 >> 2) & 0x01) << STD_HEVC); + attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) << STD_AVC); + } else if (attr->product_id == PRODUCT_ID_627) { + attr->support_encoders = (((hw_config_def1 >> 0) & 0x01) << STD_HEVC); + attr->support_encoders |= (((hw_config_def1 >> 1) & 0x01) << STD_AVC); + } else if (attr->product_id == PRODUCT_ID_637) { + attr->support_decoders = (((hw_config_def1 >> 2) & 0x01) << STD_HEVC); + attr->support_decoders |= (((hw_config_def1 >> 3) & 0x01) << STD_AVC); + attr->support_encoders = (((hw_config_def1 >> 0) & 0x01) << STD_HEVC); + attr->support_encoders |= (((hw_config_def1 >> 1) & 0x01) << STD_AVC); + } + + attr->support_dual_core = (hw_config_def1 >> 26) & 0x01; + attr->support_bitstream_mode = BS_MODE_PIC_END; + + if (version_info) + *version_info = attr->fw_version; + if (revision) + *revision = attr->fw_revision; + + return 0; +} + +int wave6_vpu_build_up_dec_param(struct vpu_instance *inst, + struct dec_open_param *param) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 reg_val; + int ret; + + p_dec_info->cycle_per_tick = 256; + p_dec_info->sec_axi_info.use_dec_ip = true; + p_dec_info->sec_axi_info.use_dec_lf_row = true; + switch (inst->std) { + case W_HEVC_DEC: + p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC; + break; + case W_AVC_DEC: + p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC; + break; + default: + return -EINVAL; + } + + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TEMP_BASE, param->inst_buffer.temp_base); + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TEMP_SIZE, param->inst_buffer.temp_size); + + reg_val = wave6_vdi_convert_endian(param->stream_endian); + reg_val = (~reg_val & VDI_128BIT_ENDIAN_MASK); + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_BS_PARAM, reg_val); + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_ADDR_EXT, param->ext_addr_vcpu); + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_DISP_MODE, param->disp_mode); + + reg_val = (COMMAND_QUEUE_DEPTH << 8) | (1 << 4) | 1; + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_CORE_INFO, reg_val); + + reg_val = (param->is_secure_inst << 8) | (param->inst_priority); + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_PRIORITY, reg_val); + vpu_write_reg(inst->dev, W6_CMD_DEC_CREATE_INST_TIMEOUT_CYCLE_COUNT, + W6_VPU_TIMEOUT_CYCLE_COUNT); + + wave6_send_command(inst->dev, 0, inst->std, W6_CMD_CREATE_INSTANCE); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + + wave6_print_reg_err(inst->dev, reason_code); + return -EIO; + } + + inst->id = vpu_read_reg(inst->dev, W6_RET_INSTANCE_ID); + + return 0; +} + +int wave6_vpu_dec_init_seq(struct vpu_instance *inst) +{ + struct dec_info *p_dec_info; + u32 cmd_option = W6_INIT_SEQ_OPT_NORMAL, bs_option; + int ret; + + if (!inst->codec_info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + if (p_dec_info->thumbnail_mode) + cmd_option = W6_INIT_SEQ_OPT_W_THUMBNAIL; + + bs_option = 0; + switch (p_dec_info->open_param.bs_mode) { + case BS_MODE_INTERRUPT: + bs_option = 0; + break; + case BS_MODE_PIC_END: + bs_option = BSOPTION_ENABLE_EXPLICIT_END; + break; + default: + return -EINVAL; + } + + vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_RD_PTR, p_dec_info->stream_rd_ptr); + vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_WR_PTR, p_dec_info->stream_wr_ptr); + + if (p_dec_info->stream_end) + bs_option = 3; + vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_BS_OPTION, bs_option); + vpu_write_reg(inst->dev, W6_CMD_DEC_INIT_SEQ_OPTION, cmd_option); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_INIT_SEQ); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + + wave6_print_reg_err(inst->dev, reason_code); + return -EIO; + } + + return 0; +} + +static void wave6_get_dec_seq_result(struct vpu_instance *inst, struct dec_initial_info *info) +{ + u32 reg_val; + u32 profile_compatibility; + u32 left, right, top, bottom; + + info->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_SIZE); + info->pic_width = ((reg_val >> 16) & 0xffff); + info->pic_height = (reg_val & 0xffff); + info->min_frame_buffer_count = vpu_read_reg(inst->dev, W6_RET_DEC_NUM_REQUIRED_FBC_FB); + info->frame_buf_delay = vpu_read_reg(inst->dev, W6_RET_DEC_NUM_REORDER_DELAY); + info->req_mv_buffer_count = vpu_read_reg(inst->dev, W6_RET_DEC_NUM_REQUIRED_COL_BUF); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_CROP_LEFT_RIGHT); + left = (reg_val >> 16) & 0xffff; + right = reg_val & 0xffff; + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_CROP_TOP_BOTTOM); + top = (reg_val >> 16) & 0xffff; + bottom = reg_val & 0xffff; + + info->pic_crop_rect.left = left; + info->pic_crop_rect.right = info->pic_width - right; + info->pic_crop_rect.top = top; + info->pic_crop_rect.bottom = info->pic_height - bottom; + + info->f_rate_numerator = vpu_read_reg(inst->dev, W6_RET_DEC_FRAME_RATE_NR); + info->f_rate_denominator = vpu_read_reg(inst->dev, W6_RET_DEC_FRAME_RATE_DR); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_COLOR_SAMPLE_INFO); + info->luma_bitdepth = (reg_val >> 0) & 0x0f; + info->chroma_bitdepth = (reg_val >> 4) & 0x0f; + info->chroma_format_idc = (reg_val >> 8) & 0x0f; + info->aspect_rate_info = (reg_val >> 16) & 0xff; + info->is_ext_sar = (info->aspect_rate_info == H264_VUI_SAR_IDC_EXTENDED ? true : false); + if (info->is_ext_sar) + info->aspect_rate_info = vpu_read_reg(inst->dev, W6_RET_DEC_ASPECT_RATIO); + info->bitrate = vpu_read_reg(inst->dev, W6_RET_DEC_BIT_RATE); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_SEQ_PARAM); + info->level = reg_val & 0xff; + profile_compatibility = (reg_val >> 12) & 0xff; + info->profile = (reg_val >> 24) & 0x1f; + info->tier = (reg_val >> 29) & 0x01; + + if (inst->std == W_HEVC_DEC) { + if (!info->profile) { + if ((profile_compatibility & 0x06) == 0x06) + info->profile = HEVC_PROFILE_MAIN; + else if ((profile_compatibility & 0x04) == 0x04) + info->profile = HEVC_PROFILE_MAIN10; + else if ((profile_compatibility & 0x08) == 0x08) + info->profile = HEVC_PROFILE_STILLPICTURE; + else + info->profile = HEVC_PROFILE_MAIN; + } + } else if (inst->std == W_AVC_DEC) { + info->profile = (reg_val >> 24) & 0x7f; + } + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_COLOR_CONFIG); + if (reg_val) { + info->color.video_signal_type_present = true; + info->color.color_description_present = reg_val & 0x1; + info->color.color_primaries = (reg_val >> 1) & 0xFF; + info->color.transfer_characteristics = (reg_val >> 9) & 0xFF; + info->color.matrix_coefficients = (reg_val >> 17) & 0xFF; + info->color.color_range = (reg_val >> 25) & 0x1; + info->color.chroma_sample_position = (reg_val >> 26) & 0x3; + } else { + info->color.video_signal_type_present = false; + } +} + +int wave6_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info) +{ + int ret; + + ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT); + if (ret) + return ret; + + if (vpu_read_reg(inst->dev, W6_RET_DEC_DECODING_SUCCESS) != 1) { + info->err_reason = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_INFO); + ret = -EIO; + } else { + info->warn_info = vpu_read_reg(inst->dev, W6_RET_DEC_WARN_INFO); + } + + wave6_get_dec_seq_result(inst, info); + + return ret; +} + +int wave6_vpu_dec_register_frame_buffer(struct vpu_instance *inst, + struct frame_buffer *fb_arr, + enum tiled_map_type map_type, u32 count) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + size_t fbc_remain, mv_remain, fbc_idx = 0, mv_idx = 0; + size_t i, k, group_num, mv_count; + dma_addr_t fbc_cr_tbl_addr; + u32 reg_val; + u32 endian; + int ret; + + mv_count = p_dec_info->initial_info.req_mv_buffer_count; + + for (i = 0; i < count; i++) { + if (!p_dec_info->vb_fbc_y_tbl[i].daddr) + return -EINVAL; + if (!p_dec_info->vb_fbc_c_tbl[i].daddr) + return -EINVAL; + } + for (i = 0; i < mv_count; i++) { + if (!p_dec_info->vb_mv[i].daddr) + return -EINVAL; + } + + endian = wave6_vdi_convert_endian(p_dec_info->open_param.frame_endian); + + reg_val = (p_dec_info->initial_info.pic_width << 16) | + (p_dec_info->initial_info.pic_height); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_PIC_SIZE, reg_val); + reg_val = (p_dec_info->initial_info.chroma_format_idc << 25) | + (p_dec_info->initial_info.luma_bitdepth << 21) | + (p_dec_info->initial_info.chroma_bitdepth << 17); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_COMMON_PIC_INFO, reg_val); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_DEFAULT_CDF, 0); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_SEGMAP, 0); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_MV_COL_PRE_ENT, 0); + + fbc_remain = count; + mv_remain = mv_count; + group_num = (count > mv_count) ? ((ALIGN(count, 16) / 16) - 1) : + ((ALIGN(mv_count, 16) / 16) - 1); + for (i = 0; i <= group_num; i++) { + bool first_group = (i == 0) ? true : false; + bool last_group = (i == group_num) ? true : false; + u32 set_fbc_num = (fbc_remain >= 16) ? 16 : fbc_remain; + u32 set_mv_num = (mv_remain >= 16) ? 16 : mv_remain; + u32 fbc_start_no = i * 16; + u32 fbc_end_no = fbc_start_no + set_fbc_num - 1; + u32 mv_start_no = i * 16; + u32 mv_end_no = mv_start_no + set_mv_num - 1; + + reg_val = (p_dec_info->open_param.enable_non_ref_fbc_write << 26) | + (endian << 16) | + (last_group << 4) | + (first_group << 3); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_OPTION, reg_val); + + reg_val = (fbc_start_no << 24) | (fbc_end_no << 16) | + (mv_start_no << 5) | mv_end_no; + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_NUM, reg_val); + + for (k = 0; k < set_fbc_num; k++) { + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_Y0 + (k * 24), + fb_arr[fbc_idx].buf_y); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_C0 + (k * 24), + fb_arr[fbc_idx].buf_cb); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_CR0 + (k * 8), + fb_arr[fbc_idx].buf_cr); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_Y_OFFSET0 + (k * 24), + p_dec_info->vb_fbc_y_tbl[fbc_idx].daddr); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_C_OFFSET0 + (k * 24), + p_dec_info->vb_fbc_c_tbl[fbc_idx].daddr); + fbc_cr_tbl_addr = p_dec_info->vb_fbc_c_tbl[fbc_idx].daddr + + (p_dec_info->vb_fbc_c_tbl[fbc_idx].size >> 1); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_FBC_CR_OFFSET0 + (k * 8), + fbc_cr_tbl_addr); + fbc_idx++; + } + fbc_remain -= k; + + for (k = 0; k < set_mv_num; k++) { + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_FB_MV_COL0 + (k * 24), + p_dec_info->vb_mv[mv_idx].daddr); + mv_idx++; + } + mv_remain -= k; + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_SET_FB); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) + return -EIO; + + return 0; +} + +int wave6_vpu_dec_register_display_buffer(struct vpu_instance *inst, struct frame_buffer fb) +{ + int ret; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 reg_val, cbcr_interleave, nv21; + u32 endian; + u32 addr_y, addr_cb, addr_cr; + u32 color_format; + u32 justified = WTL_RIGHT_JUSTIFIED; + u32 format_no = WTL_PIXEL_8BIT; + + cbcr_interleave = inst->cbcr_interleave; + nv21 = inst->nv21; + + endian = wave6_vdi_convert_endian(p_dec_info->open_param.frame_endian); + + switch (p_dec_info->wtl_format) { + case FORMAT_420: + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_420_P10_16BIT_LSB: + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_420_P10_32BIT_LSB: + color_format = 1; + break; + case FORMAT_422: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_LSB: + color_format = 2; + break; + case FORMAT_444: + case FORMAT_444_P10_16BIT_MSB: + case FORMAT_444_P10_16BIT_LSB: + case FORMAT_444_P10_32BIT_MSB: + case FORMAT_444_P10_32BIT_LSB: + color_format = 3; + break; + case FORMAT_400: + case FORMAT_400_P10_16BIT_MSB: + case FORMAT_400_P10_16BIT_LSB: + case FORMAT_400_P10_32BIT_MSB: + case FORMAT_400_P10_32BIT_LSB: + color_format = 0; + break; + default: + return -EINVAL; + } + + reg_val = (color_format << 3) | + (inst->scaler_info.scale_mode << 1) | + (inst->scaler_info.enable); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_SCL_PARAM, reg_val); + reg_val = (inst->scaler_info.width << 16) | + (inst->scaler_info.height); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_SCL_PIC_SIZE, reg_val); + reg_val = (p_dec_info->initial_info.pic_width << 16) | + (p_dec_info->initial_info.pic_height); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_PIC_SIZE, reg_val); + + switch (p_dec_info->wtl_format) { + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_444_P10_16BIT_MSB: + case FORMAT_400_P10_16BIT_MSB: + justified = WTL_RIGHT_JUSTIFIED; + format_no = WTL_PIXEL_16BIT; + break; + case FORMAT_420_P10_16BIT_LSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_444_P10_16BIT_LSB: + case FORMAT_400_P10_16BIT_LSB: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_16BIT; + break; + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_444_P10_32BIT_MSB: + case FORMAT_400_P10_32BIT_MSB: + justified = WTL_RIGHT_JUSTIFIED; + format_no = WTL_PIXEL_32BIT; + break; + case FORMAT_420_P10_32BIT_LSB: + case FORMAT_422_P10_32BIT_LSB: + case FORMAT_444_P10_32BIT_LSB: + case FORMAT_400_P10_32BIT_LSB: + justified = WTL_LEFT_JUSTIFIED; + format_no = WTL_PIXEL_32BIT; + break; + default: + break; + } + + reg_val = (REGISTER_DISPLAY_BUFFER << 28) | (color_format << 24) | + (DEFAULT_PIXEL_ORDER << 23) | (justified << 22) | (format_no << 20) | + (nv21 << 17) | (cbcr_interleave << 16) | (fb.stride); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_COMMON_PIC_INFO, reg_val); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_OPTION, (endian << 16)); + reg_val = (fb.luma_bitdepth << 22) | + (fb.chroma_bitdepth << 18) | + (fb.chroma_format_idc << 16); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_PIC_INFO, reg_val); + + if (p_dec_info->open_param.cbcr_order == CBCR_ORDER_REVERSED) { + addr_y = fb.buf_y; + addr_cb = fb.buf_cr; + addr_cr = fb.buf_cb; + } else { + addr_y = fb.buf_y; + addr_cb = fb.buf_cb; + addr_cr = fb.buf_cr; + } + + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_Y_BASE, addr_y); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_CB_BASE, addr_cb); + vpu_write_reg(inst->dev, W6_CMD_DEC_SET_DISP_CR_BASE, addr_cr); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DEC_SET_DISP); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) + return -EIO; + + wave6_dec_set_display_buffer(inst, fb); + + return 0; +} + +int wave6_vpu_decode(struct vpu_instance *inst, struct dec_param *option, u32 *fail_res) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + struct dec_open_param *p_open_param = &p_dec_info->open_param; + u32 mode_option = W6_DEC_PIC_OPT_NORMAL, bs_option, reg_val; + int ret; + + if (p_dec_info->thumbnail_mode) { + mode_option = W6_DEC_PIC_OPT_W_THUMBNAIL; + } else if (option->skipframe_mode) { + switch (option->skipframe_mode) { + case WAVE_SKIPMODE_NON_IRAP: + mode_option = W6_DEC_PIC_OPT_SKIP_NON_IRAP; + break; + case WAVE_SKIPMODE_NON_REF: + mode_option = W6_DEC_PIC_OPT_SKIP_NON_REF_PIC; + break; + default: + break; + } + } + + bs_option = 0; + switch (p_open_param->bs_mode) { + case BS_MODE_INTERRUPT: + bs_option = 0; + break; + case BS_MODE_PIC_END: + bs_option = BSOPTION_ENABLE_EXPLICIT_END; + break; + default: + return -EINVAL; + } + + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_RD_PTR, p_dec_info->stream_rd_ptr); + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_WR_PTR, p_dec_info->stream_wr_ptr); + if (p_dec_info->stream_end) + bs_option = 3; + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_BS_OPTION, bs_option); + + reg_val = (p_dec_info->sec_axi_info.use_dec_ip << 1) | + p_dec_info->sec_axi_info.use_dec_lf_row; + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_USE_SEC_AXI, reg_val); + + reg_val = (option->disable_film_grain << 6) | + (option->decode_cra_as_bla << 5) | + mode_option; + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_OPTION, reg_val); + reg_val = (DECODE_ALL_SPATIAL_LAYERS << 9) | + (TEMPORAL_ID_MODE_ABSOLUTE << 8) | + DECODE_ALL_TEMPORAL_LAYERS; + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_TEMPORAL_ID_PLUS1, reg_val); + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_SEQ_CHANGE_ENABLE_FLAG, + p_dec_info->seq_change_mask); + reg_val = ((option->timestamp.hour & 0x1F) << 26) | + ((option->timestamp.min & 0x3F) << 20) | + ((option->timestamp.sec & 0x3F) << 14) | + (option->timestamp.ms & 0x3FFF); + vpu_write_reg(inst->dev, W6_CMD_DEC_PIC_TIMESTAMP, reg_val); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DEC_PIC); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + wave6_print_reg_err(inst->dev, *fail_res); + return -EIO; + } + + return 0; +} + +int wave6_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + u32 reg_val, nal_unit_type, i; + int decoded_index = -1, display_index = -1; + int ret; + + ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT); + if (ret) + return ret; + + result->decoding_success = vpu_read_reg(inst->dev, W6_RET_DEC_DECODING_SUCCESS); + if (!result->decoding_success) + result->error_reason = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_INFO); + else + result->warn_info = vpu_read_reg(inst->dev, W6_RET_DEC_WARN_INFO); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_TYPE); + nal_unit_type = (reg_val & 0x3f0) >> 4; + result->nal_type = nal_unit_type; + + if (inst->std == W_HEVC_DEC) { + if (reg_val & 0x04) + result->pic_type = PIC_TYPE_B; + else if (reg_val & 0x02) + result->pic_type = PIC_TYPE_P; + else if (reg_val & 0x01) + result->pic_type = PIC_TYPE_I; + else + result->pic_type = PIC_TYPE_MAX; + if ((nal_unit_type == 19 || nal_unit_type == 20) && result->pic_type == PIC_TYPE_I) + result->pic_type = PIC_TYPE_IDR; + } else if (inst->std == W_AVC_DEC) { + if (reg_val & 0x04) + result->pic_type = PIC_TYPE_B; + else if (reg_val & 0x02) + result->pic_type = PIC_TYPE_P; + else if (reg_val & 0x01) + result->pic_type = PIC_TYPE_I; + else + result->pic_type = PIC_TYPE_MAX; + if (nal_unit_type == 5 && result->pic_type == PIC_TYPE_I) + result->pic_type = PIC_TYPE_IDR; + } + result->ctu_size = 16 << ((reg_val >> 10) & 0x3); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DECODED_FLAG); + if (reg_val) { + struct frame_buffer fb; + dma_addr_t addr = vpu_read_reg(inst->dev, W6_RET_DEC_DECODED_ADDR); + + fb = wave6_dec_get_display_buffer(inst, addr, false); + result->frame_decoded_addr = addr; + result->frame_decoded = true; + decoded_index = fb.index; + } + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DISPLAY_FLAG); + if (reg_val) { + struct frame_buffer fb; + dma_addr_t addr = vpu_read_reg(inst->dev, W6_RET_DEC_DISPLAY_ADDR); + + fb = wave6_dec_get_display_buffer(inst, addr, false); + result->frame_display_addr = addr; + result->frame_display = true; + display_index = fb.index; + } + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_DISP_IDC); + for (i = 0; i < WAVE6_MAX_FBS; i++) { + if (reg_val & (1 << i)) { + dma_addr_t addr = vpu_read_reg(inst->dev, + W6_RET_DEC_DISP_LINEAR_ADDR_0 + i * 4); + + result->disp_frame_addr[result->disp_frame_num] = addr; + result->disp_frame_num++; + } + } + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_RELEASE_IDC); + for (i = 0; i < WAVE6_MAX_FBS; i++) { + if (reg_val & (1 << i)) { + struct frame_buffer fb; + dma_addr_t addr = vpu_read_reg(inst->dev, + W6_RET_DEC_DISP_LINEAR_ADDR_0 + i * 4); + + fb = wave6_dec_get_display_buffer(inst, addr, true); + result->release_disp_frame_addr[result->release_disp_frame_num] = fb.buf_y; + result->release_disp_frame_num++; + } + } + + result->stream_end = vpu_read_reg(inst->dev, W6_RET_DEC_STREAM_END); + result->notification_flags = vpu_read_reg(inst->dev, W6_RET_DEC_NOTIFICATION); + + if (inst->std == W_HEVC_DEC) { + result->decoded_poc = -1; + result->display_poc = -1; + if (decoded_index >= 0) + result->decoded_poc = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_POC); + } else if (inst->std == W_AVC_DEC) { + result->decoded_poc = -1; + result->display_poc = -1; + if (decoded_index >= 0) + result->decoded_poc = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_POC); + } + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_PIC_SIZE); + result->dec_pic_width = reg_val >> 16; + result->dec_pic_height = reg_val & 0xffff; + + result->num_of_err_m_bs = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_CTB_NUM) >> 16; + result->num_of_tot_m_bs = vpu_read_reg(inst->dev, W6_RET_DEC_ERR_CTB_NUM) & 0xffff; + result->byte_pos_frame_start = vpu_read_reg(inst->dev, W6_RET_DEC_AU_START_POS); + result->byte_pos_frame_end = vpu_read_reg(inst->dev, W6_RET_DEC_AU_END_POS); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_RECOVERY_POINT); + result->h265_rp_sei.recovery_poc_cnt = reg_val & 0xFFFF; + result->h265_rp_sei.exact_match = (reg_val >> 16) & 0x01; + result->h265_rp_sei.broken_link = (reg_val >> 17) & 0x01; + result->h265_rp_sei.exist = (reg_val >> 18) & 0x01; + if (!result->h265_rp_sei.exist) { + result->h265_rp_sei.recovery_poc_cnt = 0; + result->h265_rp_sei.exact_match = false; + result->h265_rp_sei.broken_link = false; + } + + result->last_frame_in_au = vpu_read_reg(inst->dev, W6_RET_DEC_LAST_FRAME_FLAG); + + reg_val = vpu_read_reg(inst->dev, W6_RET_DEC_TIMESTAMP); + result->timestamp.hour = (reg_val >> 26) & 0x1F; + result->timestamp.min = (reg_val >> 20) & 0x3F; + result->timestamp.sec = (reg_val >> 14) & 0x3F; + result->timestamp.ms = reg_val & 0x3FFF; + + result->cycle.host_cmd_s = vpu_read_reg(inst->dev, W6_RET_CQ_IN_TICK); + result->cycle.host_cmd_e = vpu_read_reg(inst->dev, W6_RET_RQ_OUT_TICK); + result->cycle.proc_s = vpu_read_reg(inst->dev, W6_RET_HW_RUN_TICK); + result->cycle.proc_e = vpu_read_reg(inst->dev, W6_RET_HW_DONE_TICK); + result->cycle.vpu_s = vpu_read_reg(inst->dev, W6_RET_FW_RUN_TICK); + result->cycle.vpu_e = vpu_read_reg(inst->dev, W6_RET_FW_DONE_TICK); + result->cycle.frame_cycle = (result->cycle.vpu_e - result->cycle.host_cmd_s) * + p_dec_info->cycle_per_tick; + result->cycle.proc_cycle = (result->cycle.proc_e - result->cycle.proc_s) * + p_dec_info->cycle_per_tick; + result->cycle.vpu_cycle = ((result->cycle.vpu_e - result->cycle.vpu_s) - + (result->cycle.proc_e - result->cycle.proc_s)) * + p_dec_info->cycle_per_tick; + + if (decoded_index >= 0 && decoded_index < WAVE6_MAX_FBS) { + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) + p_dec_info->dec_out_info[decoded_index].decoded_poc = result->decoded_poc; + } + + if (display_index >= 0 && display_index < WAVE6_MAX_FBS) { + if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) + result->display_poc = p_dec_info->dec_out_info[display_index].decoded_poc; + + result->disp_pic_width = p_dec_info->dec_out_info[display_index].dec_pic_width; + result->disp_pic_height = p_dec_info->dec_out_info[display_index].dec_pic_height; + } + + result->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst); + result->wr_ptr = p_dec_info->stream_wr_ptr; + + result->sequence_no = p_dec_info->initial_info.sequence_no; + if (decoded_index >= 0 && decoded_index < WAVE6_MAX_FBS) + p_dec_info->dec_out_info[decoded_index] = *result; + + if (display_index >= 0 && display_index < WAVE6_MAX_FBS) { + result->num_of_tot_m_bs_in_disp = + p_dec_info->dec_out_info[display_index].num_of_tot_m_bs; + result->num_of_err_m_bs_in_disp = + p_dec_info->dec_out_info[display_index].num_of_err_m_bs; + } else { + result->num_of_tot_m_bs_in_disp = 0; + result->num_of_err_m_bs_in_disp = 0; + } + + if (result->notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE) { + wave6_get_dec_seq_result(inst, &p_dec_info->initial_info); + p_dec_info->initial_info.sequence_no++; + } + + return 0; +} + +int wave6_vpu_dec_fini_seq(struct vpu_instance *inst, u32 *fail_res) +{ + int ret; + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DESTROY_INSTANCE); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) + return -ETIMEDOUT; + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + wave6_print_reg_err(inst->dev, *fail_res); + return -EIO; + } + + return 0; +} + +void wave6_vpu_dec_set_bitstream_end(struct vpu_instance *inst, bool eos) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + + p_dec_info->stream_end = eos ? true : false; +} + +dma_addr_t wave6_vpu_dec_get_rd_ptr(struct vpu_instance *inst) +{ + return vpu_read_reg(inst->dev, W6_RET_DEC_BS_RD_PTR); +} + +int wave6_vpu_dec_flush(struct vpu_instance *inst) +{ + int ret, index; + u32 unused_idc; + u32 used_idc; + u32 using_idc; + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_FLUSH_INSTANCE); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) + return -ETIMEDOUT; + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + u32 reg_val; + + reg_val = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + wave6_print_reg_err(inst->dev, reg_val); + return -EIO; + } + + ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_FLUSH_CMD_INFO); + if (ret) + return ret; + + unused_idc = vpu_read_reg(inst->dev, W6_RET_DEC_FLUSH_CMD_BUF_STATE_UNUSED_IDC); + if (unused_idc) + dev_dbg(inst->dev->dev, "%s: unused_idc %d\n", __func__, unused_idc); + + used_idc = vpu_read_reg(inst->dev, W6_RET_DEC_FLUSH_CMD_BUF_STATE_USED_IDC); + if (used_idc) + dev_dbg(inst->dev->dev, "%s: used_idc %d\n", __func__, used_idc); + + using_idc = vpu_read_reg(inst->dev, W6_RET_DEC_FLUSH_CMD_BUF_STATE_USING_IDC); + if (using_idc) + dev_err(inst->dev->dev, "%s: using_idc %d\n", __func__, using_idc); + + for (index = 0; index < WAVE6_MAX_FBS; index++) { + struct frame_buffer fb; + bool remove = false; + dma_addr_t addr = vpu_read_reg(inst->dev, + W6_RET_DEC_FLUSH_CMD_DISP_ADDR_0 + index * 4); + + if ((unused_idc >> index) & 0x1) + remove = true; + if ((used_idc >> index) & 0x1) + remove = true; + + fb = wave6_dec_get_display_buffer(inst, addr, remove); + } + + return 0; +} + +struct enc_cmd_set_param_reg { + u32 enable; + u32 src_size; + u32 custom_map_endian; + u32 sps_param; + u32 pps_param; + u32 gop_param; + u32 intra_param; + u32 conf_win_top_bot; + u32 conf_win_left_right; + u32 rdo_param; + u32 slice_param; + u32 intra_refresh; + u32 intra_min_max_qp; + u32 rc_frame_rate; + u32 rc_target_rate; + u32 rc_param; + u32 hvs_param; + u32 rc_max_bitrate; + u32 rc_vbv_buffer_size; + u32 inter_min_max_qp; + u32 rot_param; + u32 num_units_in_tick; + u32 time_scale; + u32 num_ticks_poc_diff_one; + u32 max_intra_pic_bit; + u32 max_inter_pic_bit; + u32 bg_param; + u32 non_vcl_param; + u32 vui_rbsp_addr; + u32 hrd_rbsp_addr; + u32 qround_offset; + u32 quant_param_1; + u32 quant_param_2; + u32 custom_gop_param; + u32 custom_gop_pic_param[MAX_GOP_NUM]; + u32 tile_param; + u32 custom_lambda[MAX_CUSTOM_LAMBDA_NUM]; + u32 temporal_layer_qp[MAX_NUM_CHANGEABLE_TEMPORAL_LAYER]; + u32 scl_src_size; + u32 scl_param; + u32 color_param; + u32 sar_param; + u32 sar_extended; +}; + +struct enc_cmd_change_param_reg { + u32 enable; + u32 rc_target_rate; +}; + +int wave6_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, + struct enc_open_param *param) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + u32 reg_val; + int ret; + + p_enc_info->cycle_per_tick = 256; + p_enc_info->line_buf_int_en = param->line_buf_int_en; + p_enc_info->stride = 0; + p_enc_info->initial_info_obtained = false; + p_enc_info->sec_axi_info.use_enc_rdo = true; + p_enc_info->sec_axi_info.use_enc_lf = true; + + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TEMP_BASE, param->inst_buffer.temp_base); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TEMP_SIZE, param->inst_buffer.temp_size); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_AR_TABLE_BASE, param->inst_buffer.ar_base); + + reg_val = wave6_vdi_convert_endian(param->stream_endian); + reg_val = (~reg_val & VDI_128BIT_ENDIAN_MASK); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_BS_PARAM, reg_val); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_SRC_OPT, 0); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_ADDR_EXT, param->ext_addr_vcpu); + + reg_val = (COMMAND_QUEUE_DEPTH << 8) | (1 << 4) | 1; + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_CORE_INFO, reg_val); + + reg_val = (param->is_secure_inst << 8) | (param->inst_priority); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_PRIORITY, reg_val); + vpu_write_reg(inst->dev, W6_CMD_ENC_CREATE_INST_TIMEOUT_CYCLE_COUNT, + W6_VPU_TIMEOUT_CYCLE_COUNT); + + wave6_send_command(inst->dev, 0, inst->std, W6_CMD_CREATE_INSTANCE); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + + wave6_print_reg_err(inst->dev, reason_code); + return -EIO; + } + + inst->id = vpu_read_reg(inst->dev, W6_RET_INSTANCE_ID); + + return 0; +} + +static int wave6_set_enc_crop_info(u32 codec, struct enc_codec_param *param, int rot_mode, + int width, int height) +{ + int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(width, 32) : ALIGN(width, 16); + int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(height, 32) : ALIGN(height, 16); + int pad_right, pad_bot; + int crop_right, crop_left, crop_top, crop_bot; + int prp_mode = rot_mode >> 1; + + if (codec == W_HEVC_ENC && + (!rot_mode || prp_mode == 14)) + return 0; + + pad_right = aligned_width - width; + pad_bot = aligned_height - height; + + if (param->conf_win.right > 0) + crop_right = param->conf_win.right + pad_right; + else + crop_right = pad_right; + + if (param->conf_win.bottom > 0) + crop_bot = param->conf_win.bottom + pad_bot; + else + crop_bot = pad_bot; + + crop_top = param->conf_win.top; + crop_left = param->conf_win.left; + + param->conf_win.top = crop_top; + param->conf_win.left = crop_left; + param->conf_win.bottom = crop_bot; + param->conf_win.right = crop_right; + + if (prp_mode == 1 || prp_mode == 15) { + param->conf_win.top = crop_right; + param->conf_win.left = crop_top; + param->conf_win.bottom = crop_left; + param->conf_win.right = crop_bot; + } else if (prp_mode == 2 || prp_mode == 12) { + param->conf_win.top = crop_bot; + param->conf_win.left = crop_right; + param->conf_win.bottom = crop_top; + param->conf_win.right = crop_left; + } else if (prp_mode == 3 || prp_mode == 13) { + param->conf_win.top = crop_left; + param->conf_win.left = crop_bot; + param->conf_win.bottom = crop_right; + param->conf_win.right = crop_top; + } else if (prp_mode == 4 || prp_mode == 10) { + param->conf_win.top = crop_bot; + param->conf_win.bottom = crop_top; + } else if (prp_mode == 8 || prp_mode == 6) { + param->conf_win.left = crop_right; + param->conf_win.right = crop_left; + } else if (prp_mode == 5 || prp_mode == 11) { + param->conf_win.top = crop_left; + param->conf_win.left = crop_top; + param->conf_win.bottom = crop_right; + param->conf_win.right = crop_bot; + } else if (prp_mode == 7 || prp_mode == 9) { + param->conf_win.top = crop_right; + param->conf_win.left = crop_bot; + param->conf_win.bottom = crop_left; + param->conf_win.right = crop_top; + } + + return 0; +} + +static bool wave6_update_enc_info(struct enc_info *p_enc_info) +{ + struct enc_open_param open_param = p_enc_info->open_param; + + p_enc_info->width = open_param.pic_width; + p_enc_info->height = open_param.pic_height; + + switch (open_param.output_format) { + case FORMAT_420: + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_420_P10_16BIT_LSB: + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_420_P10_32BIT_LSB: + p_enc_info->color_format = 1; + break; + case FORMAT_422: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_LSB: + p_enc_info->color_format = 2; + break; + case FORMAT_444: + case FORMAT_444_P10_16BIT_MSB: + case FORMAT_444_P10_16BIT_LSB: + case FORMAT_444_P10_32BIT_MSB: + case FORMAT_444_P10_32BIT_LSB: + p_enc_info->color_format = 3; + break; + case FORMAT_400: + case FORMAT_400_P10_16BIT_MSB: + case FORMAT_400_P10_16BIT_LSB: + case FORMAT_400_P10_32BIT_MSB: + case FORMAT_400_P10_32BIT_LSB: + p_enc_info->color_format = 0; + break; + default: + return false; + } + + return true; +} + +static void wave6_gen_set_param_reg_common(struct enc_info *p_enc_info, enum codec_std std, + struct enc_cmd_set_param_reg *reg) +{ + struct enc_open_param *p_open_param = &p_enc_info->open_param; + struct enc_codec_param *p_param = &p_open_param->codec_param; + unsigned int i, endian; + u32 rot_mir_mode = 0; + + endian = wave6_vdi_convert_endian(p_param->custom_map_endian); + endian = (~endian & VDI_128BIT_ENDIAN_MASK); + + if (p_enc_info->rotation_enable) { + switch (p_enc_info->rotation_angle) { + case 0: + rot_mir_mode |= 0x0; break; + case 90: + rot_mir_mode |= 0x3; break; + case 180: + rot_mir_mode |= 0x5; break; + case 270: + rot_mir_mode |= 0x7; break; + } + } + + if (p_enc_info->mirror_enable) { + switch (p_enc_info->mirror_direction) { + case MIRDIR_NONE: + rot_mir_mode |= 0x0; break; + case MIRDIR_VER: + rot_mir_mode |= 0x9; break; + case MIRDIR_HOR: + rot_mir_mode |= 0x11; break; + case MIRDIR_HOR_VER: + rot_mir_mode |= 0x19; break; + } + } + + wave6_set_enc_crop_info(std, p_param, rot_mir_mode, p_enc_info->width, p_enc_info->height); + + reg->src_size = (p_enc_info->height << 16) | p_enc_info->width; + reg->custom_map_endian = endian; + reg->gop_param = (p_param->temp_layer_cnt << 16) | + (p_param->temp_layer[3].change_qp << 11) | + (p_param->temp_layer[2].change_qp << 10) | + (p_param->temp_layer[1].change_qp << 9) | + (p_param->temp_layer[0].change_qp << 8) | + p_param->gop_preset_idx; + reg->intra_refresh = (p_param->intra_refresh_arg << 16) | p_param->intra_refresh_mode; + reg->intra_min_max_qp = (p_param->max_qp_i << 6) | p_param->min_qp_i; + reg->rc_frame_rate = p_param->frame_rate; + reg->rc_target_rate = p_param->bitrate; + reg->rc_param = (p_param->rc_update_speed << 24) | + (p_param->rc_initial_level << 20) | + ((p_param->rc_initial_qp & 0x3f) << 14) | + (p_param->rc_mode << 13) | + (p_param->pic_rc_max_dqp << 7) | + (p_param->en_vbv_overflow_drop_frame << 3) | + (p_param->en_cu_level_rate_control << 1) | + p_param->en_rate_control; + reg->hvs_param = (p_param->max_delta_qp << 12) | p_param->hvs_qp_scale_div2; + reg->rc_max_bitrate = p_param->max_bitrate; + reg->rc_vbv_buffer_size = p_param->cpb_size; + reg->inter_min_max_qp = (p_param->max_qp_b << 18) | + (p_param->min_qp_b << 12) | + (p_param->max_qp_p << 6) | + p_param->min_qp_p; + reg->rot_param = rot_mir_mode; + reg->conf_win_top_bot = (p_param->conf_win.bottom << 16) | p_param->conf_win.top; + reg->conf_win_left_right = (p_param->conf_win.right << 16) | p_param->conf_win.left; + reg->num_units_in_tick = p_param->num_units_in_tick; + reg->time_scale = p_param->time_scale; + reg->num_ticks_poc_diff_one = p_param->num_ticks_poc_diff_one; + reg->max_intra_pic_bit = p_param->max_intra_pic_bit; + reg->max_inter_pic_bit = p_param->max_inter_pic_bit; + reg->bg_param = ((p_param->bg_delta_qp & 0x3F) << 24) | + (p_param->bg_th_mean_diff << 10) | + (p_param->bg_th_diff << 1) | + p_param->en_bg_detect; + reg->qround_offset = (p_param->q_round_inter << 13) | + (p_param->q_round_intra << 2); + reg->custom_gop_param = p_param->gop_param.custom_gop_size; + for (i = 0; i < p_param->gop_param.custom_gop_size; i++) { + struct custom_gop_pic_param pic_param = p_param->gop_param.pic_param[i]; + + reg->custom_gop_pic_param[i] = (pic_param.temporal_id << 26) | + ((pic_param.ref_poc_l1 & 0x3F) << 20) | + ((pic_param.ref_poc_l0 & 0x3F) << 14) | + (pic_param.use_multi_ref_p << 13) | + (pic_param.pic_qp << 7) | + (pic_param.poc_offset << 2) | + pic_param.pic_type; + } + for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) { + reg->custom_lambda[i] = (p_param->custom_lambda_ssd[i] << 7) | + p_param->custom_lambda_sad[i]; + } + for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) { + reg->temporal_layer_qp[i] = (p_param->temp_layer[i].qp_b << 12) | + (p_param->temp_layer[i].qp_p << 6) | + p_param->temp_layer[i].qp_i; + } + reg->scl_src_size = (p_open_param->pic_height << 16) | p_open_param->pic_width; + reg->scl_param = (p_enc_info->scaler_info.coef_mode << 1) | p_enc_info->scaler_info.enable; + reg->color_param = ((p_param->color.chroma_sample_position & 0x3) << 26) | + (p_param->color.color_range << 25) | + ((p_param->color.matrix_coefficients & 0xFF) << 17) | + ((p_param->color.transfer_characteristics & 0xFF) << 9) | + ((p_param->color.color_primaries & 0xFF) << 1) | + p_param->color.color_description_present; + reg->sar_param = ((p_param->sar.idc & 0xFF) << 1) | + (p_param->sar.enable & 0x1); + reg->sar_extended = ((p_param->sar.height & 0xFFFF) << 16) | + (p_param->sar.width & 0xFFFF); +} + +static void wave6_gen_set_param_reg_hevc(struct enc_info *p_enc_info, + struct enc_cmd_set_param_reg *reg) +{ + struct enc_open_param *p_open_param = &p_enc_info->open_param; + struct enc_codec_param *p_param = &p_open_param->codec_param; + + reg->sps_param = (p_param->en_scaling_list << 31) | + (p_param->en_still_picture << 30) | + (p_param->en_auto_level_adjusting << 28) | + (p_param->en_strong_intra_smoothing << 27) | + (p_param->en_intra_trans_skip << 25) | + (p_param->en_sao << 24) | + (p_param->en_temporal_mvp << 23) | + (p_param->en_long_term << 21) | + (p_enc_info->color_format << 19) | + (p_param->internal_bit_depth << 14) | + (p_param->tier << 12) | + (p_param->level << 3) | + p_param->profile; + reg->pps_param = ((p_param->cr_qp_offset & 0x1F) << 19) | + ((p_param->cb_qp_offset & 0x1F) << 14) | + ((p_param->tc_offset_div2 & 0xF) << 10) | + ((p_param->beta_offset_div2 & 0xF) << 6) | + ((!p_param->en_dbk) << 5) | + (p_param->en_lf_cross_slice_boundary << 2) | + (p_param->en_constrained_intra_pred << 1); + reg->intra_param = (p_param->intra_period << 16) | + (p_param->forced_idr_header << 9) | + (p_param->qp << 3) | + p_param->decoding_refresh_type; + reg->rdo_param = (p_param->en_custom_lambda << 22) | + (p_param->en_me_center << 21) | + (p_param->en_qp_map << 20) | + (p_param->en_mode_map << 19) | + (p_param->en_q_round_offset << 17) | + (p_param->dis_coef_clear << 4) | + (p_param->en_adaptive_round << 3) | + (p_param->en_hvs_qp << 2); + reg->slice_param = (p_param->slice_arg << 3) | p_param->slice_mode; + reg->quant_param_2 = ((p_param->lambda_dqp_inter & 0x3F) << 14) | + ((p_param->lambda_dqp_intra & 0x3F) << 8); + reg->non_vcl_param = (p_open_param->hrd_rbsp_data_size << 18) | + (p_open_param->enc_hrd_rbsp_in_vps << 2) | + (NON_VCL_PARAM_ENCODE_VUI) | + p_open_param->enc_aud; + reg->hrd_rbsp_addr = p_open_param->hrd_rbsp_data_addr; +} + +static void wave6_gen_set_param_reg_avc(struct enc_info *p_enc_info, + struct enc_cmd_set_param_reg *reg) +{ + struct enc_open_param *p_open_param = &p_enc_info->open_param; + struct enc_codec_param *p_param = &p_open_param->codec_param; + + reg->sps_param = (p_param->en_scaling_list << 31) | + (p_param->en_auto_level_adjusting << 28) | + (p_param->en_long_term << 21) | + (p_enc_info->color_format << 19) | + (p_param->internal_bit_depth << 14) | + (p_param->level << 3) | + p_param->profile; + reg->pps_param = (p_param->en_cabac << 30) | + (p_param->en_transform8x8 << 29) | + ((p_param->cr_qp_offset & 0x1F) << 19) | + ((p_param->cb_qp_offset & 0x1F) << 14) | + ((p_param->tc_offset_div2 & 0xF) << 10) | + ((p_param->beta_offset_div2 & 0xF) << 6) | + ((!p_param->en_dbk) << 5) | + (p_param->en_lf_cross_slice_boundary << 2) | + (p_param->en_constrained_intra_pred << 1); + reg->intra_param = (p_param->forced_idr_header << 28) | + (p_param->idr_period << 17) | + (p_param->intra_period << 6) | + p_param->qp; + reg->rdo_param = (p_param->en_custom_lambda << 22) | + (p_param->en_me_center << 21) | + (p_param->en_qp_map << 20) | + (p_param->en_mode_map << 19) | + (p_param->en_q_round_offset << 17) | + (p_param->dis_coef_clear << 4) | + (p_param->en_adaptive_round << 3) | + (p_param->en_hvs_qp << 2); + reg->slice_param = (p_param->slice_arg << 3) | p_param->slice_mode; + reg->quant_param_2 = ((p_param->lambda_dqp_inter & 0x3F) << 14) | + ((p_param->lambda_dqp_intra & 0x3F) << 8); + reg->non_vcl_param = (p_open_param->hrd_rbsp_data_size << 18) | + (p_open_param->enc_hrd_rbsp_in_vps << 2) | + (NON_VCL_PARAM_ENCODE_VUI) | + p_open_param->enc_aud; + reg->hrd_rbsp_addr = p_open_param->hrd_rbsp_data_addr; +} + +static void wave6_gen_change_param_reg_common(struct vpu_instance *inst, + struct enc_info *p_enc_info, + struct enc_cmd_change_param_reg *reg) +{ + if (p_enc_info->open_param.codec_param.bitrate != inst->enc_ctrls.bitrate) { + reg->enable |= BIT(W6_PARAM_CHANGE_ENABLE_BIT_RC_TARGET_RATE); + reg->rc_target_rate = inst->enc_ctrls.bitrate; + p_enc_info->open_param.codec_param.bitrate = inst->enc_ctrls.bitrate; + } +} + +int wave6_vpu_enc_init_seq(struct vpu_instance *inst) +{ + struct enc_cmd_set_param_reg reg; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + u32 i; + int ret; + + memset(®, 0, sizeof(struct enc_cmd_set_param_reg)); + + if (!wave6_update_enc_info(p_enc_info)) + return -EINVAL; + + wave6_gen_set_param_reg_common(p_enc_info, inst->std, ®); + if (inst->std == W_HEVC_ENC) + wave6_gen_set_param_reg_hevc(p_enc_info, ®); + else if (inst->std == W_AVC_ENC) + wave6_gen_set_param_reg_avc(p_enc_info, ®); + + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_OPTION, W6_SET_PARAM_OPT_COMMON); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ENABLE, reg.enable); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SRC_SIZE, reg.src_size); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_MAP_ENDIAN, reg.custom_map_endian); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SPS_PARAM, reg.sps_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_PPS_PARAM, reg.pps_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_GOP_PARAM, reg.gop_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_PARAM, reg.intra_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CONF_WIN_TOP_BOT, reg.conf_win_top_bot); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CONF_WIN_LEFT_RIGHT, reg.conf_win_left_right); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RDO_PARAM, reg.rdo_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SLICE_PARAM, reg.slice_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_REFRESH, reg.intra_refresh); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTRA_MIN_MAX_QP, reg.intra_min_max_qp); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_FRAME_RATE, reg.rc_frame_rate); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE, reg.rc_target_rate); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_PARAM, reg.rc_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_HVS_PARAM, reg.hvs_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_MAX_BITRATE, reg.rc_max_bitrate); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_VBV_BUFFER_SIZE, reg.rc_vbv_buffer_size); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_INTER_MIN_MAX_QP, reg.inter_min_max_qp); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ROT_PARAM, reg.rot_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NUM_UNITS_IN_TICK, reg.num_units_in_tick); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TIME_SCALE, reg.time_scale); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NUM_TICKS_POC_DIFF_ONE, + reg.num_ticks_poc_diff_one); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_MAX_INTRA_PIC_BIT, reg.max_intra_pic_bit); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_MAX_INTER_PIC_BIT, reg.max_inter_pic_bit); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_BG_PARAM, reg.bg_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_NON_VCL_PARAM, reg.non_vcl_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_VUI_RBSP_ADDR, reg.vui_rbsp_addr); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_HRD_RBSP_ADDR, reg.hrd_rbsp_addr); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QROUND_OFFSET, reg.qround_offset); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QUANT_PARAM_1, reg.quant_param_1); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_QUANT_PARAM_2, reg.quant_param_2); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PARAM, reg.custom_gop_param); + for (i = 0; i < MAX_GOP_NUM; i++) + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_0 + (i * 4), + reg.custom_gop_pic_param[i]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TILE_PARAM, reg.tile_param); + for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_0 + (i * 4), + reg.custom_lambda[i]); + for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_0_QP + (i * 4), + reg.temporal_layer_qp[i]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SCL_SRC_SIZE, reg.scl_src_size); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SCL_PARAM, reg.scl_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_COLOR_PARAM, reg.color_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SAR_PARAM, reg.sar_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_SAR_EXTENDED, reg.sar_extended); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_SET_PARAM); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + + wave6_print_reg_err(inst->dev, reason_code); + return -EIO; + } + + return 0; +} + +int wave6_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info) +{ + int ret; + + ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT); + if (ret) + return ret; + + if (vpu_read_reg(inst->dev, W6_RET_ENC_ENCODING_SUCCESS) != 1) { + info->err_reason = vpu_read_reg(inst->dev, W6_RET_ENC_ERR_INFO); + ret = -EIO; + } else { + info->warn_info = vpu_read_reg(inst->dev, W6_RET_ENC_WARN_INFO); + } + + info->min_frame_buffer_count = vpu_read_reg(inst->dev, W6_RET_ENC_NUM_REQUIRED_FBC_FB); + info->min_src_frame_count = vpu_read_reg(inst->dev, W6_RET_ENC_MIN_SRC_BUF_NUM); + info->max_latency_pictures = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_MAX_LATENCY_PICTURES); + info->req_mv_buffer_count = vpu_read_reg(inst->dev, W6_RET_ENC_NUM_REQUIRED_COL_BUF); + + return ret; +} + +int wave6_vpu_enc_change_seq(struct vpu_instance *inst, bool *changed) +{ + struct enc_cmd_change_param_reg reg; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + + memset(®, 0, sizeof(struct enc_cmd_change_param_reg)); + + wave6_gen_change_param_reg_common(inst, p_enc_info, ®); + + if (!reg.enable) + return 0; + + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_OPTION, W6_SET_PARAM_OPT_CHANGE_PARAM); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_ENABLE, reg.enable); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE, reg.rc_target_rate); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_SET_PARAM); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_warn(inst->dev->dev, "enc set param timed out\n"); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + u32 reason_code = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + + wave6_print_reg_err(inst->dev, reason_code); + return -EIO; + } + + *changed = true; + + return 0; +} + +struct enc_cmd_set_fb_reg { + u32 option; + u32 pic_info; + u32 pic_size; + u32 num_fb; + u32 fbc_stride; + u32 fbc_y[WAVE6_MAX_FBS]; + u32 fbc_c[WAVE6_MAX_FBS]; + u32 fbc_cr[WAVE6_MAX_FBS]; + u32 fbc_y_offset[WAVE6_MAX_FBS]; + u32 fbc_c_offset[WAVE6_MAX_FBS]; + u32 fbc_cr_offset[WAVE6_MAX_FBS]; + u32 mv_col[WAVE6_MAX_FBS]; + u32 sub_sampled[WAVE6_MAX_FBS]; + u32 default_cdf; +}; + +static void wave6_gen_set_fb_reg(struct enc_info *p_enc_info, enum codec_std std, + struct frame_buffer *fb_arr, struct enc_cmd_set_fb_reg *reg) +{ + struct enc_open_param *p_open_param = &p_enc_info->open_param; + u32 mv_count = p_enc_info->initial_info.req_mv_buffer_count; + u32 buf_width, buf_height; + u32 stride_l, stride_c, i; + + if (std == W_AVC_ENC) { + buf_width = ALIGN(p_enc_info->width, 16); + buf_height = ALIGN(p_enc_info->height, 16); + if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) { + buf_width = ALIGN(p_enc_info->height, 16); + buf_height = ALIGN(p_enc_info->width, 16); + } + } else { + buf_width = ALIGN(p_enc_info->width, 8); + buf_height = ALIGN(p_enc_info->height, 8); + if ((p_enc_info->rotation_angle != 0 || p_enc_info->mirror_direction != 0) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + buf_width = ALIGN(p_enc_info->width, 32); + buf_height = ALIGN(p_enc_info->height, 32); + } + if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) { + buf_width = ALIGN(p_enc_info->height, 32); + buf_height = ALIGN(p_enc_info->width, 32); + } + } + + if ((p_enc_info->rotation_angle != 0 || p_enc_info->mirror_direction != 0) && + !(p_enc_info->rotation_angle == 180 && + p_enc_info->mirror_direction == MIRDIR_HOR_VER)) { + stride_l = ALIGN((buf_width + 63), 64); + stride_c = ALIGN((buf_width + 31), 32) / 2; + } else { + stride_l = ALIGN((p_enc_info->width) + 63, 64); + stride_c = ALIGN((p_enc_info->width) + 31, 32) / 2; + } + + reg->option = (p_open_param->enable_non_ref_fbc_write << 26) | (1 << 4) | (1 << 3); + reg->pic_info = p_enc_info->stride; + reg->pic_size = (buf_width << 16) | buf_height; + reg->num_fb = ((p_enc_info->num_frame_buffers - 1) << 16) | (mv_count - 1); + reg->fbc_stride = (stride_l << 16) | stride_c; + reg->default_cdf = 0; + + for (i = 0; i < p_enc_info->num_frame_buffers; i++) { + reg->fbc_y[i] = fb_arr[i].buf_y; + reg->fbc_c[i] = fb_arr[i].buf_cb; + reg->fbc_cr[i] = fb_arr[i].buf_cr; + reg->fbc_y_offset[i] = p_enc_info->vb_fbc_y_tbl[i].daddr; + reg->fbc_c_offset[i] = p_enc_info->vb_fbc_c_tbl[i].daddr; + reg->fbc_cr_offset[i] = p_enc_info->vb_fbc_c_tbl[i].daddr + + (p_enc_info->vb_fbc_c_tbl[i].size >> 1); + reg->sub_sampled[i] = p_enc_info->vb_sub_sam_buf[i].daddr; + } + for (i = 0; i < mv_count; i++) + reg->mv_col[i] = p_enc_info->vb_mv[i].daddr; +} + +int wave6_vpu_enc_register_frame_buffer(struct vpu_instance *inst, struct frame_buffer *fb_arr) +{ + struct enc_cmd_set_fb_reg *reg; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + u32 mv_count = p_enc_info->initial_info.req_mv_buffer_count; + int ret; + u32 idx; + + for (idx = 0; idx < p_enc_info->num_frame_buffers; idx++) { + if (!p_enc_info->vb_fbc_y_tbl[idx].daddr) + return -EINVAL; + if (!p_enc_info->vb_fbc_c_tbl[idx].daddr) + return -EINVAL; + if (!p_enc_info->vb_sub_sam_buf[idx].daddr) + return -EINVAL; + } + for (idx = 0; idx < mv_count; idx++) { + if (!p_enc_info->vb_mv[idx].daddr) + return -EINVAL; + } + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + wave6_gen_set_fb_reg(p_enc_info, inst->std, fb_arr, reg); + + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_OPTION, reg->option); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_PIC_INFO, reg->pic_info); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_PIC_SIZE, reg->pic_size); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_NUM, reg->num_fb); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_STRIDE, reg->fbc_stride); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_DEFAULT_CDF, reg->default_cdf); + for (idx = 0; idx < p_enc_info->num_frame_buffers; idx++) { + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_Y0 + (idx * 24), reg->fbc_y[idx]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_C0 + (idx * 24), reg->fbc_c[idx]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_CR0 + (idx * 8), reg->fbc_cr[idx]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_Y_OFFSET0 + (idx * 24), + reg->fbc_y_offset[idx]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_C_OFFSET0 + (idx * 24), + reg->fbc_c_offset[idx]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_FBC_CR_OFFSET0 + (idx * 8), + reg->fbc_cr_offset[idx]); + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_SUB_SAMPLED0 + (idx * 24), + reg->sub_sampled[idx]); + } + for (idx = 0; idx < mv_count; idx++) + vpu_write_reg(inst->dev, W6_CMD_ENC_SET_FB_MV_COL0 + (idx * 24), reg->mv_col[idx]); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_SET_FB); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + kfree(reg); + return ret; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + kfree(reg); + return -EIO; + } + + kfree(reg); + return 0; +} + +struct enc_cmd_enc_pic_reg { + u32 bs_start; + u32 bs_size; + u32 bs_option; + u32 use_sec_axi; + u32 report_param; + u32 mv_histo_class0; + u32 mv_histo_class1; + u32 custom_map_param; + u32 custom_map_addr; + u32 src_pic_idx; + u32 src_addr_y; + u32 src_addr_u; + u32 src_addr_v; + u32 src_stride; + u32 src_format; + u32 src_axi_sel; + u32 code_option; + u32 pic_param; + u32 longterm_pic; + u32 prefix_sei_nal_addr; + u32 prefix_sei_info; + u32 suffix_sei_nal_addr; + u32 suffix_sei_info; + u32 timestamp; + u32 csc_coeff[MAX_CSC_COEFF_NUM]; +}; + +static bool is_format_conv(enum frame_buffer_format in_fmt, + enum frame_buffer_format out_fmt) +{ + if (in_fmt == FORMAT_420 || + in_fmt == FORMAT_420_P10_16BIT_MSB || + in_fmt == FORMAT_420_P10_16BIT_LSB || + in_fmt == FORMAT_420_P10_32BIT_MSB || + in_fmt == FORMAT_420_P10_32BIT_LSB) { + if (out_fmt != FORMAT_420 && + out_fmt != FORMAT_420_P10_16BIT_MSB && + out_fmt != FORMAT_420_P10_16BIT_LSB && + out_fmt != FORMAT_420_P10_32BIT_MSB && + out_fmt != FORMAT_420_P10_32BIT_LSB) + return true; + } else if (in_fmt == FORMAT_422 || + in_fmt == FORMAT_422_P10_16BIT_MSB || + in_fmt == FORMAT_422_P10_16BIT_LSB || + in_fmt == FORMAT_422_P10_32BIT_MSB || + in_fmt == FORMAT_422_P10_32BIT_LSB) { + if (out_fmt != FORMAT_422 && + out_fmt != FORMAT_422_P10_16BIT_MSB && + out_fmt != FORMAT_422_P10_16BIT_LSB && + out_fmt != FORMAT_422_P10_32BIT_MSB && + out_fmt != FORMAT_422_P10_32BIT_LSB) + return true; + } else if (in_fmt == FORMAT_444 || + in_fmt == FORMAT_444_P10_16BIT_MSB || + in_fmt == FORMAT_444_P10_16BIT_LSB || + in_fmt == FORMAT_444_P10_32BIT_MSB || + in_fmt == FORMAT_444_P10_32BIT_LSB) { + if (out_fmt != FORMAT_444 && + out_fmt != FORMAT_444_P10_16BIT_MSB && + out_fmt != FORMAT_444_P10_16BIT_LSB && + out_fmt != FORMAT_444_P10_32BIT_MSB && + out_fmt != FORMAT_444_P10_32BIT_LSB) + return true; + } + + return false; +} + +static void wave6_gen_enc_pic_reg(struct enc_info *p_enc_info, bool cbcr_interleave, bool nv21, + struct enc_param *opt, struct enc_cmd_enc_pic_reg *reg) +{ + struct enc_open_param open = p_enc_info->open_param; + struct enc_codec_param param = open.codec_param; + bool is_lsb = false; + bool is_10bit = false; + bool is_3p4b = false; + u32 stride_c; + u32 src_frame_format; + u32 endian; + u32 color_format; + bool is_ayuv = false; + bool is_csc_format = false; + bool is_24bit = false; + bool format_conv; + + endian = wave6_vdi_convert_endian(open.source_endian); + endian = (~endian & VDI_128BIT_ENDIAN_MASK); + format_conv = is_format_conv(open.src_format, open.output_format); + + switch (open.src_format) { + case FORMAT_420: + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_420_P10_16BIT_LSB: + color_format = 1; + stride_c = (cbcr_interleave) ? opt->source_frame->stride : + (opt->source_frame->stride / 2); + break; + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_420_P10_32BIT_LSB: + color_format = 1; + stride_c = (cbcr_interleave) ? opt->source_frame->stride : + ALIGN((opt->source_frame->stride / 2), 16); + break; + case FORMAT_422: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_LSB: + color_format = 2; + stride_c = (cbcr_interleave) ? opt->source_frame->stride : + (opt->source_frame->stride / 2); + stride_c = (format_conv) ? (stride_c * 2) : stride_c; + break; + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_LSB: + color_format = 2; + stride_c = (cbcr_interleave) ? opt->source_frame->stride : + ALIGN((opt->source_frame->stride / 2), 16); + stride_c = (format_conv) ? (stride_c * 2) : stride_c; + break; + case FORMAT_444: + case FORMAT_444_P10_16BIT_MSB: + case FORMAT_444_P10_16BIT_LSB: + color_format = 3; + stride_c = (cbcr_interleave) ? (opt->source_frame->stride * 2) : + opt->source_frame->stride; + stride_c = (format_conv) ? (stride_c * 2) : stride_c; + break; + case FORMAT_444_P10_32BIT_MSB: + case FORMAT_444_P10_32BIT_LSB: + color_format = 3; + stride_c = (cbcr_interleave) ? ALIGN((opt->source_frame->stride * 2), 16) : + opt->source_frame->stride; + stride_c = (format_conv) ? (stride_c * 2) : stride_c; + break; + case FORMAT_YUV444_24BIT: + color_format = 0; + stride_c = ALIGN((opt->source_frame->stride * 2), 16); + break; + case FORMAT_RGB_24BIT_PACKED: + case FORMAT_YUV444_24BIT_PACKED: + case FORMAT_RGB_32BIT_PACKED: + case FORMAT_RGB_P10_32BIT_PACKED: + case FORMAT_YUV444_32BIT_PACKED: + case FORMAT_YUV444_P10_32BIT_PACKED: + color_format = 4; + stride_c = 0; + break; + case FORMAT_YUYV: + case FORMAT_YVYU: + case FORMAT_UYVY: + case FORMAT_VYUY: + case FORMAT_YUYV_P10_16BIT_MSB: + case FORMAT_YVYU_P10_16BIT_MSB: + case FORMAT_UYVY_P10_16BIT_MSB: + case FORMAT_VYUY_P10_16BIT_MSB: + case FORMAT_YUYV_P10_16BIT_LSB: + case FORMAT_YVYU_P10_16BIT_LSB: + case FORMAT_UYVY_P10_16BIT_LSB: + case FORMAT_VYUY_P10_16BIT_LSB: + case FORMAT_YUYV_P10_32BIT_MSB: + case FORMAT_YVYU_P10_32BIT_MSB: + case FORMAT_UYVY_P10_32BIT_MSB: + case FORMAT_VYUY_P10_32BIT_MSB: + case FORMAT_YUYV_P10_32BIT_LSB: + case FORMAT_YVYU_P10_32BIT_LSB: + case FORMAT_UYVY_P10_32BIT_LSB: + case FORMAT_VYUY_P10_32BIT_LSB: + color_format = 2; + stride_c = 0; + break; + default: + color_format = 0; + stride_c = 0; + break; + } + + switch (open.src_format) { + case FORMAT_420: + case FORMAT_422: + case FORMAT_444: + case FORMAT_400: + case FORMAT_YUYV: + case FORMAT_YVYU: + case FORMAT_UYVY: + case FORMAT_VYUY: + is_lsb = false; + is_3p4b = false; + break; + case FORMAT_420_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_444_P10_16BIT_MSB: + case FORMAT_400_P10_16BIT_MSB: + case FORMAT_YUYV_P10_16BIT_MSB: + case FORMAT_YVYU_P10_16BIT_MSB: + case FORMAT_UYVY_P10_16BIT_MSB: + case FORMAT_VYUY_P10_16BIT_MSB: + is_lsb = false; + is_10bit = true; + is_3p4b = false; + break; + case FORMAT_420_P10_16BIT_LSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_444_P10_16BIT_LSB: + case FORMAT_400_P10_16BIT_LSB: + case FORMAT_YUYV_P10_16BIT_LSB: + case FORMAT_YVYU_P10_16BIT_LSB: + case FORMAT_UYVY_P10_16BIT_LSB: + case FORMAT_VYUY_P10_16BIT_LSB: + is_lsb = true; + is_10bit = true; + is_3p4b = false; + break; + case FORMAT_420_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_444_P10_32BIT_MSB: + case FORMAT_400_P10_32BIT_MSB: + case FORMAT_YUYV_P10_32BIT_MSB: + case FORMAT_YVYU_P10_32BIT_MSB: + case FORMAT_UYVY_P10_32BIT_MSB: + case FORMAT_VYUY_P10_32BIT_MSB: + is_lsb = false; + is_10bit = true; + is_3p4b = true; + break; + case FORMAT_420_P10_32BIT_LSB: + case FORMAT_422_P10_32BIT_LSB: + case FORMAT_444_P10_32BIT_LSB: + case FORMAT_400_P10_32BIT_LSB: + case FORMAT_YUYV_P10_32BIT_LSB: + case FORMAT_YVYU_P10_32BIT_LSB: + case FORMAT_UYVY_P10_32BIT_LSB: + case FORMAT_VYUY_P10_32BIT_LSB: + is_lsb = true; + is_10bit = true; + is_3p4b = true; + break; + case FORMAT_RGB_32BIT_PACKED: + is_ayuv = false; + is_csc_format = true; + break; + case FORMAT_RGB_P10_32BIT_PACKED: + is_ayuv = false; + is_csc_format = true; + is_10bit = true; + break; + case FORMAT_YUV444_32BIT_PACKED: + is_ayuv = true; + is_csc_format = true; + break; + case FORMAT_YUV444_P10_32BIT_PACKED: + is_ayuv = true; + is_csc_format = true; + is_10bit = true; + break; + case FORMAT_RGB_24BIT_PACKED: + is_ayuv = false; + is_csc_format = true; + is_24bit = true; + break; + case FORMAT_YUV444_24BIT_PACKED: + is_ayuv = true; + is_csc_format = true; + is_24bit = true; + break; + case FORMAT_YUV444_24BIT: + is_ayuv = true; + break; + default: + break; + } + + src_frame_format = (nv21 << 2) | (cbcr_interleave << 1); + switch (open.packed_format) { + case PACKED_YUYV: + src_frame_format = 1; break; + case PACKED_YVYU: + src_frame_format = 5; break; + case PACKED_UYVY: + src_frame_format = 9; break; + case PACKED_VYUY: + src_frame_format = 13; break; + default: + break; + } + + reg->bs_start = opt->pic_stream_buffer_addr; + reg->bs_size = opt->pic_stream_buffer_size; + reg->bs_option = (p_enc_info->line_buf_int_en << 6); + reg->use_sec_axi = (p_enc_info->sec_axi_info.use_enc_rdo << 1) | + p_enc_info->sec_axi_info.use_enc_lf; + reg->report_param = (param.en_report_mv_histo << 1); + reg->mv_histo_class0 = (param.report_mv_histo_threshold0 << 16) | + param.report_mv_histo_threshold1; + reg->mv_histo_class1 = (param.report_mv_histo_threshold2 << 16) | + param.report_mv_histo_threshold3; + + reg->src_pic_idx = opt->src_idx; + if (opt->src_end) + reg->src_pic_idx = 0xFFFFFFFF; + + reg->src_addr_y = opt->source_frame->buf_y; + if (open.cbcr_order == CBCR_ORDER_NORMAL) { + reg->src_addr_u = opt->source_frame->buf_cb; + reg->src_addr_v = opt->source_frame->buf_cr; + } else { + reg->src_addr_u = opt->source_frame->buf_cr; + reg->src_addr_v = opt->source_frame->buf_cb; + } + reg->src_stride = (opt->source_frame->stride << 16) | stride_c; + reg->src_format = (color_format << 28) | + (is_24bit << 25) | + (is_ayuv << 24) | + (is_csc_format << 20) | + (opt->csc.format_order << 16) | + (endian << 12) | + (is_lsb << 6) | + (is_3p4b << 5) | + (is_10bit << 4) | + src_frame_format; + reg->src_axi_sel = DEFAULT_SRC_AXI; + reg->code_option = (opt->src_end << 10) | + (W6_ENC_PIC_OPT_VCL) | + (W6_ENC_PIC_OPT_HEADER_IMPLICIT); + reg->pic_param = (param.intra_4x4 << 28) | + (opt->force_pic_type << 21) | + (opt->force_pic_type_enable << 20) | + (opt->force_pic_qp_b << 14) | + (opt->force_pic_qp_p << 8) | + (opt->force_pic_qp_i << 2) | + (opt->force_pic_qp_enable << 1) | + opt->skip_picture; + reg->timestamp = ((opt->timestamp.hour & 0x1F) << 26) | + ((opt->timestamp.min & 0x3F) << 20) | + ((opt->timestamp.sec & 0x3F) << 14) | + ((opt->timestamp.ms & 0x3FFF)); + reg->csc_coeff[0] = ((opt->csc.coef_ry & 0x3FF) << 20) | + ((opt->csc.coef_gy & 0x3FF) << 10) | + (opt->csc.coef_by & 0x3FF); + reg->csc_coeff[1] = ((opt->csc.coef_rcb & 0x3FF) << 20) | + ((opt->csc.coef_gcb & 0x3FF) << 10) | + (opt->csc.coef_bcb & 0x3FF); + reg->csc_coeff[2] = ((opt->csc.coef_rcr & 0x3FF) << 20) | + ((opt->csc.coef_gcr & 0x3FF) << 10) | + (opt->csc.coef_bcr & 0x3FF); + reg->csc_coeff[3] = ((opt->csc.offset_y & 0x3FF) << 20) | + ((opt->csc.offset_cb & 0x3FF) << 10) | + (opt->csc.offset_cr & 0x3FF); +} + +int wave6_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res) +{ + struct enc_cmd_enc_pic_reg reg; + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + + memset(®, 0, sizeof(struct enc_cmd_enc_pic_reg)); + + wave6_gen_enc_pic_reg(p_enc_info, inst->cbcr_interleave, + inst->nv21, option, ®); + + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_START, reg.bs_start); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_SIZE, reg.bs_size); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_BS_OPTION, reg.bs_option); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_USE_SEC_AXI, reg.use_sec_axi); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_REPORT_PARAM, reg.report_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_MV_HISTO_CLASS0, reg.mv_histo_class0); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_MV_HISTO_CLASS1, reg.mv_histo_class1); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM, reg.custom_map_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR, reg.custom_map_addr); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_PIC_IDX, reg.src_pic_idx); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_Y, reg.src_addr_y); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_U, reg.src_addr_u); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_ADDR_V, reg.src_addr_v); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_STRIDE, reg.src_stride); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_FORMAT, reg.src_format); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SRC_AXI_SEL, reg.src_axi_sel); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CODE_OPTION, reg.code_option); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PIC_PARAM, reg.pic_param); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_LONGTERM_PIC, reg.longterm_pic); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR, reg.prefix_sei_nal_addr); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_PREFIX_SEI_INFO, reg.prefix_sei_info); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR, reg.suffix_sei_nal_addr); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_SUFFIX_SEI_INFO, reg.suffix_sei_info); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_TIMESTAMP, reg.timestamp); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_0, reg.csc_coeff[0]); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_1, reg.csc_coeff[1]); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_2, reg.csc_coeff[2]); + vpu_write_reg(inst->dev, W6_CMD_ENC_PIC_CSC_COEFF_3, reg.csc_coeff[3]); + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_ENC_PIC); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) { + dev_err(inst->dev->dev, "%s: timeout\n", __func__); + return -ETIMEDOUT; + } + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + wave6_print_reg_err(inst->dev, *fail_res); + return -EIO; + } + + return 0; +} + +int wave6_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + u32 reg_val; + int ret; + + ret = wave6_send_query(inst->dev, inst->id, inst->std, W6_QUERY_OPT_GET_RESULT); + if (ret) + return ret; + + result->encoding_success = vpu_read_reg(inst->dev, W6_RET_ENC_ENCODING_SUCCESS); + if (!result->encoding_success) + result->error_reason = vpu_read_reg(inst->dev, W6_RET_ENC_ERR_INFO); + else + result->warn_info = vpu_read_reg(inst->dev, W6_RET_DEC_WARN_INFO); + + result->enc_pic_cnt = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM); + reg_val = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_TYPE); + result->pic_type = reg_val & 0xFFFF; + + result->enc_vcl_nut = vpu_read_reg(inst->dev, W6_RET_ENC_VCL_NUT); + result->recon_frame_index = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_IDX); + if (result->recon_frame_index >= 0) + result->recon_frame = inst->frame_buf[result->recon_frame_index]; + + result->non_ref_pic = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NON_REF_PIC_FLAG); + result->num_of_slices = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_SLICE_NUM); + result->pic_skipped = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_SKIP); + result->num_of_intra = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM_INTRA); + result->num_of_merge = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM_MERGE); + result->num_of_skip_block = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_NUM_SKIP); + result->bitstream_wrap_around = 0; + + result->avg_ctu_qp = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_AVG_CTU_QP); + result->enc_pic_byte = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_BYTE); + + result->enc_gop_pic_idx = vpu_read_reg(inst->dev, W6_RET_ENC_GOP_PIC_IDX); + result->enc_pic_poc = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_POC); + result->enc_src_idx = vpu_read_reg(inst->dev, W6_RET_ENC_USED_SRC_IDX); + result->wr_ptr = vpu_read_reg(inst->dev, W6_RET_ENC_WR_PTR); + result->rd_ptr = vpu_read_reg(inst->dev, W6_RET_ENC_RD_PTR); + + result->pic_distortion_low = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_DIST_LOW); + result->pic_distortion_high = vpu_read_reg(inst->dev, W6_RET_ENC_PIC_DIST_HIGH); + + result->mv_histo.cnt0 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_0); + result->mv_histo.cnt1 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_1); + result->mv_histo.cnt2 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_2); + result->mv_histo.cnt3 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_3); + result->mv_histo.cnt4 = vpu_read_reg(inst->dev, W6_RET_ENC_HISTO_CNT_4); + + result->fme_sum.lower_x0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_X_DIR_LOWER); + result->fme_sum.higher_x0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_X_DIR_HIGHER); + result->fme_sum.lower_y0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_Y_DIR_LOWER); + result->fme_sum.higher_y0 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME0_Y_DIR_HIGHER); + result->fme_sum.lower_x1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_X_DIR_LOWER); + result->fme_sum.higher_x1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_X_DIR_HIGHER); + result->fme_sum.lower_y1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_Y_DIR_LOWER); + result->fme_sum.higher_y1 = vpu_read_reg(inst->dev, W6_RET_ENC_SUM_ME1_Y_DIR_HIGHER); + + result->src_y_addr = vpu_read_reg(inst->dev, W6_RET_ENC_SRC_Y_ADDR); + result->custom_map_addr = vpu_read_reg(inst->dev, W6_RET_ENC_CUSTOM_MAP_OPTION_ADDR); + result->prefix_sei_nal_addr = vpu_read_reg(inst->dev, W6_RET_ENC_PREFIX_SEI_NAL_ADDR); + result->suffix_sei_nal_addr = vpu_read_reg(inst->dev, W6_RET_ENC_SUFFIX_SEI_NAL_ADDR); + + reg_val = vpu_read_reg(inst->dev, W6_RET_ENC_TIMESTAMP); + result->timestamp.hour = (reg_val >> 26) & 0x1F; + result->timestamp.min = (reg_val >> 20) & 0x3F; + result->timestamp.sec = (reg_val >> 14) & 0x3F; + result->timestamp.ms = reg_val & 0x3FFF; + + result->bitstream_buffer = vpu_read_reg(inst->dev, W6_RET_ENC_RD_PTR); + + if (result->recon_frame_index == RECON_IDX_FLAG_HEADER_ONLY) + result->bitstream_size = result->enc_pic_byte; + else if (result->recon_frame_index < 0) + result->bitstream_size = 0; + else + result->bitstream_size = result->enc_pic_byte; + + result->cycle.host_cmd_s = vpu_read_reg(inst->dev, W6_RET_CQ_IN_TICK); + result->cycle.host_cmd_e = vpu_read_reg(inst->dev, W6_RET_RQ_OUT_TICK); + result->cycle.proc_s = vpu_read_reg(inst->dev, W6_RET_HW_RUN_TICK); + result->cycle.proc_e = vpu_read_reg(inst->dev, W6_RET_HW_DONE_TICK); + result->cycle.vpu_s = vpu_read_reg(inst->dev, W6_RET_FW_RUN_TICK); + result->cycle.vpu_e = vpu_read_reg(inst->dev, W6_RET_FW_DONE_TICK); + result->cycle.frame_cycle = (result->cycle.vpu_e - result->cycle.host_cmd_s) * + p_enc_info->cycle_per_tick; + result->cycle.proc_cycle = (result->cycle.proc_e - result->cycle.proc_s) * + p_enc_info->cycle_per_tick; + result->cycle.vpu_cycle = ((result->cycle.vpu_e - result->cycle.vpu_s) - + (result->cycle.proc_e - result->cycle.proc_s)) * + p_enc_info->cycle_per_tick; + + return 0; +} + +int wave6_vpu_enc_fini_seq(struct vpu_instance *inst, u32 *fail_res) +{ + int ret; + + wave6_send_command(inst->dev, inst->id, inst->std, W6_CMD_DESTROY_INSTANCE); + ret = wave6_wait_vpu_busy(inst->dev, W6_VPU_BUSY_STATUS); + if (ret) + return -ETIMEDOUT; + + if (!vpu_read_reg(inst->dev, W6_RET_SUCCESS)) { + *fail_res = vpu_read_reg(inst->dev, W6_RET_FAIL_REASON); + wave6_print_reg_err(inst->dev, *fail_res); + return -EIO; + } + + return 0; +} + +static int wave6_vpu_enc_check_gop_param(struct vpu_instance *inst, struct enc_codec_param *p_param) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + int i; + bool low_delay = true; + + if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP) { + if (p_param->gop_param.custom_gop_size > 1) { + int min_val = p_param->gop_param.pic_param[0].poc_offset; + + for (i = 1; i < p_param->gop_param.custom_gop_size; i++) { + if (min_val > p_param->gop_param.pic_param[i].poc_offset) { + low_delay = false; + break; + } + min_val = p_param->gop_param.pic_param[i].poc_offset; + } + } + } else if (p_param->gop_preset_idx == PRESET_IDX_ALL_I || + p_param->gop_preset_idx == PRESET_IDX_IPP || + p_param->gop_preset_idx == PRESET_IDX_IBBB || + p_param->gop_preset_idx == PRESET_IDX_IPPPP || + p_param->gop_preset_idx == PRESET_IDX_IBBBB || + p_param->gop_preset_idx == PRESET_IDX_IPP_SINGLE) { + } + + if (p_param->gop_preset_idx >= PRESET_IDX_MAX) { + dev_err(dev, "gop_preset_idx: %d\n", p_param->gop_preset_idx); + return -EINVAL; + } + + if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP) { + if (p_param->gop_param.custom_gop_size < 1 || + p_param->gop_param.custom_gop_size > MAX_GOP_NUM) { + dev_err(dev, "custom_gop_size: %d\n", p_param->gop_param.custom_gop_size); + return -EINVAL; + } + for (i = 0; i < p_param->gop_param.custom_gop_size; i++) { + struct custom_gop_pic_param pic_param = p_param->gop_param.pic_param[i]; + + if (pic_param.pic_type != PIC_TYPE_I && + pic_param.pic_type != PIC_TYPE_P && + pic_param.pic_type != PIC_TYPE_B) { + dev_err(dev, "pic_param[%d].pic_type: %d\n", i, pic_param.pic_type); + return -EINVAL; + } + if (pic_param.poc_offset < 1 || + pic_param.poc_offset > p_param->gop_param.custom_gop_size) { + dev_err(dev, "pic_param[%d].poc_offset: %d\n", + i, pic_param.poc_offset); + return -EINVAL; + } + if (pic_param.use_multi_ref_p < 0 || pic_param.use_multi_ref_p > 1) { + dev_err(dev, "pic_param[%d].use_multi_ref_p: %d\n", + i, pic_param.use_multi_ref_p); + return -EINVAL; + } + if (pic_param.temporal_id < 0 || pic_param.temporal_id > 3) { + dev_err(dev, "pic_param[%d].temporal_id: %d\n", + i, pic_param.temporal_id); + return -EINVAL; + } + } + if (inst->std == W_AVC_ENC && !low_delay) { + for (i = 0; i < p_param->gop_param.custom_gop_size; i++) { + if (p_param->gop_param.pic_param[i].temporal_id > 0) { + dev_err(dev, "std: %d, pic_param[%d].temporal_id: %d\n", + inst->std, i, + p_param->gop_param.pic_param[i].temporal_id); + return -EINVAL; + } + } + } + } + + if (inst->std == W_HEVC_ENC) { + if (p_param->decoding_refresh_type > DEC_REFRESH_TYPE_IDR) { + dev_err(dev, "decoding_refresh_type: %d\n", p_param->decoding_refresh_type); + return -EINVAL; + } + } else { + if (p_param->decoding_refresh_type != DEC_REFRESH_TYPE_NON_IRAP) { + dev_err(dev, "decoding_refresh_type: %d\n", p_param->decoding_refresh_type); + return -EINVAL; + } + } + + return 0; +} + +static int wave6_vpu_enc_check_tile_slice_param(struct vpu_instance *inst, + int width, int height, + struct enc_codec_param *p_param) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + + if (p_param->slice_mode > 2) { + dev_err(dev, "slice_mode: %d\n", p_param->slice_mode); + return -EINVAL; + } + if (p_param->slice_mode == 1) { + unsigned int ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64; + unsigned int mb_num = ((width + ctu_size - 1) / ctu_size) * + ((height + ctu_size - 1) / ctu_size); + + if (p_param->slice_arg < 1 || p_param->slice_arg > 0x3FFFF) { + dev_err(dev, "slice_arg: %d\n", p_param->slice_arg); + return -EINVAL; + } + if (p_param->slice_arg > mb_num) { + dev_info(dev, "slice_arg: %d, mb_num: %d\n", + p_param->slice_arg, mb_num); + p_param->slice_arg = mb_num; + } + if (inst->std == W_AVC_ENC && p_param->slice_arg < 4) { + dev_info(dev, "std: %d, slice_arg: %d\n", + inst->std, p_param->slice_arg); + p_param->slice_arg = 4; + } + } + + return 0; +} + +static int wave6_vpu_enc_check_rc_param(struct vpu_instance *inst, struct enc_codec_param *p_param) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + + if (p_param->frame_rate < 1 || p_param->frame_rate > 960) { + dev_err(dev, "frame_rate: %d\n", p_param->frame_rate); + return -EINVAL; + } + if (p_param->bitrate > 1500000000) { + dev_err(dev, "bitrate: %d\n", p_param->bitrate); + return -EINVAL; + } + if (p_param->qp > 51) { + dev_err(dev, "qp: %d\n", p_param->qp); + return -EINVAL; + } + if (p_param->min_qp_i > 51 || p_param->min_qp_p > 51 || p_param->min_qp_b > 51) { + dev_err(dev, "min_qp_i: %d, min_qp_p: %d, min_qp_b: %d\n", + p_param->min_qp_i, p_param->min_qp_p, p_param->min_qp_b); + return -EINVAL; + } + if (p_param->max_qp_i > 51 || p_param->max_qp_p > 51 || p_param->max_qp_b > 51) { + dev_err(dev, "max_qp_i: %d, max_qp_p: %d, max_qp_b: %d\n", + p_param->max_qp_i, p_param->max_qp_p, p_param->max_qp_b); + return -EINVAL; + } + if (p_param->min_qp_i > p_param->max_qp_i) { + dev_err(dev, "min_qp_i: %d, max_qp_i: %d\n", p_param->min_qp_i, p_param->max_qp_i); + return -EINVAL; + } + if (p_param->min_qp_p > p_param->max_qp_p) { + dev_err(dev, "min_qp_p: %d, max_qp_p: %d\n", p_param->min_qp_p, p_param->max_qp_p); + return -EINVAL; + } + if (p_param->min_qp_b > p_param->max_qp_b) { + dev_err(dev, "min_qp_b: %d, max_qp_b: %d\n", p_param->min_qp_b, p_param->max_qp_b); + return -EINVAL; + } + if (p_param->rc_initial_qp < -1 || p_param->rc_initial_qp > 51) { + dev_err(dev, "rc_initial_qp: %d\n", p_param->rc_initial_qp); + return -EINVAL; + } + if (p_param->en_rate_control != 1 && p_param->en_rate_control != 0) { + dev_err(dev, "en_rate_control: %d\n", p_param->en_rate_control); + return -EINVAL; + } + if (p_param->rc_mode > 1) { + dev_err(dev, "rc_mode: %d\n", p_param->rc_mode); + return -EINVAL; + } + if (p_param->en_rate_control) { + if (p_param->bitrate <= p_param->frame_rate) { + dev_err(dev, "bitrate: %d, frame_rate: %d\n", + p_param->bitrate, p_param->frame_rate); + return -EINVAL; + } + if (p_param->rc_initial_qp != -1) { + if (p_param->rc_initial_qp < p_param->min_qp_i) { + dev_err(dev, "rc_initial_qp: %d, min_qp_i: %d\n", + p_param->rc_initial_qp, p_param->min_qp_i); + return -EINVAL; + } + if (p_param->rc_initial_qp > p_param->max_qp_i) { + dev_err(dev, "rc_initial_qp: %d, max_qp_i: %d\n", + p_param->rc_initial_qp, p_param->max_qp_i); + return -EINVAL; + } + } + } else { + if (p_param->qp < p_param->min_qp_i) { + dev_err(dev, "qp: %d, min_qp_i: %d\n", p_param->qp, p_param->min_qp_i); + return -EINVAL; + } + if (p_param->qp < p_param->min_qp_p) { + dev_err(dev, "qp: %d, min_qp_p: %d\n", p_param->qp, p_param->min_qp_p); + return -EINVAL; + } + if (p_param->qp < p_param->min_qp_b) { + dev_err(dev, "qp: %d, min_qp_b: %d\n", p_param->qp, p_param->min_qp_b); + return -EINVAL; + } + if (p_param->qp > p_param->max_qp_i) { + dev_err(dev, "qp: %d, max_qp_i: %d\n", p_param->qp, p_param->max_qp_i); + return -EINVAL; + } + if (p_param->qp > p_param->max_qp_p) { + dev_err(dev, "qp: %d, max_qp_p: %d\n", p_param->qp, p_param->max_qp_p); + return -EINVAL; + } + if (p_param->qp > p_param->max_qp_b) { + dev_err(dev, "qp: %d, max_qp_b: %d\n", p_param->qp, p_param->max_qp_b); + return -EINVAL; + } + } + + return 0; +} + +static int wave6_vpu_enc_check_intra_param(struct vpu_instance *inst, + int width, int height, + struct enc_codec_param *p_param) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + unsigned int ctu_size = (inst->std == W_AVC_ENC) ? 16 : 64; + unsigned int num_ctu_col = (width + ctu_size - 1) / ctu_size; + unsigned int num_ctu_row = (height + ctu_size - 1) / ctu_size; + + if (p_param->intra_refresh_mode > INTRA_REFRESH_COLUMN) { + dev_err(dev, "intra_refresh_mode: %d\n", p_param->intra_refresh_mode); + return -EINVAL; + } + if (p_param->intra_refresh_mode != INTRA_REFRESH_NONE) { + if (p_param->intra_refresh_arg < 1 || p_param->intra_refresh_arg > 511) { + dev_err(dev, "intra_refresh_arg: %d\n", p_param->intra_refresh_arg); + return -EINVAL; + } + } + if (p_param->intra_refresh_mode == INTRA_REFRESH_ROW && + p_param->intra_refresh_arg > num_ctu_row) { + dev_err(dev, "intra_refresh_mode: %d, intra_refresh_arg: %d\n", + p_param->intra_refresh_mode, p_param->intra_refresh_arg); + return -EINVAL; + } + if (p_param->intra_refresh_mode == INTRA_REFRESH_COLUMN && + p_param->intra_refresh_arg > num_ctu_col) { + dev_err(dev, "intra_refresh_mode: %d, intra_refresh_arg: %d\n", + p_param->intra_refresh_mode, p_param->intra_refresh_arg); + return -EINVAL; + } + + return 0; +} + +static int wave6_vpu_enc_check_custom_param(struct vpu_instance *inst, + struct enc_codec_param *p_param) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + int i; + + if (p_param->en_qp_map != 1 && p_param->en_qp_map != 0) { + dev_err(dev, "en_qp_map: %d\n", p_param->en_qp_map); + return -EINVAL; + } + if (p_param->en_mode_map != 1 && p_param->en_mode_map != 0) { + dev_err(dev, "en_mode_map: %d\n", p_param->en_mode_map); + return -EINVAL; + } + if (p_param->en_custom_lambda != 1 && p_param->en_custom_lambda != 0) { + dev_err(dev, "en_custom_lambda: %d\n", p_param->en_custom_lambda); + return -EINVAL; + } + for (i = 0; i < MAX_CUSTOM_LAMBDA_NUM; i++) { + if (p_param->custom_lambda_ssd[i] > 16383) { + dev_err(dev, "custom_lambda_ssd[%d]: %d\n", + i, p_param->custom_lambda_ssd[i]); + return -EINVAL; + } + if (p_param->custom_lambda_sad[i] > 127) { + dev_err(dev, "custom_lambda_sad[%d]: %d\n", + i, p_param->custom_lambda_sad[i]); + return -EINVAL; + } + } + + return 0; +} + +static int wave6_vpu_enc_check_conf_win_size_param(struct vpu_instance *inst, + int width, int height, + struct vpu_rect conf_win) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + + if (conf_win.left % 2 || conf_win.top % 2 || conf_win.right % 2 || conf_win.bottom % 2) { + dev_err(dev, "conf_win left: %d, top: %d, right: %d, bottom: %d\n", + conf_win.left, conf_win.top, conf_win.right, conf_win.bottom); + return -EINVAL; + } + if (conf_win.left > 8192 || conf_win.top > 8192 || + conf_win.right > 8192 || conf_win.bottom > 8192) { + dev_err(dev, "conf_win left: %d, top: %d, right: %d, bottom: %d\n", + conf_win.left, conf_win.top, conf_win.right, conf_win.bottom); + return -EINVAL; + } + if ((conf_win.right + conf_win.left) > width) { + dev_err(dev, "conf_win.left: %d, conf_win.right: %d, width: %d\n", + conf_win.left, conf_win.right, width); + return -EINVAL; + } + if ((conf_win.bottom + conf_win.top) > height) { + dev_err(dev, "conf_win.top: %d, conf_win.bottom: %d, height: %d\n", + conf_win.top, conf_win.bottom, height); + return -EINVAL; + } + + return 0; +} + +static int wave6_vpu_enc_check_temporal_layer_param(struct vpu_instance *inst, + struct enc_codec_param *p_param) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + int i; + + if (p_param->temp_layer_cnt < 1 || p_param->temp_layer_cnt > 4) { + dev_err(dev, "temp_layer_cnt: %d\n", p_param->temp_layer_cnt); + return -EINVAL; + } + if (p_param->temp_layer_cnt > 1) { + if (p_param->gop_preset_idx == PRESET_IDX_CUSTOM_GOP || + p_param->gop_preset_idx == PRESET_IDX_ALL_I) { + dev_err(dev, "temp_layer_cnt: %d, gop_preset_idx: %d\n", + p_param->temp_layer_cnt, p_param->gop_preset_idx); + return -EINVAL; + } + } + for (i = 0; i < MAX_NUM_CHANGEABLE_TEMPORAL_LAYER; i++) { + if (p_param->temp_layer[i].change_qp != 1 && + p_param->temp_layer[i].change_qp != 0) { + dev_err(dev, "temp_layer[%d].change_qp: %d\n", + i, p_param->temp_layer[i].change_qp); + return -EINVAL; + } + if (p_param->temp_layer[i].qp_b > 51) { + dev_err(dev, "temp_layer[%d].qp_b: %d\n", i, p_param->temp_layer[i].qp_b); + return -EINVAL; + } + if (p_param->temp_layer[i].qp_p > 51) { + dev_err(dev, "temp_layer[%d].qp_p: %d\n", i, p_param->temp_layer[i].qp_p); + return -EINVAL; + } + if (p_param->temp_layer[i].qp_i > 51) { + dev_err(dev, "temp_layer[%d].qp_i: %d\n", i, p_param->temp_layer[i].qp_i); + return -EINVAL; + } + } + + return 0; +} + +int wave6_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *pop) +{ + struct vpu_device *vpu_dev = inst->dev; + struct device *dev = vpu_dev->dev; + struct vpu_attr *attr = &inst->dev->attr; + struct enc_codec_param *p_param = &pop->codec_param; + + if (inst->std != W_HEVC_ENC && inst->std != W_AVC_ENC) { + dev_err(dev, "std %d\n", inst->std); + return -EOPNOTSUPP; + } + + if (pop->pic_width % W6_ENC_PIC_SIZE_STEP || pop->pic_height % W6_ENC_PIC_SIZE_STEP) { + dev_err(dev, "pic_width: %d | pic_height: %d\n", pop->pic_width, pop->pic_height); + return -EINVAL; + } + if (pop->pic_width < W6_MIN_ENC_PIC_WIDTH || pop->pic_width > W6_MAX_ENC_PIC_WIDTH) { + dev_err(dev, "pic_width: %d\n", pop->pic_width); + return -EINVAL; + } + if (pop->pic_height < W6_MIN_ENC_PIC_HEIGHT || pop->pic_height > W6_MAX_ENC_PIC_HEIGHT) { + dev_err(dev, "pic_height: %d\n", pop->pic_height); + return -EINVAL; + } + + if (pop->packed_format && inst->cbcr_interleave == 1) { + dev_err(dev, "packed_format: %d, cbcr_interleave: %d\n", + pop->packed_format, inst->cbcr_interleave); + return -EINVAL; + } + if (pop->packed_format && inst->nv21 == 1) { + dev_err(dev, "packed_format: %d, nv21: %d\n", pop->packed_format, inst->nv21); + return -EINVAL; + } + if (pop->src_format == FORMAT_RGB_32BIT_PACKED || + pop->src_format == FORMAT_YUV444_32BIT_PACKED || + pop->src_format == FORMAT_RGB_P10_32BIT_PACKED || + pop->src_format == FORMAT_YUV444_P10_32BIT_PACKED) { + if (!inst->cbcr_interleave) { + dev_err(dev, "src_format: %d, cbcr_interleave: %d\n", + pop->src_format, inst->cbcr_interleave); + return -EINVAL; + } + if (inst->nv21 == 1) { + dev_err(dev, "src_format: %d, nv21: %d\n", pop->src_format, inst->nv21); + return -EINVAL; + } + } + if (pop->src_format == FORMAT_RGB_24BIT_PACKED || + pop->src_format == FORMAT_YUV444_24BIT_PACKED) { + if (!inst->cbcr_interleave || inst->nv21 == 1) { + dev_err(dev, "src_format: %d, cbcr_interleave: %d, nv21: %d\n", + pop->src_format, inst->cbcr_interleave, inst->nv21); + return -EINVAL; + } + } + if (pop->src_format == FORMAT_YUV444_24BIT) { + if (!inst->cbcr_interleave) { + dev_err(dev, "src_format: %d, cbcr_interleave: %d\n", + pop->src_format, inst->cbcr_interleave); + return -EINVAL; + } + } + + if (wave6_vpu_enc_check_gop_param(inst, p_param)) { + dev_err(dev, "failed wave6_vpu_enc_check_gop_param()\n"); + return -EINVAL; + } + if (wave6_vpu_enc_check_tile_slice_param(inst, pop->pic_width, pop->pic_height, p_param)) { + dev_err(dev, "failed wave6_vpu_enc_check_tile_slice_param()\n"); + return -EINVAL; + } + if (wave6_vpu_enc_check_rc_param(inst, p_param)) { + dev_err(dev, "failed wave6_vpu_enc_check_rc_param()\n"); + return -EINVAL; + } + if (wave6_vpu_enc_check_intra_param(inst, pop->pic_width, pop->pic_height, p_param)) { + dev_err(dev, "failed wave6_vpu_enc_check_intra_param()\n"); + return -EINVAL; + } + if (wave6_vpu_enc_check_custom_param(inst, p_param)) { + dev_err(dev, "failed wave6_vpu_enc_check_custom_param()\n"); + return -EINVAL; + } + if (wave6_vpu_enc_check_conf_win_size_param(inst, pop->pic_width, pop->pic_height, + p_param->conf_win)) { + dev_err(dev, "failed wave6_vpu_enc_check_conf_win_size_param()\n"); + return -EINVAL; + } + if (wave6_vpu_enc_check_temporal_layer_param(inst, p_param)) { + dev_err(dev, "failed wave6_vpu_enc_check_temporal_layer_param()\n"); + return -EINVAL; + } + + if (p_param->internal_bit_depth != 8 && p_param->internal_bit_depth != 10) { + dev_err(dev, "internal_bit_depth: %d\n", p_param->internal_bit_depth); + return -EINVAL; + } + if (p_param->intra_period > 2047) { + dev_err(dev, "intra_period: %d\n", p_param->intra_period); + return -EINVAL; + } + if (p_param->intra_period == 1 && p_param->gop_preset_idx == PRESET_IDX_ALL_I) { + dev_err(dev, "intra_period: %d, gop_preset_idx: %d\n", + p_param->intra_period, p_param->gop_preset_idx); + return -EINVAL; + } + if (p_param->en_long_term != 1 && p_param->en_long_term != 0) { + dev_err(dev, "en_long_term: %d\n", p_param->en_long_term); + return -EINVAL; + } + if (p_param->cpb_size < 10 || p_param->cpb_size > 100000) { + dev_err(dev, "cpb_size: %d\n", p_param->cpb_size); + return -EINVAL; + } + if (p_param->en_cu_level_rate_control != 1 && p_param->en_cu_level_rate_control != 0) { + dev_err(dev, "en_cu_level_rate_control: %d\n", p_param->en_cu_level_rate_control); + return -EINVAL; + } + if (p_param->en_vbv_overflow_drop_frame != 1 && p_param->en_vbv_overflow_drop_frame != 0) { + dev_err(dev, "en_vbv_overflow_drop_frame: %d\n", + p_param->en_vbv_overflow_drop_frame); + return -EINVAL; + } + if (p_param->en_hvs_qp != 1 && p_param->en_hvs_qp != 0) { + dev_err(dev, "en_hvs_qp: %d\n", p_param->en_hvs_qp); + return -EINVAL; + } + if (p_param->en_hvs_qp) { + if (p_param->hvs_qp_scale_div2 < 1 || p_param->hvs_qp_scale_div2 > 4) { + dev_err(dev, "hvs_qp_scale_div2: %d\n", p_param->hvs_qp_scale_div2); + return -EINVAL; + } + } + if (p_param->max_delta_qp > 12) { + dev_err(dev, "max_delta_qp: %d\n", p_param->max_delta_qp); + return -EINVAL; + } + if (p_param->rc_update_speed > 255) { + dev_err(dev, "rc_update_speed: %d\n", p_param->rc_update_speed); + return -EINVAL; + } + if (p_param->max_bitrate > 1500000000) { + dev_err(dev, "max_bitrate: %d\n", p_param->max_bitrate); + return -EINVAL; + } + if (p_param->rc_initial_level > 15) { + dev_err(dev, "rc_initial_level: %d\n", p_param->rc_initial_level); + return -EINVAL; + } + if (p_param->pic_rc_max_dqp > 51) { + dev_err(dev, "pic_rc_max_dqp: %d\n", p_param->pic_rc_max_dqp); + return -EINVAL; + } + if (p_param->en_bg_detect != 1 && p_param->en_bg_detect != 0) { + dev_err(dev, "en_bg_detect: %d\n", p_param->en_bg_detect); + return -EINVAL; + } + if (p_param->bg_th_diff > 255) { + dev_err(dev, "bg_th_diff: %d\n", p_param->bg_th_diff); + return -EINVAL; + } + if (p_param->bg_th_mean_diff > 255) { + dev_err(dev, "bg_th_mean_diff: %d\n", p_param->bg_th_mean_diff); + return -EINVAL; + } + if (p_param->bg_delta_qp < -16 || p_param->bg_delta_qp > 15) { + dev_err(dev, "bg_delta_qp: %d\n", p_param->bg_delta_qp); + return -EINVAL; + } + if (p_param->en_me_center != 1 && p_param->en_me_center != 0) { + dev_err(dev, "en_me_center: %d\n", p_param->en_me_center); + return -EINVAL; + } + if (p_param->en_dbk != 1 && p_param->en_dbk != 0) { + dev_err(dev, "en_dbk: %d\n", p_param->en_dbk); + return -EINVAL; + } + if (p_param->en_scaling_list != 1 && p_param->en_scaling_list != 0) { + dev_err(dev, "en_scaling_list: %d\n", p_param->en_scaling_list); + return -EINVAL; + } + if (p_param->en_adaptive_round != 1 && p_param->en_adaptive_round != 0) { + dev_err(dev, "en_adaptive_round: %d\n", p_param->en_adaptive_round); + return -EINVAL; + } + if (p_param->q_round_intra > 255) { + dev_err(dev, "q_round_intra: %d\n", p_param->q_round_intra); + return -EINVAL; + } + if (p_param->q_round_inter > 255) { + dev_err(dev, "q_round_inter: %d\n", p_param->q_round_inter); + return -EINVAL; + } + if (p_param->dis_coef_clear != 1 && p_param->dis_coef_clear != 0) { + dev_err(dev, "dis_coef_clear: %d\n", p_param->dis_coef_clear); + return -EINVAL; + } + if (p_param->lambda_dqp_intra < -32 || p_param->lambda_dqp_intra > 31) { + dev_err(dev, "lambda_dqp_intra: %d\n", p_param->lambda_dqp_intra); + return -EINVAL; + } + if (p_param->lambda_dqp_inter < -32 || p_param->lambda_dqp_inter > 31) { + dev_err(dev, "lambda_dqp_inter: %d\n", p_param->lambda_dqp_inter); + return -EINVAL; + } + if (p_param->en_q_round_offset != 1 && p_param->en_q_round_offset != 0) { + dev_err(dev, "en_q_round_offset: %d\n", p_param->en_q_round_offset); + return -EINVAL; + } + if (p_param->forced_idr_header > 2) { + dev_err(dev, "forced_idr_header: %d\n", p_param->forced_idr_header); + return -EINVAL; + } + if (p_param->num_units_in_tick > INT_MAX) { + dev_err(dev, "num_units_in_tick: %d\n", p_param->num_units_in_tick); + return -EINVAL; + } + if (p_param->time_scale > INT_MAX) { + dev_err(dev, "time_scale: %d\n", p_param->time_scale); + return -EINVAL; + } + if (p_param->max_intra_pic_bit > 1500000000) { + dev_err(dev, "max_intra_pic_bit: %d\n", p_param->max_intra_pic_bit); + return -EINVAL; + } + if (p_param->max_inter_pic_bit > 1500000000) { + dev_err(dev, "max_inter_pic_bit: %d\n", p_param->max_inter_pic_bit); + return -EINVAL; + } + + if (p_param->color.color_range > 1) { + dev_err(dev, "color_range: %d\n", p_param->color.color_range); + return -EINVAL; + } + if (p_param->color.matrix_coefficients > 255) { + dev_err(dev, "matrix_coefficients: %d\n", p_param->color.matrix_coefficients); + return -EINVAL; + } + if (p_param->color.transfer_characteristics > 255) { + dev_err(dev, "transfer_characteristics: %d\n", + p_param->color.transfer_characteristics); + return -EINVAL; + } + if (p_param->color.color_primaries > 255) { + dev_err(dev, "color_primaries: %d\n", p_param->color.color_primaries); + return -EINVAL; + } + if (inst->std == W_HEVC_ENC) { + if (p_param->internal_bit_depth == 10 && !attr->support_hevc10bit_enc) { + dev_err(dev, "internal_bit_depth: %d, support_hevc10bit_enc: %d\n", + p_param->internal_bit_depth, attr->support_hevc10bit_enc); + return -EOPNOTSUPP; + } + if (p_param->idr_period != 0) { + dev_err(dev, "idr_period: %d\n", p_param->idr_period); + return -EINVAL; + } + if (p_param->en_strong_intra_smoothing != 1 && + p_param->en_strong_intra_smoothing != 0) { + dev_err(dev, "en_strong_intra_smoothing: %d\n", + p_param->en_strong_intra_smoothing); + return -EINVAL; + } + if (p_param->en_constrained_intra_pred != 1 && + p_param->en_constrained_intra_pred != 0) { + dev_err(dev, "en_constrained_intra_pred: %d\n", + p_param->en_constrained_intra_pred); + return -EINVAL; + } + if (p_param->en_intra_trans_skip != 1 && p_param->en_intra_trans_skip != 0) { + dev_err(dev, "en_intra_trans_skip: %d\n", p_param->en_intra_trans_skip); + return -EINVAL; + } + if (p_param->en_temporal_mvp != 1 && p_param->en_temporal_mvp != 0) { + dev_err(dev, "en_temporal_mvp: %d\n", p_param->en_temporal_mvp); + return -EINVAL; + } + if (p_param->en_cabac != 0) { + dev_err(dev, "en_cabac: %d\n", p_param->en_cabac); + return -EINVAL; + } + if (p_param->en_transform8x8 != 0) { + dev_err(dev, "en_transform8x8: %d\n", p_param->en_transform8x8); + return -EINVAL; + } + if (p_param->en_lf_cross_slice_boundary != 1 && + p_param->en_lf_cross_slice_boundary != 0) { + dev_err(dev, "en_lf_cross_slice_boundary: %d\n", + p_param->en_lf_cross_slice_boundary); + return -EINVAL; + } + if (p_param->beta_offset_div2 < -6 || p_param->beta_offset_div2 > 6) { + dev_err(dev, "beta_offset_div2: %d\n", p_param->beta_offset_div2); + return -EINVAL; + } + if (p_param->tc_offset_div2 < -6 || p_param->tc_offset_div2 > 6) { + dev_err(dev, "tc_offset_div2: %d\n", p_param->tc_offset_div2); + return -EINVAL; + } + if (p_param->en_sao != 1 && p_param->en_sao != 0) { + dev_err(dev, "en_sao: %d\n", p_param->en_sao); + return -EINVAL; + } + if (p_param->cb_qp_offset < -12 || p_param->cb_qp_offset > 12) { + dev_err(dev, "cb_qp_offset: %d\n", p_param->cb_qp_offset); + return -EINVAL; + } + if (p_param->cr_qp_offset < -12 || p_param->cr_qp_offset > 12) { + dev_err(dev, "cr_qp_offset: %d\n", p_param->cr_qp_offset); + return -EINVAL; + } + if (p_param->en_still_picture != 1 && p_param->en_still_picture != 0) { + dev_err(dev, "en_still_picture: %d\n", p_param->en_still_picture); + return -EINVAL; + } + if (p_param->en_auto_level_adjusting != 1 && + p_param->en_auto_level_adjusting != 0) { + dev_err(dev, "en_auto_level_adjusting: %d\n", + p_param->en_auto_level_adjusting); + return -EINVAL; + } + if (p_param->tier > 1) { + dev_err(dev, "tier: %d\n", p_param->tier); + return -EINVAL; + } + if (p_param->profile > HEVC_PROFILE_STILLPICTURE) { + dev_err(dev, "profile: %d\n", p_param->profile); + return -EINVAL; + } + if (p_param->internal_bit_depth == 10 && p_param->profile == HEVC_PROFILE_MAIN) { + dev_err(dev, "internal_bit_depth: %d, profile: %d\n", + p_param->internal_bit_depth, p_param->profile); + return -EINVAL; + } + if (p_param->num_ticks_poc_diff_one < 1 || + p_param->num_ticks_poc_diff_one > 65535) { + dev_err(dev, "num_ticks_poc_diff_one: %d\n", + p_param->num_ticks_poc_diff_one); + return -EINVAL; + } + if (p_param->color.chroma_sample_position != 0) { + dev_err(dev, "chroma_sample_position: %d\n", + p_param->color.chroma_sample_position); + return -EINVAL; + } + if (p_param->intra_4x4 > 3 || p_param->intra_4x4 == 1) { + dev_err(dev, "intra_4x4: %d\n", p_param->intra_4x4); + return -EINVAL; + } + } else if (inst->std == W_AVC_ENC) { + if (p_param->internal_bit_depth == 10 && !attr->support_avc10bit_enc) { + dev_err(dev, "internal_bit_depth: %d, support_avc10bit_enc: %d\n", + p_param->internal_bit_depth, attr->support_avc10bit_enc); + return -EOPNOTSUPP; + } + if (p_param->idr_period > 2047) { + dev_err(dev, "idr_period: %d\n", p_param->idr_period); + return -EINVAL; + } + if (p_param->idr_period == 1 && p_param->gop_preset_idx == PRESET_IDX_ALL_I) { + dev_err(dev, "idr_period: %d, gop_preset_idx: %d\n", + p_param->idr_period, p_param->gop_preset_idx); + return -EINVAL; + } + if (p_param->en_strong_intra_smoothing != 0) { + dev_err(dev, "en_strong_intra_smoothing: %d\n", + p_param->en_strong_intra_smoothing); + return -EINVAL; + } + if (p_param->en_constrained_intra_pred != 1 && + p_param->en_constrained_intra_pred != 0) { + dev_err(dev, "en_constrained_intra_pred: %d\n", + p_param->en_constrained_intra_pred); + return -EINVAL; + } + if (p_param->en_intra_trans_skip != 0) { + dev_err(dev, "en_intra_trans_skip: %d\n", p_param->en_intra_trans_skip); + return -EINVAL; + } + if (p_param->en_temporal_mvp != 0) { + dev_err(dev, "en_temporal_mvp: %d\n", p_param->en_temporal_mvp); + return -EINVAL; + } + if (p_param->en_cabac != 1 && p_param->en_cabac != 0) { + dev_err(dev, "en_cabac: %d\n", p_param->en_cabac); + return -EINVAL; + } + if (p_param->en_transform8x8 != 1 && p_param->en_transform8x8 != 0) { + dev_err(dev, "en_transform8x8: %d\n", p_param->en_transform8x8); + return -EINVAL; + } + if (p_param->en_lf_cross_slice_boundary != 1 && + p_param->en_lf_cross_slice_boundary != 0) { + dev_err(dev, "en_lf_cross_slice_boundary: %d\n", + p_param->en_lf_cross_slice_boundary); + return -EINVAL; + } + if (p_param->beta_offset_div2 < -6 || p_param->beta_offset_div2 > 6) { + dev_err(dev, "beta_offset_div2: %d\n", p_param->beta_offset_div2); + return -EINVAL; + } + if (p_param->tc_offset_div2 < -6 || p_param->tc_offset_div2 > 6) { + dev_err(dev, "tc_offset_div2: %d\n", p_param->tc_offset_div2); + return -EINVAL; + } + if (p_param->en_sao != 0) { + dev_err(dev, "en_sao: %d\n", p_param->en_sao); + return -EINVAL; + } + if (p_param->cb_qp_offset < -12 || p_param->cb_qp_offset > 12) { + dev_err(dev, "cb_qp_offset: %d\n", p_param->cb_qp_offset); + return -EINVAL; + } + if (p_param->cr_qp_offset < -12 || p_param->cr_qp_offset > 12) { + dev_err(dev, "cr_qp_offset: %d\n", p_param->cr_qp_offset); + return -EINVAL; + } + if (p_param->en_still_picture != 0) { + dev_err(dev, "en_still_picture: %d\n", p_param->en_still_picture); + return -EINVAL; + } + if (p_param->en_auto_level_adjusting != 1 && + p_param->en_auto_level_adjusting != 0) { + dev_err(dev, "en_auto_level_adjusting: %d\n", + p_param->en_auto_level_adjusting); + return -EINVAL; + } + if (p_param->tier != 0) { + dev_err(dev, "tier: %d\n", p_param->tier); + return -EINVAL; + } + if (p_param->profile > H264_PROFILE_HIGH10) { + dev_err(dev, "profile: %d\n", p_param->profile); + return -EINVAL; + } + if (p_param->profile) { + if (p_param->internal_bit_depth == 10 && + p_param->profile != H264_PROFILE_HIGH10) { + dev_err(dev, "internal_bit_depth: %d, profile: %d\n", + p_param->internal_bit_depth, p_param->profile); + return -EINVAL; + } + } + if (p_param->num_ticks_poc_diff_one != 0) { + dev_err(dev, "num_ticks_poc_diff_one: %d\n", + p_param->num_ticks_poc_diff_one); + return -EINVAL; + } + if (p_param->color.chroma_sample_position != 0) { + dev_err(dev, "chroma_sample_position: %d\n", + p_param->color.chroma_sample_position); + return -EINVAL; + } + if (p_param->intra_4x4 != 0) { + dev_err(dev, "intra_4x4: %d\n", p_param->intra_4x4); + return -EINVAL; + } + } + + return 0; +} diff --git a/drivers/media/platform/chips-media/wave6/wave6-hw.h b/drivers/media/platform/chips-media/wave6/wave6-hw.h new file mode 100644 index 000000000000..a40477dc023e --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-hw.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 backend interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_HW_H__ +#define __WAVE6_HW_H__ + +#define STD_AVC 0 +#define STD_HEVC 12 + +enum product_id { + PRODUCT_ID_617, + PRODUCT_ID_627, + PRODUCT_ID_637, + PRODUCT_ID_NONE, +}; + +#define BSOPTION_ENABLE_EXPLICIT_END BIT(0) +#define NON_VCL_PARAM_ENCODE_VUI BIT(1) + +#define DECODE_ALL_TEMPORAL_LAYERS 0 +#define DECODE_ALL_SPATIAL_LAYERS 0 + +#define REGISTER_DISPLAY_BUFFER 1 +#define DEFAULT_PIXEL_ORDER 1 + +#define WTL_RIGHT_JUSTIFIED 0 +#define WTL_LEFT_JUSTIFIED 1 +#define WTL_PIXEL_8BIT 0 +#define WTL_PIXEL_16BIT 1 +#define WTL_PIXEL_32BIT 2 + +#define MAX_CSC_COEFF_NUM 4 + +bool wave6_vpu_is_init(struct vpu_device *vpu_dev); +void wave6_vpu_check_state(struct vpu_device *vpu_dev); +int wave6_vpu_get_version(struct vpu_device *vpu_dev, u32 *version_info, uint32_t *revision); +void wave6_vpu_enable_interrupt(struct vpu_device *vpu_dev); +int wave6_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param); + +void wave6_vpu_dec_set_bitstream_end(struct vpu_instance *inst, bool eos); +int wave6_vpu_dec_register_frame_buffer(struct vpu_instance *inst, + struct frame_buffer *fb_arr, enum tiled_map_type map_type, + uint32_t count); +int wave6_vpu_dec_register_display_buffer(struct vpu_instance *inst, struct frame_buffer fb); +int wave6_vpu_dec_init_seq(struct vpu_instance *inst); +int wave6_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info); +int wave6_vpu_decode(struct vpu_instance *inst, struct dec_param *option, u32 *fail_res); +int wave6_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result); +int wave6_vpu_dec_fini_seq(struct vpu_instance *inst, u32 *fail_res); +dma_addr_t wave6_vpu_dec_get_rd_ptr(struct vpu_instance *inst); +int wave6_vpu_dec_flush(struct vpu_instance *inst); + +int wave6_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, + struct enc_open_param *param); +int wave6_vpu_enc_init_seq(struct vpu_instance *inst); +int wave6_vpu_enc_change_seq(struct vpu_instance *inst, bool *changed); +int wave6_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info); +int wave6_vpu_enc_register_frame_buffer(struct vpu_instance *inst, + struct frame_buffer *fb_arr); +int wave6_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res); +int wave6_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result); +int wave6_vpu_enc_fini_seq(struct vpu_instance *inst, u32 *fail_res); +int wave6_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *pop); + +#endif /* __WAVE6_HW_H__ */ diff --git a/drivers/media/platform/chips-media/wave6/wave6-regdefine.h b/drivers/media/platform/chips-media/wave6/wave6-regdefine.h new file mode 100644 index 000000000000..05d563cf9d55 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-regdefine.h @@ -0,0 +1,675 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 register definitions + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_REGDEFINE_H__ +#define __WAVE6_REGDEFINE_H__ + +enum wave6_command { + W6_CMD_INIT_VPU = 0x0001, + W6_CMD_WAKEUP_VPU = 0x0002, + W6_CMD_SLEEP_VPU = 0x0004, + W6_CMD_CREATE_INSTANCE = 0x0008, + W6_CMD_FLUSH_INSTANCE = 0x0010, + W6_CMD_DESTROY_INSTANCE = 0x0020, + W6_CMD_INIT_SEQ = 0x0040, + W6_CMD_SET_FB = 0x0080, + W6_CMD_DEC_PIC = 0x0100, + W6_CMD_ENC_PIC = 0x0100, + W6_CMD_ENC_SET_PARAM = 0x0200, + W6_CMD_DEC_SET_DISP = 0x0400, + W6_CMD_INIT_WORK_BUF = 0x1000, + W6_CMD_QUERY = 0x4000, +}; + +enum wave6_init_seq_option { + W6_INIT_SEQ_OPT_NORMAL = 1, + W6_INIT_SEQ_OPT_W_THUMBNAIL = 17, +}; + +enum wave6_set_param_option { + W6_SET_PARAM_OPT_COMMON = 0, + W6_SET_PARAM_OPT_CHANGE_PARAM = 1, +}; + +enum wave6_dec_pic_option { + W6_DEC_PIC_OPT_NORMAL = 0, + W6_DEC_PIC_OPT_W_THUMBNAIL = 16, + W6_DEC_PIC_OPT_SKIP_NON_IRAP = 17, + W6_DEC_PIC_OPT_SKIP_NON_REF_PIC = 19, +}; + +enum wave6_enc_pic_option { + W6_ENC_PIC_OPT_HEADER_IMPLICIT = 1, + W6_ENC_PIC_OPT_VCL = 2, +}; + +enum wave6_query_option { + W6_QUERY_OPT_GET_VPU_INFO = 0, + W6_QUERY_OPT_GET_RESULT = 2, + W6_QUERY_OPT_GET_FLUSH_CMD_INFO = 10, +}; + +enum wave6_interrupt_bit { + W6_INT_BIT_INIT_VPU = 0, + W6_INT_BIT_WAKEUP_VPU = 1, + W6_INT_BIT_SLEEP_VPU = 2, + W6_INT_BIT_CREATE_INSTANCE = 3, + W6_INT_BIT_FLUSH_INSTANCE = 4, + W6_INT_BIT_DESTROY_INSTANCE = 5, + W6_INT_BIT_INIT_SEQ = 6, + W6_INT_BIT_SET_FB = 7, + W6_INT_BIT_DEC_PIC = 8, + W6_INT_BIT_ENC_PIC = 8, + W6_INT_BIT_ENC_SET_PARAM = 9, + W6_INT_BIT_SET_DISP = 10, + W6_INT_BIT_REQ_WORK_BUF = 12, + W6_INT_BIT_BSBUF_ERROR = 15, +}; + +enum wave6_param_change_enable_bit { + W6_PARAM_CHANGE_ENABLE_BIT_RC_TARGET_RATE = 10 +}; + +#define W6_REG_BASE 0x00000000 +#define W6_CMD_REG_BASE 0x00000200 +#define W6_CMD_REG_END 0x00000600 + +#define W6_VPU_VCPU_CUR_PC (W6_REG_BASE + 0x0004) +#define W6_VPU_VINT_REASON_CLR (W6_REG_BASE + 0x0034) +#define W6_VPU_HOST_INT_REQ (W6_REG_BASE + 0x0038) +#define W6_VPU_VINT_CLEAR (W6_REG_BASE + 0x003C) +#define W6_VPU_VPU_INT_STS (W6_REG_BASE + 0x0044) +#define W6_VPU_VINT_ENABLE (W6_REG_BASE + 0x0048) +#define W6_VPU_VINT_REASON (W6_REG_BASE + 0x004C) +#define W6_VPU_REMAP_CTRL_GB (W6_REG_BASE + 0x0060) +#define W6_VPU_REMAP_VADDR_GB (W6_REG_BASE + 0x0064) +#define W6_VPU_REMAP_PADDR_GB (W6_REG_BASE + 0x0068) +#define W6_VPU_REMAP_CORE_START_GB (W6_REG_BASE + 0x006C) +#define W6_VPU_BUSY_STATUS (W6_REG_BASE + 0x0070) +#define W6_VPU_RET_PRODUCT_VERSION (W6_REG_BASE + 0x0094) + +/* COMMON */ +#define W6_COMMAND_GB (W6_REG_BASE + 0x104) +#define W6_COMMAND (W6_REG_BASE + 0x200) +#define W6_QUERY_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_INSTANCE_INFO (W6_REG_BASE + 0x210) +#define W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0 (W6_REG_BASE + 0x364) +#define W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0 (W6_REG_BASE + 0x368) +#define W6_CMD_SET_CTRL_WORK_BUF_ADDR (W6_REG_BASE + 0x5F0) +#define W6_CMD_SET_CTRL_WORK_BUF_SIZE (W6_REG_BASE + 0x5F4) +#define W6_RET_SUCCESS (W6_REG_BASE + 0x208) +#define W6_RET_FAIL_REASON (W6_REG_BASE + 0x20C) +#define W6_RET_INSTANCE_ID (W6_REG_BASE + 0x220) +#define W6_RET_CQ_IN_TICK (W6_REG_BASE + 0x23C) +#define W6_RET_FW_RUN_TICK (W6_REG_BASE + 0x240) +#define W6_RET_HW_RUN_TICK (W6_REG_BASE + 0x244) +#define W6_RET_HW_DONE_TICK (W6_REG_BASE + 0x248) +#define W6_RET_FW_DONE_TICK (W6_REG_BASE + 0x24C) +#define W6_RET_RQ_OUT_TICK (W6_REG_BASE + 0x250) + +/* COMMON - QUERY : GET_VPU_INFO */ +#define W6_RET_FW_VERSION (W6_REG_BASE + 0x300) +#define W6_RET_PRODUCT_NAME (W6_REG_BASE + 0x304) +#define W6_RET_PRODUCT_VERSION (W6_REG_BASE + 0x308) +#define W6_RET_STD_DEF0 (W6_REG_BASE + 0x30C) +#define W6_RET_STD_DEF1 (W6_REG_BASE + 0x310) +#define W6_RET_CONF_FEATURE (W6_REG_BASE + 0x314) +#define W6_RET_CONF_DATE (W6_REG_BASE + 0x318) +#define W6_RET_CONF_REVISION (W6_REG_BASE + 0x31C) +#define W6_RET_CONF_TYPE (W6_REG_BASE + 0x320) +#define W6_RET_FW_API_VERSION (W6_REG_BASE + 0x32C) +#define W6_RET_SHA_ID (W6_REG_BASE + 0x330) + +/* DECODER - CREATE_INSTANCE */ +#define W6_CMD_DEC_CREATE_INST_BS_PARAM (W6_REG_BASE + 0x310) +#define W6_CMD_DEC_CREATE_INST_ADDR_EXT (W6_REG_BASE + 0x318) +#define W6_CMD_DEC_CREATE_INST_DISP_MODE (W6_REG_BASE + 0x31C) +#define W6_CMD_DEC_CREATE_INST_CORE_INFO (W6_REG_BASE + 0x330) +#define W6_CMD_DEC_CREATE_INST_PRIORITY (W6_REG_BASE + 0x334) +#define W6_CMD_DEC_CREATE_INST_TEMP_BASE (W6_REG_BASE + 0x348) +#define W6_CMD_DEC_CREATE_INST_TEMP_SIZE (W6_REG_BASE + 0x34C) +#define W6_CMD_DEC_CREATE_INST_TIMEOUT_CYCLE_COUNT (W6_REG_BASE + 0x3A8) + +/* DECODER - INIT_SEQ */ +#define W6_CMD_DEC_INIT_SEQ_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_DEC_INIT_SEQ_BS_RD_PTR (W6_REG_BASE + 0x300) +#define W6_CMD_DEC_INIT_SEQ_BS_WR_PTR (W6_REG_BASE + 0x304) +#define W6_CMD_DEC_INIT_SEQ_BS_OPTION (W6_REG_BASE + 0x308) + +/* DECODER - SET_FB */ +#define W6_CMD_DEC_SET_FB_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_DEC_SET_FB_COMMON_PIC_INFO (W6_REG_BASE + 0x300) +#define W6_CMD_DEC_SET_FB_PIC_SIZE (W6_REG_BASE + 0x304) +#define W6_CMD_DEC_SET_FB_NUM (W6_REG_BASE + 0x308) +#define W6_CMD_DEC_SET_FB_FBC_Y0 (W6_REG_BASE + 0x310) +#define W6_CMD_DEC_SET_FB_FBC_C0 (W6_REG_BASE + 0x314) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET0 (W6_REG_BASE + 0x318) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET0 (W6_REG_BASE + 0x31C) +#define W6_CMD_DEC_SET_FB_MV_COL0 (W6_REG_BASE + 0x320) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED0 (W6_REG_BASE + 0x324) +#define W6_CMD_DEC_SET_FB_FBC_Y1 (W6_REG_BASE + 0x328) +#define W6_CMD_DEC_SET_FB_FBC_C1 (W6_REG_BASE + 0x32C) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET1 (W6_REG_BASE + 0x330) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET1 (W6_REG_BASE + 0x334) +#define W6_CMD_DEC_SET_FB_MV_COL1 (W6_REG_BASE + 0x338) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED1 (W6_REG_BASE + 0x33C) +#define W6_CMD_DEC_SET_FB_FBC_Y2 (W6_REG_BASE + 0x340) +#define W6_CMD_DEC_SET_FB_FBC_C2 (W6_REG_BASE + 0x344) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET2 (W6_REG_BASE + 0x348) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET2 (W6_REG_BASE + 0x34C) +#define W6_CMD_DEC_SET_FB_MV_COL2 (W6_REG_BASE + 0x350) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED2 (W6_REG_BASE + 0x354) +#define W6_CMD_DEC_SET_FB_FBC_Y3 (W6_REG_BASE + 0x358) +#define W6_CMD_DEC_SET_FB_FBC_C3 (W6_REG_BASE + 0x35C) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET3 (W6_REG_BASE + 0x360) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET3 (W6_REG_BASE + 0x364) +#define W6_CMD_DEC_SET_FB_MV_COL3 (W6_REG_BASE + 0x368) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED3 (W6_REG_BASE + 0x36C) +#define W6_CMD_DEC_SET_FB_FBC_Y4 (W6_REG_BASE + 0x370) +#define W6_CMD_DEC_SET_FB_FBC_C4 (W6_REG_BASE + 0x374) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET4 (W6_REG_BASE + 0x378) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET4 (W6_REG_BASE + 0x37C) +#define W6_CMD_DEC_SET_FB_MV_COL4 (W6_REG_BASE + 0x380) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED4 (W6_REG_BASE + 0x384) +#define W6_CMD_DEC_SET_FB_FBC_Y5 (W6_REG_BASE + 0x388) +#define W6_CMD_DEC_SET_FB_FBC_C5 (W6_REG_BASE + 0x38C) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET5 (W6_REG_BASE + 0x390) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET5 (W6_REG_BASE + 0x394) +#define W6_CMD_DEC_SET_FB_MV_COL5 (W6_REG_BASE + 0x398) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED5 (W6_REG_BASE + 0x39C) +#define W6_CMD_DEC_SET_FB_FBC_Y6 (W6_REG_BASE + 0x3A0) +#define W6_CMD_DEC_SET_FB_FBC_C6 (W6_REG_BASE + 0x3A4) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET6 (W6_REG_BASE + 0x3A8) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET6 (W6_REG_BASE + 0x3AC) +#define W6_CMD_DEC_SET_FB_MV_COL6 (W6_REG_BASE + 0x3B0) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED6 (W6_REG_BASE + 0x3B4) +#define W6_CMD_DEC_SET_FB_FBC_Y7 (W6_REG_BASE + 0x3B8) +#define W6_CMD_DEC_SET_FB_FBC_C7 (W6_REG_BASE + 0x3BC) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET7 (W6_REG_BASE + 0x3C0) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET7 (W6_REG_BASE + 0x3C4) +#define W6_CMD_DEC_SET_FB_MV_COL7 (W6_REG_BASE + 0x3C8) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED7 (W6_REG_BASE + 0x3CC) +#define W6_CMD_DEC_SET_FB_FBC_Y8 (W6_REG_BASE + 0x3D0) +#define W6_CMD_DEC_SET_FB_FBC_C8 (W6_REG_BASE + 0x3D4) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET8 (W6_REG_BASE + 0x3D8) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET8 (W6_REG_BASE + 0x3DC) +#define W6_CMD_DEC_SET_FB_MV_COL8 (W6_REG_BASE + 0x3E0) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED8 (W6_REG_BASE + 0x3E4) +#define W6_CMD_DEC_SET_FB_FBC_Y9 (W6_REG_BASE + 0x3E8) +#define W6_CMD_DEC_SET_FB_FBC_C9 (W6_REG_BASE + 0x3EC) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET9 (W6_REG_BASE + 0x3F0) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET9 (W6_REG_BASE + 0x3F4) +#define W6_CMD_DEC_SET_FB_MV_COL9 (W6_REG_BASE + 0x3F8) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED9 (W6_REG_BASE + 0x3FC) +#define W6_CMD_DEC_SET_FB_FBC_Y10 (W6_REG_BASE + 0x400) +#define W6_CMD_DEC_SET_FB_FBC_C10 (W6_REG_BASE + 0x404) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET10 (W6_REG_BASE + 0x408) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET10 (W6_REG_BASE + 0x40C) +#define W6_CMD_DEC_SET_FB_MV_COL10 (W6_REG_BASE + 0x410) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED10 (W6_REG_BASE + 0x414) +#define W6_CMD_DEC_SET_FB_FBC_Y11 (W6_REG_BASE + 0x418) +#define W6_CMD_DEC_SET_FB_FBC_C11 (W6_REG_BASE + 0x41C) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET11 (W6_REG_BASE + 0x420) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET11 (W6_REG_BASE + 0x424) +#define W6_CMD_DEC_SET_FB_MV_COL11 (W6_REG_BASE + 0x428) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED11 (W6_REG_BASE + 0x42C) +#define W6_CMD_DEC_SET_FB_FBC_Y12 (W6_REG_BASE + 0x430) +#define W6_CMD_DEC_SET_FB_FBC_C12 (W6_REG_BASE + 0x434) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET12 (W6_REG_BASE + 0x438) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET12 (W6_REG_BASE + 0x43C) +#define W6_CMD_DEC_SET_FB_MV_COL12 (W6_REG_BASE + 0x440) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED12 (W6_REG_BASE + 0x444) +#define W6_CMD_DEC_SET_FB_FBC_Y13 (W6_REG_BASE + 0x448) +#define W6_CMD_DEC_SET_FB_FBC_C13 (W6_REG_BASE + 0x44C) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET13 (W6_REG_BASE + 0x450) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET13 (W6_REG_BASE + 0x454) +#define W6_CMD_DEC_SET_FB_MV_COL13 (W6_REG_BASE + 0x458) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED13 (W6_REG_BASE + 0x45C) +#define W6_CMD_DEC_SET_FB_FBC_Y14 (W6_REG_BASE + 0x460) +#define W6_CMD_DEC_SET_FB_FBC_C14 (W6_REG_BASE + 0x464) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET14 (W6_REG_BASE + 0x468) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET14 (W6_REG_BASE + 0x46C) +#define W6_CMD_DEC_SET_FB_MV_COL14 (W6_REG_BASE + 0x470) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED14 (W6_REG_BASE + 0x474) +#define W6_CMD_DEC_SET_FB_FBC_Y15 (W6_REG_BASE + 0x478) +#define W6_CMD_DEC_SET_FB_FBC_C15 (W6_REG_BASE + 0x47C) +#define W6_CMD_DEC_SET_FB_FBC_Y_OFFSET15 (W6_REG_BASE + 0x480) +#define W6_CMD_DEC_SET_FB_FBC_C_OFFSET15 (W6_REG_BASE + 0x484) +#define W6_CMD_DEC_SET_FB_MV_COL15 (W6_REG_BASE + 0x488) +#define W6_CMD_DEC_SET_FB_SUB_SAMPLED15 (W6_REG_BASE + 0x48C) +#define W6_CMD_DEC_SET_FB_DEFAULT_CDF (W6_REG_BASE + 0x494) +#define W6_CMD_DEC_SET_FB_SEGMAP (W6_REG_BASE + 0x498) +#define W6_CMD_DEC_SET_FB_MV_COL_PRE_ENT (W6_REG_BASE + 0x4DC) +#define W6_CMD_DEC_SET_FB_FBC_CR0 (W6_REG_BASE + 0x4F0) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET0 (W6_REG_BASE + 0x4F4) +#define W6_CMD_DEC_SET_FB_FBC_CR1 (W6_REG_BASE + 0x4F8) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET1 (W6_REG_BASE + 0x4FC) +#define W6_CMD_DEC_SET_FB_FBC_CR2 (W6_REG_BASE + 0x500) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET2 (W6_REG_BASE + 0x504) +#define W6_CMD_DEC_SET_FB_FBC_CR3 (W6_REG_BASE + 0x508) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET3 (W6_REG_BASE + 0x50C) +#define W6_CMD_DEC_SET_FB_FBC_CR4 (W6_REG_BASE + 0x510) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET4 (W6_REG_BASE + 0x514) +#define W6_CMD_DEC_SET_FB_FBC_CR5 (W6_REG_BASE + 0x518) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET5 (W6_REG_BASE + 0x51C) +#define W6_CMD_DEC_SET_FB_FBC_CR6 (W6_REG_BASE + 0x520) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET6 (W6_REG_BASE + 0x524) +#define W6_CMD_DEC_SET_FB_FBC_CR7 (W6_REG_BASE + 0x528) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET7 (W6_REG_BASE + 0x52C) +#define W6_CMD_DEC_SET_FB_FBC_CR8 (W6_REG_BASE + 0x530) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET8 (W6_REG_BASE + 0x534) +#define W6_CMD_DEC_SET_FB_FBC_CR9 (W6_REG_BASE + 0x538) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET9 (W6_REG_BASE + 0x53C) +#define W6_CMD_DEC_SET_FB_FBC_CR10 (W6_REG_BASE + 0x540) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET10 (W6_REG_BASE + 0x544) +#define W6_CMD_DEC_SET_FB_FBC_CR11 (W6_REG_BASE + 0x548) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET11 (W6_REG_BASE + 0x54C) +#define W6_CMD_DEC_SET_FB_FBC_CR12 (W6_REG_BASE + 0x550) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET12 (W6_REG_BASE + 0x554) +#define W6_CMD_DEC_SET_FB_FBC_CR13 (W6_REG_BASE + 0x558) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET13 (W6_REG_BASE + 0x55C) +#define W6_CMD_DEC_SET_FB_FBC_CR14 (W6_REG_BASE + 0x560) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET14 (W6_REG_BASE + 0x564) +#define W6_CMD_DEC_SET_FB_FBC_CR15 (W6_REG_BASE + 0x568) +#define W6_CMD_DEC_SET_FB_FBC_CR_OFFSET15 (W6_REG_BASE + 0x56C) + +/* DECODER - SET_DISP */ +#define W6_CMD_DEC_SET_DISP_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_DEC_SET_DISP_COMMON_PIC_INFO (W6_REG_BASE + 0x300) +#define W6_CMD_DEC_SET_DISP_PIC_SIZE (W6_REG_BASE + 0x304) +#define W6_CMD_DEC_SET_DISP_PIC_INFO (W6_REG_BASE + 0x308) +#define W6_CMD_DEC_SET_DISP_Y_BASE (W6_REG_BASE + 0x30C) +#define W6_CMD_DEC_SET_DISP_CB_BASE (W6_REG_BASE + 0x310) +#define W6_CMD_DEC_SET_DISP_CR_BASE (W6_REG_BASE + 0x314) +#define W6_CMD_DEC_SET_DISP_SCL_PARAM (W6_REG_BASE + 0x318) +#define W6_CMD_DEC_SET_DISP_SCL_PIC_SIZE (W6_REG_BASE + 0x31C) + +/* DECODER - DEC_PIC */ +#define W6_CMD_DEC_PIC_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_DEC_PIC_BS_RD_PTR (W6_REG_BASE + 0x300) +#define W6_CMD_DEC_PIC_BS_WR_PTR (W6_REG_BASE + 0x304) +#define W6_CMD_DEC_PIC_BS_OPTION (W6_REG_BASE + 0x308) +#define W6_CMD_DEC_PIC_USE_SEC_AXI (W6_REG_BASE + 0x30C) +#define W6_CMD_DEC_PIC_SEQ_CHANGE_ENABLE_FLAG (W6_REG_BASE + 0x310) +#define W6_CMD_DEC_PIC_TEMPORAL_ID_PLUS1 (W6_REG_BASE + 0x318) +#define W6_CMD_DEC_PIC_TIMESTAMP (W6_REG_BASE + 0x32C) + +/* DECODER - QUERY : GET_RESULT */ +#define W6_RET_DEC_BS_RD_PTR (W6_REG_BASE + 0x30C) +#define W6_RET_DEC_SEQ_PARAM (W6_REG_BASE + 0x310) +#define W6_RET_DEC_COLOR_SAMPLE_INFO (W6_REG_BASE + 0x314) +#define W6_RET_DEC_ASPECT_RATIO (W6_REG_BASE + 0x318) +#define W6_RET_DEC_BIT_RATE (W6_REG_BASE + 0x31C) +#define W6_RET_DEC_FRAME_RATE_NR (W6_REG_BASE + 0x320) +#define W6_RET_DEC_FRAME_RATE_DR (W6_REG_BASE + 0x324) +#define W6_RET_DEC_NUM_REQUIRED_FBC_FB (W6_REG_BASE + 0x328) +#define W6_RET_DEC_NUM_REORDER_DELAY (W6_REG_BASE + 0x32C) +#define W6_RET_DEC_NOTIFICATION (W6_REG_BASE + 0x334) +#define W6_RET_DEC_PIC_SIZE (W6_REG_BASE + 0x33C) +#define W6_RET_DEC_CROP_TOP_BOTTOM (W6_REG_BASE + 0x340) +#define W6_RET_DEC_CROP_LEFT_RIGHT (W6_REG_BASE + 0x344) +#define W6_RET_DEC_AU_START_POS (W6_REG_BASE + 0x348) +#define W6_RET_DEC_AU_END_POS (W6_REG_BASE + 0x34C) +#define W6_RET_DEC_PIC_TYPE (W6_REG_BASE + 0x350) +#define W6_RET_DEC_PIC_POC (W6_REG_BASE + 0x354) +#define W6_RET_DEC_RECOVERY_POINT (W6_REG_BASE + 0x358) +#define W6_RET_DEC_DECODED_ADDR (W6_REG_BASE + 0x360) +#define W6_RET_DEC_DISPLAY_ADDR (W6_REG_BASE + 0x364) +#define W6_RET_DEC_ERR_CTB_NUM (W6_REG_BASE + 0x370) +#define W6_RET_DEC_DISPLAY_FLAG (W6_REG_BASE + 0x3A8) +#define W6_RET_DEC_RELEASE_IDC (W6_REG_BASE + 0x3AC) +#define W6_RET_DEC_DISP_IDC (W6_REG_BASE + 0x3B0) +#define W6_RET_DEC_STREAM_END (W6_REG_BASE + 0x3C0) +#define W6_RET_DEC_DECODED_FLAG (W6_REG_BASE + 0x3C4) +#define W6_RET_DEC_WARN_INFO (W6_REG_BASE + 0x3CC) +#define W6_RET_DEC_ERR_INFO (W6_REG_BASE + 0x3D0) +#define W6_RET_DEC_DECODING_SUCCESS (W6_REG_BASE + 0x3D4) +#define W6_RET_DEC_TIMESTAMP (W6_REG_BASE + 0x3D8) +#define W6_RET_DEC_LAST_FRAME_FLAG (W6_REG_BASE + 0x3E0) +#define W6_RET_DEC_NUM_REQUIRED_COL_BUF (W6_REG_BASE + 0x3E4) +#define W6_RET_DEC_DISP_LINEAR_ADDR_0 (W6_REG_BASE + 0x3E8) +#define W6_RET_DEC_DISP_LINEAR_ADDR_30 (W6_REG_BASE + 0x460) +#define W6_RET_DEC_COLOR_CONFIG (W6_REG_BASE + 0x57C) + +/* DECODER - QUERY : GET_FLUSH_CMD_INFO */ +#define W6_RET_DEC_FLUSH_CMD_DISP_ADDR_0 (W6_REG_BASE + 0x300) +#define W6_RET_DEC_FLUSH_CMD_DISP_ADDR_1E (W6_REG_BASE + 0x378) +#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_UNUSED_IDC (W6_REG_BASE + 0x57C) +#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_USED_IDC (W6_REG_BASE + 0x580) +#define W6_RET_DEC_FLUSH_CMD_BUF_STATE_USING_IDC (W6_REG_BASE + 0x584) + +/* ENCODER - CREATE_INSTANCE */ +#define W6_CMD_ENC_CREATE_INST_BS_PARAM (W6_REG_BASE + 0x310) +#define W6_CMD_ENC_CREATE_INST_SRC_OPT (W6_REG_BASE + 0x314) +#define W6_CMD_ENC_CREATE_INST_ADDR_EXT (W6_REG_BASE + 0x318) +#define W6_CMD_ENC_CREATE_INST_CORE_INFO (W6_REG_BASE + 0x330) +#define W6_CMD_ENC_CREATE_INST_PRIORITY (W6_REG_BASE + 0x334) +#define W6_CMD_ENC_CREATE_INST_TEMP_BASE (W6_REG_BASE + 0x348) +#define W6_CMD_ENC_CREATE_INST_TEMP_SIZE (W6_REG_BASE + 0x34C) +#define W6_CMD_ENC_CREATE_INST_AR_TABLE_BASE (W6_REG_BASE + 0x358) +#define W6_CMD_ENC_CREATE_INST_TIMEOUT_CYCLE_COUNT (W6_REG_BASE + 0x3A8) + +/* ENCODER - SET_PARAM */ +#define W6_CMD_ENC_SET_PARAM_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_ENC_SET_PARAM_ENABLE (W6_REG_BASE + 0x300) +#define W6_CMD_ENC_SET_PARAM_SRC_SIZE (W6_REG_BASE + 0x304) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_MAP_ENDIAN (W6_REG_BASE + 0x308) +#define W6_CMD_ENC_SET_PARAM_SPS_PARAM (W6_REG_BASE + 0x30C) +#define W6_CMD_ENC_SET_PARAM_PPS_PARAM (W6_REG_BASE + 0x310) +#define W6_CMD_ENC_SET_PARAM_GOP_PARAM (W6_REG_BASE + 0x314) +#define W6_CMD_ENC_SET_PARAM_INTRA_PARAM (W6_REG_BASE + 0x318) +#define W6_CMD_ENC_SET_PARAM_CONF_WIN_TOP_BOT (W6_REG_BASE + 0x31C) +#define W6_CMD_ENC_SET_PARAM_CONF_WIN_LEFT_RIGHT (W6_REG_BASE + 0x320) +#define W6_CMD_ENC_SET_PARAM_RDO_PARAM (W6_REG_BASE + 0x324) +#define W6_CMD_ENC_SET_PARAM_SLICE_PARAM (W6_REG_BASE + 0x328) +#define W6_CMD_ENC_SET_PARAM_INTRA_REFRESH (W6_REG_BASE + 0x32C) +#define W6_CMD_ENC_SET_PARAM_INTRA_MIN_MAX_QP (W6_REG_BASE + 0x330) +#define W6_CMD_ENC_SET_PARAM_RC_FRAME_RATE (W6_REG_BASE + 0x334) +#define W6_CMD_ENC_SET_PARAM_RC_TARGET_RATE (W6_REG_BASE + 0x338) +#define W6_CMD_ENC_SET_PARAM_RC_PARAM (W6_REG_BASE + 0x33C) +#define W6_CMD_ENC_SET_PARAM_HVS_PARAM (W6_REG_BASE + 0x340) +#define W6_CMD_ENC_SET_PARAM_RC_MAX_BITRATE (W6_REG_BASE + 0x344) +#define W6_CMD_ENC_SET_PARAM_RC_VBV_BUFFER_SIZE (W6_REG_BASE + 0x348) +#define W6_CMD_ENC_SET_PARAM_INTER_MIN_MAX_QP (W6_REG_BASE + 0x34C) +#define W6_CMD_ENC_SET_PARAM_ROT_PARAM (W6_REG_BASE + 0x350) +#define W6_CMD_ENC_SET_PARAM_NUM_UNITS_IN_TICK (W6_REG_BASE + 0x354) +#define W6_CMD_ENC_SET_PARAM_TIME_SCALE (W6_REG_BASE + 0x358) +#define W6_CMD_ENC_SET_PARAM_NUM_TICKS_POC_DIFF_ONE (W6_REG_BASE + 0x35C) +#define W6_CMD_ENC_SET_PARAM_MAX_INTRA_PIC_BIT (W6_REG_BASE + 0x360) +#define W6_CMD_ENC_SET_PARAM_MAX_INTER_PIC_BIT (W6_REG_BASE + 0x364) +#define W6_CMD_ENC_SET_PARAM_BG_PARAM (W6_REG_BASE + 0x36C) +#define W6_CMD_ENC_SET_PARAM_NON_VCL_PARAM (W6_REG_BASE + 0x370) +#define W6_CMD_ENC_SET_PARAM_VUI_RBSP_ADDR (W6_REG_BASE + 0x374) +#define W6_CMD_ENC_SET_PARAM_HRD_RBSP_ADDR (W6_REG_BASE + 0x378) +#define W6_CMD_ENC_SET_PARAM_QROUND_OFFSET (W6_REG_BASE + 0x380) +#define W6_CMD_ENC_SET_PARAM_QUANT_PARAM_1 (W6_REG_BASE + 0x384) +#define W6_CMD_ENC_SET_PARAM_QUANT_PARAM_2 (W6_REG_BASE + 0x388) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PARAM (W6_REG_BASE + 0x38C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_0 (W6_REG_BASE + 0x390) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_1 (W6_REG_BASE + 0x394) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_2 (W6_REG_BASE + 0x398) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_3 (W6_REG_BASE + 0x39C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_4 (W6_REG_BASE + 0x3A0) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_5 (W6_REG_BASE + 0x3A4) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_6 (W6_REG_BASE + 0x3A8) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_GOP_PIC_PARAM_7 (W6_REG_BASE + 0x3AC) +#define W6_CMD_ENC_SET_PARAM_TILE_PARAM (W6_REG_BASE + 0x3D0) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_0 (W6_REG_BASE + 0x3D4) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_1 (W6_REG_BASE + 0x3D8) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_2 (W6_REG_BASE + 0x3DC) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_3 (W6_REG_BASE + 0x3E0) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_4 (W6_REG_BASE + 0x3E4) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_5 (W6_REG_BASE + 0x3E8) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_6 (W6_REG_BASE + 0x3EC) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_7 (W6_REG_BASE + 0x3F0) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_8 (W6_REG_BASE + 0x3F4) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_9 (W6_REG_BASE + 0x3F8) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_10 (W6_REG_BASE + 0x3FC) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_11 (W6_REG_BASE + 0x400) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_12 (W6_REG_BASE + 0x404) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_13 (W6_REG_BASE + 0x408) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_14 (W6_REG_BASE + 0x40C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_15 (W6_REG_BASE + 0x410) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_16 (W6_REG_BASE + 0x414) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_17 (W6_REG_BASE + 0x418) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_18 (W6_REG_BASE + 0x41C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_19 (W6_REG_BASE + 0x420) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_20 (W6_REG_BASE + 0x424) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_21 (W6_REG_BASE + 0x428) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_22 (W6_REG_BASE + 0x42C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_23 (W6_REG_BASE + 0x430) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_24 (W6_REG_BASE + 0x434) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_25 (W6_REG_BASE + 0x438) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_26 (W6_REG_BASE + 0x43C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_27 (W6_REG_BASE + 0x440) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_28 (W6_REG_BASE + 0x444) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_29 (W6_REG_BASE + 0x448) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_30 (W6_REG_BASE + 0x44C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_31 (W6_REG_BASE + 0x450) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_32 (W6_REG_BASE + 0x454) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_33 (W6_REG_BASE + 0x458) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_34 (W6_REG_BASE + 0x45C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_35 (W6_REG_BASE + 0x460) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_36 (W6_REG_BASE + 0x464) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_37 (W6_REG_BASE + 0x468) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_38 (W6_REG_BASE + 0x46C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_39 (W6_REG_BASE + 0x470) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_40 (W6_REG_BASE + 0x474) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_41 (W6_REG_BASE + 0x478) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_42 (W6_REG_BASE + 0x47C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_43 (W6_REG_BASE + 0x480) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_44 (W6_REG_BASE + 0x484) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_45 (W6_REG_BASE + 0x488) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_46 (W6_REG_BASE + 0x48C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_47 (W6_REG_BASE + 0x490) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_48 (W6_REG_BASE + 0x494) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_49 (W6_REG_BASE + 0x498) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_50 (W6_REG_BASE + 0x49C) +#define W6_CMD_ENC_SET_PARAM_CUSTOM_LAMBDA_51 (W6_REG_BASE + 0x4A0) +#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_0_QP (W6_REG_BASE + 0x4A4) +#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_1_QP (W6_REG_BASE + 0x4A8) +#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_2_QP (W6_REG_BASE + 0x4AC) +#define W6_CMD_ENC_SET_PARAM_TEMPORAL_LAYER_3_QP (W6_REG_BASE + 0x4B0) +#define W6_CMD_ENC_SET_PARAM_SCL_SRC_SIZE (W6_REG_BASE + 0x4B4) +#define W6_CMD_ENC_SET_PARAM_SCL_PARAM (W6_REG_BASE + 0x4B8) +#define W6_CMD_ENC_SET_PARAM_COLOR_PARAM (W6_REG_BASE + 0x4F8) +#define W6_CMD_ENC_SET_PARAM_SAR_PARAM (W6_REG_BASE + 0x4FC) +#define W6_CMD_ENC_SET_PARAM_SAR_EXTENDED (W6_REG_BASE + 0x500) + +/* ENCODER - SET_FB */ +#define W6_CMD_ENC_SET_FB_OPTION (W6_REG_BASE + 0x204) +#define W6_CMD_ENC_SET_FB_PIC_INFO (W6_REG_BASE + 0x300) +#define W6_CMD_ENC_SET_FB_PIC_SIZE (W6_REG_BASE + 0x304) +#define W6_CMD_ENC_SET_FB_NUM (W6_REG_BASE + 0x308) +#define W6_CMD_ENC_SET_FB_FBC_STRIDE (W6_REG_BASE + 0x30C) +#define W6_CMD_ENC_SET_FB_FBC_Y0 (W6_REG_BASE + 0x310) +#define W6_CMD_ENC_SET_FB_FBC_C0 (W6_REG_BASE + 0x314) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET0 (W6_REG_BASE + 0x318) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET0 (W6_REG_BASE + 0x31C) +#define W6_CMD_ENC_SET_FB_MV_COL0 (W6_REG_BASE + 0x320) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED0 (W6_REG_BASE + 0x324) +#define W6_CMD_ENC_SET_FB_FBC_Y1 (W6_REG_BASE + 0x328) +#define W6_CMD_ENC_SET_FB_FBC_C1 (W6_REG_BASE + 0x32C) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET1 (W6_REG_BASE + 0x330) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET1 (W6_REG_BASE + 0x334) +#define W6_CMD_ENC_SET_FB_MV_COL1 (W6_REG_BASE + 0x338) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED1 (W6_REG_BASE + 0x33C) +#define W6_CMD_ENC_SET_FB_FBC_Y2 (W6_REG_BASE + 0x340) +#define W6_CMD_ENC_SET_FB_FBC_C2 (W6_REG_BASE + 0x344) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET2 (W6_REG_BASE + 0x348) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET2 (W6_REG_BASE + 0x34C) +#define W6_CMD_ENC_SET_FB_MV_COL2 (W6_REG_BASE + 0x350) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED2 (W6_REG_BASE + 0x354) +#define W6_CMD_ENC_SET_FB_FBC_Y3 (W6_REG_BASE + 0x358) +#define W6_CMD_ENC_SET_FB_FBC_C3 (W6_REG_BASE + 0x35C) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET3 (W6_REG_BASE + 0x360) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET3 (W6_REG_BASE + 0x364) +#define W6_CMD_ENC_SET_FB_MV_COL3 (W6_REG_BASE + 0x368) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED3 (W6_REG_BASE + 0x36C) +#define W6_CMD_ENC_SET_FB_FBC_Y4 (W6_REG_BASE + 0x370) +#define W6_CMD_ENC_SET_FB_FBC_C4 (W6_REG_BASE + 0x374) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET4 (W6_REG_BASE + 0x378) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET4 (W6_REG_BASE + 0x37C) +#define W6_CMD_ENC_SET_FB_MV_COL4 (W6_REG_BASE + 0x380) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED4 (W6_REG_BASE + 0x384) +#define W6_CMD_ENC_SET_FB_FBC_Y5 (W6_REG_BASE + 0x388) +#define W6_CMD_ENC_SET_FB_FBC_C5 (W6_REG_BASE + 0x38C) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET5 (W6_REG_BASE + 0x390) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET5 (W6_REG_BASE + 0x394) +#define W6_CMD_ENC_SET_FB_MV_COL5 (W6_REG_BASE + 0x398) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED5 (W6_REG_BASE + 0x39C) +#define W6_CMD_ENC_SET_FB_FBC_Y6 (W6_REG_BASE + 0x3A0) +#define W6_CMD_ENC_SET_FB_FBC_C6 (W6_REG_BASE + 0x3A4) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET6 (W6_REG_BASE + 0x3A8) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET6 (W6_REG_BASE + 0x3AC) +#define W6_CMD_ENC_SET_FB_MV_COL6 (W6_REG_BASE + 0x3B0) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED6 (W6_REG_BASE + 0x3B4) +#define W6_CMD_ENC_SET_FB_FBC_Y7 (W6_REG_BASE + 0x3B8) +#define W6_CMD_ENC_SET_FB_FBC_C7 (W6_REG_BASE + 0x3BC) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET7 (W6_REG_BASE + 0x3C0) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET7 (W6_REG_BASE + 0x3C4) +#define W6_CMD_ENC_SET_FB_MV_COL7 (W6_REG_BASE + 0x3C8) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED7 (W6_REG_BASE + 0x3CC) +#define W6_CMD_ENC_SET_FB_FBC_Y8 (W6_REG_BASE + 0x3D0) +#define W6_CMD_ENC_SET_FB_FBC_C8 (W6_REG_BASE + 0x3D4) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET8 (W6_REG_BASE + 0x3D8) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET8 (W6_REG_BASE + 0x3DC) +#define W6_CMD_ENC_SET_FB_MV_COL8 (W6_REG_BASE + 0x3E0) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED8 (W6_REG_BASE + 0x3E4) +#define W6_CMD_ENC_SET_FB_FBC_Y9 (W6_REG_BASE + 0x3E8) +#define W6_CMD_ENC_SET_FB_FBC_C9 (W6_REG_BASE + 0x3EC) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET9 (W6_REG_BASE + 0x3F0) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET9 (W6_REG_BASE + 0x3F4) +#define W6_CMD_ENC_SET_FB_MV_COL9 (W6_REG_BASE + 0x3F8) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED9 (W6_REG_BASE + 0x3FC) +#define W6_CMD_ENC_SET_FB_FBC_Y10 (W6_REG_BASE + 0x400) +#define W6_CMD_ENC_SET_FB_FBC_C10 (W6_REG_BASE + 0x404) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET10 (W6_REG_BASE + 0x408) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET10 (W6_REG_BASE + 0x40C) +#define W6_CMD_ENC_SET_FB_MV_COL10 (W6_REG_BASE + 0x410) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED10 (W6_REG_BASE + 0x414) +#define W6_CMD_ENC_SET_FB_FBC_Y11 (W6_REG_BASE + 0x418) +#define W6_CMD_ENC_SET_FB_FBC_C11 (W6_REG_BASE + 0x41C) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET11 (W6_REG_BASE + 0x420) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET11 (W6_REG_BASE + 0x424) +#define W6_CMD_ENC_SET_FB_MV_COL11 (W6_REG_BASE + 0x428) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED11 (W6_REG_BASE + 0x42C) +#define W6_CMD_ENC_SET_FB_FBC_Y12 (W6_REG_BASE + 0x430) +#define W6_CMD_ENC_SET_FB_FBC_C12 (W6_REG_BASE + 0x434) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET12 (W6_REG_BASE + 0x438) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET12 (W6_REG_BASE + 0x43C) +#define W6_CMD_ENC_SET_FB_MV_COL12 (W6_REG_BASE + 0x440) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED12 (W6_REG_BASE + 0x444) +#define W6_CMD_ENC_SET_FB_FBC_Y13 (W6_REG_BASE + 0x448) +#define W6_CMD_ENC_SET_FB_FBC_C13 (W6_REG_BASE + 0x44C) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET13 (W6_REG_BASE + 0x450) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET13 (W6_REG_BASE + 0x454) +#define W6_CMD_ENC_SET_FB_MV_COL13 (W6_REG_BASE + 0x458) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED13 (W6_REG_BASE + 0x45C) +#define W6_CMD_ENC_SET_FB_FBC_Y14 (W6_REG_BASE + 0x460) +#define W6_CMD_ENC_SET_FB_FBC_C14 (W6_REG_BASE + 0x464) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET14 (W6_REG_BASE + 0x468) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET14 (W6_REG_BASE + 0x46C) +#define W6_CMD_ENC_SET_FB_MV_COL14 (W6_REG_BASE + 0x470) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED14 (W6_REG_BASE + 0x474) +#define W6_CMD_ENC_SET_FB_FBC_Y15 (W6_REG_BASE + 0x478) +#define W6_CMD_ENC_SET_FB_FBC_C15 (W6_REG_BASE + 0x47C) +#define W6_CMD_ENC_SET_FB_FBC_Y_OFFSET15 (W6_REG_BASE + 0x480) +#define W6_CMD_ENC_SET_FB_FBC_C_OFFSET15 (W6_REG_BASE + 0x484) +#define W6_CMD_ENC_SET_FB_MV_COL15 (W6_REG_BASE + 0x488) +#define W6_CMD_ENC_SET_FB_SUB_SAMPLED15 (W6_REG_BASE + 0x48C) +#define W6_CMD_ENC_SET_FB_DEFAULT_CDF (W6_REG_BASE + 0x494) +#define W6_CMD_ENC_SET_FB_FBC_CR0 (W6_REG_BASE + 0x4F0) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET0 (W6_REG_BASE + 0x4F4) +#define W6_CMD_ENC_SET_FB_FBC_CR1 (W6_REG_BASE + 0x4F8) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET1 (W6_REG_BASE + 0x4FC) +#define W6_CMD_ENC_SET_FB_FBC_CR2 (W6_REG_BASE + 0x500) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET2 (W6_REG_BASE + 0x504) +#define W6_CMD_ENC_SET_FB_FBC_CR3 (W6_REG_BASE + 0x508) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET3 (W6_REG_BASE + 0x50C) +#define W6_CMD_ENC_SET_FB_FBC_CR4 (W6_REG_BASE + 0x510) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET4 (W6_REG_BASE + 0x514) +#define W6_CMD_ENC_SET_FB_FBC_CR5 (W6_REG_BASE + 0x518) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET5 (W6_REG_BASE + 0x51C) +#define W6_CMD_ENC_SET_FB_FBC_CR6 (W6_REG_BASE + 0x520) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET6 (W6_REG_BASE + 0x524) +#define W6_CMD_ENC_SET_FB_FBC_CR7 (W6_REG_BASE + 0x528) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET7 (W6_REG_BASE + 0x52C) +#define W6_CMD_ENC_SET_FB_FBC_CR8 (W6_REG_BASE + 0x530) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET8 (W6_REG_BASE + 0x534) +#define W6_CMD_ENC_SET_FB_FBC_CR9 (W6_REG_BASE + 0x538) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET9 (W6_REG_BASE + 0x53C) +#define W6_CMD_ENC_SET_FB_FBC_CR10 (W6_REG_BASE + 0x540) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET10 (W6_REG_BASE + 0x544) +#define W6_CMD_ENC_SET_FB_FBC_CR11 (W6_REG_BASE + 0x548) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET11 (W6_REG_BASE + 0x54C) +#define W6_CMD_ENC_SET_FB_FBC_CR12 (W6_REG_BASE + 0x550) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET12 (W6_REG_BASE + 0x554) +#define W6_CMD_ENC_SET_FB_FBC_CR13 (W6_REG_BASE + 0x558) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET13 (W6_REG_BASE + 0x55C) +#define W6_CMD_ENC_SET_FB_FBC_CR14 (W6_REG_BASE + 0x560) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET14 (W6_REG_BASE + 0x564) +#define W6_CMD_ENC_SET_FB_FBC_CR15 (W6_REG_BASE + 0x568) +#define W6_CMD_ENC_SET_FB_FBC_CR_OFFSET15 (W6_REG_BASE + 0x56C) + +/* ENCODER - ENC_PIC */ +#define W6_CMD_ENC_PIC_BS_START (W6_REG_BASE + 0x300) +#define W6_CMD_ENC_PIC_BS_SIZE (W6_REG_BASE + 0x304) +#define W6_CMD_ENC_PIC_BS_OPTION (W6_REG_BASE + 0x308) +#define W6_CMD_ENC_PIC_USE_SEC_AXI (W6_REG_BASE + 0x30C) +#define W6_CMD_ENC_PIC_REPORT_PARAM (W6_REG_BASE + 0x310) +#define W6_CMD_ENC_PIC_MV_HISTO_CLASS0 (W6_REG_BASE + 0x318) +#define W6_CMD_ENC_PIC_MV_HISTO_CLASS1 (W6_REG_BASE + 0x31C) +#define W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM (W6_REG_BASE + 0x320) +#define W6_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR (W6_REG_BASE + 0x324) +#define W6_CMD_ENC_PIC_SRC_PIC_IDX (W6_REG_BASE + 0x32C) +#define W6_CMD_ENC_PIC_SRC_ADDR_Y (W6_REG_BASE + 0x330) +#define W6_CMD_ENC_PIC_SRC_ADDR_U (W6_REG_BASE + 0x334) +#define W6_CMD_ENC_PIC_SRC_ADDR_V (W6_REG_BASE + 0x338) +#define W6_CMD_ENC_PIC_SRC_STRIDE (W6_REG_BASE + 0x33C) +#define W6_CMD_ENC_PIC_SRC_FORMAT (W6_REG_BASE + 0x340) +#define W6_CMD_ENC_PIC_SRC_AXI_SEL (W6_REG_BASE + 0x348) +#define W6_CMD_ENC_PIC_CODE_OPTION (W6_REG_BASE + 0x34C) +#define W6_CMD_ENC_PIC_PIC_PARAM (W6_REG_BASE + 0x350) +#define W6_CMD_ENC_PIC_LONGTERM_PIC (W6_REG_BASE + 0x354) +#define W6_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x358) +#define W6_CMD_ENC_PIC_PREFIX_SEI_INFO (W6_REG_BASE + 0x35C) +#define W6_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x360) +#define W6_CMD_ENC_PIC_SUFFIX_SEI_INFO (W6_REG_BASE + 0x364) +#define W6_CMD_ENC_PIC_CSC_COEFF_0 (W6_REG_BASE + 0x374) +#define W6_CMD_ENC_PIC_CSC_COEFF_1 (W6_REG_BASE + 0x378) +#define W6_CMD_ENC_PIC_CSC_COEFF_2 (W6_REG_BASE + 0x37C) +#define W6_CMD_ENC_PIC_CSC_COEFF_3 (W6_REG_BASE + 0x380) +#define W6_CMD_ENC_PIC_TIMESTAMP (W6_REG_BASE + 0x3F8) + +/* ENCODER - QUERY : GET_RESULT */ +#define W6_RET_ENC_RD_PTR (W6_REG_BASE + 0x300) +#define W6_RET_ENC_WR_PTR (W6_REG_BASE + 0x304) +#define W6_RET_ENC_NUM_REQUIRED_FBC_FB (W6_REG_BASE + 0x308) +#define W6_RET_ENC_MIN_SRC_BUF_NUM (W6_REG_BASE + 0x30C) +#define W6_RET_ENC_PIC_TYPE (W6_REG_BASE + 0x310) +#define W6_RET_ENC_PIC_POC (W6_REG_BASE + 0x314) +#define W6_RET_ENC_PIC_IDX (W6_REG_BASE + 0x318) +#define W6_RET_ENC_PIC_SLICE_NUM (W6_REG_BASE + 0x31C) +#define W6_RET_ENC_PIC_SKIP (W6_REG_BASE + 0x320) +#define W6_RET_ENC_PIC_NUM_INTRA (W6_REG_BASE + 0x324) +#define W6_RET_ENC_PIC_NUM_MERGE (W6_REG_BASE + 0x328) +#define W6_RET_ENC_PIC_NON_REF_PIC_FLAG (W6_REG_BASE + 0x32C) +#define W6_RET_ENC_PIC_NUM_SKIP (W6_REG_BASE + 0x330) +#define W6_RET_ENC_PIC_AVG_CTU_QP (W6_REG_BASE + 0x334) +#define W6_RET_ENC_PIC_BYTE (W6_REG_BASE + 0x338) +#define W6_RET_ENC_GOP_PIC_IDX (W6_REG_BASE + 0x33C) +#define W6_RET_ENC_USED_SRC_IDX (W6_REG_BASE + 0x340) +#define W6_RET_ENC_PIC_NUM (W6_REG_BASE + 0x344) +#define W6_RET_ENC_VCL_NUT (W6_REG_BASE + 0x348) +#define W6_RET_ENC_PIC_DIST_LOW (W6_REG_BASE + 0x350) +#define W6_RET_ENC_PIC_DIST_HIGH (W6_REG_BASE + 0x354) +#define W6_RET_ENC_PIC_MAX_LATENCY_PICTURES (W6_REG_BASE + 0x358) +#define W6_RET_ENC_HISTO_CNT_0 (W6_REG_BASE + 0x360) +#define W6_RET_ENC_HISTO_CNT_1 (W6_REG_BASE + 0x364) +#define W6_RET_ENC_HISTO_CNT_2 (W6_REG_BASE + 0x368) +#define W6_RET_ENC_HISTO_CNT_3 (W6_REG_BASE + 0x36C) +#define W6_RET_ENC_HISTO_CNT_4 (W6_REG_BASE + 0x370) +#define W6_RET_ENC_WARN_INFO (W6_REG_BASE + 0x3AC) +#define W6_RET_ENC_ERR_INFO (W6_REG_BASE + 0x3B0) +#define W6_RET_ENC_ENCODING_SUCCESS (W6_REG_BASE + 0x3B4) +#define W6_RET_ENC_SUM_ME0_X_DIR_LOWER (W6_REG_BASE + 0x3B8) +#define W6_RET_ENC_SUM_ME0_X_DIR_HIGHER (W6_REG_BASE + 0x3BC) +#define W6_RET_ENC_SUM_ME0_Y_DIR_LOWER (W6_REG_BASE + 0x3C0) +#define W6_RET_ENC_SUM_ME0_Y_DIR_HIGHER (W6_REG_BASE + 0x3C4) +#define W6_RET_ENC_SUM_ME1_X_DIR_LOWER (W6_REG_BASE + 0x3C8) +#define W6_RET_ENC_SUM_ME1_X_DIR_HIGHER (W6_REG_BASE + 0x3CC) +#define W6_RET_ENC_SUM_ME1_Y_DIR_LOWER (W6_REG_BASE + 0x3D0) +#define W6_RET_ENC_SUM_ME1_Y_DIR_HIGHER (W6_REG_BASE + 0x3D4) +#define W6_RET_ENC_SRC_Y_ADDR (W6_REG_BASE + 0x3E8) +#define W6_RET_ENC_CUSTOM_MAP_OPTION_ADDR (W6_REG_BASE + 0x3EC) +#define W6_RET_ENC_PREFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x3F0) +#define W6_RET_ENC_SUFFIX_SEI_NAL_ADDR (W6_REG_BASE + 0x3F4) +#define W6_RET_ENC_TIMESTAMP (W6_REG_BASE + 0x400) +#define W6_RET_ENC_NUM_REQUIRED_COL_BUF (W6_REG_BASE + 0x404) + +#endif /* __WAVE6_REGDEFINE_H__ */ diff --git a/drivers/media/platform/chips-media/wave6/wave6-vdi.c b/drivers/media/platform/chips-media/wave6/wave6-vdi.c new file mode 100644 index 000000000000..c255780fef0a --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vdi.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - low level access interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include +#include "wave6-vdi.h" +#include "wave6-vpu.h" +#include "wave6-regdefine.h" +#include "wave6-trace.h" + +#define VDI_SYSTEM_ENDIAN VDI_LITTLE_ENDIAN +#define VDI_128BIT_BUS_SYSTEM_ENDIAN VDI_128BIT_LITTLE_ENDIAN + +void wave6_vdi_writel(struct vpu_device *vpu_dev, unsigned int addr, unsigned int data) +{ + writel(data, vpu_dev->reg_base + addr); + trace_writel(vpu_dev->dev, addr, data); +} + +unsigned int wave6_vdi_readl(struct vpu_device *vpu_dev, u32 addr) +{ + unsigned int data; + + data = readl(vpu_dev->reg_base + addr); + trace_readl(vpu_dev->dev, addr, data); + + return data; +} + +unsigned int wave6_vdi_convert_endian(unsigned int endian) +{ + switch (endian) { + case VDI_LITTLE_ENDIAN: + endian = 0x00; + break; + case VDI_BIG_ENDIAN: + endian = 0x0f; + break; + case VDI_32BIT_LITTLE_ENDIAN: + endian = 0x04; + break; + case VDI_32BIT_BIG_ENDIAN: + endian = 0x03; + break; + } + + return (endian & 0x0f); +} diff --git a/drivers/media/platform/chips-media/wave6/wave6-vdi.h b/drivers/media/platform/chips-media/wave6/wave6-vdi.h new file mode 100644 index 000000000000..bb43b24547ed --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vdi.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - low level access interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VDI_H__ +#define __WAVE6_VDI_H__ + +#include +#include +#include +#include "wave6-vpuconfig.h" + +#define vpu_write_reg(VPU_DEV, ADDR, DATA) wave6_vdi_writel(VPU_DEV, ADDR, DATA) +#define vpu_read_reg(VPU_DEV, ADDR) wave6_vdi_readl(VPU_DEV, ADDR) + +struct vpu_buf { + size_t size; + dma_addr_t daddr; + void *vaddr; + struct device *dev; +}; + +struct vpu_dma_buf { + size_t size; + dma_addr_t dma_addr; + void *vaddr; + phys_addr_t phys_addr; +}; + +enum endian_mode { + VDI_LITTLE_ENDIAN = 0, + VDI_BIG_ENDIAN, + VDI_32BIT_LITTLE_ENDIAN, + VDI_32BIT_BIG_ENDIAN, + VDI_128BIT_LITTLE_ENDIAN = 16, + VDI_128BIT_LE_BYTE_SWAP, + VDI_128BIT_LE_WORD_SWAP, + VDI_128BIT_LE_WORD_BYTE_SWAP, + VDI_128BIT_LE_DWORD_SWAP, + VDI_128BIT_LE_DWORD_BYTE_SWAP, + VDI_128BIT_LE_DWORD_WORD_SWAP, + VDI_128BIT_LE_DWORD_WORD_BYTE_SWAP, + VDI_128BIT_BE_DWORD_WORD_BYTE_SWAP, + VDI_128BIT_BE_DWORD_WORD_SWAP, + VDI_128BIT_BE_DWORD_BYTE_SWAP, + VDI_128BIT_BE_DWORD_SWAP, + VDI_128BIT_BE_WORD_BYTE_SWAP, + VDI_128BIT_BE_WORD_SWAP, + VDI_128BIT_BE_BYTE_SWAP, + VDI_128BIT_BIG_ENDIAN = 31, + VDI_ENDIAN_MAX +}; + +#define VDI_128BIT_ENDIAN_MASK 0xf + +#endif /* __WAVE6_VDI_H__ */ diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c new file mode 100644 index 000000000000..a4f278918b15 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.c @@ -0,0 +1,1001 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - wave6 helper interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include "wave6-vpuapi.h" +#include "wave6-regdefine.h" +#include "wave6-hw.h" +#include "wave6-vpu-dbg.h" +#include "wave6-trace.h" + +static int wave6_check_dec_open_param(struct vpu_instance *inst, struct dec_open_param *param) +{ + struct vpu_attr *attr = &inst->dev->attr; + + if (param->bs_mode != attr->support_bitstream_mode) + return -EINVAL; + + return 0; +} + +int wave6_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *pop) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = wave6_check_dec_open_param(inst, pop); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave6_vpu_is_init(vpu_dev)) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENODEV; + } + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); + if (!inst->codec_info) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENOMEM; + } + + p_dec_info = &inst->codec_info->dec_info; + memcpy(&p_dec_info->open_param, pop, sizeof(struct dec_open_param)); + + ret = wave6_vpu_build_up_dec_param(inst, pop); + if (ret) + goto free_codec_info; + + mutex_unlock(&vpu_dev->hw_lock); + + return 0; + +free_codec_info: + kfree(inst->codec_info); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + if (!inst->codec_info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_dec_fini_seq(inst, fail_res); + if (ret) { + dev_warn(inst->dev->dev, "dec seq end timed out\n"); + + if (*fail_res == WAVE6_SYSERR_VPU_STILL_RUNNING) { + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + } + + dev_dbg(inst->dev->dev, "dec seq end complete\n"); + + mutex_unlock(&vpu_dev->hw_lock); + + kfree(inst->codec_info); + + return 0; +} + +int wave6_vpu_dec_issue_seq_init(struct vpu_instance *inst) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_dec_init_seq(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_dec_get_seq_info(inst, info); + if (!ret) + p_dec_info->initial_info_obtained = true; + + info->rd_ptr = wave6_vpu_dec_get_rd_ptr(inst); + info->wr_ptr = p_dec_info->stream_wr_ptr; + + p_dec_info->initial_info = *info; + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_get_aux_buffer_size(struct vpu_instance *inst, + struct dec_aux_buffer_size_info info, + uint32_t *size) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int width = info.width; + int height = info.height; + int buf_size, twice; + + if (info.type == AUX_BUF_FBC_Y_TBL) { + switch (inst->std) { + case W_HEVC_DEC: + buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height); + break; + case W_AVC_DEC: + buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height); + break; + default: + return -EINVAL; + } + buf_size = ALIGN(buf_size, 16); + } else if (info.type == AUX_BUF_FBC_C_TBL) { + if (p_dec_info->initial_info.chroma_format_idc == 2) + twice = 2; + else if (p_dec_info->initial_info.chroma_format_idc == 3) + twice = 4; + else + twice = 1; + + switch (inst->std) { + case W_HEVC_DEC: + buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height); + break; + case W_AVC_DEC: + buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height); + break; + default: + return -EINVAL; + } + buf_size = buf_size * twice; + buf_size = ALIGN(buf_size, 16); + } else if (info.type == AUX_BUF_MV_COL) { + switch (inst->std) { + case W_HEVC_DEC: + buf_size = WAVE6_DEC_HEVC_MVCOL_BUF_SIZE(width, height); + break; + case W_AVC_DEC: + buf_size = WAVE6_DEC_AVC_MVCOL_BUF_SIZE(width, height); + break; + default: + return -EINVAL; + } + buf_size = ALIGN(buf_size, 16); + } else { + return -EINVAL; + } + + *size = buf_size; + + return 0; +} + +int wave6_vpu_dec_register_aux_buffer(struct vpu_instance *inst, + struct aux_buffer_info info) +{ + struct dec_info *p_dec_info; + struct aux_buffer *aux_bufs = info.buf_array; + struct dec_aux_buffer_size_info size_info; + unsigned int expected_size; + unsigned int i; + int ret; + + p_dec_info = &inst->codec_info->dec_info; + + size_info.width = p_dec_info->initial_info.pic_width; + size_info.height = p_dec_info->initial_info.pic_height; + size_info.type = info.type; + + ret = wave6_vpu_dec_get_aux_buffer_size(inst, size_info, &expected_size); + if (ret) + return ret; + + switch (info.type) { + case AUX_BUF_FBC_Y_TBL: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_dec_info->vb_fbc_y_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_dec_info->vb_fbc_y_tbl[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + case AUX_BUF_FBC_C_TBL: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_dec_info->vb_fbc_c_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_dec_info->vb_fbc_c_tbl[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + case AUX_BUF_MV_COL: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_dec_info->vb_mv[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_dec_info->vb_mv[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +int wave6_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, + int num_of_dec_fbs, int stride, + int height, int map_type) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + struct frame_buffer *fb; + + if (num_of_dec_fbs > WAVE6_MAX_FBS) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + p_dec_info->stride = stride; + + if (!p_dec_info->initial_info_obtained) + return -EINVAL; + + if (stride < p_dec_info->initial_info.pic_width || (stride % 8) || + height < p_dec_info->initial_info.pic_height) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + fb = inst->frame_buf; + ret = wave6_vpu_dec_register_frame_buffer(inst, &fb[0], COMPRESSED_FRAME_MAP, + num_of_dec_fbs); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_register_display_buffer_ex(struct vpu_instance *inst, struct frame_buffer fb) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + p_dec_info = &inst->codec_info->dec_info; + + if (!p_dec_info->initial_info_obtained) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_dec_register_display_buffer(inst, fb); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *p_rd_ptr, + dma_addr_t *p_wr_ptr) +{ + struct dec_info *p_dec_info; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + struct vpu_device *vpu_dev = inst->dev; + int ret; + + p_dec_info = &inst->codec_info->dec_info; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + rd_ptr = wave6_vpu_dec_get_rd_ptr(inst); + mutex_unlock(&vpu_dev->hw_lock); + + wr_ptr = p_dec_info->stream_wr_ptr; + + if (p_rd_ptr) + *p_rd_ptr = rd_ptr; + if (p_wr_ptr) + *p_wr_ptr = wr_ptr; + + return 0; +} + +int wave6_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, int size) +{ + struct dec_info *p_dec_info; + dma_addr_t wr_ptr; + dma_addr_t rd_ptr; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!inst->codec_info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + wr_ptr = p_dec_info->stream_wr_ptr; + rd_ptr = p_dec_info->stream_rd_ptr; + + if (size > 0) { + if (wr_ptr < rd_ptr && rd_ptr <= wr_ptr + size) + return -EINVAL; + + wr_ptr += size; + + p_dec_info->stream_wr_ptr = wr_ptr; + p_dec_info->stream_rd_ptr = rd_ptr; + } + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + wave6_vpu_dec_set_bitstream_end(inst, (size == 0)); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_start_one_frame(struct vpu_instance *inst, struct dec_param *param, u32 *res_fail) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!p_dec_info->stride) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_decode(inst, param, res_fail); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, bool update_wr_ptr) +{ + struct dec_info *p_dec_info = &inst->codec_info->dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + p_dec_info->stream_rd_ptr = addr; + if (update_wr_ptr) + p_dec_info->stream_wr_ptr = addr; + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info) +{ + struct dec_info *p_dec_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + memset(info, 0, sizeof(*info)); + + ret = wave6_vpu_dec_get_result(inst, info); + if (ret) { + info->rd_ptr = p_dec_info->stream_rd_ptr; + info->wr_ptr = p_dec_info->stream_wr_ptr; + goto err_out; + } + +err_out: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *param) +{ + struct dec_info *p_dec_info; + + if (!inst || !inst->codec_info) + return -EINVAL; + + p_dec_info = &inst->codec_info->dec_info; + + switch (cmd) { + case ENABLE_DEC_THUMBNAIL_MODE: + p_dec_info->thumbnail_mode = 1; + break; + case DEC_RESET_FRAMEBUF_INFO: { + int i; + + for (i = 0; i < WAVE6_MAX_FBS; i++) { + wave6_free_dma(&inst->frame_vbuf[i]); + memset(&inst->frame_buf[i], 0, sizeof(struct frame_buffer)); + memset(&p_dec_info->disp_buf[i], 0, sizeof(struct frame_buffer)); + + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_MV_COL][i]); + memset(&p_dec_info->vb_mv[i], 0, sizeof(struct vpu_buf)); + + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_Y_TBL][i]); + memset(&p_dec_info->vb_fbc_y_tbl[i], 0, sizeof(struct vpu_buf)); + + wave6_free_dma(&inst->aux_vbuf[AUX_BUF_FBC_C_TBL][i]); + memset(&p_dec_info->vb_fbc_c_tbl[i], 0, sizeof(struct vpu_buf)); + } + break; + } + case DEC_GET_SEQ_INFO: { + struct dec_initial_info *seq_info = param; + + *seq_info = p_dec_info->initial_info; + break; + } + + default: + return -EINVAL; + } + + return 0; +} + +int wave6_vpu_dec_flush_instance(struct vpu_instance *inst) +{ + struct vpu_device *vpu_dev = inst->dev; + int ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_dec_flush(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *pop) +{ + struct enc_info *p_enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = wave6_vpu_enc_check_open_param(inst, pop); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + if (!wave6_vpu_is_init(vpu_dev)) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENODEV; + } + + inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL); + if (!inst->codec_info) { + mutex_unlock(&vpu_dev->hw_lock); + return -ENOMEM; + } + + p_enc_info = &inst->codec_info->enc_info; + p_enc_info->open_param = *pop; + + ret = wave6_vpu_build_up_enc_param(vpu_dev->dev, inst, pop); + if (ret) + goto free_codec_info; + mutex_unlock(&vpu_dev->hw_lock); + + return 0; + +free_codec_info: + kfree(inst->codec_info); + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + if (!inst->codec_info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_enc_fini_seq(inst, fail_res); + if (ret) { + dev_warn(inst->dev->dev, "enc seq end timed out\n"); + + if (*fail_res == WAVE6_SYSERR_VPU_STILL_RUNNING) { + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + } + + dev_dbg(inst->dev->dev, "enc seq end timed out\n"); + + mutex_unlock(&vpu_dev->hw_lock); + + kfree(inst->codec_info); + + return 0; +} + +int wave6_vpu_enc_get_aux_buffer_size(struct vpu_instance *inst, + struct enc_aux_buffer_size_info info, + uint32_t *size) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int width, height, buf_size, twice; + + if (inst->std == W_AVC_ENC) { + width = ALIGN(info.width, 16); + height = ALIGN(info.height, 16); + if (info.rotation_angle == 90 || info.rotation_angle == 270) { + width = ALIGN(info.height, 16); + height = ALIGN(info.width, 16); + } + } else { + width = ALIGN(info.width, 8); + height = ALIGN(info.height, 8); + if ((info.rotation_angle || info.mirror_direction) && + !(info.rotation_angle == 180 && info.mirror_direction == MIRDIR_HOR_VER)) { + width = ALIGN(info.width, 32); + height = ALIGN(info.height, 32); + } + if (info.rotation_angle == 90 || info.rotation_angle == 270) { + width = ALIGN(info.height, 32); + height = ALIGN(info.width, 32); + } + } + + if (info.type == AUX_BUF_FBC_Y_TBL) { + switch (inst->std) { + case W_HEVC_ENC: + buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height); + break; + case W_AVC_ENC: + buf_size = WAVE6_FBC_LUMA_TABLE_SIZE(width, height); + break; + default: + return -EINVAL; + } + } else if (info.type == AUX_BUF_FBC_C_TBL) { + switch (p_enc_info->open_param.output_format) { + case FORMAT_422: + case FORMAT_422_P10_16BIT_MSB: + case FORMAT_422_P10_16BIT_LSB: + case FORMAT_422_P10_32BIT_MSB: + case FORMAT_422_P10_32BIT_LSB: + twice = 2; + break; + case FORMAT_444: + case FORMAT_444_P10_16BIT_MSB: + case FORMAT_444_P10_16BIT_LSB: + case FORMAT_444_P10_32BIT_MSB: + case FORMAT_444_P10_32BIT_LSB: + twice = 4; + break; + default: + twice = 1; + break; + } + switch (inst->std) { + case W_HEVC_ENC: + buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height); + break; + case W_AVC_ENC: + buf_size = WAVE6_FBC_CHROMA_TABLE_SIZE(width, height); + break; + default: + return -EINVAL; + } + buf_size = buf_size * twice; + } else if (info.type == AUX_BUF_MV_COL) { + switch (inst->std) { + case W_HEVC_ENC: + buf_size = WAVE6_ENC_HEVC_MVCOL_BUF_SIZE(width, height); + break; + case W_AVC_ENC: + buf_size = WAVE6_ENC_AVC_MVCOL_BUF_SIZE(width, height); + break; + default: + return -EINVAL; + } + } else if (info.type == AUX_BUF_SUB_SAMPLE) { + switch (inst->std) { + case W_HEVC_ENC: + case W_AVC_ENC: + buf_size = WAVE6_ENC_SUBSAMPLED_SIZE(width, height); + break; + default: + return -EINVAL; + } + } else { + return -EINVAL; + } + + *size = buf_size; + + return 0; +} + +int wave6_vpu_enc_register_aux_buffer(struct vpu_instance *inst, + struct aux_buffer_info info) +{ + struct enc_info *p_enc_info; + struct aux_buffer *aux_bufs = info.buf_array; + struct enc_aux_buffer_size_info size_info; + unsigned int expected_size; + unsigned int i; + int ret; + + p_enc_info = &inst->codec_info->enc_info; + + size_info.width = p_enc_info->width; + size_info.height = p_enc_info->height; + size_info.type = info.type; + size_info.rotation_angle = p_enc_info->rotation_angle; + size_info.mirror_direction = p_enc_info->mirror_direction; + + ret = wave6_vpu_enc_get_aux_buffer_size(inst, size_info, &expected_size); + if (ret) + return ret; + + switch (info.type) { + case AUX_BUF_FBC_Y_TBL: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_enc_info->vb_fbc_y_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_enc_info->vb_fbc_y_tbl[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + case AUX_BUF_FBC_C_TBL: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_enc_info->vb_fbc_c_tbl[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_enc_info->vb_fbc_c_tbl[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + case AUX_BUF_MV_COL: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_enc_info->vb_mv[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_enc_info->vb_mv[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + case AUX_BUF_SUB_SAMPLE: + for (i = 0; i < info.num; i++) { + if (expected_size > aux_bufs[i].size) + return -EINVAL; + + p_enc_info->vb_sub_sam_buf[aux_bufs[i].index].daddr = aux_bufs[i].addr; + p_enc_info->vb_sub_sam_buf[aux_bufs[i].index].size = aux_bufs[i].size; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +int wave6_vpu_enc_register_frame_buffer_ex(struct vpu_instance *inst, int num, unsigned int stride, + int height, enum tiled_map_type map_type) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (p_enc_info->stride) + return -EINVAL; + + if (!p_enc_info->initial_info_obtained) + return -EINVAL; + + if (num < p_enc_info->initial_info.min_frame_buffer_count) + return -EINVAL; + + if (!stride || stride % 8) + return -EINVAL; + + if (height < 0) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + p_enc_info->num_frame_buffers = num; + p_enc_info->stride = stride; + + ret = wave6_vpu_enc_register_frame_buffer(inst, &inst->frame_buf[0]); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +static int wave6_check_enc_param(struct vpu_instance *inst, struct enc_param *param) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + bool is_rgb_format = false; + + if (!param) + return -EINVAL; + + if (!param->skip_picture && !param->source_frame) + return -EINVAL; + + if (!p_enc_info->open_param.codec_param.bitrate && inst->std == W_HEVC_ENC) { + if (param->force_pic_qp_enable) { + if (param->force_pic_qp_i < 0 || param->force_pic_qp_i > 63) + return -EINVAL; + + if (param->force_pic_qp_p < 0 || param->force_pic_qp_p > 63) + return -EINVAL; + + if (param->force_pic_qp_b < 0 || param->force_pic_qp_b > 63) + return -EINVAL; + } + if ((param->pic_stream_buffer_addr % 16 || !param->pic_stream_buffer_size)) + return -EINVAL; + } + + if ((param->pic_stream_buffer_addr % 8 || !param->pic_stream_buffer_size)) + return -EINVAL; + + if (p_enc_info->open_param.src_format == FORMAT_RGB_32BIT_PACKED || + p_enc_info->open_param.src_format == FORMAT_RGB_P10_32BIT_PACKED || + p_enc_info->open_param.src_format == FORMAT_RGB_24BIT_PACKED) + is_rgb_format = true; + + if (is_rgb_format) { + if (param->csc.coef_ry > 1023) + return -EINVAL; + if (param->csc.coef_gy > 1023) + return -EINVAL; + if (param->csc.coef_by > 1023) + return -EINVAL; + if (param->csc.coef_rcb > 1023) + return -EINVAL; + if (param->csc.coef_gcb > 1023) + return -EINVAL; + if (param->csc.coef_bcb > 1023) + return -EINVAL; + if (param->csc.coef_rcr > 1023) + return -EINVAL; + if (param->csc.coef_gcr > 1023) + return -EINVAL; + if (param->csc.coef_bcr > 1023) + return -EINVAL; + if (param->csc.offset_y > 1023) + return -EINVAL; + if (param->csc.offset_cb > 1023) + return -EINVAL; + if (param->csc.offset_cr > 1023) + return -EINVAL; + } + + return 0; +} + +int wave6_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, u32 *fail_res) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + *fail_res = 0; + + if (!p_enc_info->stride) + return -EINVAL; + + ret = wave6_check_enc_param(inst, param); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_encode(inst, param, fail_res); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + memset(info, 0, sizeof(*info)); + + ret = wave6_vpu_enc_get_result(inst, info); + if (ret) + goto unlock; + +unlock: + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *param) +{ + struct enc_info *p_enc_info; + + if (!inst || !inst->codec_info) + return -EINVAL; + + p_enc_info = &inst->codec_info->enc_info; + + switch (cmd) { + case ENABLE_ROTATION: + p_enc_info->rotation_enable = true; + break; + case ENABLE_MIRRORING: + p_enc_info->mirror_enable = true; + break; + case SET_MIRROR_DIRECTION: { + enum mirror_direction mir_dir; + + mir_dir = *(enum mirror_direction *)param; + if (mir_dir != MIRDIR_NONE && mir_dir != MIRDIR_HOR && + mir_dir != MIRDIR_VER && mir_dir != MIRDIR_HOR_VER) + return -EINVAL; + p_enc_info->mirror_direction = mir_dir; + break; + } + case SET_ROTATION_ANGLE: { + int angle; + + angle = *(int *)param; + if (angle && angle != 90 && angle != 180 && angle != 270) + return -EINVAL; + if (p_enc_info->initial_info_obtained && (angle == 90 || angle == 270)) + return -EINVAL; + p_enc_info->rotation_angle = angle; + break; + } + default: + return -EINVAL; + } + return 0; +} + +int wave6_vpu_enc_issue_seq_init(struct vpu_instance *inst) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_enc_init_seq(inst); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_enc_issue_seq_change(struct vpu_instance *inst, bool *changed) +{ + int ret; + struct vpu_device *vpu_dev = inst->dev; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_enc_change_seq(inst, changed); + + mutex_unlock(&vpu_dev->hw_lock); + + return ret; +} + +int wave6_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info) +{ + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + int ret; + struct vpu_device *vpu_dev = inst->dev; + + if (!info) + return -EINVAL; + + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); + if (ret) + return ret; + + ret = wave6_vpu_enc_get_seq_info(inst, info); + if (ret) { + p_enc_info->initial_info_obtained = false; + mutex_unlock(&vpu_dev->hw_lock); + return ret; + } + + if (!p_enc_info->initial_info_obtained) { + p_enc_info->initial_info_obtained = true; + p_enc_info->initial_info = *info; + } + + mutex_unlock(&vpu_dev->hw_lock); + + return 0; +} diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h new file mode 100644 index 000000000000..93c9a7b9374c --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpuapi.h @@ -0,0 +1,993 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 helper interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VPUAPI_H__ +#define __WAVE6_VPUAPI_H__ + +#include +#include +#include +#include +#include +#include "wave6-vpuerror.h" +#include "wave6-vpuconfig.h" +#include "wave6-vdi.h" +#include "wave6-vpu-ctrl.h" + +struct vpu_attr; + +enum vpu_instance_type { + VPU_INST_TYPE_DEC = 0, + VPU_INST_TYPE_ENC = 1 +}; + +enum vpu_instance_state { + VPU_INST_STATE_NONE = 0, + VPU_INST_STATE_OPEN = 1, + VPU_INST_STATE_INIT_SEQ = 2, + VPU_INST_STATE_PIC_RUN = 3, + VPU_INST_STATE_SEEK = 4, + VPU_INST_STATE_STOP = 5 +}; + +#define WAVE6_MAX_FBS 31 + +#define WAVE6_DEC_HEVC_MVCOL_BUF_SIZE(_w, _h) \ + ((ALIGN((_w), 256) / 16) * (ALIGN((_h), 64) / 16) * 1 * 16) +#define WAVE6_DEC_AVC_MVCOL_BUF_SIZE(_w, _h) \ + ((ALIGN((_w), 64) / 16) * (ALIGN((_h), 16) / 16) * 5 * 16) +#define WAVE6_FBC_LUMA_TABLE_SIZE(_w, _h) \ + (ALIGN((_w), 256) * ALIGN((_h), 64) / 32) +#define WAVE6_FBC_CHROMA_TABLE_SIZE(_w, _h) \ + (ALIGN(((_w) / 2), 256) * ALIGN((_h), 64) / 32) +#define WAVE6_ENC_AVC_MVCOL_BUF_SIZE(_w, _h) \ + ((ALIGN((_w), 512) / 512) * (ALIGN((_h), 16) / 16) * 16) +#define WAVE6_ENC_HEVC_MVCOL_BUF_SIZE(_w, _h) \ + ((ALIGN((_w), 64) / 64) * (ALIGN((_h), 64) / 64) * 128) +#define WAVE6_ENC_SUBSAMPLED_SIZE(_w, _h) \ + (ALIGN(((_w) / 4), 16) * ALIGN(((_h) / 4), 32)) + +enum codec_std { + W_HEVC_DEC = 0x00, + W_HEVC_ENC = 0x01, + W_AVC_DEC = 0x02, + W_AVC_ENC = 0x03, + STD_UNKNOWN = 0xFF +}; + +#define HEVC_PROFILE_MAIN 1 +#define HEVC_PROFILE_MAIN10 2 +#define HEVC_PROFILE_STILLPICTURE 3 +#define HEVC_PROFILE_MAIN10_STILLPICTURE 2 + +#define H264_PROFILE_BP 1 +#define H264_PROFILE_MP 2 +#define H264_PROFILE_EXTENDED 3 +#define H264_PROFILE_HP 4 +#define H264_PROFILE_HIGH10 5 + +#define H264_VUI_SAR_IDC_EXTENDED 255 + +#define DEC_REFRESH_TYPE_NON_IRAP 0 +#define DEC_REFRESH_TYPE_IDR 2 + +#define DEFAULT_TEMP_LAYER_CNT 1 +#define DEFAULT_RC_INITIAL_LEVEL 8 +#define DEFAULT_RC_INITIAL_QP -1 +#define DEFAULT_PIC_RC_MAX_DQP 3 +#define DEFAULT_EN_ADAPTIVE_ROUND 1 +#define DEFAULT_Q_ROUND_INTER 85 +#define DEFAULT_Q_ROUND_INTRA 171 +#define DEFAULT_EN_INTRA_TRANS_SKIP 1 +#define DEFAULT_EN_ME_CENTER 1 +#define DEFAULT_INTRA_4X4 3 +#define DEFAULT_EN_AUTO_LEVEL_ADJUSTING 1 +#define DEFAULT_NUM_TICKS_POC_DIFF 100 +#define DEFAULT_RC_UPDATE_SPEED_CBR 64 +#define DEFAULT_RC_UPDATE_SPEED_VBR 16 +#define DEFAULT_VUI_VIDEO_SIGNAL_TYPE_PRESENT_FLAG 1 +#define DEFAULT_VUI_COLOR_DESCRIPTION_PRESENT_FLAG 1 + +#define SEQ_CHANGE_ENABLE_PROFILE BIT(5) +#define SEQ_CHANGE_ENABLE_SIZE BIT(16) +#define SEQ_CHANGE_ENABLE_BITDEPTH BIT(18) +#define SEQ_CHANGE_ENABLE_DPB_COUNT BIT(19) + +#define SEQ_CHANGE_ENABLE_ALL_HEVC (SEQ_CHANGE_ENABLE_PROFILE | \ + SEQ_CHANGE_ENABLE_SIZE | \ + SEQ_CHANGE_ENABLE_BITDEPTH | \ + SEQ_CHANGE_ENABLE_DPB_COUNT) + +#define SEQ_CHANGE_ENABLE_ALL_AVC (SEQ_CHANGE_ENABLE_SIZE | \ + SEQ_CHANGE_ENABLE_BITDEPTH | \ + SEQ_CHANGE_ENABLE_DPB_COUNT) + +#define DEC_NOTI_FLAG_NO_FB 0x2 +#define DEC_NOTI_FLAG_SEQ_CHANGE 0x1 + +#define RECON_IDX_FLAG_ENC_END -1 +#define RECON_IDX_FLAG_ENC_DELAY -2 +#define RECON_IDX_FLAG_HEADER_ONLY -3 +#define RECON_IDX_FLAG_CHANGE_PARAM -4 + +enum codec_command { + ENABLE_ROTATION, + ENABLE_MIRRORING, + SET_MIRROR_DIRECTION, + SET_ROTATION_ANGLE, + ENABLE_DEC_THUMBNAIL_MODE, + DEC_RESET_FRAMEBUF_INFO, + DEC_GET_SEQ_INFO, +}; + +enum cb_cr_order { + CBCR_ORDER_NORMAL, + CBCR_ORDER_REVERSED +}; + +enum mirror_direction { + MIRDIR_NONE, + MIRDIR_VER, + MIRDIR_HOR, + MIRDIR_HOR_VER +}; + +enum chroma_format { + YUV400, + YUV420, + YUV422, + YUV444, +}; + +enum frame_buffer_format { + FORMAT_ERR = -1, + + FORMAT_420 = 0, + FORMAT_422, + FORMAT_224, + FORMAT_444, + FORMAT_400, + + FORMAT_420_P10_16BIT_MSB = 5, + FORMAT_420_P10_16BIT_LSB, + FORMAT_420_P10_32BIT_MSB, + FORMAT_420_P10_32BIT_LSB, + + FORMAT_422_P10_16BIT_MSB, + FORMAT_422_P10_16BIT_LSB, + FORMAT_422_P10_32BIT_MSB, + FORMAT_422_P10_32BIT_LSB, + + FORMAT_444_P10_16BIT_MSB, + FORMAT_444_P10_16BIT_LSB, + FORMAT_444_P10_32BIT_MSB, + FORMAT_444_P10_32BIT_LSB, + + FORMAT_400_P10_16BIT_MSB, + FORMAT_400_P10_16BIT_LSB, + FORMAT_400_P10_32BIT_MSB, + FORMAT_400_P10_32BIT_LSB, + + FORMAT_YUYV, + FORMAT_YUYV_P10_16BIT_MSB, + FORMAT_YUYV_P10_16BIT_LSB, + FORMAT_YUYV_P10_32BIT_MSB, + FORMAT_YUYV_P10_32BIT_LSB, + + FORMAT_YVYU, + FORMAT_YVYU_P10_16BIT_MSB, + FORMAT_YVYU_P10_16BIT_LSB, + FORMAT_YVYU_P10_32BIT_MSB, + FORMAT_YVYU_P10_32BIT_LSB, + + FORMAT_UYVY, + FORMAT_UYVY_P10_16BIT_MSB, + FORMAT_UYVY_P10_16BIT_LSB, + FORMAT_UYVY_P10_32BIT_MSB, + FORMAT_UYVY_P10_32BIT_LSB, + + FORMAT_VYUY, + FORMAT_VYUY_P10_16BIT_MSB, + FORMAT_VYUY_P10_16BIT_LSB, + FORMAT_VYUY_P10_32BIT_MSB, + FORMAT_VYUY_P10_32BIT_LSB, + + FORMAT_RGB_32BIT_PACKED = 90, + FORMAT_YUV444_32BIT_PACKED, + FORMAT_RGB_P10_32BIT_PACKED, + FORMAT_YUV444_P10_32BIT_PACKED, + + FORMAT_RGB_24BIT_PACKED = 95, + FORMAT_YUV444_24BIT_PACKED, + FORMAT_YUV444_24BIT, + + FORMAT_MAX, +}; + +enum packed_format_num { + NOT_PACKED = 0, + PACKED_YUYV, + PACKED_YVYU, + PACKED_UYVY, + PACKED_VYUY, +}; + +enum pic_type { + PIC_TYPE_I = 0, + PIC_TYPE_P = 1, + PIC_TYPE_B = 2, + PIC_TYPE_IDR = 5, + PIC_TYPE_MAX +}; + +enum enc_force_pic_type { + ENC_FORCE_PIC_TYPE_I = 0, + ENC_FORCE_PIC_TYPE_P = 1, + ENC_FORCE_PIC_TYPE_B = 2, + ENC_FORCE_PIC_TYPE_IDR = 3, + ENC_FORCE_PIC_TYPE_DISABLED = 4, +}; + +enum bitstream_mode { + BS_MODE_INTERRUPT, + BS_MODE_RESERVED, + BS_MODE_PIC_END, +}; + +enum display_mode { + DISP_MODE_DISP_ORDER, + DISP_MODE_DEC_ORDER, +}; + +enum sw_reset_mode { + SW_RESET_SAFETY, + SW_RESET_FORCE, + SW_RESET_ON_BOOT +}; + +enum tiled_map_type { + LINEAR_FRAME_MAP = 0, + COMPRESSED_FRAME_MAP = 17, +}; + +enum temporal_id_mode { + TEMPORAL_ID_MODE_ABSOLUTE, + TEMPORAL_ID_MODE_RELATIVE, +}; + +enum aux_buffer_type { + AUX_BUF_FBC_Y_TBL, + AUX_BUF_FBC_C_TBL, + AUX_BUF_MV_COL, + AUX_BUF_SUB_SAMPLE, + AUX_BUF_TYPE_MAX, +}; + +enum intra_refresh_mode { + INTRA_REFRESH_NONE = 0, + INTRA_REFRESH_ROW = 1, + INTRA_REFRESH_COLUMN = 2, +}; + +struct vpu_attr { + u32 product_id; + char product_name[8]; + u32 product_version; + u32 fw_version; + u32 fw_revision; + u32 support_decoders; + u32 support_encoders; + u32 support_bitstream_mode; + bool support_avc10bit_enc; + bool support_hevc10bit_enc; + bool support_dual_core; +}; + +struct frame_buffer { + dma_addr_t buf_y; + dma_addr_t buf_cb; + dma_addr_t buf_cr; + enum tiled_map_type map_type; + unsigned int stride; + unsigned int width; + unsigned int height; + int index; + u32 luma_bitdepth: 4; + u32 chroma_bitdepth: 4; + u32 chroma_format_idc: 2; +}; + +struct vpu_rect { + u32 left; + u32 top; + u32 right; + u32 bottom; +}; + +struct timestamp_info { + u32 hour; + u32 min; + u32 sec; + u32 ms; +}; + +struct sar_info { + u32 enable; + u32 idc; + u32 width; + u32 height; +}; + +struct aux_buffer { + int index; + int size; + dma_addr_t addr; +}; + +struct aux_buffer_info { + int num; + struct aux_buffer *buf_array; + enum aux_buffer_type type; +}; + +struct instance_buffer { + dma_addr_t temp_base; + u32 temp_size; + dma_addr_t ar_base; +}; + +struct report_cycle { + u32 host_cmd_s; + u32 host_cmd_e; + u32 proc_s; + u32 proc_e; + u32 vpu_s; + u32 vpu_e; + u32 frame_cycle; + u32 proc_cycle; + u32 vpu_cycle; +}; + +struct color_param { + u32 chroma_sample_position; + u32 color_range; + u32 matrix_coefficients; + u32 transfer_characteristics; + u32 color_primaries; + bool color_description_present; + bool video_signal_type_present; +}; + +struct sec_axi_info { + bool use_dec_ip; + bool use_dec_lf_row; + bool use_enc_rdo; + bool use_enc_lf; +}; + +struct dec_aux_buffer_size_info { + int width; + int height; + enum aux_buffer_type type; +}; + +struct dec_scaler_info { + bool enable; + int width; + int height; + u32 scale_mode; +}; + +struct dec_open_param { + enum cb_cr_order cbcr_order; + enum endian_mode frame_endian; + enum endian_mode stream_endian; + enum bitstream_mode bs_mode; + enum display_mode disp_mode; + bool enable_non_ref_fbc_write; + u32 ext_addr_vcpu: 8; + bool is_secure_inst; + u32 inst_priority: 5; + struct instance_buffer inst_buffer; +}; + +struct dec_initial_info { + u32 pic_width; + u32 pic_height; + u32 f_rate_numerator; + u32 f_rate_denominator; + struct vpu_rect pic_crop_rect; + u32 min_frame_buffer_count; + u32 req_mv_buffer_count; + u32 frame_buf_delay; + u32 profile; + u32 level; + u32 tier; + bool is_ext_sar; + u32 aspect_rate_info; + u32 bitrate; + u32 chroma_format_idc; + u32 luma_bitdepth; + u32 chroma_bitdepth; + u32 err_reason; + int warn_info; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + unsigned int sequence_no; + struct color_param color; +}; + +#define WAVE_SKIPMODE_WAVE_NONE 0 +#define WAVE_SKIPMODE_NON_IRAP 1 +#define WAVE_SKIPMODE_NON_REF 2 + +struct dec_param { + int skipframe_mode; + bool decode_cra_as_bla; + bool disable_film_grain; + struct timestamp_info timestamp; +}; + +struct h265_rp_sei { + unsigned int exist; + int recovery_poc_cnt; + bool exact_match; + bool broken_link; +}; + +struct dec_output_info { + int nal_type; + int pic_type; + int num_of_err_m_bs; + int num_of_tot_m_bs; + int num_of_err_m_bs_in_disp; + int num_of_tot_m_bs_in_disp; + int disp_pic_width; + int disp_pic_height; + int dec_pic_width; + int dec_pic_height; + int decoded_poc; + int display_poc; + struct h265_rp_sei h265_rp_sei; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + dma_addr_t byte_pos_frame_start; + dma_addr_t byte_pos_frame_end; + dma_addr_t frame_decoded_addr; + dma_addr_t frame_display_addr; + int error_reason; + int warn_info; + unsigned int sequence_no; + struct report_cycle cycle; + dma_addr_t release_disp_frame_addr[WAVE6_MAX_FBS]; + dma_addr_t disp_frame_addr[WAVE6_MAX_FBS]; + struct timestamp_info timestamp; + u32 notification_flags; + u32 release_disp_frame_num: 5; + u32 disp_frame_num: 5; + u32 ctu_size: 2; + bool frame_display; + bool frame_decoded; + bool stream_end; + bool last_frame_in_au; + bool decoding_success; +}; + +struct dec_info { + struct dec_open_param open_param; + struct dec_initial_info initial_info; + dma_addr_t stream_wr_ptr; + dma_addr_t stream_rd_ptr; + bool stream_end; + struct vpu_buf vb_mv[WAVE6_MAX_FBS]; + struct vpu_buf vb_fbc_y_tbl[WAVE6_MAX_FBS]; + struct vpu_buf vb_fbc_c_tbl[WAVE6_MAX_FBS]; + struct frame_buffer disp_buf[WAVE6_MAX_FBS]; + int stride; + bool initial_info_obtained; + struct sec_axi_info sec_axi_info; + struct dec_output_info dec_out_info[WAVE6_MAX_FBS]; + bool thumbnail_mode; + int seq_change_mask; + u32 cycle_per_tick; + enum frame_buffer_format wtl_format; +}; + +#define MAX_CUSTOM_LAMBDA_NUM 52 +#define MAX_NUM_TEMPORAL_LAYER 7 +#define MAX_GOP_NUM 8 +#define MAX_NUM_CHANGEABLE_TEMPORAL_LAYER 4 + +struct custom_gop_pic_param { + int pic_type; + int poc_offset; + int pic_qp; + int use_multi_ref_p; + int ref_poc_l0; + int ref_poc_l1; + int temporal_id; +}; + +struct custom_gop_param { + int custom_gop_size; + struct custom_gop_pic_param pic_param[MAX_GOP_NUM]; +}; + +struct temporal_layer_param { + bool change_qp; + u32 qp_i; + u32 qp_p; + u32 qp_b; +}; + +struct enc_aux_buffer_size_info { + int width; + int height; + enum aux_buffer_type type; + enum mirror_direction mirror_direction; + int rotation_angle; +}; + +struct enc_scaler_info { + bool enable; + int width; + int height; + int coef_mode; +}; + +struct enc_codec_param { + u32 internal_bit_depth; + u32 decoding_refresh_type; + u32 idr_period; + u32 intra_period; + u32 gop_preset_idx; + u32 frame_rate; + u32 bitrate; + u32 cpb_size; + u32 hvs_qp_scale_div2; + u32 max_delta_qp; + int rc_initial_qp; + u32 rc_update_speed; + u32 max_bitrate; + u32 rc_mode; + u32 rc_initial_level; + u32 pic_rc_max_dqp; + u32 bg_th_diff; + u32 bg_th_mean_diff; + int bg_delta_qp; + u32 intra_refresh_mode; + u32 intra_refresh_arg; + int beta_offset_div2; + int tc_offset_div2; + u32 qp; + u32 min_qp_i; + u32 max_qp_i; + u32 min_qp_p; + u32 max_qp_p; + u32 min_qp_b; + u32 max_qp_b; + int cb_qp_offset; + int cr_qp_offset; + u32 q_round_intra; + u32 q_round_inter; + int lambda_dqp_intra; + int lambda_dqp_inter; + u32 slice_mode; + u32 slice_arg; + u32 level; + u32 tier; + u32 profile; + struct vpu_rect conf_win; + u32 forced_idr_header; + u16 custom_lambda_ssd[MAX_CUSTOM_LAMBDA_NUM]; + u16 custom_lambda_sad[MAX_CUSTOM_LAMBDA_NUM]; + struct custom_gop_param gop_param; + struct temporal_layer_param temp_layer[MAX_NUM_CHANGEABLE_TEMPORAL_LAYER]; + u32 temp_layer_cnt; + u32 report_mv_histo_threshold0; + u32 report_mv_histo_threshold1; + u32 report_mv_histo_threshold2; + u32 report_mv_histo_threshold3; + enum endian_mode custom_map_endian; + u32 num_units_in_tick; + u32 time_scale; + u32 num_ticks_poc_diff_one; + struct color_param color; + struct sar_info sar; + u32 max_intra_pic_bit; + u32 max_inter_pic_bit; + u32 intra_4x4; + + u32 en_constrained_intra_pred: 1; + u32 en_long_term: 1; + u32 en_intra_trans_skip: 1; + u32 en_me_center: 1; + u32 en_rate_control: 1; + u32 en_transform8x8: 1; + u32 en_hvs_qp: 1; + u32 en_bg_detect: 1; + u32 en_temporal_mvp: 1; + u32 en_cabac: 1; + u32 en_dbk: 1; + u32 en_sao: 1; + u32 en_lf_cross_slice_boundary: 1; + u32 en_scaling_list: 1; + u32 en_adaptive_round: 1; + u32 en_qp_map: 1; + u32 en_mode_map: 1; + u32 en_q_round_offset: 1; + u32 en_still_picture: 1; + u32 en_strong_intra_smoothing: 1; + u32 en_custom_lambda: 1; + u32 en_report_mv_histo: 1; + u32 dis_coef_clear: 1; + u32 en_cu_level_rate_control: 1; + u32 en_vbv_overflow_drop_frame: 1; + u32 en_auto_level_adjusting: 1; +}; + +struct enc_open_param { + int pic_width; + int pic_height; + struct enc_codec_param codec_param; + enum cb_cr_order cbcr_order; + enum endian_mode stream_endian; + enum endian_mode source_endian; + bool line_buf_int_en; + enum packed_format_num packed_format; + enum frame_buffer_format src_format; + enum frame_buffer_format output_format; + bool enable_non_ref_fbc_write; + bool enc_hrd_rbsp_in_vps; + u32 hrd_rbsp_data_size; + dma_addr_t hrd_rbsp_data_addr; + u32 ext_addr_vcpu: 8; + bool is_secure_inst; + u32 inst_priority: 5; + struct instance_buffer inst_buffer; + bool enc_aud; +}; + +struct enc_initial_info { + u32 min_frame_buffer_count; + u32 min_src_frame_count; + u32 req_mv_buffer_count; + int max_latency_pictures; + int err_reason; + int warn_info; +}; + +struct enc_csc_param { + u32 format_order; + u32 coef_ry; + u32 coef_gy; + u32 coef_by; + u32 coef_rcb; + u32 coef_gcb; + u32 coef_bcb; + u32 coef_rcr; + u32 coef_gcr; + u32 coef_bcr; + u32 offset_y; + u32 offset_cb; + u32 offset_cr; +}; + +struct enc_param { + struct frame_buffer *source_frame; + bool skip_picture; + dma_addr_t pic_stream_buffer_addr; + int pic_stream_buffer_size; + bool force_pic_qp_enable; + int force_pic_qp_i; + int force_pic_qp_p; + int force_pic_qp_b; + bool force_pic_type_enable; + int force_pic_type; + int src_idx; + bool src_end; + u32 bitrate; + struct enc_csc_param csc; + struct timestamp_info timestamp; +}; + +struct enc_report_fme_sum { + u32 lower_x0; + u32 higher_x0; + u32 lower_y0; + u32 higher_y0; + u32 lower_x1; + u32 higher_x1; + u32 lower_y1; + u32 higher_y1; +}; + +struct enc_report_mv_histo { + u32 cnt0; + u32 cnt1; + u32 cnt2; + u32 cnt3; + u32 cnt4; +}; + +struct enc_output_info { + dma_addr_t bitstream_buffer; + u32 bitstream_size; + int bitstream_wrap_around; + int pic_type; + int num_of_slices; + int recon_frame_index; + struct frame_buffer recon_frame; + dma_addr_t rd_ptr; + dma_addr_t wr_ptr; + int pic_skipped; + int num_of_intra; + int num_of_merge; + int num_of_skip_block; + int avg_ctu_qp; + int enc_pic_byte; + int enc_gop_pic_idx; + int enc_pic_poc; + int enc_src_idx; + int enc_vcl_nut; + int enc_pic_cnt; + int error_reason; + int warn_info; + u32 pic_distortion_low; + u32 pic_distortion_high; + bool non_ref_pic; + bool encoding_success; + struct enc_report_fme_sum fme_sum; + struct enc_report_mv_histo mv_histo; + struct report_cycle cycle; + struct timestamp_info timestamp; + dma_addr_t src_y_addr; + dma_addr_t custom_map_addr; + dma_addr_t prefix_sei_nal_addr; + dma_addr_t suffix_sei_nal_addr; +}; + +enum gop_preset_idx { + PRESET_IDX_CUSTOM_GOP = 0, + PRESET_IDX_ALL_I = 1, + PRESET_IDX_IPP = 2, + PRESET_IDX_IBBB = 3, + PRESET_IDX_IBPBP = 4, + PRESET_IDX_IBBBP = 5, + PRESET_IDX_IPPPP = 6, + PRESET_IDX_IBBBB = 7, + PRESET_IDX_RA_IB = 8, + PRESET_IDX_IPP_SINGLE = 9, + PRESET_IDX_MAX, +}; + +struct enc_info { + struct enc_open_param open_param; + struct enc_initial_info initial_info; + int num_frame_buffers; + int stride; + bool rotation_enable; + bool mirror_enable; + enum mirror_direction mirror_direction; + int rotation_angle; + bool initial_info_obtained; + struct sec_axi_info sec_axi_info; + bool line_buf_int_en; + struct vpu_buf vb_mv[WAVE6_MAX_FBS]; + struct vpu_buf vb_fbc_y_tbl[WAVE6_MAX_FBS]; + struct vpu_buf vb_fbc_c_tbl[WAVE6_MAX_FBS]; + struct vpu_buf vb_sub_sam_buf[WAVE6_MAX_FBS]; + u32 cycle_per_tick; + u32 width; + u32 height; + struct enc_scaler_info scaler_info; + int color_format; +}; + +struct h264_enc_controls { + u32 profile; + u32 level; + u32 min_qp; + u32 max_qp; + u32 i_frame_qp; + u32 p_frame_qp; + u32 b_frame_qp; + u32 loop_filter_mode; + u32 loop_filter_beta; + u32 loop_filter_alpha; + u32 _8x8_transform; + u32 constrained_intra_prediction; + u32 chroma_qp_index_offset; + u32 entropy_mode; + u32 i_period; + u32 vui_sar_enable; + u32 vui_sar_idc; + u32 vui_ext_sar_width; + u32 vui_ext_sar_height; + u32 cpb_size; +}; + +struct hevc_enc_controls { + u32 profile; + u32 level; + u32 min_qp; + u32 max_qp; + u32 i_frame_qp; + u32 p_frame_qp; + u32 b_frame_qp; + u32 loop_filter_mode; + u32 lf_beta_offset_div2; + u32 lf_tc_offset_div2; + u32 refresh_type; + u32 refresh_period; + u32 const_intra_pred; + u32 strong_smoothing; + u32 tmv_prediction; +}; + +struct enc_controls { + u32 rot_angle; + u32 mirror_direction; + u32 bitrate; + u32 bitrate_mode; + u32 gop_size; + u32 frame_rc_enable; + u32 mb_rc_enable; + u32 slice_mode; + u32 slice_max_mb; + u32 prepend_spspps_to_idr; + u32 intra_refresh_period; + struct h264_enc_controls h264; + struct hevc_enc_controls hevc; + u32 force_key_frame; + u32 frame_skip_mode; +}; + +struct vpu_device { + struct device *dev; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *video_dev_dec; + struct video_device *video_dev_enc; + struct mutex dev_lock; /* the lock for the src,dst v4l2 queues */ + struct mutex hw_lock; /* lock hw configurations */ + int irq; + u32 fw_version; + u32 fw_revision; + u32 hw_version; + struct vpu_attr attr; + u32 last_performance_cycles; + void __iomem *reg_base; + struct device *ctrl; + int product_code; + struct vpu_buf temp_vbuf; + struct clk_bulk_data *clks; + int num_clks; + struct clk *clk_vpu; + struct completion irq_done; + struct kfifo irq_status; + struct delayed_work task_timer; + struct wave6_vpu_entity entity; + bool active; + int pause_request; + struct mutex pause_lock; /* the lock for the pause/resume m2m job. */ + const struct wave6_match_data *res; + struct dentry *debugfs; +}; + +struct vpu_instance; + +struct vpu_instance_ops { + int (*start_process)(struct vpu_instance *inst); + void (*finish_process)(struct vpu_instance *inst, bool error); +}; + +struct vpu_performance_info { + ktime_t ts_first; + ktime_t ts_last; + s64 latency_first; + s64 latency_max; + s64 min_process_time; + s64 max_process_time; + u64 total_sw_time; + u64 total_hw_time; +}; + +struct vpu_instance { + struct v4l2_fh v4l2_fh; + struct v4l2_ctrl_handler v4l2_ctrl_hdl; + struct vpu_device *dev; + + struct v4l2_pix_format_mplane src_fmt; + struct v4l2_pix_format_mplane dst_fmt; + struct v4l2_rect crop; + struct v4l2_rect codec_rect; + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + + enum vpu_instance_state state; + enum vpu_instance_state state_in_seek; + enum vpu_instance_type type; + const struct vpu_instance_ops *ops; + + enum codec_std std; + u32 id; + union { + struct enc_info enc_info; + struct dec_info dec_info; + } *codec_info; + struct frame_buffer frame_buf[WAVE6_MAX_FBS]; + struct vpu_buf frame_vbuf[WAVE6_MAX_FBS]; + u32 queued_src_buf_num; + u32 queued_dst_buf_num; + u32 processed_buf_num; + u32 error_buf_num; + u32 sequence; + bool next_buf_last; + bool cbcr_interleave; + bool nv21; + bool eos; + + struct vpu_buf aux_vbuf[AUX_BUF_TYPE_MAX][WAVE6_MAX_FBS]; + struct vpu_buf ar_vbuf; + bool thumbnail_mode; + enum display_mode disp_mode; + + unsigned int frame_rate; + struct enc_controls enc_ctrls; + struct dec_scaler_info scaler_info; + bool error_recovery; + + struct vpu_performance_info performance; + + struct dentry *debugfs; +}; + +void wave6_vdi_writel(struct vpu_device *vpu_device, unsigned int addr, unsigned int data); +unsigned int wave6_vdi_readl(struct vpu_device *vpu_dev, unsigned int addr); +unsigned int wave6_vdi_convert_endian(unsigned int endian); + +int wave6_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *pop); +int wave6_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res); +int wave6_vpu_dec_issue_seq_init(struct vpu_instance *inst); +int wave6_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info); +int wave6_vpu_dec_get_aux_buffer_size(struct vpu_instance *inst, + struct dec_aux_buffer_size_info info, + uint32_t *size); +int wave6_vpu_dec_register_aux_buffer(struct vpu_instance *inst, struct aux_buffer_info info); +int wave6_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_dec_fbs, + int stride, int height, int map_type); +int wave6_vpu_dec_register_display_buffer_ex(struct vpu_instance *inst, struct frame_buffer fb); +int wave6_vpu_dec_start_one_frame(struct vpu_instance *inst, struct dec_param *param, + u32 *res_fail); +int wave6_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info); +int wave6_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, bool update_wr_ptr); +int wave6_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter); +int wave6_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *p_rd_ptr, + dma_addr_t *p_wr_ptr); +int wave6_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, int size); +int wave6_vpu_dec_flush_instance(struct vpu_instance *inst); + +int wave6_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *enc_op_param); +int wave6_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res); +int wave6_vpu_enc_issue_seq_init(struct vpu_instance *inst); +int wave6_vpu_enc_issue_seq_change(struct vpu_instance *inst, bool *changed); +int wave6_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info); +int wave6_vpu_enc_get_aux_buffer_size(struct vpu_instance *inst, + struct enc_aux_buffer_size_info info, + uint32_t *size); +int wave6_vpu_enc_register_aux_buffer(struct vpu_instance *inst, struct aux_buffer_info info); +int wave6_vpu_enc_register_frame_buffer_ex(struct vpu_instance *inst, int num, unsigned int stride, + int height, enum tiled_map_type map_type); +int wave6_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, + u32 *fail_res); +int wave6_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info); +int wave6_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter); + +#endif /* __WAVE6_VPUAPI_H__ */ diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h b/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h new file mode 100644 index 000000000000..9078f3741644 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpuconfig.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - product config definitions + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VPUCONFIG_H__ +#define __WAVE6_VPUCONFIG_H__ + +#define WAVE617_CODE 0x6170 +#define WAVE627_CODE 0x6270 +#define WAVE633_CODE 0x6330 +#define WAVE637_CODE 0x6370 +#define WAVE663_CODE 0x6630 +#define WAVE677_CODE 0x6670 + +#define PRODUCT_CODE_W_SERIES(x) ({ \ + int c = x; \ + ((c) == WAVE617_CODE || (c) == WAVE627_CODE || \ + (c) == WAVE633_CODE || (c) == WAVE637_CODE || \ + (c) == WAVE663_CODE || (c) == WAVE677_CODE); \ +}) + +#define WAVE627ENC_WORKBUF_SIZE (512 * 1024) +#define WAVE637DEC_WORKBUF_SIZE (2 * 512 * 1024) +#define WAVE637DEC_WORKBUF_SIZE_FOR_CQ (3 * 512 * 1024) + +#define MAX_NUM_INSTANCE 32 + +#define W6_MAX_PIC_STRIDE (4096U * 4) +#define W6_DEF_DEC_PIC_WIDTH 720U +#define W6_DEF_DEC_PIC_HEIGHT 480U +#define W6_MIN_DEC_PIC_WIDTH 64U +#define W6_MIN_DEC_PIC_HEIGHT 64U +#define W6_MAX_DEC_PIC_WIDTH 4096U +#define W6_MAX_DEC_PIC_HEIGHT 4096U +#define W6_DEC_PIC_SIZE_STEP 1 + +#define W6_DEF_ENC_PIC_WIDTH 416U +#define W6_DEF_ENC_PIC_HEIGHT 240U +#define W6_MIN_ENC_PIC_WIDTH 256U +#define W6_MIN_ENC_PIC_HEIGHT 128U +#define W6_MAX_ENC_PIC_WIDTH 4096U +#define W6_MAX_ENC_PIC_HEIGHT 4096U +#define W6_ENC_PIC_SIZE_STEP 8 +#define W6_ENC_CROP_X_POS_STEP 32 +#define W6_ENC_CROP_Y_POS_STEP 2 +#define W6_ENC_CROP_STEP 2 + +#define W6_VPU_POLL_TIMEOUT 300000 +#define W6_BOOT_WAIT_TIMEOUT 10000 +#define W6_VPU_TIMEOUT 6000 +#define W6_VPU_TIMEOUT_CYCLE_COUNT (8000000 * 4 * 4) + +#define HOST_ENDIAN VDI_128BIT_LITTLE_ENDIAN +#define VPU_FRAME_ENDIAN HOST_ENDIAN +#define VPU_STREAM_ENDIAN HOST_ENDIAN +#define VPU_USER_DATA_ENDIAN HOST_ENDIAN +#define VPU_SOURCE_ENDIAN HOST_ENDIAN + +#define USE_SRC_PRP_AXI 0 +#define USE_SRC_PRI_AXI 1 +#define DEFAULT_SRC_AXI USE_SRC_PRP_AXI + +#define COMMAND_QUEUE_DEPTH (1) + +#define W6_REMAP_INDEX0 0 +#define W6_REMAP_INDEX1 1 +#define W6_REMAP_MAX_SIZE (1024 * 1024) + +#define WAVE6_ARBUF_SIZE (1024) +#define WAVE6_MAX_CODE_BUF_SIZE (4 * 1024 * 1024) +#define WAVE6_CODE_BUF_SIZE (1 * 1024 * 1024) +#define WAVE6_EXTRA_CODE_BUF_SIZE (256 * 1024) +#define WAVE6_TEMPBUF_SIZE (3 * 1024 * 1024) + +#define WAVE6_UPPER_PROC_AXI_ID 0x0 + +#endif /* __WAVE6_VPUCONFIG_H__ */ diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h b/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h new file mode 100644 index 000000000000..8bf2e1e9522d --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpuerror.h @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 vpu error values + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VPUERROR_H__ +#define __WAVE6_VPUERROR_H__ + +/* WAVE6 COMMON SYSTEM ERROR (FAIL_REASON) */ +#define WAVE6_SYSERR_QUEUEING_FAIL 0x00000001 +#define WAVE6_SYSERR_DECODER_FUSE 0x00000002 +#define WAVE6_SYSERR_INSTRUCTION_ACCESS_VIOLATION 0x00000004 +#define WAVE6_SYSERR_PRIVILEDGE_VIOLATION 0x00000008 +#define WAVE6_SYSERR_DATA_ADDR_ALIGNMENT 0x00000010 +#define WAVE6_SYSERR_DATA_ACCESS_VIOLATION 0x00000020 +#define WAVE6_SYSERR_ACCESS_VIOLATION_HW 0x00000040 +#define WAVE6_SYSERR_INSTRUCTION_ADDR_ALIGNMENT 0x00000080 +#define WAVE6_SYSERR_UNKNOWN 0x00000100 +#define WAVE6_SYSERR_BUS_ERROR 0x00000200 +#define WAVE6_SYSERR_DOUBLE_FAULT 0x00000400 +#define WAVE6_SYSERR_RESULT_NOT_READY 0x00000800 +#define WAVE6_SYSERR_VPU_STILL_RUNNING 0x00001000 +#define WAVE6_SYSERR_UNKNOWN_CMD 0x00002000 +#define WAVE6_SYSERR_UNKNOWN_CODEC_STD 0x00004000 +#define WAVE6_SYSERR_UNKNOWN_QUERY_OPTION 0x00008000 +#define WAVE6_SYSERR_WATCHDOG_TIMEOUT 0x00020000 +#define WAVE6_SYSERR_NOT_SUPPORT 0x00100000 +#define WAVE6_SYSERR_TEMP_SEC_BUF_OVERFLOW 0x00200000 +#define WAVE6_SYSERR_NOT_SUPPORT_PROFILE 0x00400000 +#define WAVE6_SYSERR_TIMEOUT_CODEC_FW 0x40000000 +#define WAVE6_SYSERR_FATAL_VPU_HANGUP 0xf0000000 + +/* WAVE6 COMMAND QUEUE ERROR (FAIL_REASON) */ +#define WAVE6_CMDQ_ERR_NOT_QUEABLE_CMD 0x00000001 +#define WAVE6_CMDQ_ERR_SKIP_MODE_ENABLE 0x00000002 +#define WAVE6_CMDQ_ERR_INST_FLUSHING 0x00000003 +#define WAVE6_CMDQ_ERR_INST_INACTIVE 0x00000004 +#define WAVE6_CMDQ_ERR_QUEUE_FAIL 0x00000005 +#define WAVE6_CMDQ_ERR_CMD_BUF_FULL 0x00000006 + +/* WAVE6 ERROR ON DECODER (ERR_INFO) */ +#define HEVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000 +#define HEVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001 +#define HEVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002 +#define HEVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003 +#define HEVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004 +#define HEVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005 +#define HEVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006 +#define HEVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007 +#define HEVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008 +#define HEVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009 +#define HEVC_SPSERR_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4 0x0000100A +#define HEVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B +#define HEVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C +#define HEVC_SPSERR_SPS_MAX_LATENCY_INCREASE 0x0000100D +#define HEVC_SPSERR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3 0x0000100E +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE 0x0000100F +#define HEVC_SPSERR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2 0x00001010 +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE 0x00001011 +#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER 0x00001012 +#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA 0x00001013 +#define HEVC_SPSERR_SCALING_LIST 0x00001014 +#define HEVC_SPSERR_LOG2_DIFF_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3 0x00001015 +#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE 0x00001016 +#define HEVC_SPSERR_NUM_SHORT_TERM_REF_PIC_SETS 0x00001017 +#define HEVC_SPSERR_NUM_LONG_TERM_REF_PICS_SPS 0x00001018 +#define HEVC_SPSERR_GBU_PARSING_ERROR 0x00001019 +#define HEVC_SPSERR_EXTENSION_FLAG 0x0000101A +#define HEVC_SPSERR_VUI_ERROR 0x0000101B +#define HEVC_SPSERR_ACTIVATE_SPS 0x0000101C +#define HEVC_SPSERR_PROFILE_SPACE 0x0000101D +#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000 +#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001 +#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002 +#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003 +#define HEVC_PPSERR_INIT_QP_MINUS26 0x00002004 +#define HEVC_PPSERR_DIFF_CU_QP_DELTA_DEPTH 0x00002005 +#define HEVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006 +#define HEVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007 +#define HEVC_PPSERR_NUM_TILE_COLUMNS_MINUS1 0x00002008 +#define HEVC_PPSERR_NUM_TILE_ROWS_MINUS1 0x00002009 +#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1 0x0000200A +#define HEVC_PPSERR_ROW_HEIGHT_MINUS1 0x0000200B +#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2 0x0000200C +#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2 0x0000200D +#define HEVC_PPSERR_SCALING_LIST 0x0000200E +#define HEVC_PPSERR_LOG2_PARALLEL_MERGE_LEVEL_MINUS2 0x0000200F +#define HEVC_PPSERR_NUM_TILE_COLUMNS_RANGE_OUT 0x00002010 +#define HEVC_PPSERR_NUM_TILE_ROWS_RANGE_OUT 0x00002011 +#define HEVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012 +#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013 +#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014 +#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015 +#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016 +#define HEVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017 +#define HEVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018 +#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1_RANGE_OUT 0x00002019 +#define HEVC_PPSERR_ROW_HEIGHT_MINUS1_RANGE_OUT 0x00002020 +#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2_RANGE_OUT 0x00002021 +#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2_RANGE_OUT 0x00002022 +#define HEVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000 +#define HEVC_SHERR_ACTIVATE_PPS 0x00003001 +#define HEVC_SHERR_ACTIVATE_SPS 0x00003002 +#define HEVC_SHERR_SLICE_TYPE 0x00003003 +#define HEVC_SHERR_FIRST_SLICE_IS_DEPENDENT_SLICE 0x00003004 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_SPS_FLAG 0x00003005 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET 0x00003006 +#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_IDX 0x00003007 +#define HEVC_SHERR_NUM_LONG_TERM_SPS 0x00003008 +#define HEVC_SHERR_NUM_LONG_TERM_PICS 0x00003009 +#define HEVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A +#define HEVC_SHERR_DELTA_POC_MSB_CYCLE_LT 0x0000300B +#define HEVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C +#define HEVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D +#define HEVC_SHERR_COLLOCATED_REF_IDX 0x0000300E +#define HEVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F +#define HEVC_SHERR_FIVE_MINUS_MAX_NUM_MERGE_CAND 0x00003010 +#define HEVC_SHERR_SLICE_QP_DELTA 0x00003011 +#define HEVC_SHERR_SLICE_QP_DELTA_IS_OUT_OF_RANGE 0x00003012 +#define HEVC_SHERR_SLICE_CB_QP_OFFSET 0x00003013 +#define HEVC_SHERR_SLICE_CR_QP_OFFSET 0x00003014 +#define HEVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015 +#define HEVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016 +#define HEVC_SHERR_NUM_ENTRY_POINT_OFFSETS 0x00003017 +#define HEVC_SHERR_OFFSET_LEN_MINUS1 0x00003018 +#define HEVC_SHERR_SLICE_SEGMENT_HEADER_EXTENSION_LENGTH 0x00003019 +#define HEVC_SHERR_WRONG_POC_IN_STILL_PICTURE_PROFILE 0x0000301A +#define HEVC_SHERR_SLICE_TYPE_ERROR_IN_STILL_PICTURE_PROFILE 0x0000301B +#define HEVC_SHERR_PPS_ID_NOT_EQUAL_PREV_VALUE 0x0000301C +#define HEVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000 +#define HEVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001 +#define HEVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002 +#define HEVC_SPECERR_OVER_BIT_DEPTH 0x00004003 +#define HEVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004 +#define HEVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005 +#define HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000 +#define HEVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001 +#define HEVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002 +#define HEVC_ETCERR_INPLACE_V 0x0000500F + +#define AVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000 +#define AVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001 +#define AVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002 +#define AVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003 +#define AVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004 +#define AVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005 +#define AVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006 +#define AVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007 +#define AVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008 +#define AVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009 +#define AVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B +#define AVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C +#define AVC_SPSERR_SCALING_LIST 0x00001014 +#define AVC_SPSERR_GBU_PARSING_ERROR 0x00001019 +#define AVC_SPSERR_VUI_ERROR 0x0000101B +#define AVC_SPSERR_ACTIVATE_SPS 0x0000101C +#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000 +#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001 +#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002 +#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003 +#define AVC_PPSERR_INIT_QP_MINUS26 0x00002004 +#define AVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006 +#define AVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007 +#define AVC_PPSERR_SCALING_LIST 0x0000200E +#define AVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012 +#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013 +#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014 +#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015 +#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016 +#define AVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017 +#define AVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018 +#define AVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000 +#define AVC_SHERR_ACTIVATE_PPS 0x00003001 +#define AVC_SHERR_ACTIVATE_SPS 0x00003002 +#define AVC_SHERR_SLICE_TYPE 0x00003003 +#define AVC_SHERR_FIRST_MB_IN_SLICE 0x00003004 +#define AVC_SHERR_RPLM 0x00003006 +#define AVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A +#define AVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C +#define AVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D +#define AVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F +#define AVC_SHERR_SLICE_QP_DELTA 0x00003011 +#define AVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015 +#define AVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016 +#define AVC_SHERR_DISABLE_DEBLOCK_FILTER_IDC 0x00003017 +#define AVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000 +#define AVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001 +#define AVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002 +#define AVC_SPECERR_OVER_BIT_DEPTH 0x00004003 +#define AVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004 +#define AVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005 +#define AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000 +#define AVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001 +#define AVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002 +#define AVC_ETCERR_ASO 0x00005004 +#define AVC_ETCERR_FMO 0x00005005 +#define AVC_ETCERR_INPLACE_V 0x0000500F + +/* WAVE6 WARNING ON DECODER (WARN_INFO) */ +#define HEVC_SPSWARN_MAX_SUB_LAYERS_MINUS1 0x00000001 +#define HEVC_SPSWARN_GENERAL_RESERVED_ZERO_44BITS 0x00000002 +#define HEVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004 +#define HEVC_SPSWARN_SUB_LAYER_RESERVED_ZERO_44BITS 0x00000008 +#define HEVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010 +#define HEVC_SPSWARN_SPS_MAX_DEC_PIC_BUFFERING_VALUE_OVER 0x00000020 +#define HEVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040 +#define HEVC_SPSWARN_ST_RPS_UE_ERROR 0x00000080 +#define HEVC_SPSWARN_EXTENSION_FLAG 0x01000000 +#define HEVC_SPSWARN_REPLACED_WITH_PREV_SPS 0x02000000 +#define HEVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100 +#define HEVC_PPSWARN_REPLACED_WITH_PREV_PPS 0x00000200 +#define HEVC_SHWARN_FIRST_SLICE_SEGMENT_IN_PIC_FLAG 0x00001000 +#define HEVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000 +#define HEVC_SHWARN_PIC_OUTPUT_FLAG 0x00004000 +#define HEVC_SHWARN_DUPLICATED_SLICE_SEGMENT 0x00008000 +#define HEVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000 +#define HEVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000 +#define HEVC_ETCWARN_WRONG_TEMPORAL_ID 0x00040000 +#define HEVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000 +#define HEVC_SPECWARN_OVER_PROFILE 0x00100000 +#define HEVC_SPECWARN_OVER_LEVEL 0x00200000 +#define HEVC_PRESWARN_PARSING_ERR 0x04000000 +#define HEVC_PRESWARN_MVD_OUT_OF_RANGE 0x08000000 +#define HEVC_PRESWARN_CU_QP_DELTA_VAL_OUT_OF_RANGE 0x09000000 +#define HEVC_PRESWARN_COEFF_LEVEL_REMAINING_OUT_OF_RANGE 0x0A000000 +#define HEVC_PRESWARN_PCM_ERR 0x0B000000 +#define HEVC_PRESWARN_OVERCONSUME 0x0C000000 +#define HEVC_PRESWARN_END_OF_SUBSET_ONE_BIT_ERR 0x10000000 +#define HEVC_PRESWARN_END_OF_SLICE_SEGMENT_FLAG 0x20000000 + +#define AVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004 +#define AVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010 +#define AVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040 +#define AVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100 +#define AVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000 +#define AVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000 +#define AVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000 +#define AVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000 +#define AVC_SPECWARN_OVER_PROFILE 0x00100000 +#define AVC_SPECWARN_OVER_LEVEL 0x00200000 +#define AVC_PRESWARN_MVD_RANGE_OUT 0x00400000 +#define AVC_PRESWARN_MB_QPD_RANGE_OUT 0x00500000 +#define AVC_PRESWARN_COEFF_RANGE_OUT 0x00600000 +#define AVC_PRESWARN_MV_RANGE_OUT 0x00700000 +#define AVC_PRESWARN_MB_SKIP_RUN_RANGE_OUT 0x00800000 +#define AVC_PRESWARN_MB_TYPE_RANGE_OUT 0x00900000 +#define AVC_PRESWARN_SUB_MB_TYPE_RANGE_OUT 0x00A00000 +#define AVC_PRESWARN_CBP_RANGE_OUT 0x00B00000 +#define AVC_PRESWARN_INTRA_CHROMA_PRED_MODE_RANGE_OUT 0x00C00000 +#define AVC_PRESWARN_REF_IDX_RANGE_OUT 0x00D00000 +#define AVC_PRESWARN_COEFF_TOKEN_RANGE_OUT 0x00E00000 +#define AVC_PRESWARN_TOTAL_ZERO_RANGE_OUT 0x00F00000 +#define AVC_PRESWARN_RUN_BEFORE_RANGE_OUT 0x01000000 +#define AVC_PRESWARN_OVERCONSUME 0x01100000 +#define AVC_PRESWARN_MISSING_SLICE 0x01200000 + +/* WAVE6 WARNING ON ENCODER (WARN_INFO) */ +#define WAVE6_ETCWARN_FORCED_SPLIT_BY_CU8X8 0x000000001 + +#endif /* __WAVE6_VPUERROR_H__ */ From patchwork Mon Feb 10 09:07:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967503 Received: from SE2P216CU007.outbound.protection.outlook.com (mail-koreacentralazon11021140.outbound.protection.outlook.com [40.107.42.140]) (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 24BE01C5F1B; Mon, 10 Feb 2025 09:07:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.42.140 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178471; cv=fail; b=PXF6/t0apZKwR1jQIYHDoeCaTF/uY7k0Nqsz1musmPtKgWYLjs09lH5qbrLGGFfpO6/u+lW61W1W9nF5DrnMi+iO0X9G9K+6ebpmnSctG8jS0SSgfVuTcc4D50OrKZ3zmhjW1rAV6iwhJ1j6KWMxZ/OHFPcRd21iI3E1C1nz4PI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178471; c=relaxed/simple; bh=VZPStha1B1C6vG3Aj4sHnIEkIAUK+Sd8GHuzSArdX+8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=MLT0vMHYBztnE0vcD6LQf6i+WKY4o6n+rgDOrHR+mdjyW33a8jOKCvR5jPElc6BiL7wcsL4rslZMN9FobNdU9ST0T8FpvBG0IcNRw4bJ4AHmZ9OKYZROjAAeGOjqjozHhJ8SLb0AlLo7F6ssnjiOZ4d3WYcmOKOv/1Afe3XxSf8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=GobkFfGB; arc=fail smtp.client-ip=40.107.42.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="GobkFfGB" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=XLTdorCAiKGaQGleOMzLs+Iruy/2kapW52o1fkjpqoLuIlLhlW71ufgACmj6ncuU6zpOi600K85OGNwWfzZPoYzjRPpKyYztxNokc3Bk0bczFbu7mBaenqzZevFngM4k8C9f0R12hSgHmu27+Ndo4+H32k04VP6gUQhao3hXp9xEtH36qnurnNLdpj1j9A7hH2NLn6xFImtm3neUDVIvIyTeFWRZlZg5dfkKSrV/ID+AfxpJgb1w+LTkVfRoE3Q5OuDfSwVz2AlGdRSyH9giqRxEHz6X0Bs+H20XzxOhnjyNVkg7dIapdsH/Szn5wv+lRhaO9UDWT9Xv/36uL7kL/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=bQH4kYKtrUZjcO5i91V4ihay/qEdlDytmqfWXXoUD8k=; b=cZ/pn2mdfnkK3m4QIvh1ewMTm3BKOYrFzfMWzRE07qerrAczVk3XsNCbE6Jdv5DtXuYpMGKKw79GUqXkIqRG74oa9RY2DrLyK/5vpnRig7/w39MEuufaA1EE6okhv2tIhDVjo78Ct0YaT13lT9bp+QXSNQbuvkqqFRAQ5JIW28K8Vzcep+ghpAvIFkVlvIn1jn/E9whgD3aDZzOsAn3uyBEYsVS0TQv/bHIzAT+tKxmvb7gKcr2bj03pMa+XwXZfctGhfXCRyJRaoOUvrLhMqxjvKtzyBDlPpwk4rfGA0DI/xUCnvxeqBr3XifaWTiVlf1fkUlzkfbnFS57Tp5XhOA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bQH4kYKtrUZjcO5i91V4ihay/qEdlDytmqfWXXoUD8k=; b=GobkFfGBc87oIsVEmwXPYZIm+1mcwP5V2oCICFLvNaJTi+YLrBFAofCII4M5EX+ILa7cwPCW6CaZCrcbMR3ZvJGLjjKrKNUozPwYvSHP8KIXfHrcKORstRxVI3hhakSmYfcQ7+vCtrZh0by7YJSZHwuOjAmRgXsqVGFZpQ/JViA= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:38 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:38 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 7/8] media: chips-media: wave6: Add Wave6 control driver Date: Mon, 10 Feb 2025 18:07:24 +0900 Message-Id: <20250210090725.4580-8-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: 86dd117d-5e98-488b-67a2-08dd49b25d62 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: +uPDfhzWa1RRQcQG1eggMJhOhO1ug/y2xBeMMlvH2hL6mbEb8YV6QsIvoOLd2EspIodvSBZsf1WkrJ0jiU+BhIHV3jr2MZGXKLclEYdL5z68OihpoM+WBJF/yXlIDxfF1Xicb/JFZ2JMYMi7IAeqHkJowQ57RbKJQ6s9nrpgP9s5trVH+sXviGMxataCT/IfCGcFkOs9SBrys91LvKGRC8tN7aU3yZuLJK/r/BfdsQhbJdq+boaKIHz+/nlXrZ0K5WvFEGjiZj8wkHYNKMblalAV4gj9NwJ3o94F5JOZb0AWlr6yIkINphYF6uNuYkZlOaKmhuIMTX+MWijptDnAVLqiWd9HFbnjmN4kyQ/VeB7w3kym0SjBa+MauIjp2+RhhuY2RQU9+AX2cyUPVlJKGkeTirrHw/3YKxk3JK9J8Ml06mRN6ZGXQOZPodoc7pfFd+aO7TCTTFhd3lDH89ECfMZe1ueLRNROCn9L6g7e85QRk6hlw5h5Z7eK7SFikLe48I42U1IwUMwgvIwYzZKr7pZg2Sr3rmPGTpJHpa59qArfxuQAenWIIinjgX/0oHOE5Wk7Qe0VWTft6ZZ/6Vn+BnjpQFl7NT2cEnL9lSVxYwXybOoGuNvpAyTmCsHajgLYtgZq98mKFgc8B+DzYAjvOMLvPMOPrReWrFE/6FYaXGOOek/YfK3olno2ukHM1GDUVGNU4ltKr04qBSk58cyukLylILlUSM5Ubu7xnyTVtqCAZ6NJ6BBBNfNSGLVHkhkAdgEyjGnDKUnSlq4d88g9csjYpalzicsXs/79iHtif0dlpFB+Mq+tPgPPpxwPSXh9LkrB8TOPJg/Nj/b8PW84sG+3KYwu4Qwp7jRoyjESi1Atu8pUdKTiRSyI5rEN5dZmDptAtQtfurKbNORVjihHw62yUO7+jxM2RX5+N1lh3GA447TthXJ25EPrNkv2ssTemdh6aOZ35Cqj3FMgTRtljSNOJmOdj4jbBGbqchWa5MtosJ0hOv/l7BOt8BClqj/ze+lXJ5NN651Uczf7Pk28xmlAEaDJV2ROI8hQI200lPHFX0yoon06PViTzY7LOlHqnnyodok8nEaRM6+vQNROkRC3pMSRZaypVFI5WzHUSIqdMzEl08kU+rqcCP5PSDS86zgQTHHTiU92rbXKPLrjY+aO9yWsZZaX4UBQPxP18wOymwD6lmwlJtP8JAl5ybw0FNw1fD1d6VtvfRjFmznl/e1yUoTKhjwHGKcGmqjyRIg9NRXfnZpK4W17CArN2oWAbvOyUmZP+F+S9dDvZ1BgRgK/RmZqMGOtInSEXMhdXxpon9vTjEAQC9P6Br5zgHRTBY90cBfMrfpoVViDZHL4K6qgpAz0oqWusBUq0s07NmDF5ABGKQrWmCBVFRxxtlvEdsBYi18Ci7wisQUJHunWbICeUyk6++YxNPLFRs4cBXc7o5N1G4SKDzJdWX/FR0+s X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: q2tgQC+ntlkkwLFt6LlFVckbCLb2ufm9kGDw1yTmNx2vv3gJKldzIEEGCPCOBtwnL1iEQ5YJxbrkVL5qus0aAO6uuFf06P286livbM36J3DL4r72mym8ByhItJAH25djUvukghE2DN6wtQojx1xpBOrAJAXkslB2exAYmnyS0tEwGiXZpcrlqzdn3ZTtNRgVcFLlX+/xRlK3Hi9XjpU05j3TQAJl0LHGrt7TlURDv8vJzganoNXGPSpR942EBCMkLZ+Yq6mrT2qQA5pzth/PuEGg6L5fWZ27maAxY+51C/uMVcbkGOkBk9Oyd1uFif7fWZFlp/nBeH/eEM1KGRXwz4WMoxbWKlkh0u5Eqr5l+f9AM54bPyH1gtlppmDCHXTn5wAc4mRFGjBz7HGNMy1z86tvg4n4K+nDzf9vTGZaNlv0CJbM/QpJ7dHPV/hp2U/9gMT5i77ySsLTRZsoUeCYGQzobQ0IiSIdOxRhi7+jyiI1r1+t0Xoiu6xYdEQ5wkh7KFiP8d+5yIaJ/iU4me9zIKJ1o9jdSTciQxq/LiDJhvj+h1mtCFYKpIwUY5U5exSRefw3Kxv/F/O3JgM5yRRli9TDBBM0phPkWqRcrq4N5e0IlOwO8Yf363wg1UEm+4I5xv1t0SXFyu7AUXyXf31/WItHWCI3YQWqp90yh8iB1Nx9d6l8XSK9ceXZjDzp8R+PHNUDVlmw6ml5XEL7FCl+lbEoEu1Wxzkh2aE3y3yVncg+KDHJqdMn9bVXzQ+7ssC6HS4QK7TGrlSih0FswS/gp+i/GBYXuRcMHjHJIkzXTkLkYpQGATpEXr7F86kaemMJRj6RSAxQS8H4/u5bira9UOmc5srkTNz31WCu5ui3jVlXXQ9UQn8lyhHOAbvuuyqKcasxNVPLThp6BWhag1oyvha0Q97+YFQJSqa9RXhhMPCnih7xKJxGSfJMTZinRTUnVtc/Fhp+UiHlWXc7HtVwSVvjncNcLvPHZB1giEamxByrNkwsoazgjHVytH54lvEx8tnkjKXTiNrX7AqseCcUGp+BZbzttV7d28VaXMr26GsA/bZ74m/3qSTrHaxyiTNKQaExkFi1e+scxY1C15P5C6r6nAlS6UarAzZxTeybnN+GQZrXole9/M2h3+zyRLrzkvVrRoIYPf7gUFnaxH2ZBSk9pngHI2y2e5VLIyRe12CWDP+GL/kYZjU2/linv6qwbrD5dYqp9WWagsUhl+RWeHatdEGcR2Rz/wWE2yB0ss4LqGyvbwgI/D/iEmACblXr8tXgOvERRYjWiW+amTY43CojRdYYDN9lGZxLlvnJH1poLDwwHeIM2IBZW9ATBfEgazApJKL0FoYmp62k/W/6biYxzX0DwCd4gSJjsHfRssueer6AB+yrHxyFnWQ+cV69GYGSjgtZsNYZ6t1qFnJ1YYsm/II/mGkcgWdsj8tMKahltRhz0emi1SOpM98/Cf4D2DvhBsiUi/qnB72JIUuli/Il/cUDOQOgmtAVIJ5Hww47/qtXpk198END4i7Rn47/g7yb+B9H7FL0HCBhorXLLcarpvnDo4Bjxoq8/k/w6p0MO5xmufrTuP/pWvUZ5piUOIcNPW+VWeYOpW5SDQ3d2A== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 86dd117d-5e98-488b-67a2-08dd49b25d62 X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:38.0824 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: NFnJev1Ee5e9y0kDlWelCqAbjmyTiw+eFpSv1lR0shh9GqTiK8qqBsJgXb+T2ikqwA6RnWbdEzF+vnYBA5JC+O7j38SEHtM3c+W3aWTGFWc= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 Chips&Media Wave6 control driver. The control driver manages shared resources such as firmware access and power domains and clock. Signed-off-by: Nas Chung --- .../chips-media/wave6/wave6-vpu-ctrl.c | 1020 +++++++++++++++++ .../chips-media/wave6/wave6-vpu-ctrl.h | 38 + 2 files changed, 1058 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c new file mode 100644 index 000000000000..fa7bf5ccc0d0 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.c @@ -0,0 +1,1020 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - wave6 control driver + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wave6-vpuconfig.h" +#include "wave6-regdefine.h" +#include "wave6-vdi.h" +#include "wave6-vpu-ctrl.h" + +#define VPU_CTRL_PLATFORM_DEVICE_NAME "wave6-vpu-ctrl" + +static unsigned int debug; +module_param(debug, uint, 0644); + +static bool wave6_cooling_disable; +module_param(wave6_cooling_disable, bool, 0644); +MODULE_PARM_DESC(wave6_cooling_disable, "enable or disable cooling"); + +#define dprintk(dev, fmt, arg...) \ + do { \ + if (debug) \ + dev_info(dev, fmt, ## arg); \ + } while (0) + +#define wave6_wait_event_freezable_timeout(wq_head, condition, timeout) \ +({ \ + int wave6_wait_ret = 0; \ + unsigned long _timeout = timeout; \ + unsigned long stop; \ + stop = jiffies + _timeout; \ + do { \ + if (wave6_wait_ret == -ERESTARTSYS && freezing(current)) \ + clear_thread_flag(TIF_SIGPENDING); \ + _timeout = stop - jiffies; \ + if ((long)_timeout <= 0) { \ + wave6_wait_ret = -ERESTARTSYS; \ + break; \ + } \ + wave6_wait_ret = wait_event_freezable_timeout(wq_head, condition, _timeout); \ + } while (wave6_wait_ret == -ERESTARTSYS && freezing(current)); \ + wave6_wait_ret; \ +}) + +struct vpu_ctrl_resource { + const char *fw_name; + u32 sram_size; +}; + +struct vpu_ctrl_buf { + struct list_head list; + struct vpu_buf buf; +}; + +struct vpu_ctrl { + struct device *dev; + void __iomem *reg_base; + struct clk_bulk_data *clks; + int num_clks; + struct vpu_dma_buf boot_mem; + u32 state; + struct mutex ctrl_lock; /* the lock for vpu control device */ + struct wave6_vpu_entity *current_entity; + struct list_head entities; + const struct vpu_ctrl_resource *res; + struct gen_pool *sram_pool; + struct vpu_dma_buf sram_buf; + struct list_head buffers; + bool support_follower; + wait_queue_head_t load_fw_wq; + int thermal_event; + int thermal_max; + struct thermal_cooling_device *cooling; + struct dev_pm_domain_list *pd_list; + struct device *dev_perf; + int clk_id; + unsigned long *freq_table; +}; + +#define DOMAIN_VPU_PWR 0 +#define DOMAIN_VPU_PERF 1 + +static const struct vpu_ctrl_resource wave633c_ctrl_data = { + .fw_name = "wave633c_codec_fw.bin", + /* For HEVC, AVC, 4096x4096, 8bit */ + .sram_size = 0x14800, +}; + +static void wave6_vpu_ctrl_writel(struct device *dev, u32 addr, u32 data) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + + writel(data, ctrl->reg_base + addr); +} + +int wave6_alloc_dma(struct device *dev, struct vpu_buf *vb) +{ + void *vaddr; + dma_addr_t daddr; + + if (!vb || !vb->size) + return -EINVAL; + + vaddr = dma_alloc_coherent(dev, vb->size, &daddr, GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + + vb->vaddr = vaddr; + vb->daddr = daddr; + vb->dev = dev; + + return 0; +} +EXPORT_SYMBOL_GPL(wave6_alloc_dma); + +void wave6_free_dma(struct vpu_buf *vb) +{ + if (!vb || !vb->size || !vb->vaddr) + return; + + dma_free_coherent(vb->dev, vb->size, vb->vaddr, vb->daddr); + memset(vb, 0, sizeof(*vb)); +} +EXPORT_SYMBOL_GPL(wave6_free_dma); + +static const char *wave6_vpu_ctrl_state_name(u32 state) +{ + switch (state) { + case WAVE6_VPU_STATE_OFF: + return "off"; + case WAVE6_VPU_STATE_PREPARE: + return "prepare"; + case WAVE6_VPU_STATE_ON: + return "on"; + case WAVE6_VPU_STATE_SLEEP: + return "sleep"; + default: + return "unknown"; + } +} + +static void wave6_vpu_ctrl_set_state(struct vpu_ctrl *ctrl, u32 state) +{ + dprintk(ctrl->dev, "set state: %s -> %s\n", + wave6_vpu_ctrl_state_name(ctrl->state), wave6_vpu_ctrl_state_name(state)); + ctrl->state = state; +} + +static int wave6_vpu_ctrl_wait_busy(struct wave6_vpu_entity *entity) +{ + u32 val; + + return read_poll_timeout(entity->read_reg, val, !val, + 10, W6_VPU_POLL_TIMEOUT, false, + entity->dev, W6_VPU_BUSY_STATUS); +} + +static int wave6_vpu_ctrl_check_result(struct wave6_vpu_entity *entity) +{ + if (entity->read_reg(entity->dev, W6_RET_SUCCESS)) + return 0; + + return entity->read_reg(entity->dev, W6_RET_FAIL_REASON); +} + +static u32 wave6_vpu_ctrl_get_code_buf_size(struct vpu_ctrl *ctrl) +{ + return min_t(u32, ctrl->boot_mem.size, WAVE6_MAX_CODE_BUF_SIZE); +} + +static void wave6_vpu_ctrl_remap_code_buffer(struct vpu_ctrl *ctrl) +{ + dma_addr_t code_base = ctrl->boot_mem.dma_addr; + u32 i, reg_val, remap_size; + + for (i = 0; i < wave6_vpu_ctrl_get_code_buf_size(ctrl) / W6_REMAP_MAX_SIZE; i++) { + remap_size = (W6_REMAP_MAX_SIZE >> 12) & 0x1ff; + reg_val = 0x80000000 | + (WAVE6_UPPER_PROC_AXI_ID << 20) | + (0 << 16) | + (i << 12) | + BIT(11) | + remap_size; + wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_CTRL_GB, reg_val); + wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_VADDR_GB, i * W6_REMAP_MAX_SIZE); + wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_PADDR_GB, + code_base + i * W6_REMAP_MAX_SIZE); + } +} + +static int wave6_vpu_ctrl_init_vpu(struct vpu_ctrl *ctrl) +{ + struct wave6_vpu_entity *entity = ctrl->current_entity; + int ret; + + dprintk(ctrl->dev, "cold boot vpu\n"); + + entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1); + entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0, + ctrl->sram_buf.dma_addr); + entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0, + ctrl->sram_buf.size); + wave6_vpu_ctrl_writel(ctrl->dev, W6_COMMAND_GB, W6_CMD_INIT_VPU); + wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_CORE_START_GB, 1); + + ret = wave6_vpu_ctrl_wait_busy(entity); + if (ret) { + dev_err(ctrl->dev, "init vpu timeout\n"); + return -EINVAL; + } + + ret = wave6_vpu_ctrl_check_result(entity); + if (ret) { + dev_err(ctrl->dev, "init vpu fail, reason 0x%x\n", ret); + return -EIO; + } + + return 0; +} + +static void wave6_vpu_ctrl_on_boot(struct wave6_vpu_entity *entity) +{ + if (!entity->on_boot) + return; + + if (!entity->booted) { + entity->on_boot(entity->dev); + entity->booted = true; + } +} + +static void wave6_vpu_ctrl_clear_firmware_buffers(struct vpu_ctrl *ctrl, + struct wave6_vpu_entity *entity) +{ + int ret; + + dprintk(ctrl->dev, "clear firmware work buffers\n"); + + entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1); + entity->write_reg(entity->dev, W6_COMMAND, W6_CMD_INIT_WORK_BUF); + entity->write_reg(entity->dev, W6_VPU_HOST_INT_REQ, 1); + + ret = wave6_vpu_ctrl_wait_busy(entity); + if (ret) { + dev_err(ctrl->dev, "set buffer failed\n"); + return; + } + + ret = wave6_vpu_ctrl_check_result(entity); + if (ret) { + dev_err(ctrl->dev, "set buffer failed, reason 0x%x\n", ret); + return; + } +} + +int wave6_vpu_ctrl_require_buffer(struct device *dev, struct wave6_vpu_entity *entity) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + struct vpu_ctrl_buf *pbuf; + u32 size; + int ret = -ENOMEM; + + if (!ctrl || !entity) + return -EINVAL; + + size = entity->read_reg(entity->dev, W6_CMD_SET_CTRL_WORK_BUF_SIZE); + if (!size) + return 0; + + pbuf = kzalloc(sizeof(*pbuf), GFP_KERNEL); + if (!pbuf) + goto exit; + + pbuf->buf.size = size; + ret = wave6_alloc_dma(ctrl->dev, &pbuf->buf); + if (ret) { + kfree(pbuf); + goto exit; + } + + list_add_tail(&pbuf->list, &ctrl->buffers); + entity->write_reg(entity->dev, W6_CMD_SET_CTRL_WORK_BUF_ADDR, pbuf->buf.daddr); +exit: + entity->write_reg(entity->dev, W6_CMD_SET_CTRL_WORK_BUF_SIZE, 0); + return ret; +} +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_require_buffer); + +static void wave6_vpu_ctrl_clear_buffers(struct vpu_ctrl *ctrl) +{ + struct wave6_vpu_entity *entity; + struct vpu_ctrl_buf *pbuf, *tmp; + + dprintk(ctrl->dev, "clear all buffers\n"); + + entity = list_first_entry_or_null(&ctrl->entities, + struct wave6_vpu_entity, list); + if (entity) + wave6_vpu_ctrl_clear_firmware_buffers(ctrl, entity); + + list_for_each_entry_safe(pbuf, tmp, &ctrl->buffers, list) { + list_del(&pbuf->list); + wave6_free_dma(&pbuf->buf); + kfree(pbuf); + } +} + +static void wave6_vpu_ctrl_boot_done(struct vpu_ctrl *ctrl, int wakeup) +{ + struct wave6_vpu_entity *entity; + + if (ctrl->state == WAVE6_VPU_STATE_ON) + return; + + if (!wakeup) + wave6_vpu_ctrl_clear_buffers(ctrl); + + list_for_each_entry(entity, &ctrl->entities, list) + wave6_vpu_ctrl_on_boot(entity); + + dprintk(ctrl->dev, "boot done from %s\n", wakeup ? "wakeup" : "cold boot"); + + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_ON); +} + +static bool wave6_vpu_ctrl_find_entity(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity) +{ + struct wave6_vpu_entity *tmp; + + list_for_each_entry(tmp, &ctrl->entities, list) { + if (tmp == entity) + return true; + } + + return false; +} + +static void wave6_vpu_ctrl_load_firmware(const struct firmware *fw, void *context) +{ + struct vpu_ctrl *ctrl = context; + struct wave6_vpu_entity *entity = ctrl->current_entity; + u32 product_code; + int ret; + + ret = pm_runtime_resume_and_get(ctrl->dev); + if (ret) { + dev_err(ctrl->dev, "pm runtime resume fail, ret = %d\n", ret); + mutex_lock(&ctrl->ctrl_lock); + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + ctrl->current_entity = NULL; + mutex_unlock(&ctrl->ctrl_lock); + release_firmware(fw); + return; + } + + if (!fw || !fw->data) { + dev_err(ctrl->dev, "No firmware.\n"); + ret = -EINVAL; + goto exit; + } + + if (fw->size + WAVE6_EXTRA_CODE_BUF_SIZE > wave6_vpu_ctrl_get_code_buf_size(ctrl)) { + dev_err(ctrl->dev, "firmware size (%ld > %zd) is too big\n", + fw->size, ctrl->boot_mem.size); + ret = -EINVAL; + goto exit; + } + + product_code = entity->read_reg(entity->dev, W6_VPU_RET_PRODUCT_VERSION); + if (!PRODUCT_CODE_W_SERIES(product_code)) { + dev_err(ctrl->dev, "unknown product : %08x\n", product_code); + ret = -EINVAL; + goto exit; + } + + memcpy(ctrl->boot_mem.vaddr, fw->data, fw->size); + +exit: + mutex_lock(&ctrl->ctrl_lock); + if (!ret && wave6_vpu_ctrl_find_entity(ctrl, ctrl->current_entity)) { + wave6_vpu_ctrl_remap_code_buffer(ctrl); + ret = wave6_vpu_ctrl_init_vpu(ctrl); + } else { + ret = -EINVAL; + } + mutex_unlock(&ctrl->ctrl_lock); + + pm_runtime_put_sync(ctrl->dev); + release_firmware(fw); + + mutex_lock(&ctrl->ctrl_lock); + ctrl->current_entity = NULL; + if (ret) + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + else + wave6_vpu_ctrl_boot_done(ctrl, 0); + mutex_unlock(&ctrl->ctrl_lock); + + wake_up_interruptible_all(&ctrl->load_fw_wq); +} + +static int wave6_vpu_ctrl_sleep(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity) +{ + int ret; + + dprintk(ctrl->dev, "sleep firmware\n"); + + entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1); + entity->write_reg(entity->dev, W6_CMD_INSTANCE_INFO, 0); + entity->write_reg(entity->dev, W6_COMMAND, W6_CMD_SLEEP_VPU); + entity->write_reg(entity->dev, W6_VPU_HOST_INT_REQ, 1); + + ret = wave6_vpu_ctrl_wait_busy(entity); + if (ret) { + dev_err(ctrl->dev, "sleep vpu timeout\n"); + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + return -EINVAL; + } + + ret = wave6_vpu_ctrl_check_result(entity); + if (ret) { + dev_err(ctrl->dev, "sleep vpu fail, reason 0x%x\n", ret); + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + return -EIO; + } + + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_SLEEP); + + return 0; +} + +static int wave6_vpu_ctrl_wakeup(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity) +{ + int ret; + + dprintk(ctrl->dev, "wakeup firmware\n"); + + wave6_vpu_ctrl_remap_code_buffer(ctrl); + + entity->write_reg(entity->dev, W6_VPU_BUSY_STATUS, 1); + entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_BASE_CORE0, + ctrl->sram_buf.dma_addr); + entity->write_reg(entity->dev, W6_CMD_INIT_VPU_SEC_AXI_SIZE_CORE0, + ctrl->sram_buf.size); + wave6_vpu_ctrl_writel(ctrl->dev, W6_COMMAND_GB, W6_CMD_WAKEUP_VPU); + wave6_vpu_ctrl_writel(ctrl->dev, W6_VPU_REMAP_CORE_START_GB, 1); + + ret = wave6_vpu_ctrl_wait_busy(entity); + if (ret) { + dev_err(ctrl->dev, "wakeup vpu timeout\n"); + return -EINVAL; + } + + ret = wave6_vpu_ctrl_check_result(entity); + if (ret) { + dev_err(ctrl->dev, "wakeup vpu fail, reason 0x%x\n", ret); + return -EIO; + } + + wave6_vpu_ctrl_boot_done(ctrl, 1); + + return 0; +} + +static int wave6_vpu_ctrl_try_boot(struct vpu_ctrl *ctrl, struct wave6_vpu_entity *entity) +{ + int ret; + + if (ctrl->state != WAVE6_VPU_STATE_OFF && ctrl->state != WAVE6_VPU_STATE_SLEEP) + return 0; + + if (entity->read_reg(entity->dev, W6_VPU_VCPU_CUR_PC)) { + dprintk(ctrl->dev, "try boot directly as firmware is running\n"); + wave6_vpu_ctrl_boot_done(ctrl, ctrl->state == WAVE6_VPU_STATE_SLEEP); + return 0; + } + + if (ctrl->state == WAVE6_VPU_STATE_SLEEP) { + ret = wave6_vpu_ctrl_wakeup(ctrl, entity); + return ret; + } + + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_PREPARE); + ctrl->current_entity = entity; + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_UEVENT, + ctrl->res->fw_name, + ctrl->dev, GFP_KERNEL, + ctrl, + wave6_vpu_ctrl_load_firmware); + if (ret) { + dev_err(ctrl->dev, "request firmware %s fail, ret = %d\n", ctrl->res->fw_name, ret); + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + return ret; + } + + return 0; +} + +bool wave6_vpu_ctrl_support_follower(struct device *dev) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + + if (!ctrl) + return false; + + return ctrl->support_follower; +} +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_support_follower); + +int wave6_vpu_ctrl_resume_and_get(struct device *dev, struct wave6_vpu_entity *entity) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + bool boot; + int ret; + + if (!ctrl) + return -EINVAL; + + if (!entity || !entity->dev || !entity->read_reg || !entity->write_reg) + return -EINVAL; + + mutex_lock(&ctrl->ctrl_lock); + + ret = pm_runtime_resume_and_get(ctrl->dev); + if (ret) { + dev_err(dev, "pm runtime resume fail, ret = %d\n", ret); + mutex_unlock(&ctrl->ctrl_lock); + return ret; + } + + entity->booted = false; + + if (ctrl->current_entity) + boot = false; + else + boot = list_empty(&ctrl->entities) ? true : false; + + list_add_tail(&entity->list, &ctrl->entities); + if (boot) + ret = wave6_vpu_ctrl_try_boot(ctrl, entity); + + if (ctrl->state == WAVE6_VPU_STATE_ON) + wave6_vpu_ctrl_on_boot(entity); + + if (ret) + pm_runtime_put_sync(ctrl->dev); + + mutex_unlock(&ctrl->ctrl_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_resume_and_get); + +void wave6_vpu_ctrl_put_sync(struct device *dev, struct wave6_vpu_entity *entity) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + + if (!ctrl) + return; + + if (entity == ctrl->current_entity) + wave6_vpu_ctrl_wait_done(dev); + + mutex_lock(&ctrl->ctrl_lock); + + if (!wave6_vpu_ctrl_find_entity(ctrl, entity)) + goto exit; + + list_del_init(&entity->list); + if (list_empty(&ctrl->entities)) { + if (!entity->read_reg(entity->dev, W6_VPU_VCPU_CUR_PC)) + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + else + wave6_vpu_ctrl_sleep(ctrl, entity); + } + + if (!pm_runtime_suspended(ctrl->dev)) + pm_runtime_put_sync(ctrl->dev); +exit: + mutex_unlock(&ctrl->ctrl_lock); +} +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_put_sync); + +int wave6_vpu_ctrl_wait_done(struct device *dev) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + int ret; + + if (!ctrl) + return -EINVAL; + + if (ctrl->state == WAVE6_VPU_STATE_OFF) + return -EINVAL; + + if (ctrl->state == WAVE6_VPU_STATE_ON) + return 0; + + ret = wave6_wait_event_freezable_timeout(ctrl->load_fw_wq, + wave6_vpu_ctrl_get_state(dev) == + WAVE6_VPU_STATE_ON, + msecs_to_jiffies(W6_BOOT_WAIT_TIMEOUT)); + if (ret == -ERESTARTSYS || !ret) { + dev_err(ctrl->dev, "fail to wait vcpu boot done,ret %d\n", ret); + mutex_lock(&ctrl->ctrl_lock); + wave6_vpu_ctrl_set_state(ctrl, WAVE6_VPU_STATE_OFF); + mutex_unlock(&ctrl->ctrl_lock); + return -EINVAL; + } + + mutex_lock(&ctrl->ctrl_lock); + wave6_vpu_ctrl_boot_done(ctrl, 0); + mutex_unlock(&ctrl->ctrl_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_wait_done); + +int wave6_vpu_ctrl_get_state(struct device *dev) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + + if (!ctrl) + return -EINVAL; + + return ctrl->state; +} +EXPORT_SYMBOL_GPL(wave6_vpu_ctrl_get_state); + +static void wave6_vpu_ctrl_init_reserved_boot_region(struct vpu_ctrl *ctrl) +{ + if (ctrl->boot_mem.size < WAVE6_CODE_BUF_SIZE) { + dev_warn(ctrl->dev, "boot memory size (%zu) is too small\n", ctrl->boot_mem.size); + ctrl->boot_mem.phys_addr = 0; + ctrl->boot_mem.size = 0; + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem)); + return; + } + + ctrl->boot_mem.vaddr = devm_memremap(ctrl->dev, + ctrl->boot_mem.phys_addr, + ctrl->boot_mem.size, + MEMREMAP_WC); + if (!ctrl->boot_mem.vaddr) { + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem)); + return; + } + + ctrl->boot_mem.dma_addr = dma_map_resource(ctrl->dev, + ctrl->boot_mem.phys_addr, + ctrl->boot_mem.size, + DMA_BIDIRECTIONAL, + 0); + if (!ctrl->boot_mem.dma_addr) { + memset(&ctrl->boot_mem, 0, sizeof(ctrl->boot_mem)); + return; + } + + dev_info(ctrl->dev, "boot phys_addr: %pad, dma_addr: %pad, size: 0x%zx\n", + &ctrl->boot_mem.phys_addr, + &ctrl->boot_mem.dma_addr, + ctrl->boot_mem.size); +} + +static int wave6_vpu_ctrl_thermal_update(struct device *dev, int state) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + unsigned long new_clock_rate; + int ret; + + if (wave6_cooling_disable || !ctrl->dev_perf || state > ctrl->thermal_max || !ctrl->cooling) + return 0; + + new_clock_rate = DIV_ROUND_UP(ctrl->freq_table[state], HZ_PER_KHZ); + dev_dbg(dev, "receive cooling set state: %d, new clock rate %ld\n", + state, new_clock_rate); + + ret = dev_pm_genpd_set_performance_state(ctrl->dev_perf, new_clock_rate); + dev_dbg(dev, "clk set to %lu\n", clk_get_rate(ctrl->clks[ctrl->clk_id].clk)); + if (ret && !((ret == -ENODEV) || (ret == -EOPNOTSUPP))) { + dev_err(dev, "failed to set perf to %lu (ret = %d)\n", new_clock_rate, ret); + return ret; + } + + return 0; +} + +static int wave6_cooling_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct vpu_ctrl *ctrl = cdev->devdata; + + *state = ctrl->thermal_max; + + return 0; +} + +static int wave6_cooling_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct vpu_ctrl *ctrl = cdev->devdata; + + *state = ctrl->thermal_event; + + return 0; +} + +static int wave6_cooling_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct vpu_ctrl *ctrl = cdev->devdata; + struct wave6_vpu_entity *entity; + + ctrl->thermal_event = state; + + list_for_each_entry(entity, &ctrl->entities, list) { + if (entity->pause) + entity->pause(entity->dev, 0); + } + + wave6_vpu_ctrl_thermal_update(ctrl->dev, state); + + list_for_each_entry(entity, &ctrl->entities, list) { + if (entity->pause) + entity->pause(entity->dev, 1); + } + + return 0; +} + +static struct thermal_cooling_device_ops wave6_cooling_ops = { + .get_max_state = wave6_cooling_get_max_state, + .get_cur_state = wave6_cooling_get_cur_state, + .set_cur_state = wave6_cooling_set_cur_state, +}; + +static void wave6_cooling_remove(struct vpu_ctrl *ctrl) +{ + int i; + + if (!ctrl->pd_list) + return; + + thermal_cooling_device_unregister(ctrl->cooling); + + kfree(ctrl->freq_table); + ctrl->freq_table = NULL; + + for (i = 0; i < ctrl->pd_list->num_pds; i++) { + struct device *pd_dev = ctrl->pd_list->pd_devs[i]; + + if (!pm_runtime_suspended(pd_dev)) + pm_runtime_force_suspend(pd_dev); + } + + dev_pm_domain_detach_list(ctrl->pd_list); + ctrl->pd_list = NULL; + ctrl->dev_perf = NULL; +} + +static void wave6_cooling_init(struct vpu_ctrl *ctrl) +{ + struct dev_pm_domain_attach_data pd_data = { + .pd_names = (const char *[]) {"vpumix", "vpuperf"}, + .num_pd_names = 2, + }; + int ret; + int i; + int num_opps; + unsigned long freq; + + ctrl->clk_id = -1; + for (i = 0; i < ctrl->num_clks; i++) { + if (!strcmp("vpu", ctrl->clks[i].id)) { + ctrl->clk_id = i; + break; + } + } + if (ctrl->clk_id == -1) { + dev_err(ctrl->dev, "cooling device unable to get clock\n"); + return; + } + + ret = dev_pm_domain_attach_list(ctrl->dev, &pd_data, &ctrl->pd_list); + ctrl->dev_perf = NULL; + if (ret < 0) + dev_err(ctrl->dev, "didn't attach perf power domains, ret=%d", ret); + else if (ret == 2) + ctrl->dev_perf = ctrl->pd_list->pd_devs[DOMAIN_VPU_PERF]; + dev_dbg(ctrl->dev, "get perf domain ret=%d, perf=%p\n", ret, ctrl->dev_perf); + if (!ctrl->dev_perf) + return; + + num_opps = dev_pm_opp_get_opp_count(ctrl->dev_perf); + if (num_opps <= 0) { + dev_err(ctrl->dev, "fail to get pm opp count, ret = %d\n", num_opps); + goto error; + } + + ctrl->freq_table = kcalloc(num_opps, sizeof(*ctrl->freq_table), GFP_KERNEL); + if (!ctrl->freq_table) + goto error; + + for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { + struct dev_pm_opp *opp; + + opp = dev_pm_opp_find_freq_floor(ctrl->dev_perf, &freq); + if (IS_ERR(opp)) + break; + + dev_pm_opp_put(opp); + + dev_dbg(ctrl->dev, "[%d] = %ld\n", i, freq); + if (freq < 100 * HZ_PER_MHZ) + break; + + ctrl->freq_table[i] = freq; + ctrl->thermal_max = i; + } + + if (!ctrl->thermal_max) + goto error; + + ctrl->thermal_event = 0; + ctrl->cooling = thermal_of_cooling_device_register(ctrl->dev->of_node, + (char *)dev_name(ctrl->dev), + ctrl, + &wave6_cooling_ops); + if (IS_ERR(ctrl->cooling)) { + dev_err(ctrl->dev, "register cooling device failed\n"); + goto error; + } + + return; +error: + wave6_cooling_remove(ctrl); +} + +static int wave6_vpu_ctrl_probe(struct platform_device *pdev) +{ + struct vpu_ctrl *ctrl; + struct device_node *np; + const struct vpu_ctrl_resource *res; + int ret; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret < 0) { + dev_err(&pdev->dev, "dma_set_mask_and_coherent failed: %d\n", ret); + return ret; + } + + res = of_device_get_match_data(&pdev->dev); + if (!res) + return -ENODEV; + + ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + mutex_init(&ctrl->ctrl_lock); + init_waitqueue_head(&ctrl->load_fw_wq); + INIT_LIST_HEAD(&ctrl->entities); + INIT_LIST_HEAD(&ctrl->buffers); + dev_set_drvdata(&pdev->dev, ctrl); + ctrl->dev = &pdev->dev; + ctrl->res = res; + ctrl->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ctrl->reg_base)) + return PTR_ERR(ctrl->reg_base); + ret = devm_clk_bulk_get_all(&pdev->dev, &ctrl->clks); + if (ret < 0) { + dev_warn(&pdev->dev, "unable to get clocks: %d\n", ret); + ret = 0; + } + + ctrl->num_clks = ret; + + np = of_parse_phandle(pdev->dev.of_node, "boot", 0); + if (np) { + struct resource mem; + + ret = of_address_to_resource(np, 0, &mem); + of_node_put(np); + if (!ret) { + ctrl->boot_mem.phys_addr = mem.start; + ctrl->boot_mem.size = resource_size(&mem); + wave6_vpu_ctrl_init_reserved_boot_region(ctrl); + } else { + dev_warn(&pdev->dev, "boot resource is not available.\n"); + } + } + + ctrl->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); + if (ctrl->sram_pool) { + ctrl->sram_buf.size = ctrl->res->sram_size; + ctrl->sram_buf.vaddr = gen_pool_dma_alloc(ctrl->sram_pool, + ctrl->sram_buf.size, + &ctrl->sram_buf.phys_addr); + if (!ctrl->sram_buf.vaddr) + ctrl->sram_buf.size = 0; + else + ctrl->sram_buf.dma_addr = dma_map_resource(&pdev->dev, + ctrl->sram_buf.phys_addr, + ctrl->sram_buf.size, + DMA_BIDIRECTIONAL, + 0); + + dev_info(&pdev->dev, "sram 0x%pad, 0x%pad, size 0x%lx\n", + &ctrl->sram_buf.phys_addr, &ctrl->sram_buf.dma_addr, ctrl->sram_buf.size); + } + + if (of_find_property(pdev->dev.of_node, "support-follower", NULL)) + ctrl->support_follower = true; + + wave6_cooling_init(ctrl); + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static void wave6_vpu_ctrl_remove(struct platform_device *pdev) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + wave6_vpu_ctrl_clear_buffers(ctrl); + wave6_cooling_remove(ctrl); + if (ctrl->sram_pool && ctrl->sram_buf.vaddr) { + dma_unmap_resource(&pdev->dev, + ctrl->sram_buf.dma_addr, + ctrl->sram_buf.size, + DMA_BIDIRECTIONAL, + 0); + gen_pool_free(ctrl->sram_pool, + (unsigned long)ctrl->sram_buf.vaddr, + ctrl->sram_buf.size); + } + if (ctrl->boot_mem.dma_addr) + dma_unmap_resource(&pdev->dev, + ctrl->boot_mem.dma_addr, + ctrl->boot_mem.size, + DMA_BIDIRECTIONAL, + 0); + mutex_destroy(&ctrl->ctrl_lock); +} + +#ifdef CONFIG_PM +static int wave6_vpu_ctrl_runtime_suspend(struct device *dev) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(ctrl->num_clks, ctrl->clks); + return 0; +} + +static int wave6_vpu_ctrl_runtime_resume(struct device *dev) +{ + struct vpu_ctrl *ctrl = dev_get_drvdata(dev); + + return clk_bulk_prepare_enable(ctrl->num_clks, ctrl->clks); +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int wave6_vpu_ctrl_suspend(struct device *dev) +{ + return 0; +} + +static int wave6_vpu_ctrl_resume(struct device *dev) +{ + return 0; +} +#endif +static const struct dev_pm_ops wave6_vpu_ctrl_pm_ops = { + SET_RUNTIME_PM_OPS(wave6_vpu_ctrl_runtime_suspend, wave6_vpu_ctrl_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(wave6_vpu_ctrl_suspend, wave6_vpu_ctrl_resume) +}; + +static const struct of_device_id wave6_ctrl_ids[] = { + { .compatible = "nxp,imx95-wave633c-ctrl", .data = &wave633c_ctrl_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, wave6_ctrl_ids); + +static struct platform_driver wave6_vpu_ctrl_driver = { + .driver = { + .name = VPU_CTRL_PLATFORM_DEVICE_NAME, + .of_match_table = of_match_ptr(wave6_ctrl_ids), + .pm = &wave6_vpu_ctrl_pm_ops, + }, + .probe = wave6_vpu_ctrl_probe, + .remove = wave6_vpu_ctrl_remove, +}; + +module_platform_driver(wave6_vpu_ctrl_driver); +MODULE_DESCRIPTION("chips&media VPU WAVE6 CTRL"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h new file mode 100644 index 000000000000..21cfd1d2e7d4 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-ctrl.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 control driver + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VPU_CTRL_H__ +#define __WAVE6_VPU_CTRL_H__ + +#include + +enum wave6_vpu_state { + WAVE6_VPU_STATE_OFF, + WAVE6_VPU_STATE_PREPARE, + WAVE6_VPU_STATE_ON, + WAVE6_VPU_STATE_SLEEP +}; + +struct wave6_vpu_entity { + struct list_head list; + struct device *dev; + u32 (*read_reg)(struct device *dev, u32 addr); + void (*write_reg)(struct device *dev, u32 addr, u32 data); + void (*on_boot)(struct device *dev); + void (*pause)(struct device *dev, int resume); + bool booted; +}; + +int wave6_alloc_dma(struct device *dev, struct vpu_buf *vb); +void wave6_free_dma(struct vpu_buf *vb); +int wave6_vpu_ctrl_resume_and_get(struct device *dev, struct wave6_vpu_entity *entity); +void wave6_vpu_ctrl_put_sync(struct device *dev, struct wave6_vpu_entity *entity); +int wave6_vpu_ctrl_get_state(struct device *dev); +int wave6_vpu_ctrl_wait_done(struct device *dev); +int wave6_vpu_ctrl_require_buffer(struct device *dev, struct wave6_vpu_entity *entity); +bool wave6_vpu_ctrl_support_follower(struct device *dev); +#endif /* __WAVE6_VPU_CTRL_H__ */ From patchwork Mon Feb 10 09:07:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nas Chung X-Patchwork-Id: 13967505 Received: from SEVP216CU002.outbound.protection.outlook.com (mail-koreacentralazon11022096.outbound.protection.outlook.com [40.107.43.96]) (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 DB0C01CC8AE; Mon, 10 Feb 2025 09:07:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.43.96 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178477; cv=fail; b=ZQI77ipMqbq93BTRSvUble8r5tL+MLDL5FggJLeUM59f3XQl/Fwjpvw3gMG2iE+g0NTcOFZ58n4B7Od/YIrSVIcM2/lmS4IG1JAkMiTQFTjWl92REdCZufmt+mkhoHtzsuqZXkx1eiobKsJ6JMgR4zbd7SOCvRqzh9yvrCaoa9c= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739178477; c=relaxed/simple; bh=nqfUv8Xa4BrZj7263foo1DKNRR4WXAR9OuyDzhwi8dU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=awDZ9JArcv7Jd7iARXV0yspkX77cvpvzsnk3eduFYqYzhq9eMuLi9v3wmX6nkeLl/DCHhqw01GyVzCEo1h0RuCTWm3BX6lfKtciOGyC4QIZu7/91PPe90tupAMxkIGnEK10UHkL+jWuf2Y3A6hnvViulVrpNDxfdWKychMHpubU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com; spf=fail smtp.mailfrom=chipsnmedia.com; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b=Yj4csc3o; arc=fail smtp.client-ip=40.107.43.96 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=chipsnmedia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chipsnmedia.com header.i=@chipsnmedia.com header.b="Yj4csc3o" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HXS/rbTSS2YHAJvOmczrHa0dXQxltQQBeqDB1k/6l43hyzWLeAkVWmaw47JXa2nI9zDEEuKpyXoq92aazKsn2qKa0ofuI3W7kIH3eUBV62Z/b5F7sDiIJODcmnVqfZlP7pdDsYtDk6uMGabmhQn20o0Jr4rsZmMQxi1+KbzgOO8Tvi4MQjevT/CeCO+p0RWWpq9ALZWxNTc7Y2MjEctj3+XaokkpPpzX+3JWZXKvbabk8NdO0asoIM4/0EEn1y/7neMu2AMe+X3/R9aZWatR1RdAdU3tFnOFTg4PdItk12iAWeqRZlMPs7FnL7OPNHgSU3O2p/eqgSn5NUQ8oiQm7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=WjJRISxY2hEy7QrDhXcrw4aY+JmWA+tRXoy027Y9gj0=; b=DnVHtvJXYPNRHngVpFPkWJpW3f9kGS6+0Ibq0rtwjAfBMeQPkgr7VDs8PbKP1O982urqVVcfu5BtGWt8MYMyWVmHuL7rZUoBspKYYSsos1tXgWAwISFLnv9LB7NzqmF0045QdmP7DVeBlwRi2A0Xmq3Yv/ju50aa6BWEsMiP12wDHxYGNb9Q5SFGCRwvHESm/iO5mejE9T1waPzWFQ0Gm6eED9YwgGlaLJ5bWuMQTUHoc0oWkSWsUuq9I2gqBXfEoKTWSVFZaQG7VqdiRaWG4Kt2e2a3s7LwjP5IBiqey0mNBh07q+CrSd8tSVZ+s1ySP9kI4zYDJIgD5feHJRq/Uw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=chipsnmedia.com; dmarc=pass action=none header.from=chipsnmedia.com; dkim=pass header.d=chipsnmedia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chipsnmedia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=WjJRISxY2hEy7QrDhXcrw4aY+JmWA+tRXoy027Y9gj0=; b=Yj4csc3osoZ0uUpQC0OKZa5nmLbBq7OSJ6IlffGqyFqkKD4TfJg230jTLvTNvgOrASh+aoYrakRfoePFXQ+ctLWsCwzWEpHN3mj+RafBRna5ie4pe1EL5uhWV5V27l3mpaTBf5gIslaa/k6jCAympjMyTh2ROTFn17Z6V0IkvIY= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=chipsnmedia.com; Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) by PU4P216MB1504.KORP216.PROD.OUTLOOK.COM (2603:1096:301:cf::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8422.18; Mon, 10 Feb 2025 09:07:38 +0000 Received: from SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07]) by SL2P216MB1246.KORP216.PROD.OUTLOOK.COM ([fe80::9e3d:ee20:8cc7:3c07%4]) with mapi id 15.20.8422.015; Mon, 10 Feb 2025 09:07:38 +0000 From: Nas Chung To: mchehab@kernel.org, hverkuil@xs4all.nl, sebastian.fricke@collabora.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-imx@nxp.com, linux-arm-kernel@lists.infradead.org, jackson.lee@chipsnmedia.com, lafley.kim@chipsnmedia.com, Nas Chung Subject: [PATCH 8/8] media: chips-media: wave6: Improve debugging capabilities Date: Mon, 10 Feb 2025 18:07:25 +0900 Message-Id: <20250210090725.4580-9-nas.chung@chipsnmedia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250210090725.4580-1-nas.chung@chipsnmedia.com> References: <20250210090725.4580-1-nas.chung@chipsnmedia.com> X-ClientProxiedBy: SL2P216CA0178.KORP216.PROD.OUTLOOK.COM (2603:1096:101:1a::6) To SL2P216MB1246.KORP216.PROD.OUTLOOK.COM (2603:1096:101:a::9) Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SL2P216MB1246:EE_|PU4P216MB1504:EE_ X-MS-Office365-Filtering-Correlation-Id: 53f3274a-b5ea-45fd-8099-08dd49b25dcb X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|52116014|366016|1800799024|38350700014; X-Microsoft-Antispam-Message-Info: jvZc+KNznguk+PWtDOfut5DuPPFATEKx7hhIX3Ptk2AEsALmVBhVoSM9uvgCm/dws7EPcfaowg56zsRQ+iQyRUg57ZeRphWYo5ljG1YSijNiPkXqBjDA+7ipZTFvX3vxIswuYDcXYCMb9IU4RWDPRZWjqtYsHltlNAmKM0fGlDnB2mdmq5TbLpMVQpjIAcrqt4Xy+WaffrmeDK60AcR0JnBeQ75G3Wk+93q3+j7oJWtvqGDRxatbHAd54YBjzKtSI94ZdUQjfFZfiGQ69GHqc9ZU3upKYwCaF41y0y0vlMnvHxJ3MBcT2bgXAJFkQh69U184tix4T1HRmKU+1dluiBgyXG4oYXmOyLAD3qugWIKN2uTv2BMSsfjC+QmElEEYu5HDKeu2TqW1N8XskZUFLVohLY0XzvdWeH2Iis76Zgp/LjgNSBHEzPaP0U9LK1awmYqUdfGvS1Lw1bFFeAlTtFE/I8kQ5JTq2+5ekDVLvg/NSLHWgSQjD3ilbDYEOl6+YsDW/B6RrisPhxpqnJm4OCEOV2DtASEJN4WT+ouURpAtKPK2jlcuhiKkwywH8mHzEFv283RYHSkpxSDXZVM4Qz8T3tKYH3c9me3ta9ONnpLXk5Bgz+iEXxNdbt24UBs/puMpGTj9/MGWUoVoz6gTJGHzYa6GoyswvUgYu3sydoomVI2NNw9+oFCjmZCgghIT1dtLsuJCgOd4mmmU9CKWSyifw9wPMwJTVkiJZv7iuc8XBIRnFFKDk0Pw4yo7KFeUasrO4APEOkjiJoTBoN1CUy6F6P5E123MSVl3bazcgCTlr3pJ7EEU77hYBCuHCTKIvlL2Hh1lYks64UHLCbAl7S/fGzmRw7M36lieveYikMcdOdIGmXnnxV0rAapdaT2brBsojoRJZo1UOGV0X5y6Oy0R0ntB1egpjA9ImlBLnyDZ/2a8wnapt36GLELmAGWquMeyWYZq7uuhKGje/WwVm3BlWNxQ+GTOCX3BBvccnyzHmGmHVSlPFK9b9OgGAR43FR1cfHJk2y+lMKeJ8/AWK1U9Ep/O61fvlMhFXQEi1ndYRyM+Z6yztXNQ4edsKoOi8Yy6QJs5Za431V8QH9Hu6/BMGEYkoesPPBnwSEwtZW3PLkAxKiTrk3GwISKAQOK8XlkpDrQVTiI/qwYODAGHP3YrQApwR+onzbsc10K3QOsqxML5KK/ZyF8ndQ17ql8zIOrmU835UJvdvaN/0n5kLrP/VqimbEZTpsv7RdisabKcpo1TxV1ddlhYoum8F63MRUii7Dx3Ti9Xjpcnphp/8ZGWSwpTwGAjZKw0Vy92J40v71lcdKPmbIunfOLuQ8mQPQr9gtEMabKRfwD1IQFCvJ10ty/IOmNbkW2Wz9xG11vlmqy189smaDUfTc8RNyihY6a+j9JWjWNPTSsgMhvHEQOrRrneJXLJbvayiC3qxVz/yl9LxsLxO9Wg/9BNZVrf X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SL2P216MB1246.KORP216.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(7416014)(52116014)(366016)(1800799024)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: byR1zErcXSBWNLjmipsCjnwzw3g4R9gWsRiUeAQ0faAkUoOM9X/M2jQsggf0xdZBgmuNlm63+CmFK9twQgYdV6aodJ4D9x2RP16Lf/iPsI2Ne7q9mq3sCQ3X8/InUM42aC1iuie8tBJAQ8K0UShCwCSDB4tAKQzOVrNqkxbTnU2azAZ/gBSLdUuMVzvZZtkLa6VYMdHl5e9X3AmZxC+cMI8NZ/ycwXNPPIihN5N7zpkJxJUEOLstsFNtW4ccgyfqx3lFrL9mvLelrcq6yubFBxDuODfDvQ7qS5MUdEwZMPDja5TsYLDPqOpIOnOHq0CZzl44XKy0ZMJtCEcnOQ5nX32xKw6W75yXtIcLCQN6Z3uoVpObK0TDGXMQ1E4nf9dfZrv4OIHnZOR6uAHytU9pnvn3MIa/Pau2+zrBhCAvld5p10ATEaRM9T2KGWkWjh1OYLy+PfOlbCPjwgJ4TTiGGuAyg+0OSxxmOXkRhK5VugYzJcA3a+nfgKLXcQqsIZs6ZK2FvG9K8naZwPIG6A2nN+i+PrZp4HLa1fZAw/FXHHteBSQ4yNiRrMgyen+IK2bbBnugLilQeEoj0MPcqDUmW/nZkzE7zhET87vvpaXNFjtCKrbtcJ0rciXfhf5ijHlDJTWwzk+gf5JutaNzbsDf4oe5e1Vd4IannEhK92OKZK5FDGFx/ROof7QlX3hbVjctyZeO3KwoqI4P5T5M1qtKQ/xZFyYU0hkUQlcVHVEMrvF2Gu3fH+6VvnEmwE5SqSYMZaIY4DTUUh1rIwBN7vzApwRvEVYsgTOp5VOMGElFNh5Kz9V8u0k1dJ5a21ANAfKPeR+M3fcjOCaE7ZgC9xnta1a7s5BFNL8uMo/bLIAEStO28JY7IF9C8wBMY2TUoL9ymAmiv+6EDFZrlFcO9iVHt6qIE7VmE8d8VhXcZE+n4iw4FC0Tv/q5MuW/AfS8aWTIpsJ3tIT7mGEGtyPO6iXkYgh2TO1znflqaEgSLUSj45QAe36gw8S6piVVEp8d22+WXv92qqb0AB9klV+ExqIAl5NxB/o+Hjsts4AMA/HG2vkK/PJmeH21g6IJraVSqtdiq86KUzJ0xy/xoeNgR7aPp5PTTXSvM610F/pU1fSQ/OYJpJjt0tdDhhdT0qkOgKaj0t+JoeID78QvAJzdZfP8yN0jBw/tehJ6gqbkjqCTOi+Cq2tTdbDkxhaMM07IOJxNfVb2OLHJ7+++PW+Q6YP0/XJsIQXdq6XWy3iFZ+4aRY1j1xA7gm2JgDtH7PoHqUOemjD7c2D6kGZJ0vyVX1JwCEQFlTuGUxqCpaVD2AIhkxkOD/0eT9wOCy0IBwojy5WxSq9OHscaiiz86DMSgljNvirMNCc7iH0X12afkS+UBdLOqj6SsiJYbDe+Z0k+ujd1Ea8adxX49dA8idUDnZmwx83ef/HHCVYxH4jkHoLMSPVJblcbHwRwEk7nL1KKm2YxqIZI9Fyl5KpaSe2y411ZgwfuAXazxr5EDtIxcUNSGCA0ILxwoXC2quRclYFzqrnpjJ9leOo7ZWQFdPx+fQGzgl9MbpCvcjiLTZQbCddDx6nMa0fhvGXwCr2O5EC/5lG4uK5ZL9MHKRUCd+DNiL0eSA== X-OriginatorOrg: chipsnmedia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 53f3274a-b5ea-45fd-8099-08dd49b25dcb X-MS-Exchange-CrossTenant-AuthSource: SL2P216MB1246.KORP216.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Feb 2025 09:07:38.4405 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4d70c8e9-142b-4389-b7f2-fa8a3c68c467 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: IGfdys81UgbtCZCbgx+eB9dB4b9J15vld2b/6uP2/e3nIA0o5u6GZ/Q5UPUJtWojgRH6xM2YJfCZpeEEn8ZPBTwjNf5e/mhhOxfBT8xDj4k= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PU4P216MB1504 Add debugfs entries and trace events to provide detailed debugging information. These enhancements help diagnose issues and improve debugging capabilities for the Wave6 driver. Signed-off-by: Nas Chung --- .../platform/chips-media/wave6/wave6-trace.h | 336 ++++++++++++++++++ .../chips-media/wave6/wave6-vpu-dbg.c | 230 ++++++++++++ .../chips-media/wave6/wave6-vpu-dbg.h | 22 ++ 3 files changed, 588 insertions(+) create mode 100644 drivers/media/platform/chips-media/wave6/wave6-trace.h create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c create mode 100644 drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h diff --git a/drivers/media/platform/chips-media/wave6/wave6-trace.h b/drivers/media/platform/chips-media/wave6/wave6-trace.h new file mode 100644 index 000000000000..8ddba6926c60 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-trace.h @@ -0,0 +1,336 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - wave6 driver tracer + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM wave6 + +#if !defined(__WAVE6_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) +#define __WAVE6_TRACE_H__ + +#include +#include + +DECLARE_EVENT_CLASS(register_access, + TP_PROTO(struct device *dev, u32 addr, u32 value), + TP_ARGS(dev, addr, value), + TP_STRUCT__entry( + __string(name, dev_name(dev)) + __field(u32, addr) + __field(u32, value) + ), + TP_fast_assign( + __assign_str(name, dev_name(dev)); + __entry->addr = addr; + __entry->value = value; + ), + TP_printk("%s:0x%03x 0x%08x", __get_str(name), __entry->addr, __entry->value) +); + +DEFINE_EVENT(register_access, writel, + TP_PROTO(struct device *dev, u32 addr, u32 value), + TP_ARGS(dev, addr, value)); +DEFINE_EVENT(register_access, readl, + TP_PROTO(struct device *dev, u32 addr, u32 value), + TP_ARGS(dev, addr, value)); + +TRACE_EVENT(send_command, + TP_PROTO(struct vpu_device *vpu_dev, u32 id, u32 std, u32 cmd), + TP_ARGS(vpu_dev, id, std, cmd), + TP_STRUCT__entry( + __string(name, dev_name(vpu_dev->dev)) + __field(u32, id) + __field(u32, std) + __field(u32, cmd) + ), + TP_fast_assign( + __assign_str(name, dev_name(vpu_dev->dev)); + __entry->id = id; + __entry->std = std; + __entry->cmd = cmd; + ), + TP_printk("%s: inst id %d, std 0x%x, cmd 0x%x", + __get_str(name), __entry->id, __entry->std, __entry->cmd) +); + +TRACE_EVENT(irq, + TP_PROTO(struct vpu_device *vpu_dev, u32 irq), + TP_ARGS(vpu_dev, irq), + TP_STRUCT__entry( + __string(name, dev_name(vpu_dev->dev)) + __field(u32, irq) + ), + TP_fast_assign( + __assign_str(name, dev_name(vpu_dev->dev)); + __entry->irq = irq; + ), + TP_printk("%s: irq 0x%x", __get_str(name), __entry->irq) +); + +TRACE_EVENT(set_state, + TP_PROTO(struct vpu_instance *inst, u32 state), + TP_ARGS(inst, state), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __string(cur_state, wave6_vpu_instance_state_name(inst->state)) + __string(nxt_state, wave6_vpu_instance_state_name(state)) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __assign_str(cur_state, wave6_vpu_instance_state_name(inst->state)); + __assign_str(nxt_state, wave6_vpu_instance_state_name(state)); + ), + TP_printk("%s: inst[%d] set state %s -> %s", + __get_str(name), __entry->id, __get_str(cur_state), __get_str(nxt_state)) +); + +DECLARE_EVENT_CLASS(inst_internal, + TP_PROTO(struct vpu_instance *inst, u32 type), + TP_ARGS(inst, type), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __string(type, V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture") + __field(u32, pixelformat) + __field(u32, width) + __field(u32, height) + __field(u32, buf_cnt_src) + __field(u32, buf_cnt_dst) + __field(u32, processed_cnt) + __field(u32, error_cnt) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __assign_str(type, V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"); + __entry->pixelformat = V4L2_TYPE_IS_OUTPUT(type) ? inst->src_fmt.pixelformat : + inst->dst_fmt.pixelformat; + __entry->width = V4L2_TYPE_IS_OUTPUT(type) ? inst->src_fmt.width : + inst->dst_fmt.width; + __entry->height = V4L2_TYPE_IS_OUTPUT(type) ? inst->src_fmt.height : + inst->dst_fmt.height; + __entry->buf_cnt_src = inst->queued_src_buf_num; + __entry->buf_cnt_dst = inst->queued_dst_buf_num; + __entry->processed_cnt = inst->processed_buf_num; + __entry->error_cnt = inst->error_buf_num; + ), + TP_printk("%s: inst[%d] %s %c%c%c%c %dx%d, input %d, %d, process %d, error %d", + __get_str(name), __entry->id, __get_str(type), + __entry->pixelformat, + __entry->pixelformat >> 8, + __entry->pixelformat >> 16, + __entry->pixelformat >> 24, + __entry->width, __entry->height, + __entry->buf_cnt_src, __entry->buf_cnt_dst, + __entry->processed_cnt, __entry->error_cnt) +); + +DEFINE_EVENT(inst_internal, start_streaming, + TP_PROTO(struct vpu_instance *inst, u32 type), + TP_ARGS(inst, type)); + +DEFINE_EVENT(inst_internal, stop_streaming, + TP_PROTO(struct vpu_instance *inst, u32 type), + TP_ARGS(inst, type)); + +TRACE_EVENT(dec_pic, + TP_PROTO(struct vpu_instance *inst, u32 srcidx, u32 size), + TP_ARGS(inst, srcidx, size), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __field(u32, srcidx) + __field(u32, start) + __field(u32, size) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __entry->srcidx = srcidx; + __entry->start = inst->codec_info->dec_info.stream_rd_ptr; + __entry->size = size; + ), + TP_printk("%s: inst[%d] src[%2d] %8x, %d", + __get_str(name), __entry->id, __entry->srcidx, __entry->start, __entry->size) +); + +TRACE_EVENT(source_change, + TP_PROTO(struct vpu_instance *inst, struct dec_initial_info *info), + TP_ARGS(inst, info), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __field(u32, width) + __field(u32, height) + __field(u32, profile) + __field(u32, level) + __field(u32, tier) + __field(u32, min_fb_cnt) + __field(u32, disp_delay) + __field(u32, quantization) + __field(u32, colorspace) + __field(u32, xfer_func) + __field(u32, ycbcr_enc) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __entry->width = info->pic_width, + __entry->height = info->pic_height, + __entry->profile = info->profile, + __entry->level = info->level; + __entry->tier = info->tier; + __entry->min_fb_cnt = info->min_frame_buffer_count; + __entry->disp_delay = info->frame_buf_delay; + __entry->quantization = inst->quantization; + __entry->colorspace = inst->colorspace; + __entry->xfer_func = inst->xfer_func; + __entry->ycbcr_enc = inst->ycbcr_enc; + ), + TP_printk("%s: inst[%d] %dx%d profile %d, %d, %d min_fb %d, delay %d, color %d,%d,%d,%d", + __get_str(name), __entry->id, + __entry->width, __entry->height, + __entry->profile, __entry->level, __entry->tier, + __entry->min_fb_cnt, __entry->disp_delay, + __entry->quantization, + __entry->colorspace, __entry->xfer_func, __entry->ycbcr_enc) +); + +TRACE_EVENT(dec_done, + TP_PROTO(struct vpu_instance *inst, struct dec_output_info *info), + TP_ARGS(inst, info), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __field(u32, dec_flag) + __field(u32, dec_poc) + __field(u32, disp_flag) + __field(u32, disp_cnt) + __field(u32, rel_cnt) + __field(u32, src_ch) + __field(u32, eos) + __field(u32, error) + __field(u32, warn) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __entry->dec_flag = info->frame_decoded; + __entry->dec_poc = info->decoded_poc; + __entry->disp_flag = info->frame_display; + __entry->disp_cnt = info->disp_frame_num; + __entry->rel_cnt = info->release_disp_frame_num; + __entry->src_ch = info->notification_flags & DEC_NOTI_FLAG_SEQ_CHANGE; + __entry->eos = info->stream_end; + __entry->error = info->error_reason; + __entry->warn = info->warn_info; + ), + TP_printk("%s: inst[%d] dec %d %d; disp %d(%d); rel %d, src_ch %d, eos %d, error 0x%x 0x%x", + __get_str(name), __entry->id, + __entry->dec_flag, __entry->dec_poc, + __entry->disp_flag, __entry->disp_cnt, + __entry->rel_cnt, + __entry->src_ch, __entry->eos, + __entry->error, __entry->warn) +); + +TRACE_EVENT(enc_pic, + TP_PROTO(struct vpu_instance *inst, struct enc_param *param), + TP_ARGS(inst, param), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __field(u32, srcidx) + __field(u32, buf_y) + __field(u32, buf_cb) + __field(u32, buf_cr) + __field(u32, stride) + __field(u32, buf_strm) + __field(u32, size_strm) + __field(u32, force_type_enable) + __field(u32, force_type) + __field(u32, end_flag) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __entry->srcidx = param->src_idx; + __entry->buf_y = param->source_frame->buf_y; + __entry->buf_cb = param->source_frame->buf_cb; + __entry->buf_cr = param->source_frame->buf_cr; + __entry->stride = param->source_frame->stride; + __entry->buf_strm = param->pic_stream_buffer_addr; + __entry->size_strm = param->pic_stream_buffer_size; + __entry->force_type_enable = param->force_pic_type_enable; + __entry->force_type = param->force_pic_type; + __entry->end_flag = param->src_end; + ), + TP_printk("%s: inst[%d] src[%2d] %8x %8x %8x (%d); dst %8x(%d); force type %d(%d), end %d", + __get_str(name), __entry->id, __entry->srcidx, + __entry->buf_y, __entry->buf_cb, __entry->buf_cr, __entry->stride, + __entry->buf_strm, __entry->size_strm, + __entry->force_type_enable, __entry->force_type, + __entry->end_flag) +); + +TRACE_EVENT(enc_done, + TP_PROTO(struct vpu_instance *inst, struct enc_output_info *info), + TP_ARGS(inst, info), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __field(u32, srcidx) + __field(u32, frmidx) + __field(u32, size) + __field(u32, type) + __field(u32, avg_qp) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __entry->srcidx = info->enc_src_idx; + __entry->frmidx = info->recon_frame_index; + __entry->size = info->bitstream_size; + __entry->type = info->pic_type; + __entry->avg_qp = info->avg_ctu_qp; + ), + TP_printk("%s: inst[%d] src %d, frame %d, size %d, type %d, qp %d, eos %d", + __get_str(name), __entry->id, + __entry->srcidx, __entry->frmidx, + __entry->size, __entry->type, __entry->avg_qp, + __entry->frmidx == RECON_IDX_FLAG_ENC_END) +); + +TRACE_EVENT(s_ctrl, + TP_PROTO(struct vpu_instance *inst, struct v4l2_ctrl *ctrl), + TP_ARGS(inst, ctrl), + TP_STRUCT__entry( + __string(name, dev_name(inst->dev->dev)) + __field(u32, id) + __string(ctrl_name, ctrl->name) + __field(u32, val) + ), + TP_fast_assign( + __assign_str(name, dev_name(inst->dev->dev)); + __entry->id = inst->id; + __assign_str(ctrl_name, ctrl->name); + __entry->val = ctrl->val; + ), + TP_printk("%s: inst[%d] %s = %d", + __get_str(name), __entry->id, __get_str(ctrl_name), __entry->val) +); + +#endif /* __WAVE6_TRACE_H__ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE wave6-trace + +/* This part must be outside protection */ +#include diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c new file mode 100644 index 000000000000..40fe75c08eeb --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Wave6 series multi-standard codec IP - debug interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#include +#include +#include "wave6-vpu.h" +#include "wave6-vpu-dbg.h" + +static int wave6_vpu_dbg_instance(struct seq_file *s, void *data) +{ + struct vpu_instance *inst = s->private; + struct vpu_performance_info *perf = &inst->performance; + struct vb2_queue *vq; + char str[128]; + int num; + s64 tmp; + s64 fps; + + if (!inst->v4l2_fh.m2m_ctx) + return 0; + + num = scnprintf(str, sizeof(str), "[%s]\n", + inst->type == VPU_INST_TYPE_DEC ? "Decoder" : "Encoder"); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), "%s : product 0x%x, fw_ver %d.%d.%d(r%d), hw_ver 0x%x\n", + dev_name(inst->dev->dev), inst->dev->product_code, + (inst->dev->fw_version >> 24) & 0xFF, + (inst->dev->fw_version >> 16) & 0xFF, + (inst->dev->fw_version >> 0) & 0xFFFF, + inst->dev->fw_revision, inst->dev->hw_version); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), "state = %s, pause request %d\n", + wave6_vpu_instance_state_name(inst->state), + inst->dev->pause_request); + if (seq_write(s, str, num)) + return 0; + + vq = v4l2_m2m_get_src_vq(inst->v4l2_fh.m2m_ctx); + num = scnprintf(str, sizeof(str), + "output (%2d, %2d): fmt = %c%c%c%c %d x %d, %d;\n", + vb2_is_streaming(vq), + vb2_get_num_buffers(vq), + inst->src_fmt.pixelformat, + inst->src_fmt.pixelformat >> 8, + inst->src_fmt.pixelformat >> 16, + inst->src_fmt.pixelformat >> 24, + inst->src_fmt.width, + inst->src_fmt.height, + vq->last_buffer_dequeued); + if (seq_write(s, str, num)) + return 0; + + vq = v4l2_m2m_get_dst_vq(inst->v4l2_fh.m2m_ctx); + num = scnprintf(str, sizeof(str), + "capture(%2d, %2d): fmt = %c%c%c%c %d x %d, %d;\n", + vb2_is_streaming(vq), + vb2_get_num_buffers(vq), + inst->dst_fmt.pixelformat, + inst->dst_fmt.pixelformat >> 8, + inst->dst_fmt.pixelformat >> 16, + inst->dst_fmt.pixelformat >> 24, + inst->dst_fmt.width, + inst->dst_fmt.height, + vq->last_buffer_dequeued); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), + "capture queued %d, consumed %d, used %d\n", + v4l2_m2m_num_dst_bufs_ready(inst->v4l2_fh.m2m_ctx), + wave6_vpu_get_consumed_fb_num(inst), + wave6_vpu_get_used_fb_num(inst)); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), "crop: (%d, %d) %d x %d\n", + inst->crop.left, + inst->crop.top, + inst->crop.width, + inst->crop.height); + if (seq_write(s, str, num)) + return 0; + + if (inst->scaler_info.enable) { + num = scnprintf(str, sizeof(str), "scale: %d x %d\n", + inst->scaler_info.width, inst->scaler_info.height); + if (seq_write(s, str, num)) + return 0; + } + + num = scnprintf(str, sizeof(str), + "queued src %d, dst %d, process %d, sequence %d, error %d, drain %d:%d\n", + inst->queued_src_buf_num, + inst->queued_dst_buf_num, + inst->processed_buf_num, + inst->sequence, + inst->error_buf_num, + inst->v4l2_fh.m2m_ctx->out_q_ctx.buffered, + inst->eos); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), "fps"); + if (seq_write(s, str, num)) + return 0; + tmp = MSEC_PER_SEC * inst->processed_buf_num; + if (perf->ts_last > perf->ts_first + NSEC_PER_MSEC) { + fps = DIV_ROUND_CLOSEST(tmp, (perf->ts_last - perf->ts_first) / NSEC_PER_MSEC); + num = scnprintf(str, sizeof(str), " actual: %lld;", fps); + if (seq_write(s, str, num)) + return 0; + } + if (perf->total_sw_time) { + fps = DIV_ROUND_CLOSEST(tmp, perf->total_sw_time / NSEC_PER_MSEC); + num = scnprintf(str, sizeof(str), " sw: %lld;", fps); + if (seq_write(s, str, num)) + return 0; + } + if (perf->total_hw_time) { + fps = DIV_ROUND_CLOSEST(tmp, perf->total_hw_time / NSEC_PER_MSEC); + num = scnprintf(str, sizeof(str), " hw: %lld", fps); + if (seq_write(s, str, num)) + return 0; + } + num = scnprintf(str, sizeof(str), "\n"); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), + "latency(ms) first: %llu.%06llu, max %llu.%06llu\n", + perf->latency_first / NSEC_PER_MSEC, + perf->latency_first % NSEC_PER_MSEC, + perf->latency_max / NSEC_PER_MSEC, + perf->latency_max % NSEC_PER_MSEC); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), + "process frame time(ms) min: %llu.%06llu, max %llu.%06llu\n", + perf->min_process_time / NSEC_PER_MSEC, + perf->min_process_time % NSEC_PER_MSEC, + perf->max_process_time / NSEC_PER_MSEC, + perf->max_process_time % NSEC_PER_MSEC); + if (seq_write(s, str, num)) + return 0; + + if (inst->type == VPU_INST_TYPE_DEC) { + num = scnprintf(str, sizeof(str), "%s order\n", + inst->disp_mode == DISP_MODE_DISP_ORDER ? "display" : "decode"); + if (seq_write(s, str, num)) + return 0; + } else { + struct enc_info *p_enc_info = &inst->codec_info->enc_info; + struct enc_codec_param *param = &p_enc_info->open_param.codec_param; + + num = scnprintf(str, sizeof(str), "profile %d, level %d, tier %d\n", + param->profile, param->level, param->tier); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), "frame_rate %d, idr_period %d, intra_period %d\n", + param->frame_rate, param->idr_period, param->intra_period); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), "rc %d, mode %d, bitrate %d\n", + param->en_rate_control, + param->rc_mode, + param->bitrate); + if (seq_write(s, str, num)) + return 0; + + num = scnprintf(str, sizeof(str), + "qp %d, i_qp [%d, %d], p_qp [%d, %d], b_qp [%d, %d]\n", + param->qp, + param->min_qp_i, param->max_qp_i, + param->min_qp_p, param->max_qp_p, + param->min_qp_b, param->max_qp_b); + if (seq_write(s, str, num)) + return 0; + } + + return 0; +} + +static int wave6_vpu_dbg_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, wave6_vpu_dbg_instance, inode->i_private); +} + +static const struct file_operations wave6_vpu_dbg_fops = { + .owner = THIS_MODULE, + .open = wave6_vpu_dbg_open, + .release = single_release, + .read = seq_read, +}; + +int wave6_vpu_create_dbgfs_file(struct vpu_instance *inst) +{ + char name[64]; + + if (!inst || !inst->dev || IS_ERR_OR_NULL(inst->dev->debugfs)) + return -EINVAL; + + scnprintf(name, sizeof(name), "instance.%d", inst->id); + inst->debugfs = debugfs_create_file((const char *)name, + VERIFY_OCTAL_PERMISSIONS(0444), + inst->dev->debugfs, + inst, + &wave6_vpu_dbg_fops); + + return 0; +} + +void wave6_vpu_remove_dbgfs_file(struct vpu_instance *inst) +{ + if (!inst || !inst->debugfs) + return; + + debugfs_remove(inst->debugfs); + inst->debugfs = NULL; +} diff --git a/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h new file mode 100644 index 000000000000..fd7da1670925 --- /dev/null +++ b/drivers/media/platform/chips-media/wave6/wave6-vpu-dbg.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Wave6 series multi-standard codec IP - debug interface + * + * Copyright (C) 2025 CHIPS&MEDIA INC + */ + +#ifndef __WAVE6_VPU_DBG_H__ +#define __WAVE6_VPU_DBG_H__ + +unsigned int wave6_vpu_debug(void); + +#define dprintk(dev, fmt, arg...) \ + do { \ + if (wave6_vpu_debug()) \ + dev_info(dev, "%s: " fmt, __func__, ## arg); \ + } while (0) + +int wave6_vpu_create_dbgfs_file(struct vpu_instance *inst); +void wave6_vpu_remove_dbgfs_file(struct vpu_instance *inst); + +#endif /* __WAVE6_VPU_DBG_H__ */