From patchwork Wed Jun 18 09:19:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Du, Bin" X-Patchwork-Id: 897814 Received: from NAM02-SN1-obe.outbound.protection.outlook.com (mail-sn1nam02on2041.outbound.protection.outlook.com [40.107.96.41]) (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 5F4E6280A5C; Wed, 18 Jun 2025 09:20:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.96.41 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238430; cv=fail; b=FoiCIAifQuGT3mFKyXhTSpz+Eno2rAmdXcXMB4/p+1ZbKxLKPRys7reECIuMb8hKYBKUkaHnp3gebNG8MMQiL00cP+bEThq8WLwg9x+FPqFleAdcZSJpc9vfaSQpZowbdOCjUaTc8xr+MD5Q6uMlbBnqcMa0X3VtlKd3mvaSQc0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238430; c=relaxed/simple; bh=jKBvG0D3TrwjDfwHpFOxI2jQHgz0fCw5u73jfKPHSM8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NEDguivAa7G+E2jM4ymSuEdXCa6YHgXDd89Zx09nFtQzDi0SGTFfqjU/xHwRJYwkD1WYQglS/gcrDFTLl1H/O6LYWV+cgjqo9mYSzRxrAMVrb6Y9RCXz7SuzQlUAxMiIMUJtxNSn2TDbo+FK1sprdWZPlV0WJRGkL2pLvsLTTfQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=rt1qhkp+; arc=fail smtp.client-ip=40.107.96.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="rt1qhkp+" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=fkgNTCool1cZ+dsXQM6+QxgEg5YxNn6RkKpkhPDHAXqsJ9/pKhvdRkEjLA+6sAsBkEs+Ud6Z0+IpxhZUWpzy8gpJ5DSl079+lmWDb6i44rmW5NoTZtzNTFJ7VNWS/eXBlIL2yTJxFZkU+9UtNUTofhXjOi6DfO5jj7Xoro20+cOvMTKr4MjQSUVZdAB9zfHCzwKLLBRVMISmFNCIPcrJGS2qAOfHCClIbSKGwmM1VGVfV29IlySvKhcC/W3b2Uk9klbzyR29xNivwnQELUfmhBMmeA2NSKjSBRJsHvI/NCKH/RgjCpTO7+yPqV9aHA8pH0L2F81KXXXClSbwzxENPQ== 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=wnv8yxUavBN3iKeHK6VVhPbAKr/Rc9N6tJKjuZ8+tU0=; b=BWCWrO94hWWk5342QDCEDoUTVK3jkG9kDgktoD21r7zv0a3apdCd8nnasowkJjIHNjdBQllB1xNEnS3FaHcMyGy9y1sr1Kw2D0fMdHdJ/Lm29M4Xf3FxpHvmCUB3AK2+/ZwpukTe2++XoEPKIwEDtHo3cJY8mco8wtMRBiIdPr/fbg7sVzecBBcfdoQfWMxnso5nhhN/E6TdxveN3InYmVairFBQvQlBuA4ZSOPLMInAFbVbxvFn3JokCZOs1g72TMWs82WKhJtr+Dlafx51S29IAWH8Su/pkS/iOYqXY2r+TdpHKkwTz8ucWKzhibRSJNAVsK9njbtqbIcx0cBwHQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=wnv8yxUavBN3iKeHK6VVhPbAKr/Rc9N6tJKjuZ8+tU0=; b=rt1qhkp+CMIZsl+d0DvFw9NMV+E3FNXKde62x+WdDI9OcrUW8sUDhQUY4PqHCRD/Xq/v3ZAZR7LkJPf7iBFeE4NOb0bHGBhl9INgLlazrscvRIguLgrsCiQ96V6jKDnbcDQI9wdzohg2MRZuB8iwv/zZxXH2ZdrXcz8Z9gjURkc= Received: from DS7PR03CA0127.namprd03.prod.outlook.com (2603:10b6:5:3b4::12) by MW4PR12MB6952.namprd12.prod.outlook.com (2603:10b6:303:207::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8835.26; Wed, 18 Jun 2025 09:20:22 +0000 Received: from CY4PEPF0000EE37.namprd05.prod.outlook.com (2603:10b6:5:3b4:cafe::a0) by DS7PR03CA0127.outlook.office365.com (2603:10b6:5:3b4::12) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8835.23 via Frontend Transport; Wed, 18 Jun 2025 09:20:22 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by CY4PEPF0000EE37.mail.protection.outlook.com (10.167.242.43) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8857.21 via Frontend Transport; Wed, 18 Jun 2025 09:20:22 +0000 Received: from 555e2b870847.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 18 Jun 2025 04:20:17 -0500 From: Bin Du To: , , , , , , , CC: , , , , , , , , "Bin Du" Subject: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Date: Wed, 18 Jun 2025 17:19:52 +0800 Message-ID: <20250618091959.68293-2-Bin.Du@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250618091959.68293-1-Bin.Du@amd.com> References: <20250618091959.68293-1-Bin.Du@amd.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CY4PEPF0000EE37:EE_|MW4PR12MB6952:EE_ X-MS-Office365-Filtering-Correlation-Id: d94814cb-49a0-43c8-ebed-08ddae4959fc X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|376014|1800799024|36860700013|82310400026; X-Microsoft-Antispam-Message-Info: eBL4ljxcY4AI5SSlCgB6H/egN+PK7RBSG3rK0fQ1drYSSp3/MUIzQEIf63QbDLdU/UpfRp9Or6uF3M497MKIx9Ut7RQRlEjSQ1QCdcbnxW7aaPUWapstaIKY9tNCbMcGGZoDN6xntR7usx5tF64UqoYL6hDUP00xovJYgQ0t//vBQSpQyXKNUpgAz+2A3C7UYhNopoZruSQJIcjss/C2nmMm9P6dL+QMISj57xBWUhsi2LveRUAQpapgggk3CqFqizM36hkCPkMxVpsHsELf9L+1B/2UW90Nfq8bLDDhRMNeFOKwACQBgwk3BV0CzRUYkNsBLUNHNwDxJ897l3H4Jn96xwmDiRaLiI2iPfOU0IqbaUp4I9871VwI4NhhgMU7T0l3objcgVNb+EbR8bpDF7zwrUd5QNFleRKJamvzaoHwb+Gk0MKiKz6nTHc02xgzl4+VAgy0t61+pE1cPm8U4MOax1d79lNu081Zjh7Pr+SM2MJxvZ78SPuDXtF7VX9Rfls+cwlN9K/QqGPktWuSpIc7Ej9rodD4t1l0DxnDGpqCrU7Dd6e8TK61lWfWGi7gAYGJ0xI+LBwIK+Q+3XpZUdfOx5ZtZN/7eb6dmDj104z6THOw9MADz0mziqmkQS28uCA3YqHZ99f+b6dKgmelhqy67nsQbLEGvO2k/1laf3G0chwfJwJHp+N/lpllVL9EhJaqyorTtFw4bjEbTSlFkDhdDEc3lOKJ20xtoW/58c3aepYlMkqQQiZmJbK6ivldhnRGNHlZ+S2AgUHo7IJ2xCIlhuBf4gfYhginOHd8BR/9WLUzXDazqnagx9NFHW5T1ck1/j7+EbmZ6gxi7YVTsMWvY29vqyWEZWlVTUTldB95claeF0LA9d4Hf8bpkAC8lE1evrktwTJHRUaUfvtxBCiAo5RvBWT2WlASqj4iY4n9QRpfF/7pvmQ5WOudviE+5SJavePegzdQuAyn4JnFZRQE3Vnjh8d7wF6952RhS7/SQdyevv+NhUnuLRcsNTK3dzqbw5nWB21cjVrL9/5H2hShWlD8067Qz9GVQZKO/Ntb+NpPhhO/zgzWm+JpPQIH9OEGGOWsdt6GUxoubVml6noauQGZwobpZSaZdKYgdN3WklpbV8eu37OjPHXSP3QX/N2IjzSCFVSlsoy7lJo6T6Nib9izRaBCc7J/0lHSZiUM2SGRZdbu3W7i9Rgh+nKo+sDuTwhCQl8qmTs6IaaZCr+TlflYJg0ZwWmP35RV95Y5i0GF5cdn/UjrGyR7RLPbDDcTUqG6PoCW8n0R7O1FHpJyaSzKyuyUvsEN+q2f8JO4+NvIfCxJwCu+bWc+go5jiiJ34rPP7N3O1cvL1c5hQgvq0dM6z9sUG0ct9a7jAFPILjHR1/tPQWYnYbvIVFNN7Fv2cnD8TmlcvtCDXZVVoxKzxYjSDaR+KRfIJFBOqb04ixyXyEUTfFHf1IdoaynlloebP7fnfqEI/oNDtLvw0lyu3w7yIRJmiqdNUiZBHIp4HrPDDseLfJchoKvn2iiL X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230040)(376014)(1800799024)(36860700013)(82310400026); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jun 2025 09:20:22.1192 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d94814cb-49a0-43c8-ebed-08ddae4959fc X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: CY4PEPF0000EE37.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR12MB6952 Amd isp4 capture is a v4l2 media device which implements media controller interface. It has one sub-device (amd ISP4 sub-device) endpoint which can be connected to a remote CSI2 TX endpoint. It supports only one physical interface for now. Also add ISP4 driver related entry info into the MAINAINERS file Signed-off-by: Bin Du Signed-off-by: Svetoslav Stoilov --- MAINTAINERS | 10 ++ drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/amd/Kconfig | 17 +++ drivers/media/platform/amd/Makefile | 5 + drivers/media/platform/amd/isp4/Makefile | 21 ++++ drivers/media/platform/amd/isp4/isp4.c | 139 +++++++++++++++++++++++ drivers/media/platform/amd/isp4/isp4.h | 35 ++++++ 8 files changed, 229 insertions(+) create mode 100644 drivers/media/platform/amd/Kconfig create mode 100644 drivers/media/platform/amd/Makefile create mode 100644 drivers/media/platform/amd/isp4/Makefile create mode 100644 drivers/media/platform/amd/isp4/isp4.c create mode 100644 drivers/media/platform/amd/isp4/isp4.h diff --git a/MAINTAINERS b/MAINTAINERS index 10893c91b1c1..15070afb14b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1107,6 +1107,16 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git F: drivers/iommu/amd/ F: include/linux/amd-iommu.h +AMD ISP4 DRIVER +M: Bin Du +M: Nirujogi Pratap +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media.git +F: drivers/media/platform/amd/Kconfig +F: drivers/media/platform/amd/Makefile +F: drivers/media/platform/amd/isp4/* + AMD KFD M: Felix Kuehling L: amd-gfx@lists.freedesktop.org diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 85d2627776b6..d525c2262a7d 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -89,5 +89,6 @@ source "drivers/media/platform/ti/Kconfig" source "drivers/media/platform/verisilicon/Kconfig" source "drivers/media/platform/via/Kconfig" source "drivers/media/platform/xilinx/Kconfig" +source "drivers/media/platform/amd/Kconfig" endif # MEDIA_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index ace4e34483dd..9f3d1693868d 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -32,6 +32,7 @@ obj-y += ti/ obj-y += verisilicon/ obj-y += via/ obj-y += xilinx/ +obj-y += amd/ # Please place here only ancillary drivers that aren't SoC-specific # Please keep it alphabetically sorted by Kconfig name diff --git a/drivers/media/platform/amd/Kconfig b/drivers/media/platform/amd/Kconfig new file mode 100644 index 000000000000..3b1dba0400a0 --- /dev/null +++ b/drivers/media/platform/amd/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: MIT + +config AMD_ISP4 + tristate "AMD ISP4 and camera driver" + default y + depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_CORE + select VIDEOBUF2_V4L2 + select VIDEOBUF2_MEMOPS + select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG + help + This is support for AMD ISP4 and camera subsystem driver. + Say Y here to enable the ISP4 and camera device for video capture. + To compile this driver as a module, choose M here. The module will + be called amd_capture. diff --git a/drivers/media/platform/amd/Makefile b/drivers/media/platform/amd/Makefile new file mode 100644 index 000000000000..76146efcd2bf --- /dev/null +++ b/drivers/media/platform/amd/Makefile @@ -0,0 +1,5 @@ +# Copyright 2024 Advanced Micro Devices, Inc. +# add isp block +ifneq ($(CONFIG_AMD_ISP4),) +obj-y += isp4/ +endif diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile new file mode 100644 index 000000000000..e9e84160517d --- /dev/null +++ b/drivers/media/platform/amd/isp4/Makefile @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2025 Advanced Micro Devices, Inc. + +obj-$(CONFIG_AMD_ISP4) += amd_capture.o +amd_capture-objs := isp4.o + +ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4 +ccflags-y += -I$(srctree)/include + +ifneq ($(call cc-option, -mpreferred-stack-boundary=4),) + cc_stack_align := -mpreferred-stack-boundary=4 +endif + +ccflags-y += $(cc_stack_align) +ccflags-y += -DCONFIG_COMPAT +ccflags-y += -Wunused-but-set-variable +ccflags-y += -Wmissing-include-dirs +ccflags-y += -Wunused-const-variable +ccflags-y += -Wmaybe-uninitialized +ccflags-y += -Wunused-value diff --git a/drivers/media/platform/amd/isp4/isp4.c b/drivers/media/platform/amd/isp4/isp4.c new file mode 100644 index 000000000000..d0be90c5ec3b --- /dev/null +++ b/drivers/media/platform/amd/isp4/isp4.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "isp4.h" + +#define VIDEO_BUF_NUM 5 + +#define ISP4_DRV_NAME "amd_isp_capture" + +/* interrupt num */ +static const u32 isp4_ringbuf_interrupt_num[] = { + 0, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9 */ + 1, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT10 */ + 3, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT11 */ + 4, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT12 */ +}; + +#define to_isp4_device(dev) \ + ((struct isp4_device *)container_of(dev, struct isp4_device, v4l2_dev)) + +static irqreturn_t isp4_irq_handler(int irq, void *arg) +{ + struct isp4_device *isp_dev = dev_get_drvdata((struct device *)arg); + + if (!isp_dev) + goto error_drv_data; + +error_drv_data: + return IRQ_HANDLED; +} + +/* + * amd capture module + */ +static int isp4_capture_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct isp4_device *isp_dev; + + int i, irq, ret; + + isp_dev = devm_kzalloc(&pdev->dev, sizeof(*isp_dev), GFP_KERNEL); + if (!isp_dev) + return -ENOMEM; + + isp_dev->pdev = pdev; + dev->init_name = ISP4_DRV_NAME; + + for (i = 0; i < ARRAY_SIZE(isp4_ringbuf_interrupt_num); i++) { + irq = platform_get_irq(pdev, isp4_ringbuf_interrupt_num[i]); + if (irq < 0) + return dev_err_probe(dev, -ENODEV, + "fail to get irq %d\n", + isp4_ringbuf_interrupt_num[i]); + ret = devm_request_irq(&pdev->dev, irq, isp4_irq_handler, 0, + "ISP_IRQ", &pdev->dev); + if (ret) + return dev_err_probe(dev, ret, "fail to req irq %d\n", + irq); + } + + isp_dev->pltf_data = pdev->dev.platform_data; + + dev_dbg(dev, "isp irq registration successful\n"); + + /* Link the media device within the v4l2_device */ + isp_dev->v4l2_dev.mdev = &isp_dev->mdev; + + /* Initialize media device */ + strscpy(isp_dev->mdev.model, "amd_isp41_mdev", + sizeof(isp_dev->mdev.model)); + snprintf(isp_dev->mdev.bus_info, sizeof(isp_dev->mdev.bus_info), + "platform:%s", ISP4_DRV_NAME); + isp_dev->mdev.dev = &pdev->dev; + media_device_init(&isp_dev->mdev); + + /* register v4l2 device */ + snprintf(isp_dev->v4l2_dev.name, sizeof(isp_dev->v4l2_dev.name), + "AMD-V4L2-ROOT"); + ret = v4l2_device_register(&pdev->dev, &isp_dev->v4l2_dev); + if (ret) + return dev_err_probe(dev, ret, + "fail register v4l2 device\n"); + + dev_dbg(dev, "AMD ISP v4l2 device registered\n"); + + ret = media_device_register(&isp_dev->mdev); + if (ret) { + dev_err(dev, "fail to register media device %d\n", ret); + goto err_unreg_v4l2; + } + + platform_set_drvdata(pdev, isp_dev); + + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + + return 0; + +err_unreg_v4l2: + v4l2_device_unregister(&isp_dev->v4l2_dev); + + return dev_err_probe(dev, ret, "isp probe fail\n"); +} + +static void isp4_capture_remove(struct platform_device *pdev) +{ + struct isp4_device *isp_dev = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + media_device_unregister(&isp_dev->mdev); + v4l2_device_unregister(&isp_dev->v4l2_dev); + dev_dbg(dev, "AMD ISP v4l2 device unregistered\n"); +} + +static struct platform_driver isp4_capture_drv = { + .probe = isp4_capture_probe, + .remove = isp4_capture_remove, + .driver = { + .name = ISP4_DRV_NAME, + .owner = THIS_MODULE, + } +}; + +module_platform_driver(isp4_capture_drv); + +MODULE_ALIAS("platform:" ISP4_DRV_NAME); +MODULE_IMPORT_NS("DMA_BUF"); + +MODULE_DESCRIPTION("AMD ISP4 Driver"); +MODULE_AUTHOR("Bin Du "); +MODULE_AUTHOR("Pratap Nirujogi "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/amd/isp4/isp4.h b/drivers/media/platform/amd/isp4/isp4.h new file mode 100644 index 000000000000..27a7362ce6f9 --- /dev/null +++ b/drivers/media/platform/amd/isp4/isp4.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#ifndef _ISP4_H_ +#define _ISP4_H_ + +#include +#include +#include +#include + +#define ISP4_GET_ISP_REG_BASE(isp4sd) (((isp4sd))->mmio) + +struct isp4_platform_data { + void *adev; + void *bo; + void *cpu_ptr; + u64 gpu_addr; + u32 size; + u32 asic_type; + resource_size_t base_rmmio_size; +}; + +struct isp4_device { + struct v4l2_device v4l2_dev; + struct media_device mdev; + + struct isp4_platform_data *pltf_data; + struct platform_device *pdev; + struct notifier_block i2c_nb; +}; + +#endif /* isp4.h */ From patchwork Wed Jun 18 09:19:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Du, Bin" X-Patchwork-Id: 897813 Received: from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11on2086.outbound.protection.outlook.com [40.107.223.86]) (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 2DF0C280A5C; Wed, 18 Jun 2025 09:20:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.223.86 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238439; cv=fail; b=Ix9MZ912/aLrs+Mas6zJfNYPOdG51B5682oTU8iiBmq71yolySKoBY1ZflPQhlCKt3LFEriEkXO+Mlp73xkuqdZwoccSV+LJ/KOetgUaTXFxK70R1ofuwJyL8g2r6RHfkxWZ5+76sIJUr8qZO+BnjiaUrre75lqqmr+qX3SGAGk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238439; c=relaxed/simple; bh=KWb1Aw6jJW8A55m5IhlLlzFxQbrTbIJqybpFw7uNlJA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=F6s43iVzk8/BfpxjQuYEPZchpD/FVJW7BV9jBdqjsE+2S6vQIs+re2lGiRzpnifMsSsi73Uyqa2fZVqLcVTgY1t95UjEE2vb1PIPD67jd33jKlqLoIEfpD3AXdcxo5PUQZ1uEV1VGVsuBdUX0ctxuXiA8Fxe+xHmnogt4ayzXU4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=Ylz6XcCl; arc=fail smtp.client-ip=40.107.223.86 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="Ylz6XcCl" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HexN4bAowUx3ti49jeSrGQoy+FBoVU9tlXHwX+GxtJ7kVGl0SGDbT9csCv940eBfjKx+Tp48DPzCTpFoA9GtkhfXNc2xj8S/K3eRzLvoCb+X6gWg+kyEDIDB4FcH6yckC+6zJ0lS41DeHK9RA0wC/K8yF23ix7rEu11ycb16j0xrFc9nzvahKxrFO7YxJGOdEd3g6Wm1+HFsmr8AIHXj2NhSPRAdILSNM4h7wyAf2Rqu3DE2ZPfWwUpFJvrFqy3DIxqTgwAvZ+Q+TuFKz0VcWbfh4HEhPsv5ZNxjb/XaVjFfbWF7SNxPM5Ay6NU2F9O+zvHh5+ECpkLGsHIPuahCVQ== 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=/WLU6lMCXUnEtfkCHMhJzt8XTH5tdJrt4B60IkZ3Pns=; b=LWkSDESiJnJfaFtZC3VZ5P5RtfYuoeSkVd/QeCAKWWe1MFUBv732Mqwj2z2OHj7JwWmMCU6f8rR+1r0iRK9ObC1LuzBwpHfGErB5uuAKDqu0YdXtuwsiM3enAs8VDlBV2GKC4SCWv3pCrhUaCKUwi1G53nfmtfYKsaunvBywtUXilkLCq9fFV1s02WHDsnWaPDv2WisNUsWQ8iB/mbNLSZJ7/GHxLUAb2MSrdvAWquK58T/yeBDHSJW4MTuKDTcJHVm4h/6MnmiFGzKOh/Jp/gmSdGoNX6KYp0efw32Hw0N0tNIjq8neULVcdzf26MmwAKSRySrQSBXj2LkzO3pdYw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=/WLU6lMCXUnEtfkCHMhJzt8XTH5tdJrt4B60IkZ3Pns=; b=Ylz6XcClCYHe9qMe2H9Czy39p0JxwtsSlVusdQ6VfFW6hs3fu8BTscxuOJrdp+StMzoJEKc9xxHwhPivKq0Z7LH6rvMPJX4IOj+FcUdAjEDNc1fSXl9/2ThBiq+xdotcHN9bN1OqK1X73uQ2+XHIMn8fzm8B/w9X8E4JNDLWrbE= Received: from DS7PR05CA0071.namprd05.prod.outlook.com (2603:10b6:8:57::14) by CH3PR12MB8511.namprd12.prod.outlook.com (2603:10b6:610:15c::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8835.29; Wed, 18 Jun 2025 09:20:30 +0000 Received: from CY4PEPF0000EE34.namprd05.prod.outlook.com (2603:10b6:8:57:cafe::b5) by DS7PR05CA0071.outlook.office365.com (2603:10b6:8:57::14) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8857.20 via Frontend Transport; Wed, 18 Jun 2025 09:20:30 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by CY4PEPF0000EE34.mail.protection.outlook.com (10.167.242.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8857.21 via Frontend Transport; Wed, 18 Jun 2025 09:20:30 +0000 Received: from 555e2b870847.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 18 Jun 2025 04:20:25 -0500 From: Bin Du To: , , , , , , , CC: , , , , , , , , "Bin Du" Subject: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy Date: Wed, 18 Jun 2025 17:19:54 +0800 Message-ID: <20250618091959.68293-4-Bin.Du@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250618091959.68293-1-Bin.Du@amd.com> References: <20250618091959.68293-1-Bin.Du@amd.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CY4PEPF0000EE34:EE_|CH3PR12MB8511:EE_ X-MS-Office365-Filtering-Correlation-Id: 498869af-6417-498e-8d17-08ddae495ecc X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|36860700013|82310400026|1800799024|376014; X-Microsoft-Antispam-Message-Info: RwZghwZKNj+uqfLR4wAvzTU/6RufTdvvlURYy3Jq/bYasTjhWdYGZyJ2Xufd7E1RoKzoX+C9yilFkyUIeMGCP/V86qpHvxyIdGCxr4WHuzYmKUf6l4/oTKDRfrytAws/VLmJYxaCsSgFBff3VPsOW63HyED6was1tMq3QqsXe5wz86+iB7UOaBGbITs93SBqufYqwzVYKqlvFm58Ooeja8AujlEqgl9YvnEmy6HDsWMDOCg0tzEdD3KfOXC3qMNHtkgbrchdvcaZ8FaDW/kqL7F5vUI3xgi0wbELovaeAycE37X0d20cGyeK1gRD1J0gN93EUg11bYzNNxlIy7qe2nh/dV6Lmzq2b22708T3RQWX+nNa/PDoAsnls7NoSDLrjRoqbtEwebW3WzcEO6IXFoNe7ZzO0HzIGEKeRYrWfqJYaGOlnwh6uF60j/xPmb5Z4gH9KMVPnPNLMaI5n83rqhuN0qAn1TA6m/pihAe193Iq2inAW/pvYgnfHnGs8WPe1sBIlDAZHKs37zEzy6pDR5bFpubCi9LF4EX9eHaq65a3G9l4CWgavhnXpO/BIeoAoVUgrt32ycB5uQvFM6Zw8Pi2L7ipepypDF8VBhZB8qwc0SWLYo+sCR6+RV6zabd1H4WzxftvawuPdg0tkQNZ2+FMPvsanvueEXubFZyqtClZTu/3xOwd+F+VykaLUptJ7edS+wDD/RWcbmrfRfzruKOBtgNRN1rBL7a9KawuE32N8zTcA8gLTS5tKa2mWRjwejZXB49hYGIuDcLs4xHcRoIn3120zljbajMSK6S8FRSr91CM6c7WPy+3dUeD09rwDNR0GUdl3c3xOshJCDpN1cymju+T/I/cABmDBTZH8wJnZc6i0zESKYGDchAMGOhalV+kLlogTFGL0PGo7eUf7dC60LkN5hUpA36PypPNt9Y6W8jKpTOuTDeSE5olZo2UknW+Em1sjtpznhowxIHLU03Qe+bWCrK1ElBaErvrTZQXuNPSMTViyAWNkUBs6qMWx54NlRcFju520bZ8obt0mRqV4W2SZhVQ6POtJBIUIqKMBzTQRrHPFxCBkGt6h9seI2QWOSHQYS7wT1g+uLwX+4hVrCLqNDw9ExyRp7LWVsKB9kfbGfGoHt86Tb2nXjDHa67wlaCLVX1Tcl7kRnR7rF07v4ocrHYXvZVCYqj2BuPmdeNL6J3sdBcX2m6kmUFWPy2GCSDfuV8L+InQ0ta0zWCBD4R1w2E1d6L2Yh8EyoKJg4n4L9apsRJYfoXtNi/DiJwBme6BxPr9Jm9ncj6JAvCyqZuESllrbU69yfutH54EWr5tzPFqDI/mD69LKGXpYNg9soSP1T8ZfAZMJhFsumLyAUau7+WV9vEiqad8gG3upz96v0yLtn7tHJpi6iVk3GtaEO09EuUyh0+Iygbdzn22EqWdqy8ckupIRW8W8VA4HxnUNGUkn0lBI/dq/BU/9HNfiywUz9Lrdzz2mvWkOeb8ns+WX50eZsoNnsJuuPWN6rOn/9X3rv7vWrTofu95 X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230040)(36860700013)(82310400026)(1800799024)(376014); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jun 2025 09:20:30.1897 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 498869af-6417-498e-8d17-08ddae495ecc X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: CY4PEPF0000EE34.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH3PR12MB8511 The helper functions is for configuring, starting and stop the MIPI PHY. All configurations related to MIPI PHY configuration and calibration parameters are encapsulated in two helper functions: start and stop mipi phy. Signed-off-by: Bin Du Signed-off-by: Svetoslav Stoilov --- drivers/media/platform/amd/isp4/Makefile | 1 + drivers/media/platform/amd/isp4/isp4_phy.c | 1547 ++++++++++++++++++++ drivers/media/platform/amd/isp4/isp4_phy.h | 14 + 3 files changed, 1562 insertions(+) create mode 100644 drivers/media/platform/amd/isp4/isp4_phy.c create mode 100644 drivers/media/platform/amd/isp4/isp4_phy.h diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile index 8ca1c4dfe246..0e36201fbb30 100644 --- a/drivers/media/platform/amd/isp4/Makefile +++ b/drivers/media/platform/amd/isp4/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_AMD_ISP4) += amd_capture.o amd_capture-objs := isp4.o \ + isp4_phy.o \ isp4_hw.o \ ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4 diff --git a/drivers/media/platform/amd/isp4/isp4_phy.c b/drivers/media/platform/amd/isp4/isp4_phy.c new file mode 100644 index 000000000000..8d31a21074bb --- /dev/null +++ b/drivers/media/platform/amd/isp4/isp4_phy.c @@ -0,0 +1,1547 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#include +#include + +#include "isp4_hw.h" +#include "isp4_hw_reg.h" +#include "isp4_phy.h" + +#define ISP_MIPI_DPHY 0 +#define T_DCO 5 /* nominal: 200MHz */ +#define TMIN_RX 4 +#define TIMEBASE 5 /* 5us */ + +#define MIN_T_HS_SETTLE_NS 95 +#define MAX_T_HS_SETTLE_NS 130 +#define MIN_T_HS_SETTLE_UI 4 +#define MAX_T_HS_SETTLE_UI 6 + +#define PPI_STARTUP_RW_COMMON_DPHY_2 0x0C02 +#define PPI_STARTUP_RW_COMMON_DPHY_6 0x0C06 +#define PPI_STARTUP_RW_COMMON_DPHY_7 0x0C07 +#define PPI_STARTUP_RW_COMMON_DPHY_8 0x0C08 +#define PPI_STARTUP_RW_COMMON_DPHY_10 0x0C10 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2 0x1CF2 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0 0x1CF0 +#define PPI_STARTUP_RW_COMMON_STARTUP_1_1 0x0C11 +#define PPI_CALIBCTRL_RW_COMMON_BG_0 0x0C26 +#define PPI_RW_LPDCOCAL_NREF 0x0E02 +#define PPI_RW_LPDCOCAL_NREF_RANGE 0x0E03 +#define PPI_RW_LPDCOCAL_TWAIT_CONFIG 0x0E05 +#define PPI_RW_LPDCOCAL_VT_CONFIG 0x0E06 +#define PPI_RW_LPDCOCAL_COARSE_CFG 0x0E08 +#define PPI_RW_COMMON_CFG 0x0E36 +#define PPI_RW_TERMCAL_CFG_0 0x0E40 +#define PPI_RW_OFFSETCAL_CFG_0 0x0E50 +#define PPI_RW_LPDCOCAL_TIMEBASE 0x0E01 +#define CORE_AFE_CTRL_2_0 0x1C20 +#define CORE_AFE_CTRL_2_1 0x1C21 +#define CORE_AFE_CTRL_2_3 0x1C23 +#define CORE_AFE_CTRL_2_5 0x1C25 +#define CORE_AFE_CTRL_2_6 0x1C26 +#define CORE_AFE_CTRL_2_7 0x1C27 +#define CORE_DIG_COMMON_RW_DESKEW_FINE_MEM 0x1FF0 +#define CORE_DIG_DLANE_CLK_RW_CFG_0 0x3800 +#define CORE_DIG_DLANE_0_RW_CFG_0 0x3000 +#define CORE_DIG_DLANE_1_RW_CFG_0 0x3200 +#define CORE_DIG_DLANE_2_RW_CFG_0 0x3400 +#define CORE_DIG_DLANE_3_RW_CFG_0 0x3600 +#define CORE_AFE_LANE0_CTRL_2_9 0x1029 +#define CORE_AFE_LANE1_CTRL_2_9 0x1229 +#define CORE_AFE_LANE2_CTRL_2_9 0x1429 +#define CORE_AFE_LANE3_CTRL_2_9 0x1629 +#define CORE_AFE_LANE4_CTRL_2_9 0x1829 +#define CORE_DIG_RW_COMMON_6 0x1C46 +#define CORE_DIG_RW_COMMON_7 0x1C47 +#define PPI_RW_DDLCAL_CFG_0 0x0E20 +#define PPI_RW_DDLCAL_CFG_1 0x0E21 +#define PPI_RW_DDLCAL_CFG_2 0x0E22 +#define PPI_RW_DDLCAL_CFG_3 0x0E23 +#define PPI_RW_DDLCAL_CFG_4 0x0E24 +#define PPI_RW_DDLCAL_CFG_5 0x0E25 +#define PPI_RW_DDLCAL_CFG_6 0x0E26 +#define PPI_RW_DDLCAL_CFG_7 0x0E27 +#define CORE_AFE_LANE0_CTRL_2_8 0x1028 +#define CORE_AFE_LANE1_CTRL_2_8 0x1228 +#define CORE_AFE_LANE2_CTRL_2_8 0x1428 +#define CORE_AFE_LANE3_CTRL_2_8 0x1628 +#define CORE_AFE_LANE4_CTRL_2_8 0x1828 +#define CORE_DIG_DLANE_0_RW_LP_0 0x3040 +#define CORE_DIG_DLANE_1_RW_LP_0 0x3240 +#define CORE_DIG_DLANE_2_RW_LP_0 0x3440 +#define CORE_DIG_DLANE_3_RW_LP_0 0x3640 +#define CORE_AFE_LANE0_CTRL_2_2 0x1022 +#define CORE_AFE_LANE1_CTRL_2_2 0x1222 +#define CORE_AFE_LANE2_CTRL_2_2 0x1422 +#define CORE_AFE_LANE3_CTRL_2_2 0x1622 +#define CORE_AFE_LANE4_CTRL_2_2 0x1822 +#define CORE_AFE_LANE0_CTRL_2_12 0x102C +#define CORE_AFE_LANE1_CTRL_2_12 0x122C +#define CORE_AFE_LANE2_CTRL_2_12 0x142C +#define CORE_AFE_LANE3_CTRL_2_12 0x162C +#define CORE_AFE_LANE4_CTRL_2_12 0x182C +#define CORE_AFE_LANE0_CTRL_2_13 0x102D +#define CORE_AFE_LANE1_CTRL_2_13 0x122D +#define CORE_AFE_LANE2_CTRL_2_13 0x142D +#define CORE_AFE_LANE3_CTRL_2_13 0x162D +#define CORE_AFE_LANE4_CTRL_2_13 0x182D +#define CORE_DIG_DLANE_CLK_RW_HS_RX_0 0x3880 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_7 0x3887 +#define CORE_DIG_DLANE_0_RW_HS_RX_0 0x3080 +#define CORE_DIG_DLANE_1_RW_HS_RX_0 0x3280 +#define CORE_DIG_DLANE_2_RW_HS_RX_0 0x3480 +#define CORE_DIG_DLANE_3_RW_HS_RX_0 0x3680 +#define CORE_DIG_DLANE_0_RW_CFG_1 0x3001 +#define CORE_DIG_DLANE_1_RW_CFG_1 0x3201 +#define CORE_DIG_DLANE_2_RW_CFG_1 0x3401 +#define CORE_DIG_DLANE_3_RW_CFG_1 0x3601 +#define CORE_DIG_DLANE_0_RW_HS_RX_2 0x3082 +#define CORE_DIG_DLANE_1_RW_HS_RX_2 0x3282 +#define CORE_DIG_DLANE_2_RW_HS_RX_2 0x3482 +#define CORE_DIG_DLANE_3_RW_HS_RX_2 0x3682 +#define CORE_DIG_DLANE_0_RW_LP_2 0x3042 +#define CORE_DIG_DLANE_1_RW_LP_2 0x3242 +#define CORE_DIG_DLANE_2_RW_LP_2 0x3442 +#define CORE_DIG_DLANE_3_RW_LP_2 0x3642 +#define CORE_DIG_DLANE_CLK_RW_LP_0 0x3840 +#define CORE_DIG_DLANE_CLK_RW_LP_2 0x3842 +#define CORE_DIG_DLANE_0_RW_HS_RX_1 0x3081 +#define CORE_DIG_DLANE_1_RW_HS_RX_1 0x3281 +#define CORE_DIG_DLANE_2_RW_HS_RX_1 0x3481 +#define CORE_DIG_DLANE_3_RW_HS_RX_1 0x3681 +#define CORE_DIG_DLANE_0_RW_HS_RX_3 0x3083 +#define CORE_DIG_DLANE_1_RW_HS_RX_3 0x3283 +#define CORE_DIG_DLANE_2_RW_HS_RX_3 0x3483 +#define CORE_DIG_DLANE_3_RW_HS_RX_3 0x3683 +#define CORE_DIG_DLANE_0_RW_HS_RX_4 0x3084 +#define CORE_DIG_DLANE_1_RW_HS_RX_4 0x3284 +#define CORE_DIG_DLANE_2_RW_HS_RX_4 0x3484 +#define CORE_DIG_DLANE_3_RW_HS_RX_4 0x3684 +#define CORE_DIG_DLANE_0_RW_HS_RX_5 0x3085 +#define CORE_DIG_DLANE_1_RW_HS_RX_5 0x3285 +#define CORE_DIG_DLANE_2_RW_HS_RX_5 0x3485 +#define CORE_DIG_DLANE_3_RW_HS_RX_5 0x3685 +#define CORE_DIG_DLANE_0_RW_HS_RX_6 0x3086 +#define CORE_DIG_DLANE_1_RW_HS_RX_6 0x3286 +#define CORE_DIG_DLANE_2_RW_HS_RX_6 0x3486 +#define CORE_DIG_DLANE_3_RW_HS_RX_6 0x3686 +#define CORE_DIG_DLANE_0_RW_HS_RX_7 0x3087 +#define CORE_DIG_DLANE_1_RW_HS_RX_7 0x3287 +#define CORE_DIG_DLANE_2_RW_HS_RX_7 0x3487 +#define CORE_DIG_DLANE_3_RW_HS_RX_7 0x3687 +#define CORE_DIG_DLANE_0_RW_HS_RX_9 0x3089 +#define CORE_DIG_DLANE_1_RW_HS_RX_9 0x3289 +#define CORE_DIG_DLANE_2_RW_HS_RX_9 0x3489 +#define CORE_DIG_DLANE_3_RW_HS_RX_9 0x3689 +#define PPI_R_TERMCAL_DEBUG_0 0x0E41 + +#define PPI_STARTUP_RW_COMMON_DPHY_2_RCAL_ADDR_MASK 0x00FF +#define PPI_STARTUP_RW_COMMON_DPHY_10_PHY_READY_ADDR_MASK 0x00FF +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2_GLOBAL_ULPS_OVR_VAL_MASK 0x2000 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2_GLOBAL_ULPS_OVR_EN_MASK 0x1000 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0_CB_LP_DCO_EN_DLY_MASK 0x00FC +#define PPI_STARTUP_RW_COMMON_STARTUP_1_1_PHY_READY_DLY_MASK 0x0FFF +#define PPI_STARTUP_RW_COMMON_DPHY_6_LP_DCO_CAL_ADDR_MASK 0x00FF +#define PPI_CALIBCTRL_RW_COMMON_BG_0_BG_MAX_COUNTER_MASK 0x01FF +#define PPI_RW_LPDCOCAL_NREF_LPDCOCAL_NREF_MASK 0x07FF +#define PPI_RW_LPDCOCAL_NREF_RANGE_LPDCOCAL_NREF_RANGE_MASK 0x001F +#define PPI_RW_LPDCOCAL_TWAIT_CONFIG_LPDCOCAL_TWAIT_PON_MASK 0xFE00 +#define PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_VT_TRACKING_EN_MASK 0x0001 +#define PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_USE_IDEAL_NREF_MASK 0x0002 +#define PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_VT_NREF_RANGE_MASK 0x007C +#define PPI_RW_LPDCOCAL_COARSE_CFG_NCOARSE_START_MASK 0x0003 +#define PPI_RW_COMMON_CFG_CFG_CLK_DIV_FACTOR_MASK 0x0003 +#define PPI_RW_TERMCAL_CFG_0_TERMCAL_TIMER_MASK 0x007F +#define PPI_RW_OFFSETCAL_CFG_0_OFFSETCAL_WAIT_THRESH_MASK 0x001F +#define PPI_RW_LPDCOCAL_TIMEBASE_LPDCOCAL_TIMEBASE_MASK 0x03FF +#define PPI_RW_LPDCOCAL_TWAIT_CONFIG_LPDCOCAL_TWAIT_COARSE_MASK 0x01FF +#define PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_TWAIT_FINE_MASK 0xFF80 +#define CORE_AFE_CTRL_2_0_OA_CB_HSTX_VCOMM_REG_PON_OVR_VAL_MASK 0x0400 +#define CORE_AFE_CTRL_2_1_OA_CB_HSTX_VCOMM_REG_PON_OVR_EN_MASK 0x0400 +#define CORE_AFE_CTRL_2_1_OA_CB_HSTXLB_DCO_CLK0_EN_OVR_VAL_MASK 0x8000 +#define CORE_AFE_CTRL_2_3_OA_CB_HSTXLB_DCO_CLK0_EN_OVR_EN_MASK 0x0100 +#define CORE_AFE_CTRL_2_0_OA_CB_HSTXLB_DCO_CLK90_EN_OVR_VAL_MASK 0x8000 +#define CORE_AFE_CTRL_2_3_OA_CB_HSTXLB_DCO_CLK90_EN_OVR_EN_MASK 0x0200 +#define CORE_AFE_CTRL_2_6_OA_CB_HSTXLB_DCO_EN_OVR_EN_MASK 0x2000 +#define CORE_AFE_CTRL_2_7_OA_CB_HSTXLB_DCO_EN_OVR_VAL_MASK 0x0200 +#define CORE_AFE_CTRL_2_6_OA_CB_HSTXLB_DCO_PON_OVR_EN_MASK 0x1000 +#define CORE_AFE_CTRL_2_7_OA_CB_HSTXLB_DCO_PON_OVR_VAL_MASK 0x0100 +#define CORE_AFE_CTRL_2_6_OA_CB_HSTXLB_DCO_TUNE_CLKDIG_EN_OVR_EN_MASK 0x4000 +#define CORE_AFE_CTRL_2_7_OA_CB_HSTXLB_DCO_TUNE_CLKDIG_EN_OVR_VAL_MASK 0x0400 +#define CORE_AFE_CTRL_2_5_OA_CB_SEL_45OHM_50OHM_MASK 0x0100 +#define CORE_DIG_DLANE_CLK_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK 0x0001 +#define CORE_DIG_DLANE_0_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK 0x0001 +#define CORE_DIG_DLANE_1_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK 0x0001 +#define CORE_DIG_DLANE_2_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK 0x0001 +#define CORE_DIG_DLANE_3_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK 0x0001 +#define CORE_DIG_DLANE_0_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK 0x0002 +#define CORE_DIG_DLANE_1_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK 0x0002 +#define CORE_DIG_DLANE_2_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK 0x0002 +#define CORE_DIG_DLANE_3_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK 0x0002 +#define CORE_AFE_LANE0_CTRL_2_9_OA_LANE0_HSRX_SEL_GATED_POLARITY_MASK 0x0100 +#define CORE_AFE_LANE1_CTRL_2_9_OA_LANE1_HSRX_SEL_GATED_POLARITY_MASK 0x0100 +#define CORE_AFE_LANE2_CTRL_2_9_OA_LANE2_HSRX_SEL_GATED_POLARITY_MASK 0x0100 +#define CORE_AFE_LANE3_CTRL_2_9_OA_LANE3_HSRX_SEL_GATED_POLARITY_MASK 0x0100 +#define CORE_AFE_LANE4_CTRL_2_9_OA_LANE4_HSRX_SEL_GATED_POLARITY_MASK 0x0100 +#define CORE_DIG_RW_COMMON_7_LANE0_HSRX_WORD_CLK_SEL_GATING_REG_MASK 0x0003 +#define CORE_DIG_RW_COMMON_7_LANE1_HSRX_WORD_CLK_SEL_GATING_REG_MASK 0x000C +#define CORE_DIG_RW_COMMON_7_LANE2_HSRX_WORD_CLK_SEL_GATING_REG_MASK 0x0030 +#define CORE_DIG_RW_COMMON_7_LANE3_HSRX_WORD_CLK_SEL_GATING_REG_MASK 0x00C0 +#define CORE_DIG_RW_COMMON_7_LANE4_HSRX_WORD_CLK_SEL_GATING_REG_MASK 0x0300 +#define PPI_STARTUP_RW_COMMON_DPHY_8_CPHY_DDL_CAL_ADDR_MASK 0x00FF +#define PPI_STARTUP_RW_COMMON_DPHY_7_DPHY_DDL_CAL_ADDR_MASK 0x00FF +#define PPI_RW_DDLCAL_CFG_0_DDLCAL_TIMEBASE_TARGET_MASK 0x03FF +#define PPI_RW_DDLCAL_CFG_7_DDLCAL_DECR_WAIT_MASK 0x1F80 +#define PPI_RW_DDLCAL_CFG_1_DDLCAL_DISABLE_TIME_MASK 0xFF00 +#define PPI_RW_DDLCAL_CFG_2_DDLCAL_WAIT_MASK 0xF000 +#define PPI_RW_DDLCAL_CFG_2_DDLCAL_TUNE_MODE_MASK 0x0C00 +#define PPI_RW_DDLCAL_CFG_2_DDLCAL_DDL_DLL_MASK 0x0100 +#define PPI_RW_DDLCAL_CFG_2_DDLCAL_ENABLE_WAIT_MASK 0x00FF +#define PPI_RW_DDLCAL_CFG_2_DDLCAL_UPDATE_SETTINGS_MASK 0x0200 +#define PPI_RW_DDLCAL_CFG_4_DDLCAL_STUCK_THRESH_MASK 0x03FF +#define PPI_RW_DDLCAL_CFG_6_DDLCAL_MAX_DIFF_MASK 0x03FF +#define PPI_RW_DDLCAL_CFG_7_DDLCAL_START_DELAY_MASK 0x007F +#define PPI_RW_DDLCAL_CFG_3_DDLCAL_COUNTER_REF_MASK 0x03FF +#define PPI_RW_DDLCAL_CFG_1_DDLCAL_MAX_PHASE_MASK 0x00FF +#define PPI_RW_DDLCAL_CFG_5_DDLCAL_DLL_FBK_MASK 0x03F0 +#define PPI_RW_DDLCAL_CFG_5_DDLCAL_DDL_COARSE_BANK_MASK 0x000F +#define CORE_AFE_LANE0_CTRL_2_8_OA_LANE0_HSRX_CDPHY_SEL_FAST_MASK 0x1000 +#define CORE_AFE_LANE1_CTRL_2_8_OA_LANE1_HSRX_CDPHY_SEL_FAST_MASK 0x1000 +#define CORE_AFE_LANE2_CTRL_2_8_OA_LANE2_HSRX_CDPHY_SEL_FAST_MASK 0x1000 +#define CORE_AFE_LANE3_CTRL_2_8_OA_LANE3_HSRX_CDPHY_SEL_FAST_MASK 0x1000 +#define CORE_AFE_LANE4_CTRL_2_8_OA_LANE4_HSRX_CDPHY_SEL_FAST_MASK 0x1000 +#define CORE_DIG_DLANE_0_RW_LP_0_LP_0_TTAGO_REG_MASK 0x0F00 +#define CORE_DIG_DLANE_1_RW_LP_0_LP_0_TTAGO_REG_MASK 0x0F00 +#define CORE_DIG_DLANE_2_RW_LP_0_LP_0_TTAGO_REG_MASK 0x0F00 +#define CORE_DIG_DLANE_3_RW_LP_0_LP_0_TTAGO_REG_MASK 0x0F00 +#define CORE_AFE_LANE0_CTRL_2_2_OA_LANE0_SEL_LANE_CFG_MASK 0x0001 +#define CORE_AFE_LANE1_CTRL_2_2_OA_LANE1_SEL_LANE_CFG_MASK 0x0001 +#define CORE_AFE_LANE2_CTRL_2_2_OA_LANE2_SEL_LANE_CFG_MASK 0x0001 +#define CORE_AFE_LANE3_CTRL_2_2_OA_LANE3_SEL_LANE_CFG_MASK 0x0001 +#define CORE_AFE_LANE4_CTRL_2_2_OA_LANE4_SEL_LANE_CFG_MASK 0x0001 +#define CORE_DIG_RW_COMMON_6_DESERIALIZER_EN_DEASS_COUNT_THRESH_D_MASK 0x0038 +#define CORE_DIG_RW_COMMON_6_DESERIALIZER_DIV_EN_DELAY_THRESH_D_MASK 0x0007 +#define CORE_AFE_LANE0_CTRL_2_12_OA_LANE0_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK 0x0002 +#define CORE_AFE_LANE1_CTRL_2_12_OA_LANE1_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK 0x0002 +#define CORE_AFE_LANE2_CTRL_2_12_OA_LANE2_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK 0x0002 +#define CORE_AFE_LANE3_CTRL_2_12_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK 0x0002 +#define CORE_AFE_LANE4_CTRL_2_12_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK 0x0002 +#define CORE_AFE_LANE0_CTRL_2_13_OA_LANE0_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK 0x0002 +#define CORE_AFE_LANE1_CTRL_2_13_OA_LANE1_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK 0x0002 +#define CORE_AFE_LANE2_CTRL_2_13_OA_LANE2_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK 0x0002 +#define CORE_AFE_LANE3_CTRL_2_13_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK 0x0002 +#define CORE_AFE_LANE4_CTRL_2_13_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK 0x0002 +#define CORE_AFE_LANE0_CTRL_2_12_OA_LANE0_HSRX_DPHY_DLL_EN_OVR_VAL_MASK 0x0008 +#define CORE_AFE_LANE1_CTRL_2_12_OA_LANE1_HSRX_DPHY_DLL_EN_OVR_VAL_MASK 0x0008 +#define CORE_AFE_LANE2_CTRL_2_12_OA_LANE2_HSRX_DPHY_DLL_EN_OVR_VAL_MASK 0x0008 +#define CORE_AFE_LANE3_CTRL_2_12_OA_LANE3_HSRX_DPHY_DLL_EN_OVR_VAL_MASK 0x0008 +#define CORE_AFE_LANE4_CTRL_2_12_OA_LANE4_HSRX_DPHY_DLL_EN_OVR_VAL_MASK 0x0008 +#define CORE_AFE_LANE0_CTRL_2_13_OA_LANE0_HSRX_DPHY_DLL_EN_OVR_EN_MASK 0x0008 +#define CORE_AFE_LANE1_CTRL_2_13_OA_LANE1_HSRX_DPHY_DLL_EN_OVR_EN_MASK 0x0008 +#define CORE_AFE_LANE2_CTRL_2_13_OA_LANE2_HSRX_DPHY_DLL_EN_OVR_EN_MASK 0x0008 +#define CORE_AFE_LANE3_CTRL_2_13_OA_LANE3_HSRX_DPHY_DLL_EN_OVR_EN_MASK 0x0008 +#define CORE_AFE_LANE4_CTRL_2_13_OA_LANE4_HSRX_DPHY_DLL_EN_OVR_EN_MASK 0x0008 +#define CORE_AFE_LANE2_CTRL_2_9_OA_LANE2_HSRX_HS_CLK_DIV_MASK 0x00E0 +#define CORE_AFE_LANE1_CTRL_2_9_OA_LANE1_HSRX_HS_CLK_DIV_MASK 0x00E0 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_0_HS_RX_0_TCLKSETTLE_REG_MASK 0x00FF +#define CORE_DIG_DLANE_CLK_RW_HS_RX_7_HS_RX_7_TCLKMISS_REG_MASK 0x00FF +#define CORE_DIG_DLANE_0_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_1_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_2_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_3_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_0_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK 0x0004 +#define CORE_DIG_DLANE_1_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK 0x0004 +#define CORE_DIG_DLANE_2_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK 0x0004 +#define CORE_DIG_DLANE_3_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK 0x0004 +#define CORE_DIG_DLANE_0_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK 0x0008 +#define CORE_DIG_DLANE_1_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK 0x0008 +#define CORE_DIG_DLANE_2_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK 0x0008 +#define CORE_DIG_DLANE_3_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK 0x0008 +#define CORE_DIG_DLANE_0_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK 0x8000 +#define CORE_DIG_DLANE_1_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK 0x8000 +#define CORE_DIG_DLANE_2_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK 0x8000 +#define CORE_DIG_DLANE_3_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK 0x8000 +#define CORE_DIG_DLANE_0_RW_LP_0_LP_0_ITMINRX_REG_MASK 0xF000 +#define CORE_DIG_DLANE_1_RW_LP_0_LP_0_ITMINRX_REG_MASK 0xF000 +#define CORE_DIG_DLANE_2_RW_LP_0_LP_0_ITMINRX_REG_MASK 0xF000 +#define CORE_DIG_DLANE_3_RW_LP_0_LP_0_ITMINRX_REG_MASK 0xF000 +#define CORE_DIG_DLANE_0_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK 0x0001 +#define CORE_DIG_DLANE_1_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK 0x0001 +#define CORE_DIG_DLANE_2_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK 0x0001 +#define CORE_DIG_DLANE_3_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK 0x0001 +#define CORE_DIG_DLANE_CLK_RW_LP_0_LP_0_ITMINRX_REG_MASK 0xF000 +#define CORE_DIG_DLANE_CLK_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK 0x0001 +#define CORE_DIG_DLANE_0_RW_HS_RX_2_HS_UPDATE_SETTINGS_DESKEW_REG_MASK 0x2000 +#define CORE_DIG_DLANE_1_RW_HS_RX_2_HS_RX_2_UPDATE_SETTINGS_DESKEW_REG_MASK 0x2000 +#define CORE_DIG_DLANE_2_RW_HS_RX_2_HS_UPDATE_SETTINGS_DESKEW_REG_MASK 0x2000 +#define CORE_DIG_DLANE_3_RW_HS_RX_2_HS_UPDATE_SETTINGS_DESKEW_REG_MASK 0x2000 +#define CORE_DIG_DLANE_0_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK 0x00FF +#define CORE_DIG_DLANE_1_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK 0x00FF +#define CORE_DIG_DLANE_2_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK 0x00FF +#define CORE_DIG_DLANE_3_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK 0x00FF +#define CORE_DIG_DLANE_0_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK 0x1E00 +#define CORE_DIG_DLANE_1_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK 0x1E00 +#define CORE_DIG_DLANE_2_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK 0x1E00 +#define CORE_DIG_DLANE_3_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK 0x1E00 +#define CORE_DIG_DLANE_0_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK 0x0007 +#define CORE_DIG_DLANE_1_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK 0x0007 +#define CORE_DIG_DLANE_2_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK 0x0007 +#define CORE_DIG_DLANE_3_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK 0x0007 +#define CORE_DIG_DLANE_0_RW_HS_RX_4_HS_RX_4_MAX_ITERATIONS_DESKEW_REG_MASK 0xFFFF +#define CORE_DIG_DLANE_1_RW_HS_RX_4_HS_RX_4_MAX_ITERATIONS_DESKEW_REG_MASK 0xFFFF +#define CORE_DIG_DLANE_2_RW_HS_RX_4_HS_MAX_ITERATIONS_DESKEW_REG_MASK 0xFFFF +#define CORE_DIG_DLANE_3_RW_HS_RX_4_HS_MAX_ITERATIONS_DESKEW_REG_MASK 0xFFFF +#define CORE_DIG_DLANE_0_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_1_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_2_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_3_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_0_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_1_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_2_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_3_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_0_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_1_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_2_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_3_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK 0x00FF +#define CORE_DIG_DLANE_0_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK 0x2000 +#define CORE_DIG_DLANE_1_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK 0x2000 +#define CORE_DIG_DLANE_2_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK 0x2000 +#define CORE_DIG_DLANE_3_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK 0x2000 +#define CORE_DIG_DLANE_0_RW_HS_RX_7_HS_RX_7_SELECT_ALTERNATE_ALGO_REG_MASK 0x8000 +#define CORE_DIG_DLANE_1_RW_HS_RX_7_HS_RX_7_SELECT_ALTERNATE_ALGO_REG_MASK 0x8000 +#define CORE_DIG_DLANE_2_RW_HS_RX_7_HS_SELECT_ALTERNATE_ALGO_REG_MASK 0x8000 +#define CORE_DIG_DLANE_3_RW_HS_RX_7_HS_SELECT_ALTERNATE_ALGO_REG_MASK 0x8000 +#define CORE_DIG_DLANE_0_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK 0x01F8 +#define CORE_DIG_DLANE_1_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK 0x01F8 +#define CORE_DIG_DLANE_2_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK 0x01F8 +#define CORE_DIG_DLANE_3_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK 0x01F8 +#define CORE_DIG_DLANE_0_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK 0x00FF +#define CORE_DIG_DLANE_1_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK 0x00FF +#define CORE_DIG_DLANE_2_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK 0x00FF +#define CORE_DIG_DLANE_3_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK 0x00FF +#define CORE_DIG_DLANE_0_RW_HS_RX_6_HS_RX_6_MIN_EYE_OPENING_DESKEW_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_1_RW_HS_RX_6_HS_RX_6_MIN_EYE_OPENING_DESKEW_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_2_RW_HS_RX_6_HS_MIN_EYE_OPENING_DESKEW_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_3_RW_HS_RX_6_HS_MIN_EYE_OPENING_DESKEW_REG_MASK 0xFF00 +#define CORE_DIG_DLANE_CLK_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK 0x0002 + +struct isp4phy_mipi_reg_seq { + u16 addr; + u16 mask; + u16 data; +}; + +union isp4phy_mipi_0 { + struct { + u32 shutdownz : 1; + u32 rstz : 1; + } bit; + u32 value; +}; + +union isp4phy_mipi_1 { + struct { + u32 mode : 1; + } bit; + u32 value; +}; + +union isp4phy_mipi_2 { + struct { + u32 rxdatawidthhs_0 : 2; + u32 rxdatawidthhs_1 : 2; + u32 rxdatawidthhs_2 : 2; + u32 rxdatawidthhs_3 : 2; + } bit; + u32 value; +}; + +struct isp4phy_mipi_3 { + u32 reserved; +}; + +union isp4phy_mipi_4 { + struct { + u32 enableclk : 1; + u32 enable_0 : 1; + u32 enable_1 : 1; + u32 enable_2 : 1; + u32 enable_3 : 1; + } bit; + u32 value; +}; + +union isp4phy_mipi_5 { + struct { + u32 forcerxmode_0 : 1; + u32 forcerxmode_1 : 1; + u32 forcerxmode_2 : 1; + u32 forcerxmode_3 : 1; + u32 forcerxmode_clk : 1; + } bit; + u32 value; +}; + +union isp4phy_mipi_6 { + struct { + u32 turndisable_0 : 1; + u32 turndisable_1 : 1; + u32 turndisable_2 : 1; + u32 turndisable_3 : 1; + } bit; + u32 value; +}; + +union isp4phy_mipi_7 { + struct { + u32 ready : 1; + } bit; + u32 value; +}; + +union isp4phy_mipi_ind_idx { + struct { + u32 addr : 16; + } bit; + u32 value; +}; + +union isp4phy_mipi_ind_data { + struct { + u32 data : 16; + } bit; + u32 value; +}; + +union isp4phy_mipi_ind_wack { + struct { + u32 ack : 1; + u32 pslverr : 1; + } bit; + u32 value; +}; + +struct isp4phy_mipi_reg { + union isp4phy_mipi_0 isp_mipi_phy0; + union isp4phy_mipi_1 isp_mipi_phy1; + union isp4phy_mipi_2 isp_mipi_phy2; + struct isp4phy_mipi_3 isp_mipi_phy3; + union isp4phy_mipi_4 isp_mipi_phy4; + union isp4phy_mipi_5 isp_mipi_phy5; + union isp4phy_mipi_6 isp_mipi_phy6; + union isp4phy_mipi_7 isp_mipi_phy7; + u32 reserve; + union isp4phy_mipi_ind_idx isp_mipi_phy_ind_idx; + union isp4phy_mipi_ind_data isp_mipi_phy_ind_data; + union isp4phy_mipi_ind_wack isp_mipi_phy_inc_wack; +}; + +struct isp4phy_mipi_config { + u16 afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg; + u16 max_phase; + u16 ddlcal_cfg_5ddlcal_dll_fbk_reg; + u16 ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg; + u16 afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg; + u16 afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg; + u16 afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg; + u16 afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg; + u16 cfg_1cfg_1_sot_detection_reg; + u16 hs_rx_2hs_rx_2_ignore_alterncal_reg; + u16 cfg_1cfg_1_deskew_supported_reg; + u16 afe_lanex_ctrl_2_9oa_hs_clk_div_reg; + u16 hs_rx_0hs_rx_0_thssettle_reg; + u16 hs_rx_3hs_rx_3_fjump_deskew_reg; + u16 hs_rx_6hs_rx_6_min_eye_opening_deskew_reg; +}; + +enum isp4phy_mipi_id { + ISP_MIPI_PHY_ID_0 = 0, + ISP_MIPI_PHY_ID_1 = 1, + ISP_MIPI_PHY_ID_2 = 2, + ISP_MIPI_PHY_ID_MAX +}; + +static const struct isp4phy_mipi_reg *isp_mipi_phy_reg[ISP_MIPI_PHY_ID_MAX] = { + (struct isp4phy_mipi_reg *)ISP_MIPI_PHY0_REG0, + (struct isp4phy_mipi_reg *)ISP_MIPI_PHY1_REG0, + (struct isp4phy_mipi_reg *)ISP_MIPI_PHY2_REG0, +}; + +static const struct isp4phy_mipi_reg_seq startup_seq_general_common_config[] = { + { PPI_STARTUP_RW_COMMON_DPHY_10, PPI_STARTUP_RW_COMMON_DPHY_10_PHY_READY_ADDR_MASK, 0x30 }, + { + CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2, + CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2_GLOBAL_ULPS_OVR_VAL_MASK, 0x0 + }, + { + CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2, + CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2_GLOBAL_ULPS_OVR_EN_MASK, 0x1 + }, + { + CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0, + CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0_CB_LP_DCO_EN_DLY_MASK, 0x3F + }, + { + PPI_STARTUP_RW_COMMON_STARTUP_1_1, + PPI_STARTUP_RW_COMMON_STARTUP_1_1_PHY_READY_DLY_MASK, 0x233 + }, + { PPI_STARTUP_RW_COMMON_DPHY_6, PPI_STARTUP_RW_COMMON_DPHY_6_LP_DCO_CAL_ADDR_MASK, 0x27 }, + { PPI_CALIBCTRL_RW_COMMON_BG_0, PPI_CALIBCTRL_RW_COMMON_BG_0_BG_MAX_COUNTER_MASK, 0x1F4 }, + { PPI_RW_LPDCOCAL_NREF, PPI_RW_LPDCOCAL_NREF_LPDCOCAL_NREF_MASK, 0x320 }, + { PPI_RW_LPDCOCAL_NREF_RANGE, PPI_RW_LPDCOCAL_NREF_RANGE_LPDCOCAL_NREF_RANGE_MASK, 0x1B }, + { PPI_RW_LPDCOCAL_TWAIT_CONFIG, PPI_RW_LPDCOCAL_TWAIT_CONFIG_LPDCOCAL_TWAIT_PON_MASK, 0x7F}, + { PPI_RW_LPDCOCAL_VT_CONFIG, PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_VT_NREF_RANGE_MASK, 0x1B }, + { PPI_RW_LPDCOCAL_VT_CONFIG, PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_USE_IDEAL_NREF_MASK, 0x1 }, + { PPI_RW_LPDCOCAL_VT_CONFIG, PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_VT_TRACKING_EN_MASK, 0x0 }, + { PPI_RW_LPDCOCAL_COARSE_CFG, PPI_RW_LPDCOCAL_COARSE_CFG_NCOARSE_START_MASK, 0x1 }, + { PPI_RW_COMMON_CFG, PPI_RW_COMMON_CFG_CFG_CLK_DIV_FACTOR_MASK, 0x3 }, +}; + +static const struct isp4phy_mipi_reg_seq startup_seq_common[] = { + { PPI_STARTUP_RW_COMMON_DPHY_2, PPI_STARTUP_RW_COMMON_DPHY_2_RCAL_ADDR_MASK, 0x5 }, + { PPI_RW_TERMCAL_CFG_0, PPI_RW_TERMCAL_CFG_0_TERMCAL_TIMER_MASK, 0x17 }, + { PPI_RW_OFFSETCAL_CFG_0, PPI_RW_OFFSETCAL_CFG_0_OFFSETCAL_WAIT_THRESH_MASK, 0x4 }, + { PPI_RW_LPDCOCAL_TIMEBASE, PPI_RW_LPDCOCAL_TIMEBASE_LPDCOCAL_TIMEBASE_MASK, 0x5F }, + { + PPI_RW_LPDCOCAL_TWAIT_CONFIG, + PPI_RW_LPDCOCAL_TWAIT_CONFIG_LPDCOCAL_TWAIT_COARSE_MASK, 0x1D + }, + { PPI_RW_LPDCOCAL_VT_CONFIG, PPI_RW_LPDCOCAL_VT_CONFIG_LPDCOCAL_TWAIT_FINE_MASK, 0x1D }, + { CORE_AFE_CTRL_2_0, CORE_AFE_CTRL_2_0_OA_CB_HSTX_VCOMM_REG_PON_OVR_VAL_MASK, 0x0 }, + { CORE_AFE_CTRL_2_1, CORE_AFE_CTRL_2_1_OA_CB_HSTX_VCOMM_REG_PON_OVR_EN_MASK, 0x1 }, + { CORE_AFE_CTRL_2_1, CORE_AFE_CTRL_2_1_OA_CB_HSTXLB_DCO_CLK0_EN_OVR_VAL_MASK, 0x0 }, + { CORE_AFE_CTRL_2_3, CORE_AFE_CTRL_2_3_OA_CB_HSTXLB_DCO_CLK0_EN_OVR_EN_MASK, 0x1 }, + { CORE_AFE_CTRL_2_0, CORE_AFE_CTRL_2_0_OA_CB_HSTXLB_DCO_CLK90_EN_OVR_VAL_MASK, 0x0 }, + { CORE_AFE_CTRL_2_3, CORE_AFE_CTRL_2_3_OA_CB_HSTXLB_DCO_CLK90_EN_OVR_EN_MASK, 0x1 }, + { CORE_AFE_CTRL_2_6, CORE_AFE_CTRL_2_6_OA_CB_HSTXLB_DCO_EN_OVR_EN_MASK, 0x1 }, + { CORE_AFE_CTRL_2_7, CORE_AFE_CTRL_2_7_OA_CB_HSTXLB_DCO_EN_OVR_VAL_MASK, 0x0 }, + { CORE_AFE_CTRL_2_6, CORE_AFE_CTRL_2_6_OA_CB_HSTXLB_DCO_PON_OVR_EN_MASK, 0x1 }, + { CORE_AFE_CTRL_2_7, CORE_AFE_CTRL_2_7_OA_CB_HSTXLB_DCO_PON_OVR_VAL_MASK, 0x0 }, + { CORE_AFE_CTRL_2_6, CORE_AFE_CTRL_2_6_OA_CB_HSTXLB_DCO_TUNE_CLKDIG_EN_OVR_EN_MASK, 0x1 }, + { CORE_AFE_CTRL_2_7, CORE_AFE_CTRL_2_7_OA_CB_HSTXLB_DCO_TUNE_CLKDIG_EN_OVR_VAL_MASK, 0x0 }, + { CORE_AFE_CTRL_2_5, CORE_AFE_CTRL_2_5_OA_CB_SEL_45OHM_50OHM_MASK, 0x0 }, +}; + +static const struct isp4phy_mipi_reg_seq + startup_seq_dphy_periodic_deskew_program[] = { + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x404 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x40C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x414 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x41C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x423 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x429 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x430 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x43A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x445 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x44A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x450 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x45A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x465 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x469 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x472 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x47A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x485 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x489 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x490 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x49A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4A4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4AC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4B4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4BC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4C4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4CC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4D4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4DC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4E4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4EC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4F4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x4FC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x504 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x50C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x514 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x51C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x523 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x529 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x530 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x53A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x545 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x54A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x550 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x55A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x565 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x569 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x572 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x57A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x585 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x589 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x590 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x59A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5A4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5AC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5B4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5BC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5C4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5CC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5D4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5DC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5E4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5EC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5F4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x5FC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x604 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x60C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x614 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x61C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x623 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x629 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x632 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x63A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x645 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x64A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x650 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x65A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x665 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x669 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x672 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x67A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x685 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x689 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x690 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x69A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6A4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6AC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6B4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6BC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6C4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6CC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6D4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6DC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6E4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6EC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6F4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x6FC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x704 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x70C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x714 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x71C }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x723 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x72A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x730 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x73A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x745 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x74A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x750 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x75A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x765 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x769 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x772 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x77A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x785 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x789 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x790 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x79A }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7A4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7AC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7B4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7BC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7C4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7CC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7D4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7DC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7E4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7EC }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7F4 }, + { CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, 0, 0x7FC }, +}; + +inline u16 isp4phy_rreg(void __iomem *base, u32 phy_id, u16 addr) +{ + const struct isp4phy_mipi_reg *reg = isp_mipi_phy_reg[phy_id]; + + isp4hw_wreg(base, (uintptr_t)(®->isp_mipi_phy_ind_idx), addr); + return (u16)isp4hw_rreg(base, (uintptr_t)(®->isp_mipi_phy_ind_data)); +} + +inline void isp4phy_wreg(void __iomem *base, u32 phy_id, u16 addr, u16 data) +{ + const struct isp4phy_mipi_reg *reg = isp_mipi_phy_reg[phy_id]; + + isp4hw_wreg(base, (uintptr_t)(®->isp_mipi_phy_ind_idx), addr); + isp4hw_wreg(base, (uintptr_t)(®->isp_mipi_phy_ind_data), data); +} + +static void isp4phy_mask_wreg(void __iomem *base, u32 phy_id, u16 addr, + u16 mask, u16 regval) +{ + unsigned long _mask = mask; + u16 shift = 0; + u16 data; + + data = isp4phy_rreg(base, phy_id, addr); + if (mask) + shift = find_first_bit(&_mask, 16); + data = (data & ~mask) | ((regval << shift) & mask); + + isp4phy_wreg(base, phy_id, addr, data); +} + +static void isp4phy_optional_features_dphy(void __iomem *base, u32 phy_id) +{ + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_CLK_RW_CFG_0, + CORE_DIG_DLANE_CLK_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_CLK_RW_CFG_0, + CORE_DIG_DLANE_CLK_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK, 0x0); + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_CFG_0, + CORE_DIG_DLANE_0_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_CFG_0, + CORE_DIG_DLANE_1_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_CFG_0, + CORE_DIG_DLANE_2_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_CFG_0, + CORE_DIG_DLANE_3_RW_CFG_0_CFG_0_LP_PIN_SWAP_REG_MASK, 0x0); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_CFG_0, + CORE_DIG_DLANE_0_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_CFG_0, + CORE_DIG_DLANE_1_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_CFG_0, + CORE_DIG_DLANE_2_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_CFG_0, + CORE_DIG_DLANE_3_RW_CFG_0_CFG_0_HS_PIN_SWAP_REG_MASK, 0x0); + } + + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_9, + CORE_AFE_LANE0_CTRL_2_9_OA_LANE0_HSRX_SEL_GATED_POLARITY_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_9, + CORE_AFE_LANE1_CTRL_2_9_OA_LANE1_HSRX_SEL_GATED_POLARITY_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_9, + CORE_AFE_LANE2_CTRL_2_9_OA_LANE2_HSRX_SEL_GATED_POLARITY_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_9, + CORE_AFE_LANE3_CTRL_2_9_OA_LANE3_HSRX_SEL_GATED_POLARITY_MASK, + 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_9, + CORE_AFE_LANE4_CTRL_2_9_OA_LANE4_HSRX_SEL_GATED_POLARITY_MASK, + 0x0); + } +} + +static void isp4phy_dphy_periodic_deskew_program(void __iomem *base, + u32 phy_id) +{ + for (int ctr = 0; + ctr < ARRAY_SIZE(startup_seq_dphy_periodic_deskew_program); + ctr++) + isp4phy_wreg(base, phy_id, + startup_seq_dphy_periodic_deskew_program[ctr].addr, + startup_seq_dphy_periodic_deskew_program[ctr].data); +} + +static void isp4phy_dphy_specific(void __iomem *base, u32 phy_id, + u64 data_rate, + struct isp4phy_mipi_config *phycfg) +{ + u64 half_rate = data_rate >> 1; + u16 ddl_cal; + + ddl_cal = TIMEBASE * half_rate; + ddl_cal = (ddl_cal + 31) >> 5; + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_7, + CORE_DIG_RW_COMMON_7_LANE0_HSRX_WORD_CLK_SEL_GATING_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_7, + CORE_DIG_RW_COMMON_7_LANE1_HSRX_WORD_CLK_SEL_GATING_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_7, + CORE_DIG_RW_COMMON_7_LANE2_HSRX_WORD_CLK_SEL_GATING_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_7, + CORE_DIG_RW_COMMON_7_LANE3_HSRX_WORD_CLK_SEL_GATING_REG_MASK, + 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_7, + CORE_DIG_RW_COMMON_7_LANE4_HSRX_WORD_CLK_SEL_GATING_REG_MASK, + 0x0); + } + + isp4phy_mask_wreg(base, phy_id, PPI_STARTUP_RW_COMMON_DPHY_8, + PPI_STARTUP_RW_COMMON_DPHY_8_CPHY_DDL_CAL_ADDR_MASK, 0x50); + + if (data_rate < 1500) { + isp4phy_mask_wreg(base, phy_id, PPI_STARTUP_RW_COMMON_DPHY_7, + PPI_STARTUP_RW_COMMON_DPHY_7_DPHY_DDL_CAL_ADDR_MASK, 0x68); + } else { + /* Digital Delay Line (DDL) tuning calibration */ + isp4phy_mask_wreg(base, phy_id, PPI_STARTUP_RW_COMMON_DPHY_7, + PPI_STARTUP_RW_COMMON_DPHY_7_DPHY_DDL_CAL_ADDR_MASK, 0x28); + /* LUT->24MHz case */ + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_0, + PPI_RW_DDLCAL_CFG_0_DDLCAL_TIMEBASE_TARGET_MASK, 0x77); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_7, + PPI_RW_DDLCAL_CFG_7_DDLCAL_DECR_WAIT_MASK, 0x22); + /* LUT->24MHz case */ + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_1, + PPI_RW_DDLCAL_CFG_1_DDLCAL_DISABLE_TIME_MASK, 0x17); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_2, + PPI_RW_DDLCAL_CFG_2_DDLCAL_WAIT_MASK, 0x4); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_2, + PPI_RW_DDLCAL_CFG_2_DDLCAL_TUNE_MODE_MASK, 0x2); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_2, + PPI_RW_DDLCAL_CFG_2_DDLCAL_DDL_DLL_MASK, 0x1); + /* LUT->24MHz case */ + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_2, + PPI_RW_DDLCAL_CFG_2_DDLCAL_ENABLE_WAIT_MASK, 0x17); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_2, + PPI_RW_DDLCAL_CFG_2_DDLCAL_UPDATE_SETTINGS_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_4, + PPI_RW_DDLCAL_CFG_4_DDLCAL_STUCK_THRESH_MASK, 0xA); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_6, + PPI_RW_DDLCAL_CFG_6_DDLCAL_MAX_DIFF_MASK, 0xA); + /* LUT->24MHz case */ + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_7, + PPI_RW_DDLCAL_CFG_7_DDLCAL_START_DELAY_MASK, 0xB); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_3, + PPI_RW_DDLCAL_CFG_3_DDLCAL_COUNTER_REF_MASK, ddl_cal); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_1, + PPI_RW_DDLCAL_CFG_1_DDLCAL_MAX_PHASE_MASK, phycfg->max_phase); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_5, + PPI_RW_DDLCAL_CFG_5_DDLCAL_DLL_FBK_MASK, + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg); + isp4phy_mask_wreg(base, phy_id, PPI_RW_DDLCAL_CFG_5, + PPI_RW_DDLCAL_CFG_5_DDLCAL_DDL_COARSE_BANK_MASK, + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_8, + CORE_AFE_LANE0_CTRL_2_8_OA_LANE0_HSRX_CDPHY_SEL_FAST_MASK, + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_8, + CORE_AFE_LANE1_CTRL_2_8_OA_LANE1_HSRX_CDPHY_SEL_FAST_MASK, + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_8, + CORE_AFE_LANE2_CTRL_2_8_OA_LANE2_HSRX_CDPHY_SEL_FAST_MASK, + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_8, + CORE_AFE_LANE3_CTRL_2_8_OA_LANE3_HSRX_CDPHY_SEL_FAST_MASK, + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_8, + CORE_AFE_LANE4_CTRL_2_8_OA_LANE4_HSRX_CDPHY_SEL_FAST_MASK, + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg); + } + } + + /* Write 6 if Tlpx (far end / near end) ratio < 1 + * Write 7 if Tlpx (far end / near end) ratio >= 1 + */ + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_LP_0, + CORE_DIG_DLANE_0_RW_LP_0_LP_0_TTAGO_REG_MASK, 0x7); + /* Write 6 if Tlpx (far end / near end) ratio < 1 + * Write 7 if Tlpx (far end / near end) ratio >= 1 + */ + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_LP_0, + CORE_DIG_DLANE_1_RW_LP_0_LP_0_TTAGO_REG_MASK, 0x7); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + /* Write 6 if Tlpx (far end / near end) ratio < 1 + * Write 7 if Tlpx (far end / near end) ratio >= 1 + */ + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_LP_0, + CORE_DIG_DLANE_2_RW_LP_0_LP_0_TTAGO_REG_MASK, 0x7); + /* Write 6 if Tlpx (far end / near end) ratio < 1 + * Write 7 if Tlpx (far end / near end) ratio >= 1 + */ + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_LP_0, + CORE_DIG_DLANE_3_RW_LP_0_LP_0_TTAGO_REG_MASK, 0x7); + } + + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_2, + CORE_AFE_LANE0_CTRL_2_2_OA_LANE0_SEL_LANE_CFG_MASK, 0x0); + + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_2, + CORE_AFE_LANE1_CTRL_2_2_OA_LANE1_SEL_LANE_CFG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_2, + CORE_AFE_LANE2_CTRL_2_2_OA_LANE2_SEL_LANE_CFG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_2, + CORE_AFE_LANE3_CTRL_2_2_OA_LANE3_SEL_LANE_CFG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_2, + CORE_AFE_LANE4_CTRL_2_2_OA_LANE4_SEL_LANE_CFG_MASK, 0x0); + } else { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_2, + CORE_AFE_LANE1_CTRL_2_2_OA_LANE1_SEL_LANE_CFG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_2, + CORE_AFE_LANE2_CTRL_2_2_OA_LANE2_SEL_LANE_CFG_MASK, 0x0); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_6, + CORE_DIG_RW_COMMON_6_DESERIALIZER_EN_DEASS_COUNT_THRESH_D_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_RW_COMMON_6, + CORE_DIG_RW_COMMON_6_DESERIALIZER_DIV_EN_DELAY_THRESH_D_MASK, 0x1); + + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_12, + CORE_AFE_LANE0_CTRL_2_12_OA_LANE0_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_12, + CORE_AFE_LANE1_CTRL_2_12_OA_LANE1_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_12, + CORE_AFE_LANE2_CTRL_2_12_OA_LANE2_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_12, + CORE_AFE_LANE3_CTRL_2_12_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_12, + CORE_AFE_LANE4_CTRL_2_12_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_13, + CORE_AFE_LANE0_CTRL_2_13_OA_LANE0_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_13, + CORE_AFE_LANE1_CTRL_2_13_OA_LANE1_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_13, + CORE_AFE_LANE2_CTRL_2_13_OA_LANE2_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_13, + CORE_AFE_LANE3_CTRL_2_13_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_13, + CORE_AFE_LANE4_CTRL_2_13_OA_HSRX_DPHY_DDL_BYPASS_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_12, + CORE_AFE_LANE0_CTRL_2_12_OA_LANE0_HSRX_DPHY_DLL_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_12, + CORE_AFE_LANE1_CTRL_2_12_OA_LANE1_HSRX_DPHY_DLL_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_12, + CORE_AFE_LANE2_CTRL_2_12_OA_LANE2_HSRX_DPHY_DLL_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_12, + CORE_AFE_LANE3_CTRL_2_12_OA_LANE3_HSRX_DPHY_DLL_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_12, + CORE_AFE_LANE4_CTRL_2_12_OA_LANE4_HSRX_DPHY_DLL_EN_OVR_VAL_MASK, + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE0_CTRL_2_13, + CORE_AFE_LANE0_CTRL_2_13_OA_LANE0_HSRX_DPHY_DLL_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_13, + CORE_AFE_LANE1_CTRL_2_13_OA_LANE1_HSRX_DPHY_DLL_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_13, + CORE_AFE_LANE2_CTRL_2_13_OA_LANE2_HSRX_DPHY_DLL_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE3_CTRL_2_13, + CORE_AFE_LANE3_CTRL_2_13_OA_LANE3_HSRX_DPHY_DLL_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE4_CTRL_2_13, + CORE_AFE_LANE4_CTRL_2_13_OA_LANE4_HSRX_DPHY_DLL_EN_OVR_EN_MASK, + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg); + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE2_CTRL_2_9, + CORE_AFE_LANE2_CTRL_2_9_OA_LANE2_HSRX_HS_CLK_DIV_MASK, + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg); + } else { + isp4phy_mask_wreg(base, phy_id, CORE_AFE_LANE1_CTRL_2_9, + CORE_AFE_LANE1_CTRL_2_9_OA_LANE1_HSRX_HS_CLK_DIV_MASK, + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_CLK_RW_HS_RX_0, + CORE_DIG_DLANE_CLK_RW_HS_RX_0_HS_RX_0_TCLKSETTLE_REG_MASK, 0x1C); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_CLK_RW_HS_RX_7, + CORE_DIG_DLANE_CLK_RW_HS_RX_7_HS_RX_7_TCLKMISS_REG_MASK, 0x6); + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_0, + CORE_DIG_DLANE_0_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK, + phycfg->hs_rx_0hs_rx_0_thssettle_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_0, + CORE_DIG_DLANE_1_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK, + phycfg->hs_rx_0hs_rx_0_thssettle_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_0, + CORE_DIG_DLANE_2_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK, + phycfg->hs_rx_0hs_rx_0_thssettle_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_0, + CORE_DIG_DLANE_3_RW_HS_RX_0_HS_RX_0_THSSETTLE_REG_MASK, + phycfg->hs_rx_0hs_rx_0_thssettle_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_CFG_1, + CORE_DIG_DLANE_0_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK, + phycfg->cfg_1cfg_1_deskew_supported_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_CFG_1, + CORE_DIG_DLANE_1_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK, + phycfg->cfg_1cfg_1_deskew_supported_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_CFG_1, + CORE_DIG_DLANE_2_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK, + phycfg->cfg_1cfg_1_deskew_supported_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_CFG_1, + CORE_DIG_DLANE_3_RW_CFG_1_CFG_1_DESKEW_SUPPORTED_REG_MASK, + phycfg->cfg_1cfg_1_deskew_supported_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_CFG_1, + CORE_DIG_DLANE_0_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK, + phycfg->cfg_1cfg_1_sot_detection_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_CFG_1, + CORE_DIG_DLANE_1_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK, + phycfg->cfg_1cfg_1_sot_detection_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_CFG_1, + CORE_DIG_DLANE_2_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK, + phycfg->cfg_1cfg_1_sot_detection_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_CFG_1, + CORE_DIG_DLANE_3_RW_CFG_1_CFG_1_SOT_DETECTION_REG_MASK, + phycfg->cfg_1cfg_1_sot_detection_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_2, + CORE_DIG_DLANE_0_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK, + phycfg->hs_rx_2hs_rx_2_ignore_alterncal_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_2, + CORE_DIG_DLANE_1_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK, + phycfg->hs_rx_2hs_rx_2_ignore_alterncal_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_2, + CORE_DIG_DLANE_2_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK, + phycfg->hs_rx_2hs_rx_2_ignore_alterncal_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_2, + CORE_DIG_DLANE_3_RW_HS_RX_2_HS_RX_2_IGNORE_ALTERNCAL_REG_MASK, + phycfg->hs_rx_2hs_rx_2_ignore_alterncal_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_LP_0, + CORE_DIG_DLANE_0_RW_LP_0_LP_0_ITMINRX_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_LP_0, + CORE_DIG_DLANE_1_RW_LP_0_LP_0_ITMINRX_REG_MASK, 0x1); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_LP_0, + CORE_DIG_DLANE_2_RW_LP_0_LP_0_ITMINRX_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_LP_0, + CORE_DIG_DLANE_3_RW_LP_0_LP_0_ITMINRX_REG_MASK, 0x1); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_LP_2, + CORE_DIG_DLANE_0_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_LP_2, + CORE_DIG_DLANE_1_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_LP_2, + CORE_DIG_DLANE_2_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK, + 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_LP_2, + CORE_DIG_DLANE_3_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK, + 0x0); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_CLK_RW_LP_0, + CORE_DIG_DLANE_CLK_RW_LP_0_LP_0_ITMINRX_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_CLK_RW_LP_2, + CORE_DIG_DLANE_CLK_RW_LP_2_LP_2_FILTER_INPUT_SAMPLING_REG_MASK, 0x0); + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_2, + CORE_DIG_DLANE_0_RW_HS_RX_2_HS_UPDATE_SETTINGS_DESKEW_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_2, + CORE_DIG_DLANE_1_RW_HS_RX_2_HS_RX_2_UPDATE_SETTINGS_DESKEW_REG_MASK, 0x1); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_2, + CORE_DIG_DLANE_2_RW_HS_RX_2_HS_UPDATE_SETTINGS_DESKEW_REG_MASK, + 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_2, + CORE_DIG_DLANE_3_RW_HS_RX_2_HS_UPDATE_SETTINGS_DESKEW_REG_MASK, + 0x1); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_1, + CORE_DIG_DLANE_0_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK, 0x10); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_1, + CORE_DIG_DLANE_1_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK, 0x10); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_1, + CORE_DIG_DLANE_2_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK, + 0x10); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_1, + CORE_DIG_DLANE_3_RW_HS_RX_1_HS_RX_1_FILTER_SIZE_DESKEW_REG_MASK, + 0x10); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_2, + CORE_DIG_DLANE_0_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK, 0x3); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_2, + CORE_DIG_DLANE_1_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK, 0x3); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_2, + CORE_DIG_DLANE_2_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK, + 0x3); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_2, + CORE_DIG_DLANE_3_RW_HS_RX_2_HS_RX_2_WINDOW_SIZE_DESKEW_REG_MASK, + 0x3); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_3, + CORE_DIG_DLANE_0_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_3, + CORE_DIG_DLANE_1_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK, 0x1); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_3, + CORE_DIG_DLANE_2_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK, + 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_3, + CORE_DIG_DLANE_3_RW_HS_RX_3_HS_RX_3_STEP_SIZE_DESKEW_REG_MASK, + 0x1); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_4, + CORE_DIG_DLANE_0_RW_HS_RX_4_HS_RX_4_MAX_ITERATIONS_DESKEW_REG_MASK, 0x96); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_4, + CORE_DIG_DLANE_1_RW_HS_RX_4_HS_RX_4_MAX_ITERATIONS_DESKEW_REG_MASK, 0x96); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_4, + CORE_DIG_DLANE_2_RW_HS_RX_4_HS_MAX_ITERATIONS_DESKEW_REG_MASK, + 0x96); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_4, + CORE_DIG_DLANE_3_RW_HS_RX_4_HS_MAX_ITERATIONS_DESKEW_REG_MASK, + 0x96); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_5, + CORE_DIG_DLANE_0_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_5, + CORE_DIG_DLANE_1_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_5, + CORE_DIG_DLANE_2_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_5, + CORE_DIG_DLANE_3_RW_HS_RX_5_HS_RX_5_DDL_LEFT_INIT_REG_MASK, 0x0); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_5, + CORE_DIG_DLANE_0_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_5, + CORE_DIG_DLANE_1_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK, 0x1); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_5, + CORE_DIG_DLANE_2_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK, 0x1); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_5, + CORE_DIG_DLANE_3_RW_HS_RX_5_HS_RX_5_DDL_MID_INIT_REG_MASK, 0x1); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_6, + CORE_DIG_DLANE_0_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK, 0x2); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_6, + CORE_DIG_DLANE_1_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK, 0x2); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_6, + CORE_DIG_DLANE_2_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK, 0x2); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_6, + CORE_DIG_DLANE_3_RW_HS_RX_6_HS_RX_6_DDL_RIGHT_INIT_REG_MASK, 0x2); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_7, + CORE_DIG_DLANE_0_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_7, + CORE_DIG_DLANE_1_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_7, + CORE_DIG_DLANE_2_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK, + 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_7, + CORE_DIG_DLANE_3_RW_HS_RX_7_HS_RX_7_DESKEW_AUTO_ALGO_SEL_REG_MASK, + 0x0); + } + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_7, + CORE_DIG_DLANE_0_RW_HS_RX_7_HS_RX_7_SELECT_ALTERNATE_ALGO_REG_MASK, 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_7, + CORE_DIG_DLANE_1_RW_HS_RX_7_HS_RX_7_SELECT_ALTERNATE_ALGO_REG_MASK, 0x0); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_7, + CORE_DIG_DLANE_2_RW_HS_RX_7_HS_SELECT_ALTERNATE_ALGO_REG_MASK, + 0x0); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_7, + CORE_DIG_DLANE_3_RW_HS_RX_7_HS_SELECT_ALTERNATE_ALGO_REG_MASK, + 0x0); + } + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_3, + CORE_DIG_DLANE_0_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK, + phycfg->hs_rx_3hs_rx_3_fjump_deskew_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_3, + CORE_DIG_DLANE_1_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK, + phycfg->hs_rx_3hs_rx_3_fjump_deskew_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_3, + CORE_DIG_DLANE_2_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK, + phycfg->hs_rx_3hs_rx_3_fjump_deskew_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_3, + CORE_DIG_DLANE_3_RW_HS_RX_3_HS_RX_3_FJUMP_DESKEW_REG_MASK, + phycfg->hs_rx_3hs_rx_3_fjump_deskew_reg); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_9, + CORE_DIG_DLANE_0_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK, + phycfg->max_phase); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_9, + CORE_DIG_DLANE_1_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK, + phycfg->max_phase); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_9, + CORE_DIG_DLANE_2_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK, + phycfg->max_phase); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_9, + CORE_DIG_DLANE_3_RW_HS_RX_9_HS_RX_9_PHASE_BOUND_REG_MASK, + phycfg->max_phase); + } + + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_HS_RX_6, + CORE_DIG_DLANE_0_RW_HS_RX_6_HS_RX_6_MIN_EYE_OPENING_DESKEW_REG_MASK, + phycfg->hs_rx_6hs_rx_6_min_eye_opening_deskew_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_1_RW_HS_RX_6, + CORE_DIG_DLANE_1_RW_HS_RX_6_HS_RX_6_MIN_EYE_OPENING_DESKEW_REG_MASK, + phycfg->hs_rx_6hs_rx_6_min_eye_opening_deskew_reg); + if (phy_id <= ISP_MIPI_PHY_ID_1) { + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_2_RW_HS_RX_6, + CORE_DIG_DLANE_2_RW_HS_RX_6_HS_MIN_EYE_OPENING_DESKEW_REG_MASK, + phycfg->hs_rx_6hs_rx_6_min_eye_opening_deskew_reg); + isp4phy_mask_wreg(base, phy_id, CORE_DIG_DLANE_3_RW_HS_RX_6, + CORE_DIG_DLANE_3_RW_HS_RX_6_HS_MIN_EYE_OPENING_DESKEW_REG_MASK, + phycfg->hs_rx_6hs_rx_6_min_eye_opening_deskew_reg); + } +} + +static void isp4phy_common(void __iomem *base, u32 phy_id) +{ + for (int ctr = 0; ctr < ARRAY_SIZE(startup_seq_common); ctr++) + isp4phy_mask_wreg(base, phy_id, startup_seq_common[ctr].addr, + startup_seq_common[ctr].mask, + startup_seq_common[ctr].data); +} + +static void isp4phy_general_common_config(void __iomem *base, u32 phy_id) +{ + for (int ctr = 0; ctr < ARRAY_SIZE(startup_seq_general_common_config); ctr++) + isp4phy_mask_wreg(base, phy_id, + startup_seq_general_common_config[ctr].addr, + startup_seq_general_common_config[ctr].mask, + startup_seq_general_common_config[ctr].data); +} + +static void +isp4phy_calculate_datarate_cfgs_rx(u32 phy_id, u64 data_rate, + u32 lane, + struct isp4phy_mipi_config *phycfg) +{ + u64 half_rate = data_rate >> 1; + u64 hs_clk_freq; + + hs_clk_freq = half_rate * 1000; + + if (data_rate <= 2500) + phycfg->hs_rx_2hs_rx_2_ignore_alterncal_reg = 1; + else if (data_rate <= 4500) + phycfg->hs_rx_2hs_rx_2_ignore_alterncal_reg = 0; + + if (data_rate < 1500) { + /* do nothing */ + } else if (data_rate < 1588) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 143; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 17; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 3; + } else if (data_rate < 1688) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 135; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 16; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 2; + } else if (data_rate < 1800) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 127; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 15; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 2; + } else if (data_rate < 1929) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 119; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 14; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 2; + } else if (data_rate < 2077) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 111; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 13; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 2; + } else if (data_rate < 2250) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 103; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 12; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else if (data_rate < 2455) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 95; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 11; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else if (data_rate < 2700) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 87; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 10; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else if (data_rate < 3000) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 79; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 9; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else if (data_rate < 3230) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 0; + phycfg->max_phase = 71; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 8; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 0; + } else if (data_rate < 3600) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 1; + phycfg->max_phase = 87; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 10; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else if (data_rate < 4000) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 1; + phycfg->max_phase = 79; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 9; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else if (data_rate < 4500) { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 1; + phycfg->max_phase = 71; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 8; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 1; + } else { + phycfg->afe_lanex_ctrl_2_8oa_cdphy_sel_fast_reg = 1; + phycfg->max_phase = 63; + phycfg->ddlcal_cfg_5ddlcal_dll_fbk_reg = 7; + phycfg->ddlcal_cfg_5ddlcal_ddl_coarse_bank_reg = 0; + } + + if (data_rate <= 1500) { + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg = 1; + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg = 1; + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg = 0; + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg = 1; + phycfg->cfg_1cfg_1_deskew_supported_reg = 0; + phycfg->cfg_1cfg_1_sot_detection_reg = 1; + } else if (data_rate <= 4500) { + phycfg->afe_lanex_ctrl_2_12oa_dphy_ddl_bypass_en_ovr_val_reg = 0; + phycfg->afe_lanex_ctrl_2_13oa_dphy_ddl_bypass_en_ovr_en_reg = 0; + phycfg->afe_lanex_ctrl_2_12oa_dphy_dll_en_ovr_val_reg = 0; + phycfg->afe_lanex_ctrl_2_13oa_dphy_dll_en_ovr_en_reg = 0; + phycfg->cfg_1cfg_1_deskew_supported_reg = 1; + phycfg->cfg_1cfg_1_sot_detection_reg = 0; + } + + if (data_rate < 160) + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg = 0b001; + else if (data_rate < 320) + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg = 0b010; + else if (data_rate < 640) + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg = 0b011; + else if (data_rate < 1280) + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg = 0b100; + else if (data_rate < 2560) + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg = 0b101; + else + phycfg->afe_lanex_ctrl_2_9oa_hs_clk_div_reg = 0b110; + + u32 t_hs_settle_ns = MIN_T_HS_SETTLE_NS + MAX_T_HS_SETTLE_NS; + + t_hs_settle_ns = t_hs_settle_ns >> 1; + u32 t_hs_settle_ui = MIN_T_HS_SETTLE_UI + MAX_T_HS_SETTLE_UI; + + t_hs_settle_ui = t_hs_settle_ui >> 1; + + t_hs_settle_ui = t_hs_settle_ui * 1000000; + t_hs_settle_ui = t_hs_settle_ui >> 1; + t_hs_settle_ui = div64_u64(t_hs_settle_ui, hs_clk_freq); + + u32 ths_settle_target = t_hs_settle_ns + t_hs_settle_ui; + + ths_settle_target = div64_u64(ths_settle_target, T_DCO); + phycfg->hs_rx_0hs_rx_0_thssettle_reg = ths_settle_target - TMIN_RX - 7; + + u16 jump_deskew_reg = phycfg->max_phase + 39; + + jump_deskew_reg = div64_u64(jump_deskew_reg, 40); + phycfg->hs_rx_3hs_rx_3_fjump_deskew_reg = jump_deskew_reg; + + u16 eye_opening_deskew_reg = phycfg->max_phase + 4; + + eye_opening_deskew_reg = div64_u64(eye_opening_deskew_reg, 5); + phycfg->hs_rx_6hs_rx_6_min_eye_opening_deskew_reg = eye_opening_deskew_reg; +} + +static void isp4phy_startup_seq_dphy_rx(void __iomem *base, u32 phy_id, + u64 data_rate, u32 lane) +{ + struct isp4phy_mipi_config phycfg; + + memset(&phycfg, 0, sizeof(phycfg)); + + isp4phy_calculate_datarate_cfgs_rx(phy_id, data_rate, lane, &phycfg); + isp4phy_general_common_config(base, phy_id); + isp4phy_common(base, phy_id); + isp4phy_dphy_specific(base, phy_id, data_rate, &phycfg); + isp4phy_dphy_periodic_deskew_program(base, phy_id); + isp4phy_optional_features_dphy(base, phy_id); +} + +static int isp4phy_startup_seq_cdphy_rx(struct device *dev, + void __iomem *base, u32 phy_id, + u64 data_rate, u32 lane) +{ + struct isp4phy_mipi_reg phy_reg = {0}; + + /* readback the mipi phy reg */ + phy_reg.isp_mipi_phy0.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy0); + phy_reg.isp_mipi_phy1.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy1); + phy_reg.isp_mipi_phy2.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy2); + phy_reg.isp_mipi_phy4.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy4); + phy_reg.isp_mipi_phy5.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy5); + phy_reg.isp_mipi_phy6.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy6); + phy_reg.isp_mipi_phy7.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy7); + + phy_reg.isp_mipi_phy0.bit.shutdownz = 0; + phy_reg.isp_mipi_phy0.bit.rstz = 0; + isp4hw_wreg(base, (uintptr_t)(&isp_mipi_phy_reg[phy_id]->isp_mipi_phy0), + phy_reg.isp_mipi_phy0.value); + + /*PHY register access test */ + isp4phy_wreg(base, phy_id, CORE_DIG_DLANE_0_RW_LP_0, 0x473C); + usleep_range(10, 20); + if (isp4phy_rreg(base, phy_id, CORE_DIG_DLANE_0_RW_LP_0) == 0x473C) { + dev_dbg(dev, "PHY register access test suc\n"); + } else { + dev_err(dev, "PHY register access test fail\n"); + return -EFAULT; + } + + /** T1: top level static inputs must be set to the desired + * configuration (for example, phyMode. These *inputs can be + * identified with Startup and Active Mode state: Static label + * in Chapter 4, ¡°Signal Descriptions¡±). + */ + phy_reg.isp_mipi_phy5.value = (1 << lane) - 1; + phy_reg.isp_mipi_phy5.bit.forcerxmode_clk = 1; + isp4hw_wreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy5, + phy_reg.isp_mipi_phy5.value); + + phy_reg.isp_mipi_phy4.value = (0x2 << lane) - 1; + isp4hw_wreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy4, + phy_reg.isp_mipi_phy4.value); + + phy_reg.isp_mipi_phy1.bit.mode = ISP_MIPI_DPHY; + isp4hw_wreg(base, (uintptr_t)(&isp_mipi_phy_reg[phy_id]->isp_mipi_phy1), + phy_reg.isp_mipi_phy1.value); + + /** T2: APB slave is active and can be accessed (presetN = 1b1)*/ + /** T3: static register fields are programmed/read through the APB, + * with PHY in reset (these register + * fields can be found in Chapter 11.2, Static Register Access). + */ + /* DPHY mode setup */ + isp4phy_startup_seq_dphy_rx(base, phy_id, data_rate, lane); + + /** T4: initial programming phase is over and PHY is ready + * to leave Shutdown Mode (shutdownN = 1¡¯b1 + * and rstN = 1¡¯b1). + */ + phy_reg.isp_mipi_phy0.bit.shutdownz = 1; + phy_reg.isp_mipi_phy0.bit.rstz = 1; + isp4hw_wreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy0, + phy_reg.isp_mipi_phy0.value); + + dev_dbg(dev, "Termination calibration observability: 0x%x\n", + isp4phy_rreg(base, phy_id, PPI_R_TERMCAL_DEBUG_0)); + + /** T5: internal calibrations ongoing. No configurations are accepted + * during power-on-reset (POR). + * phyReady asserts to signal that POR is complete. + */ + do { + usleep_range(1000, 2000); + phy_reg.isp_mipi_phy7.value = + isp4hw_rreg(base, (uintptr_t)&isp_mipi_phy_reg[phy_id]->isp_mipi_phy7); + dev_dbg(dev, "Wait for phyReady: 0x%x\n", + phy_reg.isp_mipi_phy7.value); + } while (phy_reg.isp_mipi_phy7.bit.ready != 1); + + /** T6: dynamic register fields can be programmed/read through APB + * (these register fields can be found in Chapter 11.3, Dynamic Register Access). + * Check Chapter 9.3.4, D-PHY and C-PHY HS Receivers for analog settings that must be + * programmed in T3. + */ + + /** T7: de-assert forcerxmode_N.*/ + phy_reg.isp_mipi_phy5.bit.forcerxmode_0 = 0; + phy_reg.isp_mipi_phy5.bit.forcerxmode_1 = 0; + phy_reg.isp_mipi_phy5.bit.forcerxmode_2 = 0; + phy_reg.isp_mipi_phy5.bit.forcerxmode_3 = 0; + phy_reg.isp_mipi_phy5.bit.forcerxmode_clk = 0; + isp4hw_wreg(base, (uintptr_t)(&isp_mipi_phy_reg[phy_id]->isp_mipi_phy5), + phy_reg.isp_mipi_phy5.value); + return 0; +} + +int isp4phy_start(struct device *dev, + void __iomem *base, u32 phy_id, u64 bit_rate, + u32 lane_num) +{ + if (phy_id >= ISP_MIPI_PHY_ID_MAX) + return -EINVAL; + + if (phy_id == 2 && lane_num > 2) { + dev_err(dev, "MIPI PHY 2 just has 2 lane\n"); + return -EINVAL; + } + + if (phy_id == 0 && lane_num > 4) { + dev_err(dev, "fail invalid lane number %u for phy0\n", + lane_num); + return -EINVAL; + } + + return isp4phy_startup_seq_cdphy_rx(dev, base, phy_id, bit_rate, lane_num); +} + +int isp4phy_stop(void __iomem *base, u32 phy_id) +{ + struct isp4phy_mipi_reg phy_reg = {0}; + + if (phy_id >= ISP_MIPI_PHY_ID_MAX) + return -EINVAL; + + phy_reg.isp_mipi_phy0.value = + isp4hw_rreg(base, (uintptr_t) + (&isp_mipi_phy_reg[phy_id]->isp_mipi_phy0)); + + /* shutdown phy */ + phy_reg.isp_mipi_phy0.bit.shutdownz = 0; + phy_reg.isp_mipi_phy0.bit.rstz = 0; + isp4hw_wreg(base, + (uintptr_t)(&isp_mipi_phy_reg[phy_id]->isp_mipi_phy0), + phy_reg.isp_mipi_phy0.value); + + return 0; +} diff --git a/drivers/media/platform/amd/isp4/isp4_phy.h b/drivers/media/platform/amd/isp4/isp4_phy.h new file mode 100644 index 000000000000..2909892dbd00 --- /dev/null +++ b/drivers/media/platform/amd/isp4/isp4_phy.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#ifndef _ISP4_PHY_H_ +#define _ISP4_PHY_H_ + +int isp4phy_start(struct device *dev, + void __iomem *base, u32 phy_id, u64 bit_rate, + u32 lane_num); +int isp4phy_stop(void __iomem *base, u32 phy_id); + +#endif From patchwork Wed Jun 18 09:19:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Du, Bin" X-Patchwork-Id: 897812 Received: from NAM11-CO1-obe.outbound.protection.outlook.com (mail-co1nam11on2056.outbound.protection.outlook.com [40.107.220.56]) (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 CE2DE283FEA; Wed, 18 Jun 2025 09:20:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.220.56 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238449; cv=fail; b=KhpN/MeXd9Y/cN1TyHY+KBvPo2hB/s/AgVYw0DIm7QXx5O3YXdpEzgLMt0OAknJTV+p+VZPXKV1h8TA9YIenE60LjdwklFCwrPMdmPRd3gtGqUYD9HosBbOeWuWScUCUM7iMFA670dQWQXBs9KVb3McOrjSOW7iii5U6auMisNU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238449; c=relaxed/simple; bh=8RGI2avAOrJZeWnP83Hb+6sEcHEyADS6EmDroAwTRVA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=K6b2yYDD8jvN5hlMC1hR15UQ9mArieUXuYp/OV1T+HBj8L3rSPZwevb3jNGOtxA3WkuTFoelZ8KZkZHVere5hrwQPsH5Y8VOrlu0HfbnSLPnc7QYUv3F4BEjDV0eEM0XOd75HIEPxF5uarliiq/wxHUvosUeESG1xX0I9IMikts= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=ghhzvYfw; arc=fail smtp.client-ip=40.107.220.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="ghhzvYfw" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=UNsuPm/CuWHyBgbr2+Th0O7CTVC6uotLb1nuG+ZQt+dBwaJkL/IWgTNcWhYYOPtWalmQZ+LiV/Qow8SAE1Mx4CsOx46inAmVP5+t28V4CH+N3iMeTK6zvhaMeBhlkP9vWTb9nEebzg00i5qjAvHvyb1PMeVFMUnV5UU8sDYFby1lRfNF27LrL6N5FGROwSKouue19AhqMF+D02x+h5XdnUTkxfkFbFUoX5I8sUFRYgdj35xb574R3c2bNr5tKBwKR8MWgNALWGTqBQ68aYwN4QY0eGt2OWZYY/J3377gpgM0z951xtUPr68u/DEaFi3OLlscw3fVqJ6tjR7Wa5mijw== 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=cYJDAbd6MWnKQALyVtBraNnR5csLW9E25lon+uYZX58=; b=Yibmc/r2apqo7ski6io80Axa+eFQ3QNdMOf0SSjSa2iZC9Z2TfufBFzrBgSRYZ0EpZI8gEDTD8R1nqIE7mOG1eGdvgGIXmTL7bHg9ehBbVcvoZyCGUfXtTsMEuvf41HhDzivcGuuLq+hjjwPRJ6wjtr7zxgz29PxvwIHiRDPJuKMDMEwPLFzblIxgXVWlX47XUYSa4LxOESmz3a6sD041Bv+o4tU77pyccUtowjAc6WlpIgURfjUNYfbKRMvYOG17ydwvLgmqL6XgalRFM+G2bhDVILsm0unOjBFYVtTPVm8F2/OLiMz7maDCEUo03e/5UuqjH1ZC2DhyiI1f/FJbA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=cYJDAbd6MWnKQALyVtBraNnR5csLW9E25lon+uYZX58=; b=ghhzvYfwx1USrLb/bJFsY8Ut2n+OY6NeHCZt6i2az9ZHGz6HMLyDFFY4Y/RGAsZxiSThcjXFekF59BblllsIeJMwbeLjQC3pZtSfcXr5aALlsKBjGthjzMem7xG2xRZfkhy/1MyLgwEjlBy8FAIA4eEm362c//3uVr7hQWzprgg= Received: from BN0PR02CA0057.namprd02.prod.outlook.com (2603:10b6:408:e5::32) by IA1PR12MB6531.namprd12.prod.outlook.com (2603:10b6:208:3a4::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8835.30; Wed, 18 Jun 2025 09:20:39 +0000 Received: from BN3PEPF0000B372.namprd21.prod.outlook.com (2603:10b6:408:e5:cafe::a2) by BN0PR02CA0057.outlook.office365.com (2603:10b6:408:e5::32) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8835.25 via Frontend Transport; Wed, 18 Jun 2025 09:20:39 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by BN3PEPF0000B372.mail.protection.outlook.com (10.167.243.169) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8880.0 via Frontend Transport; Wed, 18 Jun 2025 09:20:39 +0000 Received: from 555e2b870847.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 18 Jun 2025 04:20:33 -0500 From: Bin Du To: , , , , , , , CC: , , , , , , , , "Bin Du" Subject: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added Date: Wed, 18 Jun 2025 17:19:56 +0800 Message-ID: <20250618091959.68293-6-Bin.Du@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250618091959.68293-1-Bin.Du@amd.com> References: <20250618091959.68293-1-Bin.Du@amd.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN3PEPF0000B372:EE_|IA1PR12MB6531:EE_ X-MS-Office365-Filtering-Correlation-Id: b0933da5-6048-407c-9420-08ddae49645f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|82310400026|36860700013|1800799024|376014; X-Microsoft-Antispam-Message-Info: E1nEIvDokEWaL59a4xgUgWZIGtE/ss+MCjtM5rkBdUI7Ctohr1rMdkz5lZdyeqbSy1kVRf8+Im/ObdTF4DRGOrCLuJtGMwl1plSeHpHGBqMNnf95xKl2SO7MiNbGd70bp/aTHpknFvD0OVBJEwC4HqTpDEPwXsf7gux3Ie1vgzBzX7MzPadR0py2QhkLev9Q//0LcA+71HmL513ZlLfNwY8Khu5SB1hi/9jHhUdA8LjLtehksF8sum685NUUmz+4NnE09Sj+J0sY/p2dyXXtG/PWUSI/r8ef6+oMsoE9HkiOKKnAkWvrOVC2/eJL7QxBdHaIXI1EWEh1LlgJw9w9KR9ZBUj8uI2jWEiQSn2ajtNmeAHaZAg/w3DcfIr3sb2TnrGHzb7IOtr9MEGV9OISgVELrpPoRjtWWv1MB9sKK8rFv5jGFn9wgzaxBWZwh5mJedcvRhc3XouxnesX9FiCokt4jDWG/biLzjKVTuAAaWGGK1F7TB86jEIn1PwItckz8fy84iK0wim7PXLPoP5c27gG09KR8m6cDYIh/lqU1XG97AqYy6Pj/rFBzK7xkJkk9bGWgbFZi1Ql8JLcF2FE0fF1VggImIGWBU0QHLShcDZTZbvZE/gjxX78ae65FsbCaj2mqxskY7EKvJshKBEOLOafMpS3CE7CPUswJdpebLvI2s3J2j3pQSVU62heSeLiTeS/2Jnn9+Ln0EJXHN8RpEsrg60dkBWgeuAEmG+4RCUkYY7VEL9HMbUhTjK3oNf9scH+ePyoQyII3Mv9EyYS+dP6sKpLyB/B81BArcrVCuhwrjjF/ZwFz6h2gYrZiF6aNlJIihGnJT6NYGfbRy2OIu3Z9jofOC/o04xCBjmND95MZNhWyxRosYFsyNZZjmLU/SkmYRL5QFp5udmvrZiRhkyPapgXuy6W2UbVy9bwD9Feuj+2HNX634ZrZUklOgM0lIZTpduwn2xq9FHO09/V9zqMQP9/qXi51lb5jWNAbYnDoTirzjtsvkRV/8Al3GKrF9fduq8juARAWSiB4rdJMpOQVcKsHfm9W+Hh8TRTSw/AJAtizWopFZwzvXRyN64FDYmnH/ZHbexti5iDxbOblcmYLHReQc4oLEi6PYNlfpOKYuBWUse9wmv5wC2AFRrz/V1N7mw1jNB5nkNhtEutsJKOh6A+ehCJymblBKty1k+ofrb+Eri2tS3MTCA83FXS/pdoKlDwBqpmqq++7wYqVQz/XdKfYo4LonavJlk0/+txrPeuE0/EvqAAmnQSNohPPmLaKY78MylbrHzMrFXhbG02JLlRlP20wO7DO9n83cM17LxPhx4eGq90FcPkSejaPbkBLn16goiSUPhGwYAbsGvDZcRgSc6dpDJH1DU5XLFWIa3F9GtUFoA3k/3VWHV2y+0RP7MvFCGQYhNpoL40M8Yua91gMq5wHhPd7OxotwDSjLWc5cvT+k2UV6veAu/j805U7CMiP0inVA7LT2YS4DGx4M0LCX079fBKnlx13r/jNhGBOjcuYYXqKbyeUw2Q X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230040)(82310400026)(36860700013)(1800799024)(376014); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jun 2025 09:20:39.5881 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b0933da5-6048-407c-9420-08ddae49645f X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BN3PEPF0000B372.namprd21.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: IA1PR12MB6531 Isp4 sub-device is implementing v4l2 sub-device interface. It has one capture video node, and supports only preview stream. It manages firmware states, stream configuration and mipi phy configuration. This change also adds interrupt handling and notification for isp firmware to isp-subdevice. Signed-off-by: Bin Du Signed-off-by: Svetoslav Stoilov --- drivers/media/platform/amd/isp4/Makefile | 3 +- drivers/media/platform/amd/isp4/isp4.c | 267 +++- drivers/media/platform/amd/isp4/isp4.h | 4 +- drivers/media/platform/amd/isp4/isp4_subdev.c | 1192 +++++++++++++++++ drivers/media/platform/amd/isp4/isp4_subdev.h | 145 ++ 5 files changed, 1601 insertions(+), 10 deletions(-) create mode 100644 drivers/media/platform/amd/isp4/isp4_subdev.c create mode 100644 drivers/media/platform/amd/isp4/isp4_subdev.h diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile index c0166f954516..52defc06189e 100644 --- a/drivers/media/platform/amd/isp4/Makefile +++ b/drivers/media/platform/amd/isp4/Makefile @@ -3,9 +3,10 @@ # Copyright (C) 2025 Advanced Micro Devices, Inc. obj-$(CONFIG_AMD_ISP4) += amd_capture.o -amd_capture-objs := isp4.o \ +amd_capture-objs := isp4_subdev.o \ isp4_phy.o \ isp4_interface.o \ + isp4.o \ isp4_hw.o \ ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4 diff --git a/drivers/media/platform/amd/isp4/isp4.c b/drivers/media/platform/amd/isp4/isp4.c index d0be90c5ec3b..c1aca2bd35e3 100644 --- a/drivers/media/platform/amd/isp4/isp4.c +++ b/drivers/media/platform/amd/isp4/isp4.c @@ -5,13 +5,20 @@ #include #include +#include #include -#include "isp4.h" +#include "amdgpu_object.h" -#define VIDEO_BUF_NUM 5 +#include "isp4.h" +#include "isp4_hw.h" #define ISP4_DRV_NAME "amd_isp_capture" +#define ISP4_FW_RESP_RB_IRQ_STATUS_MASK \ + (ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK | \ + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK | \ + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK | \ + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK) /* interrupt num */ static const u32 isp4_ringbuf_interrupt_num[] = { @@ -24,23 +31,233 @@ static const u32 isp4_ringbuf_interrupt_num[] = { #define to_isp4_device(dev) \ ((struct isp4_device *)container_of(dev, struct isp4_device, v4l2_dev)) +static int isp4_create_links(struct isp4_device *isp4_dev, + struct v4l2_subdev *sensor_sdev) +{ + struct v4l2_subdev *isp4_sdev = &isp4_dev->isp_sdev.sdev; + struct device *dev = &isp4_dev->pdev->dev; + int ret; + + ret = media_create_pad_link(&sensor_sdev->entity, + 0, &isp4_sdev->entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + dev_err(dev, "create sensor to isp link fail:%d\n", ret); + + return ret; +} + +static int isp4_register_subdev_and_create_links(struct isp4_device *isp_dev, + struct v4l2_subdev *sdev) +{ + struct device *dev = &isp_dev->pdev->dev; + int ret; + + ret = isp4_create_links(isp_dev, sdev); + if (ret) + dev_err(dev, "fail create isp link:%d\n", ret); + + ret = v4l2_device_register_subdev_nodes(&isp_dev->v4l2_dev); + if (ret != 0) { + dev_warn(dev, "register subdev as nodes fail:%d\n", ret); + ret = 0; + } + + return ret; +} + +static int isp4_camera_sensor_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sensor_sdev, + struct v4l2_async_connection *asd) +{ + struct isp4_device *isp_dev = to_isp4_device(notifier->v4l2_dev); + struct device *dev = &isp_dev->pdev->dev; + int ret; + + ret = isp4_register_subdev_and_create_links(isp_dev, sensor_sdev); + if (ret) + dev_err(dev, "register sensor subdev fail:%d\n", + ret); + else + dev_dbg(dev, "register sensor subdev suc\n"); + return ret; +} + +static void isp4_camera_sensor_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sensor_sdev, + struct v4l2_async_connection *asd) +{ +} + +static const struct v4l2_async_notifier_operations isp4_camera_sensor_ops = { + .bound = isp4_camera_sensor_bound, + .unbind = isp4_camera_sensor_unbind, +}; + +static void isp4_wake_up_resp_thread(struct isp4_subdev *isp, u32 index) +{ + if (isp && index < ISP4SD_MAX_FW_RESP_STREAM_NUM) { + struct isp4sd_thread_handler *thread_ctx = + &isp->fw_resp_thread[index]; + + thread_ctx->wq_cond = 1; + wake_up_interruptible(&thread_ctx->waitq); + } +} + +static void isp4_resp_interrupt_notify(struct isp4_subdev *isp, u32 intr_status) +{ + bool wake = (isp->ispif.status == ISP4IF_STATUS_FW_RUNNING); + + u32 intr_ack = 0; + + /* global response */ + if (intr_status & + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK) { + if (wake) + isp4_wake_up_resp_thread(isp, 0); + + intr_ack |= ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK; + } + + /* stream 1 response */ + if (intr_status & + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK) { + if (wake) + isp4_wake_up_resp_thread(isp, 1); + + intr_ack |= ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK; + } + + /* stream 2 response */ + if (intr_status & + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK) { + if (wake) + isp4_wake_up_resp_thread(isp, 2); + + intr_ack |= ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT10_ACK_MASK; + } + + /* stream 3 response */ + if (intr_status & + ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK) { + if (wake) + isp4_wake_up_resp_thread(isp, 3); + + intr_ack |= ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT11_ACK_MASK; + } + + /* clear ISP_SYS interrupts */ + isp4hw_wreg(ISP4_GET_ISP_REG_BASE(isp), ISP_SYS_INT0_ACK, intr_ack); +} + static irqreturn_t isp4_irq_handler(int irq, void *arg) { - struct isp4_device *isp_dev = dev_get_drvdata((struct device *)arg); + struct isp4_device *isp_dev = dev_get_drvdata(arg); + struct isp4_subdev *isp = NULL; + u32 isp_sys_irq_status = 0x0; + u32 r1; if (!isp_dev) - goto error_drv_data; + return IRQ_HANDLED; + + isp = &isp_dev->isp_sdev; + /* check ISP_SYS interrupts status */ + r1 = isp4hw_rreg(ISP4_GET_ISP_REG_BASE(isp), ISP_SYS_INT0_STATUS); + + isp_sys_irq_status = r1 & ISP4_FW_RESP_RB_IRQ_STATUS_MASK; + + isp4_resp_interrupt_notify(isp, isp_sys_irq_status); -error_drv_data: return IRQ_HANDLED; } +static int isp4_parse_fwnode_init_async_nf(struct isp4_device *isp_dev) +{ + struct isp4_subdev *isp_sdev = &isp_dev->isp_sdev; + struct device *dev = &isp_dev->pdev->dev; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *remote_ep = NULL; + struct fwnode_handle *local_ep = NULL; + struct v4l2_async_connection *asd; + struct fwnode_handle *fwnode; + struct fwnode_endpoint fwep; + int ret; + + fwnode = dev_fwnode(dev); + + local_ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!local_ep) { + ret = -ENXIO; + goto err_fwnode; + } + + remote_ep = fwnode_graph_get_remote_endpoint(local_ep); + if (!remote_ep) { + ret = -ENXIO; + goto err_fwnode; + } + + ret = fwnode_graph_parse_endpoint(remote_ep, &fwep); + if (ret) + goto err_fwnode; + isp_sdev->phy_id = fwep.port; + + ret = v4l2_fwnode_endpoint_alloc_parse(remote_ep, &bus_cfg); + if (ret) + goto err_fwnode; + + if (!bus_cfg.nr_of_link_frequencies) { + ret = -EINVAL; + dev_err(dev, "fail invalid link freq number %u\n", bus_cfg.nr_of_link_frequencies); + v4l2_fwnode_endpoint_free(&bus_cfg); + goto err_fwnode; + } + isp_sdev->phy_link_freq = *bus_cfg.link_frequencies; + v4l2_fwnode_endpoint_free(&bus_cfg); + + isp_sdev->phy_num_data_lanes = + fwnode_property_count_u32(remote_ep, "data-lanes"); + + v4l2_async_nf_init(&isp_dev->notifier, &isp_dev->v4l2_dev); + + asd = v4l2_async_nf_add_fwnode(&isp_dev->notifier, remote_ep, + struct v4l2_async_connection); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto err_async_nf_cleanup; + } + + isp_dev->notifier.ops = &isp4_camera_sensor_ops; + ret = v4l2_async_nf_register(&isp_dev->notifier); + if (ret) { + dev_err(dev, "v4l2_async_nf_register fail:%d", ret); + goto err_async_nf_cleanup; + } + + return 0; + +err_async_nf_cleanup: + v4l2_async_nf_cleanup(&isp_dev->notifier); +err_fwnode: + if (remote_ep) + fwnode_handle_put(remote_ep); + if (local_ep) + fwnode_handle_put(remote_ep); + + return ret; +} + /* * amd capture module */ static int isp4_capture_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct isp4_subdev *isp_sdev; struct isp4_device *isp_dev; int i, irq, ret; @@ -52,6 +269,17 @@ static int isp4_capture_probe(struct platform_device *pdev) isp_dev->pdev = pdev; dev->init_name = ISP4_DRV_NAME; + isp_sdev = &isp_dev->isp_sdev; + isp_sdev->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(isp_sdev->mmio)) + return dev_err_probe(dev, PTR_ERR(isp_sdev->mmio), + "isp ioremap fail\n"); + + isp_sdev->isp_phy_mmio = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(isp_sdev->isp_phy_mmio)) + return dev_err_probe(dev, PTR_ERR(isp_sdev->isp_phy_mmio), + "isp phy mmio ioremap fail\n"); + for (i = 0; i < ARRAY_SIZE(isp4_ringbuf_interrupt_num); i++) { irq = platform_get_irq(pdev, isp4_ringbuf_interrupt_num[i]); if (irq < 0) @@ -90,10 +318,23 @@ static int isp4_capture_probe(struct platform_device *pdev) dev_dbg(dev, "AMD ISP v4l2 device registered\n"); + ret = isp4sd_init(&isp_dev->isp_sdev, &isp_dev->v4l2_dev, + isp_dev->pltf_data->adev); + if (ret) { + dev_err(dev, "fail init isp4 sub dev %d\n", ret); + goto err_unreg_v4l2; + } + + ret = isp4_parse_fwnode_init_async_nf(isp_dev); + if (ret) { + dev_err(dev, "fail to parse fwnode %d\n", ret); + goto err_unreg_v4l2; + } + ret = media_device_register(&isp_dev->mdev); if (ret) { dev_err(dev, "fail to register media device %d\n", ret); - goto err_unreg_v4l2; + goto err_isp4_deinit; } platform_set_drvdata(pdev, isp_dev); @@ -103,6 +344,10 @@ static int isp4_capture_probe(struct platform_device *pdev) return 0; +err_isp4_deinit: + v4l2_async_nf_unregister(&isp_dev->notifier); + v4l2_async_nf_cleanup(&isp_dev->notifier); + isp4sd_deinit(&isp_dev->isp_sdev); err_unreg_v4l2: v4l2_device_unregister(&isp_dev->v4l2_dev); @@ -112,11 +357,17 @@ static int isp4_capture_probe(struct platform_device *pdev) static void isp4_capture_remove(struct platform_device *pdev) { struct isp4_device *isp_dev = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; + + v4l2_async_nf_unregister(&isp_dev->notifier); + v4l2_async_nf_cleanup(&isp_dev->notifier); + v4l2_device_unregister_subdev(&isp_dev->isp_sdev.sdev); media_device_unregister(&isp_dev->mdev); + media_entity_cleanup(&isp_dev->isp_sdev.sdev.entity); v4l2_device_unregister(&isp_dev->v4l2_dev); - dev_dbg(dev, "AMD ISP v4l2 device unregistered\n"); + dev_dbg(&pdev->dev, "AMD ISP v4l2 device unregistered\n"); + + isp4sd_deinit(&isp_dev->isp_sdev); } static struct platform_driver isp4_capture_drv = { diff --git a/drivers/media/platform/amd/isp4/isp4.h b/drivers/media/platform/amd/isp4/isp4.h index 27a7362ce6f9..596431b4a5c2 100644 --- a/drivers/media/platform/amd/isp4/isp4.h +++ b/drivers/media/platform/amd/isp4/isp4.h @@ -7,9 +7,9 @@ #define _ISP4_H_ #include -#include #include #include +#include "isp4_subdev.h" #define ISP4_GET_ISP_REG_BASE(isp4sd) (((isp4sd))->mmio) @@ -25,11 +25,13 @@ struct isp4_platform_data { struct isp4_device { struct v4l2_device v4l2_dev; + struct isp4_subdev isp_sdev; struct media_device mdev; struct isp4_platform_data *pltf_data; struct platform_device *pdev; struct notifier_block i2c_nb; + struct v4l2_async_notifier notifier; }; #endif /* isp4.h */ diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.c b/drivers/media/platform/amd/isp4/isp4_subdev.c new file mode 100644 index 000000000000..978164031067 --- /dev/null +++ b/drivers/media/platform/amd/isp4/isp4_subdev.c @@ -0,0 +1,1192 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "isp4_fw_cmd_resp.h" +#include "isp4_hw.h" +#include "isp4_interface.h" +#include "isp4_phy.h" +#include "isp4_subdev.h" +#include + +#define ISP4SD_MAX_CMD_RESP_BUF_SIZE (4 * 1024) +#define ISP4SD_MIN_BUF_CNT_BEF_START_STREAM 4 + +#define ISP4SD_PERFORMANCE_STATE_LOW 0 +#define ISP4SD_PERFORMANCE_STATE_HIGH 1 + +#define ISP4SD_FW_CMD_TIMEOUT_IN_MS 500 +#define ISP4SD_WAIT_RESP_IRQ_TIMEOUT 5 /* ms */ +/* align 32KB */ +#define ISP4SD_META_BUF_SIZE ALIGN(sizeof(struct isp4fw_meta_info), 0x8000) + +#define to_isp4_subdev(v4l2_sdev) \ + container_of(v4l2_sdev, struct isp4_subdev, sdev) + +#define to_isp4_vdev(isp4_vid) \ + container_of(isp4_vid, struct isp4_subdev, isp_vdev) + +static const char *isp4sd_entity_name = "amd isp4"; + +struct isp4sd_mbus_image_format_remap { + u32 mbus_code; + enum isp4fw_image_format image_format; +}; + +static const struct isp4sd_mbus_image_format_remap + isp4sd_image_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1_5X8, + .image_format = IMAGE_FORMAT_NV12, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .image_format = IMAGE_FORMAT_YUV422INTERLEAVED, + }, +}; + +static void isp4sd_module_enable(struct isp4_subdev *isp_subdev, bool enable) +{ + if (isp_subdev->enable_gpio) { + gpiod_set_value(isp_subdev->enable_gpio, enable ? 1 : 0); + dev_dbg(isp_subdev->dev, "%s isp_subdev module\n", + enable ? "enable" : "disable"); + } +} + +static int isp4sd_setup_fw_mem_pool(struct isp4_subdev *isp_subdev) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4fw_cmd_send_buffer buf_type; + struct device *dev = isp_subdev->dev; + int ret; + + if (!ispif->fw_mem_pool) { + dev_err(dev, "fail to alloc mem pool\n"); + return -ENOMEM; + } + + memset(&buf_type, 0, sizeof(buf_type)); + buf_type.buffer_type = BUFFER_TYPE_MEM_POOL; + buf_type.buffer.buf_tags = 0; + buf_type.buffer.vmid_space.bit.vmid = 0; + buf_type.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA; + isp4if_split_addr64(ispif->fw_mem_pool->gpu_mc_addr, + &buf_type.buffer.buf_base_a_lo, + &buf_type.buffer.buf_base_a_hi); + buf_type.buffer.buf_size_a = (u32)ispif->fw_mem_pool->mem_size; + + ret = isp4if_send_command(ispif, CMD_ID_SEND_BUFFER, + &buf_type, sizeof(buf_type)); + if (ret) { + dev_err(dev, "send fw mem pool 0x%llx(%u) fail %d\n", + ispif->fw_mem_pool->gpu_mc_addr, + buf_type.buffer.buf_size_a, + ret); + return ret; + } + + dev_dbg(dev, "send fw mem pool 0x%llx(%u) suc\n", + ispif->fw_mem_pool->gpu_mc_addr, + buf_type.buffer.buf_size_a); + + return 0; +}; + +static int isp4sd_set_stream_path(struct isp4_subdev *isp_subdev) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4fw_cmd_set_stream_cfg cmd = {0}; + struct device *dev = isp_subdev->dev; + + cmd.stream_cfg.mipi_pipe_path_cfg.isp4fw_sensor_id = SENSOR_ID_ON_MIPI0; + cmd.stream_cfg.mipi_pipe_path_cfg.b_enable = true; + cmd.stream_cfg.isp_pipe_path_cfg.isp_pipe_id = MIPI0_ISP_PIPELINE_ID; + + cmd.stream_cfg.b_enable_tnr = true; + dev_dbg(dev, "isp4fw_sensor_id %d, pipeId 0x%x EnableTnr %u\n", + cmd.stream_cfg.mipi_pipe_path_cfg.isp4fw_sensor_id, + cmd.stream_cfg.isp_pipe_path_cfg.isp_pipe_id, + cmd.stream_cfg.b_enable_tnr); + + return isp4if_send_command(ispif, CMD_ID_SET_STREAM_CONFIG, + &cmd, sizeof(cmd)); +} + +static int isp4sd_send_meta_buf(struct isp4_subdev *isp_subdev) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4fw_cmd_send_buffer buf_type = { 0 }; + struct isp4sd_sensor_info *sensor_info; + struct device *dev = isp_subdev->dev; + u32 i; + + sensor_info = &isp_subdev->sensor_info; + for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) { + int ret; + + if (!sensor_info->meta_info_buf[i]) { + dev_err(dev, "fail for no meta info buf(%u)\n", i); + return -ENOMEM; + } + buf_type.buffer_type = BUFFER_TYPE_META_INFO; + buf_type.buffer.buf_tags = 0; + buf_type.buffer.vmid_space.bit.vmid = 0; + buf_type.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA; + isp4if_split_addr64(sensor_info->meta_info_buf[i]->gpu_mc_addr, + &buf_type.buffer.buf_base_a_lo, + &buf_type.buffer.buf_base_a_hi); + buf_type.buffer.buf_size_a = + (u32)sensor_info->meta_info_buf[i]->mem_size; + ret = isp4if_send_command(ispif, CMD_ID_SEND_BUFFER, + &buf_type, + sizeof(buf_type)); + if (ret) { + dev_err(dev, "send meta info(%u) fail\n", i); + return ret; + } + } + + dev_dbg(dev, "send meta info suc\n"); + return 0; +} + +static int isp4sd_enum_mbus_code(struct v4l2_subdev *isp_subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(isp4sd_image_formats)) + return -EINVAL; + + code_enum->code = isp4sd_image_formats[code_enum->index].mbus_code; + + return 0; +} + +static bool isp4sd_get_str_out_prop(struct isp4_subdev *isp_subdev, + struct isp4fw_image_prop *out_prop, + struct v4l2_subdev_state *state, u32 pad) +{ + struct v4l2_mbus_framefmt *format = NULL; + struct device *dev = isp_subdev->dev; + bool ret; + + format = v4l2_subdev_state_get_format(state, pad, 0); + if (!format) { + dev_err(dev, "fail get subdev state format\n"); + return false; + } + + switch (format->code) { + case MEDIA_BUS_FMT_YUYV8_1_5X8: + out_prop->image_format = IMAGE_FORMAT_NV12; + out_prop->width = format->width; + out_prop->height = format->height; + out_prop->luma_pitch = format->width; + out_prop->chroma_pitch = out_prop->width; + ret = true; + break; + case MEDIA_BUS_FMT_YUYV8_1X16: + out_prop->image_format = IMAGE_FORMAT_YUV422INTERLEAVED; + out_prop->width = format->width; + out_prop->height = format->height; + out_prop->luma_pitch = format->width * 2; + out_prop->chroma_pitch = 0; + ret = true; + break; + default: + dev_err(dev, "fail for bad image format:0x%x\n", + format->code); + ret = false; + break; + } + + if (!out_prop->width || !out_prop->height) + ret = false; + return ret; +} + +static int isp4sd_kickoff_stream(struct isp4_subdev *isp_subdev, u32 w, u32 h) +{ + struct isp4sd_sensor_info *sensor_info = &isp_subdev->sensor_info; + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + + if (sensor_info->status == ISP4SD_START_STATUS_STARTED) { + return 0; + } else if (sensor_info->status == ISP4SD_START_STATUS_START_FAIL) { + dev_err(dev, "fail for previous start fail\n"); + return -EINVAL; + } + + dev_dbg(dev, "w:%u,h:%u\n", w, h); + + sensor_info->status = ISP4SD_START_STATUS_START_FAIL; + + if (isp4sd_send_meta_buf(isp_subdev)) { + dev_err(dev, "fail to send meta buf\n"); + return -EINVAL; + }; + + sensor_info->status = ISP4SD_START_STATUS_NOT_START; + + if (!sensor_info->start_stream_cmd_sent && + sensor_info->buf_sent_cnt >= + ISP4SD_MIN_BUF_CNT_BEF_START_STREAM) { + int ret = isp4if_send_command(ispif, CMD_ID_START_STREAM, + NULL, 0); + if (ret) { + dev_err(dev, "fail to start stream\n"); + return ret; + } + + sensor_info->start_stream_cmd_sent = true; + } else { + dev_dbg(dev, + "no send START_STREAM, start_sent %u, buf_sent %u\n", + sensor_info->start_stream_cmd_sent, + sensor_info->buf_sent_cnt); + } + + return 0; +} + +static int isp4sd_setup_output(struct isp4_subdev *isp_subdev, + struct v4l2_subdev_state *state, u32 pad) +{ + struct isp4sd_sensor_info *sensor_info = &isp_subdev->sensor_info; + struct isp4sd_output_info *output_info = + &isp_subdev->sensor_info.output_info; + struct isp4fw_cmd_set_out_ch_prop cmd_ch_prop = {0}; + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4fw_cmd_enable_out_ch cmd_ch_en = {0}; + struct device *dev = isp_subdev->dev; + struct isp4fw_image_prop *out_prop; + int ret; + + if (output_info->start_status == ISP4SD_START_STATUS_STARTED) + return 0; + + if (output_info->start_status == ISP4SD_START_STATUS_START_FAIL) { + dev_err(dev, "fail for previous start fail\n"); + return -EINVAL; + } + + out_prop = &cmd_ch_prop.image_prop; + cmd_ch_prop.ch = ISP_PIPE_OUT_CH_PREVIEW; + cmd_ch_en.ch = ISP_PIPE_OUT_CH_PREVIEW; + cmd_ch_en.is_enable = true; + + if (!isp4sd_get_str_out_prop(isp_subdev, out_prop, state, pad)) { + dev_err(dev, "fail to get out prop\n"); + return -EINVAL; + } + + dev_dbg(dev, "channel: w:h=%u:%u,lp:%u,cp%u\n", + cmd_ch_prop.image_prop.width, cmd_ch_prop.image_prop.height, + cmd_ch_prop.image_prop.luma_pitch, + cmd_ch_prop.image_prop.chroma_pitch); + + ret = isp4if_send_command(ispif, CMD_ID_SET_OUT_CHAN_PROP, + &cmd_ch_prop, + sizeof(cmd_ch_prop)); + if (ret) { + output_info->start_status = ISP4SD_START_STATUS_START_FAIL; + dev_err(dev, "fail to set out prop\n"); + return ret; + }; + + ret = isp4if_send_command(ispif, CMD_ID_ENABLE_OUT_CHAN, + &cmd_ch_en, sizeof(cmd_ch_en)); + + if (ret) { + output_info->start_status = ISP4SD_START_STATUS_START_FAIL; + dev_err(dev, "fail to enable channel\n"); + return ret; + } + + if (!sensor_info->start_stream_cmd_sent) { + ret = isp4sd_kickoff_stream(isp_subdev, out_prop->width, + out_prop->height); + if (ret) { + dev_err(dev, "kickoff stream fail %d\n", ret); + return ret; + } + /* sensor_info->start_stream_cmd_sent will be set to true + * 1. in isp4sd_kickoff_stream, if app first send buffer then + * start stream + * 2. in isp_set_stream_buf, if app first start stream, then + * send buffer + * because ISP FW has the requirement, host needs to send buffer + * before send start stream cmd + */ + if (sensor_info->start_stream_cmd_sent) { + sensor_info->status = ISP4SD_START_STATUS_STARTED; + output_info->start_status = ISP4SD_START_STATUS_STARTED; + dev_dbg(dev, "kickoff stream suc,start cmd sent\n"); + } else { + dev_dbg(dev, "kickoff stream suc,start cmd not sent\n"); + } + } else { + dev_dbg(dev, "stream running, no need kickoff\n"); + output_info->start_status = ISP4SD_START_STATUS_STARTED; + } + + dev_dbg(dev, "setup output suc\n"); + return 0; +} + +static int isp4sd_alloc_meta_buf(struct isp4_subdev *isp_subdev) +{ + struct isp4sd_sensor_info *sensor_info = &isp_subdev->sensor_info; + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + u32 i; + + /* TODO: check alloc method */ + for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) { + if (!sensor_info->meta_info_buf[i]) { + sensor_info->meta_info_buf[i] = + ispif->metainfo_buf_pool[i]; + if (sensor_info->meta_info_buf[i]) { + dev_dbg(dev, "valid %u meta_info_buf ok\n", i); + } else { + dev_err(dev, + "invalid %u meta_info_buf fail\n", i); + return -ENOMEM; + } + } + } + + return 0; +} + +static int isp4sd_init_stream(struct isp4_subdev *isp_subdev) +{ + struct device *dev = isp_subdev->dev; + int ret; + + ret = isp4sd_setup_fw_mem_pool(isp_subdev); + if (ret) { + dev_err(dev, "fail to setup fw mem pool\n"); + return ret; + } + + ret = isp4sd_alloc_meta_buf(isp_subdev); + if (ret) { + dev_err(dev, "fail to alloc fw driver shared buf\n"); + return ret; + } + + ret = isp4sd_set_stream_path(isp_subdev); + if (ret) { + dev_err(dev, "fail to setup stream path\n"); + return ret; + } + + return 0; +} + +static void isp4sd_reset_stream_info(struct isp4_subdev *isp_subdev, + struct v4l2_subdev_state *state, u32 pad) +{ + struct isp4sd_sensor_info *sensor_info = &isp_subdev->sensor_info; + struct v4l2_mbus_framefmt *format = NULL; + struct isp4sd_output_info *str_info; + int i; + + format = v4l2_subdev_state_get_format(state, + pad, + 0); + + if (!format) { + pr_err("fail reset stream info for not get format\n"); + + } else { + memset(format, 0, sizeof(*format)); + format->code = MEDIA_BUS_FMT_YUYV8_1_5X8; + } + + for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) + sensor_info->meta_info_buf[i] = NULL; + + str_info = &sensor_info->output_info; + str_info->start_status = ISP4SD_START_STATUS_NOT_START; +} + +static bool isp4sd_is_stream_running(struct isp4_subdev *isp_subdev) +{ + struct isp4sd_sensor_info *sif; + enum isp4sd_start_status stat; + + sif = &isp_subdev->sensor_info; + stat = sif->output_info.start_status; + if (stat == ISP4SD_START_STATUS_STARTED) + return true; + + return false; +} + +static void isp4sd_reset_camera_info(struct isp4_subdev *isp_subdev, + struct v4l2_subdev_state *state, u32 pad) +{ + struct isp4sd_sensor_info *info = &isp_subdev->sensor_info; + + info->status = ISP4SD_START_STATUS_NOT_START; + isp4sd_reset_stream_info(isp_subdev, state, pad); + + info->start_stream_cmd_sent = false; +} + +static int isp4sd_uninit_stream(struct isp4_subdev *isp_subdev, + struct v4l2_subdev_state *state, u32 pad) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + bool running; + + running = isp4sd_is_stream_running(isp_subdev); + + if (running) { + dev_dbg(dev, "fail for stream is still running\n"); + return -EINVAL; + } + + isp4sd_reset_camera_info(isp_subdev, state, pad); + + isp4if_clear_cmdq(ispif); + return 0; +} + +static void isp4sd_fw_resp_cmd_done(struct isp4_subdev *isp_subdev, + enum isp4if_stream_id stream_id, + struct isp4fw_resp_cmd_done *para) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4if_cmd_element *ele = + isp4if_rm_cmd_from_cmdq(ispif, para->cmd_seq_num, para->cmd_id); + struct device *dev = isp_subdev->dev; + + dev_dbg(dev, "stream %d,cmd (0x%08x)(%d),seq %u, ele %p\n", + stream_id, + para->cmd_id, para->cmd_status, para->cmd_seq_num, + ele); + + if (!ele) + return; + + if (ele->wq) { + dev_dbg(dev, "signal event %p\n", ele->wq); + if (ele->wq_cond) + *ele->wq_cond = 1; + wake_up(ele->wq); + } + + kfree(ele); +} + +static struct isp4fw_meta_info * +isp4sd_get_meta_by_mc(struct isp4_subdev *isp_subdev, + u64 mc) +{ + u32 i; + + for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) { + struct isp4if_gpu_mem_info *meta_info_buf = + isp_subdev->sensor_info.meta_info_buf[i]; + + if (meta_info_buf) { + if (mc == meta_info_buf->gpu_mc_addr) + return meta_info_buf->sys_addr; + } + } + return NULL; +}; + +static struct isp4if_img_buf_node * +isp4sd_preview_done(struct isp4_subdev *isp_subdev, + struct isp4fw_meta_info *meta) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4if_img_buf_node *prev = NULL; + struct device *dev = isp_subdev->dev; + + if (!meta) { + dev_err(dev, "fail bad param for preview done\n"); + return prev; + } + + if (meta->preview.enabled && + (meta->preview.status == BUFFER_STATUS_SKIPPED || + meta->preview.status == BUFFER_STATUS_DONE || + meta->preview.status == BUFFER_STATUS_DIRTY)) { + prev = isp4if_dequeue_buffer(ispif); + if (!prev) + dev_err(dev, "fail null prev buf\n"); + + } else if (meta->preview.enabled) { + dev_err(dev, "fail bad preview status %u\n", + meta->preview.status); + } + + return prev; +} + +static void isp4sd_send_meta_info(struct isp4_subdev *isp_subdev, + u64 meta_info_mc) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4fw_cmd_send_buffer buf_type; + struct device *dev = isp_subdev->dev; + + if (isp_subdev->sensor_info.status != ISP4SD_START_STATUS_STARTED) { + dev_warn(dev, "not working status %i, meta_info 0x%llx\n", + isp_subdev->sensor_info.status, meta_info_mc); + return; + } + + if (meta_info_mc) { + memset(&buf_type, 0, sizeof(buf_type)); + buf_type.buffer_type = BUFFER_TYPE_META_INFO; + buf_type.buffer.buf_tags = 0; + buf_type.buffer.vmid_space.bit.vmid = 0; + buf_type.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA; + isp4if_split_addr64(meta_info_mc, + &buf_type.buffer.buf_base_a_lo, + &buf_type.buffer.buf_base_a_hi); + + buf_type.buffer.buf_size_a = ISP4SD_META_BUF_SIZE; + if (isp4if_send_command(ispif, CMD_ID_SEND_BUFFER, + &buf_type, sizeof(buf_type))) { + dev_err(dev, "fail send meta_info 0x%llx\n", + meta_info_mc); + } else { + dev_dbg(dev, "resend meta_info 0x%llx\n", meta_info_mc); + } + } +} + +static void isp4sd_fw_resp_frame_done(struct isp4_subdev *isp_subdev, + enum isp4if_stream_id stream_id, + struct isp4fw_resp_param_package *para) +{ + struct isp4if_img_buf_node *prev = NULL; + struct device *dev = isp_subdev->dev; + struct isp4fw_meta_info *meta; + u64 mc = 0; + + mc = isp4if_join_addr64(para->package_addr_lo, para->package_addr_hi); + meta = isp4sd_get_meta_by_mc(isp_subdev, mc); + if (mc == 0 || !meta) { + dev_err(dev, "fail to get meta from mc %llx\n", mc); + return; + } + + dev_dbg(dev, "ts:%llu,streamId:%d,poc:%u,preview_en:%u,(%i)\n", + ktime_get_ns(), stream_id, meta->poc, + meta->preview.enabled, + meta->preview.status); + + prev = isp4sd_preview_done(isp_subdev, meta); + + isp4if_dealloc_buffer_node(prev); + + if (isp_subdev->sensor_info.status == ISP4SD_START_STATUS_STARTED) + isp4sd_send_meta_info(isp_subdev, mc); + + dev_dbg(dev, "stream_id:%d, status:%d\n", stream_id, + isp_subdev->sensor_info.status); +} + +static void isp4sd_fw_resp_func(struct isp4_subdev *isp_subdev, + enum isp4if_stream_id stream_id) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + struct isp4fw_resp resp; + + if (ispif->status < ISP4IF_STATUS_FW_RUNNING) + return; + + while (true) { + s32 ret; + + ret = isp4if_f2h_resp(ispif, stream_id, &resp); + if (ret) + break; + + switch (resp.resp_id) { + case RESP_ID_CMD_DONE: + isp4sd_fw_resp_cmd_done(isp_subdev, stream_id, + &resp.param.cmd_done); + break; + case RESP_ID_NOTI_FRAME_DONE: + isp4sd_fw_resp_frame_done(isp_subdev, stream_id, + &resp.param.frame_done); + break; + default: + dev_err(dev, "-><- fail respid (0x%x)\n", + resp.resp_id); + break; + } + } +} + +static s32 isp4sd_fw_resp_thread_wrapper(void *context) +{ + struct isp4_subdev_thread_param *para = context; + struct isp4sd_thread_handler *thread_ctx; + enum isp4if_stream_id stream_id; + + struct isp4_subdev *isp_subdev; + struct device *dev; + u64 timeout; + + if (!para) + return -EINVAL; + + isp_subdev = para->isp_subdev; + dev = isp_subdev->dev; + + switch (para->idx) { + case 0: + stream_id = ISP4IF_STREAM_ID_GLOBAL; + break; + case 1: + stream_id = ISP4IF_STREAM_ID_1; + break; + default: + dev_err(dev, "fail invalid %d\n", para->idx); + return -EINVAL; + } + + thread_ctx = &isp_subdev->fw_resp_thread[para->idx]; + + thread_ctx->wq_cond = 0; + mutex_init(&thread_ctx->mutex); + init_waitqueue_head(&thread_ctx->waitq); + timeout = msecs_to_jiffies(ISP4SD_WAIT_RESP_IRQ_TIMEOUT); + + dev_dbg(dev, "[%u] started\n", para->idx); + + while (true) { + wait_event_interruptible_timeout(thread_ctx->waitq, + thread_ctx->wq_cond != 0, + timeout); + thread_ctx->wq_cond = 0; + + if (kthread_should_stop()) { + dev_dbg(dev, "[%u] quit\n", para->idx); + break; + } + + mutex_lock(&thread_ctx->mutex); + isp4sd_fw_resp_func(isp_subdev, stream_id); + mutex_unlock(&thread_ctx->mutex); + } + + mutex_destroy(&thread_ctx->mutex); + + return 0; +} + +static int isp4sd_start_resp_proc_threads(struct isp4_subdev *isp_subdev) +{ + struct device *dev = isp_subdev->dev; + int i; + + for (i = 0; i < ISP4SD_MAX_FW_RESP_STREAM_NUM; i++) { + struct isp4sd_thread_handler *thread_ctx = + &isp_subdev->fw_resp_thread[i]; + + isp_subdev->isp_resp_para[i].idx = i; + isp_subdev->isp_resp_para[i].isp_subdev = isp_subdev; + + thread_ctx->thread = kthread_run(isp4sd_fw_resp_thread_wrapper, + &isp_subdev->isp_resp_para[i], + "amd_isp4_thread"); + if (IS_ERR(thread_ctx->thread)) { + dev_err(dev, "create thread [%d] fail\n", i); + return -EINVAL; + } + } + + return 0; +} + +static int isp4sd_stop_resp_proc_threads(struct isp4_subdev *isp_subdev) +{ + int i; + + for (i = 0; i < ISP4SD_MAX_FW_RESP_STREAM_NUM; i++) { + struct isp4sd_thread_handler *thread_ctx = + &isp_subdev->fw_resp_thread[i]; + + if (thread_ctx->thread) { + kthread_stop(thread_ctx->thread); + thread_ctx->thread = NULL; + } + } + + return 0; +} + +static u32 isp4sd_get_started_stream_count(struct isp4_subdev *isp_subdev) +{ + u32 cnt = 0; + + if (isp_subdev->sensor_info.status == ISP4SD_START_STATUS_STARTED) + cnt++; + return cnt; +} + +static int isp4sd_pwroff_and_deinit(struct isp4_subdev *isp_subdev) +{ + struct isp4sd_sensor_info *sensor_info = &isp_subdev->sensor_info; + unsigned int perf_state = ISP4SD_PERFORMANCE_STATE_LOW; + struct isp4_interface *ispif = &isp_subdev->ispif; + + struct device *dev = isp_subdev->dev; + u32 cnt; + int ret; + + mutex_lock(&isp_subdev->ops_mutex); + + if (sensor_info->status == ISP4SD_START_STATUS_STARTED) { + dev_err(dev, "fail for stream still running\n"); + mutex_unlock(&isp_subdev->ops_mutex); + return -EINVAL; + } + + sensor_info->status = ISP4SD_START_STATUS_NOT_START; + cnt = isp4sd_get_started_stream_count(isp_subdev); + if (cnt > 0) { + dev_dbg(dev, "no need power off isp_subdev\n"); + mutex_unlock(&isp_subdev->ops_mutex); + return 0; + } + + isp4if_stop(ispif); + + ret = dev_pm_genpd_set_performance_state(dev, perf_state); + if (ret) + dev_err(dev, + "fail to set isp_subdev performance state %u,ret %d\n", + perf_state, ret); + isp4sd_stop_resp_proc_threads(isp_subdev); + dev_dbg(dev, "isp_subdev stop resp proc streads suc"); + /* hold ccpu reset */ + isp4hw_wreg(isp_subdev->mmio, ISP_SOFT_RESET, 0x0); + isp4hw_wreg(isp_subdev->mmio, ISP_POWER_STATUS, 0); + ret = pm_runtime_put_sync(dev); + if (ret) + dev_err(dev, "power off isp_subdev fail %d\n", ret); + else + dev_dbg(dev, "power off isp_subdev suc\n"); + + ispif->status = ISP4IF_STATUS_PWR_OFF; + isp4if_clear_cmdq(ispif); + isp4sd_module_enable(isp_subdev, false); + + msleep(20); + + mutex_unlock(&isp_subdev->ops_mutex); + + return 0; +} + +static int isp4sd_pwron_and_init(struct isp4_subdev *isp_subdev) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + int ret; + + if (ispif->status == ISP4IF_STATUS_FW_RUNNING) { + dev_dbg(dev, "camera already opened, do nothing\n"); + return 0; + } + + mutex_lock(&isp_subdev->ops_mutex); + + isp4sd_module_enable(isp_subdev, true); + + isp_subdev->sensor_info.start_stream_cmd_sent = false; + isp_subdev->sensor_info.buf_sent_cnt = 0; + + if (ispif->status < ISP4IF_STATUS_PWR_ON) { + unsigned int perf_state = ISP4SD_PERFORMANCE_STATE_HIGH; + + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(dev, "fail to power on isp_subdev ret %d\n", + ret); + goto err_unlock_and_close; + } + + /* ISPPG ISP Power Status */ + isp4hw_wreg(isp_subdev->mmio, ISP_POWER_STATUS, 0x7FF); + ret = dev_pm_genpd_set_performance_state(dev, perf_state); + if (ret) { + dev_err(dev, + "fail to set performance state %u, ret %d\n", + perf_state, ret); + goto err_unlock_and_close; + } + + ispif->status = ISP4IF_STATUS_PWR_ON; + + if (isp4sd_start_resp_proc_threads(isp_subdev)) { + dev_err(dev, "isp_start_resp_proc_threads fail"); + goto err_unlock_and_close; + } else { + dev_dbg(dev, "create resp threads ok"); + } + } + + isp_subdev->sensor_info.start_stream_cmd_sent = false; + isp_subdev->sensor_info.buf_sent_cnt = 0; + + ret = isp4if_start(ispif); + if (ret) { + dev_err(dev, "fail to start isp_subdev interface\n"); + goto err_unlock_and_close; + } + + mutex_unlock(&isp_subdev->ops_mutex); + return 0; +err_unlock_and_close: + mutex_unlock(&isp_subdev->ops_mutex); + isp4sd_pwroff_and_deinit(isp_subdev); + return -EINVAL; +} + +static int isp4sd_stop_stream(struct isp4_subdev *isp_subdev, + struct v4l2_subdev_state *state, u32 pad) +{ + struct isp4sd_output_info *output_info = + &isp_subdev->sensor_info.output_info; + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + int ret = 0; + + dev_dbg(dev, "status %i\n", output_info->start_status); + mutex_lock(&isp_subdev->ops_mutex); + + if (output_info->start_status == ISP4SD_START_STATUS_STARTED) { + struct isp4fw_cmd_enable_out_ch cmd_ch_disable; + + cmd_ch_disable.ch = ISP_PIPE_OUT_CH_PREVIEW; + cmd_ch_disable.is_enable = false; + ret = isp4if_send_command_sync(ispif, + CMD_ID_ENABLE_OUT_CHAN, + &cmd_ch_disable, + sizeof(cmd_ch_disable), + ISP4SD_FW_CMD_TIMEOUT_IN_MS); + if (ret) + dev_err(dev, "fail to disable stream\n"); + else + dev_dbg(dev, "wait disable stream suc\n"); + + ret = isp4if_send_command_sync(ispif, CMD_ID_STOP_STREAM, + NULL, + 0, + ISP4SD_FW_CMD_TIMEOUT_IN_MS); + if (ret) + dev_err(dev, "fail to stop steam\n"); + else + dev_dbg(dev, "wait stop stream suc\n"); + } + + isp4if_clear_bufq(ispif); + + output_info->start_status = ISP4SD_START_STATUS_NOT_START; + isp4sd_reset_stream_info(isp_subdev, state, pad); + + mutex_unlock(&isp_subdev->ops_mutex); + + isp4sd_uninit_stream(isp_subdev, state, pad); + + return ret; +} + +static int isp4sd_start_stream(struct isp4_subdev *isp_subdev, + struct v4l2_subdev_state *state, u32 pad) +{ + struct isp4sd_output_info *output_info = + &isp_subdev->sensor_info.output_info; + struct isp4_interface *ispif = &isp_subdev->ispif; + struct device *dev = isp_subdev->dev; + int ret; + + mutex_lock(&isp_subdev->ops_mutex); + + if (ispif->status != ISP4IF_STATUS_FW_RUNNING) { + mutex_unlock(&isp_subdev->ops_mutex); + dev_err(dev, "fail, bad fsm %d", ispif->status); + return -EINVAL; + } + + ret = isp4sd_init_stream(isp_subdev); + + if (ret) { + dev_err(dev, "fail to init isp_subdev stream\n"); + ret = -EINVAL; + goto unlock_and_check_ret; + } + + if (output_info->start_status == ISP4SD_START_STATUS_STARTED) { + ret = 0; + dev_dbg(dev, "stream started, do nothing\n"); + goto unlock_and_check_ret; + } else if (output_info->start_status == + ISP4SD_START_STATUS_START_FAIL) { + ret = -EINVAL; + dev_err(dev, "stream fail to start before\n"); + goto unlock_and_check_ret; + } + + if (isp4sd_setup_output(isp_subdev, state, pad)) { + dev_err(dev, "fail to setup output\n"); + ret = -EINVAL; + } else { + ret = 0; + dev_dbg(dev, "suc to setup out\n"); + } +unlock_and_check_ret: + mutex_unlock(&isp_subdev->ops_mutex); + if (ret) { + isp4sd_stop_stream(isp_subdev, state, pad); + dev_err(dev, "start stream fail\n"); + } else { + dev_dbg(dev, "start stream suc\n"); + } + + return ret; +} + +static int isp4sd_subdev_pre_streamon(struct v4l2_subdev *sd, u32 flags) +{ + struct isp4_subdev *isp_subdev = to_isp4_subdev(sd); + u64 phy_bit_rate = isp_subdev->phy_link_freq * isp_subdev->phy_num_data_lanes / HZ_PER_MHZ; + u32 num_data_lanes = isp_subdev->phy_num_data_lanes; + u32 phy_id = isp_subdev->phy_id; + int ret; + + ret = isp4phy_start(isp_subdev->dev, + isp_subdev->isp_phy_mmio, phy_id, + phy_bit_rate, num_data_lanes); + if (ret) { + dev_err(isp_subdev->dev, + "fail start phy,lane %d id %u bitrate %llu, %d\n", + num_data_lanes, phy_id, phy_bit_rate, ret); + return ret; + } + + dev_dbg(isp_subdev->dev, "start phy suc,lane %d id %u bit_rate %llu\n", + num_data_lanes, phy_id, phy_bit_rate); + + return ret; +} + +static int isp4sd_subdev_post_streamoff(struct v4l2_subdev *sd) +{ + struct isp4_subdev *isp_subdev = to_isp4_subdev(sd); + int ret; + + dev_dbg(isp_subdev->dev, "stopping phy %u\n", isp_subdev->phy_id); + ret = isp4phy_stop(isp_subdev->isp_phy_mmio, + isp_subdev->phy_id); + if (ret) + dev_err(isp_subdev->dev, "fail to stop the Phy:%d", ret); + + return ret; +} + +static int isp4sd_set_power(struct v4l2_subdev *sd, int on) +{ + struct isp4_subdev *ispsd = to_isp4_subdev(sd); + + if (on) + return isp4sd_pwron_and_init(ispsd); + else + return isp4sd_pwroff_and_deinit(ispsd); +}; + +static const struct v4l2_subdev_core_ops isp4sd_core_ops = { + .s_power = isp4sd_set_power, +}; + +static const struct v4l2_subdev_video_ops isp4sd_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, + .pre_streamon = isp4sd_subdev_pre_streamon, + .post_streamoff = isp4sd_subdev_post_streamoff, +}; + +static int isp4sd_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct isp4sd_output_info *steam_info = + &(to_isp4_subdev(sd)->sensor_info.output_info); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_state_get_format(sd_state, fmt->pad); + + if (!format) { + dev_err(sd->dev, "fail to get state format\n"); + return -EINVAL; + } + + *format = fmt->format; + switch (format->code) { + case MEDIA_BUS_FMT_YUYV8_1_5X8: + steam_info->image_size = format->width * format->height * 3 / 2; + break; + case MEDIA_BUS_FMT_YUYV8_1X16: + steam_info->image_size = format->width * format->height * 2; + break; + default: + steam_info->image_size = 0; + break; + } + if (!steam_info->image_size) { + dev_err(sd->dev, + "fail set pad format,code 0x%x,width %u, height %u\n", + format->code, format->width, format->height); + return -EINVAL; + } + dev_dbg(sd->dev, + "set pad format suc, code:%x w:%u h:%u size:%u\n", format->code, + format->width, format->height, steam_info->image_size); + + return 0; +} + +static int isp4sd_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct isp4_subdev *ispsd = to_isp4_subdev(sd); + + return isp4sd_start_stream(ispsd, state, pad); +} + +static int isp4sd_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct isp4_subdev *ispsd = to_isp4_subdev(sd); + + return isp4sd_stop_stream(ispsd, state, pad); +} + +static const struct v4l2_subdev_pad_ops isp4sd_pad_ops = { + .enum_mbus_code = isp4sd_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = isp4sd_set_pad_format, + .enable_streams = isp4sd_enable_streams, + .disable_streams = isp4sd_disable_streams, +}; + +static const struct v4l2_subdev_ops isp4sd_subdev_ops = { + .core = &isp4sd_core_ops, + .video = &isp4sd_video_ops, + .pad = &isp4sd_pad_ops, +}; + +static int isp4sd_sdev_link_validate(struct media_link *link) +{ + return 0; +} + +static const struct media_entity_operations isp4sd_sdev_ent_ops = { + .link_validate = isp4sd_sdev_link_validate, +}; + +int isp4sd_init(struct isp4_subdev *isp_subdev, + struct v4l2_device *v4l2_dev, + void *amdgpu_dev) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + struct isp4sd_sensor_info *sensor_info; + struct device *dev = v4l2_dev->dev; + int ret; + + isp_subdev->dev = dev; + isp_subdev->amdgpu_dev = amdgpu_dev; + v4l2_subdev_init(&isp_subdev->sdev, &isp4sd_subdev_ops); + isp_subdev->sdev.owner = THIS_MODULE; + isp_subdev->sdev.dev = dev; + snprintf(isp_subdev->sdev.name, sizeof(isp_subdev->sdev.name), "%s", + dev_name(dev)); + + isp_subdev->sdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + isp_subdev->sdev.entity.name = isp4sd_entity_name; + isp_subdev->sdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP; + isp_subdev->sdev.entity.ops = &isp4sd_sdev_ent_ops; + isp_subdev->sdev_pad[0].flags = MEDIA_PAD_FL_SINK; + isp_subdev->sdev_pad[1].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&isp_subdev->sdev.entity, 2, + isp_subdev->sdev_pad); + if (ret) { + dev_err(dev, "fail to init isp4 subdev entity pad %d\n", ret); + return ret; + } + ret = v4l2_subdev_init_finalize(&isp_subdev->sdev); + if (ret < 0) { + dev_err(dev, "fail to init finalize isp4 subdev %d\n", + ret); + return ret; + } + ret = v4l2_device_register_subdev(v4l2_dev, &isp_subdev->sdev); + if (ret) { + dev_err(dev, "fail to register isp4 subdev to V4L2 device %d\n", + ret); + goto err_media_clean_up; + } + + sensor_info = &isp_subdev->sensor_info; + + isp4if_init(ispif, dev, amdgpu_dev, isp_subdev->mmio); + + mutex_init(&isp_subdev->ops_mutex); + sensor_info->start_stream_cmd_sent = false; + sensor_info->status = ISP4SD_START_STATUS_NOT_START; + + /* create ISP enable gpio control */ + isp_subdev->enable_gpio = devm_gpiod_get(isp_subdev->dev, + "enable_isp", + GPIOD_OUT_LOW); + if (IS_ERR(isp_subdev->enable_gpio)) { + dev_err(dev, "fail to get gpiod %d\n", ret); + media_entity_cleanup(&isp_subdev->sdev.entity); + return PTR_ERR(isp_subdev->enable_gpio); + } + + isp_subdev->host2fw_seq_num = 1; + ispif->status = ISP4IF_STATUS_PWR_OFF; + + if (ret) + goto err_media_clean_up; + return ret; + +err_media_clean_up: + media_entity_cleanup(&isp_subdev->sdev.entity); + return ret; +} + +void isp4sd_deinit(struct isp4_subdev *isp_subdev) +{ + struct isp4_interface *ispif = &isp_subdev->ispif; + + media_entity_cleanup(&isp_subdev->sdev.entity); + isp4if_deinit(ispif); + isp4sd_module_enable(isp_subdev, false); + + ispif->status = ISP4IF_STATUS_PWR_OFF; +} diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.h b/drivers/media/platform/amd/isp4/isp4_subdev.h new file mode 100644 index 000000000000..bcbb93dce18f --- /dev/null +++ b/drivers/media/platform/amd/isp4/isp4_subdev.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#ifndef _ISP4_CONTEXT_H_ +#define _ISP4_CONTEXT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isp4_fw_cmd_resp.h" +#include "isp4_hw_reg.h" +#include "isp4_interface.h" + +/* + * one is for none sesnor specefic response which is not used now + * another is for sensor specific response + */ +#define ISP4SD_MAX_FW_RESP_STREAM_NUM 2 + +/* + * cmd used to register frame done callback, parameter is + * struct isp4sd_register_framedone_cb_param * + * when a image buffer is filled by ISP, ISP will call the registered callback. + * callback func prototype is isp4sd_framedone_cb, cb_ctx can be anything + * provided by caller which will be provided back as the first parameter of the + * callback function. + * both cb_func and cb_ctx are provide by caller, set cb_func to NULL to + * unregister the callback + */ + +/* used to indicate the ISP status*/ +enum isp4sd_status { + ISP4SD_STATUS_PWR_OFF, + ISP4SD_STATUS_PWR_ON, + ISP4SD_STATUS_FW_RUNNING, + ISP4SD_STATUS_MAX +}; + +/*used to indicate the status of sensor, output stream */ +enum isp4sd_start_status { + ISP4SD_START_STATUS_NOT_START, + ISP4SD_START_STATUS_STARTED, + ISP4SD_START_STATUS_START_FAIL, +}; + +struct isp4sd_img_buf_node { + struct list_head node; + struct isp4if_img_buf_info buf_info; +}; + +/* this is isp output after processing bayer raw input from sensor */ +struct isp4sd_output_info { + enum isp4sd_start_status start_status; + u32 image_size; +}; + +/* This struct represents the sensor info which is input or source of ISP, + * meta_info_buf is the buffer store the fw to driver metainfo response + * status is the sensor status + * output_info is the isp output info after ISP processing the sensor input, + * start_stream_cmd_sent mean if CMD_ID_START_STREAM has sent to fw. + * buf_sent_cnt is buffer count app has sent to receive the images + */ +struct isp4sd_sensor_info { + struct isp4if_gpu_mem_info * + meta_info_buf[ISP4IF_MAX_STREAM_META_BUF_COUNT]; + struct isp4sd_output_info output_info; + enum isp4sd_start_status status; + bool start_stream_cmd_sent; + u32 buf_sent_cnt; +}; + +/* + * Thread created by driver to receive fw response + * thread will be wakeup by fw to driver response interrupt + */ +struct isp4sd_thread_handler { + struct task_struct *thread; + struct mutex mutex; /* mutex */ + wait_queue_head_t waitq; + int wq_cond; +}; + +struct isp4_subdev_thread_param { + u32 idx; + struct isp4_subdev *isp_subdev; +}; + +struct isp4_subdev { + struct v4l2_subdev sdev; + struct isp4_interface ispif; + + /* + * sdev_pad[0] is sink pad connected to sensor + * sdev_pad[0] is sink pad connected to sensor + * sdev_pad[1] is sourc pad connected v4l2 video device + */ + struct media_pad sdev_pad[2]; + + enum isp4sd_status isp_status; + struct mutex ops_mutex; /* ops_mutex */ + + /* Used to store fw cmds sent to FW whose response driver needs + * to wait for + */ + struct isp4sd_thread_handler + fw_resp_thread[ISP4SD_MAX_FW_RESP_STREAM_NUM]; + + u32 host2fw_seq_num; + + struct isp4sd_sensor_info sensor_info; + + /* gpio descriptor */ + struct gpio_desc *enable_gpio; + struct device *dev; + void *amdgpu_dev; + void __iomem *mmio; + struct isp4_subdev_thread_param + isp_resp_para[ISP4SD_MAX_FW_RESP_STREAM_NUM]; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_dir; + bool enable_fw_log; + char *fw_log_output; +#endif + u32 phy_num_data_lanes; + u32 phy_id; + u64 phy_link_freq; + + void __iomem *isp_phy_mmio; +}; + +int isp4sd_init(struct isp4_subdev *isp_subdev, + struct v4l2_device *v4l2_dev, + void *amdgpu_dev); +void isp4sd_deinit(struct isp4_subdev *isp_subdev); + +#endif From patchwork Wed Jun 18 09:19:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Du, Bin" X-Patchwork-Id: 897811 Received: from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11on2045.outbound.protection.outlook.com [40.107.223.45]) (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 D5838285055; Wed, 18 Jun 2025 09:20:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.223.45 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238455; cv=fail; b=XRfxVBGCeIxHjNi8dOwcOSlWj19JMLQuLBWts3evds4MMlBLjGNlx8M2nSrd+u11NMRiGdsoQw2lLIlqh8iWhyPDlnsQ0IP55/SD8rmNiJu5Lfa/TeUPtM5ov7ZnG+1zVOCHCV31FC2zMX703Tsj1Bj9snbozsTwKyWyVK5tSnU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750238455; c=relaxed/simple; bh=UP3YDN8HC2yUxPpaTk0oaf2B9RWOIytfyWfU40dNOAc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JxRAMKbPds9BccnYM0bsAw1rOGk0/r8gjmoEU2yZRSiTJC9opyYx+UYVhxJY0sP9bPZaqbd+zGmtA6T+jA//i4fZJziNyBoqsKMhV+aUe0zFo/m66Cm0Hj7yYx1961X61p3in7TXcwcVnL+V8SGbn7FcVIKxGk1cyPXd07FlC3I= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=lvnQRKX4; arc=fail smtp.client-ip=40.107.223.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="lvnQRKX4" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=MOnkyVkast+rOpanvx6Bghg3mICFGvytDdGHaRYgZ0IVy/zkchNJKWi6xoD2chkegNHyMnVwOldwBnUmh2H0i3mTf6TUek8dL5PzfICO49iG3UXqa7YgzO+pL0JJYX4xOyTYn8k6AvTWe+Hg9c7aCU5vC/+dzokZyEXLxZxH6F8fxfyhxT0+kzUKQ86wBVCedlwnkLEuekvg9dAx48bHL+H1SG/eTx7GNEplsYKGr0Qx4oCWLn6YUUZcGVQQyLnugp13kg2M7H6knuUF7Ul3SGWylnTwg7ihWh1nPq2c2Kl2CReW0VufCZTBHsm8kH62ncCO7jn8whHpBZ4X+bBk3A== 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=zynAxN2Y5NO1WagF9Ei4gkCHTi2vkG7SgfJlmm0z278=; b=tP+3RrULILTujLMFdjsDmqcn2H1Owvt7akj7NBq+pCwfzMZmEbFyJ9JSl35EfAkdXRPJEGopKwVbOPyhLzAreln3vFnRpgbBPKARU+baSoTmCTRDoOXkXyZVxdpJ2WL30cz+GhQF+6ylbIVBAX/88Uko0bBH+hv8VwtrcQHYgUJGwGtgRZgWCHY5cf7/UfPZpZT78V3dnNPqr3e36Yrb+tiTF9xfPNDWj7snf34bOKnMK1Uvzrs/SZmTerYwmgmvZElX2q6cJp9vHJlU3l+/l6OmDYSc8jzyjzmqfPQZ9TV0SHShb/rfMfjEucKIYK52Ok/nhlaekqUfjeeXLTYfFw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=zynAxN2Y5NO1WagF9Ei4gkCHTi2vkG7SgfJlmm0z278=; b=lvnQRKX4f1aZjRsrRSKiL5HPZYg/HW/csPfcpvo+0LFxG7WiyPYFSEjdpWuKKYf5sd+2EBnyhMJrkYh1KFHWaXMoQQN09oxRViNNW133qnB9RLY0BJ98qSveg6q0zp3lmQxojSKgXb8c3Q/ghsJl3miHIfZCLm+H3LhbVEf8ofI= Received: from BN9PR03CA0271.namprd03.prod.outlook.com (2603:10b6:408:f5::6) by MN2PR12MB4488.namprd12.prod.outlook.com (2603:10b6:208:24e::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8857.19; Wed, 18 Jun 2025 09:20:50 +0000 Received: from BN3PEPF0000B371.namprd21.prod.outlook.com (2603:10b6:408:f5:cafe::3) by BN9PR03CA0271.outlook.office365.com (2603:10b6:408:f5::6) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.8835.19 via Frontend Transport; Wed, 18 Jun 2025 09:20:50 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by BN3PEPF0000B371.mail.protection.outlook.com (10.167.243.168) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.8880.0 via Frontend Transport; Wed, 18 Jun 2025 09:20:50 +0000 Received: from 555e2b870847.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 18 Jun 2025 04:20:46 -0500 From: Bin Du To: , , , , , , , CC: , , , , , , , , "Bin Du" Subject: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver Date: Wed, 18 Jun 2025 17:19:59 +0800 Message-ID: <20250618091959.68293-9-Bin.Du@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250618091959.68293-1-Bin.Du@amd.com> References: <20250618091959.68293-1-Bin.Du@amd.com> Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN3PEPF0000B371:EE_|MN2PR12MB4488:EE_ X-MS-Office365-Filtering-Correlation-Id: bcc2a434-e717-4618-bcf9-08ddae496ab3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|376014|1800799024|36860700013|82310400026; X-Microsoft-Antispam-Message-Info: lbeB/erPAbQKtVInUZUziEwv1tN0k0NUIhj4ifuw41ohMJ5ysh5l/9QjY9Bl5iAdC4SKU6UzubMYWxVQjp7X0bBgtAMAfBZM0RRE3V8/0yx+MzZR/lOtNiQO+VO3cJp9yAkrA3e/sF3jeGbi1574Vr3ThvBfB2eKrImL8NhcdKilQ2yj/HKWNxAG1ExPvOauwixR3uqaLcuOBH8FHXU5fprorKRhEzJPbzTlNl+vzPa1pyGYCyPl+T5Us6O4rStqDAVlCxlsHPIU83aHIOdOJCfPnAE2iptf0HjiX+NdHgUcAgUxuDlXHUq0LL0FMpnCpFwwg7q6Rr9TkkjRg3je/erh2thKqmmjak4SKn+tif70O8KwznLWREjKlpFGFYHxZbxHSaYflb2Slfbs6RklWyP6rOB/klA4ri90pfFhZlNESVMBhbPjypUR88zNM/XpY9wT8X5rB5wSzw1uihM2UMz+SlSxt5F3ndGiiEkfgEbe7AJ1e3Kl6p67flGAKm7gEJmfLvIMqoHWfAlxVwq7knJPEIgaKfkFFcMAB3hQg7HfIHKI1oNYjhDd1cpUiKUlVHsd+zH5gbnKzYJxxsSCMoUWkSzXtuCF+WZRUqgjw2t58zqlyut4SDOCA0IwtXp4D5pvbE8MDTHZB+5k/NnEeHosYgigd4dKQ/Jy/2LZFzYdI9zgpi5V99Ya7ElLTaH2MXaRAUF+faB2BzPqLDF45NYSBKv1ITH1mKseKDkEx2L1/9H9tylfD+0zjs0q4ciltuadkMX8bX7gXNSsgc49lIRSoTagWxAIvLBHPiCxC96TYDwl8g0VpdRT3427slEqsgpc2yWuRQ9HKjhE7mFlu0Ji0pBhfWnJPNt/jDi8l5190saPlYjhyIW0vCgdmwuBDFcLbQSNClwsUdB1yT9K5UPJV5Ctu5DPGuFxFnsnHo7PXsB2lqd8LpBWLdrJweMVRUzhDPxnzAqv4v2R4vE2TbfrKBdxIU1pFqygwTv0094qwMELi5VZTMzO4H0sDYOXssFBIkH+/rI2n2HKCxr+8SWuKUWggsjEy/MRT+oqVEYQddZoYgpwVR/aPgWvLJIAkx96KjmJmUcEABjBTyJ4DK8HfQ+d2niC5/bHQXKBO/nh4MWr/kc17wEIMqHnHd8BPL+Z62tO4dPHL18siOhcG51X6M1VbjFENPCWPU2PuuZ5YhQmkxuu5Y7YPFV5YE9wJZM9L9y0GoHtRu5tHF39mugfGCbzJ+VuXBFwN0gHgpA0gN1gqZ7NMEfVq9h6iuZmO+18+tTQlTDxYFwUqtsGyif3Ow3W35Xs5drYBpBDOR06eTWAcYCzYmHpNNLFhkeljcSXg2EvPMF1FeUK6e48SpZavcotrBXrx6lMzkoglqbLcmhd3NWd4ymaqIBfmREb6gtF9+7ZlrI+cy/AAgDGaKHpMb/LAyxXTLw/sgABNj5eQRXXYu9ZFzNlSv0sZIr1+WM/v/kgwE6oDqRRp4YJsUwv4yIrEYJHrVPeOv+yWFj6MjBh7NKY/ozkfzUPYHqr X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230040)(376014)(1800799024)(36860700013)(82310400026); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jun 2025 09:20:50.2067 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: bcc2a434-e717-4618-bcf9-08ddae496ab3 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BN3PEPF0000B371.namprd21.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR12MB4488 Add documentation for AMD isp 4 and describe the main components Signed-off-by: Bin Du Signed-off-by: Svetoslav Stoilov --- Documentation/admin-guide/media/amdisp4-1.rst | 64 +++++++++++++++++++ Documentation/admin-guide/media/amdisp4.dot | 8 +++ MAINTAINERS | 2 + 3 files changed, 74 insertions(+) create mode 100644 Documentation/admin-guide/media/amdisp4-1.rst create mode 100644 Documentation/admin-guide/media/amdisp4.dot diff --git a/Documentation/admin-guide/media/amdisp4-1.rst b/Documentation/admin-guide/media/amdisp4-1.rst new file mode 100644 index 000000000000..417b15af689a --- /dev/null +++ b/Documentation/admin-guide/media/amdisp4-1.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: + +==================================== +AMD Image Signal Processor (amdisp4) +==================================== + +Introduction +============ + +This file documents the driver for the AMD ISP4 that is part of +AMD Ryzen AI Max 385 SoC. + +The driver is located under drivers/media/platform/amd/isp4 and uses +the Media-Controller API. + +Topology +======== + +.. _amdisp4_topology_graph: + +.. kernel-figure:: amdisp4.dot + :alt: Diagram of the media pipeline topology + :align: center + + + +The driver has 1 sub-device: + +- isp: used to resize and process bayer raw frames in to yuv. + +The driver has 1 video device: + +- n00000004 [style=bold] + n00000004 [label="Preview\n/dev/video0", shape=box, style=filled, fillcolor=yellow] + n0000000a [label="{{} | ov05c10 22-0010\n/dev/v4l-subdev0 | { 0}}", shape=Mrecord, style=filled, fillcolor=green] + n0000000a:port0 -> n00000001:port0 [style=bold] +} diff --git a/MAINTAINERS b/MAINTAINERS index 15070afb14b5..e4455bde376f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1113,6 +1113,8 @@ M: Nirujogi Pratap L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git +F: Documentation/admin-guide/media/amdisp4-1.rst +F: Documentation/admin-guide/media/amdisp4.dot F: drivers/media/platform/amd/Kconfig F: drivers/media/platform/amd/Makefile F: drivers/media/platform/amd/isp4/*