From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from TYDPR03CU002.outbound.protection.outlook.com (mail-japaneastazon11023117.outbound.protection.outlook.com [52.101.127.117]) (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 594B132B991; Tue, 28 Oct 2025 12:16:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.127.117 ARC-Seal:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761653824; cv=fail; b=udsaqNNPQ59odLkRUhRXQCx3iqb7Zx3UNKo7rsjyEbpMIMQQELJrK49mDh8edbrwd5BDqYcAr6A/iXtvrPINmy/Qdr8PB0ANODmFSgfoCbg0Ag2BsmOCYyC1NxTBR6/Jfc3r7MxZeLfbaCeL5zIA0cB0Yq1D5hlHSMFTp3Zla3k= ARC-Message-Signature:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761653824; c=relaxed/simple; bh=8vL/PcWpaIWVrww0Xew5y3MNxMn/eGyqLbc2wLC5lmI=; h=Message-ID:Date:Subject:To:Cc:References:From:In-Reply-To: Content-Type:MIME-Version; b=X1dxnbuMXQTfvebx5knKDTW151a8UHvFV8PDS1/V4Y5T1j3Rlv3R4Gn+X8niRnfSfX7C+yplEn2Qt9ZpCRRISIEs14pG8SoYsPH21hZ9HTW2GutTE7PVsoNHy6f/kJjAQot/gcUi8FdJUUTPKQbdRRc/zQeKsMc/u/EFZ3o+e08= ARC-Authentication-Results:i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amlogic.com; spf=pass smtp.mailfrom=amlogic.com; dkim=pass (2048-bit key) header.d=amlogic.com header.i=@amlogic.com header.b=fhLXJ/p+; arc=fail smtp.client-ip=52.101.127.117 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amlogic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amlogic.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=amlogic.com header.i=@amlogic.com header.b="fhLXJ/p+" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=NkVGDzuz3ZNxvhziLLfwvLCmMS+oKp4fMZMDmga3k2W5ejwCITVW9TUntSXzp4UvLa9GVYKdisC9PRglc0axJHxM9GRp9mQM/0vt90FTEVjuKIsOmfUmzo6WXIkBnvTY65yMLvgCpRKKICnSed2O/mJOtfz7aEatIoZprEFZnBsO4BoYDYBH3f5cr9FePMWWyYZWQRM/cxwmzMe7XVwI01zTXKPQA2X+/0Yz64Jqx3sBXi2081FvLSIB9UpJsGGgYmrDwAkbPNVen9Z37bkEkfGqWUErpS0PSJCrBsAaiuLYYodyAtb4B5i5kA8A192LOjxIz2UZTieQ2vyaOf4Tjw== 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=ExmnfowaAsGK3Ws4U6GUxG467+XXEGekAMRI6OSoVUQ=; b=gJ14FqIsu8Te8xudhNBX+QyzHFkrPA82I2DlhxbcHqjaawAQlpGZAPk+SAmz+D6GWKZUQeMCUzWxz25svn95xP1Xyoz+8BlfokXRe7b4iFvoHFBqhOBDRP4j06L4dF7nNjmLkcRisySw9Y/AP5ENt4wRi6y3uJZJbluMt7oZsJ0zQ/j6aQG4NCOQLp+LKxexuOIoLE8qUKqoo6Xj827XCZZUb7gq9zV98h5ErOOOqTbpRhC1EfckaT/qbGen91T+/6ngdsifYw7BY4Bzoz9OdJguJzRXLXakorXTb/xyEgcQXVe9NAikcr1kwZ0p5aAPxmO/r50Q9ZbfQ18IhLSn+Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=amlogic.com; dmarc=pass action=none header.from=amlogic.com; dkim=pass header.d=amlogic.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amlogic.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ExmnfowaAsGK3Ws4U6GUxG467+XXEGekAMRI6OSoVUQ=; b=fhLXJ/p+U7JHzt/FUVS4jtMv6kBibrAl//i9SGIFEIou2cRZNMldktgbjuaTAKkEWGEuzC+C4u0lTTc1LFrJb9N+lkrc3PCmFC3n/ABqdxq2MgSgzUUC++RlvlB52S6IOLHA5Me4I9QJMpuaSm2vQa67GC7ABlJYYYH4HC58znpTZe4S8YNLMf08jQ/Kkp2ti8fSXEhwo+9aZumWF/sIL01HgUT2ZsBhaUDlTAKztMnZl/sA/NrnxPagF9rW3CtVMXrE9hxa0tcOLiIDJK8Y/TXtYHPv5esn8CupOATjjTNMD2Fjs1tZ2wUoRkwtuD/mjI6FuvSnPsO24Es5keEv6w== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=amlogic.com; Received: from TYZPR03MB5536.apcprd03.prod.outlook.com (2603:1096:400:5e::9) by SEZPR03MB7811.apcprd03.prod.outlook.com (2603:1096:101:18b::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9253.18; Tue, 28 Oct 2025 12:16:50 +0000 Received: from TYZPR03MB5536.apcprd03.prod.outlook.com ([fe80::9a50:1a8:fa6a:579e]) by TYZPR03MB5536.apcprd03.prod.outlook.com ([fe80::9a50:1a8:fa6a:579e%7]) with mapi id 15.20.9253.017; Tue, 28 Oct 2025 12:16:50 +0000 Message-ID: <107081de-8ef5-4ad8-9482-424e218d49e2@amlogic.com> Date: Tue, 28 Oct 2025 20:16:44 +0800 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH 3/3] decoder: Add V4L2 stateless H.264 decoder driver To: Neil Armstrong , Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kevin Hilman , Jerome Brunet , Martin Blumenstingl Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-amlogic@lists.infradead.org References: <20251027-b4-s4-vdec-upstream-v1-0-620401813b5d@amlogic.com> <20251027-b4-s4-vdec-upstream-v1-3-620401813b5d@amlogic.com> <42909f90-e2d3-4911-ae6d-47d180ccb367@linaro.org> From: Zhentao Guo In-Reply-To: <42909f90-e2d3-4911-ae6d-47d180ccb367@linaro.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-ClientProxiedBy: SI1PR02CA0050.apcprd02.prod.outlook.com (2603:1096:4:1f5::12) To TYZPR03MB5536.apcprd03.prod.outlook.com (2603:1096:400:5e::9) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: TYZPR03MB5536:EE_|SEZPR03MB7811:EE_ X-MS-Office365-Filtering-Correlation-Id: a9897d4f-990c-4fd2-6aae-08de161bdf1d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|376014|7416014; X-Microsoft-Antispam-Message-Info: =?utf-8?B?MDhFMjJWaDl0UmJ3Y09TNjgxbkxpR3NoRkVJZC9OY2c5dm4rUm1POWliM05C?= =?utf-8?B?VXliVWE5ZkgrT3d0NjhWOTAvV3M1MjRsRlByNjB1NjNhSElVTk1sNXAyY2Ni?= =?utf-8?B?azhxSjVzM2tJMG5MTC95U0ZHdlYvVzdzWVhyVGtxK254UW1ZQUNlZFZZRXRo?= =?utf-8?B?Z2NYQUI3Qnh0ZWk2UGZySHhyUTFuUFo5SDVvc1ZIWHJqazBEUWxHMnJiUmpk?= =?utf-8?B?UFdCeDI3ZG5vRFR6Vi9NYWRCZHpOTFhrUXhtc2ZkVzZ0Z0RmSG94ZTdTWVR1?= =?utf-8?B?ZHMyNTR5UDNqcDFaVXRqMnBiZElBQ3N5NzJsT1VpOUhVVWk4VVZWMkwrKy9o?= =?utf-8?B?T2hveWFGUktKUGpQNGpZTHVKNnFzbVJ3a2FSblFGcDJrMklTVzh3RnIyYXdN?= =?utf-8?B?MzVPWFl3c01Ic05iL2Z6VEIzSkdNOHhVVDUyWDJFRVdJQ2cwbGx5NkUzTzJJ?= =?utf-8?B?amttaFdBOXBaTFZGNE5aanpWendMMitZYkRhUVlQUWxwYUJvZkxCdmc3NlJk?= =?utf-8?B?Y2czeUlBKzFFb3V5cTY0SGhZdStIOGp2bWRsN3kwekNiVU1RTVpsNVN5UTBY?= =?utf-8?B?Y0lHQTRlZ0lRRlIxUEhpUXA3cTBTZHYxQm5aakliYkJsL2MvQ3BZdStuMFdD?= =?utf-8?B?aXdCRm1iZC84M2crdWdZL1FWaThNaktZdWZNTy9ZZ21ZN0tienplVVEwQzFL?= =?utf-8?B?ZGxMREI5b0dzazhUMlNmQ2FxQzFyQzlxZWNNK1pFT1U0enBOQmozN2pFYjNZ?= =?utf-8?B?cVBOWlFLaXRMNmZRalZUTTYrZHlUZEE3MjF3QmpuZTNGZkErMFZzS0pUTll3?= =?utf-8?B?WnplQjV6NmcvOU93aFQrbzdBS1pvbUt2MDR0WUJSeXBKbjRFUHpmdUQ1bUp5?= =?utf-8?B?ZVFZdFF3b0RETTVJc0xVM1d2dmxQMlB3QjZUa09jQ01ldCt5VmdrYStFb0Zs?= =?utf-8?B?eVM4TzFrTFlVdGZtZyt6TllmRkNYN2tvNW43UlMzQzdsdGIwV2xrT0ZRRXp0?= =?utf-8?B?cjZDbVdVRzJiT09Hb3kybk1OdXF4NHl1eWhiR2swK2c1MEUwcVZIN3FnRW5a?= =?utf-8?B?dzZRSlZCc2NDUVhOM0NzVi9Sdk1zdklEdkxDODRLRkViZFY3KzdtUE5qamtB?= =?utf-8?B?dUNTODB6R2loM2tYRFViNXZSdDJDSWQvUkEwSCtVM1g5VkhRR0FlOUlQVGYw?= =?utf-8?B?OVRBTXBIVjJ1RHV6bThzcVlTdXlOd2xtMkFLd0hLUERLNFVwVlgyTmJmaGht?= =?utf-8?B?eFp2cVM1TnVKZkN0SUtJVTE0NCszcnliRGFaU3oveThjbjJJY3pBWW00ZEZr?= =?utf-8?B?QUt6QmlJZVVkNnVHS204TVJ0NGx5bGlaRWl5Q0I5OWZsdmlwQ2ZtZUFWS3JZ?= =?utf-8?B?a3owV0U5dzRBblBxRm9PbEE3Wm0rdy9DNTJ1d2wzalNiVWVEaHNsRTVvZU9h?= =?utf-8?B?VWhHd2pZU0YwaVRpZys1MDRUMG9BZ29EbnZ5Ky9tQzRHQ0NwMnYwM2lsdkF2?= =?utf-8?B?V21xamdJWEtGd1VPU1duNW51anNzaXN5LysyYWYxQnRsdmhYVk8yL0EydlJD?= =?utf-8?B?Zm55YVNSOTI5SWdqODFNVWQwVHgzVW9TRW9oVGIyaWJlMXEydU9KcExOc3dS?= =?utf-8?B?S3BnZjRkcjZKZzBNQkpYY1VPUXJmYklGV05sK2ZkeWZyYmg5d2xVSVRreTdr?= =?utf-8?B?aXlmWXpISkY1M0tzTkg2Ync1ZE5CQjJFYWw1dVJJZmt3Qk9uc2hHbUMweDA0?= =?utf-8?B?V1lZMlFuc3JQbGEvNEFYYm5xWUprb1ZuTzBSMk5BeTN3SEpNYUdyQ3BSTUZr?= =?utf-8?B?UHJXUXhEYzBIMHNZQm43TU9HT0xQZHlaRnp0SUQrNndodXhpbFJpTGQ0bWFs?= =?utf-8?B?SGsrb242d2doLzZVbzZOTVU5ZUh5cDRZTnVCTEdodTlMeFNleEczVEsvcG1K?= =?utf-8?Q?y1RgS7F3eZN8AKQi2JlswGaGkYHoz8mw?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:TYZPR03MB5536.apcprd03.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(376014)(7416014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?WGJjdE1VMUxnV2JBV0hCS3BERWlHdUhKay95alRvTExrOWNKN202c2hYd0do?= =?utf-8?B?RW44MHcyY0FneFFXVk9WdDlIOGthWlovWi9oU3FvNS9ZQU9wcHVHUEM2SzM0?= =?utf-8?B?bFhCbVo5b2lQR0NGRnB0SmdsZXU0dWUvbldjRkdLRXY3MitHZ3E0bTlCNmZ2?= =?utf-8?B?VCtCMVhzQVdNZDFRTmhRSVdWYzh4a2xDK2p3d214YXRzUTVxTkRCSTlJaW11?= =?utf-8?B?U3FPU0dVejhqWHBLdnFyaDJVbU9DZXhKNWxSZ3FoWDNDdDBHZXZsaW5HaWVJ?= =?utf-8?B?a0kvVUtDa0tmbnlzbThoNTVWZEFIVC9PQkVnS3A5Yis4L2JCM1pha1lnd1ZN?= =?utf-8?B?RGwyaG9rWWtLWVBlTFI1K3U4WnNTOFdMczlUOWZpZTVYcE84dGgzVFJJVVoz?= =?utf-8?B?RkdsK1B1Z3hLcVN5NE5kamZVRG56UlVrQzNsOWpLZnVqSDRCUUZnQ21xL2hH?= =?utf-8?B?aVpOS2gzdE5ITTVyS2hhNG5hdllTOGg4VU9tSkZnb1didmgvZzJZZWFBaU94?= =?utf-8?B?S3RmdXpnamVPaWQ5OG5RUU0yeTN2Q1dDczVNZ0ZPMlJGUlhmZlJEUitlN2hY?= =?utf-8?B?czR1dmtuUHdmU0JUaVNuOHJ3ditKMk1CYzNRV3IxeC9LUVE1L3MxNGd1cE5w?= =?utf-8?B?UTRhMENidGRxVHNjQkU1SFY2V29hQ25lUVNsMEI1UzdFYjJhK29NK0g0N1p5?= =?utf-8?B?THFxLzdyY2F2YTluUHRkTkNGNlZYVGd5TVIvQ3BJNkNxUWUreisyWEdEbEJ2?= =?utf-8?B?TUUzRXM5Zi90MndiYWw4ZWY0MHZjM1FpRVUvOTYyQXlJOGk1UEtJWCtXdDlY?= =?utf-8?B?aFY1SkhZOFhTY3NCc2lvSUZERFRqYk9JRlA3ZGFCZWZTMnBkZExEZlN4U2gr?= =?utf-8?B?NExFNkpoMHgxVDd5R0dCRmJWOVo2dzBsMURpSVhDckl4VzZLbkVyaGtDL0ZI?= =?utf-8?B?K0FQVHQ2ZnNua25lNlc2MGRVNklWdWFxVWRjdVNTZ0F6Z0hJOUZRbmlHbnho?= =?utf-8?B?eHBaRWZYcENQT1VuUG9JcGtHaHl5QmhkbG4weVo5SEkzYXFQNmQ3WkdZNDVD?= =?utf-8?B?VXM1eHkwTnpQVlZRdUFlKzh5dE11SWdIK21MWUM5SGVvMnpxcUdoOWRHNysx?= =?utf-8?B?UUZXaS84WFFvRndhY3ovQzl1UWs3ZmNNTHozMVBLY0Q2bUVvdVRYQWJ2NzNG?= =?utf-8?B?em9FY1UvNjRuTy9udk8wVGE5Y2tkNXRzUmUySnVSYjRidjhNeEwvNDNQQWtz?= =?utf-8?B?cUxTMENzc2VIMG1CajBBSkJVa2RBSlhJejVrQ09pbGdZd2xMU1FvbE0zOVJQ?= =?utf-8?B?aDVkWnk2ZW9lQThETVdnM09HMjI2SEFHZ0s1TFF2R3R0Z0FhY3FrWHVvSWFX?= =?utf-8?B?cjlFWEtnZDVMTk9lbVNsVU8zN20rNk9kNHJBVlJLVTB6enNmcWx2WkZSWHVm?= =?utf-8?B?NGNKUnZXMkNVTk1lcnRFOHRhMUYxK2NNc0NoM1Y2a3BxWC9pd1pxSG9TZHl6?= =?utf-8?B?dHBZR3d2d09yanlDaUhOYkhhcjF1VE84T3lsR3V0eXJ4NjhldFZ3TGtFUzli?= =?utf-8?B?dXBRa3RsR0ZKU1IxM09CT0ZXeDd5d2JaYTc1UnVORE1xZy9CeE9UdGVEQU1o?= =?utf-8?B?U3Mzd2RjditpdmJmcS9EZUM4Ui90MFZubkY5RnNlcDlDbjJZS3cyU01pUnRY?= =?utf-8?B?N1loaGNvMDhlSGhiclEyTENuV2tDbTJzVHRPOUE1QnBLVXNrdGJMWWNuWlQ1?= =?utf-8?B?MVp1bEdDZ1djblJXVnhIM2M3NVZaWHRRbE5YVk1ZLzhuOUc0Tjlxd3ROZG1E?= =?utf-8?B?YkJTenJNdFJEYjhQTjliaFoyUWxBa3JKOW90eVVEMDRKY1JJYTdZS2duVmZK?= =?utf-8?B?Y0tyRktUU20wTHlEcXF2YnBjMjRTQi9SeFV5LzRjSGwwcGJsQjcwUlN4U0l2?= =?utf-8?B?VW5DWlA5Q2J4ZDkzRjZrV1hjVmVTdFdVWmtvcmJXcjRnck4yL0o0bFFzdVkx?= =?utf-8?B?c1MwTlVlUEdYUXRTQThsQjdEeVhIODA0aWo3NURIK2RYeWlzdEJrbGV2T0tI?= =?utf-8?B?akY2blpVaGJYVjhGR25QbU8zd2s5SFUrcjRtb3dCdDVyYTJ4dHhtU3ExREc2?= =?utf-8?B?ekdDbkUwajZFMGMyS0gzUVNZS1VUUVBxVlhWQ0lTQTc2a2xudi9valZITGtG?= =?utf-8?B?VEE9PQ==?= X-OriginatorOrg: amlogic.com X-MS-Exchange-CrossTenant-Network-Message-Id: a9897d4f-990c-4fd2-6aae-08de161bdf1d X-MS-Exchange-CrossTenant-AuthSource: TYZPR03MB5536.apcprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Oct 2025 12:16:50.3332 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 0df2add9-25ca-4b3a-acb4-c99ddf0b1114 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: /ge881ll7himgtLKU4NzLedj7Dp3wYWZqERX8j6DRIUyG2SPqUUYMFx5YAoBO54r5ZU4gk/Tx/U9C5PMqc5CMg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SEZPR03MB7811 在 2025/10/28 19:01, Neil Armstrong 写道: > [ EXTERNAL EMAIL ] > > Hi, > > On 10/27/25 06:42, Zhentao Guo via B4 Relay wrote: >> From: Zhentao Guo >> >> This patch introduces initial driver support for Amlogic's new >> video acceleration hardware architecture, designed for video >> stream decoding. The driver is designed to support the >> V4L2 M2M stateless decoder API. In phase 1, it supports H.264 >> bitstreams decoding. >> >> Signed-off-by: Zhentao Guo >> --- >>   MAINTAINERS                                        |    7 + >>   drivers/media/platform/amlogic/Kconfig             |    2 + >>   drivers/media/platform/amlogic/Makefile            |    1 + >>   drivers/media/platform/amlogic/vdec/Kconfig        |   15 + >>   drivers/media/platform/amlogic/vdec/Makefile       |    4 + >>   drivers/media/platform/amlogic/vdec/aml_vdec.c     |  759 +++++++++ >>   drivers/media/platform/amlogic/vdec/aml_vdec.h     |   31 + >>   .../platform/amlogic/vdec/aml_vdec_canvas_utils.c  |  154 ++ >>   .../platform/amlogic/vdec/aml_vdec_canvas_utils.h  |   22 + >>   drivers/media/platform/amlogic/vdec/aml_vdec_drv.c |  263 +++ >>   drivers/media/platform/amlogic/vdec/aml_vdec_drv.h |  194 +++ >>   drivers/media/platform/amlogic/vdec/aml_vdec_hw.c  |  652 +++++++ >>   drivers/media/platform/amlogic/vdec/aml_vdec_hw.h  |  182 ++ >>   .../platform/amlogic/vdec/aml_vdec_platform.c      |   37 + >>   .../platform/amlogic/vdec/aml_vdec_platform.h      |   62 + >>   drivers/media/platform/amlogic/vdec/h264.c         | 1790 >> ++++++++++++++++++++ >>   drivers/media/platform/amlogic/vdec/h264.h         |  300 ++++ >>   drivers/media/platform/amlogic/vdec/reg_defines.h  |  175 ++ >>   18 files changed, 4650 insertions(+) >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 5ea78444f035..f400b5dabf30 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -1352,6 +1352,13 @@ S:     Maintained >>   F: Documentation/devicetree/bindings/spi/amlogic,a4-spisg.yaml >>   F:  drivers/spi/spi-amlogic-spisg.c >> >> +AMLOGIC VCODEC DRIVER >> +M:   Zhentao Guo >> +L:   linux-media@vger.kernel.org >> +S:   Maintained >> +F: Documentation/devicetree/bindings/media/amlogic,vcodec-dec.yaml >> +F:   drivers/media/platform/amlogic/vdec/ >> + >>   AMPHENOL CHIPCAP 2 DRIVER >>   M:  Javier Carrasco >>   L:  linux-hwmon@vger.kernel.org >> diff --git a/drivers/media/platform/amlogic/Kconfig >> b/drivers/media/platform/amlogic/Kconfig >> index 458acf3d5fa8..8132f5b9282b 100644 >> --- a/drivers/media/platform/amlogic/Kconfig >> +++ b/drivers/media/platform/amlogic/Kconfig >> @@ -4,3 +4,5 @@ comment "Amlogic media platform drivers" >> >>   source "drivers/media/platform/amlogic/c3/Kconfig" >>   source "drivers/media/platform/amlogic/meson-ge2d/Kconfig" >> + >> +source "drivers/media/platform/amlogic/vdec/Kconfig" > > PLease respect original formatting and drop the empty line Got it, I'll correct this. > >> diff --git a/drivers/media/platform/amlogic/Makefile >> b/drivers/media/platform/amlogic/Makefile >> index c744afcd1b9e..7409de674c0b 100644 >> --- a/drivers/media/platform/amlogic/Makefile >> +++ b/drivers/media/platform/amlogic/Makefile >> @@ -2,3 +2,4 @@ >> >>   obj-y += c3/ >>   obj-y += meson-ge2d/ >> +obj-y += vdec/ > > Ditto> diff --git a/drivers/media/platform/amlogic/vdec/Kconfig > b/drivers/media/platform/amlogic/vdec/Kconfig I'm sorry, I did not get what you mean here. It is a mistake? >> new file mode 100644 >> index 000000000000..05c4568e058b >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/Kconfig >> @@ -0,0 +1,15 @@ >> +# SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> + >> +config VIDEO_AMLOGIC_VCODEC >> +    tristate "Amlogic Video Codec Driver" >> +    depends on ARCH_MESON || COMPILE_TEST >> +    depends on VIDEO_DEV >> +    depends on V4L_MEM2MEM_DRIVERS >> +    select VIDEOBUF2_DMA_CONTIG >> +    select V4L2_H264 >> +    select V4L2_MEM2MEM_DEV >> +    help >> +      This is a v4l2 driver for Amlogic video codec driver. >> +       This driver is designed to support V4L2 M2M STATELESS >> +       interface. >> +      To compile this driver as a module choose m here. >> diff --git a/drivers/media/platform/amlogic/vdec/Makefile >> b/drivers/media/platform/amlogic/vdec/Makefile >> new file mode 100644 >> index 000000000000..f645f7ca5e2d >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/Makefile >> @@ -0,0 +1,4 @@ >> +# SPDX-License-Identifier: GPL-2.0-only >> +aml-vdec-drv-objs := aml_vdec.o aml_vdec_drv.o aml_vdec_hw.o >> aml_vdec_platform.o h264.o aml_vdec_canvas_utils.o\ >> + >> +obj-$(CONFIG_VIDEO_AMLOGIC_VCODEC) += aml-vdec-drv.o >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec.c >> b/drivers/media/platform/amlogic/vdec/aml_vdec.c >> new file mode 100644 >> index 000000000000..e8a66bde0397 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec.c >> @@ -0,0 +1,759 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "aml_vdec.h" >> +#include "aml_vdec_hw.h" >> +#include "aml_vdec_platform.h" >> + >> +#define VCODEC_DRV_NAME "aml-vdec-drv" >> + >> +static const struct aml_vdec_v4l2_ctrl controls[] = { >> +     { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_STATELESS_H264_SPS, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_STATELESS_H264_PPS, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_STATELESS_H264_DECODE_MODE, >> +                     .min = >> V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, >> +                     .def = >> V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, >> +                     .max = >> V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_STATELESS_H264_START_CODE, >> +                     .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, >> +                     .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, >> +                     .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, >> +             }, >> +     }, { >> +             .codec_type = CODEC_TYPE_H264, >> +             .cfg = { >> +                     .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, >> +                     .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, >> +                     .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, >> +                     .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, >> +             }, >> +     } >> +}; >> + >> +static struct aml_video_fmt aml_video_formats[] = { >> +     { >> +             .name = "H.264", >> +             .fourcc = V4L2_PIX_FMT_H264_SLICE, >> +             .type = AML_FMT_DEC, >> +             .codec_type = CODEC_TYPE_H264, >> +             .num_planes = 1, >> +             .stepwise = {AML_VDEC_MIN_W, AML_VDEC_1080P_MAX_W, 2, >> +                     AML_VDEC_MIN_H, AML_VDEC_1080P_MAX_H, 2}, >> +     }, >> +     { >> +             .name = "NV21M", >> +             .fourcc = V4L2_PIX_FMT_NV21M, >> +             .type = AML_FMT_FRAME, >> +             .codec_type = CODEC_TYPE_FRAME, >> +             .num_planes = 2, >> +             .stepwise = {AML_VDEC_MIN_W, AML_VDEC_1080P_MAX_W, 2, >> +                     AML_VDEC_MIN_H, AML_VDEC_1080P_MAX_H, 2}, >> +     }, >> +     { >> +             .name = "NV21", >> +             .fourcc = V4L2_PIX_FMT_NV21, >> +             .type = AML_FMT_FRAME, >> +             .codec_type = CODEC_TYPE_FRAME, >> +             .num_planes = 1, >> +             .stepwise = {AML_VDEC_MIN_W, AML_VDEC_1080P_MAX_W, 2, >> +                     AML_VDEC_MIN_H, AML_VDEC_1080P_MAX_H, 2}, >> +     }, >> +     { >> +             .name = "NV12M", >> +             .fourcc = V4L2_PIX_FMT_NV12M, >> +             .type = AML_FMT_FRAME, >> +             .codec_type = CODEC_TYPE_FRAME, >> +             .num_planes = 2, >> +             .stepwise = {AML_VDEC_MIN_W, AML_VDEC_1080P_MAX_W, 2, >> +                     AML_VDEC_MIN_H, AML_VDEC_1080P_MAX_H, 2}, >> + >> +     }, >> +     { >> +             .name = "NV12", >> +             .fourcc = V4L2_PIX_FMT_NV12, >> +             .type = AML_FMT_FRAME, >> +             .codec_type = CODEC_TYPE_FRAME, >> +             .num_planes = 1, >> +             .stepwise = {AML_VDEC_MIN_W, AML_VDEC_1080P_MAX_W, 2, >> +                     AML_VDEC_MIN_H, AML_VDEC_1080P_MAX_H, 2}, >> +     }, >> +}; >> + >> +void aml_vdec_set_default_params(struct aml_vdec_ctx *ctx) >> +{ >> +     struct aml_q_data *q_data = NULL; >> + >> +     ctx->m2m_ctx->q_lock = &ctx->v4l2_intf_lock; >> + >> +     ctx->pic_info.colorspace = V4L2_COLORSPACE_DEFAULT; >> +     ctx->pic_info.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; >> +     ctx->pic_info.quantization = V4L2_QUANTIZATION_DEFAULT; >> +     ctx->pic_info.xfer_func = V4L2_XFER_FUNC_DEFAULT; >> + >> +     q_data = &ctx->q_data[AML_Q_DATA_SRC]; >> +     memset(q_data, 0, sizeof(struct aml_q_data)); >> +     q_data->visible_width = AML_VDEC_MIN_W; >> +     q_data->visible_height = AML_VDEC_MIN_H; >> +     q_data->coded_width = AML_VDEC_MIN_W; >> +     q_data->coded_height = AML_VDEC_MIN_H; >> +     q_data->filed_flag = V4L2_FIELD_NONE; >> +     q_data->bytesperline[0] = 0; >> +     q_data->sizeimage[0] = (1024 * 1024); >> +     q_data->fmt = &aml_video_formats[DEFAULT_OUT_IDX]; >> + >> +     q_data = &ctx->q_data[AML_Q_DATA_DST]; >> +     memset(q_data, 0, sizeof(struct aml_q_data)); >> +     q_data->visible_width = AML_VDEC_MIN_W; >> +     q_data->visible_height = AML_VDEC_MIN_H; >> +     q_data->coded_width = AML_VDEC_MIN_W; >> +     q_data->coded_height = AML_VDEC_MIN_H; >> +     q_data->filed_flag = V4L2_FIELD_NONE; >> +     q_data->bytesperline[0] = q_data->coded_width; >> +     q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; >> +     q_data->bytesperline[1] = q_data->coded_width; >> +     q_data->sizeimage[1] = q_data->sizeimage[0] / 2; >> +     q_data->fmt = &aml_video_formats[DEFAULT_CAP_IDX]; >> +} >> + >> +int aml_vdec_ctrls_setup(struct aml_vdec_ctx *ctx) >> +{ >> +     int i; >> +     int ctrls_size = sizeof(controls) / sizeof(struct >> aml_vdec_v4l2_ctrl); >> + >> +     v4l2_ctrl_handler_init(&ctx->ctrl_handler, ctrls_size); >> +     for (i = 0; i < ctrls_size; i++) { >> +             v4l2_ctrl_new_custom(&ctx->ctrl_handler, >> &controls[i].cfg, NULL); >> +             if (ctx->ctrl_handler.error) { >> +                     pr_debug("add ctrl for (%d) failed%d\n", >> +                              controls[i].cfg.id, >> ctx->ctrl_handler.error); >> + v4l2_ctrl_handler_free(&ctx->ctrl_handler); >> +                     return ctx->ctrl_handler.error; >> +             } >> +     } >> +     ctx->fh.ctrl_handler = &ctx->ctrl_handler; >> +     return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); >> +} >> + >> +static void m2mops_vdec_device_run(void *m2m_priv) >> +{ >> +     struct aml_vdec_ctx *ctx = (struct aml_vdec_ctx *)m2m_priv; >> +     struct aml_vdec_dev *dev = ctx->dev; >> +     struct vb2_v4l2_buffer *src, *dst; >> +     struct media_request *src_req; >> +     const char *fw_path = >> dev->pvdec_data->fw_path[ctx->curr_dec_type]; >> + >> +     src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); >> +     dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); >> +     pr_debug("device run : src buf : %d dst buf %d\n", >> src->vb2_buf.index, dst->vb2_buf.index); > > Switch to dev_dbg everywhere OK, I'll replace all these pr_xxx with dev_debug. > >> + >> +     src_req = src->vb2_buf.req_obj.req; >> +     if (src_req) >> +             v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); >> + >> +     dos_enable(); >> +     /* incase of bus hang in stop_streaming */ >> +     ctx->dos_clk_en = 1; >> +     aml_vdec_reset_core(); >> +     load_firmware(dev->dec_hw, fw_path); >> + >> +     if (ctx->codec_ops->run) >> +             ctx->codec_ops->run(ctx); >> + >> +     v4l2_m2m_buf_copy_metadata(src, dst); >> +     if (src_req) >> +             v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler); >> + >> +     v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, >> ctx->m2m_ctx, VB2_BUF_STATE_DONE); >> +} >> + >> +const struct v4l2_m2m_ops aml_vdec_m2m_ops = { >> +     .device_run = m2mops_vdec_device_run, >> +}; >> + >> +static int vidioc_vdec_querycap(struct file *file, void *priv, >> +                             struct v4l2_capability *cap) >> +{ >> +     strscpy(cap->driver, VCODEC_DRV_NAME, sizeof(cap->driver)); >> +     strscpy(cap->card, "platform:" VCODEC_DRV_NAME, >> sizeof(cap->card)); >> + >> +     return 0; >> +} >> + >> +static int vidioc_vdec_enum_fmt(struct v4l2_fmtdesc *f, bool is_output) >> +{ >> +     struct aml_video_fmt *fmt; >> +     int fmt_size = sizeof(aml_video_formats) / sizeof(struct >> aml_video_fmt); >> +     int i = 0, j = 0; >> + >> +     for (; i < fmt_size; i++) { >> +             fmt = &aml_video_formats[i]; >> +             if (is_output && fmt->type != AML_FMT_DEC) >> +                     continue; >> +             if (!is_output && fmt->type != AML_FMT_FRAME) >> +                     continue; >> + >> +             if (j == f->index) { >> +                     f->pixelformat = fmt->fourcc; >> +                     strscpy(f->description, fmt->name, >> +                             sizeof(f->description)); >> +                     if (strlen(fmt->name) >= sizeof(f->description)) { >> +                             pr_err("fmt name string is too long!\n"); >> + f->description[sizeof(f->description) - 1] = '\0'; >> +                     } >> +                     return 0; >> +             } >> +             ++j; >> +     } >> +     return -EINVAL; >> +} >> + >> +static struct aml_q_data *aml_vdec_get_qdata_by_type(struct >> aml_vdec_ctx *ctx, >> +                                                  enum v4l2_buf_type >> type) >> +{ >> +     if (V4L2_TYPE_IS_OUTPUT(type)) >> +             return &ctx->q_data[AML_Q_DATA_SRC]; >> + >> +     return &ctx->q_data[AML_Q_DATA_DST]; >> +} >> + >> +static struct aml_video_fmt *aml_vdec_get_video_fmt(u32 format) >> +{ >> +     struct aml_video_fmt *fmt; >> +     unsigned int k; >> + >> +     for (k = 0; k < (sizeof(aml_video_formats) / sizeof(struct >> aml_video_fmt)); k++) { >> +             fmt = &aml_video_formats[k]; >> +             if (fmt->fourcc == format) >> +                     return fmt; >> +     } >> + >> +     return NULL; >> +} >> + >> +static int aml_vdec_init_dec_inst(struct aml_vdec_ctx *ctx, >> +                               struct aml_video_fmt *fmt_out) >> +{ >> +     struct aml_vdec_dev *dev = ctx->dev; >> +     int ret = -1; >> + >> +     if (!fmt_out) >> +             return ret; >> + >> +     if (fmt_out->codec_type == CODEC_TYPE_FRAME) { >> +             pr_debug("capture type no need to set\n"); >> +             return 0; >> +     } >> + >> +     ctx->codec_ops = &dev->pvdec_data->codec_ops[fmt_out->codec_type]; >> +     if (ctx->codec_ops->init) { >> +             ret = ctx->codec_ops->init(ctx); >> +             if (ret < 0) >> +                     return ret; >> +     } >> +     ctx->curr_dec_type = fmt_out->codec_type; >> +     pr_info("%s set curr_dec_type = %d\n", __func__, >> ctx->curr_dec_type); > > And dev_info/dev_err/dev_warn... Got it. I'll get rid of them and replace with dev logs. > >> + >> +     return ret; >> +} >> + > > > >> diff --git >> a/drivers/media/platform/amlogic/vdec/aml_vdec_canvas_utils.c >> b/drivers/media/platform/amlogic/vdec/aml_vdec_canvas_utils.c >> new file mode 100644 >> index 000000000000..066958118b00 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_canvas_utils.c >> @@ -0,0 +1,154 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#include "aml_vdec_canvas_utils.h" >> + >> +#define CANVAS_REG_OFFSET   (0x12 << 2) >> + >> +/* >> + * DMC_CAV_LUT_DATAL/DMC_CAV_LUT_DATAH >> + * high 32bits of canvas data which need to be configured >> + * to canvas memory. >> + * 64bits CANVAS look up table >> + * bit 61 : 58   Endian control. >> + * bit 61 :  1 : switch 2 64bits data inside 128bits boundary. >> + * 0 : no change. >> + * bit 60 :  1 : switch 2 32bits data inside 64bits data boundary. >> + * 0 : no change. >> + * bit 59 :  1 : switch 2 16bits data inside 32bits data boundary. >> + * 0 : no change. >> + * bit 58 :  1 : switch 2 8bits data  inside 16bits data boundary. >> + * 0 : no change. >> + * bit 57 : 56.   Canvas block mode.  2 : 64x32, 1: 32x32; >> + *  0 : linear mode. >> + * bit 55 :      canvas Y direction wrap control. >> + * 1: wrap back in y.  0: not wrap back. >> + * bit 54 :      canvas X direction wrap control. >> + * 1: wrap back in X.  0: not wrap back. >> + * bit 53 : 41.   canvas Hight. >> + * bit 40 : 29.   canvas Width, unit: 8bytes. must in 32bytes boundary. >> + * that means last 2 bits must be 0. >> + * bit 28 : 0.    canvas start address.   unit. 8 bytes. must be in >> + * 32bytes boundary. that means last 2bits must be 0. >> + */ >> + >> +#define CANVAS_WADDR_LBIT       0 >> +#define CANVAS_WIDTH_LBIT       29 >> +#define CANVAS_HEIGHT_HBIT      (41 - 32) >> +#define CANVAS_WRAPX_HBIT       (54 - 32) >> +#define CANVAS_WRAPY_HBIT       (55 - 32) >> +#define CANVAS_BLKMODE_HBIT     (56 - 32) >> +#define CANVAS_ENDIAN_HBIT      (58 - 32) >> + >> +/* canvas regs */ >> +#define DC_CAV_LUT_DATAL        0x12 >> +#define DC_CAV_LUT_DATAH        0x13 >> +#define DC_CAV_LUT_ADDR         0x14 >> +#define DC_CAV_LUT_RDATAL       0x15 >> +#define DC_CAV_LUT_RDATAH       0x16 >> + >> +#define CANVAS_ADDR_LMASK       0x1fffffff >> +#define CANVAS_WIDTH_LMASK      0x7 >> +#define CANVAS_WIDTH_LWID       3 >> +#define CANVAS_WIDTH_HMASK      0x1ff >> +#define CANVAS_WIDTH_HBIT       0 >> +#define CANVAS_HEIGHT_MASK      0x1fff >> +#define CANVAS_HEIGHT_BIT       9 >> +#define CANVAS_ADDR_NOWRAP      0x00 >> +#define CANVAS_ADDR_WRAPX       0x01 >> +#define CANVAS_ADDR_WRAPY       0x02 >> +#define CANVAS_BLKMODE_MASK     0x03 >> + >> +#define CANVAS_BLKMODE_LINEAR   0x00 >> +#define CANVAS_BLKMODE_32X32    0x01 >> +#define CANVAS_BLKMODE_64X32    0x02 >> + >> +#define CANVAS_LUT_WR_EN   (0x2 << 8) >> +#define CANVAS_LUT_RD_EN   (0x1 << 8) >> + >> +#define CANVAS_ADDR_BITS_MASK                GENMASK(28, 0) >> +#define CANVAS_WIDTH_L_MASK          GENMASK(31, 29) >> +#define CANVAS_WIDTH_H_MASK          GENMASK(8, 0) >> +#define CANVAS_HEIGHT_H_MASK         GENMASK(21, 9) >> +#define CANVAS_WRAP_H_MASK           GENMASK(23, 23) >> +#define CANVAS_BLOCK_H_MASK          GENMASK(25, 24) >> +#define CANVAS_BITS_CTRL_MASK                GENMASK(29, 26) >> + >> +static struct vdec_canvas_s canvas; > > There's already a canvas driver for that, please use it and extend it > if necessary: > drivers/soc/amlogic/meson-canvas.c Ok, I'll check if we can use the existing canvas interfaces. > > >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec_drv.c >> b/drivers/media/platform/amlogic/vdec/aml_vdec_drv.c >> new file mode 100644 >> index 000000000000..ef2c779839d8 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_drv.c >> @@ -0,0 +1,263 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> + >> +#include "aml_vdec.h" >> +#include "aml_vdec_hw.h" >> +#include "aml_vdec_platform.h" >> + >> +#define AML_VDEC_DRV_NAME "aml-vdec-drv" >> + >> +static int fops_vcodec_open(struct file *file) >> +{ >> +     struct aml_vdec_dev *dec_dev = video_drvdata(file); >> +     struct aml_vdec_ctx *ctx = NULL; >> +     int ret = 0; >> + >> +     ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); >> +     if (!ctx) >> +             return -ENOMEM; >> + >> +     mutex_lock(&dec_dev->dev_mutex); >> +     dec_dev->dec_ctx = ctx; >> +     ctx->dev = dec_dev; >> +     v4l2_fh_init(&ctx->fh, video_devdata(file)); >> +     file->private_data = &ctx->fh; >> +     v4l2_fh_add(&ctx->fh, file); >> +     dec_dev->filp = file; >> +     mutex_init(&ctx->v4l2_intf_lock); >> +     init_waitqueue_head(&ctx->queue); >> +     ctx->int_cond = 0; >> + >> +     ctx->m2m_ctx = v4l2_m2m_ctx_init(dec_dev->m2m_dev_dec, ctx, >> + &aml_vdec_queue_init); >> +     if (IS_ERR((__force void *)ctx->m2m_ctx)) { >> +             ret = PTR_ERR((__force void *)ctx->m2m_ctx); >> +             v4l2_err(&dec_dev->v4l2_dev, "Failed to >> v4l2_m2m_ctx_init() (%d)", ret); >> +             goto err_m2m_ctx_init; >> +     } >> + >> +     ctx->fh.m2m_ctx = ctx->m2m_ctx; >> +     ret = aml_vdec_ctrls_setup(ctx); >> +     if (ret) { >> +             v4l2_err(&dec_dev->v4l2_dev, "Failed to init all ctrls >> (%d)", ret); >> +             goto err_ctrls_setup; >> +     } >> + >> +     aml_vdec_set_default_params(ctx); >> +     mutex_unlock(&dec_dev->dev_mutex); >> + >> +     return ret; >> + >> +err_ctrls_setup: >> +     v4l2_m2m_ctx_release(ctx->m2m_ctx); >> +err_m2m_ctx_init: >> +     v4l2_fh_del(&ctx->fh, file); >> +     v4l2_fh_exit(&ctx->fh); >> +     kfree(ctx); >> +     mutex_unlock(&dec_dev->dev_mutex); >> + >> +     return ret; >> +} >> + >> +static int fops_vcodec_release(struct file *file) >> +{ >> +     struct aml_vdec_dev *dec_dev = video_drvdata(file); >> +     struct aml_vdec_ctx *ctx = fh_to_dec_ctx(file->private_data); >> + >> +     mutex_lock(&dec_dev->dev_mutex); >> +     v4l2_ctrl_handler_free(&ctx->ctrl_handler); >> +     v4l2_m2m_ctx_release(ctx->m2m_ctx); >> +     v4l2_fh_del(&ctx->fh, file); >> +     v4l2_fh_exit(&ctx->fh); >> +     kfree(ctx); >> +     mutex_unlock(&dec_dev->dev_mutex); >> + >> +     return 0; >> +} >> + >> +static const struct v4l2_file_operations aml_vdec_fops = { >> +     .owner        = THIS_MODULE, >> +     .open        = fops_vcodec_open, >> +     .release    = fops_vcodec_release, >> +     .poll        = v4l2_m2m_fop_poll, >> +     .unlocked_ioctl    = video_ioctl2, >> +     .mmap        = v4l2_m2m_fop_mmap, >> +}; >> + >> +static const struct video_device dec_dev = { >> +     .name = "aml_dev_drv", >> +     .fops = &aml_vdec_fops, >> +     .ioctl_ops = &aml_vdec_ioctl_ops, >> +     .release = video_device_release, >> +     .vfl_dir = VFL_DIR_M2M, >> +     .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, >> +}; >> + >> +static const struct media_device_ops aml_m2m_media_ops = { >> +     .req_validate = vb2_request_validate, >> +     .req_queue = v4l2_m2m_request_queue, >> +}; >> + >> +static int aml_vdec_drv_probe(struct platform_device *pdev) >> +{ >> +     struct aml_vdec_dev *dev; >> +     struct video_device *vfd_dec; >> +     struct aml_vdec_hw *hw; >> +     int ret = 0; >> + >> +     dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); >> +     if (!dev) >> +             return -ENOMEM; >> + >> +     dev->plat_dev = pdev; >> +     mutex_init(&dev->dev_mutex); >> + >> +     ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); >> +     if (ret) >> +             return dev_err_probe(&pdev->dev, ret, >> "v4l2_device_register err\n"); >> + >> +     vfd_dec = video_device_alloc(); >> +     if (!vfd_dec) { >> +             v4l2_err(&dev->v4l2_dev, "Failed to allocate video >> device\n"); >> +             ret = -ENOMEM; >> +             goto err_device_alloc; >> +     } >> +     *vfd_dec = dec_dev; >> +     vfd_dec->v4l2_dev = &dev->v4l2_dev; >> +     vfd_dec->lock = &dev->dev_mutex; >> +     video_set_drvdata(vfd_dec, dev); >> +     dev->vfd = vfd_dec; >> +     platform_set_drvdata(pdev, dev); >> + >> +     hw = kzalloc(sizeof(*hw), GFP_KERNEL); >> +     if (!hw) { >> +             ret = -ENOMEM; >> +             goto err_dec_mem_init; >> +     } >> +     dev->dec_hw = hw; >> + >> +     dev->pvdec_data = of_device_get_match_data(&pdev->dev); >> +     ret = dev->pvdec_data->req_hw_resource(dev); >> +     if (ret < 0) >> +             goto err_hw_init; >> + >> +     dev->m2m_dev_dec = v4l2_m2m_init(&aml_vdec_m2m_ops); >> +     if (IS_ERR((__force void *)dev->m2m_dev_dec)) { >> +             v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem dec >> device\n"); >> +             ret = PTR_ERR((__force void *)dev->m2m_dev_dec); >> +             goto err_hw_init; >> +     } >> + >> +     ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1); >> +     if (ret) { >> +             v4l2_err(&dev->v4l2_dev, "Failed to register video >> device"); >> +             goto err_vid_dev_register; >> +     } >> + >> +     v4l2_info(&dev->v4l2_dev, "Registered %s as /dev/%s\n", >> +               vfd_dec->name, video_device_node_name(vfd_dec)); >> + >> +     dev->mdev.dev = &pdev->dev; >> +     strscpy(dev->mdev.model, AML_VDEC_DRV_NAME, >> sizeof(dev->mdev.model)); >> +     media_device_init(&dev->mdev); >> +     dev->mdev.ops = &aml_m2m_media_ops; >> +     dev->v4l2_dev.mdev = &dev->mdev; >> + >> +     ret = v4l2_m2m_register_media_controller(dev->m2m_dev_dec, >> vfd_dec, >> + MEDIA_ENT_F_PROC_VIDEO_DECODER); >> +     if (ret) { >> +             v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media >> controller\n"); >> +             goto error_m2m_mc_register; >> +     } >> + >> +     ret = media_device_register(&dev->mdev); >> +     if (ret) { >> +             v4l2_err(&dev->v4l2_dev, "Failed to register media >> device"); >> +             goto err_media_dev_register; >> +     } >> +     vdec_enable(dev->dec_hw); >> +     return 0; >> + >> +err_media_dev_register: >> +     v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec); >> +error_m2m_mc_register: >> +     media_device_cleanup(&dev->mdev); >> +err_vid_dev_register: >> +     v4l2_m2m_release(dev->m2m_dev_dec); >> +err_hw_init: >> +     kfree(hw); >> +     dev->dec_hw = NULL; >> +err_dec_mem_init: >> +     video_device_release(vfd_dec); >> +err_device_alloc: >> +     v4l2_device_unregister(&dev->v4l2_dev); >> +     return ret; >> +} >> + >> +static void aml_vdec_drv_remove(struct platform_device *pdev) >> +{ >> +     struct aml_vdec_dev *dev = platform_get_drvdata(pdev); >> + >> +     vdec_disable(dev->dec_hw); >> + >> +     if (media_devnode_is_registered(dev->mdev.devnode)) { >> +             media_device_unregister(&dev->mdev); >> +             media_device_cleanup(&dev->mdev); >> +     } >> + >> +     if (dev->m2m_dev_dec) >> +             v4l2_m2m_release(dev->m2m_dev_dec); >> +     if (dev->vfd) >> +             video_unregister_device(dev->vfd); >> +     if (dev->dec_hw) >> +             dev->pvdec_data->destroy_hw_resource(dev); >> + >> +     v4l2_device_unregister(&dev->v4l2_dev); >> + >> +     pr_debug("aml v4l2 decoder driver remove\n"); >> +} >> + >> +static const struct of_device_id aml_vdec_match[] = { >> +     {.compatible = "amlogic,s4-vcodec-dec", .data = >> &aml_vdec_s4_pdata}, >> +     {}, >> +}; >> + >> +static struct platform_driver aml_vcodec_dec_driver = { >> +     .probe    = aml_vdec_drv_probe, >> +     .remove    = aml_vdec_drv_remove, >> +     .driver    = { >> +             .name    = AML_VDEC_DRV_NAME, > > Use proper formatting here Could you please give me some examples? Thanks a lot! > >> +             .of_match_table = aml_vdec_match, >> +     }, >> +}; >> + >> +static int __init aml_vdec_init(void) >> +{ >> +     pr_debug("aml v4l2 decoder module init\n"); >> + >> +     if (platform_driver_register(&aml_vcodec_dec_driver)) { >> +             pr_err("failed to register aml v4l2 decoder\n"); >> +             return -ENODEV; >> +     } >> + >> +     return 0; >> +} >> + >> +static void __exit aml_vdec_exit(void) >> +{ >> +     pr_debug("aml v4l2 decoder module exit\n"); >> +     platform_driver_unregister(&aml_vcodec_dec_driver); >> +} >> + >> +module_init(aml_vdec_init); >> +module_exit(aml_vdec_exit); >> + >> +MODULE_DESCRIPTION("Amlogic V4L2 decoder driver"); >> +MODULE_LICENSE("GPL"); >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec_drv.h >> b/drivers/media/platform/amlogic/vdec/aml_vdec_drv.h >> new file mode 100644 >> index 000000000000..f3318cceff3f >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_drv.h >> @@ -0,0 +1,194 @@ >> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#ifndef _AML_VDEC_DRV_H_ >> +#define _AML_VDEC_DRV_H_ >> + >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#define AML_VCODEC_MAX_PLANES 3 >> +#define AML_VDEC_MIN_W    64U >> +#define AML_VDEC_MIN_H    64U >> +#define AML_VDEC_1080P_MAX_H  1088U >> +#define AML_VDEC_1080P_MAX_W  1920U >> + >> +struct aml_vdec_ctx; >> +/** >> + * enum aml_fmt_type - Type of format type >> + */ >> +enum aml_fmt_type { >> +     AML_FMT_DEC = 0, >> +     AML_FMT_FRAME = 1, >> +}; >> + >> +/** >> + * enum aml_codec_type - Type of codec format >> + */ >> +enum aml_codec_type { >> +     CODEC_TYPE_H264 = 0, >> +     CODEC_TYPE_FRAME, >> +}; >> + >> +/** >> + * enum aml_q_type - Type of queue : cap or output >> + */ >> +enum aml_q_type { >> +     AML_Q_DATA_SRC = 0, >> +     AML_Q_DATA_DST = 1, >> +}; >> + >> +/** >> + * struct aml_video_fmt - aml video decoder fmt information >> + * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. >> + * @type: Curr queue type: capture or output. >> + * @codec_type: Codec mode related. See aml_codec_type. >> + * @num_planes: Num planes of the format. >> + * @name: Name of the format. >> + * @stepwise: Supported range of frame sizes (only for bitstream >> formats). >> + */ >> +struct aml_video_fmt { >> +     u32 fourcc; >> +     enum aml_fmt_type type; >> +     enum aml_codec_type codec_type; >> +     u32 num_planes; >> +     const u8 *name; >> +     struct v4l2_frmsize_stepwise stepwise; >> +}; >> + >> +/** >> + * struct aml_q_data - aml video queue information >> + * @visible_width: Width for display. >> + * @visible_height: Height for display. >> + * @coded_width: Width for decode, which is 64/32 aligned. >> + * @coded_height: Height for decode, which is 64/32 aligned. >> + * @filed_flag: Field pic flag. >> + * @bytesperline: Byte num of each pixel line. >> + * @sizeimage: Size of frame in bytes. >> + * @fmt: Format for curr queue. See struct aml_video_fmt. >> + */ >> +struct aml_q_data { >> +     u32 visible_width; >> +     u32 visible_height; >> +     u32 coded_width; >> +     u32 coded_height; >> +     u32 filed_flag; >> +     u32 bytesperline[AML_VCODEC_MAX_PLANES]; >> +     u32 sizeimage[AML_VCODEC_MAX_PLANES]; >> +     struct aml_video_fmt *fmt; >> +}; >> + >> +/** >> + * struct aml_vdec_dev - driver data >> + * @plat_dev: Platform device for the current driver. >> + * @v4l2_dev: V4L2 device to register video devices for. >> + * @m2m_dev_dec: Mem2mem device associated to this device. >> + * @vfd: Video_device associated to this device. >> + * @mdev: Media_device associated to this device. >> + * @dec_ctx: Decoder context. See struct aml_vdec_ctx. >> + * @dec_hw: Decoder hardware resources. See struct aml_vdec_hw. >> + * @pvdec_data: Decoder platform data. See struct >> aml_dev_platform_data. >> + * @dev_mutex: video_device lock. >> + * @filp: v4l2 file handle pointer. >> + */ >> +struct aml_vdec_dev { >> +     struct platform_device *plat_dev; >> +     struct v4l2_device v4l2_dev; >> +     struct v4l2_m2m_dev *m2m_dev_dec; >> +     struct video_device *vfd; >> +     struct media_device mdev; >> + >> +     struct aml_vdec_ctx *dec_ctx; >> +     struct aml_vdec_hw *dec_hw; >> +     const struct aml_dev_platform_data *pvdec_data; >> + >> +     struct mutex dev_mutex; >> +     struct file *filp; >> +}; >> + >> +/** >> + * struct dec_pic_info - pic information description >> + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat >> + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding >> + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function >> + * @quantization: enum v4l2_quantization, colorspace quantization >> + * @cap_pix_fmt: Pixel format for capture queue. >> + * @output_pix_fmt: Pixel format for output queue. >> + * @coded_width: Width for decode. >> + * @coded_height: Height for decode. >> + * @fb_size: Frame buffer size for Y or UV. >> + * @plane_num: Num for planes for curr format. >> + */ >> +struct dec_pic_info { >> +     enum v4l2_colorspace colorspace; >> +     enum v4l2_ycbcr_encoding ycbcr_enc; >> +     enum v4l2_xfer_func xfer_func; >> +     enum v4l2_quantization quantization; >> +     u32 cap_pix_fmt; >> +     u32 output_pix_fmt; >> +     u32 coded_width; >> +     u32 coded_height; >> +     u32 fb_size[2]; >> +     u32 plane_num; >> +}; >> + >> +/** >> + * struct aml_vdec_ctx - driver instance context >> + * @dev: pointer to the aml_vdec_dev of the device. >> + * @fh: struct v4l2 fh. >> + * @m2m_ctx: pointer to v4l2_m2m_ctx context. >> + * @ctrl_handler: V4L2 ctrl handler. >> + * @v4l2_intf_lock: Mutex lock for v4l2 interface. >> + * @codec_ops: Codec operation functions. See struct aml_codec_ops. >> + * @int_cond: Variable used by the waitqueue. >> + * @queue: Waitqueue to wait for the current decode context finish. >> + * @q_data: feature supported by the current decoder instance. >> + * @is_cap_streamon: indicates if the current capture stream is on. >> + * @is_output_streamon: indicates if the current output stream is on. >> + * @dos_clk_en: indicates if dos clk is enabled. >> + * @pic_info: Pic information for curr decoder context. See struct >> dec_pic_info. >> + * @curr_dec_type: Current decoder type. (CODEC_TYPE_H264, etc.) >> + * @codec_priv: Pointer to current decoder instance. >> + */ >> +struct aml_vdec_ctx { >> +     struct aml_vdec_dev *dev; >> +     struct v4l2_fh fh; >> +     struct v4l2_m2m_ctx *m2m_ctx; >> +     struct v4l2_ctrl_handler ctrl_handler; >> +     struct mutex v4l2_intf_lock; >> + >> +     const struct aml_codec_ops *codec_ops; >> +     int int_cond; >> +     wait_queue_head_t queue; >> +     struct aml_q_data q_data[2]; >> + >> +     bool is_cap_streamon; >> +     bool is_output_streamon; >> +     bool dos_clk_en; >> + >> +     struct dec_pic_info pic_info; >> +     u32 curr_dec_type; >> +     void *codec_priv; >> +}; >> + >> +static inline struct aml_vdec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh) >> +{ >> +     return container_of(fh, struct aml_vdec_ctx, fh); >> +} >> + >> +static inline struct aml_vdec_ctx *ctrl_to_dec_ctx(struct >> v4l2_ctrl_handler *ctrl) >> +{ >> +     return container_of(ctrl, struct aml_vdec_ctx, ctrl_handler); >> +} >> + >> +#endif >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec_hw.c >> b/drivers/media/platform/amlogic/vdec/aml_vdec_hw.c >> new file mode 100644 >> index 000000000000..4db0e3076761 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_hw.c >> @@ -0,0 +1,652 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "aml_vdec_drv.h" >> +#include "aml_vdec_hw.h" >> +#include "aml_vdec_platform.h" >> +#include "aml_vdec_canvas_utils.h" >> + >> +#define MHz     (1000000) >> +#define MC_SIZE (4096 * 16) >> + >> +static void __iomem *reg_base[MAX_REG_BUS]; >> + >> +static struct pm_pd_s vdec_domain_data[] = { >> +     [VDEC_1] = {.name = "pwrc-vdec", }, >> +     [VDEC_HEVC] = {.name = "pwrc-hevc", }, >> +}; >> + >> +u32 read_dos_reg(u32 addr) >> +{ >> +     return readl(reg_base[DOS_BUS] + (addr << 2)); >> +} >> + >> +void write_dos_reg(u32 addr, int val) >> +{ >> +     writel(val, reg_base[DOS_BUS] + (addr << 2)); >> +} >> + >> +u32 read_dmc_reg(u32 addr) >> +{ >> +     return readl(reg_base[DMC_BUS] + (addr << 2)); >> +} >> + >> +void write_dmc_reg(u32 addr, int val) >> +{ >> +     writel(val, reg_base[DMC_BUS] + (addr << 2)); >> +} >> + >> +void dos_reg_set_mask(u32 addr, u32 mask) >> +{ >> +     u32 r; >> + >> +     r = read_dos_reg(addr); >> +     write_dos_reg(addr, (r | mask)); >> +} >> + >> +void dos_reg_clear_mask(u32 addr, u32 mask) >> +{ >> +     u32 r; >> + >> +     r = read_dos_reg(addr); >> +     write_dos_reg(addr, (r & (~mask))); >> +} >> + >> +void dos_reg_write_bits(u32 reg, u32 val, int start, int len) >> +{ >> +     u32 to_val = read_dos_reg(reg); >> +     u32 mask = (((1L << (len)) - 1) << (start)); >> + >> +     to_val &= ~mask; >> +     to_val |= (val << start) & mask; >> +     write_dos_reg(reg, to_val); >> +} > > Do not reinvent register writting, use regmap for all that. Ok, I'll use regmap instead of custom register I/O function. > >> + >> +void dos_enable(void) >> +{ >> +     WRITE_VREG_BITS(DOS_GCLK_EN0, 0x3ff, 0, 10); >> + >> +     WRITE_VREG(GCLK_EN, 0x3ff); >> + >> +     CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, (1 << 31)); >> +} >> + >> +void aml_vdec_reset_core(void) >> +{ >> +     unsigned int mask = 0; >> + >> +     mask = (1 << 21); >> + >> +     write_dmc_reg(0x0, (read_dmc_reg(0x0) & ~mask)); >> +     usleep_range(60, 70); >> +     WRITE_VREG(DOS_SW_RESET0, (1 << 3) | (1 << 4) | >> +                (1 << 5) | (1 << 7) | (1 << 8) | (1 << 9)); >> +     WRITE_VREG(DOS_SW_RESET0, 0); >> +     CLEAR_VREG_MASK(VDEC_ASSIST_MMC_CTRL1, 1 << 3); >> +     CLEAR_VREG_MASK(MDEC_PIC_DC_MUX_CTRL, 1 << 31); >> +     WRITE_VREG(MDEC_EXTIF_CFG1, 0); >> + >> +     write_dmc_reg(0x0, (read_dmc_reg(0x0) | mask)); >> +} >> + >> +void aml_start_vdec_hw(void) >> +{ >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> + >> +     WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11)); >> +     WRITE_VREG(DOS_SW_RESET0, 0); >> + >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> + >> +     WRITE_VREG(MPSR, 0x0001); > > This is basilly copuy of downstream code, use proper register writing > functions and stop using downstream macros. Got it. I'll replace all these function with proper functions. > >> +} >> + >> +void aml_stop_vdec_hw(void) >> +{ >> +     ulong timeout = jiffies + HZ / 10; >> + >> +     WRITE_VREG(MPSR, 0); >> +     WRITE_VREG(CPSR, 0); >> + >> +     while (RD_VREG(IMEM_DMA_CTRL) & 0x8000) { >> +             if (time_after(jiffies, timeout)) >> +                     break; >> +     } > > Use read_poll_timeout() or any variant instead of re-inventig polling. Ok, I'll fix this. >> + >> +     timeout = jiffies + HZ / 10; >> +     while (RD_VREG(LMEM_DMA_CTRL) & 0x8000) { >> +             if (time_after(jiffies, timeout)) >> +                     break; >> +     } >> + >> +     timeout = jiffies + HZ / 80; >> +     while (RD_VREG(WRRSP_LMEM) & 0xfff) { >> +             if (time_after(jiffies, timeout)) { >> +                     pr_err("%s, ctrl %x, rsp %x, pc %x status >> %x,%x\n", >> +                            __func__, RD_VREG(LMEM_DMA_CTRL), >> +                            RD_VREG(WRRSP_LMEM), RD_VREG(MPC_E), >> +                            RD_VREG(AV_SCRATCH_J), >> RD_VREG(AV_SCRATCH_9)); >> +                     break; >> +             } >> +     } >> + >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> + >> +     WRITE_VREG(DOS_SW_RESET0, (1 << 12) | (1 << 11)); >> +     WRITE_VREG(DOS_SW_RESET0, 0); >> + >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> +     RD_VREG(DOS_SW_RESET0); >> +} >> + >> +int load_firmware(struct aml_vdec_hw *hw, const char *path) >> +{ >> +     const struct firmware *fw; >> +     struct device *dev = hw->dev; >> +     static u8 *mc_addr; >> +     static dma_addr_t mc_addr_map; >> +     int fw_head_len; >> +     ulong timeout; >> +     int ret; >> + >> +     ret = request_firmware(&fw, path, dev); >> +     if (ret < 0) { >> +             pr_info("request_firmware %s failed ret %d\n", path, ret); >> +             return -EINVAL; >> +     } >> + >> +     if (fw->size > MC_SIZE) { >> +             pr_info("fw %s oversize\n", path); >> +             ret = -EINVAL; >> +             goto release_firmware; >> +     } >> + >> +     fw_head_len = 512; >> +     mc_addr = dma_alloc_coherent(dev, MC_SIZE, &mc_addr_map, >> GFP_KERNEL); >> +     if (!mc_addr) { >> +             pr_info("no mem for fw %s\n", path); >> +             ret = -ENOMEM; >> +             goto release_firmware; >> +     } >> +     memset(mc_addr, 0, MC_SIZE); >> +     memcpy(mc_addr, ((u8 *)fw->data + fw_head_len), >> +            (fw->size - fw_head_len)); >> + >> +     WRITE_VREG(MPSR, 0); >> +     WRITE_VREG(CPSR, 0); >> + >> +     timeout = RD_VREG(MPSR); >> +     timeout = RD_VREG(MPSR); >> +     timeout = jiffies + HZ; >> + >> +     WRITE_VREG(IMEM_DMA_ADR, mc_addr_map); >> +     WRITE_VREG(IMEM_DMA_COUNT, 0x1000); >> +     WRITE_VREG(IMEM_DMA_CTRL, (0x8000 | (7 << 16))); >> + >> +     while (RD_VREG(IMEM_DMA_CTRL) & 0x8000) { >> +             if (time_before(jiffies, timeout)) { >> +                     schedule(); >> +             } else { >> +                     pr_info("vdec load mc error\n"); >> +                     ret = -EBUSY; >> +                     break; >> +             } >> +     } >> + >> +     /* Only h264 needs this step */ >> +     if (hw->hw_ops.load_firmware_ex) { >> +             ret = hw->hw_ops.load_firmware_ex(hw->curr_ctx, >> +                                               mc_addr, >> +                                               (fw->size - >> fw_head_len)); >> +             if (ret < 0) { >> +                     ret = -EINVAL; >> +                     goto free_dma_mem; >> +             } >> +     } >> + >> +free_dma_mem: >> +     dma_free_coherent(dev, MC_SIZE, mc_addr, mc_addr_map); >> +release_firmware: >> +     release_firmware(fw); >> +     return ret; >> +} >> + >> +static int vdec_clock_gate_init(struct aml_vdec_hw *hw) >> +{ >> +     int i; >> + >> +     hw->gates[VDEC].name = "vdec"; >> +     hw->gates[VDEC_MUX].name = "clk_vdec_mux"; >> +     hw->gates[HEVCF_MUX].name = "clk_hevcf_mux"; >> + >> +     for (i = 0; i < DOS_CLK_MAX; i++) { >> +             hw->gates[i].clk = devm_clk_get(hw->dev, >> hw->gates[i].name); >> +             hw->gates[i].ref_count = 0; >> +             mutex_init(&hw->gates[i].mutex); >> +     } >> + >> +     return 0; >> +} >> + >> +static int vdec_gate_clk(struct gate_switch_node *gate_node, bool >> enable) >> +{ >> +     int ret = 0; >> + >> +     mutex_lock(&gate_node->mutex); >> +     if (enable) { >> +             gate_node->ref_count++; >> +             if (gate_node->ref_count == 1) { >> +                     ret = clk_prepare_enable(gate_node->clk); >> +                     pr_debug("the %-15s clock on, ref cnt: %d ret = >> %d\n", >> +                              gate_node->name, gate_node->ref_count, >> ret); >> +             } >> +     } else { >> +             gate_node->ref_count--; >> +             if (!gate_node->ref_count) { >> +                     clk_disable_unprepare(gate_node->clk); >> +                     pr_debug("the %-15s clock off, ref cnt: %d ret >> = %d\n", >> +                              gate_node->name, gate_node->ref_count, >> ret); >> +             } >> +     } >> +     mutex_unlock(&gate_node->mutex); >> + >> +     return 0; >> +} >> + >> +static int vdec_switch_gate(struct aml_vdec_hw *hw, >> +                         const char *name, bool enable) >> +{ >> +     int i; >> + >> +     for (i = 0; i < DOS_CLK_MAX; i++) { >> +             if (!strcmp(name, hw->gates[i].name)) { >> +                     if (hw->gates[i].clk) >> + vdec_gate_clk(&hw->gates[i], enable); >> +                     else >> +                             return -ENODEV; >> +             } >> +     } >> +     return 0; >> +} >> + >> +static int vdec_set_rate(struct aml_vdec_hw *hw, >> +                      const char *name, unsigned long hz) >> +{ >> +     int i; >> + >> +     for (i = 0; i < DOS_CLK_MAX; i++) { >> +             if (!strcmp(name, hw->gates[i].name)) { >> +                     if (hw->gates[i].clk && hw->gates[i].ref_count) { >> +                             clk_set_rate(hw->gates[i].clk, hz); >> +                             pr_debug("after set, vdec mux clock is >> %lu Hz\n", >> + clk_get_rate(hw->gates[i].clk)); >> +                     } else { >> +                             return -ENODEV; >> +                     } >> +             } >> +     } >> +     return 0; >> +} >> + >> +static void pm_vdec_clock_switch(struct aml_vdec_hw *hw, int id, >> bool on) >> +{ >> +     int ret = 0; >> + >> +     if (id == VDEC_1) { >> +             ret = vdec_switch_gate(hw, "clk_vdec_mux", on); >> +             vdec_set_rate(hw, "clk_vdec_mux", 499999992); >> +     } else if (id == VDEC_HEVC) { >> +             /* enable hevc clock */ >> +             ret = vdec_switch_gate(hw, "clk_hevcf_mux", on); >> +             if (ret == -ENODEV) >> +                     ret = vdec_switch_gate(hw, "clk_hevc_mux", on); >> +     } >> + >> +     if (ret < 0) >> +             pr_debug("clk %d, unreachable ret %d\n", id, ret); >> +} >> + >> +static void pm_vdec_power_switch(struct pm_pd_s *pd, int id, bool on) >> +{ >> +     struct device *dev = pd[id].dev; >> +     int ret; >> + >> +     if (!dev) { >> +             pr_debug("no dev %d, maybe always on\n", id); >> +             return; >> +     } >> + >> +     if (on) >> +             ret = pm_runtime_get_sync(dev); >> +     else >> +             ret = pm_runtime_put_sync(dev); >> + >> +     pr_debug("dev: %p link %p the %-15s power %s ret %d\n", >> +              dev, pd[id].link, pd[id].name, on ? "on" : "off", ret); >> +} > > Thoses helpers functions are quite overengineered and only used in 2 > functions, > just call pm_runtime_XXX, clk_XXX functions directly... OK, this can be simplified. I'll get rid of it and use pm_runtime_XXX, clk_XXX functions instead. > >> + >> +static int pm_vdec_power_domain_init(struct aml_vdec_hw *hw) >> +{ >> +     int i, err; >> +     const struct power_manager_s *pm = hw->pm; >> +     struct pm_pd_s *pd = pm->pd_data; >> + >> +     mutex_init(&hw->pm_mutex); >> + >> +     for (i = 0; i < VDEC_MAX; i++) { >> +             pd[i].dev = dev_pm_domain_attach_by_name(hw->dev, >> pd[i].name); >> +             if (IS_ERR_OR_NULL(pd[i].dev)) { >> +                     err = PTR_ERR(pd[i].dev); >> +                     pr_debug("Get %s failed, pm-domain: %d\n", >> +                              pd[i].name, err); >> +                     continue; >> +             } >> + >> +             pd[i].link = device_link_add(hw->dev, pd[i].dev, >> +                                          DL_FLAG_PM_RUNTIME | >> +                                          DL_FLAG_STATELESS); >> +             if (IS_ERR_OR_NULL(pd[i].link)) { >> +                     pr_err("Adding %s device link failed!\n", >> pd[i].name); >> +                     return -ENODEV; >> +             } >> + >> +             pr_debug("power domain: name: %s, dev: %p, link: %p\n", >> +                      pd[i].name, pd[i].dev, pd[i].link); >> +     } >> + >> +     return 0; >> +} >> + >> +static void pm_vdec_power_domain_release(struct aml_vdec_hw *hw) >> +{ >> +     int i; >> +     const struct power_manager_s *pm = hw->pm; >> +     struct pm_pd_s *pd = pm->pd_data; >> + >> +     for (i = 0; i < VDEC_MAX; i++) { >> +             if (!IS_ERR_OR_NULL(pd[i].link)) >> +                     device_link_del(pd[i].link); >> + >> +             if (!IS_ERR_OR_NULL(pd[i].dev)) >> +                     dev_pm_domain_detach(pd[i].dev, true); >> +     } >> +} >> + >> +static void dos_local_config(bool is_on, int id) >> +{ >> +     if (is_on) { >> +             usleep_range(20, 100); >> + >> +             switch (id) { >> +             case VDEC_1: >> +                     WRITE_VREG(DOS_MEM_PD_VDEC, 0); >> +                     WRITE_VREG(DOS_SW_RESET0, 0xfffffffc); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_SW_RESET0, 0); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_MEM_PD_VDEC, 0); >> +                     break; >> +             case VDEC_HEVC: >> +                     WRITE_VREG(DOS_MEM_PD_HEVC, 0); >> +                     WRITE_VREG(DOS_SW_RESET3, 0xffffffff); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_SW_RESET3, 0); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_MEM_PD_HEVC, 0); >> +                     break; >> +             default: >> +                     pr_debug("%s on, not found id %d\n", __func__, >> id); >> +                     break; >> +             } >> +     } else { >> +             switch (id) { >> +             case VDEC_1: >> +                     WRITE_VREG(DOS_SW_RESET0, 0xfffffffc); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_SW_RESET0, 0); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_MEM_PD_VDEC, 0xffffffffUL); >> +                     break; >> +             case VDEC_HEVC: >> +                     WRITE_VREG(DOS_SW_RESET3, 0xffffffff); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_SW_RESET3, 0); >> +                     usleep_range(20, 100); >> +                     WRITE_VREG(DOS_MEM_PD_HEVC, 0xffffffffUL); >> +                     break; >> +             default: >> +                     pr_debug("%s off, not found id %d\n", __func__, >> id); >> +                     break; >> +             } >> +     } >> + >> +     pr_debug("%s end, id %d, is_on %d\n", __func__, id, is_on); >> +} >> + >> +static void pm_vdec_power_domain_power_on(struct aml_vdec_hw *hw, >> int id) >> +{ >> +     const struct power_manager_s *pm = hw->pm; >> + >> +     pm_vdec_clock_switch(hw, id, true); >> +     pm_vdec_power_switch(pm->pd_data, id, true); >> + >> +     dos_local_config(1, id); >> +} >> + >> +static void pm_vdec_power_domain_power_off(struct aml_vdec_hw *hw, >> int id) >> +{ >> +     const struct power_manager_s *pm = hw->pm; >> + >> +     dos_local_config(0, id); >> + >> +     pm_vdec_clock_switch(hw, id, false); >> +     pm_vdec_power_switch(pm->pd_data, id, false); >> +} >> + >> +static bool pm_vdec_power_domain_power_state(struct aml_vdec_hw *hw, >> int id) >> +{ >> +     if (hw->pm->pd_data[id].dev) >> +             return pm_runtime_active(hw->pm->pd_data[id].dev); >> +     else >> +             return false; >> +} >> + >> +static void vdec_poweron(struct aml_vdec_hw *hw, enum vdec_type_e core) >> +{ >> +     if (core >= VDEC_MAX) >> +             return; >> + >> +     mutex_lock(&hw->pm_mutex); >> +     if (!hw->pm->pd_data[core].dev) >> +             goto out; >> + >> +     hw->pm->pd_data[core].ref_count++; >> +     if (hw->pm->pd_data[core].ref_count > 1) >> +             goto out; >> + >> +     if (hw->pm->power_state(hw, core)) >> +             goto out; >> + >> +     hw->pm->power_on(hw, core); >> + >> +out: >> +     mutex_unlock(&hw->pm_mutex); >> +} >> + >> +static void vdec_poweroff(struct aml_vdec_hw *hw, enum vdec_type_e >> core) >> +{ >> +     if (core >= VDEC_MAX) >> +             return; >> + >> +     mutex_lock(&hw->pm_mutex); >> +     if (hw->pm->pd_data[core].ref_count == 0) >> +             goto out; >> + >> +     hw->pm->pd_data[core].ref_count--; >> +     if (hw->pm->pd_data[core].ref_count > 0) >> +             goto out; >> + >> +     hw->pm->power_off(hw, core); >> + >> +out: >> +     mutex_unlock(&hw->pm_mutex); >> +} >> + >> +int vdec_enable(struct aml_vdec_hw *hw) >> +{ >> +     vdec_switch_gate(hw, "vdec", 1); >> +     vdec_poweron(hw, VDEC_1); >> + >> +     return 0; >> +} >> + >> +int vdec_disable(struct aml_vdec_hw *hw) >> +{ >> +     vdec_poweroff(hw, VDEC_1); >> +     vdec_switch_gate(hw, "vdec", 0); >> + >> +     return 0; >> +} >> + >> +static const struct power_manager_s pm[] = { >> +     [AML_PM_PD] = { >> +             .pd_data    = vdec_domain_data, >> +             .init        = pm_vdec_power_domain_init, >> +             .release    = pm_vdec_power_domain_release, >> +             .power_on    = pm_vdec_power_domain_power_on, >> +             .power_off    = pm_vdec_power_domain_power_off, >> +             .power_state = pm_vdec_power_domain_power_state, >> +     }, >> +}; >> + >> +static irqreturn_t vdec_irq_handler(int irq, void *priv) >> +{ >> +     struct aml_vdec_dev *dev = (struct aml_vdec_dev *)priv; >> +     struct aml_vdec_hw *hw = dev->dec_hw; >> +     irqreturn_t ret; >> + >> +     if (hw->hw_ops.irq_handler) >> +             ret = hw->hw_ops.irq_handler(irq, priv); >> + >> +     return ret; >> +} >> + >> +static irqreturn_t vdec_threaded_isr_handler(int irq, void *priv) >> +{ >> +     struct aml_vdec_dev *dev = (struct aml_vdec_dev *)priv; >> +     struct aml_vdec_hw *hw = dev->dec_hw; >> +     irqreturn_t ret = IRQ_HANDLED; >> + >> +     if (hw->hw_ops.irq_threaded_func) >> +             ret = hw->hw_ops.irq_threaded_func(irq, priv); >> + >> +     return ret; >> +} >> + >> +struct aml_vdec_hw *vdec_get_hw(void *priv) >> +{ >> +     struct aml_vdec_dev *dev = (struct aml_vdec_dev *)priv; >> + >> +     return dev->dec_hw; >> +} >> + >> +int dev_request_hw_resources(void *priv) >> +{ >> +     struct aml_vdec_dev *dev = (struct aml_vdec_dev *)priv; >> +     struct aml_vdec_hw *hw; >> +     struct platform_device *pdev; >> +     struct resource res; >> +     u32 res_size; >> +     int i; >> +     int ret = -1; >> + >> +     if (!dev || !dev->dec_hw) { >> +             pr_err("%s param invalid\n", __func__); >> +             return -1; >> +     } >> +     pdev = dev->plat_dev; >> +     hw = dev->dec_hw; >> +     hw->dev = &pdev->dev; >> + >> +     hw->dec_irq = platform_get_irq(pdev, VDEC_IRQ_1); >> +     if (hw->dec_irq < 0) { >> +             dev_err(&pdev->dev, "get irq failed\n"); >> +             return hw->dec_irq; >> +     } >> +     ret = devm_request_threaded_irq(&pdev->dev, hw->dec_irq, >> vdec_irq_handler, >> +                                     vdec_threaded_isr_handler, >> IRQF_ONESHOT, >> +                                     "vdec-1", dev); >> +     if (ret) { >> +             dev_err(&pdev->dev, "failed to install irq %d (%d)", >> +                     hw->dec_irq, ret); >> +             return -1; >> +     } >> + >> +     for (i = 0; i < MAX_REG_BUS; i++) { >> +             if (of_address_to_resource(pdev->dev.of_node, i, &res)) { >> +                     pr_err("of_address_to_resource %d failed\n", i); >> +                     return -EINVAL; >> +             } >> + >> +             res_size = resource_size(&res); >> +             hw->regs[i] = ioremap(res.start, res_size); >> +             reg_base[i] = hw->regs[i]; >> + >> +             pr_debug("%s, res start %llx, end %llx, iomap: %p\n", >> +                      __func__, (unsigned long long)res.start, >> +                      (unsigned long long)res.end, reg_base[i]); >> +     } >> + >> +     hw->pm = &pm[dev->pvdec_data->power_type]; >> +     if (hw->pm->init) { >> +             ret = hw->pm->init(hw); >> +             if (ret < 0) { >> +                     pr_err("power mgr init failed!\n"); >> +                     return ret; >> +             } >> +     } >> +     vdec_clock_gate_init(hw); >> + >> +     aml_vdec_canvas_register(hw); >> + >> +     pr_debug("##Amlogic hw resource init OK##\n"); >> + >> +     return 0; >> +} >> + >> +void dev_destroy_hw_resources(void *priv) >> +{ >> +     struct aml_vdec_dev *dev = (struct aml_vdec_dev *)priv; >> +     struct aml_vdec_hw *hw; >> + >> +     if (!dev || !dev->dec_hw) { >> +             pr_err("%s param invalid\n", __func__); >> +             return; >> +     } >> +     hw = dev->dec_hw; >> + >> +     if (hw->pm->release) >> +             hw->pm->release(hw); >> + >> +     kfree(hw); >> +     dev->dec_hw = NULL; >> +     pr_debug("##Amlogic hw resource release OK##\n"); >> +} >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec_hw.h >> b/drivers/media/platform/amlogic/vdec/aml_vdec_hw.h >> new file mode 100644 >> index 000000000000..ad1e613a2cf8 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_hw.h >> @@ -0,0 +1,182 @@ >> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#ifndef _AML_VDEC_HW_H_ >> +#define _AML_VDEC_HW_H_ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include "reg_defines.h" >> + >> +#define VDEC_FIFO_ALIGN     8 >> +#define VLD_PADDING_SIZE    1024 >> + >> +#define RD_VREG(addr) read_dos_reg(addr) >> +#define WRITE_VREG(addr, val) write_dos_reg(addr, val) >> +#define WRITE_VREG_BITS(r, val, start, len) dos_reg_write_bits(r, >> val, start, len) >> +#define CLEAR_VREG_MASK(r, mask) dos_reg_clear_mask(r, mask) >> +#define SET_VREG_MASK(r, mask) dos_reg_set_mask(r, mask) > > > Please drop this macros and use the functions directly. Got it, I'll drop them. >> + >> +/** >> + * struct aml_vdec_hw_ops - codec mode specific operations for hw >> + * @load_firmware_ex: Load firmware for current dec specific. >> + * @irq_handler: mandatory call when the ISR triggers >> + * @irq_threaded_func: mandatory call for the threaded ISR >> + * @canvas_alloc: Alloc canvas for curr frame >> + * @canvas_free: Release canvas. >> + * @config_canvas: Config for curr frame, such as w/h, Y/UV start >> addr etc. >> + */ >> +struct aml_vdec_hw_ops { >> +     int (*load_firmware_ex)(void *priv, const u8 *data, u32 len); >> +     irqreturn_t (*irq_handler)(int irq, void *priv); >> +     irqreturn_t (*irq_threaded_func)(int irq, void *priv); >> +     int (*canvas_alloc)(u8 *canvas_index); >> +     void (*canvas_free)(u8 canvas_index); >> +     void (*config_canvas)(u8 canvas_index, >> +                           ulong addr, u32 width, u32 height, >> +                           u32 wrap, u32 blkmode, u32 endian); >> +}; >> + >> +/** >> + * enum vdec_type_e - Type of decoder hardware. >> + */ >> +enum vdec_type_e { >> +     VDEC_1 = 0, >> +     VDEC_HEVC, >> +     VDEC_MAX, >> +}; >> + >> +/** >> + * enum vdec_irq_num - Definition of the irq. >> + */ >> +enum vdec_irq_num { >> +     VDEC_IRQ_0 = 0, >> +     VDEC_IRQ_1, >> +     VDEC_IRQ_2, >> +     VDEC_IRQ_MAX, >> +}; >> + >> +/** >> + * enum vdec_type_e - Type of decoder clock. >> + */ >> +enum clk_type_e { >> +     VDEC = 0, >> +     VDEC_MUX, >> +     HEVCF_MUX, >> +     DOS_CLK_MAX, >> +}; >> + >> +/** >> + * enum aml_power_type_e - Type of decoder power. >> + */ >> +enum aml_power_type_e { >> +     AML_PM_PD = 0, >> +}; >> + >> +/** >> + * enum mm_bus_e - Type of decoder hardware bus. >> + */ >> +enum mm_bus_e { >> +     DOS_BUS = 0, >> +     DMC_BUS, >> +     MAX_REG_BUS >> +}; >> + >> +/** >> + * struct gate_switch_node - clock node definition >> + * @clk: Pointer to clk instance. >> + * @name: Clock name used. >> + * @mutex: Mutex lock for multi decoder instance. >> + * @ref_count: Curr clk instance ref count. >> + */ >> +struct gate_switch_node { >> +     struct clk *clk; >> +     const char *name; >> +     struct mutex mutex; >> +     int ref_count; >> +}; >> + >> +/** >> + * struct pm_pd_s - power domain definition >> + * @name: Power domain name. >> + * @dev: Pointer to device structure. >> + * @mutex: Pointer to device_link structure. >> + * @ref_count: Curr power domain instance ref count. >> + */ >> +struct pm_pd_s { >> +     u8 *name; >> +     struct device *dev; >> +     struct device_link *link; >> +     int ref_count; >> +}; >> + >> +/** >> + * struct aml_vdec_hw - decoder hardware resources definition >> + * @pdev: Pointer to struct platform_device. >> + * @dev: Pointer to struct device. >> + * @regs: Reg base for dos/dmc hardware. >> + * @pm_mutex: Mutex for pm->pd_data. >> + * @pm: Pointer to struct power_manager_s. >> + * @hw_ops: Hardware resource operation functions. See struct >> aml_vdec_hw_ops. >> + * @gates: Clk instance used by curr decoder context. >> + * @dec_irq: Irq registered. >> + * @curr_ctx: Pointer to curr decoder context. >> + */ >> +struct aml_vdec_hw { >> +     struct platform_device *pdev; >> +     struct device *dev; >> +     void __iomem *regs[MAX_REG_BUS]; >> +     struct mutex pm_mutex; >> +     const struct power_manager_s *pm; >> +     struct aml_vdec_hw_ops hw_ops; >> +     struct gate_switch_node gates[DOS_CLK_MAX]; >> +     int dec_irq; >> +     void *curr_ctx; >> +}; >> + >> +/** >> + * struct power_manager_s - Power manager & opertion function >> + * @pd_data: Pointer to struct pm_pd_s >> + * @init: Power manager init. >> + * @release: Power manager release. >> + * @power_on: Power on for decoder hw. >> + * @power_off: Power off for decoder hw. >> + * @power_state: Query the power state. >> + */ >> +struct power_manager_s { >> +     struct pm_pd_s *pd_data; >> +     int (*init)(struct aml_vdec_hw *hw); >> +     void (*release)(struct aml_vdec_hw *hw); >> +     void (*power_on)(struct aml_vdec_hw *hw, int id); >> +     void (*power_off)(struct aml_vdec_hw *hw, int id); >> +     bool (*power_state)(struct aml_vdec_hw *hw, int id); >> +}; >> + >> +int dev_request_hw_resources(void *priv); >> +void dev_destroy_hw_resources(void *priv); >> +struct aml_vdec_hw *vdec_get_hw(void *priv); >> +u32 read_dos_reg(u32 reg_addr); >> +void write_dos_reg(u32 addr, int val); >> +void dos_reg_write_bits(u32 reg, u32 val, int start, int len); >> +void dos_reg_clear_mask(u32 addr, u32 mask); >> +void dos_reg_set_mask(u32 addr, u32 mask); >> +u32 read_dmc_reg(u32 addr); >> +void write_dmc_reg(u32 addr, int val); >> +int vdec_enable(struct aml_vdec_hw *hw); >> +int vdec_disable(struct aml_vdec_hw *hw); >> +void dos_enable(void); >> +void aml_start_vdec_hw(void); >> +void aml_stop_vdec_hw(void); >> +int load_firmware(struct aml_vdec_hw *hw, const char *path); >> +void aml_vdec_reset_core(void); >> + >> +#endif >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec_platform.c >> b/drivers/media/platform/amlogic/vdec/aml_vdec_platform.c >> new file mode 100644 >> index 000000000000..f1f8ba1f4ff6 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_platform.c >> @@ -0,0 +1,37 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#include "aml_vdec_platform.h" >> +#include "aml_vdec_drv.h" >> +#include "aml_vdec_hw.h" >> +#include "h264.h" >> + >> +#define VIDEO_DEC_H264  "s4_h264_multi.bin" >> + >> +const struct aml_codec_ops aml_S4_dec_ops[] = { >> +     [CODEC_TYPE_H264] = { >> +             .init = aml_h264_init, >> +             .exit = aml_h264_exit, >> +             .run = aml_h264_dec_run, >> +     }, >> +}; >> + >> +static const struct aml_video_dec_fmt aml_S4_dec_fmts = { >> +     .max_height = AML_VDEC_1080P_MAX_H, >> +     .max_width = AML_VDEC_1080P_MAX_W, >> +     .align = 32, >> +     .is_10_bit_support = 0, >> +}; >> + >> +const struct aml_dev_platform_data aml_vdec_s4_pdata = { >> +     .dec_fmt = &aml_S4_dec_fmts, >> +     .codec_ops = aml_S4_dec_ops, >> +     .power_type = AML_PM_PD, >> +     .req_hw_resource = dev_request_hw_resources, >> +     .destroy_hw_resource = dev_destroy_hw_resources, >> +     .fw_path = { >> +             VIDEO_DEC_H264, >> +     }, >> +}; >> diff --git a/drivers/media/platform/amlogic/vdec/aml_vdec_platform.h >> b/drivers/media/platform/amlogic/vdec/aml_vdec_platform.h >> new file mode 100644 >> index 000000000000..ff0933f6f074 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/aml_vdec_platform.h >> @@ -0,0 +1,62 @@ >> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#ifndef AML_VDEC_PLATFORM_H_ >> +#define AML_VDEC_PLATFORM_H_ >> + >> +#include >> + >> +#define MAX_DEC_FORMAT 3 >> + >> +/** >> + * struct aml_codec_ops - codec mode specific operations >> + * @init: Used for decoder initialization. >> + * @exit: If needed, can be used to undo the .init phase. >> + * @run: Start a single decoding job. Called from atomic context. >> + * Caller should ensure that a pair of buffers is ready and the >> + * hardware is powered on and clk is enabled. Returns zero if OK, >> + * a negative value in error cases. >> + */ >> +struct aml_codec_ops { >> +     int (*init)(void *priv); >> +     void (*exit)(void *priv); >> +     int (*run)(void *priv); >> +}; >> + >> +/** >> + * struct aml_video_dec_fmt - codec format required by platform >> + * @max_height: Max decode frame height of current platform. >> + * @max_width: Max decode frame width of current platform. >> + * @align: Align requirement of the current platform. >> + * @is_10_bit_support: Whether the platform supports 10 bit. >> + */ >> +struct aml_video_dec_fmt { >> +     u32 max_height; >> +     u32 max_width; >> +     int align; >> +     int is_10_bit_support; >> +}; >> + >> +/** >> + * struct aml_dev_platform_data - compatible data for each chip. >> + * @dec_fmt: Support dec format. >> + * @codec_ops: Codec operation function. >> + * @req_hw_resource: Operation function to request the hardware >> resource. >> + * @destroy_hw_resource: Operation function to release the hardware >> resource. >> + * @power_type: Type of power that the current chip need. See >> aml_power_type_e. >> + * @fw_path: Path of the firmware.bin. >> + */ >> +struct aml_dev_platform_data { >> +     const struct aml_video_dec_fmt *dec_fmt; >> +     const struct aml_codec_ops *codec_ops; >> +     int (*req_hw_resource)(void *priv); >> +     void (*destroy_hw_resource)(void *priv); >> +     int power_type; >> +     const char *fw_path[MAX_DEC_FORMAT]; >> +}; >> + >> +extern const struct aml_dev_platform_data aml_vdec_s4_pdata; >> + >> +#endif >> diff --git a/drivers/media/platform/amlogic/vdec/h264.c >> b/drivers/media/platform/amlogic/vdec/h264.c >> new file mode 100644 >> index 000000000000..ebfd10885eaa >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/h264.c >> @@ -0,0 +1,1790 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#include >> +#include >> +#include "aml_vdec.h" >> +#include "aml_vdec_hw.h" >> +#include "h264.h" >> + >> +#define INVALID_POC 0xffffffff >> + >> +#define H264_SLICE_HEADER_DONE               0x1 >> +#define H264_SLICE_DATA_DONE         0x2 >> + >> +#define DECODER_TIMEOUT_MS                   500 >> + >> +#define COL_BUFFER_MARGIN                    2 >> + >> +struct vdec_h264_stateless_ctrl_ref { >> +     const struct v4l2_ctrl_h264_decode_params *decode; >> +     const struct v4l2_ctrl_h264_scaling_matrix *scaling; >> +     const struct v4l2_ctrl_h264_sps *sps; >> +     const struct v4l2_ctrl_h264_pps *pps; >> +}; >> + >> +enum SliceType { >> +     P_SLICE = 0, >> +     B_SLICE = 1, >> +     I_SLICE = 2, >> +     SP_SLICE = 3, >> +     SI_SLICE = 4, >> +     MAX_SLICE_TYPES = 5 >> +}; >> + >> +/* Used by firmware */ >> +union param { >> +     struct { >> +             unsigned short data[RPM_END - RPM_BEGIN]; >> +     } l; >> +     struct { >> +             unsigned short dump[DPB_OFFSET]; >> +             unsigned short dpb_base[FRAME_IN_DPB << 3]; >> + >> +             unsigned short dpb_max_buffer_frame; >> +             unsigned short actual_dpb_size; >> + >> +             unsigned short colocated_buf_status; >> + >> +             unsigned short num_forward_short_term_reference_pic; >> +             unsigned short num_short_term_reference_pic; >> +             unsigned short num_reference_pic; >> + >> +             unsigned short current_dpb_index; >> +             unsigned short current_decoded_frame_num; >> +             unsigned short current_reference_frame_num; >> + >> +             unsigned short l0_size; >> +             unsigned short l1_size; >> +             /** >> +              * [6:5] : nal_ref_idc >> +              * [4:0] : nal_unit_type >> +              */ >> +             unsigned short NAL_info_mmco; >> +             /** >> +              * [1:0] : 00 - top field, 01 - bottom field, >> +              *         10 - frame, 11 - mbaff frame >> +              */ >> +             unsigned short picture_structure_mmco; >> +             unsigned short frame_num; >> +             unsigned short pic_order_cnt_lsb; >> + >> +             unsigned short num_ref_idx_l0_active_minus1; >> +             unsigned short num_ref_idx_l1_active_minus1; >> + >> +             unsigned short PrevPicOrderCntLsb; >> +             unsigned short PreviousFrameNum; >> + >> +             /* 32 bits variables */ >> +             unsigned short delta_pic_order_cnt_bottom[2]; >> +             unsigned short delta_pic_order_cnt_0[2]; >> +             unsigned short delta_pic_order_cnt_1[2]; >> + >> +             unsigned short PrevPicOrderCntMsb[2]; >> +             unsigned short PrevFrameNumOffset[2]; >> + >> +             unsigned short frame_pic_order_cnt[2]; >> +             unsigned short top_field_pic_order_cnt[2]; >> +             unsigned short bottom_field_pic_order_cnt[2]; >> + >> +             unsigned short colocated_mv_addr_start[2]; >> +             unsigned short colocated_mv_addr_end[2]; >> +             unsigned short colocated_mv_wr_addr[2]; >> +     } dpb; >> +     struct { >> +             unsigned short dump[MMCO_OFFSET]; >> + >> +             /* array base address for offset_for_ref_frame */ >> +             unsigned short offset_for_ref_frame_base[128]; >> + >> +             /** >> +              * 0 - Index in DPB >> +              * 1 - Picture Flag >> +              *  [2] : 0 - short term reference, >> +              *                      1 - long term reference >> +              *  [1] : bottom field >> +              *  [0] : top field >> +              * 2 - Picture Number (short term or long term) low 16 >> bits >> +              * 3 - Picture Number (short term or long term) high 16 >> bits >> +              */ >> +             unsigned short reference_base[128]; >> + >> +             /* command and parameter, until command is 3 */ >> +             unsigned short l0_reorder_cmd[REORDER_CMD_MAX]; >> +             unsigned short l1_reorder_cmd[REORDER_CMD_MAX]; >> + >> +             /* command and parameter, until command is 0 */ >> +             unsigned short mmco_cmd[44]; >> + >> +             unsigned short l0_base[40]; >> +             unsigned short l1_base[40]; >> +     } mmco; >> +     struct { >> +             /* from ucode lmem, do not change this struct */ >> +     } p; >> +}; >> + >> +struct h264_decode_buf_spec { >> +     struct v4l2_h264_dpb_entry *dpb; >> +     u32 canvas_pos; >> +     u32 dpb_index; >> +     u32 poc; >> +     int col_buf_index; >> +     u8 y_canvas_index; >> +     u8 u_canvas_index; >> +     u8 v_canvas_index; >> +     u8 used; >> +     u8 long_term_flag; >> +     dma_addr_t y_dma_addr; >> +     dma_addr_t c_dma_addr; >> +}; >> + >> +#define REORDERING_COMMAND_MAX_SIZE  33 >> +struct slice { >> +     int frame_num; >> +     /*modification */ >> +     int slice_type; >> +     int num_ref_idx_l0; >> +     int num_ref_idx_l1; >> +     int ref_pic_list_reordering_flag[2]; >> +     int modification_of_pic_nums_idc[2][REORDERING_COMMAND_MAX_SIZE]; >> +     int abs_diff_pic_num_minus1[2][REORDERING_COMMAND_MAX_SIZE]; >> +     int long_term_pic_idx[2][REORDERING_COMMAND_MAX_SIZE]; >> +     unsigned char dec_ref_pic_marking_buffer_valid; >> +}; >> + >> +struct aml_h264_ctx { >> +     struct aml_vdec_ctx *v4l2_ctx; >> +     u8 init_flag; >> +     u8 new_pic_flag; >> +     u8 mc_cpu_loaded; >> +     u8 param_set; >> +     u8 colocated_buf_num; >> +     u8 reg_iqidct_control_init_flag; >> +     u32 reg_iqidct_control; >> +     u32 reg_vcop_ctrl_reg; >> +     u32 reg_rv_ai_mb_count; >> +     u32 vld_dec_control; >> +     u32 save_avscratch_f; >> +     u32 seq_info; >> +     u32 decode_pic_count; >> +     union param dpb_param; >> +     u32 dec_status; >> +     struct slice mslice; >> +     struct h264_decode_buf_spec curr_spec; >> +     struct h264_decode_buf_spec ref_list0[V4L2_H264_NUM_DPB_ENTRIES >> + 1]; >> +     struct h264_decode_buf_spec ref_list1[V4L2_H264_NUM_DPB_ENTRIES >> + 1]; >> +     struct h264_decode_buf_spec >> ref_list0_unreordered[V4L2_H264_NUM_DPB_ENTRIES + 1]; >> +     struct h264_decode_buf_spec >> ref_list1_unreordered[V4L2_H264_NUM_DPB_ENTRIES + 1]; >> +     u8 list_size[2]; >> +     dma_addr_t lmem_phy_addr; >> +     void *lmem_addr; >> +     dma_addr_t mc_cpu_paddr; >> +     void *mc_cpu_vaddr; >> +     dma_addr_t cma_alloc_addr; >> +     void *cma_alloc_vaddr; >> +     dma_addr_t collated_cma_addr; >> +     dma_addr_t collated_cma_addr_end; >> +     void *collated_cma_vaddr; >> +     dma_addr_t workspace_offset; >> +     void *workspace_vaddr; >> +     u32 col_buf_alloc_size; >> +     u32 one_col_buf_size; >> +     u32 colocated_buf_map; >> +     int colocated_buf_poc[32]; >> + >> +     u32 frame_width; >> +     u32 frame_height; >> +     u32 mb_width; >> +     u32 mb_height; >> +     u32 mb_total; >> +     u32 max_num_ref_frames; >> + >> +     struct vdec_h264_stateless_ctrl_ref ctrl_ref; >> +}; >> + >> +static inline int get_flag(u32 flag, u32 mask) >> +{ >> +     return (flag & mask) ? 1 : 0; >> +} >> + >> +static inline void write_lmem(unsigned short *base, u32 offset, u32 >> value) >> +{ >> +     base[offset] = value; >> +} >> + >> +static inline uint32_t spec2canvas(struct h264_decode_buf_spec >> *buf_spec) >> +{ >> +     return (buf_spec->v_canvas_index << 16) | >> +             (buf_spec->u_canvas_index << 8) | >> +             (buf_spec->y_canvas_index << 0); >> +} >> + >> +static struct h264_decode_buf_spec *find_spec_by_dpb_index(struct >> aml_h264_ctx *h264_ctx, int index) >> +{ >> +     int i; >> + >> +     for (i = 0; i < h264_ctx->list_size[0]; i++) { >> +             if (index == h264_ctx->ref_list0[i].dpb_index) >> +                     return &h264_ctx->ref_list0[i]; >> +     } >> + >> +     for (i = 0; i < h264_ctx->list_size[1]; i++) { >> +             if (index == h264_ctx->ref_list1[i].dpb_index) >> +                     return &h264_ctx->ref_list1[i]; >> +     } >> +     return NULL; >> +} >> + >> +static int h264_prepare_input(struct aml_vdec_ctx *ctx) >> +{ >> +     struct vb2_v4l2_buffer *src; >> +     struct vb2_buffer *vb; >> +     dma_addr_t src_dma; >> +     u32 payload_size; >> +     int dummy; >> + >> +     src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); >> +     if (!src) { >> +             pr_info("no input buffer available!\n"); >> +             return -1; >> +     } >> +     vb = &src->vb2_buf; >> +     payload_size = vb2_get_plane_payload(vb, 0); >> +     src_dma = vb2_dma_contig_plane_dma_addr(vb, 0); >> + >> +     WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0); >> +     /* reset VLD fifo for all vdec */ >> +     WRITE_VREG(DOS_SW_RESET0, (1 << 5) | (1 << 4) | (1 << 3)); >> +     WRITE_VREG(DOS_SW_RESET0, 0); >> +     WRITE_VREG(POWER_CTL_VLD, 1 << 4); >> + >> +     WRITE_VREG(VLD_MEM_VIFIFO_START_PTR, src_dma); >> +     WRITE_VREG(VLD_MEM_VIFIFO_END_PTR, (src_dma + payload_size)); >> +     WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR, >> +                round_down(src_dma, VDEC_FIFO_ALIGN)); >> + >> +     WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1); >> +     WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0); >> +     WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2); >> + >> +     WRITE_VREG(VLD_MEM_VIFIFO_RP, >> +                round_down(src_dma, VDEC_FIFO_ALIGN)); >> +     dummy = payload_size + VLD_PADDING_SIZE; >> +     WRITE_VREG(VLD_MEM_VIFIFO_WP, >> +                round_down((src_dma + dummy), VDEC_FIFO_ALIGN)); >> + >> +     WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 3); >> +     WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, 2); >> + >> +     WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, >> +                (0x11 << 16) | (1 << 10) | (7 << 3)); >> + >> +     WRITE_VREG(AV_SCRATCH_1, 0x0); >> +     WRITE_VREG(H264_DECODE_INFO, (1 << 13)); >> +     WRITE_VREG(H264_DECODE_SIZE, payload_size); >> +     WRITE_VREG(VIFF_BIT_CNT, payload_size * 8); >> + >> +     return 0; >> +} >> + >> +static void config_sps_params(struct aml_h264_ctx *h264_ctx, >> +                           unsigned short *sps_base, >> +                           const struct v4l2_ctrl_h264_sps *sps) >> +{ >> +     u32 cfg_tmp = 0; >> +     u32 frame_size; >> +     u32 offset = 0; >> +     unsigned short data_tmp[0x100]; >> +     int i, ii; >> + >> +     memset(sps_base, 0, 0x100); >> + >> +     h264_ctx->frame_width = (sps->pic_width_in_mbs_minus1 + 1) << 4; >> +     h264_ctx->frame_height = (sps->pic_height_in_map_units_minus1 + >> 1) << 4; >> + >> +     data_tmp[offset] = PARAM_BASE_VAL; >> +     offset += 2; >> + >> +     data_tmp[offset++] = GET_SPS_PROFILE_IDC(sps->profile_idc); >> + >> +     data_tmp[offset++] = >> GET_SPS_SEQ_PARAM_SET_ID(sps->seq_parameter_set_id) | >> +         GET_SPS_LEVEL_IDC(sps->level_idc); >> + >> +     if (sps->profile_idc >= 100) { >> +             data_tmp[offset++] = >> GET_SPS_CHROMA_FORMAT_IDC(sps->chroma_format_idc); >> + >> +             data_tmp[offset++] = ((sps->chroma_format_idc ^ 1) << 1); >> +     } >> + >> +     data_tmp[offset++] = >> GET_SPS_LOG2_MAX_FRAME_NUM(sps->log2_max_frame_num_minus4); >> +     data_tmp[offset++] = >> GET_SPS_PIC_ORDER_TYPE(sps->pic_order_cnt_type); >> + >> +     if (sps->pic_order_cnt_type == 0) { >> +             data_tmp[offset++] = >> + GET_SPS_PIC_ORDER_CNT_LSB(sps->log2_max_pic_order_cnt_lsb_minus4); >> +     } else if (sps->pic_order_cnt_type == 1) { >> +             data_tmp[offset++] = >> +                     get_flag(sps->flags, >> + V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); >> +             data_tmp[offset++] = >> + GET_SPS_OFFSET_FOR_NONREF_PIC_LOW(sps->offset_for_non_ref_pic); >> +             data_tmp[offset++] = >> + GET_SPS_OFFSET_FOR_NONREF_PIC_HIGH(sps->offset_for_non_ref_pic); >> +             data_tmp[offset++] = >> + >> GET_SPS_OFFSET_FOR_TOP_BOT_FIELD_LOW(sps->offset_for_top_to_bottom_field); >> +             data_tmp[offset++] = >> + >> GET_SPS_OFFSET_FOR_TOP_BOT_FIELD_HIGH(sps->offset_for_top_to_bottom_field); >> +             data_tmp[offset++] = >> sps->num_ref_frames_in_pic_order_cnt_cycle; >> +     } >> + >> +     data_tmp[offset++] = >> GET_SPS_NUM_REF_FRAMES(sps->max_num_ref_frames) | >> +         GET_SPS_GAPS_ALLOWED_FLAG(get_flag(sps->flags, >> + V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED)); >> + >> +     data_tmp[offset++] = >> GET_SPS_PIC_WIDTH_IN_MBS(sps->pic_width_in_mbs_minus1); >> + >> +     data_tmp[offset++] = >> GET_SPS_PIC_HEIGHT_IN_MBS(sps->pic_height_in_map_units_minus1); >> +     data_tmp[offset++] = >> +             GET_SPS_DIRECT_8X8_FLAGS >> +                             (get_flag(sps->flags, >> + V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)) | >> +             GET_SPS_MB_ADAPTIVE_FRAME_FIELD_FLAGS >> +                             (get_flag(sps->flags, >> + V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) | >> +             GET_SPS_FRAME_MBS_ONLY_FLAGS >> +                             (get_flag(sps->flags, >> + V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)); >> + >> +     for (i = 0; i < 0x100; i += 4) { >> +             for (ii = 0; ii < 4; ii++) >> +                     sps_base[i + 3 - ii] = data_tmp[i + ii]; >> +     } >> + >> +     frame_size = (sps->pic_width_in_mbs_minus1 + 1) * >> (sps->pic_height_in_map_units_minus1 + 1); >> +     cfg_tmp = (get_flag(sps->flags, >> V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) << 31) | >> +                             (sps->max_num_ref_frames << 24) | >> (frame_size << 8) | >> +                             (sps->pic_width_in_mbs_minus1 + 1); >> +     WRITE_VREG(AV_SCRATCH_1, cfg_tmp); >> +     h264_ctx->seq_info = cfg_tmp; >> + >> +     cfg_tmp = 0; >> +     cfg_tmp = (get_flag(sps->flags, >> V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) << 15) | >> +                             (sps->chroma_format_idc); >> +     WRITE_VREG(AV_SCRATCH_2, cfg_tmp); >> + >> +     cfg_tmp = 0; >> +     cfg_tmp = (sps->max_num_ref_frames << 8) | (sps->level_idc); >> +     WRITE_VREG(AV_SCRATCH_B, cfg_tmp); >> + >> +     cfg_tmp = ((sps->level_idc & 0xff) << 7) | >> +         (get_flag(sps->flags, V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) << >> 2); >> +     WRITE_VREG(NAL_SEARCH_CTL, RD_VREG(NAL_SEARCH_CTL) | cfg_tmp); >> + >> +     h264_ctx->mb_width = (sps->pic_width_in_mbs_minus1 + 4) & >> 0xfffffffc; >> +     h264_ctx->mb_height = (sps->pic_height_in_map_units_minus1 + 4) >> & 0xfffffffc; >> +     h264_ctx->mb_total = h264_ctx->mb_width * h264_ctx->mb_height; >> +     h264_ctx->max_num_ref_frames = sps->max_num_ref_frames; >> +} >> + >> +static void config_pps_params(struct aml_h264_ctx *h264_ctx, >> +                           unsigned short *pps_base, >> +                           const struct v4l2_ctrl_h264_pps *pps) >> +{ >> +     u32 offset = 0; >> +     unsigned short data_tmp[0x100]; >> +     u32 max_reference_size = V4L2_H264_NUM_DPB_ENTRIES; >> +     u32 max_list_size; >> +     int i, ii; >> + >> +     memset(pps_base, 0, 0x100); >> + >> +     data_tmp[offset++] = PARAM_BASE_VAL; >> + >> +     data_tmp[offset++] = >> + GET_PPS_PIC_PARAM_SET_ID(pps->pic_parameter_set_id) | >> +         GET_PPS_SEQ_PARAM_SET_ID(pps->seq_parameter_set_id) | >> +         GET_PPS_ENTROPY_CODING_MODE_FLAG >> +                     (get_flag(pps->flags, >> + V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE)) | >> +         GET_PPS_PIC_ORDER_PRESENT_FLAG >> +                     (get_flag(pps->flags, >> + V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT)); >> + >> +     data_tmp[offset++] = >> + GET_PPS_WEIGHTED_BIPRED_IDC(pps->weighted_bipred_idc) | >> +             GET_PPS_WEIGHTED_PRED_FLAG(get_flag(pps->flags, >> + V4L2_H264_PPS_FLAG_WEIGHTED_PRED)) | >> + >> GET_PPS_NUM_IDX_REF_L1_MINUS1(pps->num_ref_idx_l1_default_active_minus1) >> | >> + >> GET_PPS_NUM_IDX_REF_L0_MINUS1(pps->num_ref_idx_l0_default_active_minus1); >> + >> +     data_tmp[offset++] = >> GET_PPS_INIT_QS_MINUS26(pps->pic_init_qs_minus26) | >> +         GET_PPS_INIT_QP_MINUS26(pps->pic_init_qp_minus26); >> + >> +     data_tmp[offset] = >> + GET_PPS_CHROMA_QP_INDEX_OFFSET(pps->chroma_qp_index_offset) | >> +         GET_PPS_DEBLOCK_FILTER_CTRL_PRESENT_FLAG >> +                             (get_flag(pps->flags, >> + V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT)) | >> +         GET_PPS_CONSTRAIN_INTRA_PRED_FLAG >> +                             (get_flag(pps->flags, >> + V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED)) | >> +         GET_PPS_REDUNDANT_PIC_CNT_PRESENT_FLAG >> +                             (get_flag(pps->flags, >> + V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT)); >> +     if (get_flag >> +         (pps->flags, >> +          V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE | >> +          V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) >> +             data_tmp[offset] |= (1 << 11); >> +     offset++; >> + >> +     data_tmp[offset++] = >> +         GET_PPS_SCALING_MATRIX_PRESENT_FLAG(get_flag >> +                                             (pps->flags, >> + V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) | >> +         GET_PPS_TRANSFORM_8X8_FLAG(get_flag >> +                                    (pps->flags, >> + V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE)); >> + >> +     data_tmp[offset++] = >> + >> GET_PPS_GET_SECOND_CHROMA_QP_OFFSET(pps->second_chroma_qp_index_offset); >> + >> +     max_list_size = (pps->num_ref_idx_l1_default_active_minus1 + 1) + >> +         (pps->num_ref_idx_l0_default_active_minus1 + 1); >> + >> +     h264_ctx->max_num_ref_frames = max_list_size > >> h264_ctx->max_num_ref_frames ? >> +                                             max_list_size : >> h264_ctx->max_num_ref_frames; >> + >> +     WRITE_VREG(AV_SCRATCH_0, ((h264_ctx->max_num_ref_frames + 1) << >> 24) | >> +                (max_reference_size << 16) | (max_reference_size << >> 8)); >> + >> +     for (i = 0; i < 0x100; i += 4) { >> +             for (ii = 0; ii < 4; ii++) >> +                     pps_base[i + 3 - ii] = data_tmp[i + ii]; >> +     } >> +} >> + >> +static void h264_config_params(struct aml_vdec_ctx *ctx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)ctx->codec_priv; >> +     unsigned short *p_sps_base, *p_pps_base; >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> +     const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; >> +     const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; >> + >> +     p_sps_base = (unsigned short *)(h264_ctx->workspace_vaddr + >> +             MEM_SPS_BASE + sps->seq_parameter_set_id * 0x400); >> +     p_pps_base = (unsigned short *)(h264_ctx->workspace_vaddr + >> +             MEM_PPS_BASE + pps->pic_parameter_set_id * 0x200); >> + >> +     config_sps_params(h264_ctx, p_sps_base, sps); >> +     config_pps_params(h264_ctx, p_pps_base, pps); >> +} >> + >> +static void config_decode_canvas(struct aml_vdec_hw *hw, >> +                              struct h264_decode_buf_spec *buf_spec, >> +                              u32 mb_width, u32 mb_height) >> +{ >> +     int canvas_alloc_result = 0; >> +     int blkmode = 0x0; >> + >> +     canvas_alloc_result = >> hw->hw_ops.canvas_alloc(&buf_spec->y_canvas_index); >> +     canvas_alloc_result = >> hw->hw_ops.canvas_alloc(&buf_spec->u_canvas_index); >> +     buf_spec->v_canvas_index = buf_spec->u_canvas_index; >> + >> +     if (!canvas_alloc_result) { >> +             /* config y canvas */ >> + hw->hw_ops.config_canvas(buf_spec->y_canvas_index, >> +                                      buf_spec->y_dma_addr, mb_width >> << 4, >> +                                      mb_height << 4, 0, blkmode, 7); >> +             WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, (1 << 11) |        >> /* canvas_blk32_wr */ >> +                        (blkmode << 10) |    /* canvas_blk32 */ >> +                        (1 << 8) |   /* canvas_index_wr */ >> +                        (buf_spec->y_canvas_index << 0)      /* >> canvas index */ >> +                 ); >> + >> +             /* config uv canvas */ >> + hw->hw_ops.config_canvas(buf_spec->u_canvas_index, >> +                                      buf_spec->c_dma_addr, mb_width >> << 4, >> +                                      mb_height << 3, 0, blkmode, 7); >> +             WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, (1 << 11) |        >> /* canvas_blk32_wr */ >> +                        (blkmode << 10) |    /* canvas_blk32 */ >> +                        (1 << 8) |   /* canvas_index_wr */ >> +                        (buf_spec->u_canvas_index << 0)      /* >> canvas index */ >> +                 ); >> + >> +             WRITE_VREG(ANC0_CANVAS_ADDR + buf_spec->canvas_pos, >> +                        spec2canvas(buf_spec)); >> +     } >> +} >> + >> +static int allocate_colocate_buf(struct aml_h264_ctx *h264_ctx, int >> poc) >> +{ >> +     int i; >> + >> +     for (i = 0; i < h264_ctx->colocated_buf_num; i++) { >> +             if (((h264_ctx->colocated_buf_map >> i) & 0x1) == 0) { >> +                     h264_ctx->colocated_buf_map |= (1 << i); >> +                     break; >> +             } >> +     } >> + >> +     if (i == h264_ctx->colocated_buf_num) >> +             return -1; >> + >> +     h264_ctx->colocated_buf_poc[i] = poc; >> +     pr_debug("%s colocated_buf_index %d poc %d\n", __func__, i, >> +              h264_ctx->colocated_buf_poc[i]); >> + >> +     return i; >> +} >> + >> +static void release_colocate_buf(struct aml_h264_ctx *h264_ctx, int >> index) >> +{ >> +     if (index >= 0) { >> +             if (index >= h264_ctx->colocated_buf_num) { >> +                     pr_debug >> +                         ("%s error, index %d is bigger than buf >> count %d\n", >> +                          __func__, index, >> h264_ctx->max_num_ref_frames); >> +             } else { >> +                     if (((h264_ctx->colocated_buf_map >> index) & >> 0x1) == 0x1) { >> +                             h264_ctx->colocated_buf_map &= (~(1 << >> index)); >> +                             pr_debug >> +                                 ("%s colocated_buf_index %d >> released poc %d\n", >> +                                  __func__, index, >> + h264_ctx->colocated_buf_poc[index]); >> +                     } >> +                     h264_ctx->colocated_buf_poc[index] = INVALID_POC; >> +             } >> +     } >> +} >> + >> +static int get_col_buf_index_by_poc(struct aml_h264_ctx *h264_ctx, >> int poc) >> +{ >> +     int idx; >> + >> +     for (idx = 0; idx < h264_ctx->colocated_buf_num; idx++) { >> +             if (h264_ctx->colocated_buf_poc[idx] == poc) >> +                     break; >> +     } >> + >> +     if (idx == h264_ctx->colocated_buf_num) >> +             idx = -1; >> + >> +     return idx; >> +} >> + >> +static int alloc_colocate_cma(struct aml_h264_ctx *h264_ctx, >> +                           struct aml_vdec_ctx *ctx) >> +{ >> +     int alloc_size = 0; >> +     int i; >> +     struct aml_vdec_hw *hw; >> + >> +     if (h264_ctx->collated_cma_vaddr) >> +             return 0; >> + >> +     hw = vdec_get_hw(ctx->dev); >> +     if (!hw) >> +             return -1; >> + >> +     /* 96 :col buf size for each mb */ >> +     h264_ctx->one_col_buf_size = h264_ctx->mb_total * 96; >> +     alloc_size = PAGE_ALIGN(h264_ctx->one_col_buf_size * >> +                     (h264_ctx->max_num_ref_frames + >> COL_BUFFER_MARGIN)); >> +     h264_ctx->collated_cma_vaddr = dma_alloc_coherent(hw->dev, >> alloc_size, >> + &h264_ctx->collated_cma_addr, GFP_KERNEL); >> +     if (!h264_ctx->collated_cma_vaddr) >> +             return -ENOMEM; >> + >> +     pr_debug >> +         ("collated_cma_addr = 0x%llx, one_col_buf_size = %x >> alloc_size = %x\n", >> +          h264_ctx->collated_cma_addr, h264_ctx->one_col_buf_size, >> +          alloc_size); >> +     h264_ctx->collated_cma_addr_end = >> +         h264_ctx->collated_cma_addr + alloc_size; >> +     memset(h264_ctx->collated_cma_vaddr, 0, alloc_size); >> +     h264_ctx->col_buf_alloc_size = alloc_size; >> +     h264_ctx->colocated_buf_map = 0; >> +     h264_ctx->colocated_buf_num = h264_ctx->max_num_ref_frames + >> COL_BUFFER_MARGIN; >> + >> +     /* 32 : max index of co-locate buffer */ >> +     for (i = 0; i < 32; i++) >> +             h264_ctx->colocated_buf_poc[i] = INVALID_POC; >> + >> +     return 0; >> +} >> + >> +static void config_p_reflist(struct aml_h264_ctx *h264_ctx, >> +                          struct v4l2_h264_reference *v4l2_p0_reflist, >> +                          u32 list_size) >> +{ >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> +     struct v4l2_ctrl_h264_decode_params *decode = >> +         (struct v4l2_ctrl_h264_decode_params *)ctrls->decode; >> +     struct v4l2_h264_dpb_entry *dpb = decode->dpb; >> +     u8 index; >> +     int i; >> + >> +     for (i = 0; i < list_size; i++) { >> +             index = v4l2_p0_reflist[i].index; >> +             h264_ctx->ref_list0[i].used = 1; >> +             h264_ctx->ref_list0[i].dpb = &dpb[index]; >> +             h264_ctx->ref_list0[i].poc = >> dpb[index].top_field_order_cnt; >> +             h264_ctx->ref_list0[i].long_term_flag = >> +                 dpb[index].flags & >> V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM ? true : false; >> +             h264_ctx->ref_list0[i].dpb_index = index; >> +     } >> +     h264_ctx->list_size[0] = i; >> +} >> + >> +static void config_b_reflist(struct aml_h264_ctx *h264_ctx, >> +                          struct v4l2_h264_reference *v4l2_b0_reflist, >> +                          struct v4l2_h264_reference *v4l2_b1_reflist, >> +                          u32 list_size) >> +{ >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> +     struct v4l2_ctrl_h264_decode_params *decode = >> +         (struct v4l2_ctrl_h264_decode_params *)ctrls->decode; >> +     struct v4l2_h264_dpb_entry *dpb = decode->dpb; >> +     u8 index; >> +     int i, j; >> + >> +     for (i = 0; i < list_size; i++) { >> +             index = v4l2_b0_reflist[i].index; >> +             if (dpb[index].top_field_order_cnt > >> decode->top_field_order_cnt) { >> +                     h264_ctx->list_size[0] = i; >> +                     break; >> +             } >> +             h264_ctx->ref_list0[i].used = 1; >> +             h264_ctx->ref_list0[i].dpb = &dpb[index]; >> +             h264_ctx->ref_list0[i].poc = >> dpb[index].top_field_order_cnt; >> +             h264_ctx->ref_list0[i].long_term_flag = >> +                 dpb[index].flags & >> V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM ? true : false; >> +             h264_ctx->ref_list0[i].col_buf_index = >> +                     get_col_buf_index_by_poc(h264_ctx, >> dpb[index].top_field_order_cnt); >> +             h264_ctx->ref_list0[i].dpb_index = index; >> +     } >> + >> +     for (j = 0; j < list_size; j++) { >> +             index = v4l2_b1_reflist[j].index; >> +             if (dpb[index].top_field_order_cnt < >> decode->top_field_order_cnt) { >> +                     h264_ctx->list_size[1] = j; >> +                     break; >> +             } >> +             h264_ctx->ref_list1[j].used = 1; >> +             h264_ctx->ref_list1[j].dpb = &dpb[index]; >> +             h264_ctx->ref_list1[j].poc = >> dpb[index].top_field_order_cnt; >> +             h264_ctx->ref_list1[j].long_term_flag = >> +                 dpb[index].flags & >> V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM ? true : false; >> +             h264_ctx->ref_list1[j].col_buf_index = >> +                     get_col_buf_index_by_poc(h264_ctx, >> dpb[index].top_field_order_cnt); >> +             h264_ctx->ref_list1[j].dpb_index = index; >> +     } >> + >> +     if ((h264_ctx->list_size[1] + h264_ctx->list_size[0]) < list_size) >> +             pr_info("ref list incorrect list0 %d list0 %d >> list_size%d\n", >> +                     h264_ctx->list_size[0], h264_ctx->list_size[1], >> list_size); >> +} >> + >> +static int poc_is_in_dpb(int poc, const struct v4l2_h264_dpb_entry >> *dpb) >> +{ >> +     int i; >> +     int ret = 0; >> + >> +     for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { >> +             if (poc == dpb[i].top_field_order_cnt) { >> +                     ret = 1; >> +                     pr_debug("%s find poc %d col index %x inDPB\n", >> __func__, poc, i); >> +                     break; >> +             } >> +     } >> + >> +     return ret; >> +} >> + >> +static int get_ref_list_size(struct aml_h264_ctx *h264_ctx, int >> cur_list) >> +{ >> +     unsigned short override_flag = >> h264_ctx->dpb_param.l.data[REF_IDC_OVERRIDE_FLAG]; >> +     int num_ref_idx_lx_active_minus1; >> + >> +     if (cur_list == 0) { >> +             num_ref_idx_lx_active_minus1 = >> + h264_ctx->ctrl_ref.pps->num_ref_idx_l0_default_active_minus1; >> +             if (override_flag) >> +                     num_ref_idx_lx_active_minus1 = >> + h264_ctx->dpb_param.dpb.num_ref_idx_l0_active_minus1; >> +     } else { >> +             num_ref_idx_lx_active_minus1 = >> + h264_ctx->ctrl_ref.pps->num_ref_idx_l1_default_active_minus1; >> +     } >> +     pr_debug("%s get list %d size %d\n", __func__, cur_list, >> num_ref_idx_lx_active_minus1 + 1); >> + >> +     return num_ref_idx_lx_active_minus1 + 1; >> +} >> + >> +static int get_refidx_by_picnum(struct aml_h264_ctx *h264_ctx, int >> pic_num, >> +                             int curr_list) >> +{ >> +     int i; >> +     struct h264_decode_buf_spec *ref_list; >> + >> +     if (curr_list == 0) >> +             ref_list = &h264_ctx->ref_list0[0]; >> +     else >> +             ref_list = &h264_ctx->ref_list1[0]; >> + >> +     for (i = 0; ref_list[i].dpb; i++) { >> +             if (pic_num == ref_list[i].dpb->pic_num) >> +                     return i; >> +     } >> + >> +     return -1; >> +} >> + >> +static struct h264_decode_buf_spec *get_st_refpic_by_num(struct >> aml_h264_ctx *h264_ctx, >> +                                                      int pic_num, >> int curr_list) >> +{ >> +     int i; >> +     struct h264_decode_buf_spec *ref_list; >> + >> +     if (curr_list == 0) >> +             ref_list = &h264_ctx->ref_list0_unreordered[0]; >> +     else >> +             ref_list = &h264_ctx->ref_list1_unreordered[0]; >> + >> +     for (i = 0; ref_list[i].dpb; i++) { >> +             if (pic_num == ref_list[i].dpb->pic_num && >> ref_list[i].long_term_flag == 0) >> +                     return &ref_list[i]; >> +     } >> + >> +     return NULL; >> +} >> + >> +static struct h264_decode_buf_spec *get_lt_refpic_by_num(struct >> aml_h264_ctx *h264_ctx, >> +                                                      int pic_num, >> int curr_list) >> +{ >> +     int i; >> +     struct h264_decode_buf_spec *ref_list; >> + >> +     if (curr_list == 0) >> +             ref_list = &h264_ctx->ref_list0_unreordered[0]; >> +     else >> +             ref_list = &h264_ctx->ref_list1_unreordered[0]; >> + >> +     for (i = 0; ref_list[i].dpb; i++) { >> +             if (pic_num == ref_list[i].dpb->pic_num && >> ref_list[i].long_term_flag == 1) >> +                     return &ref_list[i]; >> +     } >> + >> +     return NULL; >> +} >> + >> +static void reorder_short_term(struct slice *curr_slice, int cur_list, >> +                            int pic_num_lx, int *ref_idx_lx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = container_of(curr_slice, struct >> aml_h264_ctx, mslice); >> +     int c_idx, n_idx; >> +     int num_ref_idx_lx_active; >> +     struct h264_decode_buf_spec *pic_lx = NULL; >> +     struct h264_decode_buf_spec *ref_list_reordered; >> + >> +     if (cur_list == 0) >> +             ref_list_reordered = &h264_ctx->ref_list0[0]; >> +     else >> +             ref_list_reordered = &h264_ctx->ref_list1[0]; >> + >> +     num_ref_idx_lx_active = get_ref_list_size(h264_ctx, cur_list); >> + >> +     /* find short-term ref frame with pic_num is pic_num_lx */ >> +     pic_lx = get_st_refpic_by_num(h264_ctx, pic_num_lx, cur_list); >> +     if (!pic_lx) { >> +             pr_debug("cannot find st pic_lx for %d\n", pic_num_lx); >> +             return; >> +     } >> + >> +     if (*ref_idx_lx == get_refidx_by_picnum(h264_ctx, pic_num_lx, >> cur_list)) { >> +             pr_debug("no need to move pic lx %d\n", *ref_idx_lx); >> +             *ref_idx_lx = *ref_idx_lx + 1; >> +             return; >> +     } >> + >> +     for (c_idx = num_ref_idx_lx_active; c_idx > *ref_idx_lx; c_idx--) >> +             memcpy(&ref_list_reordered[c_idx], >> &ref_list_reordered[c_idx - 1], >> +                    sizeof(struct h264_decode_buf_spec)); >> + >> +     memcpy(&ref_list_reordered[*ref_idx_lx], pic_lx, sizeof(struct >> h264_decode_buf_spec)); >> +     pr_debug("%s 1 : RefPicListX[%d ] = pic %p pic_num(%d)\n", >> __func__, >> +              *ref_idx_lx, pic_lx, >> ref_list_reordered[*ref_idx_lx].dpb->pic_num); >> +     *ref_idx_lx = *ref_idx_lx + 1; >> + >> +     n_idx = *ref_idx_lx; >> +     for (c_idx = *ref_idx_lx; c_idx <= num_ref_idx_lx_active; >> c_idx++) { >> +             if (ref_list_reordered[c_idx].long_term_flag || >> !ref_list_reordered[c_idx].dpb || >> +                 ref_list_reordered[c_idx].dpb->pic_num != pic_num_lx) >> +                     memcpy(&ref_list_reordered[n_idx++], >> &ref_list_reordered[c_idx], >> +                            sizeof(struct h264_decode_buf_spec)); >> +     } >> + >> +     h264_ctx->list_size[cur_list] = num_ref_idx_lx_active; >> +} >> + >> +static void reorder_long_term(struct slice *curr_slice, int cur_list, >> +                           int lt_pic_num, int *ref_idx_lx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = container_of(curr_slice, struct >> aml_h264_ctx, mslice); >> +     int num_ref_idx_lx_active; >> +     int c_idx, n_idx; >> +     struct h264_decode_buf_spec *ref_list; >> +     struct h264_decode_buf_spec *pic_lt = NULL; >> + >> +     if (cur_list == 0) >> +             ref_list = &h264_ctx->ref_list0[0]; >> +     else >> +             ref_list = &h264_ctx->ref_list1[0]; >> + >> +     num_ref_idx_lx_active = get_ref_list_size(h264_ctx, cur_list); >> + >> +     /* find long-term ref frame with pic_num is lt_pic_num */ >> +     pic_lt = get_lt_refpic_by_num(h264_ctx, lt_pic_num, cur_list); >> +     if (!pic_lt) { >> +             pr_debug("cannot find lt pic_lx for %d\n", lt_pic_num); >> +             return; >> +     } >> + >> +     if (*ref_idx_lx == get_refidx_by_picnum(h264_ctx, lt_pic_num, >> cur_list)) { >> +             pr_debug("no need to move pic lx %d\n", *ref_idx_lx); >> +             *ref_idx_lx = *ref_idx_lx + 1; >> +             return; >> +     } >> + >> +     for (c_idx = num_ref_idx_lx_active; c_idx > *ref_idx_lx; c_idx--) >> +             memcpy(&ref_list[c_idx], &ref_list[c_idx - 1], >> sizeof(struct h264_decode_buf_spec)); >> + >> +     memcpy(&ref_list[*ref_idx_lx], pic_lt, sizeof(struct >> h264_decode_buf_spec)); >> +     pr_debug("%s 1 : RefPicListX[%d ] = pic %p pic_num(%d)\n", >> __func__, >> +              *ref_idx_lx, pic_lt, ref_list[*ref_idx_lx].dpb->pic_num); >> +     *ref_idx_lx = *ref_idx_lx + 1; >> + >> +     n_idx = *ref_idx_lx; >> +     /* Pointer dpb is NULL means this is a dummy frame store */ >> +     for (c_idx = *ref_idx_lx; c_idx <= num_ref_idx_lx_active; >> c_idx++) { >> +             if (!ref_list[c_idx].long_term_flag || >> !ref_list[c_idx].dpb || >> +                 ref_list[c_idx].dpb->pic_num != lt_pic_num) >> +                     memcpy(&ref_list[n_idx++], &ref_list[c_idx], >> +                            sizeof(struct h264_decode_buf_spec)); >> +     } >> + >> +     h264_ctx->list_size[cur_list] = num_ref_idx_lx_active; >> +} >> + >> +static void get_modification_cmd(unsigned short *reorder_cmd, struct >> slice *curr_slice, int list) >> +{ >> +     int i, j, val; >> + >> +     val = curr_slice->ref_pic_list_reordering_flag[list]; >> +     if (val) { >> +             i = 0; >> +             j = 0; >> +             do { >> + curr_slice->modification_of_pic_nums_idc[list][i] = >> +                             reorder_cmd[j++]; >> +                     if (j >= REORDER_CMD_MAX) { >> + curr_slice->modification_of_pic_nums_idc[list][i] = 0; >> +                             break; >> +                     } >> + >> +                     val = >> curr_slice->modification_of_pic_nums_idc[list][i]; >> +                     if (val == 0 || val == 1) >> + curr_slice->abs_diff_pic_num_minus1[list][i] = reorder_cmd[j++]; >> +                     else if (val == 2) >> + curr_slice->long_term_pic_idx[list][i] = reorder_cmd[j++]; >> + >> +                     i++; >> + >> +                     if (i >= REORDERING_COMMAND_MAX_SIZE) { >> + curr_slice->ref_pic_list_reordering_flag[list] = 0; >> +                             break; >> +                     }; >> +                     if (j > REORDER_CMD_MAX) { >> + curr_slice->ref_pic_list_reordering_flag[list] = 0; >> +                             break; >> +                     }; >> +             } while (val != 3); >> +     } >> +} >> + >> +static void reorder_pics(struct aml_h264_ctx *h264_ctx, struct slice >> *curr_slice, int cur_list) >> +{ >> +     int *modification_of_pic_nums_idc = >> + curr_slice->modification_of_pic_nums_idc[cur_list]; >> +     int *abs_diff_pic_num_minus1 = >> +             curr_slice->abs_diff_pic_num_minus1[cur_list]; >> +     int *long_term_pic_idx = curr_slice->long_term_pic_idx[cur_list]; >> +     int pic_num_lx_nowarp, pic_num_lx_pred, pic_num_lx; >> +     int curr_pic_num = curr_slice->frame_num; >> +     int max_pic_num = 1 << (4 + >> h264_ctx->ctrl_ref.sps->log2_max_frame_num_minus4); >> +     int ref_idx_lx = 0; >> +     int nowarp_tmp = 0; >> +     int i; >> + >> +     pic_num_lx_pred = curr_pic_num; >> +     for (i = 0; i < REORDERING_COMMAND_MAX_SIZE && >> modification_of_pic_nums_idc[i] != 3; i++) { >> +             if (modification_of_pic_nums_idc[i] > 3) { >> +                     pr_info("error, Invalid >> modification_of_pic_nums_idc command\n"); >> +                     break; >> +             } >> + >> +             if (modification_of_pic_nums_idc[i] < 2) { >> +                     if (modification_of_pic_nums_idc[i] == 0) { >> +                             nowarp_tmp = pic_num_lx_pred - >> (abs_diff_pic_num_minus1[i] + 1); >> +                             pic_num_lx_nowarp = nowarp_tmp + >> (nowarp_tmp < 0 ? max_pic_num : 0); >> +                     } else if (modification_of_pic_nums_idc[i] == 1) { >> +                             nowarp_tmp = pic_num_lx_pred + >> (abs_diff_pic_num_minus1[i] + 1); >> +                             pic_num_lx_nowarp = nowarp_tmp - >> +                                     (nowarp_tmp > max_pic_num ? >> max_pic_num : 0); >> +                     } >> +                     pic_num_lx_pred = pic_num_lx_nowarp; >> +                     if (pic_num_lx_nowarp > curr_pic_num) >> +                             pic_num_lx = pic_num_lx_nowarp - >> max_pic_num; >> +                     else >> +                             pic_num_lx = pic_num_lx_nowarp; >> + >> +                     reorder_short_term(curr_slice, cur_list, >> pic_num_lx, &ref_idx_lx); >> +             } else { >> +                     reorder_long_term(curr_slice, cur_list, >> long_term_pic_idx[i], &ref_idx_lx); >> +             } >> +     } >> +} >> + >> +static void copy_ref_list(struct aml_h264_ctx *h264_ctx, int curr_list) >> +{ >> +     if (curr_list == 0) >> +             memcpy(h264_ctx->ref_list0_unreordered, >> h264_ctx->ref_list0, >> +                    sizeof(h264_ctx->ref_list0)); >> +     else >> +             memcpy(h264_ctx->ref_list1_unreordered, >> h264_ctx->ref_list0, >> +                    sizeof(h264_ctx->ref_list1)); >> +} >> + >> +static void h264_reorder_reflists(struct aml_h264_ctx *h264_ctx) >> +{ >> +     unsigned short *reorder_cmd; >> +     struct slice *curr_slice = &h264_ctx->mslice; >> + >> +     memset(curr_slice, 0, sizeof(struct slice)); >> +     /* parsed by ucode */ >> +     curr_slice->slice_type = h264_ctx->dpb_param.l.data[SLICE_TYPE]; >> +     curr_slice->num_ref_idx_l0 = >> h264_ctx->dpb_param.dpb.num_ref_idx_l0_active_minus1 + 1; >> +     curr_slice->num_ref_idx_l1 = >> h264_ctx->dpb_param.dpb.num_ref_idx_l1_active_minus1 + 1; >> +     curr_slice->frame_num = h264_ctx->ctrl_ref.decode->frame_num; >> + >> +     if (curr_slice->slice_type != I_SLICE && curr_slice->slice_type >> != SI_SLICE) { >> +             reorder_cmd = &h264_ctx->dpb_param.mmco.l0_reorder_cmd[0]; >> +             /* 3:parsed by ucode, means no reorder needed */ >> +             if (reorder_cmd[0] != 3) >> + curr_slice->ref_pic_list_reordering_flag[0] = 1; >> +             else >> + curr_slice->ref_pic_list_reordering_flag[0] = 0; >> + >> +             get_modification_cmd(reorder_cmd, curr_slice, 0); >> +     } >> + >> +     if (curr_slice->slice_type == B_SLICE) { >> +             reorder_cmd = &h264_ctx->dpb_param.mmco.l1_reorder_cmd[0]; >> +             /* 3:parsed by ucode, means no reorder needed */ >> +             if (reorder_cmd[0] != 3) >> + curr_slice->ref_pic_list_reordering_flag[1] = 1; >> +             else >> + curr_slice->ref_pic_list_reordering_flag[1] = 0; >> + >> +             get_modification_cmd(reorder_cmd, curr_slice, 1); >> +     } >> + >> +     if (curr_slice->slice_type != I_SLICE && >> +         curr_slice->slice_type != SI_SLICE && >> +         curr_slice->ref_pic_list_reordering_flag[0] != 0) { >> +             copy_ref_list(h264_ctx, 0); >> +             reorder_pics(h264_ctx, curr_slice, 0); >> +     } >> + >> +     if (curr_slice->slice_type == B_SLICE && >> curr_slice->ref_pic_list_reordering_flag[1] != 0) { >> +             copy_ref_list(h264_ctx, 1); >> +             reorder_pics(h264_ctx, curr_slice, 1); >> +     } >> +} >> + >> +static void h264_config_ref_lists(struct aml_vdec_ctx *ctx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)ctx->codec_priv; >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> +     struct v4l2_ctrl_h264_decode_params *decode = >> +             (struct v4l2_ctrl_h264_decode_params *)ctrls->decode; >> +     struct v4l2_ctrl_h264_sps *sps = (struct v4l2_ctrl_h264_sps >> *)ctrls->sps; >> +     const struct v4l2_h264_dpb_entry *dpb = decode->dpb; >> +     struct v4l2_h264_reflist_builder builder; >> +     struct v4l2_h264_reference >> v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; >> +     struct v4l2_h264_reference >> v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; >> +     struct v4l2_h264_reference >> v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; >> + >> +     if (decode->flags == V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) >> +             return; >> + >> +     v4l2_h264_init_reflist_builder(&builder, decode, sps, dpb); >> +     pr_debug("%s num_valid = %d", __func__, builder.num_valid); >> + >> +     if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_PFRAME) { >> +             v4l2_h264_build_p_ref_list(&builder, v4l2_p0_reflist); >> +             config_p_reflist(h264_ctx, v4l2_p0_reflist, >> builder.num_valid); >> +     } else if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) { >> +             v4l2_h264_build_b_ref_lists(&builder, v4l2_b0_reflist, >> v4l2_b1_reflist); >> +             config_b_reflist(h264_ctx, v4l2_b0_reflist, >> v4l2_b1_reflist, builder.num_valid); >> +     } >> +} >> + >> +static void clear_unused_col_buf(struct aml_h264_ctx *h264_ctx, >> +                              struct v4l2_ctrl_h264_decode_params >> *decode) >> +{ >> +     int i, col_poc; >> + >> +     /* flush all col buffers when IDR */ >> +     if (decode->flags == V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) { >> +             /* 32 : max index of co-locate buffer */ >> +             for (i = 0; i < 32; i++) >> +                     release_colocate_buf(h264_ctx, i); >> +             return; >> +     } >> + >> +     for (i = 0; i < h264_ctx->colocated_buf_num; i++) { >> +             col_poc = h264_ctx->colocated_buf_poc[i]; >> +             if (col_poc != INVALID_POC && (poc_is_in_dpb(col_poc, >> decode->dpb) != 1)) >> +                     release_colocate_buf(h264_ctx, i); >> +     } >> +} >> + >> +static void h264_config_decode_spec(struct aml_vdec_hw *hw, struct >> aml_vdec_ctx *ctx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)hw->curr_ctx; >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> +     struct v4l2_ctrl_h264_decode_params *decode = >> +             (struct v4l2_ctrl_h264_decode_params *)ctrls->decode; >> +     struct h264_decode_buf_spec *buf_spec; >> +     struct vb2_buffer *vb; >> +     struct vb2_v4l2_buffer *vb2_v4l2; >> +     struct vb2_queue *vq; >> +     int i; >> + >> +     clear_unused_col_buf(h264_ctx, decode); >> + >> +     vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); >> +     vb = &vb2_v4l2->vb2_buf; >> + >> +     h264_ctx->curr_spec.y_dma_addr = >> vb2_dma_contig_plane_dma_addr(vb, 0); >> +     if (ctx->pic_info.plane_num > 1) >> +             h264_ctx->curr_spec.c_dma_addr = >> vb2_dma_contig_plane_dma_addr(vb, 1); >> +     else >> +             h264_ctx->curr_spec.c_dma_addr = >> +                             h264_ctx->curr_spec.y_dma_addr + >> ctx->pic_info.fb_size[0]; >> +     h264_ctx->curr_spec.canvas_pos = 0; >> +     h264_ctx->curr_spec.col_buf_index = >> +             allocate_colocate_buf(h264_ctx, >> decode->top_field_order_cnt); >> +     h264_ctx->curr_spec.poc = decode->top_field_order_cnt; >> +     config_decode_canvas(hw, &h264_ctx->curr_spec, >> h264_ctx->mb_width, h264_ctx->mb_height); >> + >> +     h264_config_ref_lists(ctx); >> + >> +     vq = v4l2_m2m_get_vq(ctx->m2m_ctx, >> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); >> + >> +     for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { >> +             struct v4l2_h264_dpb_entry *dpb = &decode->dpb[i]; >> + >> +             if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) >> +                     continue; >> + >> +             buf_spec = find_spec_by_dpb_index(h264_ctx, i); >> +             if (buf_spec) { >> +                     buf_spec->canvas_pos = i + 1; >> +                     vb = vb2_find_buffer(vq, dpb->reference_ts); >> +                     if (!vb) { >> +                             pr_err("ref pic for ts %llu lost\n", >> dpb->reference_ts); >> +                             continue; >> +                     } >> + >> +                     buf_spec->y_dma_addr = >> +                             vb2_dma_contig_plane_dma_addr(vb, 0); >> +                     if (ctx->pic_info.plane_num > 1) >> +                             buf_spec->c_dma_addr = >> vb2_dma_contig_plane_dma_addr(vb, 1); >> +                     else >> +                             buf_spec->c_dma_addr = >> +                                     buf_spec->y_dma_addr + >> ctx->pic_info.fb_size[0]; >> +                     config_decode_canvas(hw, buf_spec, >> h264_ctx->mb_width, h264_ctx->mb_height); >> +                     pr_debug >> +                         ("config canvas for poc %d canvas %d >> y_dma_addr 0x%llx\n", >> + buf_spec->dpb->top_field_order_cnt, >> +                          buf_spec->canvas_pos, buf_spec->y_dma_addr); >> +             } >> +     } >> + >> +     h264_reorder_reflists(h264_ctx); >> +} >> + >> +static int h264_config_decode_buf(struct aml_vdec_hw *hw, struct >> aml_vdec_ctx *ctx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)hw->curr_ctx; >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> +     struct v4l2_ctrl_h264_decode_params *decode = >> +             (struct v4l2_ctrl_h264_decode_params *)ctrls->decode; >> +     unsigned long canvas_adr; >> +     unsigned int ref_cfg; >> +     unsigned int ref_cfg_once = 0; >> +     unsigned int type_cfg = 0x3; /* 0x3: frame type */ >> +     unsigned int colocate_adr_offset, colocate_wr_adr; >> +     unsigned int info0; >> +     unsigned int info1; >> +     unsigned int info2; >> +     int i, j; >> +     int h264_buffer_info_data_write_count; >> +     u8 canvas_pos; >> +     u8 use_mode_8x8_flag; >> + >> +     WRITE_VREG(H264_CURRENT_POC_IDX_RESET, 0); >> +     WRITE_VREG(H264_CURRENT_POC, decode->top_field_order_cnt); >> +     WRITE_VREG(H264_CURRENT_POC, decode->top_field_order_cnt); >> +     WRITE_VREG(H264_CURRENT_POC, decode->bottom_field_order_cnt); >> +     WRITE_VREG(CURR_CANVAS_CTRL, h264_ctx->curr_spec.canvas_pos << >> 24); >> +     canvas_adr = RD_VREG(CURR_CANVAS_CTRL) & 0xffffff; >> +     pr_debug("canvas_pos = %d canvas_adr 0x%lx\n", >> h264_ctx->curr_spec.canvas_pos, canvas_adr); >> + >> +     WRITE_VREG(REC_CANVAS_ADDR, canvas_adr); >> +     WRITE_VREG(DBKR_CANVAS_ADDR, canvas_adr); >> +     WRITE_VREG(DBKW_CANVAS_ADDR, canvas_adr); >> + >> +     WRITE_VREG(H264_BUFFER_INFO_INDEX, 16); >> +     info0 = 0xf480; >> +     info1 = decode->top_field_order_cnt; >> +     info2 = decode->bottom_field_order_cnt; >> +     if (decode->bottom_field_order_cnt < decode->top_field_order_cnt) >> +             info0 |= 0x100; >> + >> +     WRITE_VREG(H264_BUFFER_INFO_DATA, info0 | 0xf); >> +     WRITE_VREG(H264_BUFFER_INFO_DATA, info1); >> +     WRITE_VREG(H264_BUFFER_INFO_DATA, info2); >> + >> +     for (j = 0; j < V4L2_H264_NUM_DPB_ENTRIES; j++) { >> +             struct v4l2_h264_dpb_entry *dpb = &decode->dpb[j]; >> + >> +             info0 = 0; >> +             info1 = 0; >> +             info2 = 0; >> +             if (dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { >> +                     info0 = 0xf480; >> +                     if (decode->bottom_field_order_cnt < >> decode->top_field_order_cnt) >> +                             info0 |= 0x100; >> +                     info1 = dpb->top_field_order_cnt; >> +                     info2 = dpb->bottom_field_order_cnt; >> +                     if (dpb->flags & >> V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) >> +                             info0 |= ((1 << 5) | (1 << 4)); >> +             } >> +             WRITE_VREG(H264_BUFFER_INFO_DATA, info0); >> +             WRITE_VREG(H264_BUFFER_INFO_DATA, info1); >> +             WRITE_VREG(H264_BUFFER_INFO_DATA, info2); >> +     } >> + >> +     WRITE_VREG(H264_BUFFER_INFO_INDEX, 0); >> +     /* when frame width <= 256, Disable DDR_BYTE64_CACHE */ >> +     if (ctx->pic_info.coded_width <= 256) { >> +             SET_VREG_MASK(IQIDCT_CONTROL, (1 << 16)); >> +             WRITE_VREG(DCAC_DDR_BYTE64_CTL, >> +                        (RD_VREG(DCAC_DDR_BYTE64_CTL) & (~0xf)) | 0xa); >> +     } else { >> +             CLEAR_VREG_MASK(IQIDCT_CONTROL, (1 << 16)); >> +     } >> + >> +     ref_cfg = 0; >> +     j = 0; >> + >> +     if (h264_ctx->list_size[0] > 0) { >> +             for (i = 0; i < h264_ctx->list_size[0]; i++) { >> +                     canvas_pos = h264_ctx->ref_list0[i].canvas_pos; >> +                     /* bit 0:3 canvas_pos bit 5:6 frame struct cfg */ >> +                     ref_cfg_once = (canvas_pos & 0x1f) | (type_cfg >> << 5); >> +                     ref_cfg <<= 8; >> +                     ref_cfg |= ref_cfg_once; >> +                     j++; >> + >> +                     if (j == 4) { >> +                             WRITE_VREG(H264_BUFFER_INFO_DATA, >> ref_cfg); >> +                             pr_debug("H264_BUFFER_INFO_DATA: %x\n", >> ref_cfg); >> + h264_buffer_info_data_write_count++; >> +                             j = 0; >> +                     } >> +             } >> + >> +             if (j != 0) { >> +                     while (j != 4) { >> +                             ref_cfg <<= 8; >> +                             ref_cfg |= ref_cfg_once; >> +                             j++; >> +                     } >> +                     WRITE_VREG(H264_BUFFER_INFO_DATA, ref_cfg); >> +                     pr_debug("H264_BUFFER_INFO_DATA: %x\n", ref_cfg); >> +                     h264_buffer_info_data_write_count++; >> +             } >> +             ref_cfg = (ref_cfg_once << 24) | (ref_cfg_once << 16) | >> +                     (ref_cfg_once << 8) | ref_cfg_once; >> +             for (j = h264_buffer_info_data_write_count; j < 8; j++) >> +                     WRITE_VREG(H264_BUFFER_INFO_DATA, ref_cfg); >> +     } >> + >> +     WRITE_VREG(H264_BUFFER_INFO_INDEX, 8); >> +     j = 0; >> +     ref_cfg = 0; >> + >> +     if (h264_ctx->list_size[1] > 0) { >> +             for (i = 0; i < h264_ctx->list_size[1]; i++) { >> +                     canvas_pos = h264_ctx->ref_list1[i].canvas_pos; >> +                     ref_cfg_once = (canvas_pos & 0x1f) | (type_cfg >> << 5); >> +                     ref_cfg <<= 8; >> +                     ref_cfg |= ref_cfg_once; >> +                     j++; >> + >> +                     if (j == 4) { >> +                             WRITE_VREG(H264_BUFFER_INFO_DATA, >> ref_cfg); >> +                             pr_debug("H264_BUFFER_INFO_DATA: %x\n", >> ref_cfg); >> +                             j = 0; >> +                     } >> +             } >> +     } >> + >> +     if (j != 0) { >> +             while (j != 4) { >> +                     ref_cfg <<= 8; >> +                     ref_cfg |= ref_cfg_once; >> +                     j++; >> +             } >> +             pr_debug("H264_BUFFER_INFO_DATA: %x\n", ref_cfg); >> +             WRITE_VREG(H264_BUFFER_INFO_DATA, ref_cfg); >> +     } >> + >> +     if (get_flag(ctrls->sps->flags, >> V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && >> +         get_flag(ctrls->sps->flags, >> V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)) >> +             use_mode_8x8_flag = 1; >> +     else >> +             use_mode_8x8_flag = 0; >> + >> +     while ((RD_VREG(H264_CO_MB_RW_CTL) >> 11) & 0x1) >> +             continue; >> + >> +     /* col buf for curr frame */ >> +     colocate_adr_offset = 0; >> +     if (h264_ctx->curr_spec.col_buf_index >= 0 && >> +         h264_ctx->curr_spec.col_buf_index < >> h264_ctx->colocated_buf_num) { >> +             colocate_wr_adr = h264_ctx->collated_cma_addr + >> +                     ((h264_ctx->one_col_buf_size * >> h264_ctx->curr_spec.col_buf_index) >> >> +                     (use_mode_8x8_flag ? 2 : 0)); >> +             if (colocate_wr_adr + h264_ctx->one_col_buf_size > >> +                 h264_ctx->collated_cma_addr_end) { >> +                     pr_err >> +                         ("Error, colocate buf is not enough, index >> is %d\n", >> + h264_ctx->curr_spec.col_buf_index); >> +                     return -1; >> +             } >> +             WRITE_VREG(H264_CO_MB_WR_ADDR, >> +                        (colocate_wr_adr + colocate_adr_offset)); >> +             pr_debug("col buffer addr = 0x%x col_buf_index %d\n", >> +                      (colocate_wr_adr + colocate_adr_offset), >> +                      h264_ctx->curr_spec.col_buf_index); >> +     } else { >> +             WRITE_VREG(H264_CO_MB_WR_ADDR, 0xffffffff); >> +             pr_debug("col buffer addr = 0xffffffff\n"); >> +     } >> + >> +     if (h264_ctx->list_size[1] > 0) { >> +             struct h264_decode_buf_spec *colocate_pic = >> &h264_ctx->ref_list1[0]; >> +             struct h264_decode_buf_spec *curr_pic = >> &h264_ctx->curr_spec; >> +             int l10_structure = 2; /* for pic struct == FRAME, >> default to 2 */ >> +             int cur_colocate_ref_type; >> +             unsigned int colocate_rd_adr; >> +             unsigned int colocate_rd_adr_offset = 0; >> +             unsigned int val; >> + >> +             cur_colocate_ref_type = >> +                     (abs(curr_pic->poc - >> colocate_pic->dpb->top_field_order_cnt) < >> +                     abs(curr_pic->poc - >> colocate_pic->dpb->bottom_field_order_cnt)) ? >> +                     0 : 1; >> + >> +             if (colocate_pic->col_buf_index >= 0 && >> +                 colocate_pic->col_buf_index < >> h264_ctx->colocated_buf_num) { >> +                     colocate_rd_adr = h264_ctx->collated_cma_addr + >> +                             ((h264_ctx->one_col_buf_size * >> colocate_pic->col_buf_index) >> >> +                             (use_mode_8x8_flag ? 2 : 0)); >> +                     if (colocate_rd_adr + h264_ctx->one_col_buf_size > >> +                         h264_ctx->collated_cma_addr_end) { >> +                             pr_err >> +                                 ("Error, colocate rd buf is not >> enough, index is %d\n", >> + colocate_pic->col_buf_index); >> +                             return -1; >> +                     } >> +                     val  = ((colocate_rd_adr_offset + >> colocate_rd_adr) >> 3) | >> +                             (cur_colocate_ref_type << 29) | >> +                             (l10_structure << 30); >> +                     WRITE_VREG(H264_CO_MB_RD_ADDR, val); >> +             } else { >> +                     pr_err >> +                         ("Error, reference pic has no colocated buf >> poc %d\n", >> +                          curr_pic->poc); >> +                     return -1; >> +             } >> +     } >> + >> +     return 0; >> +} >> + >> +static void h264_release_decode_spec(struct aml_vdec_hw *hw, struct >> aml_vdec_ctx *ctx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)hw->curr_ctx; >> +     int i; >> +     struct h264_decode_buf_spec *buf; >> + >> + hw->hw_ops.canvas_free(h264_ctx->curr_spec.y_canvas_index); >> + hw->hw_ops.canvas_free(h264_ctx->curr_spec.v_canvas_index); >> + >> +     if (h264_ctx->list_size[0] > 0) { >> +             for (i = 0; i < h264_ctx->list_size[0]; i++) { >> +                     buf = &h264_ctx->ref_list0[i]; >> +                     if (buf->used) { >> +                             buf->canvas_pos = 0; >> +                             buf->dpb = NULL; >> + hw->hw_ops.canvas_free(buf->y_canvas_index); >> + hw->hw_ops.canvas_free(buf->u_canvas_index); >> +                             buf->used = 0; >> +                     } >> +             } >> +             h264_ctx->list_size[0] = 0; >> +     } >> + >> +     if (h264_ctx->list_size[1] > 0) { >> +             for (i = 0; i < h264_ctx->list_size[1]; i++) { >> +                     buf = &h264_ctx->ref_list1[i]; >> +                     if (buf->used) { >> +                             buf->canvas_pos = 0; >> +                             buf->dpb = NULL; >> + hw->hw_ops.canvas_free(buf->y_canvas_index); >> + hw->hw_ops.canvas_free(buf->u_canvas_index); >> +                             buf->used = 0; >> +                     } >> +             } >> +             h264_ctx->list_size[1] = 0; >> +     } >> +} >> + >> +static void save_reg_status(struct aml_h264_ctx *h264_ctx) >> +{ >> +     h264_ctx->reg_iqidct_control = RD_VREG(IQIDCT_CONTROL); >> +     h264_ctx->reg_iqidct_control_init_flag = 1; >> +     h264_ctx->reg_vcop_ctrl_reg = RD_VREG(VCOP_CTRL_REG); >> +     h264_ctx->reg_rv_ai_mb_count = RD_VREG(RV_AI_MB_COUNT); >> +     h264_ctx->vld_dec_control = RD_VREG(VLD_DECODE_CONTROL); >> +} >> + >> +static irqreturn_t h264_isr(int irq, void *priv) >> +{ >> +     WRITE_VREG(VDEC_ASSIST_MBOX1_CLR_REG, 1); >> + >> +     return IRQ_WAKE_THREAD; >> +} >> + >> +static irqreturn_t h264_threaded_isr_func(int irq, void *priv) >> +{ >> +     int dec_status = RD_VREG(DPB_STATUS_REG); >> +     struct aml_vdec_dev *dev = (struct aml_vdec_dev *)priv; >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)dev->dec_hw->curr_ctx; >> +     struct aml_vdec_ctx *ctx = (struct aml_vdec_ctx *)dev->dec_ctx; >> +     struct aml_vdec_hw *hw = (struct aml_vdec_hw *)dev->dec_hw; >> +     unsigned short *p = (unsigned short *)h264_ctx->lmem_addr; >> +     int i, ii; >> + >> +     h264_ctx->dec_status = dec_status; >> +     pr_debug >> +         ("%s, dec_status 0x%x VIFF_BIT_CNT 0x%x MBY_MBX 0x%x >> VLD_SHIFT_STATUS 0x%x\n", >> +          __func__, dec_status, RD_VREG(VIFF_BIT_CNT), >> RD_VREG(MBY_MBX), >> +          RD_VREG(VLD_SHIFT_STATUS)); >> + >> +     h264_ctx->save_avscratch_f = RD_VREG(AV_SCRATCH_F); >> + >> +     switch (dec_status) { >> +     case H264_SLICE_HEADER_DONE: >> +             for (i = 0; i < 0x400; i += 4) >> +                     for (ii = 0; ii < 4; ii++) >> +                             h264_ctx->dpb_param.l.data[i + ii] = >> p[i + 3 - ii]; >> +             save_reg_status(h264_ctx); >> +             if (h264_ctx->new_pic_flag == 1) >> +                     h264_config_decode_spec(hw, ctx); >> + >> +             if (h264_config_decode_buf(hw, ctx) < 0) { >> +                     h264_release_decode_spec(hw, ctx); >> +                     ctx->int_cond = 1; >> +                     wake_up_interruptible(&ctx->queue); >> +                     goto irq_handled; >> +             } >> +             if (h264_ctx->new_pic_flag == 1) { >> +                     WRITE_VREG(DPB_STATUS_REG, >> H264_ACTION_DECODE_NEWPIC); >> +                     pr_debug("action decode new pic\n"); >> +                     h264_ctx->new_pic_flag = 0; >> +             } else { >> +                     WRITE_VREG(DPB_STATUS_REG, >> H264_ACTION_DECODE_SLICE); >> +                     pr_debug("action decode new slice\n"); >> +             } >> +             break; >> +     case H264_SLICE_DATA_DONE: >> +             h264_release_decode_spec(hw, ctx); >> +             h264_ctx->decode_pic_count++; >> +             ctx->int_cond = 1; >> +             wake_up_interruptible(&ctx->queue); >> +             break; >> +     default: >> +             h264_release_decode_spec(hw, ctx); >> +             ctx->int_cond = 1; >> +             wake_up_interruptible(&ctx->queue); >> +             break; >> +     } >> +irq_handled: >> +     return IRQ_HANDLED; >> +} >> + >> +static int h264_restore_hw_ctx(struct aml_vdec_ctx *ctx) >> +{ >> +     struct aml_h264_ctx *h264_ctx = >> +             (struct aml_h264_ctx *)ctx->codec_priv; >> + >> +     WRITE_VREG(POWER_CTL_VLD, >> +                (RD_VREG(POWER_CTL_VLD) | (0 << 10) | (1 << 9) | (1 >> << 6))); >> + >> +     WRITE_VREG(PSCALE_CTRL, 0); >> + >> +     /* clear mailbox interrupt */ >> +     WRITE_VREG(VDEC_ASSIST_MBOX1_CLR_REG, 1); >> + >> +     /* enable mailbox interrupt */ >> +     WRITE_VREG(VDEC_ASSIST_MBOX1_MASK, 1); >> + >> +     SET_VREG_MASK(MDEC_PIC_DC_CTRL, (1 << 17)); >> +     if (ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == >> V4L2_PIX_FMT_NV21 || >> +         ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M) >> +             SET_VREG_MASK(MDEC_PIC_DC_CTRL, (1 << 16)); >> +     else >> +             CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, (1 << 16)); >> + >> +     SET_VREG_MASK(MDEC_PIC_DC_CTRL, (0xbf << 24)); >> +     CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, (0xbf << 24)); >> +     CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, (1 << 31)); >> + >> +     CLEAR_VREG_MASK(MDEC_PIC_DC_MUX_CTRL, 1 << 31); >> +     WRITE_VREG(MDEC_EXTIF_CFG1, 0); >> +     WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); >> + >> +     WRITE_VREG(DPB_STATUS_REG, 0); >> + >> +     WRITE_VREG(LMEM_DUMP_ADR, h264_ctx->lmem_phy_addr); >> +     WRITE_VREG(FRAME_COUNTER_REG, h264_ctx->decode_pic_count); >> +     WRITE_VREG(AV_SCRATCH_8, h264_ctx->workspace_offset); >> +     WRITE_VREG(AV_SCRATCH_G, h264_ctx->mc_cpu_paddr); >> + >> +     WRITE_VREG(AV_SCRATCH_F, ((h264_ctx->save_avscratch_f & >> 0xffffffc3) | (1 << 4))); >> +     CLEAR_VREG_MASK(AV_SCRATCH_F, 1 << 6); >> + >> +     WRITE_VREG(MDEC_PIC_DC_THRESH, 0x404038aa); >> + >> +     if (h264_ctx->reg_iqidct_control_init_flag == 0) >> +             WRITE_VREG(IQIDCT_CONTROL, 0x200); >> + >> +     if (h264_ctx->reg_iqidct_control) >> +             WRITE_VREG(IQIDCT_CONTROL, h264_ctx->reg_iqidct_control); >> + >> +     if (h264_ctx->reg_vcop_ctrl_reg) >> +             WRITE_VREG(VCOP_CTRL_REG, h264_ctx->reg_vcop_ctrl_reg); >> + >> +     if (h264_ctx->vld_dec_control) >> +             WRITE_VREG(VLD_DECODE_CONTROL, h264_ctx->vld_dec_control); >> + >> +     pr_debug >> +         ("IQIDCT_CONTROL = 0x%x, VCOP_CTRL_REG 0x%x >> VLD_DECODE_CONTROL 0x%x\n", >> +          RD_VREG(IQIDCT_CONTROL), RD_VREG(VCOP_CTRL_REG), >> +          RD_VREG(VLD_DECODE_CONTROL)); >> + >> +     return 0; >> +} >> + >> +static void *aml_h264_get_ctrl(struct v4l2_ctrl_handler *hdl, u32 id) >> +{ >> +     struct v4l2_ctrl *ctrl; >> + >> +     ctrl = v4l2_ctrl_find(hdl, id); >> +     return ctrl ? ctrl->p_cur.p : NULL; >> +} >> + >> +static int aml_h264_get_stateless_ctrl_ref(struct aml_h264_ctx >> *h264_ctx) >> +{ >> +     struct aml_vdec_ctx *ctx = h264_ctx->v4l2_ctx; >> +     struct vdec_h264_stateless_ctrl_ref *ctrls = &h264_ctx->ctrl_ref; >> + >> +     ctrls->sps = >> +             (struct v4l2_ctrl_h264_sps >> *)aml_h264_get_ctrl(&ctx->ctrl_handler, >> +                     V4L2_CID_STATELESS_H264_SPS); >> +     if (WARN_ON(!ctrls->sps)) >> +             return -EINVAL; >> + >> +     ctrls->pps = >> +             (struct v4l2_ctrl_h264_pps >> *)aml_h264_get_ctrl(&ctx->ctrl_handler, >> +                     V4L2_CID_STATELESS_H264_PPS); >> +     if (WARN_ON(!ctrls->pps)) >> +             return -EINVAL; >> + >> +     ctrls->decode = >> +             (struct v4l2_ctrl_h264_decode_params >> *)aml_h264_get_ctrl(&ctx->ctrl_handler, >> +                     V4L2_CID_STATELESS_H264_DECODE_PARAMS); >> +     if (WARN_ON(!ctrls->decode)) >> +             return -EINVAL; >> + >> +     ctrls->scaling = >> +             (struct v4l2_ctrl_h264_scaling_matrix >> *)aml_h264_get_ctrl(&ctx->ctrl_handler, >> +                     V4L2_CID_STATELESS_H264_SCALING_MATRIX); >> +     if (WARN_ON(!ctrls->scaling)) >> +             return -EINVAL; >> + >> +     return 0; >> +} >> + >> +static void copy_mc_cpu_fw(void *mc_cpu_addr, const u8 *data) >> +{ >> +     /*header */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_HEADER, >> +            data + 0x4000, MC_SWAP_SIZE); >> +     /*data */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_DATA, >> +            data + 0x2000, MC_SWAP_SIZE); >> +     /*mmco */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_MMCO, >> +            data + 0x6000, MC_SWAP_SIZE); >> +     /*list */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_LIST, >> +            data + 0x3000, MC_SWAP_SIZE); >> +     /*slice */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_SLICE, >> +            data + 0x5000, MC_SWAP_SIZE); >> +     /*main */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_MAIN, data, 0x2000); >> +     /*data */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_MAIN + 0x2000, >> +            data + 0x2000, 0x1000); >> +     /*slice */ >> +     memcpy((u8 *)mc_cpu_addr + MC_OFFSET_MAIN + 0x3000, >> +            data + 0x5000, 0x1000); >> +} >> + >> +static int aml_h264_load_fw_ext(void *priv, const u8 *data, u32 len) >> +{ >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx *)priv; >> +     struct aml_vdec_ctx *ctx = (struct aml_vdec_ctx >> *)h264_ctx->v4l2_ctx; >> +     struct aml_vdec_hw *dec_hw; >> + >> +     if (h264_ctx->mc_cpu_loaded) >> +             return 0; >> + >> +     dec_hw = vdec_get_hw(ctx->dev); >> +     if (!dec_hw) >> +             return -1; >> + >> +     if (len > MC_TOTAL_SIZE) { >> +             pr_info("size of mc_cpu_fw id invalid\n"); >> +             return -1; >> +     } >> + >> +     h264_ctx->mc_cpu_vaddr = dma_alloc_coherent(dec_hw->dev, >> MC_TOTAL_SIZE, >> + &h264_ctx->mc_cpu_paddr, >> +                                                 GFP_KERNEL); >> +     if (!h264_ctx->mc_cpu_vaddr) >> +             return -ENOMEM; >> + >> +     copy_mc_cpu_fw(h264_ctx->mc_cpu_vaddr, data); >> + >> +     h264_ctx->mc_cpu_loaded = true; >> + >> +     pr_debug("h264 mccpu fw loaded\n"); >> + >> +     return 0; >> +} >> + >> +int aml_h264_init(void *priv) >> +{ >> +     struct aml_vdec_ctx *ctx = (struct aml_vdec_ctx *)priv; >> +     struct aml_vdec_hw *dec_hw; >> +     struct aml_h264_ctx *h264_ctx; >> +     int ret = 0; >> + >> +     h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); >> +     if (!h264_ctx) >> +             return -ENOMEM; >> + >> +     h264_ctx->v4l2_ctx = ctx; >> +     dec_hw = vdec_get_hw(ctx->dev); >> +     if (!dec_hw) >> +             return -1; >> + >> +     h264_ctx->mc_cpu_loaded = false; >> +     dec_hw->hw_ops.irq_handler = h264_isr; >> +     dec_hw->hw_ops.irq_threaded_func = h264_threaded_isr_func; >> +     dec_hw->hw_ops.load_firmware_ex = aml_h264_load_fw_ext; >> + >> +     h264_ctx->lmem_addr = dma_alloc_coherent(dec_hw->dev, >> LMEM_DUMP_SIZE, >> + &h264_ctx->lmem_phy_addr, >> +                                              GFP_KERNEL); >> +     if (!h264_ctx->lmem_addr) { >> +             ret = -ENOMEM; >> +             goto err_alloc_lmem; >> +     } >> + >> +     h264_ctx->cma_alloc_vaddr = >> +         dma_alloc_coherent(dec_hw->dev, V_BUF_ADDR_OFFSET, >> +                            &h264_ctx->cma_alloc_addr, GFP_KERNEL); >> +     if (!h264_ctx->cma_alloc_vaddr) { >> +             ret = -ENOMEM; >> +             goto err_alloc_workspace; >> +     } >> + >> +     h264_ctx->workspace_offset = h264_ctx->cma_alloc_addr + >> DCAC_READ_MARGIN; >> +     h264_ctx->workspace_vaddr = h264_ctx->cma_alloc_vaddr + >> DCAC_READ_MARGIN; >> + >> +     ctx->codec_priv = h264_ctx; >> +     dec_hw->curr_ctx = h264_ctx; >> +     h264_ctx->col_buf_alloc_size = 0; >> +     h264_ctx->init_flag = 0; >> +     h264_ctx->new_pic_flag = 0; >> +     h264_ctx->param_set = 0; >> +     h264_ctx->reg_iqidct_control_init_flag = 0; >> +     h264_ctx->decode_pic_count = 0; >> + >> +     return 0; >> + >> +err_alloc_workspace: >> +     dma_free_coherent(dec_hw->dev, LMEM_DUMP_SIZE, >> +                       h264_ctx->lmem_addr, h264_ctx->lmem_phy_addr); >> +err_alloc_lmem: >> +     kfree(h264_ctx); >> + >> +     return ret; >> +} >> + >> +void aml_h264_exit(void *priv) >> +{ >> +     struct aml_vdec_ctx *ctx = (struct aml_vdec_ctx *)priv; >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)ctx->codec_priv; >> +     struct aml_vdec_hw *dec_hw; >> + >> +     if (!h264_ctx) { >> +             pr_info("h264 decoder is already destroyed or not >> created!\n"); >> +             return; >> +     } >> +     dec_hw = vdec_get_hw(ctx->dev); >> +     h264_ctx->param_set = 0; >> + >> +     if (ctx->dos_clk_en) >> +             aml_stop_vdec_hw(); >> + >> +     if (h264_ctx->collated_cma_vaddr) { >> +             dma_free_coherent(dec_hw->dev, >> h264_ctx->col_buf_alloc_size, >> +                               h264_ctx->collated_cma_vaddr, >> +                               h264_ctx->collated_cma_addr); >> +             h264_ctx->col_buf_alloc_size = 0; >> +     } >> + >> +     if (h264_ctx->mc_cpu_vaddr) { >> +             dma_free_coherent(dec_hw->dev, MC_TOTAL_SIZE, >> +                               h264_ctx->mc_cpu_vaddr, >> +                               h264_ctx->mc_cpu_paddr); >> +             h264_ctx->mc_cpu_loaded = false; >> +     } >> + >> +     if (h264_ctx->lmem_addr) >> +             dma_free_coherent(dec_hw->dev, LMEM_DUMP_SIZE, >> +                               h264_ctx->lmem_addr, >> h264_ctx->lmem_phy_addr); >> + >> +     if (h264_ctx->cma_alloc_vaddr) >> +             dma_free_coherent(dec_hw->dev, V_BUF_ADDR_OFFSET, >> +                               h264_ctx->cma_alloc_vaddr, >> +                               h264_ctx->cma_alloc_addr); >> + >> +     kfree(ctx->codec_priv); >> +     dec_hw->curr_ctx = NULL; >> +     ctx->codec_priv = NULL; >> +} >> + >> +static void config_decode_mode(struct aml_h264_ctx *h264_ctx) >> +{ >> +     WRITE_VREG(H264_DECODE_MODE, 0x1);  /*decode mode framebase*/ >> +     WRITE_VREG(HEAD_PADDING_REG, 0); >> +     WRITE_VREG(H264_DECODE_SEQINFO, h264_ctx->seq_info); >> +     WRITE_VREG(INIT_FLAG_REG, 1); >> +} >> + >> +int aml_h264_dec_run(void *priv) >> +{ >> +     struct aml_vdec_ctx *ctx = (struct aml_vdec_ctx *)priv; >> +     struct aml_h264_ctx *h264_ctx = (struct aml_h264_ctx >> *)ctx->codec_priv; >> +     int ret = -1; >> +     int i; >> + >> +     ret = aml_h264_get_stateless_ctrl_ref(h264_ctx); >> +     if (ret < 0) { >> +             pr_err("not ctrl ref for h264 decoder\n"); >> +             return ret; >> +     } >> + >> +     h264_config_params(ctx); >> + >> +     if (h264_prepare_input(ctx) < 0) >> +             return ret; >> + >> +     if (alloc_colocate_cma(h264_ctx, ctx) < 0) >> +             return ret; >> + >> +     h264_restore_hw_ctx(ctx); >> + >> +     config_decode_mode(h264_ctx); >> +     /* enable stream input hardware */ >> +     SET_VREG_MASK(VLD_MEM_VIFIFO_CONTROL, (1 << 2) | (1 << 1)); >> +     /* enable hardware timer */ >> +     WRITE_VREG(NAL_SEARCH_CTL, RD_VREG(NAL_SEARCH_CTL) | (1 << 16)); >> +     WRITE_VREG(MDEC_EXTIF_CFG2, RD_VREG(MDEC_EXTIF_CFG2) | 0x20); >> +     WRITE_VREG(NAL_SEARCH_CTL, RD_VREG(NAL_SEARCH_CTL) & (~0x2)); >> +     CLEAR_VREG_MASK(VDEC_ASSIST_MMC_CTRL1, 1 << 3); >> + >> +     aml_start_vdec_hw(); >> +     h264_ctx->init_flag = 1; >> +     h264_ctx->new_pic_flag = 1; >> + >> +     WRITE_VREG(DPB_STATUS_REG, H264_ACTION_SEARCH_HEAD); >> + >> +     ret = wait_event_interruptible_timeout(ctx->queue, ctx->int_cond, >> + msecs_to_jiffies(DECODER_TIMEOUT_MS)); >> +     ctx->int_cond = 0; >> +     if (!ret) { >> +             ret = -1; >> +             pr_err("dec timeout=%u\n", DECODER_TIMEOUT_MS); >> +             for (i = 0; i < 16; i++) {      /* 16 : show ucode PC >> 16 times when timeout */ >> +                     pr_info("decoder timeout, pc 0x%x\n", >> RD_VREG(MPC_E)); >> +                     usleep_range(10, 20); >> +             } >> +     } else if (-ERESTARTSYS == ret) { >> +             ret = -1; >> +             pr_err("dec inter fail\n"); >> +     } >> + >> +     aml_stop_vdec_hw(); >> +     h264_ctx->init_flag = 0; >> + >> +     return ret; >> +} >> diff --git a/drivers/media/platform/amlogic/vdec/h264.h >> b/drivers/media/platform/amlogic/vdec/h264.h >> new file mode 100644 >> index 000000000000..3d3a35a641c9 >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/h264.h >> @@ -0,0 +1,300 @@ >> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> +#ifndef _H264_H_ >> +#define _H264_H_ >> + >> +#define RPM_BEGIN           0x0 >> +#define FRAME_IN_DPB        24 >> +#define RPM_END             0x400 >> +#define DPB_OFFSET          0x100 >> +#define MMCO_OFFSET         0x200 >> +#define SPS_OFFSET          0x100 >> +#define PPS_OFFSET          0x300 >> +#define PARAM_BASE_VAL      0x414d >> +#define MEM_MMCO_BASE       0x01c3000 >> +#define MEM_SPS_BASE        0x01c3c00 >> +#define MEM_PPS_BASE        0x01cbc00 >> +#define MC_TOTAL_SIZE       ((20 + 16) * SZ_1K) >> +#define MC_SWAP_SIZE        (4 * SZ_1K) >> +#define LMEM_DUMP_SIZE      4096 >> +#define V_BUF_ADDR_OFFSET   (0x200000 + 0x8000 + 0x20000 + 0x1000) >> +#define DCAC_READ_MARGIN    (64 * 1024) >> +#define MC_OFFSET_HEADER    0x0000 >> +#define MC_OFFSET_DATA      0x1000 >> +#define MC_OFFSET_MMCO      0x2000 >> +#define MC_OFFSET_LIST      0x3000 >> +#define MC_OFFSET_SLICE     0x4000 >> +#define MC_OFFSET_MAIN      0x5000 >> + >> +/* Rename the dos regs */ >> +#define H264_DECODE_INFO    M4_CONTROL_REG >> +#define INIT_FLAG_REG       AV_SCRATCH_2 >> +#define HEAD_PADDING_REG     AV_SCRATCH_3 >> +#define UCODE_WATCHDOG_REG   AV_SCRATCH_7 >> +#define LMEM_DUMP_ADR       AV_SCRATCH_L >> +#define DEBUG_REG1          AV_SCRATCH_M >> +#define DEBUG_REG2          AV_SCRATCH_N >> +#define FRAME_COUNTER_REG       AV_SCRATCH_I >> +#define RPM_CMD_REG          AV_SCRATCH_A >> +#define H264_DECODE_SIZE    AV_SCRATCH_E >> +#define H264_DECODE_MODE    AV_SCRATCH_4 >> +#define H264_DECODE_SEQINFO    AV_SCRATCH_5 >> +/** >> + * NAL_SEARCH_CTL: bit 0, enable itu_t35 >> + * NAL_SEARCH_CTL: bit 1, enable mmu >> + * NAL_SEARCH_CTL: bit 2, detect frame_mbs_only_flag whether switch >> resolution >> + * NAL_SEARCH_CTL: bit 3, recover the correct sps pps >> + * NAL_SEARCH_CTL: bit 7-14,level_idc >> + * NAL_SEARCH_CTL: bit 15,bitstream_restriction_flag >> + */ >> +#define NAL_SEARCH_CTL      AV_SCRATCH_9 >> +#define DPB_STATUS_REG      AV_SCRATCH_J >> +#define ERROR_STATUS_REG    AV_SCRATCH_9 >> + >> +#define H264_BUFFER_INFO_INDEX      PMV3_X   /* 0xc24 */ >> +#define H264_BUFFER_INFO_DATA       PMV2_X   /* 0xc22 */ >> +#define H264_CURRENT_POC_IDX_RESET  LAST_SLICE_MV_ADDR       /* >> 0xc30 */ >> +#define H264_CURRENT_POC            LAST_MVY /* 0xc32 shared with >> conceal MV */ >> +#define H264_CO_MB_WR_ADDR          VLD_C38 >> +#define H264_CO_MB_RD_ADDR          VLD_C39 >> +#define H264_CO_MB_RW_CTL           VLD_C3D >> +#define MBY_MBX                     MB_MOTION_MODE >> + >> +#define H264_ACTION_SEARCH_HEAD     0xf0 >> +#define H264_ACTION_DECODE_SLICE    0xf1 >> +#define H264_ACTION_CONFIG_DONE     0xf2 >> +#define H264_ACTION_DECODE_NEWPIC   0xf3 >> +#define H264_ACTION_DECODE_START    0xff >> + >> +/* RPM memory definition */ >> +#define FIXED_FRAME_RATE_FLAG 0X21 >> +#define OFFSET_DELIMITER_LO 0x2f >> +#define OFFSET_DELIMITER_HI 0x30 >> +#define REF_IDC_OVERRIDE_FLAG 0x35 >> +#define SLICE_IPONLY_BREAK 0X5C >> +#define PREV_MAX_REFERENCE_FRAME_NUM 0X5D >> +#define EOS 0X5E >> +#define FRAME_PACKING_TYPE 0X5F >> +#define OLD_POC_PAR_1 0X60 >> +#define OLD_POC_PAR_2 0X61 >> +#define PREV_MBX 0X62 >> +#define PREV_MBY 0X63 >> +#define ERROR_SKIP_MB_NUM 0X64 >> +#define ERROR_MB_STATUS 0X65 >> +#define L0_PIC0_STATUS 0X66 >> +#define TIMEOUT_COUNTER 0X67 >> +#define BUFFER_SIZE 0X68 >> +#define BUFFER_SIZE_HI 0X69 >> +#define CROPPING_LEFT_RIGHT 0X6A >> +#define CROPPING_TOP_BOTTOM 0X6B >> +/** >> + * sps_flags2: >> + * bit 3, bitstream_restriction_flag >> + * bit 2, pic_struct_present_flag >> + * bit 1, vcl_hrd_parameters_present_flag >> + * bit 0, nal_hrd_parameters_present_flag >> + */ >> +#define SPS_FLAGS2 0x6C >> +#define NUM_REORDER_FRAMES 0x6D >> +#define MAX_BUFFER_FRAME 0X6E >> + >> +#define NON_CONFORMING_STREAM 0X70 >> +#define RECOVERY_POINT 0X71 >> +#define POST_CANVAS 0X72 >> +#define POST_CANVAS_H 0X73 >> +#define SKIP_PIC_COUNT 0X74 >> +#define TARGET_NUM_SCALING_LIST 0X75 >> +#define FF_POST_ONE_FRAME 0X76 >> +#define PREVIOUS_BIT_CNT 0X77 >> +#define MB_NOT_SHIFT_COUNT 0X78 >> +#define PIC_STATUS 0X79 >> +#define FRAME_COUNTER 0X7A >> +#define NEW_SLICE_TYPE 0X7B >> +#define NEW_PICTURE_STRUCTURE 0X7C >> +#define NEW_FRAME_NUM 0X7D >> +#define NEW_IDR_PIC_ID 0X7E >> +#define IDR_PIC_ID 0X7F >> + >> +/* h264 LOCAL */ >> +#define NAL_UNIT_TYPE 0X80 >> +#define NAL_REF_IDC 0X81 >> +#define SLICE_TYPE 0X82 >> +#define LOG2_MAX_FRAME_NUM 0X83 >> +#define FRAME_MBS_ONLY_FLAG 0X84 >> +#define PIC_ORDER_CNT_TYPE 0X85 >> +#define LOG2_MAX_PIC_ORDER_CNT_LSB 0X86 >> +#define PIC_ORDER_PRESENT_FLAG 0X87 >> +#define REDUNDANT_PIC_CNT_PRESENT_FLAG 0X88 >> +#define PIC_INIT_QP_MINUS26 0X89 >> +#define DEBLOCKING_FILTER_CONTROL_PRESENT_FLAG 0X8A >> +#define NUM_SLICE_GROUPS_MINUS1 0X8B >> +#define MODE_8X8_FLAGS 0X8C >> +#define ENTROPY_CODING_MODE_FLAG 0X8D >> +#define SLICE_QUANT 0X8E >> +#define TOTAL_MB_HEIGHT 0X8F >> +#define PICTURE_STRUCTURE 0X90 >> +#define TOP_INTRA_TYPE 0X91 >> +#define RV_AI_STATUS 0X92 >> +#define AI_READ_START 0X93 >> +#define AI_WRITE_START 0X94 >> +#define AI_CUR_BUFFER 0X95 >> +#define AI_DMA_BUFFER 0X96 >> +#define AI_READ_OFFSET 0X97 >> +#define AI_WRITE_OFFSET 0X98 >> +#define AI_WRITE_OFFSET_SAVE 0X99 >> +#define RV_AI_BUFF_START 0X9A >> +#define I_PIC_MB_COUNT 0X9B >> +#define AI_WR_DCAC_DMA_CTRL 0X9C >> +#define SLICE_MB_COUNT 0X9D >> +#define PICTYPE 0X9E >> +#define SLICE_GROUP_MAP_TYPE 0X9F >> +#define MB_TYPE 0XA0 >> +#define MB_AFF_ADDED_DMA 0XA1 >> +#define PREVIOUS_MB_TYPE 0XA2 >> +#define WEIGHTED_PRED_FLAG 0XA3 >> +#define WEIGHTED_BIPRED_IDC 0XA4 >> +/* bit 3:2 - PICTURE_STRUCTURE >> + * bit 1 - MB_ADAPTIVE_FRAME_FIELD_FLAG >> + * bit 0 - FRAME_MBS_ONLY_FLAG >> + */ >> +#define MBFF_INFO 0XA5 >> +#define TOP_INTRA_TYPE_TOP 0XA6 >> +#define RV_AI_BUFF_INC 0xA7 >> +#define DEFAULT_MB_INFO_LO 0xA8 >> +/* 0 -- no need to read >> + * 1 -- need to wait Left >> + * 2 -- need to read Intra >> + * 3 -- need to read back MV >> + */ >> +#define NEED_READ_TOP_INFO 0xA9 >> +/* 0 -- idle >> + * 1 -- wait Left >> + * 2 -- reading top Intra >> + * 3 -- reading back MV >> + */ >> +#define READ_TOP_INFO_STATE 0xAA >> +#define DCAC_MBX 0xAB >> +#define TOP_MB_INFO_OFFSET 0xAC >> +#define TOP_MB_INFO_RD_IDX 0xAD >> +#define TOP_MB_INFO_WR_IDX 0xAE >> + >> +#define VLD_NO_WAIT   0 >> +#define VLD_WAIT_BUFFER 1 >> +#define VLD_WAIT_HOST   2 >> +#define VLD_WAIT_GAP 3 >> + >> +#define VLD_WAITING 0xAF >> + >> +#define MB_X_NUM 0xB0 >> +#define MB_HEIGHT 0xB2 >> +#define MBX 0xB3 >> +#define TOTAL_MBY 0xB4 >> +#define INTR_MSK_SAVE 0xB5 >> +#define NEED_DISABLE_PPE 0xB6 >> +#define IS_NEW_PICTURE 0XB7 >> +#define PREV_NAL_REF_IDC 0XB8 >> +#define PREV_NAL_UNIT_TYPE 0XB9 >> +#define FRAME_MB_COUNT 0XBA >> +#define SLICE_GROUP_UCODE 0XBB >> +#define SLICE_GROUP_CHANGE_RATE 0XBC >> +#define SLICE_GROUP_CHANGE_CYCLE_LEN 0XBD >> +#define DELAY_LENGTH 0XBE >> +#define PICTURE_STRUCT 0XBF >> +#define DCAC_PREVIOUS_MB_TYPE 0xC1 >> + >> +#define TIME_STAMP 0XC2 >> +#define H_TIME_STAMP 0XC3 >> +#define VPTS_MAP_ADDR 0XC4 >> +#define H_VPTS_MAP_ADDR 0XC5 >> +#define PIC_INSERT_FLAG 0XC7 >> +#define TIME_STAMP_START 0XC8 >> +#define TIME_STAMP_END 0XDF >> +#define OFFSET_FOR_NON_REF_PIC 0XE0 >> +#define OFFSET_FOR_TOP_TO_BOTTOM_FIELD 0XE2 >> +#define MAX_REFERENCE_FRAME_NUM 0XE4 >> +#define FRAME_NUM_GAP_ALLOWED 0XE5 >> +#define NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE 0XE6 >> +#define PROFILE_IDC_MMCO 0XE7 >> +#define LEVEL_IDC_MMCO 0XE8 >> +#define FRAME_SIZE_IN_MB 0XE9 >> +#define DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG 0XEA >> +#define PPS_NUM_REF_IDX_L0_ACTIVE_MINUS1 0XEB >> +#define PPS_NUM_REF_IDX_L1_ACTIVE_MINUS1 0XEC >> +#define CURRENT_SPS_ID 0XED >> +#define CURRENT_PPS_ID 0XEE >> +/* bit 0 - sequence parameter set may change >> + * bit 1 - picture parameter set may change >> + * bit 2 - new dpb just inited >> + * bit 3 - IDR picture not decoded yet >> + * bit 5:4 - 0: mb level code loaded 1: picture >> + * level code loaded 2: slice level code loaded >> + */ >> +#define DECODE_STATUS 0XEF >> +#define FIRST_MB_IN_SLICE 0XF0 >> +#define PREV_MB_WIDTH 0XF1 >> +#define PREV_FRAME_SIZE_IN_MB 0XF2 >> +/* bit 0 - aspect_ratio_info_present_flag >> + * bit 1 - timing_info_present_flag >> + * bit 2 - nal_hrd_parameters_present_flag >> + * bit 3 - vcl_hrd_parameters_present_flag >> + * bit 4 - pic_struct_present_flag >> + * bit 5 - bitstream_restriction_flag >> + */ >> +#define VUI_STATUS 0XF4 >> +#define ASPECT_RATIO_IDC 0XF5 >> +#define ASPECT_RATIO_SAR_WIDTH 0XF6 >> +#define ASPECT_RATIO_SAR_HEIGHT 0XF7 >> +#define NUM_UNITS_IN_TICK 0XF8 >> +#define TIME_SCALE 0XFA >> +#define CURRENT_PIC_INFO 0XFC >> +#define DPB_BUFFER_INFO 0XFD >> +#define REFERENCE_POOL_INFO 0XFE >> +#define REFERENCE_LIST_INFO 0XFF >> + >> +#define REORDER_CMD_MAX             66 >> + >> +/* config parameters to DDR lmem */ >> +#define GET_SPS_PROFILE_IDC(x)       (((x) & 0xff) << 8) >> +#define GET_SPS_LEVEL_IDC(x)         ((x) & 0xff) >> +#define GET_SPS_SEQ_PARAM_SET_ID(x)       (((x) & 0x1f) << 8) >> +#define GET_SPS_CHROMA_FORMAT_IDC(x)      ((x) << 8) >> +#define GET_SPS_NUM_REF_FRAMES(x)         ((x) & 0xff) >> +#define GET_SPS_GAPS_ALLOWED_FLAG(x)      ((x) << 8) >> +#define GET_SPS_LOG2_MAX_FRAME_NUM(x)     ((x) + 4) >> +#define GET_SPS_PIC_ORDER_CNT_LSB(x)      ((x) + 4) >> +#define GET_SPS_PIC_ORDER_TYPE(x)         (x) >> +#define GET_SPS_OFFSET_FOR_NONREF_PIC_HIGH(x)      (((x) & >> 0xffff0000) >> 16) >> +#define GET_SPS_OFFSET_FOR_NONREF_PIC_LOW(x)         ((x) & 0xffff) >> +#define GET_SPS_OFFSET_FOR_TOP_BOT_FIELD_HIGH(x)      (((x) & >> 0xffff0000) >> 16) >> +#define GET_SPS_OFFSET_FOR_TOP_BOT_FIELD_LOW(x)         ((x) & 0xffff) >> +#define GET_SPS_PIC_WIDTH_IN_MBS(x)       ((x) + 1) >> +#define GET_SPS_PIC_HEIGHT_IN_MBS(x)      ((x) + 1) >> +#define GET_SPS_DIRECT_8X8_FLAGS(x)       (((x) & 0x1) << 2) >> +#define GET_SPS_MB_ADAPTIVE_FRAME_FIELD_FLAGS(x)       (((x) & 0x1) >> << 1) >> +#define GET_SPS_FRAME_MBS_ONLY_FLAGS(x)   ((x) & 0x1) >> + >> +#define GET_PPS_PIC_PARAM_SET_ID(x)       ((x) & 0xff) >> +#define GET_PPS_SEQ_PARAM_SET_ID(x)       (((x) & 0x1f) << 8) >> +#define GET_PPS_ENTROPY_CODING_MODE_FLAG(x)  (((x) & 0x1) << 13) >> +#define GET_PPS_PIC_ORDER_PRESENT_FLAG(x)    (((x) & 0x1) << 14) >> +#define GET_PPS_NUM_IDX_REF_L0_MINUS1(x)       ((x) & 0x1f) >> +#define GET_PPS_NUM_IDX_REF_L1_MINUS1(x)       (((x) & 0x1f) << 5) >> +#define GET_PPS_WEIGHTED_PRED_FLAG(x)         (((x) & 0x1) << 10) >> +#define GET_PPS_WEIGHTED_BIPRED_IDC(x)        (((x) & 0x3) << 11) >> +#define GET_PPS_INIT_QS_MINUS26(x)           (((x) & 0xff) << 8) >> +#define GET_PPS_INIT_QP_MINUS26(x)           ((x) & 0xff) >> +#define GET_PPS_CHROMA_QP_INDEX_OFFSET(x)   ((x) & 0xff) >> +#define GET_PPS_DEBLOCK_FILTER_CTRL_PRESENT_FLAG(x)   (((x) & 0x1) >> << 8) >> +#define GET_PPS_CONSTRAIN_INTRA_PRED_FLAG(x)          (((x) & 0x1) >> << 9) >> +#define GET_PPS_REDUNDANT_PIC_CNT_PRESENT_FLAG(x)     (((x) & 0x1) >> << 10) >> +#define GET_PPS_SCALING_MATRIX_PRESENT_FLAG(x)        (((x) & 0x1) >> << 1) >> +#define GET_PPS_TRANSFORM_8X8_FLAG(x)                 ((x) & 0x1) >> +#define GET_PPS_GET_SECOND_CHROMA_QP_OFFSET(x)        (x) >> + >> +int aml_h264_init(void *priv); >> +void aml_h264_exit(void *priv); >> +int aml_h264_dec_run(void *priv); >> + >> +#endif >> diff --git a/drivers/media/platform/amlogic/vdec/reg_defines.h >> b/drivers/media/platform/amlogic/vdec/reg_defines.h >> new file mode 100644 >> index 000000000000..6b1900ecbedb >> --- /dev/null >> +++ b/drivers/media/platform/amlogic/vdec/reg_defines.h >> @@ -0,0 +1,175 @@ >> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ >> +/* >> + * Copyright (C) 2025 Amlogic, Inc. All rights reserved >> + */ >> + >> +#ifndef _REG_DEFINES_H_ >> +#define _REG_DEFINES_H_ >> + >> +#define VDEC_ASSIST_MMC_CTRL0        0x0001 >> +#define VDEC_ASSIST_MMC_CTRL1        0x0002 >> + >> +#define VDEC_ASSIST_CANVAS_BLK32     0x0005 >> + >> +#define VDEC_ASSIST_MBOX1_CLR_REG    0x0075 >> +#define VDEC_ASSIST_MBOX1_MASK       0x0076 >> + >> +#define MPSR                         0x0301 >> +#define MPC_P                        0x0306 >> +#define MPC_D                        0x0307 >> +#define MPC_E                        0x0308 >> +#define MPC_W                        0x0309 >> +#define CPSR                         0x0321 >> +#define IMEM_DMA_CTRL                0x0340 >> +#define IMEM_DMA_ADR                 0x0341 >> +#define IMEM_DMA_COUNT               0x0342 >> +#define WRRSP_IMEM                   0x0343 >> +#define LMEM_DMA_CTRL                0x0350 >> +#define WRRSP_LMEM                   0x0353 >> + >> +#define PSCALE_CTRL                  0x0911 >> +#define GCLK_EN                      0x0983 >> +#define MDEC_PIC_DC_CTRL             0x098e >> +#define MDEC_PIC_DC_MUX_CTRL         0x098d >> +#define ANC0_CANVAS_ADDR             0x0990 >> +#define ANC1_CANVAS_ADDR             0x0991 >> +#define ANC2_CANVAS_ADDR             0x0992 >> +#define ANC3_CANVAS_ADDR             0x0993 >> +#define ANC4_CANVAS_ADDR             0x0994 >> +#define ANC5_CANVAS_ADDR             0x0995 >> +#define ANC6_CANVAS_ADDR             0x0996 >> +#define ANC7_CANVAS_ADDR             0x0997 >> +#define ANC8_CANVAS_ADDR             0x0998 >> +#define ANC9_CANVAS_ADDR             0x0999 >> +#define ANC10_CANVAS_ADDR            0x099a >> +#define ANC11_CANVAS_ADDR            0x099b >> +#define ANC12_CANVAS_ADDR            0x099c >> +#define ANC13_CANVAS_ADDR            0x099d >> +#define ANC14_CANVAS_ADDR            0x099e >> +#define ANC15_CANVAS_ADDR            0x099f >> +#define ANC16_CANVAS_ADDR            0x09a0 >> +#define ANC17_CANVAS_ADDR            0x09a1 >> +#define ANC18_CANVAS_ADDR            0x09a2 >> +#define ANC19_CANVAS_ADDR            0x09a3 >> +#define ANC20_CANVAS_ADDR            0x09a4 >> +#define ANC21_CANVAS_ADDR            0x09a5 >> +#define ANC22_CANVAS_ADDR            0x09a6 >> +#define ANC23_CANVAS_ADDR            0x09a7 >> +#define ANC24_CANVAS_ADDR            0x09a8 >> +#define ANC25_CANVAS_ADDR            0x09a9 >> +#define ANC26_CANVAS_ADDR            0x09aa >> +#define ANC27_CANVAS_ADDR            0x09ab >> +#define ANC28_CANVAS_ADDR            0x09ac >> +#define ANC29_CANVAS_ADDR            0x09ad >> +#define ANC30_CANVAS_ADDR            0x09ae >> +#define ANC31_CANVAS_ADDR            0x09af >> +#define DBKR_CANVAS_ADDR             0x09b0 >> +#define DBKW_CANVAS_ADDR             0x09b1 >> +#define REC_CANVAS_ADDR              0x09b2 >> +#define CURR_CANVAS_CTRL             0x09b3 >> +#define MDEC_PIC_DC_THRESH           0x09b8 >> +#define AV_SCRATCH_0                 0x09c0 >> +#define AV_SCRATCH_1                 0x09c1 >> +#define AV_SCRATCH_2                 0x09c2 >> +#define AV_SCRATCH_3                 0x09c3 >> +#define AV_SCRATCH_4                 0x09c4 >> +#define AV_SCRATCH_5                 0x09c5 >> +#define AV_SCRATCH_6                 0x09c6 >> +#define AV_SCRATCH_7                 0x09c7 >> +#define AV_SCRATCH_8                 0x09c8 >> +#define AV_SCRATCH_9                 0x09c9 >> +#define AV_SCRATCH_A                 0x09ca >> +#define AV_SCRATCH_B                 0x09cb >> +#define AV_SCRATCH_C                 0x09cc >> +#define AV_SCRATCH_D                 0x09cd >> +#define AV_SCRATCH_E                 0x09ce >> +#define AV_SCRATCH_F                 0x09cf >> +#define AV_SCRATCH_G                 0x09d0 >> +#define AV_SCRATCH_H                 0x09d1 >> +#define AV_SCRATCH_I                 0x09d2 >> +#define AV_SCRATCH_J                 0x09d3 >> +#define AV_SCRATCH_K                 0x09d4 >> +#define AV_SCRATCH_L                 0x09d5 >> +#define AV_SCRATCH_M                 0x09d6 >> +#define AV_SCRATCH_N                 0x09d7 >> +#define WRRSP_VLD                    0x09da >> +#define MDEC_DOUBLEW_CFG0            0x09db >> +#define MDEC_DOUBLEW_CFG1            0x09dc >> +#define MDEC_DOUBLEW_CFG2            0x09dd >> +#define MDEC_DOUBLEW_CFG3            0x09de >> +#define MDEC_DOUBLEW_CFG4            0x09df >> +#define MDEC_DOUBLEW_CFG5            0x09e0 >> +#define MDEC_DOUBLEW_CFG6            0x09e1 >> +#define MDEC_DOUBLEW_CFG7            0x09e2 >> +#define MDEC_DOUBLEW_STATUS          0x09e3 >> +#define MDEC_EXTIF_CFG0              0x09e4 >> + >> +#define MDEC_EXTIF_CFG1              0x09e5 >> +#define MDEC_EXTIF_CFG2              0x09e6 >> + >> +#define POWER_CTL_VLD                0x0c08 >> +#define VLD_DECODE_CONTROL           0x0c18 >> + >> +#define PMV1_X                       0x0c20 >> +#define PMV1_Y                       0x0c21 >> +#define PMV2_X                       0x0c22 >> +#define PMV2_Y                       0x0c23 >> +#define PMV3_X                       0x0c24 >> +#define PMV3_Y                       0x0c25 >> +#define PMV4_X                       0x0c26 >> +#define PMV4_Y                       0x0c27 >> +#define M4_TABLE_SELECT              0x0c28 >> +#define M4_CONTROL_REG               0x0c29 >> +#define BLOCK_NUM                    0x0c2a >> +#define PATTERN_CODE                 0x0c2b >> +#define MB_INFO                      0x0c2c >> +#define VLD_DC_PRED                  0x0c2d >> +#define VLD_ERROR_MASK               0x0c2e >> +#define VLD_DC_PRED_C                0x0c2f >> +#define LAST_SLICE_MV_ADDR           0x0c30 >> +#define LAST_MVX                     0x0c31 >> +#define LAST_MVY                     0x0c32 >> + >> +#define MB_MOTION_MODE               0x0c07 >> +#define VIFF_BIT_CNT                 0x0c1a >> +#define M4_CONTROL_REG               0x0c29 >> +#define VLD_C38                      0x0c38 >> +#define VLD_C39                      0x0c39 >> +#define VLD_SHIFT_STATUS             0x0c3b >> +#define VLD_C3D                      0x0c3d >> +#define VLD_MEM_VIFIFO_START_PTR     0x0c40 >> +#define VLD_MEM_VIFIFO_CURR_PTR      0x0c41 >> +#define VLD_MEM_VIFIFO_END_PTR       0x0c42 >> +#define VLD_MEM_VIFIFO_BYTES_AVAIL   0x0c43 >> +#define VLD_MEM_VIFIFO_CONTROL       0x0c44 >> +#define VLD_MEM_VIFIFO_WP            0x0c45 >> +#define VLD_MEM_VIFIFO_RP            0x0c46 >> +#define VLD_MEM_VIFIFO_LEVEL         0x0c47 >> +#define VLD_MEM_VIFIFO_BUF_CNTL      0x0c48 >> + >> +#define VCOP_CTRL_REG                0x0e00 >> +#define RV_AI_MB_COUNT               0x0e0c >> +#define IQIDCT_CONTROL               0x0e0e >> +#define DCAC_DDR_BYTE64_CTL          0x0e1d >> + >> +#define VDEC2_IMEM_DMA_CTRL          0x2340 >> +#define VDEC2_IMEM_DMA_ADR           0x2341 >> +#define VDEC2_IMEM_DMA_COUNT         0x2342 >> + >> +#define DOS_SW_RESET0                0x3f00 >> +#define DOS_GCLK_EN0                 0x3f01 >> +#define DOS_GCLK_EN1                 0x3f09 >> +#define DOS_GCLK_EN3                 0x3f35 >> + >> +#define DOS_MEM_PD_VDEC              0x3f30 >> +#define DOS_MEM_PD_VDEC2             0x3f31 >> +#define DOS_MEM_PD_HCODEC            0x3f32 >> +/*add from M8M2*/ >> +#define DOS_MEM_PD_HEVC              0x3f33 >> + >> +#define DOS_SW_RESET3                0x3f34 >> +#define DOS_GCLK_EN3                 0x3f35 >> +#define DOS_HEVC_INT_EN              0x3f36 >> + >> +#endif >> + >> > Thanks, > Neil Best regards Zhentao