linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Add AMD ISP4 driver
@ 2025-06-18  9:19 Bin Du
  2025-06-18  9:19 ` [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Bin Du
                   ` (9 more replies)
  0 siblings, 10 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

Hello,

AMD ISP4 is the AMD image processing gen 4 which can be found in HP ZBook Ultra G1a 14 inch Mobile Workstation PC ( Ryzen AI Max 385)
(https://ubuntu.com/certified/202411-36043)
This patch series introduces the initial driver support for the AMD ISP4.

Patch summary:
- Powers up/off and initializes ISP HW
- Configures and kicks off ISP FW
- Interacts with APP using standard V4l2 interface by video node
- Controls ISP HW and interacts with ISP FW to do image processing
- Support enum/set output image format and resolution
- Support queueing buffer from app and dequeueing ISP filled buffer to App
- Starts/stops sensor and mipi csi when camera App starts/stops streaming.
- It supports libcamera ver0.2 SimplePipeline
- It is verified on qv4l2, cheese and qcam
- It is verified together with following patches
	platform/x86: Add AMD ISP platform config for OV05C10 (https://lore.kernel.org/all/20250514215623.522746-1-pratap.nirujogi@amd.com/)
	media: i2c: Add OV05C10 camera sensor driver (https://lore.kernel.org/all/20250408221246.911508-1-pratap.nirujogi@amd.com/)
	pinctrl: amd: isp411: Add amdisp GPIO pinctrl (https://github.com/torvalds/linux/commit/e97435ab09f3ad7b6a588dd7c4e45a96699bbb4a)
	i2c: amd-isp: Add ISP i2c-designware driver (https://github.com/torvalds/linux/commit/d6263c468a761cd4c89887073614394ac48441e1)
	drm/amd/amdgpu: Add GPIO resources required for amdisp (https://gitlab.freedesktop.org/agd5f/linux/-/commit/ad0f5966ed8297aa47b3184192b00b7379ae0758)

AMD ISP4 Key features:
- Processes bayer raw data from the connected sensor and output them to different YUV formats
- Downscale input image to different output image resolution
- Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc

Changes v1 -> v2:
- Fix media CI test errors and valid warnings
- Reduce patch number in the series from 9 to 8 by merging MAINTAINERS adding patch to the first patch
- In patch 5
	- do modification to use remote endpoint instead of local endpoint
	- use link frequency and port number as start phy parameter instead of extra added phy-id and phy-bit-rate property of endpoint

It passes v4l2 compliance test, the test reports for:

(a) ov05c10 device /dev/v4l-subdev0
(b) amd_isp_capture device /dev/video0


Compliance test for device /dev/v4l-subdev0:
--------------------------------------------

atg@isp-pv-linux:~/v4l-utils/build/utils/v4l2-compliance$ sudo ./v4l2-compliance -u 0 v4l2-compliance 1.29.0-5348, 64 bits, 64-bit time_t v4l2-compliance SHA: 75e3f0e2c2cb 2025-03-17 18:12:17

Compliance test for device /dev/v4l-subdev0:

Driver Info:
         Driver version   : 6.14.0
         Capabilities     : 0x00000000
         Client Capabilities: 0x0000000000000002 interval-uses-which Required ioctls:
         test VIDIOC_SUDBEV_QUERYCAP: OK
         test invalid ioctls: OK

Allow for multiple opens:
         test second /dev/v4l-subdev0 open: OK
         test VIDIOC_SUBDEV_QUERYCAP: OK
         test for unlimited opens: OK

Debug ioctls:
         test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
         test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
         test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
         test VIDIOC_ENUMAUDIO: OK (Not Supported)
         test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
         test VIDIOC_G/S_AUDIO: OK (Not Supported)
         Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
         test VIDIOC_G/S_MODULATOR: OK (Not Supported)
         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
         test VIDIOC_ENUMAUDOUT: OK (Not Supported)
         test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
         test VIDIOC_G/S_AUDOUT: OK (Not Supported)
         Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
         test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
         test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
         test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
         test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls:
         test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
         test VIDIOC_QUERYCTRL: OK
         test VIDIOC_G/S_CTRL: OK
         test VIDIOC_G/S/TRY_EXT_CTRLS: OK
         test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
         test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
         Standard Controls: 11 Private Controls: 0

Format ioctls:
         test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
         test VIDIOC_G/S_PARM: OK (Not Supported)
         test VIDIOC_G_FBUF: OK (Not Supported)
         test VIDIOC_G_FMT: OK (Not Supported)
         test VIDIOC_TRY_FMT: OK (Not Supported)
         test VIDIOC_S_FMT: OK (Not Supported)
         test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
         test Cropping: OK (Not Supported)
         test Composing: OK (Not Supported)
         test Scaling: OK (Not Supported)

Codec ioctls:
         test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
         test VIDIOC_G_ENC_INDEX: OK (Not Supported)
         test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
         test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
         test CREATE_BUFS maximum buffers: OK
         test VIDIOC_REMOVE_BUFS: OK
         test VIDIOC_EXPBUF: OK (Not Supported)
         test Requests: OK (Not Supported)
         test blocking wait: OK (Not Supported)

Total for device /dev/v4l-subdev0: 46, Succeeded: 46, Failed: 0, Warnings: 0
---

Compliance test for amd_isp_capture device /dev/video0:
-------------------------------------------------------
atg@isp-pv-linux:~/test$ sudo ./v4l2-compliance -d /dev/video0
v4l2-compliance 1.29.0-5348, 64 bits, 64-bit time_t v4l2-compliance SHA: 75e3f0e2c2cb 2025-03-17 18:12:17

Compliance test for amd_isp_capture device /dev/video0:

Driver Info:
         Driver name      : amd_isp_capture
         Card type        : amd_isp_capture
         Bus info         : platform:amd_isp_capture
         Driver version   : 6.14.0
         Capabilities     : 0xa4200001
                 Video Capture
                 I/O MC
                 Streaming
                 Extended Pix Format
                 Device Capabilities
         Device Caps      : 0x24200001
                 Video Capture
                 I/O MC
                 Streaming
                 Extended Pix Format
Media Driver Info:
         Driver name      : amd_isp_capture
         Model            : amd_isp41_mdev
         Serial           :
         Bus info         : platform:amd_isp_capture
         Media version    : 6.14.0
         Hardware revision: 0x00000000 (0)
         Driver version   : 6.14.0
Interface Info:
         ID               : 0x03000003
         Type             : V4L Video
Entity Info:
         ID               : 0x00000001 (1)
         Name             : Preview
         Function         : V4L2 I/O
         Pad 0x01000002   : 0: Sink
           Link 0x02000007: from remote pad 0x1000006 of entity 'ov05c10 99-0010' (Camera Sensor): Data, Enabled, Immutable

Required ioctls:
         test MC information (see 'Media Driver Info' above): OK
         test VIDIOC_QUERYCAP: OK
         test invalid ioctls: OK

Allow for multiple opens:
         test second /dev/video0 open: OK
         test VIDIOC_QUERYCAP: OK
         test VIDIOC_G/S_PRIORITY: OK
         test for unlimited opens: OK

Debug ioctls:
         test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
         test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
         test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
         test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
         test VIDIOC_ENUMAUDIO: OK (Not Supported)
         test VIDIOC_G/S/ENUMINPUT: OK
         test VIDIOC_G/S_AUDIO: OK (Not Supported)
         Inputs: 1 Audio Inputs: 0 Tuners: 0

Output ioctls:
         test VIDIOC_G/S_MODULATOR: OK (Not Supported)
         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
         test VIDIOC_ENUMAUDOUT: OK (Not Supported)
         test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
         test VIDIOC_G/S_AUDOUT: OK (Not Supported)
         Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
         test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
         test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
         test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
         test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls (Input 0):
         test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
         test VIDIOC_QUERYCTRL: OK (Not Supported)
         test VIDIOC_G/S_CTRL: OK (Not Supported)
         test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
         test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
         test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
         Standard Controls: 0 Private Controls: 0

Format ioctls (Input 0):
         test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
         test VIDIOC_G/S_PARM: OK
         test VIDIOC_G_FBUF: OK (Not Supported)
         test VIDIOC_G_FMT: OK
         test VIDIOC_TRY_FMT: OK
         test VIDIOC_S_FMT: OK
         test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
         test Cropping: OK (Not Supported)
         test Composing: OK (Not Supported)
         test Scaling: OK (Not Supported)

Codec ioctls (Input 0):
         test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
         test VIDIOC_G_ENC_INDEX: OK (Not Supported)
         test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls (Input 0):
         test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
         test CREATE_BUFS maximum buffers: OK
         test VIDIOC_REMOVE_BUFS: OK
         test VIDIOC_EXPBUF: OK
         test Requests: OK (Not Supported)
         test blocking wait: OK

Total for amd_isp_capture device /dev/video0: 49, Succeeded: 49, Failed: 0, Warnings: 0

Please review and provide feedback.

Many thanks,

Bin Du (8):
  media: platform: amd: Introduce amd isp4 capture driver
  media: platform: amd: low level support for isp4 firmware
  media: platform: amd: Add helpers to configure isp4 mipi phy
  media: platform: amd: Add isp4 fw and hw interface
  media: platform: amd: isp4 subdev and firmware loading handling added
  media: platform: amd: isp4 video node and buffers handling added
  media: platform: amd: isp4 debug fs logging and  more descriptive
    errors
  Documentation: add documentation of AMD isp 4 driver

 Documentation/admin-guide/media/amdisp4-1.rst |   64 +
 Documentation/admin-guide/media/amdisp4.dot   |    8 +
 MAINTAINERS                                   |   12 +
 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      |   38 +
 drivers/media/platform/amd/isp4/isp4.c        |  406 +++++
 drivers/media/platform/amd/isp4/isp4.h        |   37 +
 drivers/media/platform/amd/isp4/isp4_debug.c  |  272 +++
 drivers/media/platform/amd/isp4/isp4_debug.h  |   41 +
 .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 ++++
 drivers/media/platform/amd/isp4/isp4_hw.c     |   46 +
 drivers/media/platform/amd/isp4/isp4_hw.h     |   14 +
 drivers/media/platform/amd/isp4/isp4_hw_reg.h |  116 ++
 .../media/platform/amd/isp4/isp4_interface.c  | 1064 ++++++++++++
 .../media/platform/amd/isp4/isp4_interface.h  |  164 ++
 drivers/media/platform/amd/isp4/isp4_phy.c    | 1547 +++++++++++++++++
 drivers/media/platform/amd/isp4/isp4_phy.h    |   14 +
 drivers/media/platform/amd/isp4/isp4_subdev.c | 1308 ++++++++++++++
 drivers/media/platform/amd/isp4/isp4_subdev.h |  147 ++
 drivers/media/platform/amd/isp4/isp4_video.c  | 1443 +++++++++++++++
 drivers/media/platform/amd/isp4/isp4_video.h  |   93 +
 24 files changed, 7176 insertions(+)
 create mode 100644 Documentation/admin-guide/media/amdisp4-1.rst
 create mode 100644 Documentation/admin-guide/media/amdisp4.dot
 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
 create mode 100644 drivers/media/platform/amd/isp4/isp4_debug.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_debug.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_hw_reg.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_phy.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_phy.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_subdev.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_subdev.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_video.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_video.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-06-18 15:58   ` Mario Limonciello
  2025-07-28  5:54   ` Sakari Ailus
  2025-06-18  9:19 ` [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware Bin Du
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

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 <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 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 <bin.du@amd.com>
+M:	Nirujogi Pratap <pratap.nirujogi@amd.com>
+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 <Felix.Kuehling@amd.com>
 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 <linux/pm_runtime.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-ioctl.h>
+
+#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 <bin.du@amd.com>");
+MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
+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 <linux/mutex.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-memops.h>
+#include <media/videobuf2-vmalloc.h>
+
+#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 */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
  2025-06-18  9:19 ` [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-06-18 16:00   ` Mario Limonciello
  2025-07-28  5:57   ` Sakari Ailus
  2025-06-18  9:19 ` [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy Bin Du
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

Low level functions for access the registers and mapping to their ranges.
This change also includes register definitions for ring buffer used to
communicate with ISP Firmware.
Ring buffer is the communication interface between driver and ISP Firmware.
Command and responses are exchanged through the ring buffer.

Signed-off-by: Bin Du <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 drivers/media/platform/amd/isp4/Makefile      |   3 +-
 drivers/media/platform/amd/isp4/isp4_hw.c     |  46 +++++++
 drivers/media/platform/amd/isp4/isp4_hw.h     |  14 +++
 drivers/media/platform/amd/isp4/isp4_hw_reg.h | 116 ++++++++++++++++++
 4 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_hw_reg.h

diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
index e9e84160517d..8ca1c4dfe246 100644
--- a/drivers/media/platform/amd/isp4/Makefile
+++ b/drivers/media/platform/amd/isp4/Makefile
@@ -3,7 +3,8 @@
 # Copyright (C) 2025 Advanced Micro Devices, Inc.
 
 obj-$(CONFIG_AMD_ISP4) += amd_capture.o
-amd_capture-objs := isp4.o
+amd_capture-objs := isp4.o	\
+			isp4_hw.o	\
 
 ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
 ccflags-y += -I$(srctree)/include
diff --git a/drivers/media/platform/amd/isp4/isp4_hw.c b/drivers/media/platform/amd/isp4/isp4_hw.c
new file mode 100644
index 000000000000..e5315330a514
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_hw.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include "isp4_hw.h"
+#include "isp4_hw_reg.h"
+
+#define RMMIO_SIZE 524288
+
+u32 isp4hw_rreg(void __iomem *base, u32 reg)
+{
+	void __iomem *reg_addr;
+
+	if (reg >= RMMIO_SIZE)
+		return RREG_FAILED_VAL;
+
+	if (reg < ISP_MIPI_PHY0_REG0)
+		reg_addr = base + reg;
+	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
+		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
+	else
+		return RREG_FAILED_VAL;
+
+	return readl(reg_addr);
+};
+
+void isp4hw_wreg(void __iomem *base, u32 reg, u32 val)
+{
+	void __iomem *reg_addr;
+
+	if (reg >= RMMIO_SIZE)
+		return;
+
+	if (reg < ISP_MIPI_PHY0_REG0)
+		reg_addr = base + reg;
+	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
+		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
+	else
+		return;
+
+	writel(val, reg_addr);
+};
diff --git a/drivers/media/platform/amd/isp4/isp4_hw.h b/drivers/media/platform/amd/isp4/isp4_hw.h
new file mode 100644
index 000000000000..072d135b9e3a
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_hw.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _ISP4_HW_H_
+#define _ISP4_HW_H_
+
+#define RREG_FAILED_VAL 0xFFFFFFFF
+
+u32 isp4hw_rreg(void __iomem *base, u32 reg);
+void isp4hw_wreg(void __iomem *base, u32 reg, u32 val);
+
+#endif
diff --git a/drivers/media/platform/amd/isp4/isp4_hw_reg.h b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
new file mode 100644
index 000000000000..b11f12ba6c56
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _ISP4_HW_REG_H_
+#define _ISP4_HW_REG_H_
+
+#define ISP_SOFT_RESET		0x62000
+#define ISP_SYS_INT0_EN		0x62010
+#define ISP_SYS_INT0_STATUS	0x62014
+#define ISP_SYS_INT0_ACK	0x62018
+#define ISP_CCPU_CNTL		0x62054
+#define ISP_STATUS		0x62058
+#define ISP_LOG_RB_BASE_LO0	0x62148
+#define ISP_LOG_RB_BASE_HI0	0x6214C
+#define ISP_LOG_RB_SIZE0	0x62150
+#define ISP_LOG_RB_RPTR0	0x62154
+#define ISP_LOG_RB_WPTR0	0x62158
+#define ISP_RB_BASE_LO1		0x62170
+#define ISP_RB_BASE_HI1		0x62174
+#define ISP_RB_SIZE1		0x62178
+#define ISP_RB_RPTR1		0x6217C
+#define ISP_RB_WPTR1		0x62180
+#define ISP_RB_BASE_LO2		0x62184
+#define ISP_RB_BASE_HI2		0x62188
+#define ISP_RB_SIZE2		0x6218C
+#define ISP_RB_RPTR2		0x62190
+#define ISP_RB_WPTR2		0x62194
+#define ISP_RB_BASE_LO3		0x62198
+#define ISP_RB_BASE_HI3		0x6219C
+#define ISP_RB_SIZE3		0x621A0
+#define ISP_RB_RPTR3		0x621A4
+#define ISP_RB_WPTR3		0x621A8
+#define ISP_RB_BASE_LO4		0x621AC
+#define ISP_RB_BASE_HI4		0x621B0
+#define ISP_RB_SIZE4		0x621B4
+#define ISP_RB_RPTR4		0x621B8
+#define ISP_RB_WPTR4		0x621BC
+#define ISP_RB_BASE_LO5		0x621C0
+#define ISP_RB_BASE_HI5		0x621C4
+#define ISP_RB_SIZE5		0x621C8
+#define ISP_RB_RPTR5		0x621CC
+#define ISP_RB_WPTR5		0x621D0
+#define ISP_RB_BASE_LO6		0x621D4
+#define ISP_RB_BASE_HI6		0x621D8
+#define ISP_RB_SIZE6		0x621DC
+#define ISP_RB_RPTR6		0x621E0
+#define ISP_RB_WPTR6		0x621E4
+#define ISP_RB_BASE_LO7		0x621E8
+#define ISP_RB_BASE_HI7		0x621EC
+#define ISP_RB_SIZE7		0x621F0
+#define ISP_RB_RPTR7		0x621F4
+#define ISP_RB_WPTR7		0x621F8
+#define ISP_RB_BASE_LO8		0x621FC
+#define ISP_RB_BASE_HI8		0x62200
+#define ISP_RB_SIZE8		0x62204
+#define ISP_RB_RPTR8		0x62208
+#define ISP_RB_WPTR8		0x6220C
+#define ISP_RB_BASE_LO9		0x62210
+#define ISP_RB_BASE_HI9		0x62214
+#define ISP_RB_SIZE9		0x62218
+#define ISP_RB_RPTR9		0x6221C
+#define ISP_RB_WPTR9		0x62220
+#define ISP_RB_BASE_LO10	0x62224
+#define ISP_RB_BASE_HI10	0x62228
+#define ISP_RB_SIZE10		0x6222C
+#define ISP_RB_RPTR10		0x62230
+#define ISP_RB_WPTR10		0x62234
+#define ISP_RB_BASE_LO11	0x62238
+#define ISP_RB_BASE_HI11	0x6223C
+#define ISP_RB_SIZE11		0x62240
+#define ISP_RB_RPTR11		0x62244
+#define ISP_RB_WPTR11		0x62248
+#define ISP_RB_BASE_LO12	0x6224C
+#define ISP_RB_BASE_HI12	0x62250
+#define ISP_RB_SIZE12		0x62254
+#define ISP_RB_RPTR12		0x62258
+#define ISP_RB_WPTR12		0x6225C
+
+#define ISP_POWER_STATUS	0x60000
+
+#define ISP_MIPI_PHY0_REG0	0x66700
+#define ISP_MIPI_PHY1_REG0	0x66780
+#define ISP_MIPI_PHY2_REG0	0x67400
+
+#define ISP_MIPI_PHY0_SIZE	0xD30
+
+/* ISP_SOFT_RESET */
+#define ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK			0x00000001UL
+
+/* ISP_CCPU_CNTL */
+#define ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK			0x00040000UL
+
+/* ISP_STATUS */
+#define ISP_STATUS__CCPU_REPORT_MASK				0x000000feUL
+
+/* ISP_SYS_INT0_STATUS */
+#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK	0x00010000UL
+#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK	0x00040000UL
+#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK	0x00100000UL
+#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK	0x00400000UL
+
+/* ISP_SYS_INT0_EN */
+#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK	0x00010000UL
+#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK	0x00040000UL
+#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK	0x00100000UL
+#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK	0x00400000UL
+
+/* ISP_SYS_INT0_ACK */
+#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK	0x00010000UL
+#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT10_ACK_MASK	0x00040000UL
+#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT11_ACK_MASK	0x00100000UL
+#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK	0x00400000UL
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
  2025-06-18  9:19 ` [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Bin Du
  2025-06-18  9:19 ` [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-07-28  6:33   ` Sakari Ailus
  2025-07-28  7:28   ` Sakari Ailus
  2025-06-18  9:19 ` [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface Bin Du
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="y", Size: 73945 bytes --]

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 <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 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 <linux/delay.h>
+#include <linux/device.h>
+
+#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)(&reg->isp_mipi_phy_ind_idx), addr);
+	return (u16)isp4hw_rreg(base, (uintptr_t)(&reg->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)(&reg->isp_mipi_phy_ind_idx), addr);
+	isp4hw_wreg(base, (uintptr_t)(&reg->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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (2 preceding siblings ...)
  2025-06-18  9:19 ` [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-06-18 16:17   ` Mario Limonciello
  2025-07-28  7:23   ` Sakari Ailus
  2025-06-18  9:19 ` [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added Bin Du
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

ISP firmware controls ISP HW pipeline using dedicated embedded processor
called ccpu.
The communication between ISP FW and driver is using commands and
response messages sent through the ring buffer. Command buffers support
either global setting that is not specific to the steam and support stream
specific parameters. Response buffers contains ISP FW notification
information such as frame buffer done and command done. IRQ is used for
receiving response buffer from ISP firmware, which is handled in the main
isp4 media device. ISP ccpu is booted up through the firmware loading
helper function prior to stream start.
Memory used for command buffer and response buffer needs to be allocated
from amdgpu buffer manager because isp4 is a child device of amdgpu.

Signed-off-by: Bin Du <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 drivers/media/platform/amd/isp4/Makefile      |   12 +
 .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
 .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++++++
 .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
 4 files changed, 1546 insertions(+)
 create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
 create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h

diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
index 0e36201fbb30..c0166f954516 100644
--- a/drivers/media/platform/amd/isp4/Makefile
+++ b/drivers/media/platform/amd/isp4/Makefile
@@ -5,10 +5,22 @@
 obj-$(CONFIG_AMD_ISP4) += amd_capture.o
 amd_capture-objs := isp4.o	\
 			isp4_phy.o \
+			isp4_interface.o \
 			isp4_hw.o	\
 
 ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
+ccflags-y += -I$(srctree)/include/drm
 ccflags-y += -I$(srctree)/include
+ccflags-y += -I$(srctree)/include/uapi/drm
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
+ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm
 
 ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
 	cc_stack_align := -mpreferred-stack-boundary=4
diff --git a/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
new file mode 100644
index 000000000000..437d89469af2
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
@@ -0,0 +1,318 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _ISP4_CMD_RESP_H_
+#define _ISP4_CMD_RESP_H_
+
+/*
+ * @brief Host and Firmware command & response channel.
+ *        Two types of command/response channel.
+ *          Type Global Command has one command/response channel.
+ *          Type Stream Command has one command/response channel.
+ *-----------                                        ------------
+ *|         |       ---------------------------      |          |
+ *|         |  ---->|  Global Command         |----> |          |
+ *|         |       ---------------------------      |          |
+ *|         |                                        |          |
+ *|         |                                        |          |
+ *|         |       ---------------------------      |          |
+ *|         |  ---->|   Stream Command        |----> |          |
+ *|         |       ---------------------------      |          |
+ *|         |                                        |          |
+ *|         |                                        |          |
+ *|         |                                        |          |
+ *|  HOST   |                                        | Firmware |
+ *|         |                                        |          |
+ *|         |                                        |          |
+ *|         |       --------------------------       |          |
+ *|         |  <----|  Global Response       |<----  |          |
+ *|         |       --------------------------       |          |
+ *|         |                                        |          |
+ *|         |                                        |          |
+ *|         |       --------------------------       |          |
+ *|         |  <----|  Stream Response       |<----  |          |
+ *|         |       --------------------------       |          |
+ *|         |                                        |          |
+ *|         |                                        |          |
+ *-----------                                        ------------
+ */
+
+/*
+ * @brief command ID format
+ *        cmd_id is in the format of following type:
+ *        type: indicate command type, global/stream commands.
+ *        group: indicate the command group.
+ *        id: A unique command identification in one type and group.
+ *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
+ *        |      type       |      group      |       id       |
+ */
+
+#define CMD_TYPE_SHIFT (24)
+#define CMD_GROUP_SHIFT (16)
+#define CMD_TYPE_STREAM_CTRL ((u32)0x2 << CMD_TYPE_SHIFT)
+
+#define CMD_GROUP_STREAM_CTRL ((u32)0x1 << CMD_GROUP_SHIFT)
+#define CMD_GROUP_STREAM_BUFFER ((u32)0x4 << CMD_GROUP_SHIFT)
+
+/* Stream  Command */
+#define CMD_ID_SET_STREAM_CONFIG                        \
+	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x1)
+#define CMD_ID_SET_OUT_CHAN_PROP                        \
+	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x3)
+#define CMD_ID_ENABLE_OUT_CHAN                          \
+	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x5)
+#define CMD_ID_START_STREAM                             \
+	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x7)
+#define CMD_ID_STOP_STREAM                              \
+	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x8)
+
+/* Stream Buffer Command */
+#define CMD_ID_SEND_BUFFER                                \
+	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_BUFFER | 0x1)
+
+/*
+ * @brief response ID format
+ *        resp_id is in the format of following type:
+ *        type: indicate command type, global/stream commands.
+ *        group: indicate the command group.
+ *        id: A unique command identification in one type and group.
+ *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
+ *        |      type       |      group      |       id       |
+ */
+
+#define RESP_GROUP_SHIFT (16)
+#define RESP_GROUP_MASK  (0xff << RESP_GROUP_SHIFT)
+
+#define GET_RESP_GROUP_VALUE(resp_id)   \
+	(((resp_id) & RESP_GROUP_MASK) >> \
+	 RESP_GROUP_SHIFT)
+#define GET_RESP_ID_VALUE(resp_id) ((resp_id) & 0xffff)
+
+#define RESP_GROUP_GENERAL (0x1 << RESP_GROUP_SHIFT)
+#define RESP_GROUP_NOTIFICATION (0x3 << RESP_GROUP_SHIFT)
+
+/* General  Response */
+#define RESP_ID_CMD_DONE (RESP_GROUP_GENERAL | 0x1)
+
+/* Notification */
+#define RESP_ID_NOTI_FRAME_DONE (RESP_GROUP_NOTIFICATION | 0x1)
+
+#define CMD_STATUS_SUCCESS (0)
+#define CMD_STATUS_FAIL (1)
+#define CMD_STATUS_SKIPPED (2)
+
+#define ADDR_SPACE_TYPE_GPU_VA 4
+
+#define FW_MEMORY_POOL_SIZE (200 * 1024 * 1024)
+
+/*
+ * standard ISP mipicsi=>isp
+ */
+#define MIPI0_ISP_PIPELINE_ID 0x5f91
+
+enum isp4fw_sensor_id {
+	SENSOR_ID_ON_MIPI0  = 0,  /* Sensor id for ISP input from MIPI port 0 */
+};
+
+enum isp4fw_stream_id {
+	STREAM_ID_INVALID = -1, /* STREAM_ID_INVALID. */
+	STREAM_ID_1 = 0,        /* STREAM_ID_1. */
+	STREAM_ID_2 = 1,        /* STREAM_ID_2. */
+	STREAM_ID_3 = 2,        /* STREAM_ID_3. */
+	STREAM_ID_MAXIMUM       /* STREAM_ID_MAXIMUM. */
+};
+
+enum isp4fw_image_format {
+	IMAGE_FORMAT_NV12 = 1,              /* 4:2:0,semi-planar, 8-bit */
+	IMAGE_FORMAT_YUV422INTERLEAVED = 7, /* interleave, 4:2:2, 8-bit */
+};
+
+enum isp4fw_pipe_out_ch {
+	ISP_PIPE_OUT_CH_PREVIEW = 0,
+};
+
+enum isp4fw_yuv_range {
+	ISP_YUV_RANGE_FULL = 0,     /* YUV value range in 0~255 */
+	ISP_YUV_RANGE_NARROW = 1,   /* YUV value range in 16~235 */
+	ISP_YUV_RANGE_MAX
+};
+
+enum isp4fw_buffer_type {
+	BUFFER_TYPE_PREVIEW = 8,
+	BUFFER_TYPE_META_INFO = 10,
+	BUFFER_TYPE_MEM_POOL = 15,
+};
+
+enum isp4fw_buffer_status {
+	BUFFER_STATUS_INVALID,  /* The buffer is INVALID */
+	BUFFER_STATUS_SKIPPED,  /* The buffer is not filled with image data */
+	BUFFER_STATUS_EXIST,    /* The buffer is exist and waiting for filled */
+	BUFFER_STATUS_DONE,     /* The buffer is filled with image data */
+	BUFFER_STATUS_LACK,     /* The buffer is unavailable */
+	BUFFER_STATUS_DIRTY,    /* The buffer is dirty, probably caused by
+				 * LMI leakage
+				 */
+	BUFFER_STATUS_MAX       /* The buffer STATUS_MAX */
+};
+
+enum isp4fw_buffer_source {
+	/* The buffer is from the stream buffer queue */
+	BUFFER_SOURCE_STREAM,
+};
+
+struct isp4fw_error_code {
+	u32 code1;
+	u32 code2;
+	u32 code3;
+	u32 code4;
+	u32 code5;
+};
+
+/*
+ * Command Structure for FW
+ */
+
+struct isp4fw_cmd {
+	u32 cmd_seq_num;
+	u32 cmd_id;
+	u32 cmd_param[12];
+	u16 cmd_stream_id;
+	u8 cmd_silent_resp;
+	u8 reserved;
+	u32 cmd_check_sum;
+};
+
+struct isp4fw_resp_cmd_done {
+	/* The host2fw command seqNum.
+	 * To indicate which command this response refer to.
+	 */
+	u32 cmd_seq_num;
+	/* The host2fw command id for host double check. */
+	u32 cmd_id;
+	/* Indicate the command process status.
+	 * 0 means success. 1 means fail. 2 means skipped
+	 */
+	u16 cmd_status;
+	/* If the cmd_status is 1, that means the command is processed fail, */
+	/* host can check the isp4fw_error_code to get the detail
+	 * error information
+	 */
+	u16 isp4fw_error_code;
+	/* The response payload will be in different struct type */
+	/* according to different cmd done response. */
+	u8 payload[36];
+};
+
+struct isp4fw_resp_param_package {
+	u32 package_addr_lo;	/* The low 32 bit addr of the pkg address. */
+	u32 package_addr_hi;	/* The high 32 bit addr of the pkg address. */
+	u32 package_size;	/* The total pkg size in bytes. */
+	u32 package_check_sum;	/* The byte sum of the pkg. */
+};
+
+struct isp4fw_resp {
+	u32 resp_seq_num;
+	u32 resp_id;
+	union {
+		struct isp4fw_resp_cmd_done cmd_done;
+		struct isp4fw_resp_param_package frame_done;
+		u32 resp_param[12];
+	} param;
+	u8  reserved[4];
+	u32 resp_check_sum;
+};
+
+struct isp4fw_mipi_pipe_path_cfg {
+	u32 b_enable;
+	enum isp4fw_sensor_id isp4fw_sensor_id;
+};
+
+struct isp4fw_isp_pipe_path_cfg {
+	u32  isp_pipe_id;	/* pipe ids for pipeline construction */
+};
+
+struct isp4fw_isp_stream_cfg {
+	/* Isp mipi path */
+	struct isp4fw_mipi_pipe_path_cfg mipi_pipe_path_cfg;
+	/* Isp pipe path */
+	struct isp4fw_isp_pipe_path_cfg  isp_pipe_path_cfg;
+	/* enable TNR */
+	u32 b_enable_tnr;
+	/* number of frame rta per-processing,
+	 * set to 0 to use fw default value
+	 */
+	u32 rta_frames_per_proc;
+};
+
+struct isp4fw_image_prop {
+	enum isp4fw_image_format image_format;	/* Image format */
+	u32 width;				/* Width */
+	u32 height;				/* Height */
+	u32 luma_pitch;				/* Luma pitch */
+	u32 chroma_pitch;			/* Chrom pitch */
+	enum isp4fw_yuv_range yuv_range;		/* YUV value range */
+};
+
+struct isp4fw_buffer {
+	/* A check num for debug usage, host need to */
+	/* set the buf_tags to different number */
+	u32 buf_tags;
+	union {
+		u32 value;
+		struct {
+			u32 space : 16;
+			u32 vmid  : 16;
+		} bit;
+	} vmid_space;
+	u32 buf_base_a_lo;		/* Low address of buffer A */
+	u32 buf_base_a_hi;		/* High address of buffer A */
+	u32 buf_size_a;			/* Buffer size of buffer A */
+
+	u32 buf_base_b_lo;		/* Low address of buffer B */
+	u32 buf_base_b_hi;		/* High address of buffer B */
+	u32 buf_size_b;			/* Buffer size of buffer B */
+
+	u32 buf_base_c_lo;		/* Low address of buffer C */
+	u32 buf_base_c_hi;		/* High address of buffer C */
+	u32 buf_size_c;			/* Buffer size of buffer C */
+};
+
+struct isp4fw_buffer_meta_info {
+	u32 enabled;					/* enabled flag */
+	enum isp4fw_buffer_status status;		/* BufferStatus */
+	struct isp4fw_error_code err;			/* err code */
+	enum isp4fw_buffer_source source;		/* BufferSource */
+	struct isp4fw_image_prop image_prop;		/* image_prop */
+	struct isp4fw_buffer buffer;			/* buffer */
+};
+
+struct isp4fw_meta_info {
+	u32 poc;				/* frame id */
+	u32 fc_id;				/* frame ctl id */
+	u32 time_stamp_lo;			/* time_stamp_lo */
+	u32 time_stamp_hi;			/* time_stamp_hi */
+	struct isp4fw_buffer_meta_info preview;	/* preview BufferMetaInfo */
+};
+
+struct isp4fw_cmd_send_buffer {
+	enum isp4fw_buffer_type buffer_type;	/* buffer Type */
+	struct isp4fw_buffer buffer;		/* buffer info */
+};
+
+struct isp4fw_cmd_set_out_ch_prop {
+	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
+	struct isp4fw_image_prop image_prop;	/* image property */
+};
+
+struct isp4fw_cmd_enable_out_ch {
+	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
+	u32 is_enable;			/* If enable channel or not */
+};
+
+struct isp4fw_cmd_set_stream_cfg {
+	struct isp4fw_isp_stream_cfg stream_cfg; /* stream path config */
+};
+
+#endif
diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c
new file mode 100644
index 000000000000..0e1eb22a0de5
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_interface.c
@@ -0,0 +1,1052 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/mutex.h>
+
+#include "amdgpu_object.h"
+
+#include "isp4_fw_cmd_resp.h"
+#include "isp4_hw.h"
+#include "isp4_hw_reg.h"
+#include "isp4_interface.h"
+
+#define ISP4IF_FW_RESP_RB_IRQ_EN_MASK \
+	(ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK |  \
+	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK | \
+	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK | \
+	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK)
+
+struct isp4if_rb_config {
+	const char *name;
+	u32 index;
+	u32 reg_rptr;
+	u32 reg_wptr;
+	u32 reg_base_lo;
+	u32 reg_base_hi;
+	u32 reg_size;
+	u32 val_size;
+	u64 base_mc_addr;
+	void *base_sys_addr;
+};
+
+/* FW cmd ring buffer configuration */
+static struct isp4if_rb_config
+	isp4if_cmd_rb_config[ISP4IF_STREAM_ID_MAX] = {
+	{
+		.name = "CMD_RB_GBL0",
+		.index = 3,
+		.reg_rptr = ISP_RB_RPTR4,
+		.reg_wptr = ISP_RB_WPTR4,
+		.reg_base_lo = ISP_RB_BASE_LO4,
+		.reg_base_hi = ISP_RB_BASE_HI4,
+		.reg_size = ISP_RB_SIZE4,
+	},
+	{
+		.name = "CMD_RB_STR1",
+		.index = 0,
+		.reg_rptr = ISP_RB_RPTR1,
+		.reg_wptr = ISP_RB_WPTR1,
+		.reg_base_lo = ISP_RB_BASE_LO1,
+		.reg_base_hi = ISP_RB_BASE_HI1,
+		.reg_size = ISP_RB_SIZE1,
+	},
+	{
+		.name = "CMD_RB_STR2",
+		.index = 1,
+		.reg_rptr = ISP_RB_RPTR2,
+		.reg_wptr = ISP_RB_WPTR2,
+		.reg_base_lo = ISP_RB_BASE_LO2,
+		.reg_base_hi = ISP_RB_BASE_HI2,
+		.reg_size = ISP_RB_SIZE2,
+	},
+	{
+		.name = "CMD_RB_STR3",
+		.index = 2,
+		.reg_rptr = ISP_RB_RPTR3,
+		.reg_wptr = ISP_RB_WPTR3,
+		.reg_base_lo = ISP_RB_BASE_LO3,
+		.reg_base_hi = ISP_RB_BASE_HI3,
+		.reg_size = ISP_RB_SIZE3,
+	},
+};
+
+/* FW resp ring buffer configuration */
+static struct isp4if_rb_config
+	isp4if_resp_rb_config[ISP4IF_STREAM_ID_MAX] = {
+	{
+		.name = "RES_RB_GBL0",
+		.index = 3,
+		.reg_rptr = ISP_RB_RPTR12,
+		.reg_wptr = ISP_RB_WPTR12,
+		.reg_base_lo = ISP_RB_BASE_LO12,
+		.reg_base_hi = ISP_RB_BASE_HI12,
+		.reg_size = ISP_RB_SIZE12,
+	},
+	{
+		.name = "RES_RB_STR1",
+		.index = 0,
+		.reg_rptr = ISP_RB_RPTR9,
+		.reg_wptr = ISP_RB_WPTR9,
+		.reg_base_lo = ISP_RB_BASE_LO9,
+		.reg_base_hi = ISP_RB_BASE_HI9,
+		.reg_size = ISP_RB_SIZE9,
+	},
+	{
+		.name = "RES_RB_STR2",
+		.index = 1,
+		.reg_rptr = ISP_RB_RPTR10,
+		.reg_wptr = ISP_RB_WPTR10,
+		.reg_base_lo = ISP_RB_BASE_LO10,
+		.reg_base_hi = ISP_RB_BASE_HI10,
+		.reg_size = ISP_RB_SIZE10,
+	},
+	{
+		.name = "RES_RB_STR3",
+		.index = 2,
+		.reg_rptr = ISP_RB_RPTR11,
+		.reg_wptr = ISP_RB_WPTR11,
+		.reg_base_lo = ISP_RB_BASE_LO11,
+		.reg_base_hi = ISP_RB_BASE_HI11,
+		.reg_size = ISP_RB_SIZE11,
+	},
+};
+
+/* FW log ring buffer configuration */
+static struct isp4if_rb_config isp4if_log_rb_config = {
+	.name = "LOG_RB",
+	.index = 0,
+	.reg_rptr = ISP_LOG_RB_RPTR0,
+	.reg_wptr = ISP_LOG_RB_WPTR0,
+	.reg_base_lo = ISP_LOG_RB_BASE_LO0,
+	.reg_base_hi = ISP_LOG_RB_BASE_HI0,
+	.reg_size = ISP_LOG_RB_SIZE0,
+};
+
+static struct isp4if_gpu_mem_info *isp4if_gpu_mem_alloc(struct isp4_interface
+							*ispif,
+							u32 mem_size)
+{
+	struct isp4if_gpu_mem_info *mem_info;
+	struct amdgpu_bo *bo = NULL;
+	struct amdgpu_device *adev;
+	struct device *dev;
+
+	void *cpu_ptr;
+	u64 gpu_addr;
+	u32 ret;
+
+	dev = ispif->dev;
+
+	if (!mem_size)
+		return NULL;
+
+	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
+	if (!mem_info)
+		return NULL;
+
+	adev = (struct amdgpu_device *)ispif->adev;
+	mem_info->mem_size = mem_size;
+	mem_info->mem_align = ISP4IF_ISP_MC_ADDR_ALIGN;
+	mem_info->mem_domain = AMDGPU_GEM_DOMAIN_GTT;
+
+	ret = amdgpu_bo_create_kernel(adev,
+				      mem_info->mem_size,
+				      mem_info->mem_align,
+				      mem_info->mem_domain,
+				      &bo,
+				      &gpu_addr,
+				      &cpu_ptr);
+
+	if (!cpu_ptr || ret) {
+		dev_err(dev, "gpuvm buffer alloc fail, size %u\n", mem_size);
+		kfree(mem_info);
+		return NULL;
+	}
+
+	mem_info->sys_addr = cpu_ptr;
+	mem_info->gpu_mc_addr = gpu_addr;
+	mem_info->mem_handle = (void *)bo;
+
+	return mem_info;
+}
+
+static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
+			       struct isp4if_gpu_mem_info *mem_info)
+{
+	struct device *dev = ispif->dev;
+	struct amdgpu_bo *bo;
+
+	if (!mem_info) {
+		dev_err(dev, "invalid mem_info\n");
+		return -EINVAL;
+	}
+
+	bo = (struct amdgpu_bo *)mem_info->mem_handle;
+
+	amdgpu_bo_free_kernel(&bo, &mem_info->gpu_mc_addr, &mem_info->sys_addr);
+
+	kfree(mem_info);
+
+	return 0;
+}
+
+static int isp4if_dealloc_fw_gpumem(struct isp4_interface *ispif)
+{
+	int i;
+
+	if (ispif->fw_mem_pool) {
+		isp4if_gpu_mem_free(ispif, ispif->fw_mem_pool);
+		ispif->fw_mem_pool = NULL;
+	}
+
+	if (ispif->fw_cmd_resp_buf) {
+		isp4if_gpu_mem_free(ispif, ispif->fw_cmd_resp_buf);
+		ispif->fw_cmd_resp_buf = NULL;
+	}
+
+	if (ispif->fw_log_buf) {
+		isp4if_gpu_mem_free(ispif, ispif->fw_log_buf);
+		ispif->fw_log_buf = NULL;
+	}
+
+	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
+		if (ispif->metainfo_buf_pool[i]) {
+			isp4if_gpu_mem_free(ispif, ispif->metainfo_buf_pool[i]);
+			ispif->metainfo_buf_pool[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif)
+{
+	struct device *dev = ispif->dev;
+	int i;
+
+	ispif->fw_mem_pool = isp4if_gpu_mem_alloc(ispif, FW_MEMORY_POOL_SIZE);
+	if (!ispif->fw_mem_pool)
+		goto error_no_memory;
+
+	ispif->fw_cmd_resp_buf =
+		isp4if_gpu_mem_alloc(ispif, ISP4IF_RB_PMBMAP_MEM_SIZE);
+	if (!ispif->fw_cmd_resp_buf)
+		goto error_no_memory;
+
+	ispif->fw_log_buf =
+		isp4if_gpu_mem_alloc(ispif, ISP4IF_FW_LOG_RINGBUF_SIZE);
+	if (!ispif->fw_log_buf)
+		goto error_no_memory;
+
+	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
+		ispif->metainfo_buf_pool[i] =
+			isp4if_gpu_mem_alloc(ispif,
+					     ISP4IF_META_INFO_BUF_SIZE);
+		if (!ispif->metainfo_buf_pool[i])
+			goto error_no_memory;
+	}
+
+	return 0;
+
+error_no_memory:
+	dev_err(dev, "failed to allocate gpu memory");
+	return -ENOMEM;
+}
+
+static u32 isp4if_compute_check_sum(u8 *buf, u32 buf_size)
+{
+	u32 checksum = 0;
+	u8 *surplus_ptr;
+	u32 *buffer;
+	u32 i;
+
+	buffer = (u32 *)buf;
+	for (i = 0; i < buf_size / sizeof(u32); i++)
+		checksum += buffer[i];
+
+	surplus_ptr = (u8 *)&buffer[i];
+	/* add surplus data crc checksum */
+	for (i = 0; i < buf_size % sizeof(u32); i++)
+		checksum += surplus_ptr[i];
+
+	return checksum;
+}
+
+void isp4if_clear_cmdq(struct isp4_interface *ispif)
+{
+	struct isp4if_cmd_element *buf_node = NULL;
+	struct isp4if_cmd_element *tmp_node = NULL;
+
+	guard(mutex)(&ispif->cmdq_mutex);
+
+	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
+		list_del(&buf_node->list);
+		kfree(buf_node);
+	}
+}
+
+static bool isp4if_is_cmdq_rb_full(struct isp4_interface *ispif,
+				   enum isp4if_stream_id cmd_buf_idx)
+{
+	struct isp4if_rb_config *rb_config;
+	u32 rd_ptr, wr_ptr;
+	u32 new_wr_ptr;
+	u32 rreg;
+	u32 wreg;
+	u32 len;
+
+	rb_config = &isp4if_cmd_rb_config[cmd_buf_idx];
+	rreg = rb_config->reg_rptr;
+	wreg = rb_config->reg_wptr;
+	len = rb_config->val_size;
+
+	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
+	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
+
+	new_wr_ptr = wr_ptr + sizeof(struct isp4fw_cmd);
+
+	if (wr_ptr >= rd_ptr) {
+		if (new_wr_ptr < len) {
+			return false;
+		} else if (new_wr_ptr == len) {
+			if (rd_ptr == 0)
+				return true;
+
+			return false;
+		}
+
+		new_wr_ptr -= len;
+		if (new_wr_ptr < rd_ptr)
+			return false;
+
+		return true;
+	}
+
+	if (new_wr_ptr < rd_ptr)
+		return false;
+
+	return true;
+}
+
+static struct isp4if_cmd_element *
+isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
+			 struct isp4if_cmd_element *cmd_ele)
+{
+	struct isp4if_cmd_element *copy_command = NULL;
+
+	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
+	if (!copy_command)
+		return NULL;
+
+	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
+
+	guard(mutex)(&ispif->cmdq_mutex);
+
+	list_add_tail(&copy_command->list, &ispif->cmdq);
+
+	return copy_command;
+}
+
+struct isp4if_cmd_element *
+isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
+			u32 seq_num,
+			u32 cmd_id)
+{
+	struct isp4if_cmd_element *buf_node = NULL;
+	struct isp4if_cmd_element *tmp_node = NULL;
+
+	guard(mutex)(&ispif->cmdq_mutex);
+
+	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
+		if (buf_node->seq_num == seq_num &&
+		    buf_node->cmd_id == cmd_id) {
+			list_del(&buf_node->list);
+			return buf_node;
+		}
+	}
+
+	return NULL;
+}
+
+static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
+				    enum isp4if_stream_id stream,
+				    struct isp4fw_cmd *cmd)
+{
+	struct isp4if_rb_config *rb_config;
+	struct device *dev = ispif->dev;
+	u64 mem_addr;
+	u64 mem_sys;
+	u32 wr_ptr;
+	u32 rd_ptr;
+	u32 rreg;
+	u32 wreg;
+	u32 len;
+
+	rb_config = &isp4if_cmd_rb_config[stream];
+	rreg = rb_config->reg_rptr;
+	wreg = rb_config->reg_wptr;
+	mem_sys = (u64)rb_config->base_sys_addr;
+	mem_addr = rb_config->base_mc_addr;
+	len = rb_config->val_size;
+
+	if (isp4if_is_cmdq_rb_full(ispif, stream)) {
+		dev_err(dev, "fail no cmdslot (%d)\n", stream);
+		return -EINVAL;
+	}
+
+	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
+	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
+
+	if (rd_ptr > len) {
+		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
+			stream, rd_ptr, len, wr_ptr);
+		return -EINVAL;
+	}
+
+	if (wr_ptr > len) {
+		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
+			stream, wr_ptr, len, rd_ptr);
+		return -EINVAL;
+	}
+
+	if (wr_ptr < rd_ptr) {
+		mem_addr += wr_ptr;
+
+		memcpy((u8 *)(mem_sys + wr_ptr),
+		       (u8 *)cmd, sizeof(struct isp4fw_cmd));
+	} else {
+		if ((len - wr_ptr) >= (sizeof(struct isp4fw_cmd))) {
+			mem_addr += wr_ptr;
+
+			memcpy((u8 *)(mem_sys + wr_ptr),
+			       (u8 *)cmd, sizeof(struct isp4fw_cmd));
+		} else {
+			u32 size;
+			u8 *src;
+
+			src = (u8 *)cmd;
+			size = len - wr_ptr;
+
+			memcpy((u8 *)(mem_sys + wr_ptr), src, size);
+
+			src += size;
+			size = sizeof(struct isp4fw_cmd) - size;
+			memcpy((u8 *)(mem_sys), src, size);
+		}
+	}
+
+	wr_ptr += sizeof(struct isp4fw_cmd);
+	if (wr_ptr >= len)
+		wr_ptr -= len;
+
+	isp4hw_wreg(ispif->mmio, wreg, wr_ptr);
+
+	return 0;
+}
+
+static inline enum isp4if_stream_id isp4if_get_fw_stream(u32 cmd_id)
+{
+	return ISP4IF_STREAM_ID_1;
+}
+
+static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
+			      u32 cmd_id,
+			      void *package,
+			      u32 package_size,
+			      wait_queue_head_t *wq,
+			      u32 *wq_cond,
+			      u32 *seq)
+{
+	enum isp4if_stream_id stream = isp4if_get_fw_stream(cmd_id);
+	struct isp4if_cmd_element command_element = { 0 };
+	struct isp4if_gpu_mem_info *gpu_mem = NULL;
+	struct isp4if_cmd_element *cmd_ele = NULL;
+	struct isp4if_rb_config *rb_config;
+	struct device *dev = ispif->dev;
+	struct isp4fw_cmd cmd = {0};
+	u64 package_base = 0;
+	u32 sleep_count;
+	u32 seq_num;
+	u32 rreg;
+	u32 wreg;
+	int ret;
+
+	if (package_size > sizeof(cmd.cmd_param)) {
+		dev_err(dev, "fail pkgsize(%u)>%lu cmd:0x%x,stream %d\n",
+			package_size, sizeof(cmd.cmd_param), cmd_id, stream);
+		return -EINVAL;
+	}
+
+	sleep_count = 0;
+
+	rb_config = &isp4if_resp_rb_config[stream];
+	rreg = rb_config->reg_rptr;
+	wreg = rb_config->reg_wptr;
+
+	guard(mutex)(&ispif->isp4if_mutex);
+
+	while (1) {
+		if (isp4if_is_cmdq_rb_full(ispif, stream)) {
+			u32 rd_ptr, wr_ptr;
+
+			if (sleep_count < ISP4IF_MAX_SLEEP_COUNT) {
+				msleep(ISP4IF_MAX_SLEEP_TIME);
+				sleep_count++;
+				continue;
+			}
+			rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
+			wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
+			dev_err(dev, "fail to get cmdq slot,stream (%d), rd %u, wr %u\n",
+				stream, rd_ptr, wr_ptr);
+			return -ETIMEDOUT;
+		}
+		break;
+	}
+
+	cmd.cmd_id = cmd_id;
+	switch (stream) {
+	case ISP4IF_STREAM_ID_GLOBAL:
+		cmd.cmd_stream_id = (u16)STREAM_ID_INVALID;
+		break;
+	case ISP4IF_STREAM_ID_1:
+		cmd.cmd_stream_id = STREAM_ID_1;
+		break;
+	default:
+		dev_err(dev, "fail bad stream id %d\n", stream);
+		return -EINVAL;
+	}
+
+	if (package && package_size)
+		memcpy(cmd.cmd_param, package, package_size);
+
+	seq_num = ispif->host2fw_seq_num++;
+	cmd.cmd_seq_num = seq_num;
+	cmd.cmd_check_sum =
+		isp4if_compute_check_sum((u8 *)&cmd, sizeof(cmd) - 4);
+
+	if (seq)
+		*seq = seq_num;
+	command_element.seq_num = seq_num;
+	command_element.cmd_id = cmd_id;
+	command_element.mc_addr = package_base;
+	command_element.wq = wq;
+	command_element.wq_cond = wq_cond;
+	command_element.gpu_pkg = gpu_mem;
+	command_element.stream = stream;
+	/* only append the fw cmd to queue when its response needs to be
+	 * waited for, currently there are only two such commands,
+	 * disable channel and stop stream which are only sent after close
+	 * camera
+	 */
+	if (wq && wq_cond) {
+		cmd_ele = isp4if_append_cmd_2_cmdq(ispif, &command_element);
+		if (!cmd_ele) {
+			dev_err(dev, "fail for isp_append_cmd_2_cmdq\n");
+			return -ENOMEM;
+		}
+	}
+
+	ret = isp4if_insert_isp_fw_cmd(ispif, stream, &cmd);
+	if (ret) {
+		dev_err(dev, "fail for insert_isp_fw_cmd camId (0x%08x)\n",
+			cmd_id);
+		if (cmd_ele) {
+			isp4if_rm_cmd_from_cmdq(ispif, cmd_ele->seq_num,
+						cmd_ele->cmd_id);
+			kfree(cmd_ele);
+		}
+	}
+
+	return ret;
+}
+
+static int isp4if_send_buffer(struct isp4_interface *ispif,
+			      struct isp4if_img_buf_info *buf_info)
+{
+	struct isp4fw_cmd_send_buffer cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.buffer_type = BUFFER_TYPE_PREVIEW;
+	cmd.buffer.vmid_space.bit.vmid = 0;
+	cmd.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA;
+	isp4if_split_addr64(buf_info->planes[0].mc_addr,
+			    &cmd.buffer.buf_base_a_lo,
+			    &cmd.buffer.buf_base_a_hi);
+	cmd.buffer.buf_size_a = buf_info->planes[0].len;
+
+	isp4if_split_addr64(buf_info->planes[1].mc_addr,
+			    &cmd.buffer.buf_base_b_lo,
+			    &cmd.buffer.buf_base_b_hi);
+	cmd.buffer.buf_size_b = buf_info->planes[1].len;
+
+	isp4if_split_addr64(buf_info->planes[2].mc_addr,
+			    &cmd.buffer.buf_base_c_lo,
+			    &cmd.buffer.buf_base_c_hi);
+	cmd.buffer.buf_size_c = buf_info->planes[2].len;
+
+	return isp4if_send_fw_cmd(ispif, CMD_ID_SEND_BUFFER, &cmd,
+				  sizeof(cmd), NULL, NULL, NULL);
+}
+
+static void isp4if_init_rb_config(struct isp4_interface *ispif,
+				  struct isp4if_rb_config *rb_config)
+{
+	u32 lo;
+	u32 hi;
+
+	isp4if_split_addr64(rb_config->base_mc_addr, &lo, &hi);
+
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+		    rb_config->reg_rptr, 0x0);
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+		    rb_config->reg_wptr, 0x0);
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+		    rb_config->reg_base_lo, lo);
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+		    rb_config->reg_base_hi, hi);
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+		    rb_config->reg_size, rb_config->val_size);
+}
+
+static int isp4if_fw_init(struct isp4_interface *ispif)
+{
+	struct isp4if_rb_config *rb_config;
+	u32 offset;
+	int i;
+
+	/* initialize CMD_RB streams */
+	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
+		rb_config = (isp4if_cmd_rb_config + i);
+		offset = ispif->aligned_rb_chunk_size *
+			 (rb_config->index + ispif->cmd_rb_base_index);
+
+		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
+		rb_config->base_sys_addr =
+			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
+		rb_config->base_mc_addr =
+			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
+
+		isp4if_init_rb_config(ispif, rb_config);
+	}
+
+	/* initialize RESP_RB streams */
+	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
+		rb_config = (isp4if_resp_rb_config + i);
+		offset = ispif->aligned_rb_chunk_size *
+			 (rb_config->index + ispif->resp_rb_base_index);
+
+		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
+		rb_config->base_sys_addr =
+			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
+		rb_config->base_mc_addr =
+			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
+
+		isp4if_init_rb_config(ispif, rb_config);
+	}
+
+	/* initialize LOG_RB stream */
+	rb_config = &isp4if_log_rb_config;
+	rb_config->val_size = ISP4IF_FW_LOG_RINGBUF_SIZE;
+	rb_config->base_mc_addr = ispif->fw_log_buf->gpu_mc_addr;
+	rb_config->base_sys_addr = ispif->fw_log_buf->sys_addr;
+
+	isp4if_init_rb_config(ispif, rb_config);
+
+	return 0;
+}
+
+static int isp4if_wait_fw_ready(struct isp4_interface *ispif,
+				u32 isp_status_addr)
+{
+	struct device *dev = ispif->dev;
+	u32 fw_ready_timeout;
+	u32 timeout_ms = 100;
+	u32 interval_ms = 1;
+	u32 timeout = 0;
+	u32 reg_val;
+
+	fw_ready_timeout = timeout_ms / interval_ms;
+
+	/* wait for FW initialize done! */
+	while (timeout < fw_ready_timeout) {
+		reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif),
+				      isp_status_addr);
+		if (reg_val & ISP_STATUS__CCPU_REPORT_MASK)
+			return 0;
+
+		msleep(interval_ms);
+		timeout++;
+	}
+
+	dev_err(dev, "ISP CCPU FW boot failed\n");
+
+	return -ETIME;
+}
+
+static void isp4if_enable_ccpu(struct isp4_interface *ispif)
+{
+	u32 reg_val;
+
+	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
+	reg_val &= (~ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK);
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
+
+	usleep_range(100, 150);
+
+	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
+	reg_val &= (~ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK);
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
+}
+
+static void isp4if_disable_ccpu(struct isp4_interface *ispif)
+{
+	u32 reg_val;
+
+	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
+	reg_val |= ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK;
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
+
+	usleep_range(100, 150);
+
+	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
+	reg_val |= ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK;
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
+}
+
+static int isp4if_fw_boot(struct isp4_interface *ispif)
+{
+	struct device *dev = ispif->dev;
+
+	if (ispif->status != ISP4IF_STATUS_PWR_ON) {
+		dev_err(dev, "invalid isp power status %d\n", ispif->status);
+		return -EINVAL;
+	}
+
+	isp4if_disable_ccpu(ispif);
+
+	isp4if_fw_init(ispif);
+
+	/* clear ccpu status */
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_STATUS, 0x0);
+
+	isp4if_enable_ccpu(ispif);
+
+	if (isp4if_wait_fw_ready(ispif, ISP_STATUS)) {
+		isp4if_disable_ccpu(ispif);
+		return -EINVAL;
+	}
+
+	/* enable interrupts */
+	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SYS_INT0_EN,
+		    ISP4IF_FW_RESP_RB_IRQ_EN_MASK);
+
+	ispif->status = ISP4IF_STATUS_FW_RUNNING;
+
+	dev_dbg(dev, "ISP CCPU FW boot success\n");
+
+	return 0;
+}
+
+int isp4if_f2h_resp(struct isp4_interface *ispif,
+		    enum isp4if_stream_id stream,
+		    void *resp)
+{
+	struct isp4fw_resp *response = resp;
+	struct isp4if_rb_config *rb_config;
+	struct device *dev = ispif->dev;
+	u32 rd_ptr_dbg;
+	u32 wr_ptr_dbg;
+	void *mem_sys;
+	u64 mem_addr;
+	u32 checksum;
+	u32 rd_ptr;
+	u32 wr_ptr;
+	u32 rreg;
+	u32 wreg;
+	u32 len;
+
+	rb_config = &isp4if_resp_rb_config[stream];
+	rreg = rb_config->reg_rptr;
+	wreg = rb_config->reg_wptr;
+	mem_sys = rb_config->base_sys_addr;
+	mem_addr = rb_config->base_mc_addr;
+	len = rb_config->val_size;
+
+	rd_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), rreg);
+	wr_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), wreg);
+	rd_ptr_dbg = rd_ptr;
+	wr_ptr_dbg = wr_ptr;
+
+	if (rd_ptr > len) {
+		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
+			stream, rd_ptr, len, wr_ptr);
+		return -EINVAL;
+	}
+
+	if (wr_ptr > len) {
+		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
+			stream, wr_ptr, len, rd_ptr);
+		return -EINVAL;
+	}
+
+	if (rd_ptr < wr_ptr) {
+		if ((wr_ptr - rd_ptr) >= (sizeof(struct isp4fw_resp))) {
+			memcpy((u8 *)response, (u8 *)mem_sys + rd_ptr,
+			       sizeof(struct isp4fw_resp));
+
+			rd_ptr += sizeof(struct isp4fw_resp);
+			if (rd_ptr < len) {
+				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+					    rreg, rd_ptr);
+			} else {
+				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
+					stream, rd_ptr, len, wr_ptr);
+				return -EINVAL;
+			}
+
+		} else {
+			dev_err(dev, "sth wrong with wptr and rptr\n");
+			return -EINVAL;
+		}
+	} else if (rd_ptr > wr_ptr) {
+		u32 size;
+		u8 *dst;
+
+		dst = (u8 *)response;
+
+		size = len - rd_ptr;
+		if (size > sizeof(struct isp4fw_resp)) {
+			mem_addr += rd_ptr;
+			memcpy((u8 *)response,
+			       (u8 *)(mem_sys) + rd_ptr,
+			       sizeof(struct isp4fw_resp));
+			rd_ptr += sizeof(struct isp4fw_resp);
+			if (rd_ptr < len) {
+				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+					    rreg, rd_ptr);
+			} else {
+				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
+					stream, rd_ptr, len, wr_ptr);
+				return -EINVAL;
+			}
+
+		} else {
+			if ((size + wr_ptr) < (sizeof(struct isp4fw_resp))) {
+				dev_err(dev, "sth wrong with wptr and rptr1\n");
+				return -EINVAL;
+			}
+
+			memcpy(dst, (u8 *)(mem_sys) + rd_ptr, size);
+
+			dst += size;
+			size = sizeof(struct isp4fw_resp) - size;
+			if (size)
+				memcpy(dst, (u8 *)(mem_sys), size);
+			rd_ptr = size;
+			if (rd_ptr < len) {
+				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
+					    rreg, rd_ptr);
+			} else {
+				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
+					stream, rd_ptr, len, wr_ptr);
+				return -EINVAL;
+			}
+		}
+	} else {
+		return -ETIME;
+	}
+
+	checksum = isp4if_compute_check_sum((u8 *)response,
+					    (sizeof(struct isp4fw_resp) - 4));
+
+	if (checksum != response->resp_check_sum) {
+		dev_err(dev, "resp checksum 0x%x,should 0x%x,rptr %u,wptr %u\n",
+			checksum, response->resp_check_sum,
+			rd_ptr_dbg, wr_ptr_dbg);
+
+		dev_err(dev, "(%u), seqNo %u, resp_id (0x%x)\n",
+			stream,
+			response->resp_seq_num,
+			response->resp_id);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int isp4if_send_command(struct isp4_interface *ispif,
+			u32 cmd_id,
+			void *package,
+			u32 package_size)
+{
+	return isp4if_send_fw_cmd(ispif,
+				  cmd_id, package,
+				  package_size, NULL, NULL, NULL);
+}
+
+int isp4if_send_command_sync(struct isp4_interface *ispif,
+			     u32 cmd_id,
+			     void *package,
+			     u32 package_size,
+			     u32 timeout)
+{
+	struct device *dev = ispif->dev;
+	DECLARE_WAIT_QUEUE_HEAD(cmd_wq);
+	u32 wq_cond = 0;
+	int ret;
+	u32 seq;
+
+	ret = isp4if_send_fw_cmd(ispif,
+				 cmd_id, package,
+				 package_size, &cmd_wq, &wq_cond, &seq);
+
+	if (ret) {
+		dev_err(dev, "send fw cmd fail %d\n", ret);
+		return ret;
+	}
+
+	ret = wait_event_timeout(cmd_wq, wq_cond != 0,
+				 msecs_to_jiffies(timeout));
+
+	/* timeout occurred */
+	if (ret == 0) {
+		struct isp4if_cmd_element *ele;
+
+		ele = isp4if_rm_cmd_from_cmdq(ispif, seq, cmd_id);
+		kfree(ele);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+void isp4if_clear_bufq(struct isp4_interface *ispif)
+{
+	struct isp4if_img_buf_node *buf_node = NULL;
+	struct isp4if_img_buf_node *tmp_node = NULL;
+
+	guard(mutex)(&ispif->bufq_mutex);
+
+	list_for_each_entry_safe(buf_node, tmp_node, &ispif->bufq,
+				 node) {
+		list_del(&buf_node->node);
+		kfree(buf_node);
+	}
+}
+
+void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node)
+{
+	kfree(buf_node);
+}
+
+struct isp4if_img_buf_node *
+isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info)
+{
+	struct isp4if_img_buf_node *node = NULL;
+
+	node = kmalloc(sizeof(*node), GFP_KERNEL);
+	if (node)
+		node->buf_info = *buf_info;
+
+	return node;
+};
+
+struct isp4if_img_buf_node *
+isp4if_dequeue_buffer(struct isp4_interface *ispif)
+{
+	struct isp4if_img_buf_node *buf_node = NULL;
+
+	guard(mutex)(&ispif->bufq_mutex);
+
+	buf_node = list_first_entry_or_null(&ispif->bufq,
+					    typeof(*buf_node),
+					    node);
+	if (buf_node)
+		list_del(&buf_node->node);
+
+	return buf_node;
+}
+
+int isp4if_queue_buffer(struct isp4_interface *ispif,
+			struct isp4if_img_buf_node *buf_node)
+{
+	int ret;
+
+	ret = isp4if_send_buffer(ispif, &buf_node->buf_info);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&ispif->bufq_mutex);
+
+	list_add_tail(&buf_node->node, &ispif->bufq);
+
+	return 0;
+}
+
+int isp4if_stop(struct isp4_interface *ispif)
+{
+	isp4if_disable_ccpu(ispif);
+
+	isp4if_dealloc_fw_gpumem(ispif);
+
+	return 0;
+}
+
+int isp4if_start(struct isp4_interface *ispif)
+{
+	int ret;
+
+	ret = isp4if_alloc_fw_gpumem(ispif);
+	if (ret)
+		goto failed_gpumem_alloc;
+
+	ret = isp4if_fw_boot(ispif);
+	if (ret)
+		goto failed_fw_boot;
+
+	return 0;
+
+failed_gpumem_alloc:
+	return -ENOMEM;
+
+failed_fw_boot:
+	isp4if_dealloc_fw_gpumem(ispif);
+	return ret;
+}
+
+int isp4if_deinit(struct isp4_interface *ispif)
+{
+	isp4if_clear_cmdq(ispif);
+
+	isp4if_clear_bufq(ispif);
+
+	mutex_destroy(&ispif->cmdq_mutex);
+	mutex_destroy(&ispif->bufq_mutex);
+	mutex_destroy(&ispif->isp4if_mutex);
+
+	return 0;
+}
+
+int isp4if_init(struct isp4_interface *ispif, struct device *dev,
+		void *amdgpu_dev, void __iomem *isp_mmip)
+{
+	ispif->dev = dev;
+	ispif->adev = amdgpu_dev;
+	ispif->mmio = isp_mmip;
+
+	ispif->cmd_rb_base_index = 0;
+	ispif->resp_rb_base_index = ISP4IF_RESP_CHAN_TO_RB_OFFSET - 1;
+	ispif->aligned_rb_chunk_size = ISP4IF_RB_PMBMAP_MEM_CHUNK & 0xffffffc0;
+
+	mutex_init(&ispif->cmdq_mutex); /* used for cmdq access */
+	mutex_init(&ispif->bufq_mutex); /* used for bufq access */
+	mutex_init(&ispif->isp4if_mutex); /* used for commands sent to ispfw */
+
+	INIT_LIST_HEAD(&ispif->cmdq);
+	INIT_LIST_HEAD(&ispif->bufq);
+
+	return 0;
+}
diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/drivers/media/platform/amd/isp4/isp4_interface.h
new file mode 100644
index 000000000000..b2ca147b78b6
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_interface.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _ISP4_INTERFACE_
+#define _ISP4_INTERFACE_
+
+#define ISP4IF_RB_MAX (25)
+#define ISP4IF_RESP_CHAN_TO_RB_OFFSET (9)
+#define ISP4IF_RB_PMBMAP_MEM_SIZE (16 * 1024 * 1024 - 1)
+#define ISP4IF_RB_PMBMAP_MEM_CHUNK (ISP4IF_RB_PMBMAP_MEM_SIZE \
+	/ (ISP4IF_RB_MAX - 1))
+#define ISP4IF_ISP_MC_ADDR_ALIGN (1024 * 32)
+#define ISP4IF_HOST2FW_COMMAND_SIZE (sizeof(struct isp4fw_cmd))
+#define ISP4IF_FW_CMD_BUF_COUNT 4
+#define ISP4IF_FW_RESP_BUF_COUNT 4
+#define ISP4IF_MAX_NUM_HOST2FW_COMMAND (40)
+#define ISP4IF_FW_CMD_BUF_SIZE (ISP4IF_MAX_NUM_HOST2FW_COMMAND \
+	* ISP4IF_HOST2FW_COMMAND_SIZE)
+#define ISP4IF_MAX_SLEEP_COUNT (10)
+#define ISP4IF_MAX_SLEEP_TIME (33)
+
+#define ISP4IF_META_INFO_BUF_SIZE ALIGN(sizeof(struct isp4fw_meta_info), 0x8000)
+#define ISP4IF_MAX_STREAM_META_BUF_COUNT 6
+
+#define ISP4IF_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
+
+#define ISP4IF_MAX_CMD_RESPONSE_BUF_SIZE (4 * 1024)
+
+#define GET_ISP4IF_REG_BASE(ispif) (((ispif))->mmio)
+
+enum isp4if_stream_id {
+	ISP4IF_STREAM_ID_GLOBAL = 0,
+	ISP4IF_STREAM_ID_1 = 1,
+	ISP4IF_STREAM_ID_MAX = 4
+};
+
+enum isp4if_status {
+	ISP4IF_STATUS_PWR_OFF,
+	ISP4IF_STATUS_PWR_ON,
+	ISP4IF_STATUS_FW_RUNNING,
+	ISP4IF_FSM_STATUS_MAX
+};
+
+struct isp4if_gpu_mem_info {
+	u32	mem_domain;
+	u64	mem_size;
+	u32	mem_align;
+	u64	gpu_mc_addr;
+	void	*sys_addr;
+	void	*mem_handle;
+};
+
+struct isp4if_img_buf_info {
+	struct {
+		void *sys_addr;
+		u64 mc_addr;
+		u32 len;
+	} planes[3];
+};
+
+struct isp4if_img_buf_node {
+	struct list_head node;
+	struct isp4if_img_buf_info buf_info;
+};
+
+struct isp4if_cmd_element {
+	struct list_head list;
+	u32 seq_num;
+	u32 cmd_id;
+	enum isp4if_stream_id stream;
+	u64 mc_addr;
+	wait_queue_head_t *wq;
+	u32 *wq_cond;
+	struct isp4if_gpu_mem_info *gpu_pkg;
+};
+
+struct isp4_interface {
+	struct amdgpu_device *adev;
+
+	struct device *dev;
+	void __iomem *mmio;
+
+	struct mutex cmdq_mutex; /* used for cmdq access */
+	struct mutex bufq_mutex; /* used for bufq access */
+	struct mutex isp4if_mutex; /* used to send fw cmd and read fw log */
+
+	struct list_head cmdq; /* commands sent to fw */
+	struct list_head bufq; /* buffers sent to fw */
+
+	enum isp4if_status status;
+	u32 host2fw_seq_num;
+
+	/* FW ring buffer configs */
+	u32 cmd_rb_base_index;
+	u32 resp_rb_base_index;
+	u32 aligned_rb_chunk_size;
+
+	/* ISP fw buffers */
+	struct isp4if_gpu_mem_info *fw_log_buf;
+	struct isp4if_gpu_mem_info *fw_cmd_resp_buf;
+	struct isp4if_gpu_mem_info *fw_mem_pool;
+	struct isp4if_gpu_mem_info *
+		metainfo_buf_pool[ISP4IF_MAX_STREAM_META_BUF_COUNT];
+};
+
+static inline void isp4if_split_addr64(u64 addr, u32 *lo, u32 *hi)
+{
+	if (lo)
+		*lo = (u32)(addr & 0xffffffff);
+	if (hi)
+		*hi = (u32)(addr >> 32);
+}
+
+static inline u64 isp4if_join_addr64(u32 lo, u32 hi)
+{
+	return (((u64)hi) << 32) | (u64)lo;
+}
+
+int isp4if_f2h_resp(struct isp4_interface *ispif,
+		    enum isp4if_stream_id stream,
+		    void *response);
+
+int isp4if_send_command(struct isp4_interface *ispif,
+			u32 cmd_id,
+			void *package,
+			u32 package_size);
+
+int isp4if_send_command_sync(struct isp4_interface *ispif,
+			     u32 cmd_id,
+			     void *package,
+			     u32 package_size,
+			     u32 timeout);
+
+struct isp4if_cmd_element *
+isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
+			u32 seq_num,
+			u32 cmd_id);
+
+void isp4if_clear_cmdq(struct isp4_interface *ispif);
+
+void isp4if_clear_bufq(struct isp4_interface *ispif);
+
+void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node);
+
+struct isp4if_img_buf_node *
+isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info);
+
+struct isp4if_img_buf_node *isp4if_dequeue_buffer(struct isp4_interface *ispif);
+
+int isp4if_queue_buffer(struct isp4_interface *ispif,
+			struct isp4if_img_buf_node *buf_node);
+
+int isp4if_stop(struct isp4_interface *ispif);
+
+int isp4if_start(struct isp4_interface *ispif);
+
+int isp4if_deinit(struct isp4_interface *ispif);
+
+int isp4if_init(struct isp4_interface *ispif, struct device *dev,
+		void *amdgpu_dev, void __iomem *isp_mmip);
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (3 preceding siblings ...)
  2025-06-18  9:19 ` [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-06-18 16:35   ` Mario Limonciello
  2025-07-25  1:35   ` Sultan Alsawaf
  2025-06-18  9:19 ` [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers " Bin Du
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

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 <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 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 <linux/pm_runtime.h>
 #include <linux/vmalloc.h>
+#include <media/v4l2-fwnode.h>
 #include <media/v4l2-ioctl.h>
 
-#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 <linux/mutex.h>
-#include <media/v4l2-device.h>
 #include <media/videobuf2-memops.h>
 #include <media/videobuf2-vmalloc.h>
+#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 <linux/mutex.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "isp4_fw_cmd_resp.h"
+#include "isp4_hw.h"
+#include "isp4_interface.h"
+#include "isp4_phy.h"
+#include "isp4_subdev.h"
+#include <linux/units.h>
+
+#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 <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-vmalloc.h>
+
+#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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (4 preceding siblings ...)
  2025-06-18  9:19 ` [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-07-23 17:55   ` Sultan Alsawaf
  2025-07-28  7:04   ` Sultan Alsawaf
  2025-06-18  9:19 ` [PATCH v2 7/8] media: platform: amd: isp4 debug fs logging and more descriptive errors Bin Du
                   ` (3 subsequent siblings)
  9 siblings, 2 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

Isp video implements v4l2 video interface and supports NV12 and YUYV.
It manages buffers, pipeline power and state.

Signed-off-by: Bin Du <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 drivers/media/platform/amd/isp4/Makefile      |    1 +
 drivers/media/platform/amd/isp4/isp4.c        |   13 +-
 drivers/media/platform/amd/isp4/isp4_subdev.c |  119 +-
 drivers/media/platform/amd/isp4/isp4_subdev.h |    2 +
 drivers/media/platform/amd/isp4/isp4_video.c  | 1443 +++++++++++++++++
 drivers/media/platform/amd/isp4/isp4_video.h  |   93 ++
 6 files changed, 1661 insertions(+), 10 deletions(-)
 create mode 100644 drivers/media/platform/amd/isp4/isp4_video.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_video.h

diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
index 52defc06189e..99285fe45b52 100644
--- a/drivers/media/platform/amd/isp4/Makefile
+++ b/drivers/media/platform/amd/isp4/Makefile
@@ -7,6 +7,7 @@ amd_capture-objs := isp4_subdev.o \
 			isp4_phy.o \
 			isp4_interface.o \
 			isp4.o	\
+			isp4_video.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 c1aca2bd35e3..3d971fe2813d 100644
--- a/drivers/media/platform/amd/isp4/isp4.c
+++ b/drivers/media/platform/amd/isp4/isp4.c
@@ -337,6 +337,16 @@ static int isp4_capture_probe(struct platform_device *pdev)
 		goto err_isp4_deinit;
 	}
 
+	ret = media_create_pad_link(&isp_dev->isp_sdev.sdev.entity,
+				    1, &isp_dev->isp_sdev.isp_vdev.vdev.entity,
+				    0,
+				    MEDIA_LNK_FL_ENABLED |
+				    MEDIA_LNK_FL_IMMUTABLE);
+	if (ret) {
+		dev_err(dev, "fail to create pad link %d\n", ret);
+		goto err_unreg_video_dev_notifier;
+	}
+
 	platform_set_drvdata(pdev, isp_dev);
 
 	pm_runtime_set_suspended(dev);
@@ -344,9 +354,10 @@ static int isp4_capture_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_isp4_deinit:
+err_unreg_video_dev_notifier:
 	v4l2_async_nf_unregister(&isp_dev->notifier);
 	v4l2_async_nf_cleanup(&isp_dev->notifier);
+err_isp4_deinit:
 	isp4sd_deinit(&isp_dev->isp_sdev);
 err_unreg_v4l2:
 	v4l2_device_unregister(&isp_dev->v4l2_dev);
diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.c b/drivers/media/platform/amd/isp4/isp4_subdev.c
index 978164031067..d93cdb9dc477 100644
--- a/drivers/media/platform/amd/isp4/isp4_subdev.c
+++ b/drivers/media/platform/amd/isp4/isp4_subdev.c
@@ -168,6 +168,24 @@ static int isp4sd_enum_mbus_code(struct v4l2_subdev *isp_subdev,
 	return 0;
 }
 
+static int isp4sd_enum_frame_size(struct v4l2_subdev *isp_subdev,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct v4l2_frmsize_discrete min, max;
+
+	if (fse->index >= ARRAY_SIZE(isp4sd_image_formats))
+		return -EINVAL;
+
+	isp4vid_frmsize_range(&min, &max);
+	fse->min_width = min.width;
+	fse->max_width = max.width;
+	fse->min_height = min.height;
+	fse->max_height = max.height;
+
+	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)
@@ -510,25 +528,25 @@ isp4sd_get_meta_by_mc(struct isp4_subdev *isp_subdev,
 
 static struct isp4if_img_buf_node *
 isp4sd_preview_done(struct isp4_subdev *isp_subdev,
-		    struct isp4fw_meta_info *meta)
+		    struct isp4fw_meta_info *meta,
+		    struct isp4vid_framedone_param *pcb)
 {
 	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;
-	}
-
+	pcb->preview.status = ISP4VID_BUF_DONE_STATUS_ABSENT;
 	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)
+		if (!prev) {
 			dev_err(dev, "fail null prev buf\n");
-
+		} else {
+			pcb->preview.buf = prev->buf_info;
+			pcb->preview.status = ISP4VID_BUF_DONE_STATUS_SUCCESS;
+		}
 	} else if (meta->preview.enabled) {
 		dev_err(dev, "fail bad preview status %u\n",
 			meta->preview.status);
@@ -575,6 +593,7 @@ 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 isp4vid_framedone_param pcb = {0};
 	struct isp4if_img_buf_node *prev = NULL;
 	struct device *dev = isp_subdev->dev;
 	struct isp4fw_meta_info *meta;
@@ -587,12 +606,17 @@ static void isp4sd_fw_resp_frame_done(struct isp4_subdev *isp_subdev,
 		return;
 	}
 
+	pcb.poc = meta->poc;
+	pcb.cam_id = 0;
+
 	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);
+	prev = isp4sd_preview_done(isp_subdev, meta, &pcb);
+	if (pcb.preview.status != ISP4VID_BUF_DONE_STATUS_ABSENT)
+		isp4vid_notify(&isp_subdev->isp_vdev, &pcb);
 
 	isp4if_dealloc_buffer_node(prev);
 
@@ -969,6 +993,75 @@ static int isp4sd_start_stream(struct isp4_subdev *isp_subdev,
 	return ret;
 }
 
+static int isp4sd_ioc_send_img_buf(struct isp4vid_dev *sd,
+				   struct isp4if_img_buf_info *buf_info)
+{
+	struct isp4_subdev *isp_subdev = to_isp4_vdev(sd);
+	struct isp4_interface *ispif = &isp_subdev->ispif;
+	struct isp4if_img_buf_node *buf_node = NULL;
+	struct device *dev = isp_subdev->dev;
+	int ret = -EINVAL;
+
+	mutex_lock(&isp_subdev->ops_mutex);
+	/* TODO: remove isp_status */
+	if (ispif->status != ISP4IF_STATUS_FW_RUNNING) {
+		dev_err(dev, "fail send img buf for bad fsm %d\n",
+			ispif->status);
+		mutex_unlock(&isp_subdev->ops_mutex);
+		return -EINVAL;
+	}
+
+	buf_node = isp4if_alloc_buffer_node(buf_info);
+	if (!buf_node) {
+		dev_err(dev, "fail alloc sys img buf info node\n");
+		ret = -ENOMEM;
+		goto unlock_and_return;
+	}
+
+	ret = isp4if_queue_buffer(ispif, buf_node);
+	if (ret) {
+		dev_err(dev, "fail to queue image buf, %d\n", ret);
+		goto error_release_buf_node;
+	}
+
+	if (!isp_subdev->sensor_info.start_stream_cmd_sent) {
+		isp_subdev->sensor_info.buf_sent_cnt++;
+
+		if (isp_subdev->sensor_info.buf_sent_cnt >=
+		    ISP4SD_MIN_BUF_CNT_BEF_START_STREAM) {
+			ret = isp4if_send_command(ispif, CMD_ID_START_STREAM,
+						  NULL, 0);
+
+			if (ret) {
+				dev_err(dev, "fail to START_STREAM");
+				goto error_release_buf_node;
+			}
+			isp_subdev->sensor_info.start_stream_cmd_sent = true;
+			isp_subdev->sensor_info.output_info.start_status =
+				ISP4SD_START_STATUS_STARTED;
+			isp_subdev->sensor_info.status =
+				ISP4SD_START_STATUS_STARTED;
+		} else {
+			dev_dbg(dev,
+				"no send start,required %u,buf sent %u\n",
+				ISP4SD_MIN_BUF_CNT_BEF_START_STREAM,
+				isp_subdev->sensor_info.buf_sent_cnt);
+		}
+	}
+
+	mutex_unlock(&isp_subdev->ops_mutex);
+
+	return 0;
+
+error_release_buf_node:
+	isp4if_dealloc_buffer_node(buf_node);
+
+unlock_and_return:
+	mutex_unlock(&isp_subdev->ops_mutex);
+
+	return ret;
+}
+
 static int isp4sd_subdev_pre_streamon(struct v4l2_subdev *sd, u32 flags)
 {
 	struct isp4_subdev *isp_subdev = to_isp4_subdev(sd);
@@ -1087,6 +1180,7 @@ static int isp4sd_disable_streams(struct v4l2_subdev *sd,
 
 static const struct v4l2_subdev_pad_ops isp4sd_pad_ops = {
 	.enum_mbus_code	= isp4sd_enum_mbus_code,
+	.enum_frame_size = isp4sd_enum_frame_size,
 	.get_fmt = v4l2_subdev_get_fmt,
 	.set_fmt = isp4sd_set_pad_format,
 	.enable_streams = isp4sd_enable_streams,
@@ -1108,6 +1202,10 @@ static const struct media_entity_operations isp4sd_sdev_ent_ops = {
 	.link_validate = isp4sd_sdev_link_validate,
 };
 
+static const struct isp4vid_ops isp4sd_isp4vid_ops = {
+	.send_buffer = isp4sd_ioc_send_img_buf,
+};
+
 int isp4sd_init(struct isp4_subdev *isp_subdev,
 		struct v4l2_device *v4l2_dev,
 		void *amdgpu_dev)
@@ -1171,6 +1269,8 @@ int isp4sd_init(struct isp4_subdev *isp_subdev,
 	isp_subdev->host2fw_seq_num = 1;
 	ispif->status = ISP4IF_STATUS_PWR_OFF;
 
+	ret = isp4vid_dev_init(&isp_subdev->isp_vdev, &isp_subdev->sdev,
+			       &isp4sd_isp4vid_ops, amdgpu_dev);
 	if (ret)
 		goto err_media_clean_up;
 	return ret;
@@ -1184,6 +1284,7 @@ void isp4sd_deinit(struct isp4_subdev *isp_subdev)
 {
 	struct isp4_interface *ispif = &isp_subdev->ispif;
 
+	isp4vid_dev_deinit(&isp_subdev->isp_vdev);
 	media_entity_cleanup(&isp_subdev->sdev.entity);
 	isp4if_deinit(ispif);
 	isp4sd_module_enable(isp_subdev, false);
diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.h b/drivers/media/platform/amd/isp4/isp4_subdev.h
index bcbb93dce18f..7959a119527a 100644
--- a/drivers/media/platform/amd/isp4/isp4_subdev.h
+++ b/drivers/media/platform/amd/isp4/isp4_subdev.h
@@ -18,6 +18,7 @@
 #include "isp4_fw_cmd_resp.h"
 #include "isp4_hw_reg.h"
 #include "isp4_interface.h"
+#include "isp4_video.h"
 
 /*
  * one is for none sesnor specefic response which is not used now
@@ -97,6 +98,7 @@ struct isp4_subdev_thread_param {
 struct isp4_subdev {
 	struct v4l2_subdev sdev;
 	struct isp4_interface ispif;
+	struct isp4vid_dev isp_vdev;
 
 	/*
 	 * sdev_pad[0] is sink pad connected to sensor
diff --git a/drivers/media/platform/amd/isp4/isp4_video.c b/drivers/media/platform/amd/isp4/isp4_video.c
new file mode 100644
index 000000000000..e2898dad9e7e
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_video.c
@@ -0,0 +1,1443 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+
+#include "amdgpu_object.h"
+#include "isp4_interface.h"
+#include "isp4_subdev.h"
+#include "isp4_video.h"
+
+#define ISP4VID_ISP_DRV_NAME "amd_isp_capture"
+#define ISP4VID_VIDEO_BUF_NUM 5
+#define ISP4VID_MAX_PREVIEW_FPS 30
+#define ISP4VID_DEFAULT_FMT isp4vid_formats[0]
+
+#define ISP4VID_PAD_VIDEO_OUTPUT 1
+
+/* timeperframe default */
+#define ISP4VID_ISP_TPF_DEFAULT isp4vid_tpfs[0]
+
+/* amdisp buffer for vb2 operations */
+struct isp4vid_vb2_buf {
+	struct device			*dev;
+	void				*vaddr;
+	struct frame_vector		*vec;
+	enum dma_data_direction		dma_dir;
+	unsigned long			size;
+	refcount_t			refcount;
+	struct dma_buf			*dbuf;
+	void				*bo;
+	u64				gpu_addr;
+	struct vb2_vmarea_handler	handler;
+	bool				is_expbuf;
+};
+
+static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma);
+
+static void isp4vid_vb2_put(void *buf_priv);
+
+static const char *isp4vid_video_dev_name = "Preview";
+
+/* Sizes must be in increasing order */
+static const struct v4l2_frmsize_discrete isp4vid_frmsize[] = {
+	{640, 360},
+	{640, 480},
+	{1280, 720},
+	{1280, 960},
+	{1920, 1080},
+	{1920, 1440},
+	{2560, 1440},
+	{2880, 1620},
+	{2880, 1624},
+	{2888, 1808},
+};
+
+static const u32 isp4vid_formats[] = {
+	V4L2_PIX_FMT_NV12,
+	V4L2_PIX_FMT_YUYV
+};
+
+/* timeperframe list */
+static const struct v4l2_fract isp4vid_tpfs[] = {
+	{.numerator = 1, .denominator = ISP4VID_MAX_PREVIEW_FPS}
+};
+
+static void
+isp4vid_handle_frame_done(struct isp4vid_dev *isp_vdev,
+			  const struct isp4if_img_buf_info *img_buf,
+			  bool done_suc)
+{
+	struct isp4vid_capture_buffer *isp4vid_buf;
+	enum vb2_buffer_state state;
+	void *vbuf;
+
+	mutex_lock(&isp_vdev->buf_list_lock);
+
+	/* Get the first entry of the list */
+	isp4vid_buf = list_first_entry_or_null(&isp_vdev->buf_list,
+					       typeof(*isp4vid_buf), list);
+	if (!isp4vid_buf) {
+		mutex_unlock(&isp_vdev->buf_list_lock);
+		return;
+	}
+
+	vbuf = vb2_plane_vaddr(&isp4vid_buf->vb2.vb2_buf, 0);
+
+	if (vbuf != img_buf->planes[0].sys_addr) {
+		dev_err(isp_vdev->dev, "Invalid vbuf");
+		mutex_unlock(&isp_vdev->buf_list_lock);
+		return;
+	}
+
+	/* Remove this entry from the list */
+	list_del(&isp4vid_buf->list);
+
+	mutex_unlock(&isp_vdev->buf_list_lock);
+
+	/* Fill the buffer */
+	isp4vid_buf->vb2.vb2_buf.timestamp = ktime_get_ns();
+	isp4vid_buf->vb2.sequence = isp_vdev->sequence++;
+	isp4vid_buf->vb2.field = V4L2_FIELD_ANY;
+
+	/* at most 2 planes */
+	vb2_set_plane_payload(&isp4vid_buf->vb2.vb2_buf,
+			      0, isp_vdev->format.sizeimage);
+
+	state = done_suc ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+	vb2_buffer_done(&isp4vid_buf->vb2.vb2_buf, state);
+
+	dev_dbg(isp_vdev->dev, "call vb2_buffer_done(size=%u)\n",
+		isp_vdev->format.sizeimage);
+}
+
+s32 isp4vid_notify(void *cb_ctx, struct isp4vid_framedone_param *evt_param)
+{
+	struct isp4vid_dev *isp4vid_vdev = cb_ctx;
+
+	if (evt_param->preview.status != ISP4VID_BUF_DONE_STATUS_ABSENT) {
+		bool suc;
+
+		suc = (evt_param->preview.status ==
+		       ISP4VID_BUF_DONE_STATUS_SUCCESS);
+		isp4vid_handle_frame_done(isp4vid_vdev,
+					  &evt_param->preview.buf,
+					  suc);
+	}
+
+	return 0;
+}
+
+void isp4vid_frmsize_range(struct v4l2_frmsize_discrete *min,
+			   struct v4l2_frmsize_discrete *max)
+{
+	if (!min || !max) {
+		pr_err("fail, null param\n");
+		return;
+	}
+
+	min->width = isp4vid_frmsize[0].width;
+	min->height = isp4vid_frmsize[0].height;
+	max->width = isp4vid_frmsize[ARRAY_SIZE(isp4vid_frmsize) - 1].width;
+	max->height = isp4vid_frmsize[ARRAY_SIZE(isp4vid_frmsize) - 1].height;
+}
+
+static unsigned int isp4vid_vb2_num_users(void *buf_priv)
+{
+	struct isp4vid_vb2_buf *buf = buf_priv;
+
+	if (!buf) {
+		pr_err("fail null buf handle\n");
+		return 0;
+	}
+	return refcount_read(&buf->refcount);
+}
+
+static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+	struct isp4vid_vb2_buf *buf = buf_priv;
+	int ret;
+
+	if (!buf) {
+		pr_err("fail no memory to map\n");
+		return -EINVAL;
+	}
+
+	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+	if (ret) {
+		dev_err(buf->dev, "fail remap vmalloc mem, %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Make sure that vm_areas for 2 buffers won't be merged together
+	 */
+	vm_flags_set(vma, VM_DONTEXPAND);
+
+	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
+		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
+
+	return 0;
+}
+
+static void *isp4vid_vb2_vaddr(struct vb2_buffer *vb, void *buf_priv)
+{
+	struct isp4vid_vb2_buf *buf = buf_priv;
+
+	if (!buf) {
+		pr_err("fail for empty buf\n");
+		return NULL;
+	}
+
+	if (!buf->vaddr) {
+		dev_err(buf->dev,
+			"fail for buf vaddr is null\n");
+		return NULL;
+	}
+	return buf->vaddr;
+}
+
+static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
+{
+	struct isp4vid_vb2_buf *buf = mem_priv;
+
+	if (!buf) {
+		pr_err("fail invalid buf handle\n");
+		return;
+	}
+
+	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
+
+	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
+		buf->gpu_addr, buf->size);
+
+	if (buf->vaddr)
+		dma_buf_vunmap_unlocked(buf->dbuf, &map);
+
+	// put dmabuf for exported ones
+	dma_buf_put(buf->dbuf);
+
+	kfree(buf);
+}
+
+static void *isp4vid_vb2_attach_dmabuf(struct vb2_buffer *vb,
+				       struct device *dev,
+				       struct dma_buf *dbuf,
+				       unsigned long size)
+{
+	struct isp4vid_vb2_buf *buf;
+
+	if (dbuf->size < size) {
+		dev_err(dev, "Invalid dmabuf size %ld %ld", dbuf->size, size);
+		return ERR_PTR(-EFAULT);
+	}
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	struct isp4vid_vb2_buf *dbg_buf = (struct isp4vid_vb2_buf *)dbuf->priv;
+
+	buf->dev = dev;
+	buf->dbuf = dbuf;
+	buf->dma_dir = vb->vb2_queue->dma_dir;
+	buf->size = size;
+
+	dev_dbg(dev, "attach dmabuf of isp user bo 0x%llx size %ld",
+		dbg_buf->gpu_addr, dbg_buf->size);
+
+	return buf;
+}
+
+static void isp4vid_vb2_unmap_dmabuf(void *mem_priv)
+{
+	struct isp4vid_vb2_buf *buf = mem_priv;
+
+	if (!buf) {
+		pr_err("fail invalid buf handle\n");
+		return;
+	}
+
+	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
+
+	dev_dbg(buf->dev, "unmap dmabuf of isp user bo 0x%llx size %ld",
+		buf->gpu_addr, buf->size);
+
+	dma_buf_vunmap_unlocked(buf->dbuf, &map);
+	buf->vaddr = NULL;
+}
+
+static int isp4vid_vb2_map_dmabuf(void *mem_priv)
+{
+	struct isp4vid_vb2_buf *mmap_buf = NULL;
+	struct isp4vid_vb2_buf *buf = mem_priv;
+	struct iosys_map map;
+	int ret;
+
+	memset(&map, 0x0, sizeof(map));
+
+	if (!buf) {
+		pr_err("fail invalid buf handle\n");
+		return -EINVAL;
+	}
+
+	ret = dma_buf_vmap_unlocked(buf->dbuf, &map);
+	if (ret) {
+		dev_err(buf->dev, "vmap_unlocked fail");
+		return -EFAULT;
+	}
+	buf->vaddr = map.vaddr;
+
+	mmap_buf = (struct isp4vid_vb2_buf *)buf->dbuf->priv;
+	buf->gpu_addr = mmap_buf->gpu_addr;
+
+	dev_dbg(buf->dev, "map dmabuf of isp user bo 0x%llx size %ld",
+		buf->gpu_addr, buf->size);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_DMA
+struct isp4vid_vb2_amdgpu_attachment {
+	struct sg_table sgt;
+	enum dma_data_direction dma_dir;
+};
+
+static int isp4vid_vb2_dmabuf_ops_attach(struct dma_buf *dbuf,
+					 struct dma_buf_attachment *dbuf_attach)
+{
+	struct isp4vid_vb2_buf *buf = dbuf->priv;
+	int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE;
+	struct isp4vid_vb2_amdgpu_attachment *attach;
+	void *vaddr = buf->vaddr;
+	struct scatterlist *sg;
+	struct sg_table *sgt;
+	int ret;
+	int i;
+
+	attach = kzalloc(sizeof(*attach), GFP_KERNEL);
+	if (!attach)
+		return -ENOMEM;
+
+	sgt = &attach->sgt;
+	ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL);
+	if (ret) {
+		kfree(attach);
+		return ret;
+	}
+	for_each_sgtable_sg(sgt, sg, i) {
+		struct page *page = vmalloc_to_page(vaddr);
+
+		if (!page) {
+			sg_free_table(sgt);
+			kfree(attach);
+			return -ENOMEM;
+		}
+		sg_set_page(sg, page, PAGE_SIZE, 0);
+		vaddr = ((char *)vaddr) + PAGE_SIZE;
+	}
+
+	attach->dma_dir = DMA_NONE;
+	dbuf_attach->priv = attach;
+
+	return 0;
+}
+
+static void
+isp4vid_vb2_dmabuf_ops_detach(struct dma_buf *dbuf,
+			      struct dma_buf_attachment *dbuf_attach)
+{
+	struct isp4vid_vb2_amdgpu_attachment *attach = dbuf_attach->priv;
+	struct sg_table *sgt;
+
+	if (!attach) {
+		pr_err("fail invalid attach handler\n");
+		return;
+	}
+
+	sgt = &attach->sgt;
+
+	/* release the scatterlist cache */
+	if (attach->dma_dir != DMA_NONE)
+		dma_unmap_sgtable(dbuf_attach->dev, sgt, attach->dma_dir, 0);
+	sg_free_table(sgt);
+	kfree(attach);
+	dbuf_attach->priv = NULL;
+}
+
+static struct sg_table
+*isp4vid_vb2_dmabuf_ops_map(struct dma_buf_attachment *dbuf_attach,
+			    enum dma_data_direction dma_dir)
+{
+	struct isp4vid_vb2_amdgpu_attachment *attach = dbuf_attach->priv;
+	struct sg_table *sgt;
+
+	sgt = &attach->sgt;
+	/* return previously mapped sg table */
+	if (attach->dma_dir == dma_dir)
+		return sgt;
+
+	/* release any previous cache */
+	if (attach->dma_dir != DMA_NONE) {
+		dma_unmap_sgtable(dbuf_attach->dev, sgt, attach->dma_dir, 0);
+		attach->dma_dir = DMA_NONE;
+	}
+
+	/* mapping to the client with new direction */
+	if (dma_map_sgtable(dbuf_attach->dev, sgt, dma_dir, 0)) {
+		dev_err(dbuf_attach->dev, "fail to map scatterlist");
+		return ERR_PTR(-EIO);
+	}
+
+	attach->dma_dir = dma_dir;
+
+	return sgt;
+}
+
+static void isp4vid_vb2_dmabuf_ops_unmap(struct dma_buf_attachment *dbuf_attach,
+					 struct sg_table *sgt,
+					 enum dma_data_direction dma_dir)
+{
+	/* nothing to be done here */
+}
+
+static int isp4vid_vb2_dmabuf_ops_vmap(struct dma_buf *dbuf,
+				       struct iosys_map *map)
+{
+	struct isp4vid_vb2_buf *buf = dbuf->priv;
+
+	iosys_map_set_vaddr(map, buf->vaddr);
+
+	return 0;
+}
+
+static void isp4vid_vb2_dmabuf_ops_release(struct dma_buf *dbuf)
+{
+	struct isp4vid_vb2_buf *buf = dbuf->priv;
+
+	/* drop reference obtained in vb2_isp4vid_get_dmabuf */
+	if (buf->is_expbuf)
+		isp4vid_vb2_put(dbuf->priv);
+	else
+		dev_dbg(buf->dev, "ignore buf release for implicit case");
+}
+
+static int isp4vid_vb2_dmabuf_ops_mmap(struct dma_buf *dbuf,
+				       struct vm_area_struct *vma)
+{
+	return isp4vid_vb2_mmap(dbuf->priv, vma);
+}
+
+static const struct dma_buf_ops vb2_isp4vid_dmabuf_ops = {
+	.attach = isp4vid_vb2_dmabuf_ops_attach,
+	.detach = isp4vid_vb2_dmabuf_ops_detach,
+	.map_dma_buf = isp4vid_vb2_dmabuf_ops_map,
+	.unmap_dma_buf = isp4vid_vb2_dmabuf_ops_unmap,
+	.vmap = isp4vid_vb2_dmabuf_ops_vmap,
+	.mmap = isp4vid_vb2_dmabuf_ops_mmap,
+	.release = isp4vid_vb2_dmabuf_ops_release,
+};
+
+static struct dma_buf *isp4vid_get_dmabuf(struct vb2_buffer *vb,
+					  void *buf_priv,
+					  unsigned long flags)
+{
+	struct isp4vid_vb2_buf *buf = buf_priv;
+	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+	struct dma_buf *dbuf;
+
+	if (!buf) {
+		pr_err("fail invalid buf handle\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	exp_info.ops = &vb2_isp4vid_dmabuf_ops;
+	exp_info.size = buf->size;
+	exp_info.flags = flags;
+	exp_info.priv = buf;
+
+	if (WARN_ON(!buf->vaddr))
+		return NULL;
+
+	dbuf = dma_buf_export(&exp_info);
+	if (IS_ERR(dbuf))
+		return NULL;
+
+	return dbuf;
+}
+
+static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
+					      void *buf_priv,
+					      unsigned long flags)
+{
+	struct isp4vid_vb2_buf *buf = buf_priv;
+	struct dma_buf *dbuf;
+
+	if (buf->dbuf) {
+		dev_dbg(buf->dev,
+			"dbuf already created, reuse implicit dbuf\n");
+		dbuf = buf->dbuf;
+	} else {
+		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
+		dev_dbg(buf->dev, "created new dbuf\n");
+	}
+	buf->is_expbuf = true;
+	refcount_inc(&buf->refcount);
+
+	dev_dbg(buf->dev, "buf exported, refcount %d\n",
+		buf->refcount.refs.counter);
+
+	return dbuf;
+}
+
+#endif
+
+static void isp4vid_vb2_put_userptr(void *buf_priv)
+{
+	struct isp4vid_vb2_buf *buf = buf_priv;
+
+	if (!buf->vec->is_pfns) {
+		unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
+		unsigned int n_pages;
+
+		n_pages = frame_vector_count(buf->vec);
+		if (vaddr)
+			vm_unmap_ram((void *)vaddr, n_pages);
+		if (buf->dma_dir == DMA_FROM_DEVICE ||
+		    buf->dma_dir == DMA_BIDIRECTIONAL) {
+			struct page **pages;
+
+			pages = frame_vector_pages(buf->vec);
+			if (!WARN_ON_ONCE(IS_ERR(pages))) {
+				unsigned int i;
+
+				for (i = 0; i < n_pages; i++)
+					set_page_dirty_lock(pages[i]);
+			}
+		}
+	} else {
+		iounmap((__force void __iomem *)buf->vaddr);
+	}
+	vb2_destroy_framevec(buf->vec);
+	kfree(buf);
+}
+
+static void *isp4vid_vb2_get_userptr(struct vb2_buffer *vb, struct device *dev,
+				     unsigned long vaddr, unsigned long size)
+{
+	struct isp4vid_vb2_buf *buf;
+	struct frame_vector *vec;
+	int n_pages, offset, i;
+	int ret = -ENOMEM;
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	buf->dev = dev;
+	buf->dma_dir = vb->vb2_queue->dma_dir;
+	offset = vaddr & ~PAGE_MASK;
+	buf->size = size;
+	vec = vb2_create_framevec(vaddr, size,
+				  buf->dma_dir == DMA_FROM_DEVICE ||
+				  buf->dma_dir == DMA_BIDIRECTIONAL);
+	if (IS_ERR(vec)) {
+		kfree(buf);
+		return vec;
+	}
+	buf->vec = vec;
+	n_pages = frame_vector_count(vec);
+	if (frame_vector_to_pages(vec) < 0) {
+		unsigned long *nums = frame_vector_pfns(vec);
+
+		/*
+		 * We cannot get page pointers for these pfns. Check memory is
+		 * physically contiguous and use direct mapping.
+		 */
+		for (i = 1; i < n_pages; i++)
+			if (nums[i - 1] + 1 != nums[i])
+				goto err_destroy_free;
+		buf->vaddr = (__force void *)
+			     ioremap(__pfn_to_phys(nums[0]), size + offset);
+	} else {
+		buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1);
+	}
+
+	if (!buf->vaddr)
+		goto err_destroy_free;
+
+	buf->vaddr = ((char *)buf->vaddr) + offset;
+	return buf;
+
+err_destroy_free:
+	vb2_destroy_framevec(vec);
+	kfree(buf);
+	return ERR_PTR(ret);
+}
+
+static void isp4vid_vb2_put(void *buf_priv)
+{
+	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
+	struct amdgpu_bo *bo = (struct amdgpu_bo *)buf->bo;
+
+	dev_dbg(buf->dev,
+		"release isp user bo 0x%llx size %ld refcount %d is_expbuf %d",
+		buf->gpu_addr, buf->size,
+		buf->refcount.refs.counter, buf->is_expbuf);
+
+	if (refcount_dec_and_test(&buf->refcount)) {
+		amdgpu_bo_free_isp_user(bo);
+
+		// put implicit dmabuf here, detach_dmabuf will not be called
+		if (!buf->is_expbuf)
+			dma_buf_put(buf->dbuf);
+
+		vfree(buf->vaddr);
+		kfree(buf);
+		buf = NULL;
+	} else {
+		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
+			 refcount_read(&buf->refcount));
+	}
+}
+
+static void *isp4vid_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
+			       unsigned long size)
+{
+	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
+	struct isp4vid_vb2_buf *buf = NULL;
+	struct amdgpu_bo *bo;
+	u64 gpu_addr;
+	u32 ret;
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	buf->dev = dev;
+	buf->size = size;
+	buf->vaddr = vmalloc_user(buf->size);
+	if (!buf->vaddr) {
+		kfree(buf);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	buf->dma_dir = vb->vb2_queue->dma_dir;
+	buf->handler.refcount = &buf->refcount;
+	buf->handler.put = isp4vid_vb2_put;
+	buf->handler.arg = buf;
+
+	// get implicit dmabuf
+	buf->dbuf = isp4vid_get_dmabuf(vb, buf, 0);
+	if (!buf->dbuf) {
+		dev_err(dev, "fail to get dmabuf\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	// create isp user BO and obtain gpu_addr
+	ret = amdgpu_bo_create_isp_user(isp_vdev->amdgpu_dev, buf->dbuf,
+					AMDGPU_GEM_DOMAIN_GTT, &bo, &gpu_addr);
+	if (ret) {
+		dev_err(dev, "fail to create BO\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	buf->bo = (void *)bo;
+	buf->gpu_addr = gpu_addr;
+
+	refcount_set(&buf->refcount, 1);
+
+	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d",
+		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
+
+	return buf;
+}
+
+const struct vb2_mem_ops isp4vid_vb2_memops = {
+	.alloc		= isp4vid_vb2_alloc,
+	.put		= isp4vid_vb2_put,
+	.get_userptr	= isp4vid_vb2_get_userptr,
+	.put_userptr	= isp4vid_vb2_put_userptr,
+#ifdef CONFIG_HAS_DMA
+	.get_dmabuf	= isp4vid_vb2_get_dmabuf,
+#endif
+	.map_dmabuf	= isp4vid_vb2_map_dmabuf,
+	.unmap_dmabuf	= isp4vid_vb2_unmap_dmabuf,
+	.attach_dmabuf	= isp4vid_vb2_attach_dmabuf,
+	.detach_dmabuf	= isp4vid_vb2_detach_dmabuf,
+	.vaddr		= isp4vid_vb2_vaddr,
+	.mmap		= isp4vid_vb2_mmap,
+	.num_users	= isp4vid_vb2_num_users,
+};
+
+static const struct v4l2_pix_format isp4vid_fmt_default = {
+	.width = 1920,
+	.height = 1080,
+	.pixelformat = V4L2_PIX_FMT_NV12,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SRGB,
+};
+
+static void isp4vid_capture_return_all_buffers(struct isp4vid_dev *isp_vdev,
+					       enum vb2_buffer_state state)
+{
+	struct isp4vid_capture_buffer *vbuf, *node;
+
+	mutex_lock(&isp_vdev->buf_list_lock);
+
+	list_for_each_entry_safe(vbuf, node, &isp_vdev->buf_list, list) {
+		list_del(&vbuf->list);
+		vb2_buffer_done(&vbuf->vb2.vb2_buf, state);
+	}
+	mutex_unlock(&isp_vdev->buf_list_lock);
+
+	dev_dbg(isp_vdev->dev, "call vb2_buffer_done(%d)\n", state);
+}
+
+static int isp4vid_vdev_link_validate(struct media_link *link)
+{
+	return 0;
+}
+
+static const struct media_entity_operations isp4vid_vdev_ent_ops = {
+	.link_validate = isp4vid_vdev_link_validate,
+};
+
+static const struct v4l2_file_operations isp4vid_vdev_fops = {
+	.owner = THIS_MODULE,
+	.open = v4l2_fh_open,
+	.release = vb2_fop_release,
+	.read = vb2_fop_read,
+	.poll = vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vb2_fop_mmap,
+};
+
+static int isp4vid_ioctl_querycap(struct file *file, void *fh,
+				  struct v4l2_capability *cap)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+
+	strscpy(cap->driver, ISP4VID_ISP_DRV_NAME, sizeof(cap->driver));
+	snprintf(cap->card, sizeof(cap->card), "%s", ISP4VID_ISP_DRV_NAME);
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "platform:%s", ISP4VID_ISP_DRV_NAME);
+
+	cap->capabilities |= (V4L2_CAP_STREAMING |
+			      V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_IO_MC);
+
+	dev_dbg(isp_vdev->dev, "%s|capabilities=0x%X",
+		isp_vdev->vdev.name, cap->capabilities);
+
+	return 0;
+}
+
+static int isp4vid_g_fmt_vid_cap(struct file *file, void *priv,
+				 struct v4l2_format *f)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+
+	f->fmt.pix = isp_vdev->format;
+
+	return 0;
+}
+
+static int isp4vid_try_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_format *f)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+	struct v4l2_pix_format *format = &f->fmt.pix;
+	unsigned int i;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/*
+	 * Check if the hardware supports the requested format, use the default
+	 * format otherwise.
+	 */
+	for (i = 0; i < ARRAY_SIZE(isp4vid_formats); i++)
+		if (isp4vid_formats[i] == format->pixelformat)
+			break;
+
+	if (i == ARRAY_SIZE(isp4vid_formats))
+		format->pixelformat = ISP4VID_DEFAULT_FMT;
+
+	switch (format->pixelformat) {
+	case V4L2_PIX_FMT_NV12: {
+		const struct v4l2_frmsize_discrete *fsz =
+			v4l2_find_nearest_size(isp4vid_frmsize,
+					       ARRAY_SIZE(isp4vid_frmsize),
+					       width, height,
+					       format->width, format->height);
+
+		format->width = fsz->width;
+		format->height = fsz->height;
+
+		format->bytesperline = format->width;
+		format->sizeimage = format->bytesperline *
+				    format->height * 3 / 2;
+	}
+	break;
+	case V4L2_PIX_FMT_YUYV: {
+		const struct v4l2_frmsize_discrete *fsz =
+			v4l2_find_nearest_size(isp4vid_frmsize,
+					       ARRAY_SIZE(isp4vid_frmsize),
+					       width, height,
+					       format->width, format->height);
+
+		format->width = fsz->width;
+		format->height = fsz->height;
+
+		format->bytesperline = format->width * 2;
+		format->sizeimage = format->bytesperline * format->height;
+	}
+	break;
+	default:
+		dev_err(isp_vdev->dev, "%s|unsupported fmt=%u",
+			isp_vdev->vdev.name, format->pixelformat);
+		return -EINVAL;
+	}
+
+	if (format->field == V4L2_FIELD_ANY)
+		format->field = isp4vid_fmt_default.field;
+
+	if (format->colorspace == V4L2_COLORSPACE_DEFAULT)
+		format->colorspace = isp4vid_fmt_default.colorspace;
+
+	return 0;
+}
+
+static int isp4vid_set_fmt_2_isp(struct v4l2_subdev *sdev,
+				 struct v4l2_pix_format *pix_fmt)
+{
+	struct v4l2_subdev_format fmt = {0};
+
+	switch (pix_fmt->pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+		fmt.format.code = MEDIA_BUS_FMT_YUYV8_1_5X8;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		fmt.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
+		break;
+	default:
+		return -EINVAL;
+	};
+	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+	fmt.pad = ISP4VID_PAD_VIDEO_OUTPUT;
+	fmt.format.width = pix_fmt->width;
+	fmt.format.height = pix_fmt->height;
+	return v4l2_subdev_call(sdev, pad, set_fmt, NULL, &fmt);
+}
+
+static int isp4vid_s_fmt_vid_cap(struct file *file, void *priv,
+				 struct v4l2_format *f)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+	int ret;
+
+	/* Do not change the format while stream is on */
+	if (vb2_is_busy(&isp_vdev->vbq))
+		return -EBUSY;
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	ret = isp4vid_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	dev_dbg(isp_vdev->dev, "%s|width height:%ux%u->%ux%u",
+		isp_vdev->vdev.name,
+		isp_vdev->format.width, isp_vdev->format.height,
+		f->fmt.pix.width, f->fmt.pix.height);
+	dev_dbg(isp_vdev->dev, "%s|pixelformat:0x%x-0x%x",
+		isp_vdev->vdev.name, isp_vdev->format.pixelformat,
+		f->fmt.pix.pixelformat);
+	dev_dbg(isp_vdev->dev, "%s|bytesperline:%u->%u",
+		isp_vdev->vdev.name, isp_vdev->format.bytesperline,
+		f->fmt.pix.bytesperline);
+	dev_dbg(isp_vdev->dev, "%s|sizeimage:%u->%u",
+		isp_vdev->vdev.name, isp_vdev->format.sizeimage,
+		f->fmt.pix.sizeimage);
+
+	isp_vdev->format = f->fmt.pix;
+	ret = isp4vid_set_fmt_2_isp(isp_vdev->isp_sdev, &isp_vdev->format);
+
+	return ret;
+}
+
+static int isp4vid_enum_fmt_vid_cap(struct file *file, void *priv,
+				    struct v4l2_fmtdesc *f)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+
+	switch (f->index) {
+	case 0:
+		f->pixelformat = V4L2_PIX_FMT_NV12;
+		break;
+	case 1:
+		f->pixelformat = V4L2_PIX_FMT_YUYV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(isp_vdev->dev, "%s|index=%d, pixelformat=0x%X",
+		isp_vdev->vdev.name, f->index, f->pixelformat);
+
+	return 0;
+}
+
+static int isp4vid_enum_framesizes(struct file *file, void *fh,
+				   struct v4l2_frmsizeenum *fsize)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(isp4vid_formats); i++) {
+		if (isp4vid_formats[i] == fsize->pixel_format)
+			break;
+	}
+	if (i == ARRAY_SIZE(isp4vid_formats))
+		return -EINVAL;
+
+	if (fsize->index < ARRAY_SIZE(isp4vid_frmsize)) {
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		fsize->discrete = isp4vid_frmsize[fsize->index];
+		dev_dbg(isp_vdev->dev, "%s|size[%d]=%dx%d",
+			isp_vdev->vdev.name, fsize->index,
+			fsize->discrete.width, fsize->discrete.height);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int isp4vid_ioctl_enum_frameintervals(struct file *file, void *priv,
+					     struct v4l2_frmivalenum *fival)
+{
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+	int i;
+
+	if (fival->index >= ARRAY_SIZE(isp4vid_tpfs))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(isp4vid_formats); i++)
+		if (isp4vid_formats[i] == fival->pixel_format)
+			break;
+	if (i == ARRAY_SIZE(isp4vid_formats))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(isp4vid_frmsize); i++)
+		if (isp4vid_frmsize[i].width == fival->width &&
+		    isp4vid_frmsize[i].height == fival->height)
+			break;
+	if (i == ARRAY_SIZE(isp4vid_frmsize))
+		return -EINVAL;
+
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete = isp4vid_tpfs[fival->index];
+	v4l2_simplify_fraction(&fival->discrete.numerator,
+			       &fival->discrete.denominator, 8, 333);
+
+	dev_dbg(isp_vdev->dev, "%s|interval[%d]=%d/%d",
+		isp_vdev->vdev.name, fival->index,
+		fival->discrete.numerator,
+		fival->discrete.denominator);
+
+	return 0;
+}
+
+static int isp4vid_ioctl_g_param(struct file *file, void *priv,
+				 struct v4l2_streamparm *param)
+{
+	struct v4l2_captureparm *capture = &param->parm.capture;
+	struct isp4vid_dev *isp_vdev = video_drvdata(file);
+
+	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	capture->capability   = V4L2_CAP_TIMEPERFRAME;
+	capture->timeperframe = isp_vdev->timeperframe;
+	capture->readbuffers  = 0;
+
+	dev_dbg(isp_vdev->dev, "%s|timeperframe=%d/%d", isp_vdev->vdev.name,
+		capture->timeperframe.numerator,
+		capture->timeperframe.denominator);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops isp4vid_vdev_ioctl_ops = {
+	/* VIDIOC_QUERYCAP handler */
+	.vidioc_querycap = isp4vid_ioctl_querycap,
+
+	/* VIDIOC_ENUM_FMT handlers */
+	.vidioc_enum_fmt_vid_cap = isp4vid_enum_fmt_vid_cap,
+
+	/* VIDIOC_G_FMT handlers */
+	.vidioc_g_fmt_vid_cap = isp4vid_g_fmt_vid_cap,
+
+	/* VIDIOC_S_FMT handlers */
+	.vidioc_s_fmt_vid_cap = isp4vid_s_fmt_vid_cap,
+
+	/* VIDIOC_TRY_FMT handlers */
+	.vidioc_try_fmt_vid_cap = isp4vid_try_fmt_vid_cap,
+
+	/* Buffer handlers */
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+
+	/* Stream on/off */
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+
+	/* Stream type-dependent parameter ioctls */
+	.vidioc_g_parm        = isp4vid_ioctl_g_param,
+
+	/* Debugging ioctls */
+	.vidioc_enum_framesizes = isp4vid_enum_framesizes,
+
+	/* VIDIOC_ENUM_FRAMEINTERVALS */
+	.vidioc_enum_frameintervals = isp4vid_ioctl_enum_frameintervals,
+
+};
+
+static unsigned int isp4vid_get_image_size(struct v4l2_pix_format *fmt)
+{
+	switch (fmt->pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+		return fmt->width * fmt->height * 3 / 2;
+	case V4L2_PIX_FMT_YUYV:
+		return fmt->width * fmt->height * 2;
+	default:
+		return 0;
+	}
+};
+
+static int isp4vid_qops_queue_setup(struct vb2_queue *vq,
+				    unsigned int *nbuffers,
+				    unsigned int *nplanes, unsigned int sizes[],
+				    struct device *alloc_devs[])
+{
+	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vq);
+	unsigned int q_num_bufs = vb2_get_num_buffers(vq);
+
+	if (*nplanes > 1) {
+		dev_err(isp_vdev->dev,
+			"fail to setup queue, no mplane supported %u\n",
+			*nplanes);
+		return -EINVAL;
+	};
+
+	if (*nplanes == 1) {
+		unsigned int size;
+
+		size = isp4vid_get_image_size(&isp_vdev->format);
+		if (sizes[0] < size) {
+			dev_err(isp_vdev->dev,
+				"fail for small plane size %u, %u expected\n",
+				sizes[0], size);
+			return -EINVAL;
+		}
+	}
+
+	if (q_num_bufs + *nbuffers < ISP4VID_VIDEO_BUF_NUM)
+		*nbuffers = ISP4VID_VIDEO_BUF_NUM - q_num_bufs;
+
+	switch (isp_vdev->format.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_YUYV: {
+		*nplanes = 1;
+		sizes[0] = max(sizes[0], isp_vdev->format.sizeimage);
+		isp_vdev->format.sizeimage = sizes[0];
+	}
+	break;
+	default:
+		dev_err(isp_vdev->dev, "%s|unsupported fmt=%u\n",
+			isp_vdev->vdev.name, isp_vdev->format.pixelformat);
+		return -EINVAL;
+	}
+
+	dev_dbg(isp_vdev->dev, "%s|*nbuffers=%u *nplanes=%u sizes[0]=%u\n",
+		isp_vdev->vdev.name,
+		*nbuffers, *nplanes, sizes[0]);
+
+	return 0;
+}
+
+static void isp4vid_qops_buffer_queue(struct vb2_buffer *vb)
+{
+	struct isp4vid_capture_buffer *buf =
+		container_of(vb, struct isp4vid_capture_buffer, vb2.vb2_buf);
+	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
+
+	struct isp4vid_vb2_buf *priv_buf = vb->planes[0].mem_priv;
+	struct isp4if_img_buf_info *img_buf = &buf->img_buf;
+
+	dev_dbg(isp_vdev->dev, "%s|index=%u", isp_vdev->vdev.name, vb->index);
+
+	dev_dbg(isp_vdev->dev, "queue isp user bo 0x%llx size=%lu",
+		priv_buf->gpu_addr,
+		priv_buf->size);
+
+	switch (isp_vdev->format.pixelformat) {
+	case V4L2_PIX_FMT_NV12: {
+		u32 y_size = isp_vdev->format.sizeimage / 3 * 2;
+		u32 uv_size = isp_vdev->format.sizeimage / 3;
+
+		img_buf->planes[0].len = y_size;
+		img_buf->planes[0].sys_addr = priv_buf->vaddr;
+		img_buf->planes[0].mc_addr = priv_buf->gpu_addr;
+
+		dev_dbg(isp_vdev->dev, "img_buf[0]: mc=0x%llx size=%u",
+			img_buf->planes[0].mc_addr,
+			img_buf->planes[0].len);
+
+		img_buf->planes[1].len = uv_size;
+		img_buf->planes[1].sys_addr =
+			(void *)((u64)priv_buf->vaddr + y_size);
+		img_buf->planes[1].mc_addr = priv_buf->gpu_addr + y_size;
+
+		dev_dbg(isp_vdev->dev, "img_buf[1]: mc=0x%llx size=%u",
+			img_buf->planes[1].mc_addr,
+			img_buf->planes[1].len);
+
+		img_buf->planes[2].len = 0;
+	}
+	break;
+	case V4L2_PIX_FMT_YUYV: {
+		img_buf->planes[0].len = isp_vdev->format.sizeimage;
+		img_buf->planes[0].sys_addr = priv_buf->vaddr;
+		img_buf->planes[0].mc_addr = priv_buf->gpu_addr;
+
+		dev_dbg(isp_vdev->dev, "img_buf[0]: mc=0x%llx size=%u",
+			img_buf->planes[0].mc_addr,
+			img_buf->planes[0].len);
+
+		img_buf->planes[1].len = 0;
+		img_buf->planes[2].len = 0;
+	}
+	break;
+	default:
+		dev_err(isp_vdev->dev, "%s|unsupported fmt=%u",
+			isp_vdev->vdev.name, isp_vdev->format.pixelformat);
+		return;
+	}
+
+	if (isp_vdev->stream_started)
+		isp_vdev->ops->send_buffer(isp_vdev, img_buf);
+
+	mutex_lock(&isp_vdev->buf_list_lock);
+	list_add_tail(&buf->list, &isp_vdev->buf_list);
+	mutex_unlock(&isp_vdev->buf_list_lock);
+}
+
+static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
+{
+	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
+	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
+
+	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
+		isp_vdev->vdev.name, vb->index, vb->memory);
+
+	if (!buf) {
+		dev_err(isp_vdev->dev, "Invalid buf handle");
+		return;
+	}
+
+	// release implicit dmabuf reference here for vb2 buffer
+	// of type MMAP and is exported
+	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
+		dma_buf_put(buf->dbuf);
+		dev_dbg(isp_vdev->dev,
+			"put dmabuf for vb->memory %d expbuf %d",
+			vb->memory,
+			buf->is_expbuf);
+	}
+}
+
+static int isp4vid_qops_start_streaming(struct vb2_queue *vq,
+					unsigned int count)
+{
+	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vq);
+	struct isp4vid_capture_buffer *isp_buf;
+	struct v4l2_subdev *isp_subdev = NULL;
+	struct media_entity *entity;
+	struct v4l2_subdev *subdev;
+	struct media_pad *pad;
+	int ret = 0;
+
+	if (isp_vdev->stream_started) {
+		dev_dbg(isp_vdev->dev,
+			"%s do nothing for already streaming\n",
+			isp_vdev->vdev.name);
+		return 0;
+	}
+	isp_vdev->sequence = 0;
+	ret = v4l2_pipeline_pm_get(&isp_vdev->vdev.entity);
+	if (ret) {
+		dev_err(isp_vdev->dev, "power up isp fail %d\n", ret);
+		return ret;
+	}
+
+	entity = &isp_vdev->vdev.entity;
+	while (1) {
+		pad = &entity->pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		pad = media_pad_remote_pad_first(pad);
+		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+			break;
+
+		entity = pad->entity;
+		subdev = media_entity_to_v4l2_subdev(entity);
+
+		if (entity->function == MEDIA_ENT_F_PROC_VIDEO_ISP) {
+			ret = v4l2_subdev_call(subdev, video, pre_streamon, 0);
+			/* The isp s_stream should be called last! */
+			isp_subdev = subdev;
+		} else {
+			ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+		}
+
+		if (ret < 0 && ret != -ENOIOCTLCMD) {
+			dev_dbg(isp_vdev->dev, "fail start streaming: %s %d\n",
+				subdev->name, ret);
+			return ret;
+		}
+	}
+
+	if (isp_subdev) {
+		ret = v4l2_subdev_call(isp_subdev, video, s_stream, 1);
+		if (ret < 0 && ret != -ENOIOCTLCMD) {
+			dev_dbg(isp_vdev->dev, "fail start stream: %s %d\n",
+				isp_subdev->name, ret);
+			return ret;
+		}
+	}
+
+	list_for_each_entry(isp_buf, &isp_vdev->buf_list, list) {
+		isp_vdev->ops->send_buffer(isp_vdev, &isp_buf->img_buf);
+	}
+
+	/* Start the media pipeline */
+	ret = video_device_pipeline_start(&isp_vdev->vdev, &isp_vdev->pipe);
+	if (ret) {
+		dev_err(isp_vdev->dev, "video_device_pipeline_start fail:%d",
+			ret);
+		isp4vid_capture_return_all_buffers(isp_vdev,
+						   VB2_BUF_STATE_QUEUED);
+		return ret;
+	}
+	isp_vdev->stream_started = true;
+
+	return 0;
+}
+
+static void isp4vid_qops_stop_streaming(struct vb2_queue *vq)
+{
+	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vq);
+	struct v4l2_subdev *subdev, *isp_subdev = NULL;
+	struct media_entity *entity;
+	struct media_pad *pad;
+	int ret;
+
+	if (!isp_vdev->stream_started) {
+		dev_dbg(isp_vdev->dev,
+			"%s stop_streaming, do none for not started\n",
+			isp_vdev->vdev.name);
+		return;
+	}
+	dev_dbg(isp_vdev->dev, "%s stop_streaming\n",
+		isp_vdev->vdev.name);
+
+	entity = &isp_vdev->vdev.entity;
+	while (1) {
+		pad = &entity->pads[0];
+		if (!(pad->flags & MEDIA_PAD_FL_SINK))
+			break;
+
+		pad = media_pad_remote_pad_first(pad);
+		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+			break;
+
+		entity = pad->entity;
+		subdev = media_entity_to_v4l2_subdev(entity);
+
+		if (entity->function == MEDIA_ENT_F_PROC_VIDEO_ISP) {
+			/*
+			 * isp subdev to call isp post_streamoff
+			 * after s_stream sequence
+			 */
+			isp_subdev = subdev;
+		}
+		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			dev_dbg(isp_vdev->dev, "fail start streaming: %s %d\n",
+				subdev->name, ret);
+	}
+
+	if (isp_subdev) {
+		ret = v4l2_subdev_call(isp_subdev, video, post_streamoff);
+		if (ret < 0 && ret != -ENOIOCTLCMD)
+			dev_dbg(isp_vdev->dev, "fail start stream: %s %d\n",
+				isp_subdev->name, ret);
+	}
+
+	isp_vdev->stream_started = false;
+	v4l2_pipeline_pm_put(&isp_vdev->vdev.entity);
+
+	/* Stop the media pipeline */
+	video_device_pipeline_stop(&isp_vdev->vdev);
+
+	/* Release all active buffers */
+	isp4vid_capture_return_all_buffers(isp_vdev, VB2_BUF_STATE_ERROR);
+}
+
+static int isp4vid_fill_buffer_size(struct isp4vid_dev *isp_vdev)
+{
+	int ret = 0;
+
+	switch (isp_vdev->format.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+		isp_vdev->format.bytesperline = isp_vdev->format.width;
+		isp_vdev->format.sizeimage = isp_vdev->format.bytesperline *
+					     isp_vdev->format.height * 3 / 2;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		isp_vdev->format.bytesperline = isp_vdev->format.width;
+		isp_vdev->format.sizeimage = isp_vdev->format.bytesperline *
+					     isp_vdev->format.height * 2;
+		break;
+	default:
+		dev_err(isp_vdev->dev, "fail for invalid default format 0x%x",
+			isp_vdev->format.pixelformat);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static const struct vb2_ops isp4vid_qops = {
+	.queue_setup = isp4vid_qops_queue_setup,
+	.buf_cleanup = isp4vid_qops_buffer_cleanup,
+	.buf_queue = isp4vid_qops_buffer_queue,
+	.start_streaming = isp4vid_qops_start_streaming,
+	.stop_streaming = isp4vid_qops_stop_streaming,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+};
+
+int isp4vid_dev_init(struct isp4vid_dev *isp_vdev,
+		     struct v4l2_subdev *isp_sdev,
+		     const struct isp4vid_ops *ops,
+		     void *amdgpu_dev)
+{
+	const char *vdev_name = isp4vid_video_dev_name;
+	struct v4l2_device *v4l2_dev;
+	struct video_device *vdev;
+	struct vb2_queue *q;
+	int ret;
+
+	if (!isp_vdev || !isp_sdev || !isp_sdev->v4l2_dev || !amdgpu_dev)
+		return -EINVAL;
+
+	v4l2_dev = isp_sdev->v4l2_dev;
+	vdev = &isp_vdev->vdev;
+
+	isp_vdev->isp_sdev = isp_sdev;
+	isp_vdev->amdgpu_dev = amdgpu_dev;
+	isp_vdev->dev = v4l2_dev->dev;
+	isp_vdev->ops = ops;
+
+	/* Initialize the vb2_queue struct */
+	mutex_init(&isp_vdev->vbq_lock);
+	q = &isp_vdev->vbq;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->buf_struct_size = sizeof(struct isp4vid_capture_buffer);
+	q->min_queued_buffers = 2;
+	q->ops = &isp4vid_qops;
+	q->drv_priv = isp_vdev;
+	q->mem_ops = &isp4vid_vb2_memops;
+	q->lock = &isp_vdev->vbq_lock;
+	q->dev = v4l2_dev->dev;
+	ret = vb2_queue_init(q);
+	if (ret) {
+		dev_err(v4l2_dev->dev, "vb2_queue_init error:%d", ret);
+		return ret;
+	}
+	/* Initialize buffer list and its lock */
+	mutex_init(&isp_vdev->buf_list_lock);
+	INIT_LIST_HEAD(&isp_vdev->buf_list);
+
+	/* Set default frame format */
+	isp_vdev->format = isp4vid_fmt_default;
+	isp_vdev->timeperframe = ISP4VID_ISP_TPF_DEFAULT;
+	v4l2_simplify_fraction(&isp_vdev->timeperframe.numerator,
+			       &isp_vdev->timeperframe.denominator, 8, 333);
+
+	ret = isp4vid_fill_buffer_size(isp_vdev);
+	if (ret) {
+		dev_err(v4l2_dev->dev, "fail to fill buffer size: %d\n", ret);
+		return ret;
+	}
+
+	ret = isp4vid_set_fmt_2_isp(isp_sdev, &isp_vdev->format);
+	if (ret) {
+		dev_err(v4l2_dev->dev, "fail init format :%d\n", ret);
+		return ret;
+	}
+
+	/* Initialize the video_device struct */
+	isp_vdev->vdev.entity.name = vdev_name;
+	isp_vdev->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
+	isp_vdev->vdev_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_pads_init(&isp_vdev->vdev.entity, 1,
+				     &isp_vdev->vdev_pad);
+
+	if (ret) {
+		dev_err(v4l2_dev->dev, "init media entity pad fail:%d\n", ret);
+		return ret;
+	}
+
+	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+			    V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
+	vdev->entity.ops = &isp4vid_vdev_ent_ops;
+	vdev->release = video_device_release_empty;
+	vdev->fops = &isp4vid_vdev_fops;
+	vdev->ioctl_ops = &isp4vid_vdev_ioctl_ops;
+	vdev->lock = NULL;
+	vdev->queue = q;
+	vdev->v4l2_dev = v4l2_dev;
+	vdev->vfl_dir = VFL_DIR_RX;
+	strscpy(vdev->name, vdev_name, sizeof(vdev->name));
+	video_set_drvdata(vdev, isp_vdev);
+
+	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+	if (ret)
+		dev_err(v4l2_dev->dev, "register video device fail:%d\n", ret);
+
+	return ret;
+}
+
+void isp4vid_dev_deinit(struct isp4vid_dev *isp_vdev)
+{
+	video_unregister_device(&isp_vdev->vdev);
+}
diff --git a/drivers/media/platform/amd/isp4/isp4_video.h b/drivers/media/platform/amd/isp4/isp4_video.h
new file mode 100644
index 000000000000..4d6705174d34
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_video.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _ISP4_VIDEO_H_
+#define _ISP4_VIDEO_H_
+
+#include <linux/mutex.h>
+#include <media/videobuf2-memops.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dev.h>
+#include "isp4_interface.h"
+
+enum isp4vid_buf_done_status {
+	/* It means no corresponding image buf in fw response */
+	ISP4VID_BUF_DONE_STATUS_ABSENT,
+	ISP4VID_BUF_DONE_STATUS_SUCCESS,
+	ISP4VID_BUF_DONE_STATUS_FAILED
+};
+
+struct isp4vid_buf_done_info {
+	enum isp4vid_buf_done_status status;
+	struct isp4if_img_buf_info buf;
+};
+
+/* call back parameter for CB_EVT_ID_FRAME_DONE */
+struct isp4vid_framedone_param {
+	s32 poc;
+	s32 cam_id;
+	s64 time_stamp;
+	struct isp4vid_buf_done_info preview;
+};
+
+struct isp4vid_capture_buffer {
+	/*
+	 * struct vb2_v4l2_buffer must be the first element
+	 * the videobuf2 framework will allocate this struct based on
+	 * buf_struct_size and use the first sizeof(struct vb2_buffer) bytes of
+	 * memory as a vb2_buffer
+	 */
+	struct vb2_v4l2_buffer vb2;
+	struct isp4if_img_buf_info img_buf;
+	struct list_head list;
+};
+
+struct isp4vid_dev;
+
+struct isp4vid_ops {
+	int (*send_buffer)(struct isp4vid_dev *vid,
+			   struct isp4if_img_buf_info *img_buf);
+};
+
+struct isp4vid_dev {
+	struct video_device vdev;
+	struct media_pad vdev_pad;
+	struct v4l2_pix_format format;
+
+	/* mutex that protects vbq */
+	struct mutex vbq_lock;
+	struct vb2_queue vbq;
+
+	/* mutex that protects buf_list */
+	struct mutex buf_list_lock;
+	struct list_head buf_list;
+
+	u32 sequence;
+	bool stream_started;
+	struct task_struct *kthread;
+
+	struct media_pipeline pipe;
+	struct device *dev;
+	void *amdgpu_dev;
+	struct v4l2_subdev *isp_sdev;
+	struct v4l2_fract timeperframe;
+
+	/* Callback operations */
+	const struct isp4vid_ops *ops;
+};
+
+int isp4vid_dev_init(struct isp4vid_dev *isp_vdev,
+		     struct v4l2_subdev *isp_sdev,
+		     const struct isp4vid_ops *ops,
+		     void *amdgpu_dev);
+
+void isp4vid_dev_deinit(struct isp4vid_dev *isp_vdev);
+
+s32 isp4vid_notify(void *cb_ctx, struct isp4vid_framedone_param *evt_param);
+
+void isp4vid_frmsize_range(struct v4l2_frmsize_discrete *min,
+			   struct v4l2_frmsize_discrete *max);
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 7/8] media: platform: amd: isp4 debug fs logging and  more descriptive errors
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (5 preceding siblings ...)
  2025-06-18  9:19 ` [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers " Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-06-18  9:19 ` [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver Bin Du
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

Add debug fs for isp4 driver and add more detailed descriptive error
info to some of the log message

Signed-off-by: Bin Du <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 drivers/media/platform/amd/isp4/Makefile      |   1 +
 drivers/media/platform/amd/isp4/isp4.c        |   5 +
 drivers/media/platform/amd/isp4/isp4_debug.c  | 272 ++++++++++++++++++
 drivers/media/platform/amd/isp4/isp4_debug.h  |  41 +++
 .../media/platform/amd/isp4/isp4_interface.c  |  38 ++-
 drivers/media/platform/amd/isp4/isp4_subdev.c |  29 +-
 6 files changed, 366 insertions(+), 20 deletions(-)
 create mode 100644 drivers/media/platform/amd/isp4/isp4_debug.c
 create mode 100644 drivers/media/platform/amd/isp4/isp4_debug.h

diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
index 99285fe45b52..99d16ecfb64b 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_subdev.o \
+			isp4_debug.o \
 			isp4_phy.o \
 			isp4_interface.o \
 			isp4.o	\
diff --git a/drivers/media/platform/amd/isp4/isp4.c b/drivers/media/platform/amd/isp4/isp4.c
index 3d971fe2813d..c3d2e52e0201 100644
--- a/drivers/media/platform/amd/isp4/isp4.c
+++ b/drivers/media/platform/amd/isp4/isp4.c
@@ -11,6 +11,7 @@
 #include "amdgpu_object.h"
 
 #include "isp4.h"
+#include "isp4_debug.h"
 #include "isp4_hw.h"
 
 #define ISP4_DRV_NAME "amd_isp_capture"
@@ -352,6 +353,8 @@ static int isp4_capture_probe(struct platform_device *pdev)
 	pm_runtime_set_suspended(dev);
 	pm_runtime_enable(dev);
 
+	isp_debugfs_create(isp_dev);
+
 	return 0;
 
 err_unreg_video_dev_notifier:
@@ -369,6 +372,8 @@ static void isp4_capture_remove(struct platform_device *pdev)
 {
 	struct isp4_device *isp_dev = platform_get_drvdata(pdev);
 
+	isp_debugfs_remove(isp_dev);
+
 	v4l2_async_nf_unregister(&isp_dev->notifier);
 	v4l2_async_nf_cleanup(&isp_dev->notifier);
 	v4l2_device_unregister_subdev(&isp_dev->isp_sdev.sdev);
diff --git a/drivers/media/platform/amd/isp4/isp4_debug.c b/drivers/media/platform/amd/isp4/isp4_debug.c
new file mode 100644
index 000000000000..549c36614306
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_debug.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#include "isp4.h"
+#include "isp4_debug.h"
+#include "isp4_hw.h"
+#include "isp4_interface.h"
+
+#define ISP4DBG_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
+#define ISP4DBG_MACRO_2_STR(X) #X
+#define ISP4DBG_MAX_ONE_TIME_LOG_LEN 510
+
+#ifdef CONFIG_DEBUG_FS
+
+void isp_debugfs_create(struct isp4_device *isp_dev)
+{
+	isp_dev->isp_sdev.debugfs_dir = debugfs_create_dir("amd_isp", NULL);
+	debugfs_create_bool("fw_log_enable", 0644,
+			    isp_dev->isp_sdev.debugfs_dir,
+			    &isp_dev->isp_sdev.enable_fw_log);
+	isp_dev->isp_sdev.fw_log_output =
+		devm_kzalloc(&isp_dev->pdev->dev,
+			     ISP4DBG_FW_LOG_RINGBUF_SIZE + 32,
+			     GFP_KERNEL);
+}
+
+void isp_debugfs_remove(struct isp4_device *isp_dev)
+{
+	debugfs_remove_recursive(isp_dev->isp_sdev.debugfs_dir);
+	isp_dev->isp_sdev.debugfs_dir = NULL;
+}
+
+static u32 isp_fw_fill_rb_log(struct isp4_subdev *isp, u8 *sys, u32 rb_size)
+{
+	struct isp4_interface *ispif = &isp->ispif;
+	struct device *dev = isp->dev;
+	u8 *buf = isp->fw_log_output;
+	u32 rd_ptr, wr_ptr;
+	u32 total_cnt = 0;
+	u32 offset = 0;
+	u32 cnt;
+
+	if (!sys || rb_size == 0)
+		return 0;
+
+	mutex_lock(&ispif->isp4if_mutex);
+
+	rd_ptr = isp4hw_rreg(ISP4_GET_ISP_REG_BASE(isp), ISP_LOG_RB_RPTR0);
+	wr_ptr = isp4hw_rreg(ISP4_GET_ISP_REG_BASE(isp), ISP_LOG_RB_WPTR0);
+
+	do {
+		if (wr_ptr > rd_ptr)
+			cnt = wr_ptr - rd_ptr;
+		else if (wr_ptr < rd_ptr)
+			cnt = rb_size - rd_ptr;
+		else
+			goto unlock_and_quit;
+
+		if (cnt > rb_size) {
+			dev_err(dev, "fail bad fw log size %u\n", cnt);
+			goto unlock_and_quit;
+		}
+
+		memcpy(buf + offset, (u8 *)(sys + rd_ptr), cnt);
+
+		offset += cnt;
+		total_cnt += cnt;
+		rd_ptr = (rd_ptr + cnt) % rb_size;
+	} while (rd_ptr < wr_ptr);
+
+	isp4hw_wreg(ISP4_GET_ISP_REG_BASE(isp), ISP_LOG_RB_RPTR0, rd_ptr);
+
+unlock_and_quit:
+	mutex_unlock(&ispif->isp4if_mutex);
+	return total_cnt;
+}
+
+void isp_fw_log_print(struct isp4_subdev *isp)
+{
+	struct isp4_interface *ispif = &isp->ispif;
+	char *fw_log_buf = isp->fw_log_output;
+	u32 cnt;
+
+	if (!isp->enable_fw_log || !fw_log_buf)
+		return;
+
+	cnt = isp_fw_fill_rb_log(isp, ispif->fw_log_buf->sys_addr,
+				 ispif->fw_log_buf->mem_size);
+
+	if (cnt) {
+		char *line_end;
+		char temp_ch;
+		char *str;
+		char *end;
+
+		str = (char *)fw_log_buf;
+		end = ((char *)fw_log_buf + cnt);
+		fw_log_buf[cnt] = 0;
+
+		while (str < end) {
+			line_end = strchr(str, 0x0A);
+			if ((line_end && (str + ISP4DBG_MAX_ONE_TIME_LOG_LEN) >= line_end) ||
+			    (!line_end && (str + ISP4DBG_MAX_ONE_TIME_LOG_LEN) >= end)) {
+				if (line_end)
+					*line_end = 0;
+
+				if (*str != '\0')
+					dev_dbg(isp->dev,
+						"%s", str);
+
+				if (line_end) {
+					*line_end = 0x0A;
+					str = line_end + 1;
+				} else {
+					break;
+				}
+			} else {
+				u32 tmp_len = ISP4DBG_MAX_ONE_TIME_LOG_LEN;
+
+				temp_ch = str[tmp_len];
+				str[tmp_len] = 0;
+				dev_dbg(isp->dev, "%s", str);
+				str[tmp_len] = temp_ch;
+				str = &str[tmp_len];
+			}
+		}
+	}
+}
+#endif
+
+char *isp4dbg_get_buf_src_str(u32 src)
+{
+	switch (src) {
+	case BUFFER_SOURCE_STREAM:
+		return ISP4DBG_MACRO_2_STR(BUFFER_SOURCE_STREAM);
+	default:
+		return "Unknown buf source";
+	}
+}
+
+char *isp4dbg_get_buf_done_str(u32 status)
+{
+	switch (status) {
+	case BUFFER_STATUS_INVALID:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_INVALID);
+	case BUFFER_STATUS_SKIPPED:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_SKIPPED);
+	case BUFFER_STATUS_EXIST:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_EXIST);
+	case BUFFER_STATUS_DONE:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_DONE);
+	case BUFFER_STATUS_LACK:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_LACK);
+	case BUFFER_STATUS_DIRTY:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_DIRTY);
+	case BUFFER_STATUS_MAX:
+		return ISP4DBG_MACRO_2_STR(BUFFER_STATUS_MAX);
+	default:
+		return "Unknown Buf Done Status";
+	}
+};
+
+char *isp4dbg_get_img_fmt_str(int fmt /* enum isp4fw_image_format * */)
+{
+	switch (fmt) {
+	case IMAGE_FORMAT_NV12:
+		return "NV12";
+	case IMAGE_FORMAT_YUV422INTERLEAVED:
+		return "YUV422INTERLEAVED";
+	default:
+		return "unknown fmt";
+	}
+}
+
+void isp4dbg_show_bufmeta_info(struct device *dev, char *pre,
+			       void *in, void *orig_buf)
+{
+	struct isp4fw_buffer_meta_info *p;
+	struct isp4if_img_buf_info *orig;
+
+	if (!in)
+		return;
+
+	if (!pre)
+		pre = "";
+
+	p = (struct isp4fw_buffer_meta_info *)in;
+	orig = (struct isp4if_img_buf_info *)orig_buf;
+
+	dev_dbg(dev, "%s(%s) en:%d,stat:%s(%u),src:%s\n", pre,
+		isp4dbg_get_img_fmt_str(p->image_prop.image_format),
+		p->enabled, isp4dbg_get_buf_done_str(p->status), p->status,
+		isp4dbg_get_buf_src_str(p->source));
+
+	dev_dbg(dev, "%p,0x%llx(%u) %p,0x%llx(%u) %p,0x%llx(%u)\n",
+		orig->planes[0].sys_addr, orig->planes[0].mc_addr,
+		orig->planes[0].len, orig->planes[1].sys_addr,
+		orig->planes[1].mc_addr, orig->planes[1].len,
+		orig->planes[2].sys_addr, orig->planes[2].mc_addr,
+		orig->planes[2].len);
+}
+
+char *isp4dbg_get_buf_type(u32 type)
+{
+	/* enum isp4fw_buffer_type */
+	switch (type) {
+	case BUFFER_TYPE_PREVIEW:
+		return ISP4DBG_MACRO_2_STR(BUFFER_TYPE_PREVIEW);
+	case BUFFER_TYPE_META_INFO:
+		return ISP4DBG_MACRO_2_STR(BUFFER_TYPE_META_INFO);
+	case BUFFER_TYPE_MEM_POOL:
+		return ISP4DBG_MACRO_2_STR(BUFFER_TYPE_MEM_POOL);
+	default:
+		return "unknown type";
+	}
+}
+
+char *isp4dbg_get_cmd_str(u32 cmd)
+{
+	switch (cmd) {
+	case CMD_ID_START_STREAM:
+		return ISP4DBG_MACRO_2_STR(CMD_ID_START_STREAM);
+	case CMD_ID_STOP_STREAM:
+		return ISP4DBG_MACRO_2_STR(CMD_ID_STOP_STREAM);
+	case CMD_ID_SEND_BUFFER:
+		return ISP4DBG_MACRO_2_STR(CMD_ID_SEND_BUFFER);
+	case CMD_ID_SET_STREAM_CONFIG:
+		return ISP4DBG_MACRO_2_STR(CMD_ID_SET_STREAM_CONFIG);
+	case CMD_ID_SET_OUT_CHAN_PROP:
+		return ISP4DBG_MACRO_2_STR(CMD_ID_SET_OUT_CHAN_PROP);
+	case CMD_ID_ENABLE_OUT_CHAN:
+		return ISP4DBG_MACRO_2_STR(CMD_ID_ENABLE_OUT_CHAN);
+	default:
+		return "unknown cmd";
+	};
+}
+
+char *isp4dbg_get_resp_str(u32 cmd)
+{
+	switch (cmd) {
+	case RESP_ID_CMD_DONE:
+		return ISP4DBG_MACRO_2_STR(RESP_ID_CMD_DONE);
+	case RESP_ID_NOTI_FRAME_DONE:
+		return ISP4DBG_MACRO_2_STR(RESP_ID_NOTI_FRAME_DONE);
+	default:
+		return "unknown respid";
+	};
+}
+
+char *isp4dbg_get_if_stream_str(u32 stream /* enum fw_cmd_resp_stream_id */)
+{
+	switch (stream) {
+	case ISP4IF_STREAM_ID_GLOBAL:
+		return "STREAM_GLOBAL";
+	case ISP4IF_STREAM_ID_1:
+		return "STREAM1";
+	default:
+		return "unknown streamID";
+	}
+}
+
+char *isp4dbg_get_out_ch_str(int ch /* enum isp4fw_pipe_out_ch */)
+{
+	switch ((enum isp4fw_pipe_out_ch)ch) {
+	case ISP_PIPE_OUT_CH_PREVIEW:
+		return "prev";
+	default:
+		return "unknown channel";
+	}
+}
diff --git a/drivers/media/platform/amd/isp4/isp4_debug.h b/drivers/media/platform/amd/isp4/isp4_debug.h
new file mode 100644
index 000000000000..acf99bf129ae
--- /dev/null
+++ b/drivers/media/platform/amd/isp4/isp4_debug.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _ISP4_DEBUG_H_
+#define _ISP4_DEBUG_H_
+
+#include <linux/printk.h>
+#include <linux/dev_printk.h>
+
+#include "isp4_subdev.h"
+
+#ifdef CONFIG_DEBUG_FS
+struct isp4_device;
+
+void isp_debugfs_create(struct isp4_device *isp_dev);
+void isp_debugfs_remove(struct isp4_device *isp_dev);
+void isp_fw_log_print(struct isp4_subdev *isp);
+
+#else
+
+/*to avoid checkpatch warning*/
+#define isp_debugfs_create(cam) cam
+#define isp_debugfs_remove(cam) cam
+#define isp_fw_log_print(isp) isp
+
+#endif /* CONFIG_DEBUG_FS */
+
+void isp4dbg_show_bufmeta_info(struct device *dev, char *pre, void *p,
+			       void *orig_buf /* struct sys_img_buf_handle* */);
+char *isp4dbg_get_img_fmt_str(int fmt /* enum _image_format_t * */);
+char *isp4dbg_get_out_ch_str(int ch /* enum _isp_pipe_out_ch_t */);
+char *isp4dbg_get_cmd_str(u32 cmd);
+char *isp4dbg_get_buf_type(u32 type);/* enum _buffer_type_t */
+char *isp4dbg_get_resp_str(u32 resp);
+char *isp4dbg_get_buf_src_str(u32 src);
+char *isp4dbg_get_buf_done_str(u32 status);
+char *isp4dbg_get_if_stream_str(u32 stream);
+
+#endif
diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c
index 0e1eb22a0de5..b79b0f2a4776 100644
--- a/drivers/media/platform/amd/isp4/isp4_interface.c
+++ b/drivers/media/platform/amd/isp4/isp4_interface.c
@@ -7,6 +7,7 @@
 
 #include "amdgpu_object.h"
 
+#include "isp4_debug.h"
 #include "isp4_fw_cmd_resp.h"
 #include "isp4_hw.h"
 #include "isp4_hw_reg.h"
@@ -392,7 +393,8 @@ static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
 	len = rb_config->val_size;
 
 	if (isp4if_is_cmdq_rb_full(ispif, stream)) {
-		dev_err(dev, "fail no cmdslot (%d)\n", stream);
+		dev_err(dev, "fail no cmdslot %s(%d)\n",
+			isp4dbg_get_if_stream_str(stream), stream);
 		return -EINVAL;
 	}
 
@@ -400,13 +402,15 @@ static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
 	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
 
 	if (rd_ptr > len) {
-		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
+		dev_err(dev, "fail %s(%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
+			isp4dbg_get_if_stream_str(stream),
 			stream, rd_ptr, len, wr_ptr);
 		return -EINVAL;
 	}
 
 	if (wr_ptr > len) {
-		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
+		dev_err(dev, "fail %s(%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
+			isp4dbg_get_if_stream_str(stream),
 			stream, wr_ptr, len, rd_ptr);
 		return -EINVAL;
 	}
@@ -498,7 +502,9 @@ static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
 			}
 			rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
 			wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
-			dev_err(dev, "fail to get cmdq slot,stream (%d), rd %u, wr %u\n",
+			dev_err(dev,
+				"failed to get free cmdq slot, stream %s(%d),rd %u, wr %u\n",
+				isp4dbg_get_if_stream_str(stream),
 				stream, rd_ptr, wr_ptr);
 			return -ETIMEDOUT;
 		}
@@ -550,8 +556,8 @@ static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
 
 	ret = isp4if_insert_isp_fw_cmd(ispif, stream, &cmd);
 	if (ret) {
-		dev_err(dev, "fail for insert_isp_fw_cmd camId (0x%08x)\n",
-			cmd_id);
+		dev_err(dev, "fail for insert_isp_fw_cmd camId %s(0x%08x)\n",
+			isp4dbg_get_cmd_str(cmd_id), cmd_id);
 		if (cmd_ele) {
 			isp4if_rm_cmd_from_cmdq(ispif, cmd_ele->seq_num,
 						cmd_ele->cmd_id);
@@ -780,13 +786,15 @@ int isp4if_f2h_resp(struct isp4_interface *ispif,
 	wr_ptr_dbg = wr_ptr;
 
 	if (rd_ptr > len) {
-		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
+		dev_err(dev, "fail %s(%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
+			isp4dbg_get_if_stream_str(stream),
 			stream, rd_ptr, len, wr_ptr);
 		return -EINVAL;
 	}
 
 	if (wr_ptr > len) {
-		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
+		dev_err(dev, "fail %s(%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
+			isp4dbg_get_if_stream_str(stream),
 			stream, wr_ptr, len, rd_ptr);
 		return -EINVAL;
 	}
@@ -801,7 +809,8 @@ int isp4if_f2h_resp(struct isp4_interface *ispif,
 				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
 					    rreg, rd_ptr);
 			} else {
-				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
+				dev_err(dev, "%s(%u),rd %u(should<=%u),wr %u\n",
+					isp4dbg_get_if_stream_str(stream),
 					stream, rd_ptr, len, wr_ptr);
 				return -EINVAL;
 			}
@@ -827,7 +836,8 @@ int isp4if_f2h_resp(struct isp4_interface *ispif,
 				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
 					    rreg, rd_ptr);
 			} else {
-				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
+				dev_err(dev, "%s(%u),rd %u(should<=%u),wr %u\n",
+					isp4dbg_get_if_stream_str(stream),
 					stream, rd_ptr, len, wr_ptr);
 				return -EINVAL;
 			}
@@ -849,7 +859,8 @@ int isp4if_f2h_resp(struct isp4_interface *ispif,
 				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
 					    rreg, rd_ptr);
 			} else {
-				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
+				dev_err(dev, "%s(%u),rd %u(should<=%u),wr %u\n",
+					isp4dbg_get_if_stream_str(stream),
 					stream, rd_ptr, len, wr_ptr);
 				return -EINVAL;
 			}
@@ -866,9 +877,10 @@ int isp4if_f2h_resp(struct isp4_interface *ispif,
 			checksum, response->resp_check_sum,
 			rd_ptr_dbg, wr_ptr_dbg);
 
-		dev_err(dev, "(%u), seqNo %u, resp_id (0x%x)\n",
-			stream,
+		dev_err(dev, "%s(%u), seqNo %u, resp_id %s(0x%x)\n",
+			isp4dbg_get_if_stream_str(stream), stream,
 			response->resp_seq_num,
+			isp4dbg_get_resp_str(response->resp_id),
 			response->resp_id);
 
 		return -EINVAL;
diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.c b/drivers/media/platform/amd/isp4/isp4_subdev.c
index d93cdb9dc477..e2084030c79d 100644
--- a/drivers/media/platform/amd/isp4/isp4_subdev.c
+++ b/drivers/media/platform/amd/isp4/isp4_subdev.c
@@ -7,6 +7,7 @@
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 
+#include "isp4_debug.h"
 #include "isp4_fw_cmd_resp.h"
 #include "isp4_hw.h"
 #include "isp4_interface.h"
@@ -305,7 +306,9 @@ static int isp4sd_setup_output(struct isp4_subdev *isp_subdev,
 		return -EINVAL;
 	}
 
-	dev_dbg(dev, "channel: w:h=%u:%u,lp:%u,cp%u\n",
+	dev_dbg(dev, "channel:%s,fmt %s,w:h=%u:%u,lp:%u,cp%u\n",
+		isp4dbg_get_out_ch_str(cmd_ch_prop.ch),
+		isp4dbg_get_img_fmt_str(cmd_ch_prop.image_prop.image_format),
 		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);
@@ -328,6 +331,9 @@ static int isp4sd_setup_output(struct isp4_subdev *isp_subdev,
 		return ret;
 	}
 
+	dev_dbg(dev, "enable channel %s\n",
+		isp4dbg_get_out_ch_str(cmd_ch_en.ch));
+
 	if (!sensor_info->start_stream_cmd_sent) {
 		ret = isp4sd_kickoff_stream(isp_subdev, out_prop->width,
 					    out_prop->height);
@@ -490,8 +496,9 @@ static void isp4sd_fw_resp_cmd_done(struct isp4_subdev *isp_subdev,
 		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",
+	dev_dbg(dev, "stream %d,cmd %s(0x%08x)(%d),seq %u, ele %p\n",
 		stream_id,
+		isp4dbg_get_cmd_str(para->cmd_id),
 		para->cmd_id, para->cmd_status, para->cmd_seq_num,
 		ele);
 
@@ -548,8 +555,9 @@ isp4sd_preview_done(struct isp4_subdev *isp_subdev,
 			pcb->preview.status = ISP4VID_BUF_DONE_STATUS_SUCCESS;
 		}
 	} else if (meta->preview.enabled) {
-		dev_err(dev, "fail bad preview status %u\n",
-			meta->preview.status);
+		dev_err(dev, "fail bad preview status %u(%s)\n",
+			meta->preview.status,
+			isp4dbg_get_buf_done_str(meta->preview.status));
 	}
 
 	return prev;
@@ -609,14 +617,18 @@ static void isp4sd_fw_resp_frame_done(struct isp4_subdev *isp_subdev,
 	pcb.poc = meta->poc;
 	pcb.cam_id = 0;
 
-	dev_dbg(dev, "ts:%llu,streamId:%d,poc:%u,preview_en:%u,(%i)\n",
+	dev_dbg(dev, "ts:%llu,streamId:%d,poc:%u,preview_en:%u,%s(%i)\n",
 		ktime_get_ns(), stream_id, meta->poc,
 		meta->preview.enabled,
+		isp4dbg_get_buf_done_str(meta->preview.status),
 		meta->preview.status);
 
 	prev = isp4sd_preview_done(isp_subdev, meta, &pcb);
-	if (pcb.preview.status != ISP4VID_BUF_DONE_STATUS_ABSENT)
+	if (pcb.preview.status != ISP4VID_BUF_DONE_STATUS_ABSENT) {
+		isp4dbg_show_bufmeta_info(dev, "prev", &meta->preview,
+					  &pcb.preview.buf);
 		isp4vid_notify(&isp_subdev->isp_vdev, &pcb);
+	}
 
 	isp4if_dealloc_buffer_node(prev);
 
@@ -637,6 +649,8 @@ static void isp4sd_fw_resp_func(struct isp4_subdev *isp_subdev,
 	if (ispif->status < ISP4IF_STATUS_FW_RUNNING)
 		return;
 
+	isp_fw_log_print(isp_subdev);
+
 	while (true) {
 		s32 ret;
 
@@ -654,7 +668,8 @@ static void isp4sd_fw_resp_func(struct isp4_subdev *isp_subdev,
 						  &resp.param.frame_done);
 			break;
 		default:
-			dev_err(dev, "-><- fail respid (0x%x)\n",
+			dev_err(dev, "-><- fail respid %s(0x%x)\n",
+				isp4dbg_get_resp_str(resp.resp_id),
 				resp.resp_id);
 			break;
 		}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (6 preceding siblings ...)
  2025-06-18  9:19 ` [PATCH v2 7/8] media: platform: amd: isp4 debug fs logging and more descriptive errors Bin Du
@ 2025-06-18  9:19 ` Bin Du
  2025-08-05 11:37   ` Laurent Pinchart
  2025-07-23 18:12 ` [PATCH v2 0/8] Add AMD ISP4 driver Sultan Alsawaf
  2025-08-14  6:53 ` Sultan Alsawaf
  9 siblings, 1 reply; 96+ messages in thread
From: Bin Du @ 2025-06-18  9:19 UTC (permalink / raw)
  To: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du, Bin Du

Add documentation for AMD isp 4 and describe the main components

Signed-off-by: Bin Du <Bin.Du@amd.com>
Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
---
 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:: <isonum.txt>
+
+====================================
+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:
+
+- <capture video device: capture device for retrieving images.
+
+
+  - ISP4 Image Signal Processing Subdevice Node
+-----------------------------------------------
+
+The isp4 is represented as a single V4L2 subdev, the sub-device does not
+provide interface to the user space. The sub-device is connected to one video node
+(isp4_capture) with immutable active link. The isp entity is connected
+to sensor pad 0 and receives the frames using CSI-2 protocol. The sub-device is
+also responsible to configure CSI2-2 receiver.
+The sub-device processes bayer raw data from the connected sensor and output
+them to different YUV formats. The isp also has scaling capabilities.
+
+  - isp4_capture - Frames Capture Video Node
+--------------------------------------------
+
+Isp4_capture is a capture device to capture frames to memory.
+This entity is the DMA engine that write the frames to memory.
+The entity is connected to isp4 sub-device.
+
+Capturing Video Frames Example
+==============================
+
+.. code-block:: bash
+
+         # set the links
+
+         # start streaming:
+         v4l2-ctl "-d" "/dev/video0" "--set-fmt-video=width=1920,height=1080,pixelformat=NV12" "--stream-mmap" "--stream-count=10"
diff --git a/Documentation/admin-guide/media/amdisp4.dot b/Documentation/admin-guide/media/amdisp4.dot
new file mode 100644
index 000000000000..a4c2f0cceb30
--- /dev/null
+++ b/Documentation/admin-guide/media/amdisp4.dot
@@ -0,0 +1,8 @@
+digraph board {
+	rankdir=TB
+	n00000001 [label="{{<port0> 0} | amd isp4\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
+	n00000001:port1 -> n00000004 [style=bold]
+	n00000004 [label="Preview\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
+	n0000000a [label="{{} | ov05c10 22-0010\n/dev/v4l-subdev0 | {<port0> 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 <pratap.nirujogi@amd.com>
 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/*
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-06-18  9:19 ` [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Bin Du
@ 2025-06-18 15:58   ` Mario Limonciello
  2025-06-19  7:46     ` Du, Bin
  2025-07-28  5:54   ` Sakari Ailus
  1 sibling, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-06-18 15:58 UTC (permalink / raw)
  To: Bin Du, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On 6/18/2025 4:19 AM, Bin Du wrote:
> Amd isp4 capture is a v4l2 media device which implements media controller

AMD

> interface.
> It has one sub-device (amd ISP4 sub-device) endpoint which can be connected

AMD

> 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

MAINTAINERS

> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>

Who actually developed?  If both are developers there should be a 
Co-developed-by tag.

> ---
>   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 <bin.du@amd.com>
> +M:	Nirujogi Pratap <pratap.nirujogi@amd.com>
> +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 <Felix.Kuehling@amd.com>
>   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/

Is this whole file alphabetical?  If so this is the wrong place.

>   
>   # 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

I don't believe this should default 'y'.  Normally drivers need to be 
opt in.

> +	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.

2025

> +# 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

As the directory is already conditional on CONFIG_AMD_ISP4 is this 
obj-$() needed?  Or should it really be obj-y?

> +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

Do you really need to enforce all these flags just for this driver?

Was this just for development to avoid having to remember to call the 
build with W=1 or CONFIG_WERROR?

> 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 <linux/pm_runtime.h>
> +#include <linux/vmalloc.h>
> +#include <media/v4l2-ioctl.h>
> +
> +#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;

In patch 5 you change this function, including dropping the goto and label.

So I suggest that for patch 1 you KISS:

static irqreturn_t isp4_irq_handler(int irq, void *arg)
{
	return IRQ_HANDLED;
}

Then in patch 5 add the extra conditional code and real handling.

> +}
> +
> +/*
> + * amd capture module
> + */

Pointless comment, no?

> +static int isp4_capture_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct isp4_device *isp_dev;
> +

Why newline here?

> +	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");

As you have error handling in place with dev_err_probe() I think the 
lack of an error implies this message.  I'd say drop it.

> +
> +	/* 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");

As you have error handling in place with dev_err_probe() I think the 
lack of an error implies this message.  I'd say drop it.

> +
> +	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");

Probably not needed message anymore, right?

> +}
> +
> +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 <bin.du@amd.com>");
> +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
> +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 <linux/mutex.h>
> +#include <media/v4l2-device.h>
> +#include <media/videobuf2-memops.h>
> +#include <media/videobuf2-vmalloc.h>
> +
> +#define ISP4_GET_ISP_REG_BASE(isp4sd) (((isp4sd))->mmio)
> +
> +struct isp4_platform_data {
> +	void *adev;
> +	void *bo;
> +	void *cpu_ptr;

Will touch more on these in later patches, but I would say don't 
introduce them until the patch they're needed.

> +	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 */

/* ISP4_H */


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware
  2025-06-18  9:19 ` [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware Bin Du
@ 2025-06-18 16:00   ` Mario Limonciello
  2025-06-19  7:53     ` Du, Bin
  2025-07-28  5:57   ` Sakari Ailus
  1 sibling, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-06-18 16:00 UTC (permalink / raw)
  To: Bin Du, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On 6/18/2025 4:19 AM, Bin Du wrote:
> Low level functions for access the registers and mapping to their ranges.
> This change also includes register definitions for ring buffer used to
> communicate with ISP Firmware.
> Ring buffer is the communication interface between driver and ISP Firmware.
> Command and responses are exchanged through the ring buffer.
> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>

Same comment as first patch (and others), who wrote it?  Is 
Co-developed-by missing?

> ---
>   drivers/media/platform/amd/isp4/Makefile      |   3 +-
>   drivers/media/platform/amd/isp4/isp4_hw.c     |  46 +++++++
>   drivers/media/platform/amd/isp4/isp4_hw.h     |  14 +++
>   drivers/media/platform/amd/isp4/isp4_hw_reg.h | 116 ++++++++++++++++++
>   4 files changed, 178 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.c
>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.h
>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw_reg.h
> 
> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
> index e9e84160517d..8ca1c4dfe246 100644
> --- a/drivers/media/platform/amd/isp4/Makefile
> +++ b/drivers/media/platform/amd/isp4/Makefile
> @@ -3,7 +3,8 @@
>   # Copyright (C) 2025 Advanced Micro Devices, Inc.
>   
>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
> -amd_capture-objs := isp4.o
> +amd_capture-objs := isp4.o	\
> +			isp4_hw.o	\
>   
>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>   ccflags-y += -I$(srctree)/include
> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.c b/drivers/media/platform/amd/isp4/isp4_hw.c
> new file mode 100644
> index 000000000000..e5315330a514
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_hw.c
> @@ -0,0 +1,46 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/types.h>
> +
> +#include "isp4_hw.h"
> +#include "isp4_hw_reg.h"
> +
> +#define RMMIO_SIZE 524288
> +
> +u32 isp4hw_rreg(void __iomem *base, u32 reg)
> +{
> +	void __iomem *reg_addr;
> +
> +	if (reg >= RMMIO_SIZE)
> +		return RREG_FAILED_VAL;
> +
> +	if (reg < ISP_MIPI_PHY0_REG0)
> +		reg_addr = base + reg;
> +	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
> +		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
> +	else
> +		return RREG_FAILED_VAL;
> +
> +	return readl(reg_addr);
> +};
> +
> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val)
> +{
> +	void __iomem *reg_addr;
> +
> +	if (reg >= RMMIO_SIZE)
> +		return;
> +
> +	if (reg < ISP_MIPI_PHY0_REG0)
> +		reg_addr = base + reg;
> +	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
> +		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
> +	else
> +		return;
> +
> +	writel(val, reg_addr);
> +};
> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.h b/drivers/media/platform/amd/isp4/isp4_hw.h
> new file mode 100644
> index 000000000000..072d135b9e3a
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_hw.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_HW_H_
> +#define _ISP4_HW_H_
> +
> +#define RREG_FAILED_VAL 0xFFFFFFFF
> +
> +u32 isp4hw_rreg(void __iomem *base, u32 reg);
> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val);
> +
> +#endif
> diff --git a/drivers/media/platform/amd/isp4/isp4_hw_reg.h b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
> new file mode 100644
> index 000000000000..b11f12ba6c56
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
> @@ -0,0 +1,116 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_HW_REG_H_
> +#define _ISP4_HW_REG_H_
> +
> +#define ISP_SOFT_RESET		0x62000
> +#define ISP_SYS_INT0_EN		0x62010
> +#define ISP_SYS_INT0_STATUS	0x62014
> +#define ISP_SYS_INT0_ACK	0x62018
> +#define ISP_CCPU_CNTL		0x62054
> +#define ISP_STATUS		0x62058
> +#define ISP_LOG_RB_BASE_LO0	0x62148
> +#define ISP_LOG_RB_BASE_HI0	0x6214C
> +#define ISP_LOG_RB_SIZE0	0x62150
> +#define ISP_LOG_RB_RPTR0	0x62154
> +#define ISP_LOG_RB_WPTR0	0x62158
> +#define ISP_RB_BASE_LO1		0x62170
> +#define ISP_RB_BASE_HI1		0x62174
> +#define ISP_RB_SIZE1		0x62178
> +#define ISP_RB_RPTR1		0x6217C
> +#define ISP_RB_WPTR1		0x62180
> +#define ISP_RB_BASE_LO2		0x62184
> +#define ISP_RB_BASE_HI2		0x62188
> +#define ISP_RB_SIZE2		0x6218C
> +#define ISP_RB_RPTR2		0x62190
> +#define ISP_RB_WPTR2		0x62194
> +#define ISP_RB_BASE_LO3		0x62198
> +#define ISP_RB_BASE_HI3		0x6219C
> +#define ISP_RB_SIZE3		0x621A0
> +#define ISP_RB_RPTR3		0x621A4
> +#define ISP_RB_WPTR3		0x621A8
> +#define ISP_RB_BASE_LO4		0x621AC
> +#define ISP_RB_BASE_HI4		0x621B0
> +#define ISP_RB_SIZE4		0x621B4
> +#define ISP_RB_RPTR4		0x621B8
> +#define ISP_RB_WPTR4		0x621BC
> +#define ISP_RB_BASE_LO5		0x621C0
> +#define ISP_RB_BASE_HI5		0x621C4
> +#define ISP_RB_SIZE5		0x621C8
> +#define ISP_RB_RPTR5		0x621CC
> +#define ISP_RB_WPTR5		0x621D0
> +#define ISP_RB_BASE_LO6		0x621D4
> +#define ISP_RB_BASE_HI6		0x621D8
> +#define ISP_RB_SIZE6		0x621DC
> +#define ISP_RB_RPTR6		0x621E0
> +#define ISP_RB_WPTR6		0x621E4
> +#define ISP_RB_BASE_LO7		0x621E8
> +#define ISP_RB_BASE_HI7		0x621EC
> +#define ISP_RB_SIZE7		0x621F0
> +#define ISP_RB_RPTR7		0x621F4
> +#define ISP_RB_WPTR7		0x621F8
> +#define ISP_RB_BASE_LO8		0x621FC
> +#define ISP_RB_BASE_HI8		0x62200
> +#define ISP_RB_SIZE8		0x62204
> +#define ISP_RB_RPTR8		0x62208
> +#define ISP_RB_WPTR8		0x6220C
> +#define ISP_RB_BASE_LO9		0x62210
> +#define ISP_RB_BASE_HI9		0x62214
> +#define ISP_RB_SIZE9		0x62218
> +#define ISP_RB_RPTR9		0x6221C
> +#define ISP_RB_WPTR9		0x62220
> +#define ISP_RB_BASE_LO10	0x62224
> +#define ISP_RB_BASE_HI10	0x62228
> +#define ISP_RB_SIZE10		0x6222C
> +#define ISP_RB_RPTR10		0x62230
> +#define ISP_RB_WPTR10		0x62234
> +#define ISP_RB_BASE_LO11	0x62238
> +#define ISP_RB_BASE_HI11	0x6223C
> +#define ISP_RB_SIZE11		0x62240
> +#define ISP_RB_RPTR11		0x62244
> +#define ISP_RB_WPTR11		0x62248
> +#define ISP_RB_BASE_LO12	0x6224C
> +#define ISP_RB_BASE_HI12	0x62250
> +#define ISP_RB_SIZE12		0x62254
> +#define ISP_RB_RPTR12		0x62258
> +#define ISP_RB_WPTR12		0x6225C
> +
> +#define ISP_POWER_STATUS	0x60000
> +
> +#define ISP_MIPI_PHY0_REG0	0x66700
> +#define ISP_MIPI_PHY1_REG0	0x66780
> +#define ISP_MIPI_PHY2_REG0	0x67400
> +
> +#define ISP_MIPI_PHY0_SIZE	0xD30
> +
> +/* ISP_SOFT_RESET */
> +#define ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK			0x00000001UL
> +
> +/* ISP_CCPU_CNTL */
> +#define ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK			0x00040000UL
> +
> +/* ISP_STATUS */
> +#define ISP_STATUS__CCPU_REPORT_MASK				0x000000feUL
> +
> +/* ISP_SYS_INT0_STATUS */
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK	0x00010000UL
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK	0x00040000UL
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK	0x00100000UL
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK	0x00400000UL
> +
> +/* ISP_SYS_INT0_EN */
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK	0x00010000UL
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK	0x00040000UL
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK	0x00100000UL
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK	0x00400000UL
> +
> +/* ISP_SYS_INT0_ACK */
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK	0x00010000UL
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT10_ACK_MASK	0x00040000UL
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT11_ACK_MASK	0x00100000UL
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK	0x00400000UL
> +
> +#endif


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-06-18  9:19 ` [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface Bin Du
@ 2025-06-18 16:17   ` Mario Limonciello
  2025-06-19  9:58     ` Du, Bin
  2025-07-28  7:23   ` Sakari Ailus
  1 sibling, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-06-18 16:17 UTC (permalink / raw)
  To: Bin Du, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, Alex Deucher
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov,
	amd-gfx@lists.freedesktop.org

+Alex
+amd-gfx

On 6/18/2025 4:19 AM, Bin Du wrote:
> ISP firmware controls ISP HW pipeline using dedicated embedded processor
> called ccpu.
> The communication between ISP FW and driver is using commands and
> response messages sent through the ring buffer. Command buffers support
> either global setting that is not specific to the steam and support stream
> specific parameters. Response buffers contains ISP FW notification
> information such as frame buffer done and command done. IRQ is used for
> receiving response buffer from ISP firmware, which is handled in the main
> isp4 media device. ISP ccpu is booted up through the firmware loading
> helper function prior to stream start.
> Memory used for command buffer and response buffer needs to be allocated
> from amdgpu buffer manager because isp4 is a child device of amdgpu.
> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>   drivers/media/platform/amd/isp4/Makefile      |   12 +
>   .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
>   .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++++++
>   .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
>   4 files changed, 1546 insertions(+)
>   create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
> 
> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
> index 0e36201fbb30..c0166f954516 100644
> --- a/drivers/media/platform/amd/isp4/Makefile
> +++ b/drivers/media/platform/amd/isp4/Makefile
> @@ -5,10 +5,22 @@
>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>   amd_capture-objs := isp4.o	\
>   			isp4_phy.o \
> +			isp4_interface.o \
>   			isp4_hw.o	\
>   
>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
> +ccflags-y += -I$(srctree)/include/drm
>   ccflags-y += -I$(srctree)/include
> +ccflags-y += -I$(srctree)/include/uapi/drm
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm

IMO this feels like a hack and also fragile to be sharing so much across 
subsystems.

Either there should be a kernel wide include/ header that can be used by 
both or there should be a helper exported to get just the data that is 
needed.

>   
>   ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
>   	cc_stack_align := -mpreferred-stack-boundary=4
> diff --git a/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
> new file mode 100644
> index 000000000000..437d89469af2
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
> @@ -0,0 +1,318 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_CMD_RESP_H_
> +#define _ISP4_CMD_RESP_H_
> +
> +/*

Did you mean this to be kernel doc?  If so you need:

/**

> + * @brief Host and Firmware command & response channel.
> + *        Two types of command/response channel.
> + *          Type Global Command has one command/response channel.
> + *          Type Stream Command has one command/response channel.
> + *-----------                                        ------------
> + *|         |       ---------------------------      |          |
> + *|         |  ---->|  Global Command         |----> |          |
> + *|         |       ---------------------------      |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |       ---------------------------      |          |
> + *|         |  ---->|   Stream Command        |----> |          |
> + *|         |       ---------------------------      |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|  HOST   |                                        | Firmware |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |       --------------------------       |          |
> + *|         |  <----|  Global Response       |<----  |          |
> + *|         |       --------------------------       |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |       --------------------------       |          |
> + *|         |  <----|  Stream Response       |<----  |          |
> + *|         |       --------------------------       |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *-----------                                        ------------
> + */
> +
> +/*

Same comment about kernel doc

> + * @brief command ID format
> + *        cmd_id is in the format of following type:
> + *        type: indicate command type, global/stream commands.
> + *        group: indicate the command group.
> + *        id: A unique command identification in one type and group.
> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
> + *        |      type       |      group      |       id       |
> + */
> +
> +#define CMD_TYPE_SHIFT (24)
> +#define CMD_GROUP_SHIFT (16)
> +#define CMD_TYPE_STREAM_CTRL ((u32)0x2 << CMD_TYPE_SHIFT)
> +
> +#define CMD_GROUP_STREAM_CTRL ((u32)0x1 << CMD_GROUP_SHIFT)
> +#define CMD_GROUP_STREAM_BUFFER ((u32)0x4 << CMD_GROUP_SHIFT)
> +
> +/* Stream  Command */
> +#define CMD_ID_SET_STREAM_CONFIG                        \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x1)
> +#define CMD_ID_SET_OUT_CHAN_PROP                        \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x3)
> +#define CMD_ID_ENABLE_OUT_CHAN                          \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x5)
> +#define CMD_ID_START_STREAM                             \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x7)
> +#define CMD_ID_STOP_STREAM                              \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x8)
> +
> +/* Stream Buffer Command */
> +#define CMD_ID_SEND_BUFFER                                \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_BUFFER | 0x1)
> +
> +/*

Same comment about kernel doc

> + * @brief response ID format
> + *        resp_id is in the format of following type:
> + *        type: indicate command type, global/stream commands.
> + *        group: indicate the command group.
> + *        id: A unique command identification in one type and group.
> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
> + *        |      type       |      group      |       id       |
> + */
> +
> +#define RESP_GROUP_SHIFT (16)
> +#define RESP_GROUP_MASK  (0xff << RESP_GROUP_SHIFT)
> +
> +#define GET_RESP_GROUP_VALUE(resp_id)   \
> +	(((resp_id) & RESP_GROUP_MASK) >> \
> +	 RESP_GROUP_SHIFT)
> +#define GET_RESP_ID_VALUE(resp_id) ((resp_id) & 0xffff)
> +
> +#define RESP_GROUP_GENERAL (0x1 << RESP_GROUP_SHIFT)
> +#define RESP_GROUP_NOTIFICATION (0x3 << RESP_GROUP_SHIFT)
> +
> +/* General  Response */
Extra whitespace between words
> +#define RESP_ID_CMD_DONE (RESP_GROUP_GENERAL | 0x1)
> +
> +/* Notification */
> +#define RESP_ID_NOTI_FRAME_DONE (RESP_GROUP_NOTIFICATION | 0x1)
> +
> +#define CMD_STATUS_SUCCESS (0)
> +#define CMD_STATUS_FAIL (1)
> +#define CMD_STATUS_SKIPPED (2)
> +
> +#define ADDR_SPACE_TYPE_GPU_VA 4
> +
> +#define FW_MEMORY_POOL_SIZE (200 * 1024 * 1024)
> +
> +/*
> + * standard ISP mipicsi=>isp
> + */
> +#define MIPI0_ISP_PIPELINE_ID 0x5f91
> +
> +enum isp4fw_sensor_id {
> +	SENSOR_ID_ON_MIPI0  = 0,  /* Sensor id for ISP input from MIPI port 0 */
> +};
> +
> +enum isp4fw_stream_id {
> +	STREAM_ID_INVALID = -1, /* STREAM_ID_INVALID. */
> +	STREAM_ID_1 = 0,        /* STREAM_ID_1. */
> +	STREAM_ID_2 = 1,        /* STREAM_ID_2. */
> +	STREAM_ID_3 = 2,        /* STREAM_ID_3. */
> +	STREAM_ID_MAXIMUM       /* STREAM_ID_MAXIMUM. */
> +};
> +
> +enum isp4fw_image_format {
> +	IMAGE_FORMAT_NV12 = 1,              /* 4:2:0,semi-planar, 8-bit */
> +	IMAGE_FORMAT_YUV422INTERLEAVED = 7, /* interleave, 4:2:2, 8-bit */
> +};
> +
> +enum isp4fw_pipe_out_ch {
> +	ISP_PIPE_OUT_CH_PREVIEW = 0,
> +};
> +
> +enum isp4fw_yuv_range {
> +	ISP_YUV_RANGE_FULL = 0,     /* YUV value range in 0~255 */
> +	ISP_YUV_RANGE_NARROW = 1,   /* YUV value range in 16~235 */
> +	ISP_YUV_RANGE_MAX
> +};
> +
> +enum isp4fw_buffer_type {
> +	BUFFER_TYPE_PREVIEW = 8,
> +	BUFFER_TYPE_META_INFO = 10,
> +	BUFFER_TYPE_MEM_POOL = 15,
> +};
> +
> +enum isp4fw_buffer_status {
> +	BUFFER_STATUS_INVALID,  /* The buffer is INVALID */
> +	BUFFER_STATUS_SKIPPED,  /* The buffer is not filled with image data */
> +	BUFFER_STATUS_EXIST,    /* The buffer is exist and waiting for filled */
> +	BUFFER_STATUS_DONE,     /* The buffer is filled with image data */
> +	BUFFER_STATUS_LACK,     /* The buffer is unavailable */
> +	BUFFER_STATUS_DIRTY,    /* The buffer is dirty, probably caused by
> +				 * LMI leakage
> +				 */
> +	BUFFER_STATUS_MAX       /* The buffer STATUS_MAX */
> +};
> +
> +enum isp4fw_buffer_source {
> +	/* The buffer is from the stream buffer queue */
> +	BUFFER_SOURCE_STREAM,
> +};
> +
> +struct isp4fw_error_code {
> +	u32 code1;
> +	u32 code2;
> +	u32 code3;
> +	u32 code4;
> +	u32 code5;
> +};
> +
> +/*
> + * Command Structure for FW
> + */
> +
> +struct isp4fw_cmd {
> +	u32 cmd_seq_num;
> +	u32 cmd_id;
> +	u32 cmd_param[12];
> +	u16 cmd_stream_id;
> +	u8 cmd_silent_resp;
> +	u8 reserved;
> +	u32 cmd_check_sum;
> +};
> +
> +struct isp4fw_resp_cmd_done {
> +	/* The host2fw command seqNum.
> +	 * To indicate which command this response refer to.
> +	 */
> +	u32 cmd_seq_num;
> +	/* The host2fw command id for host double check. */
> +	u32 cmd_id;
> +	/* Indicate the command process status.
> +	 * 0 means success. 1 means fail. 2 means skipped
> +	 */
> +	u16 cmd_status;
> +	/* If the cmd_status is 1, that means the command is processed fail, */
> +	/* host can check the isp4fw_error_code to get the detail
> +	 * error information
> +	 */
> +	u16 isp4fw_error_code;
> +	/* The response payload will be in different struct type */
> +	/* according to different cmd done response. */
> +	u8 payload[36];
> +};
> +
> +struct isp4fw_resp_param_package {
> +	u32 package_addr_lo;	/* The low 32 bit addr of the pkg address. */
> +	u32 package_addr_hi;	/* The high 32 bit addr of the pkg address. */
> +	u32 package_size;	/* The total pkg size in bytes. */
> +	u32 package_check_sum;	/* The byte sum of the pkg. */
> +};
> +
> +struct isp4fw_resp {
> +	u32 resp_seq_num;
> +	u32 resp_id;
> +	union {
> +		struct isp4fw_resp_cmd_done cmd_done;
> +		struct isp4fw_resp_param_package frame_done;
> +		u32 resp_param[12];
> +	} param;
> +	u8  reserved[4];
> +	u32 resp_check_sum;
> +};
> +
> +struct isp4fw_mipi_pipe_path_cfg {
> +	u32 b_enable;
> +	enum isp4fw_sensor_id isp4fw_sensor_id;
> +};
> +
> +struct isp4fw_isp_pipe_path_cfg {
> +	u32  isp_pipe_id;	/* pipe ids for pipeline construction */
> +};
> +
> +struct isp4fw_isp_stream_cfg {
> +	/* Isp mipi path */
> +	struct isp4fw_mipi_pipe_path_cfg mipi_pipe_path_cfg;
> +	/* Isp pipe path */
> +	struct isp4fw_isp_pipe_path_cfg  isp_pipe_path_cfg;
> +	/* enable TNR */
> +	u32 b_enable_tnr;
> +	/* number of frame rta per-processing,
> +	 * set to 0 to use fw default value
> +	 */
> +	u32 rta_frames_per_proc;
> +};
> +
> +struct isp4fw_image_prop {
> +	enum isp4fw_image_format image_format;	/* Image format */
> +	u32 width;				/* Width */
> +	u32 height;				/* Height */
> +	u32 luma_pitch;				/* Luma pitch */
> +	u32 chroma_pitch;			/* Chrom pitch */
> +	enum isp4fw_yuv_range yuv_range;		/* YUV value range */
> +};
> +
> +struct isp4fw_buffer {
> +	/* A check num for debug usage, host need to */
> +	/* set the buf_tags to different number */
> +	u32 buf_tags;
> +	union {
> +		u32 value;
> +		struct {
> +			u32 space : 16;
> +			u32 vmid  : 16;
> +		} bit;
> +	} vmid_space;
> +	u32 buf_base_a_lo;		/* Low address of buffer A */
> +	u32 buf_base_a_hi;		/* High address of buffer A */
> +	u32 buf_size_a;			/* Buffer size of buffer A */
> +
> +	u32 buf_base_b_lo;		/* Low address of buffer B */
> +	u32 buf_base_b_hi;		/* High address of buffer B */
> +	u32 buf_size_b;			/* Buffer size of buffer B */
> +
> +	u32 buf_base_c_lo;		/* Low address of buffer C */
> +	u32 buf_base_c_hi;		/* High address of buffer C */
> +	u32 buf_size_c;			/* Buffer size of buffer C */
> +};
> +
> +struct isp4fw_buffer_meta_info {
> +	u32 enabled;					/* enabled flag */
> +	enum isp4fw_buffer_status status;		/* BufferStatus */
> +	struct isp4fw_error_code err;			/* err code */
> +	enum isp4fw_buffer_source source;		/* BufferSource */
> +	struct isp4fw_image_prop image_prop;		/* image_prop */
> +	struct isp4fw_buffer buffer;			/* buffer */
> +};
> +
> +struct isp4fw_meta_info {
> +	u32 poc;				/* frame id */
> +	u32 fc_id;				/* frame ctl id */
> +	u32 time_stamp_lo;			/* time_stamp_lo */
> +	u32 time_stamp_hi;			/* time_stamp_hi */
> +	struct isp4fw_buffer_meta_info preview;	/* preview BufferMetaInfo */
> +};
> +
> +struct isp4fw_cmd_send_buffer {
> +	enum isp4fw_buffer_type buffer_type;	/* buffer Type */
> +	struct isp4fw_buffer buffer;		/* buffer info */
> +};
> +
> +struct isp4fw_cmd_set_out_ch_prop {
> +	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
> +	struct isp4fw_image_prop image_prop;	/* image property */
> +};
> +
> +struct isp4fw_cmd_enable_out_ch {
> +	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
> +	u32 is_enable;			/* If enable channel or not */
> +};
> +
> +struct isp4fw_cmd_set_stream_cfg {
> +	struct isp4fw_isp_stream_cfg stream_cfg; /* stream path config */
> +};
> +
> +#endif
> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c
> new file mode 100644
> index 000000000000..0e1eb22a0de5
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_interface.c
> @@ -0,0 +1,1052 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/mutex.h>
> +
> +#include "amdgpu_object.h"
> +
> +#include "isp4_fw_cmd_resp.h"
> +#include "isp4_hw.h"
> +#include "isp4_hw_reg.h"
> +#include "isp4_interface.h"
> +
> +#define ISP4IF_FW_RESP_RB_IRQ_EN_MASK \
> +	(ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK |  \
> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK | \
> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK | \
> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK)
> +
> +struct isp4if_rb_config {
> +	const char *name;
> +	u32 index;
> +	u32 reg_rptr;
> +	u32 reg_wptr;
> +	u32 reg_base_lo;
> +	u32 reg_base_hi;
> +	u32 reg_size;
> +	u32 val_size;
> +	u64 base_mc_addr;
> +	void *base_sys_addr;
> +};
> +
> +/* FW cmd ring buffer configuration */
> +static struct isp4if_rb_config
> +	isp4if_cmd_rb_config[ISP4IF_STREAM_ID_MAX] = {
> +	{
> +		.name = "CMD_RB_GBL0",
> +		.index = 3,
> +		.reg_rptr = ISP_RB_RPTR4,
> +		.reg_wptr = ISP_RB_WPTR4,
> +		.reg_base_lo = ISP_RB_BASE_LO4,
> +		.reg_base_hi = ISP_RB_BASE_HI4,
> +		.reg_size = ISP_RB_SIZE4,
> +	},
> +	{
> +		.name = "CMD_RB_STR1",
> +		.index = 0,
> +		.reg_rptr = ISP_RB_RPTR1,
> +		.reg_wptr = ISP_RB_WPTR1,
> +		.reg_base_lo = ISP_RB_BASE_LO1,
> +		.reg_base_hi = ISP_RB_BASE_HI1,
> +		.reg_size = ISP_RB_SIZE1,
> +	},
> +	{
> +		.name = "CMD_RB_STR2",
> +		.index = 1,
> +		.reg_rptr = ISP_RB_RPTR2,
> +		.reg_wptr = ISP_RB_WPTR2,
> +		.reg_base_lo = ISP_RB_BASE_LO2,
> +		.reg_base_hi = ISP_RB_BASE_HI2,
> +		.reg_size = ISP_RB_SIZE2,
> +	},
> +	{
> +		.name = "CMD_RB_STR3",
> +		.index = 2,
> +		.reg_rptr = ISP_RB_RPTR3,
> +		.reg_wptr = ISP_RB_WPTR3,
> +		.reg_base_lo = ISP_RB_BASE_LO3,
> +		.reg_base_hi = ISP_RB_BASE_HI3,
> +		.reg_size = ISP_RB_SIZE3,
> +	},
> +};
> +
> +/* FW resp ring buffer configuration */
> +static struct isp4if_rb_config
> +	isp4if_resp_rb_config[ISP4IF_STREAM_ID_MAX] = {
> +	{
> +		.name = "RES_RB_GBL0",
> +		.index = 3,
> +		.reg_rptr = ISP_RB_RPTR12,
> +		.reg_wptr = ISP_RB_WPTR12,
> +		.reg_base_lo = ISP_RB_BASE_LO12,
> +		.reg_base_hi = ISP_RB_BASE_HI12,
> +		.reg_size = ISP_RB_SIZE12,
> +	},
> +	{
> +		.name = "RES_RB_STR1",
> +		.index = 0,
> +		.reg_rptr = ISP_RB_RPTR9,
> +		.reg_wptr = ISP_RB_WPTR9,
> +		.reg_base_lo = ISP_RB_BASE_LO9,
> +		.reg_base_hi = ISP_RB_BASE_HI9,
> +		.reg_size = ISP_RB_SIZE9,
> +	},
> +	{
> +		.name = "RES_RB_STR2",
> +		.index = 1,
> +		.reg_rptr = ISP_RB_RPTR10,
> +		.reg_wptr = ISP_RB_WPTR10,
> +		.reg_base_lo = ISP_RB_BASE_LO10,
> +		.reg_base_hi = ISP_RB_BASE_HI10,
> +		.reg_size = ISP_RB_SIZE10,
> +	},
> +	{
> +		.name = "RES_RB_STR3",
> +		.index = 2,
> +		.reg_rptr = ISP_RB_RPTR11,
> +		.reg_wptr = ISP_RB_WPTR11,
> +		.reg_base_lo = ISP_RB_BASE_LO11,
> +		.reg_base_hi = ISP_RB_BASE_HI11,
> +		.reg_size = ISP_RB_SIZE11,
> +	},
> +};
> +
> +/* FW log ring buffer configuration */
> +static struct isp4if_rb_config isp4if_log_rb_config = {
> +	.name = "LOG_RB",
> +	.index = 0,
> +	.reg_rptr = ISP_LOG_RB_RPTR0,
> +	.reg_wptr = ISP_LOG_RB_WPTR0,
> +	.reg_base_lo = ISP_LOG_RB_BASE_LO0,
> +	.reg_base_hi = ISP_LOG_RB_BASE_HI0,
> +	.reg_size = ISP_LOG_RB_SIZE0,
> +};
> +
> +static struct isp4if_gpu_mem_info *isp4if_gpu_mem_alloc(struct isp4_interface
> +							*ispif,
> +							u32 mem_size)
> +{
> +	struct isp4if_gpu_mem_info *mem_info;
> +	struct amdgpu_bo *bo = NULL;
> +	struct amdgpu_device *adev;
> +	struct device *dev;
> +
> +	void *cpu_ptr;
> +	u64 gpu_addr;
> +	u32 ret;
> +
> +	dev = ispif->dev;
> +
> +	if (!mem_size)
> +		return NULL;
> +
> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
> +	if (!mem_info)
> +		return NULL;
> +
> +	adev = (struct amdgpu_device *)ispif->adev;
> +	mem_info->mem_size = mem_size;
> +	mem_info->mem_align = ISP4IF_ISP_MC_ADDR_ALIGN;
> +	mem_info->mem_domain = AMDGPU_GEM_DOMAIN_GTT;
> +
> +	ret = amdgpu_bo_create_kernel(adev,
> +				      mem_info->mem_size,
> +				      mem_info->mem_align,
> +				      mem_info->mem_domain,
> +				      &bo,
> +				      &gpu_addr,
> +				      &cpu_ptr);

IMO this is begging for an extra helper that has a true exported symbol 
and kernel-wide header for use rather than hacking around the includes 
for drm headers.

The kernel-wide header can describe the data types exchanged, so there 
wouldn't be a need to have all the amdgpu headers included.

> +
> +	if (!cpu_ptr || ret) {
> +		dev_err(dev, "gpuvm buffer alloc fail, size %u\n", mem_size);
> +		kfree(mem_info);
> +		return NULL;
> +	}
> +
> +	mem_info->sys_addr = cpu_ptr;
> +	mem_info->gpu_mc_addr = gpu_addr;
> +	mem_info->mem_handle = (void *)bo;
> +
> +	return mem_info;
> +}
> +
> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
> +			       struct isp4if_gpu_mem_info *mem_info)
> +{
> +	struct device *dev = ispif->dev;
> +	struct amdgpu_bo *bo;
> +
> +	if (!mem_info) {
> +		dev_err(dev, "invalid mem_info\n");
> +		return -EINVAL;
> +	}
> +
> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
> +
> +	amdgpu_bo_free_kernel(&bo, &mem_info->gpu_mc_addr, &mem_info->sys_addr);

This also I think needs another helper

> +
> +	kfree(mem_info);
> +
> +	return 0;
> +}
> +
> +static int isp4if_dealloc_fw_gpumem(struct isp4_interface *ispif)
> +{
> +	int i;
> +
> +	if (ispif->fw_mem_pool) {
> +		isp4if_gpu_mem_free(ispif, ispif->fw_mem_pool);
> +		ispif->fw_mem_pool = NULL;
> +	}
> +
> +	if (ispif->fw_cmd_resp_buf) {
> +		isp4if_gpu_mem_free(ispif, ispif->fw_cmd_resp_buf);
> +		ispif->fw_cmd_resp_buf = NULL;
> +	}
> +
> +	if (ispif->fw_log_buf) {
> +		isp4if_gpu_mem_free(ispif, ispif->fw_log_buf);
> +		ispif->fw_log_buf = NULL;
> +	}
> +
> +	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
> +		if (ispif->metainfo_buf_pool[i]) {
> +			isp4if_gpu_mem_free(ispif, ispif->metainfo_buf_pool[i]);
> +			ispif->metainfo_buf_pool[i] = NULL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif)
> +{
> +	struct device *dev = ispif->dev;
> +	int i;
> +
> +	ispif->fw_mem_pool = isp4if_gpu_mem_alloc(ispif, FW_MEMORY_POOL_SIZE);
> +	if (!ispif->fw_mem_pool)
> +		goto error_no_memory;
> +
> +	ispif->fw_cmd_resp_buf =
> +		isp4if_gpu_mem_alloc(ispif, ISP4IF_RB_PMBMAP_MEM_SIZE);
> +	if (!ispif->fw_cmd_resp_buf)
> +		goto error_no_memory;
> +
> +	ispif->fw_log_buf =
> +		isp4if_gpu_mem_alloc(ispif, ISP4IF_FW_LOG_RINGBUF_SIZE);
> +	if (!ispif->fw_log_buf)
> +		goto error_no_memory;
> +
> +	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
> +		ispif->metainfo_buf_pool[i] =
> +			isp4if_gpu_mem_alloc(ispif,
> +					     ISP4IF_META_INFO_BUF_SIZE);
> +		if (!ispif->metainfo_buf_pool[i])
> +			goto error_no_memory;
> +	}
> +
> +	return 0;
> +
> +error_no_memory:
> +	dev_err(dev, "failed to allocate gpu memory");

I don't think the error message is necessary, checkpatch usually 
complains about this.

> +	return -ENOMEM;
> +}
> +
> +static u32 isp4if_compute_check_sum(u8 *buf, u32 buf_size)
> +{
> +	u32 checksum = 0;
> +	u8 *surplus_ptr;
> +	u32 *buffer;
> +	u32 i;
> +
> +	buffer = (u32 *)buf;
> +	for (i = 0; i < buf_size / sizeof(u32); i++)
> +		checksum += buffer[i];
> +
> +	surplus_ptr = (u8 *)&buffer[i];
> +	/* add surplus data crc checksum */
> +	for (i = 0; i < buf_size % sizeof(u32); i++)
> +		checksum += surplus_ptr[i];
> +
> +	return checksum;
> +}
> +
> +void isp4if_clear_cmdq(struct isp4_interface *ispif)
> +{
> +	struct isp4if_cmd_element *buf_node = NULL;
> +	struct isp4if_cmd_element *tmp_node = NULL;
> +
> +	guard(mutex)(&ispif->cmdq_mutex);
> +
> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
> +		list_del(&buf_node->list);
> +		kfree(buf_node);
> +	}
> +}
> +
> +static bool isp4if_is_cmdq_rb_full(struct isp4_interface *ispif,
> +				   enum isp4if_stream_id cmd_buf_idx)
> +{
> +	struct isp4if_rb_config *rb_config;
> +	u32 rd_ptr, wr_ptr;
> +	u32 new_wr_ptr;
> +	u32 rreg;
> +	u32 wreg;
> +	u32 len;
> +
> +	rb_config = &isp4if_cmd_rb_config[cmd_buf_idx];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +	len = rb_config->val_size;
> +
> +	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
> +	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
> +
> +	new_wr_ptr = wr_ptr + sizeof(struct isp4fw_cmd);
> +
> +	if (wr_ptr >= rd_ptr) {
> +		if (new_wr_ptr < len) {
> +			return false;
> +		} else if (new_wr_ptr == len) {
> +			if (rd_ptr == 0)
> +				return true;
> +
> +			return false;
> +		}
> +
> +		new_wr_ptr -= len;
> +		if (new_wr_ptr < rd_ptr)
> +			return false;
> +
> +		return true;
> +	}
> +
> +	if (new_wr_ptr < rd_ptr)
> +		return false;
> +
> +	return true;
> +}
> +
> +static struct isp4if_cmd_element *
> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
> +			 struct isp4if_cmd_element *cmd_ele)
> +{
> +	struct isp4if_cmd_element *copy_command = NULL;
> +
> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
> +	if (!copy_command)
> +		return NULL;
> +
> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
> +
> +	guard(mutex)(&ispif->cmdq_mutex);
> +
> +	list_add_tail(&copy_command->list, &ispif->cmdq);
> +
> +	return copy_command;
> +}
> +
> +struct isp4if_cmd_element *
> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
> +			u32 seq_num,
> +			u32 cmd_id)
> +{
> +	struct isp4if_cmd_element *buf_node = NULL;
> +	struct isp4if_cmd_element *tmp_node = NULL;
> +
> +	guard(mutex)(&ispif->cmdq_mutex);
> +
> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
> +		if (buf_node->seq_num == seq_num &&
> +		    buf_node->cmd_id == cmd_id) {
> +			list_del(&buf_node->list);
> +			return buf_node;
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
> +				    enum isp4if_stream_id stream,
> +				    struct isp4fw_cmd *cmd)
> +{
> +	struct isp4if_rb_config *rb_config;
> +	struct device *dev = ispif->dev;
> +	u64 mem_addr;
> +	u64 mem_sys;
> +	u32 wr_ptr;
> +	u32 rd_ptr;
> +	u32 rreg;
> +	u32 wreg;
> +	u32 len;
> +
> +	rb_config = &isp4if_cmd_rb_config[stream];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +	mem_sys = (u64)rb_config->base_sys_addr;
> +	mem_addr = rb_config->base_mc_addr;
> +	len = rb_config->val_size;
> +
> +	if (isp4if_is_cmdq_rb_full(ispif, stream)) {
> +		dev_err(dev, "fail no cmdslot (%d)\n", stream);
> +		return -EINVAL;
> +	}
> +
> +	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
> +	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
> +
> +	if (rd_ptr > len) {
> +		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
> +			stream, rd_ptr, len, wr_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (wr_ptr > len) {
> +		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
> +			stream, wr_ptr, len, rd_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (wr_ptr < rd_ptr) {
> +		mem_addr += wr_ptr;
> +
> +		memcpy((u8 *)(mem_sys + wr_ptr),
> +		       (u8 *)cmd, sizeof(struct isp4fw_cmd));
> +	} else {
> +		if ((len - wr_ptr) >= (sizeof(struct isp4fw_cmd))) {
> +			mem_addr += wr_ptr;
> +
> +			memcpy((u8 *)(mem_sys + wr_ptr),
> +			       (u8 *)cmd, sizeof(struct isp4fw_cmd));
> +		} else {
> +			u32 size;
> +			u8 *src;
> +
> +			src = (u8 *)cmd;
> +			size = len - wr_ptr;
> +
> +			memcpy((u8 *)(mem_sys + wr_ptr), src, size);
> +
> +			src += size;
> +			size = sizeof(struct isp4fw_cmd) - size;
> +			memcpy((u8 *)(mem_sys), src, size);
> +		}
> +	}
> +
> +	wr_ptr += sizeof(struct isp4fw_cmd);
> +	if (wr_ptr >= len)
> +		wr_ptr -= len;
> +
> +	isp4hw_wreg(ispif->mmio, wreg, wr_ptr);
> +
> +	return 0;
> +}
> +
> +static inline enum isp4if_stream_id isp4if_get_fw_stream(u32 cmd_id)
> +{
> +	return ISP4IF_STREAM_ID_1;
> +}
> +
> +static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
> +			      u32 cmd_id,
> +			      void *package,
> +			      u32 package_size,
> +			      wait_queue_head_t *wq,
> +			      u32 *wq_cond,
> +			      u32 *seq)
> +{
> +	enum isp4if_stream_id stream = isp4if_get_fw_stream(cmd_id);
> +	struct isp4if_cmd_element command_element = { 0 };
> +	struct isp4if_gpu_mem_info *gpu_mem = NULL;
> +	struct isp4if_cmd_element *cmd_ele = NULL;
> +	struct isp4if_rb_config *rb_config;
> +	struct device *dev = ispif->dev;
> +	struct isp4fw_cmd cmd = {0};
> +	u64 package_base = 0;
> +	u32 sleep_count;
> +	u32 seq_num;
> +	u32 rreg;
> +	u32 wreg;
> +	int ret;
> +
> +	if (package_size > sizeof(cmd.cmd_param)) {
> +		dev_err(dev, "fail pkgsize(%u)>%lu cmd:0x%x,stream %d\n",
> +			package_size, sizeof(cmd.cmd_param), cmd_id, stream);
> +		return -EINVAL;
> +	}
> +
> +	sleep_count = 0;
> +
> +	rb_config = &isp4if_resp_rb_config[stream];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +
> +	guard(mutex)(&ispif->isp4if_mutex);
> +
> +	while (1) {
> +		if (isp4if_is_cmdq_rb_full(ispif, stream)) {
> +			u32 rd_ptr, wr_ptr;
> +
> +			if (sleep_count < ISP4IF_MAX_SLEEP_COUNT) {
> +				msleep(ISP4IF_MAX_SLEEP_TIME);
> +				sleep_count++;
> +				continue;
> +			}
> +			rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
> +			wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
> +			dev_err(dev, "fail to get cmdq slot,stream (%d), rd %u, wr %u\n",
> +				stream, rd_ptr, wr_ptr);
> +			return -ETIMEDOUT;
> +		}
> +		break;
> +	}
> +
> +	cmd.cmd_id = cmd_id;
> +	switch (stream) {
> +	case ISP4IF_STREAM_ID_GLOBAL:
> +		cmd.cmd_stream_id = (u16)STREAM_ID_INVALID;
> +		break;
> +	case ISP4IF_STREAM_ID_1:
> +		cmd.cmd_stream_id = STREAM_ID_1;
> +		break;
> +	default:
> +		dev_err(dev, "fail bad stream id %d\n", stream);
> +		return -EINVAL;
> +	}
> +
> +	if (package && package_size)
> +		memcpy(cmd.cmd_param, package, package_size);
> +
> +	seq_num = ispif->host2fw_seq_num++;
> +	cmd.cmd_seq_num = seq_num;
> +	cmd.cmd_check_sum =
> +		isp4if_compute_check_sum((u8 *)&cmd, sizeof(cmd) - 4);
> +
> +	if (seq)
> +		*seq = seq_num;
> +	command_element.seq_num = seq_num;
> +	command_element.cmd_id = cmd_id;
> +	command_element.mc_addr = package_base;
> +	command_element.wq = wq;
> +	command_element.wq_cond = wq_cond;
> +	command_element.gpu_pkg = gpu_mem;
> +	command_element.stream = stream;
> +	/* only append the fw cmd to queue when its response needs to be
> +	 * waited for, currently there are only two such commands,
> +	 * disable channel and stop stream which are only sent after close
> +	 * camera
> +	 */
> +	if (wq && wq_cond) {
> +		cmd_ele = isp4if_append_cmd_2_cmdq(ispif, &command_element);
> +		if (!cmd_ele) {
> +			dev_err(dev, "fail for isp_append_cmd_2_cmdq\n");
> +			return -ENOMEM;
> +		}
> +	}
> +
> +	ret = isp4if_insert_isp_fw_cmd(ispif, stream, &cmd);
> +	if (ret) {
> +		dev_err(dev, "fail for insert_isp_fw_cmd camId (0x%08x)\n",
> +			cmd_id);
> +		if (cmd_ele) {
> +			isp4if_rm_cmd_from_cmdq(ispif, cmd_ele->seq_num,
> +						cmd_ele->cmd_id);
> +			kfree(cmd_ele);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int isp4if_send_buffer(struct isp4_interface *ispif,
> +			      struct isp4if_img_buf_info *buf_info)
> +{
> +	struct isp4fw_cmd_send_buffer cmd;
> +
> +	memset(&cmd, 0, sizeof(cmd));
> +	cmd.buffer_type = BUFFER_TYPE_PREVIEW;
> +	cmd.buffer.vmid_space.bit.vmid = 0;
> +	cmd.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA;
> +	isp4if_split_addr64(buf_info->planes[0].mc_addr,
> +			    &cmd.buffer.buf_base_a_lo,
> +			    &cmd.buffer.buf_base_a_hi);
> +	cmd.buffer.buf_size_a = buf_info->planes[0].len;
> +
> +	isp4if_split_addr64(buf_info->planes[1].mc_addr,
> +			    &cmd.buffer.buf_base_b_lo,
> +			    &cmd.buffer.buf_base_b_hi);
> +	cmd.buffer.buf_size_b = buf_info->planes[1].len;
> +
> +	isp4if_split_addr64(buf_info->planes[2].mc_addr,
> +			    &cmd.buffer.buf_base_c_lo,
> +			    &cmd.buffer.buf_base_c_hi);
> +	cmd.buffer.buf_size_c = buf_info->planes[2].len;
> +
> +	return isp4if_send_fw_cmd(ispif, CMD_ID_SEND_BUFFER, &cmd,
> +				  sizeof(cmd), NULL, NULL, NULL);
> +}
> +
> +static void isp4if_init_rb_config(struct isp4_interface *ispif,
> +				  struct isp4if_rb_config *rb_config)
> +{
> +	u32 lo;
> +	u32 hi;
> +
> +	isp4if_split_addr64(rb_config->base_mc_addr, &lo, &hi);
> +
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_rptr, 0x0);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_wptr, 0x0);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_base_lo, lo);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_base_hi, hi);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_size, rb_config->val_size);
> +}
> +
> +static int isp4if_fw_init(struct isp4_interface *ispif)
> +{
> +	struct isp4if_rb_config *rb_config;
> +	u32 offset;
> +	int i;
> +
> +	/* initialize CMD_RB streams */
> +	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
> +		rb_config = (isp4if_cmd_rb_config + i);
> +		offset = ispif->aligned_rb_chunk_size *
> +			 (rb_config->index + ispif->cmd_rb_base_index);
> +
> +		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
> +		rb_config->base_sys_addr =
> +			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
> +		rb_config->base_mc_addr =
> +			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
> +
> +		isp4if_init_rb_config(ispif, rb_config);
> +	}
> +
> +	/* initialize RESP_RB streams */
> +	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
> +		rb_config = (isp4if_resp_rb_config + i);
> +		offset = ispif->aligned_rb_chunk_size *
> +			 (rb_config->index + ispif->resp_rb_base_index);
> +
> +		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
> +		rb_config->base_sys_addr =
> +			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
> +		rb_config->base_mc_addr =
> +			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
> +
> +		isp4if_init_rb_config(ispif, rb_config);
> +	}
> +
> +	/* initialize LOG_RB stream */
> +	rb_config = &isp4if_log_rb_config;
> +	rb_config->val_size = ISP4IF_FW_LOG_RINGBUF_SIZE;
> +	rb_config->base_mc_addr = ispif->fw_log_buf->gpu_mc_addr;
> +	rb_config->base_sys_addr = ispif->fw_log_buf->sys_addr;
> +
> +	isp4if_init_rb_config(ispif, rb_config);
> +
> +	return 0;
> +}
> +
> +static int isp4if_wait_fw_ready(struct isp4_interface *ispif,
> +				u32 isp_status_addr)
> +{
> +	struct device *dev = ispif->dev;
> +	u32 fw_ready_timeout;
> +	u32 timeout_ms = 100;
> +	u32 interval_ms = 1;
> +	u32 timeout = 0;
> +	u32 reg_val;
> +
> +	fw_ready_timeout = timeout_ms / interval_ms;
> +
> +	/* wait for FW initialize done! */
> +	while (timeout < fw_ready_timeout) {
> +		reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif),
> +				      isp_status_addr);
> +		if (reg_val & ISP_STATUS__CCPU_REPORT_MASK)
> +			return 0;
> +
> +		msleep(interval_ms);
> +		timeout++;
> +	}
> +
> +	dev_err(dev, "ISP CCPU FW boot failed\n");
> +
> +	return -ETIME;
> +}
> +
> +static void isp4if_enable_ccpu(struct isp4_interface *ispif)
> +{
> +	u32 reg_val;
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
> +	reg_val &= (~ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
> +
> +	usleep_range(100, 150);
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
> +	reg_val &= (~ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
> +}
> +
> +static void isp4if_disable_ccpu(struct isp4_interface *ispif)
> +{
> +	u32 reg_val;
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
> +	reg_val |= ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK;
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
> +
> +	usleep_range(100, 150);
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
> +	reg_val |= ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK;
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
> +}
> +
> +static int isp4if_fw_boot(struct isp4_interface *ispif)
> +{
> +	struct device *dev = ispif->dev;
> +
> +	if (ispif->status != ISP4IF_STATUS_PWR_ON) {
> +		dev_err(dev, "invalid isp power status %d\n", ispif->status);
> +		return -EINVAL;
> +	}
> +
> +	isp4if_disable_ccpu(ispif);
> +
> +	isp4if_fw_init(ispif);
> +
> +	/* clear ccpu status */
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_STATUS, 0x0);
> +
> +	isp4if_enable_ccpu(ispif);
> +
> +	if (isp4if_wait_fw_ready(ispif, ISP_STATUS)) {
> +		isp4if_disable_ccpu(ispif);
> +		return -EINVAL;
> +	}
> +
> +	/* enable interrupts */
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SYS_INT0_EN,
> +		    ISP4IF_FW_RESP_RB_IRQ_EN_MASK);
> +
> +	ispif->status = ISP4IF_STATUS_FW_RUNNING;
> +
> +	dev_dbg(dev, "ISP CCPU FW boot success\n");
> +
> +	return 0;
> +}
> +
> +int isp4if_f2h_resp(struct isp4_interface *ispif,
> +		    enum isp4if_stream_id stream,
> +		    void *resp)
> +{
> +	struct isp4fw_resp *response = resp;
> +	struct isp4if_rb_config *rb_config;
> +	struct device *dev = ispif->dev;
> +	u32 rd_ptr_dbg;
> +	u32 wr_ptr_dbg;
> +	void *mem_sys;
> +	u64 mem_addr;
> +	u32 checksum;
> +	u32 rd_ptr;
> +	u32 wr_ptr;
> +	u32 rreg;
> +	u32 wreg;
> +	u32 len;
> +
> +	rb_config = &isp4if_resp_rb_config[stream];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +	mem_sys = rb_config->base_sys_addr;
> +	mem_addr = rb_config->base_mc_addr;
> +	len = rb_config->val_size;
> +
> +	rd_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), rreg);
> +	wr_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), wreg);
> +	rd_ptr_dbg = rd_ptr;
> +	wr_ptr_dbg = wr_ptr;
> +
> +	if (rd_ptr > len) {
> +		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
> +			stream, rd_ptr, len, wr_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (wr_ptr > len) {
> +		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
> +			stream, wr_ptr, len, rd_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (rd_ptr < wr_ptr) {
> +		if ((wr_ptr - rd_ptr) >= (sizeof(struct isp4fw_resp))) {
> +			memcpy((u8 *)response, (u8 *)mem_sys + rd_ptr,
> +			       sizeof(struct isp4fw_resp));
> +
> +			rd_ptr += sizeof(struct isp4fw_resp);
> +			if (rd_ptr < len) {
> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +					    rreg, rd_ptr);
> +			} else {
> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
> +					stream, rd_ptr, len, wr_ptr);
> +				return -EINVAL;
> +			}
> +
> +		} else {
> +			dev_err(dev, "sth wrong with wptr and rptr\n");
> +			return -EINVAL;
> +		}
> +	} else if (rd_ptr > wr_ptr) {
> +		u32 size;
> +		u8 *dst;
> +
> +		dst = (u8 *)response;
> +
> +		size = len - rd_ptr;
> +		if (size > sizeof(struct isp4fw_resp)) {
> +			mem_addr += rd_ptr;
> +			memcpy((u8 *)response,
> +			       (u8 *)(mem_sys) + rd_ptr,
> +			       sizeof(struct isp4fw_resp));
> +			rd_ptr += sizeof(struct isp4fw_resp);
> +			if (rd_ptr < len) {
> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +					    rreg, rd_ptr);
> +			} else {
> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
> +					stream, rd_ptr, len, wr_ptr);
> +				return -EINVAL;
> +			}
> +
> +		} else {
> +			if ((size + wr_ptr) < (sizeof(struct isp4fw_resp))) {
> +				dev_err(dev, "sth wrong with wptr and rptr1\n");
> +				return -EINVAL;
> +			}
> +
> +			memcpy(dst, (u8 *)(mem_sys) + rd_ptr, size);
> +
> +			dst += size;
> +			size = sizeof(struct isp4fw_resp) - size;
> +			if (size)
> +				memcpy(dst, (u8 *)(mem_sys), size);
> +			rd_ptr = size;
> +			if (rd_ptr < len) {
> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +					    rreg, rd_ptr);
> +			} else {
> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
> +					stream, rd_ptr, len, wr_ptr);
> +				return -EINVAL;
> +			}
> +		}
> +	} else {
> +		return -ETIME;
> +	}
> +
> +	checksum = isp4if_compute_check_sum((u8 *)response,
> +					    (sizeof(struct isp4fw_resp) - 4));
> +
> +	if (checksum != response->resp_check_sum) {
> +		dev_err(dev, "resp checksum 0x%x,should 0x%x,rptr %u,wptr %u\n",
> +			checksum, response->resp_check_sum,
> +			rd_ptr_dbg, wr_ptr_dbg);
> +
> +		dev_err(dev, "(%u), seqNo %u, resp_id (0x%x)\n",
> +			stream,
> +			response->resp_seq_num,
> +			response->resp_id);
> +
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int isp4if_send_command(struct isp4_interface *ispif,
> +			u32 cmd_id,
> +			void *package,
> +			u32 package_size)
> +{
> +	return isp4if_send_fw_cmd(ispif,
> +				  cmd_id, package,
> +				  package_size, NULL, NULL, NULL);
> +}
> +
> +int isp4if_send_command_sync(struct isp4_interface *ispif,
> +			     u32 cmd_id,
> +			     void *package,
> +			     u32 package_size,
> +			     u32 timeout)
> +{
> +	struct device *dev = ispif->dev;
> +	DECLARE_WAIT_QUEUE_HEAD(cmd_wq);
> +	u32 wq_cond = 0;
> +	int ret;
> +	u32 seq;
> +
> +	ret = isp4if_send_fw_cmd(ispif,
> +				 cmd_id, package,
> +				 package_size, &cmd_wq, &wq_cond, &seq);
> +
> +	if (ret) {
> +		dev_err(dev, "send fw cmd fail %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = wait_event_timeout(cmd_wq, wq_cond != 0,
> +				 msecs_to_jiffies(timeout));
> +
> +	/* timeout occurred */
> +	if (ret == 0) {
> +		struct isp4if_cmd_element *ele;
> +
> +		ele = isp4if_rm_cmd_from_cmdq(ispif, seq, cmd_id);
> +		kfree(ele);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +void isp4if_clear_bufq(struct isp4_interface *ispif)
> +{
> +	struct isp4if_img_buf_node *buf_node = NULL;
> +	struct isp4if_img_buf_node *tmp_node = NULL;
> +
> +	guard(mutex)(&ispif->bufq_mutex);
> +
> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->bufq,
> +				 node) {
> +		list_del(&buf_node->node);
> +		kfree(buf_node);
> +	}
> +}
> +
> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node)
> +{
> +	kfree(buf_node);
> +}
> +
> +struct isp4if_img_buf_node *
> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info)
> +{
> +	struct isp4if_img_buf_node *node = NULL;
> +
> +	node = kmalloc(sizeof(*node), GFP_KERNEL);
> +	if (node)
> +		node->buf_info = *buf_info;
> +
> +	return node;
> +};
> +
> +struct isp4if_img_buf_node *
> +isp4if_dequeue_buffer(struct isp4_interface *ispif)
> +{
> +	struct isp4if_img_buf_node *buf_node = NULL;
> +
> +	guard(mutex)(&ispif->bufq_mutex);
> +
> +	buf_node = list_first_entry_or_null(&ispif->bufq,
> +					    typeof(*buf_node),
> +					    node);
> +	if (buf_node)
> +		list_del(&buf_node->node);
> +
> +	return buf_node;
> +}
> +
> +int isp4if_queue_buffer(struct isp4_interface *ispif,
> +			struct isp4if_img_buf_node *buf_node)
> +{
> +	int ret;
> +
> +	ret = isp4if_send_buffer(ispif, &buf_node->buf_info);
> +	if (ret)
> +		return ret;
> +
> +	guard(mutex)(&ispif->bufq_mutex);
> +
> +	list_add_tail(&buf_node->node, &ispif->bufq);
> +
> +	return 0;
> +}
> +
> +int isp4if_stop(struct isp4_interface *ispif)
> +{
> +	isp4if_disable_ccpu(ispif);
> +
> +	isp4if_dealloc_fw_gpumem(ispif);
> +
> +	return 0;
> +}
> +
> +int isp4if_start(struct isp4_interface *ispif)
> +{
> +	int ret;
> +
> +	ret = isp4if_alloc_fw_gpumem(ispif);
> +	if (ret)
> +		goto failed_gpumem_alloc;
> +
> +	ret = isp4if_fw_boot(ispif);
> +	if (ret)
> +		goto failed_fw_boot;
> +
> +	return 0;
> +
> +failed_gpumem_alloc:
> +	return -ENOMEM;
> +
> +failed_fw_boot:
> +	isp4if_dealloc_fw_gpumem(ispif);
> +	return ret;
> +}
> +
> +int isp4if_deinit(struct isp4_interface *ispif)
> +{
> +	isp4if_clear_cmdq(ispif);
> +
> +	isp4if_clear_bufq(ispif);
> +
> +	mutex_destroy(&ispif->cmdq_mutex);
> +	mutex_destroy(&ispif->bufq_mutex);
> +	mutex_destroy(&ispif->isp4if_mutex);
> +
> +	return 0;
> +}
> +
> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
> +		void *amdgpu_dev, void __iomem *isp_mmip)
> +{
> +	ispif->dev = dev;
> +	ispif->adev = amdgpu_dev;
> +	ispif->mmio = isp_mmip;
> +
> +	ispif->cmd_rb_base_index = 0;
> +	ispif->resp_rb_base_index = ISP4IF_RESP_CHAN_TO_RB_OFFSET - 1;
> +	ispif->aligned_rb_chunk_size = ISP4IF_RB_PMBMAP_MEM_CHUNK & 0xffffffc0;
> +
> +	mutex_init(&ispif->cmdq_mutex); /* used for cmdq access */
> +	mutex_init(&ispif->bufq_mutex); /* used for bufq access */
> +	mutex_init(&ispif->isp4if_mutex); /* used for commands sent to ispfw */
> +
> +	INIT_LIST_HEAD(&ispif->cmdq);
> +	INIT_LIST_HEAD(&ispif->bufq);
> +
> +	return 0;
> +}
> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/drivers/media/platform/amd/isp4/isp4_interface.h
> new file mode 100644
> index 000000000000..b2ca147b78b6
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_interface.h
> @@ -0,0 +1,164 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_INTERFACE_
> +#define _ISP4_INTERFACE_
> +
> +#define ISP4IF_RB_MAX (25)
> +#define ISP4IF_RESP_CHAN_TO_RB_OFFSET (9)
> +#define ISP4IF_RB_PMBMAP_MEM_SIZE (16 * 1024 * 1024 - 1)
> +#define ISP4IF_RB_PMBMAP_MEM_CHUNK (ISP4IF_RB_PMBMAP_MEM_SIZE \
> +	/ (ISP4IF_RB_MAX - 1))
> +#define ISP4IF_ISP_MC_ADDR_ALIGN (1024 * 32)
> +#define ISP4IF_HOST2FW_COMMAND_SIZE (sizeof(struct isp4fw_cmd))
> +#define ISP4IF_FW_CMD_BUF_COUNT 4
> +#define ISP4IF_FW_RESP_BUF_COUNT 4
> +#define ISP4IF_MAX_NUM_HOST2FW_COMMAND (40)
> +#define ISP4IF_FW_CMD_BUF_SIZE (ISP4IF_MAX_NUM_HOST2FW_COMMAND \
> +	* ISP4IF_HOST2FW_COMMAND_SIZE)
> +#define ISP4IF_MAX_SLEEP_COUNT (10)
> +#define ISP4IF_MAX_SLEEP_TIME (33)
> +
> +#define ISP4IF_META_INFO_BUF_SIZE ALIGN(sizeof(struct isp4fw_meta_info), 0x8000)
> +#define ISP4IF_MAX_STREAM_META_BUF_COUNT 6
> +
> +#define ISP4IF_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
> +
> +#define ISP4IF_MAX_CMD_RESPONSE_BUF_SIZE (4 * 1024)
> +
> +#define GET_ISP4IF_REG_BASE(ispif) (((ispif))->mmio)
> +
> +enum isp4if_stream_id {
> +	ISP4IF_STREAM_ID_GLOBAL = 0,
> +	ISP4IF_STREAM_ID_1 = 1,
> +	ISP4IF_STREAM_ID_MAX = 4
> +};
> +
> +enum isp4if_status {
> +	ISP4IF_STATUS_PWR_OFF,
> +	ISP4IF_STATUS_PWR_ON,
> +	ISP4IF_STATUS_FW_RUNNING,
> +	ISP4IF_FSM_STATUS_MAX
> +};
> +
> +struct isp4if_gpu_mem_info {
> +	u32	mem_domain;
> +	u64	mem_size;
> +	u32	mem_align;
> +	u64	gpu_mc_addr;
> +	void	*sys_addr;
> +	void	*mem_handle;
> +};
> +
> +struct isp4if_img_buf_info {
> +	struct {
> +		void *sys_addr;
> +		u64 mc_addr;
> +		u32 len;
> +	} planes[3];
> +};
> +
> +struct isp4if_img_buf_node {
> +	struct list_head node;
> +	struct isp4if_img_buf_info buf_info;
> +};
> +
> +struct isp4if_cmd_element {
> +	struct list_head list;
> +	u32 seq_num;
> +	u32 cmd_id;
> +	enum isp4if_stream_id stream;
> +	u64 mc_addr;
> +	wait_queue_head_t *wq;
> +	u32 *wq_cond;
> +	struct isp4if_gpu_mem_info *gpu_pkg;
> +};
> +
> +struct isp4_interface {
> +	struct amdgpu_device *adev;
> +
> +	struct device *dev;
> +	void __iomem *mmio;
> +
> +	struct mutex cmdq_mutex; /* used for cmdq access */
> +	struct mutex bufq_mutex; /* used for bufq access */
> +	struct mutex isp4if_mutex; /* used to send fw cmd and read fw log */
> +
> +	struct list_head cmdq; /* commands sent to fw */
> +	struct list_head bufq; /* buffers sent to fw */
> +
> +	enum isp4if_status status;
> +	u32 host2fw_seq_num;
> +
> +	/* FW ring buffer configs */
> +	u32 cmd_rb_base_index;
> +	u32 resp_rb_base_index;
> +	u32 aligned_rb_chunk_size;
> +
> +	/* ISP fw buffers */
> +	struct isp4if_gpu_mem_info *fw_log_buf;
> +	struct isp4if_gpu_mem_info *fw_cmd_resp_buf;
> +	struct isp4if_gpu_mem_info *fw_mem_pool;
> +	struct isp4if_gpu_mem_info *
> +		metainfo_buf_pool[ISP4IF_MAX_STREAM_META_BUF_COUNT];
> +};
> +
> +static inline void isp4if_split_addr64(u64 addr, u32 *lo, u32 *hi)
> +{
> +	if (lo)
> +		*lo = (u32)(addr & 0xffffffff);
> +	if (hi)
> +		*hi = (u32)(addr >> 32);
> +}
> +
> +static inline u64 isp4if_join_addr64(u32 lo, u32 hi)
> +{
> +	return (((u64)hi) << 32) | (u64)lo;
> +}
> +
> +int isp4if_f2h_resp(struct isp4_interface *ispif,
> +		    enum isp4if_stream_id stream,
> +		    void *response);
> +
> +int isp4if_send_command(struct isp4_interface *ispif,
> +			u32 cmd_id,
> +			void *package,
> +			u32 package_size);
> +
> +int isp4if_send_command_sync(struct isp4_interface *ispif,
> +			     u32 cmd_id,
> +			     void *package,
> +			     u32 package_size,
> +			     u32 timeout);
> +
> +struct isp4if_cmd_element *
> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
> +			u32 seq_num,
> +			u32 cmd_id);
> +
> +void isp4if_clear_cmdq(struct isp4_interface *ispif);
> +
> +void isp4if_clear_bufq(struct isp4_interface *ispif);
> +
> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node);
> +
> +struct isp4if_img_buf_node *
> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info);
> +
> +struct isp4if_img_buf_node *isp4if_dequeue_buffer(struct isp4_interface *ispif);
> +
> +int isp4if_queue_buffer(struct isp4_interface *ispif,
> +			struct isp4if_img_buf_node *buf_node);
> +
> +int isp4if_stop(struct isp4_interface *ispif);
> +
> +int isp4if_start(struct isp4_interface *ispif);
> +
> +int isp4if_deinit(struct isp4_interface *ispif);
> +
> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
> +		void *amdgpu_dev, void __iomem *isp_mmip);
> +
> +#endif


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-06-18  9:19 ` [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added Bin Du
@ 2025-06-18 16:35   ` Mario Limonciello
  2025-06-20  9:31     ` Du, Bin
  2025-07-25  1:35   ` Sultan Alsawaf
  1 sibling, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-06-18 16:35 UTC (permalink / raw)
  To: Bin Du, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On 6/18/2025 4:19 AM, Bin Du wrote:
> 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 <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>   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 <linux/pm_runtime.h>
>   #include <linux/vmalloc.h>
> +#include <media/v4l2-fwnode.h>
>   #include <media/v4l2-ioctl.h>
>   
> -#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);

You're discarding ret here.  Shouldn't you return ret in the failure path?

> +
> +	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;

This isn't fatal?

> +	}
> +
> +	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");

Probably can drop this now

> +	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;

As mentioned in the first patch, avoid ping ponging the code.

> +
> +	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:
As mentioned in the first patch, avoid ping ponging the code.
>   	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");

Don't ping pong this

> +
> +	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 <linux/mutex.h>
> -#include <media/v4l2-device.h>
>   #include <media/videobuf2-memops.h>
>   #include <media/videobuf2-vmalloc.h>
> +#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 <linux/mutex.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "isp4_fw_cmd_resp.h"
> +#include "isp4_hw.h"
> +#include "isp4_interface.h"
> +#include "isp4_phy.h"
> +#include "isp4_subdev.h"
> +#include <linux/units.h>
> +
> +#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 <linux/delay.h>
> +#include <linux/firmware.h>
> +#include <linux/platform_device.h>
> +#include <linux/uaccess.h>
> +#include <linux/types.h>
> +#include <linux/debugfs.h>
> +#include <media/v4l2-device.h>
> +#include <media/videobuf2-vmalloc.h>
> +
> +#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


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-06-18 15:58   ` Mario Limonciello
@ 2025-06-19  7:46     ` Du, Bin
  2025-06-19 13:00       ` Mario Limonciello
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-06-19  7:46 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Many thx Mario for your comments, really helpful, will address all of 
them in the next patch.
Add inline for some of your comments, pls check

On 6/18/2025 11:58 PM, Mario Limonciello wrote:
> On 6/18/2025 4:19 AM, Bin Du wrote:
>> Amd isp4 capture is a v4l2 media device which implements media controller
> 
> AMD
> 
>> interface.
>> It has one sub-device (amd ISP4 sub-device) endpoint which can be 
>> connected
> 
> AMD
> 
>> 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
> 
> MAINTAINERS
> 
>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> 
> Who actually developed?  If both are developers there should be a Co- 
> developed-by tag.
> 
>> ---
>>   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 <bin.du@amd.com>
>> +M:    Nirujogi Pratap <pratap.nirujogi@amd.com>
>> +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 <Felix.Kuehling@amd.com>
>>   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/
> 
> Is this whole file alphabetical?  If so this is the wrong place.
> 
>>   # 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
> 
> I don't believe this should default 'y'.  Normally drivers need to be 
> opt in.
> 
>> +    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.
> 
> 2025
> 
>> +# 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
> 
> As the directory is already conditional on CONFIG_AMD_ISP4 is this obj- 
> $() needed?  Or should it really be obj-y?
>
Yes, it is needed, because AMD_ISP4 is trisate in Kconfig, it can be y or m

>> +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
> 
> Do you really need to enforce all these flags just for this driver?
> 
> Was this just for development to avoid having to remember to call the 
> build with W=1 or CONFIG_WERROR?
> 
We found after patch submission, Media CI robot test will be triggered, 
when it builds the patch it will set these flags, so adding these flags 
to align with Media CI robot test to discover potential issue before 
submission.

>> 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 <linux/pm_runtime.h>
>> +#include <linux/vmalloc.h>
>> +#include <media/v4l2-ioctl.h>
>> +
>> +#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;
> 
> In patch 5 you change this function, including dropping the goto and label.
> 
> So I suggest that for patch 1 you KISS:
> 
> static irqreturn_t isp4_irq_handler(int irq, void *arg)
> {
>      return IRQ_HANDLED;
> }
> 
> Then in patch 5 add the extra conditional code and real handling.
> 
>> +}
>> +
>> +/*
>> + * amd capture module
>> + */
> 
> Pointless comment, no?
> 
>> +static int isp4_capture_probe(struct platform_device *pdev)
>> +{
>> +    struct device *dev = &pdev->dev;
>> +    struct isp4_device *isp_dev;
>> +
> 
> Why newline here?
> 
>> +    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");
> 
> As you have error handling in place with dev_err_probe() I think the 
> lack of an error implies this message.  I'd say drop it.
> 
>> +
>> +    /* 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");
> 
> As you have error handling in place with dev_err_probe() I think the 
> lack of an error implies this message.  I'd say drop it.
> 
>> +
>> +    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");
> 
> Probably not needed message anymore, right?
> 
>> +}
>> +
>> +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 <bin.du@amd.com>");
>> +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
>> +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 <linux/mutex.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/videobuf2-memops.h>
>> +#include <media/videobuf2-vmalloc.h>
>> +
>> +#define ISP4_GET_ISP_REG_BASE(isp4sd) (((isp4sd))->mmio)
>> +
>> +struct isp4_platform_data {
>> +    void *adev;
>> +    void *bo;
>> +    void *cpu_ptr;
> 
> Will touch more on these in later patches, but I would say don't 
> introduce them until the patch they're needed.
> 
>> +    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 */
> 
> /* ISP4_H */
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware
  2025-06-18 16:00   ` Mario Limonciello
@ 2025-06-19  7:53     ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-06-19  7:53 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du

Thanks Mario, will add the Co-developed-by in all patches in the series.

On 6/19/2025 12:00 AM, Mario Limonciello wrote:
> On 6/18/2025 4:19 AM, Bin Du wrote:
>> Low level functions for access the registers and mapping to their ranges.
>> This change also includes register definitions for ring buffer used to
>> communicate with ISP Firmware.
>> Ring buffer is the communication interface between driver and ISP 
>> Firmware.
>> Command and responses are exchanged through the ring buffer.
>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> 
> Same comment as first patch (and others), who wrote it?  Is Co- 
> developed-by missing?
> 
>> ---
>>   drivers/media/platform/amd/isp4/Makefile      |   3 +-
>>   drivers/media/platform/amd/isp4/isp4_hw.c     |  46 +++++++
>>   drivers/media/platform/amd/isp4/isp4_hw.h     |  14 +++
>>   drivers/media/platform/amd/isp4/isp4_hw_reg.h | 116 ++++++++++++++++++
>>   4 files changed, 178 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.c
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.h
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw_reg.h
>>
>> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/ 
>> platform/amd/isp4/Makefile
>> index e9e84160517d..8ca1c4dfe246 100644
>> --- a/drivers/media/platform/amd/isp4/Makefile
>> +++ b/drivers/media/platform/amd/isp4/Makefile
>> @@ -3,7 +3,8 @@
>>   # Copyright (C) 2025 Advanced Micro Devices, Inc.
>>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>> -amd_capture-objs := isp4.o
>> +amd_capture-objs := isp4.o    \
>> +            isp4_hw.o    \
>>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>>   ccflags-y += -I$(srctree)/include
>> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.c b/drivers/ 
>> media/platform/amd/isp4/isp4_hw.c
>> new file mode 100644
>> index 000000000000..e5315330a514
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_hw.c
>> @@ -0,0 +1,46 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/io.h>
>> +#include <linux/types.h>
>> +
>> +#include "isp4_hw.h"
>> +#include "isp4_hw_reg.h"
>> +
>> +#define RMMIO_SIZE 524288
>> +
>> +u32 isp4hw_rreg(void __iomem *base, u32 reg)
>> +{
>> +    void __iomem *reg_addr;
>> +
>> +    if (reg >= RMMIO_SIZE)
>> +        return RREG_FAILED_VAL;
>> +
>> +    if (reg < ISP_MIPI_PHY0_REG0)
>> +        reg_addr = base + reg;
>> +    else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
>> +        reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
>> +    else
>> +        return RREG_FAILED_VAL;
>> +
>> +    return readl(reg_addr);
>> +};
>> +
>> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val)
>> +{
>> +    void __iomem *reg_addr;
>> +
>> +    if (reg >= RMMIO_SIZE)
>> +        return;
>> +
>> +    if (reg < ISP_MIPI_PHY0_REG0)
>> +        reg_addr = base + reg;
>> +    else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
>> +        reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
>> +    else
>> +        return;
>> +
>> +    writel(val, reg_addr);
>> +};
>> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.h b/drivers/ 
>> media/platform/amd/isp4/isp4_hw.h
>> new file mode 100644
>> index 000000000000..072d135b9e3a
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_hw.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_HW_H_
>> +#define _ISP4_HW_H_
>> +
>> +#define RREG_FAILED_VAL 0xFFFFFFFF
>> +
>> +u32 isp4hw_rreg(void __iomem *base, u32 reg);
>> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val);
>> +
>> +#endif
>> diff --git a/drivers/media/platform/amd/isp4/isp4_hw_reg.h b/drivers/ 
>> media/platform/amd/isp4/isp4_hw_reg.h
>> new file mode 100644
>> index 000000000000..b11f12ba6c56
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
>> @@ -0,0 +1,116 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_HW_REG_H_
>> +#define _ISP4_HW_REG_H_
>> +
>> +#define ISP_SOFT_RESET        0x62000
>> +#define ISP_SYS_INT0_EN        0x62010
>> +#define ISP_SYS_INT0_STATUS    0x62014
>> +#define ISP_SYS_INT0_ACK    0x62018
>> +#define ISP_CCPU_CNTL        0x62054
>> +#define ISP_STATUS        0x62058
>> +#define ISP_LOG_RB_BASE_LO0    0x62148
>> +#define ISP_LOG_RB_BASE_HI0    0x6214C
>> +#define ISP_LOG_RB_SIZE0    0x62150
>> +#define ISP_LOG_RB_RPTR0    0x62154
>> +#define ISP_LOG_RB_WPTR0    0x62158
>> +#define ISP_RB_BASE_LO1        0x62170
>> +#define ISP_RB_BASE_HI1        0x62174
>> +#define ISP_RB_SIZE1        0x62178
>> +#define ISP_RB_RPTR1        0x6217C
>> +#define ISP_RB_WPTR1        0x62180
>> +#define ISP_RB_BASE_LO2        0x62184
>> +#define ISP_RB_BASE_HI2        0x62188
>> +#define ISP_RB_SIZE2        0x6218C
>> +#define ISP_RB_RPTR2        0x62190
>> +#define ISP_RB_WPTR2        0x62194
>> +#define ISP_RB_BASE_LO3        0x62198
>> +#define ISP_RB_BASE_HI3        0x6219C
>> +#define ISP_RB_SIZE3        0x621A0
>> +#define ISP_RB_RPTR3        0x621A4
>> +#define ISP_RB_WPTR3        0x621A8
>> +#define ISP_RB_BASE_LO4        0x621AC
>> +#define ISP_RB_BASE_HI4        0x621B0
>> +#define ISP_RB_SIZE4        0x621B4
>> +#define ISP_RB_RPTR4        0x621B8
>> +#define ISP_RB_WPTR4        0x621BC
>> +#define ISP_RB_BASE_LO5        0x621C0
>> +#define ISP_RB_BASE_HI5        0x621C4
>> +#define ISP_RB_SIZE5        0x621C8
>> +#define ISP_RB_RPTR5        0x621CC
>> +#define ISP_RB_WPTR5        0x621D0
>> +#define ISP_RB_BASE_LO6        0x621D4
>> +#define ISP_RB_BASE_HI6        0x621D8
>> +#define ISP_RB_SIZE6        0x621DC
>> +#define ISP_RB_RPTR6        0x621E0
>> +#define ISP_RB_WPTR6        0x621E4
>> +#define ISP_RB_BASE_LO7        0x621E8
>> +#define ISP_RB_BASE_HI7        0x621EC
>> +#define ISP_RB_SIZE7        0x621F0
>> +#define ISP_RB_RPTR7        0x621F4
>> +#define ISP_RB_WPTR7        0x621F8
>> +#define ISP_RB_BASE_LO8        0x621FC
>> +#define ISP_RB_BASE_HI8        0x62200
>> +#define ISP_RB_SIZE8        0x62204
>> +#define ISP_RB_RPTR8        0x62208
>> +#define ISP_RB_WPTR8        0x6220C
>> +#define ISP_RB_BASE_LO9        0x62210
>> +#define ISP_RB_BASE_HI9        0x62214
>> +#define ISP_RB_SIZE9        0x62218
>> +#define ISP_RB_RPTR9        0x6221C
>> +#define ISP_RB_WPTR9        0x62220
>> +#define ISP_RB_BASE_LO10    0x62224
>> +#define ISP_RB_BASE_HI10    0x62228
>> +#define ISP_RB_SIZE10        0x6222C
>> +#define ISP_RB_RPTR10        0x62230
>> +#define ISP_RB_WPTR10        0x62234
>> +#define ISP_RB_BASE_LO11    0x62238
>> +#define ISP_RB_BASE_HI11    0x6223C
>> +#define ISP_RB_SIZE11        0x62240
>> +#define ISP_RB_RPTR11        0x62244
>> +#define ISP_RB_WPTR11        0x62248
>> +#define ISP_RB_BASE_LO12    0x6224C
>> +#define ISP_RB_BASE_HI12    0x62250
>> +#define ISP_RB_SIZE12        0x62254
>> +#define ISP_RB_RPTR12        0x62258
>> +#define ISP_RB_WPTR12        0x6225C
>> +
>> +#define ISP_POWER_STATUS    0x60000
>> +
>> +#define ISP_MIPI_PHY0_REG0    0x66700
>> +#define ISP_MIPI_PHY1_REG0    0x66780
>> +#define ISP_MIPI_PHY2_REG0    0x67400
>> +
>> +#define ISP_MIPI_PHY0_SIZE    0xD30
>> +
>> +/* ISP_SOFT_RESET */
>> +#define ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK            0x00000001UL
>> +
>> +/* ISP_CCPU_CNTL */
>> +#define ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK            0x00040000UL
>> +
>> +/* ISP_STATUS */
>> +#define ISP_STATUS__CCPU_REPORT_MASK                0x000000feUL
>> +
>> +/* ISP_SYS_INT0_STATUS */
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK    
>> 0x00010000UL
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK    
>> 0x00040000UL
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK    
>> 0x00100000UL
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK    
>> 0x00400000UL
>> +
>> +/* ISP_SYS_INT0_EN */
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK    0x00010000UL
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK    
>> 0x00040000UL
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK    
>> 0x00100000UL
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK    
>> 0x00400000UL
>> +
>> +/* ISP_SYS_INT0_ACK */
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK    
>> 0x00010000UL
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT10_ACK_MASK    
>> 0x00040000UL
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT11_ACK_MASK    
>> 0x00100000UL
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK    
>> 0x00400000UL
>> +
>> +#endif
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-06-18 16:17   ` Mario Limonciello
@ 2025-06-19  9:58     ` Du, Bin
  2025-06-19 15:11       ` Mario Limonciello
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-06-19  9:58 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, Alex Deucher
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov,
	amd-gfx@lists.freedesktop.org

Thanks Mario, will fix in the next version and pls see some of my comments

On 6/19/2025 12:17 AM, Mario Limonciello wrote:
> +Alex
> +amd-gfx
> 
> On 6/18/2025 4:19 AM, Bin Du wrote:
>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>> called ccpu.
>> The communication between ISP FW and driver is using commands and
>> response messages sent through the ring buffer. Command buffers support
>> either global setting that is not specific to the steam and support 
>> stream
>> specific parameters. Response buffers contains ISP FW notification
>> information such as frame buffer done and command done. IRQ is used for
>> receiving response buffer from ISP firmware, which is handled in the main
>> isp4 media device. ISP ccpu is booted up through the firmware loading
>> helper function prior to stream start.
>> Memory used for command buffer and response buffer needs to be allocated
>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   drivers/media/platform/amd/isp4/Makefile      |   12 +
>>   .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
>>   .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++++++
>>   .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
>>   4 files changed, 1546 insertions(+)
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
>>
>> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/ 
>> platform/amd/isp4/Makefile
>> index 0e36201fbb30..c0166f954516 100644
>> --- a/drivers/media/platform/amd/isp4/Makefile
>> +++ b/drivers/media/platform/amd/isp4/Makefile
>> @@ -5,10 +5,22 @@
>>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>>   amd_capture-objs := isp4.o    \
>>               isp4_phy.o \
>> +            isp4_interface.o \
>>               isp4_hw.o    \
>>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
>> +ccflags-y += -I$(srctree)/include/drm
>>   ccflags-y += -I$(srctree)/include
>> +ccflags-y += -I$(srctree)/include/uapi/drm
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm
> 
> IMO this feels like a hack and also fragile to be sharing so much across 
> subsystems.
> 
> Either there should be a kernel wide include/ header that can be used by 
> both or there should be a helper exported to get just the data that is 
> needed.

Yes, will refine to remove unnecessary ones in the next version, 
actually isp driver needs to access function amdgpu_bo_create_kernel 
which is exported by amdgpu and delared in amdgpu_object.h, because 
amdgpu_object.h also includes other amd gpu header files, so have to add 
these include path to avoid compilation error.
It'll be greate if there is kernel wide include, any suggestion for this?

> 
>>   ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
>>       cc_stack_align := -mpreferred-stack-boundary=4
>> diff --git a/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h b/ 
>> drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>> new file mode 100644
>> index 000000000000..437d89469af2
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>> @@ -0,0 +1,318 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_CMD_RESP_H_
>> +#define _ISP4_CMD_RESP_H_
>> +
>> +/*
> 
> Did you mean this to be kernel doc?  If so you need:
> 
> /**
> 
Many thx, will update in the next patch

>> + * @brief Host and Firmware command & response channel.
>> + *        Two types of command/response channel.
>> + *          Type Global Command has one command/response channel.
>> + *          Type Stream Command has one command/response channel.
>> + *-----------                                        ------------
>> + *|         |       ---------------------------      |          |
>> + *|         |  ---->|  Global Command         |----> |          |
>> + *|         |       ---------------------------      |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |       ---------------------------      |          |
>> + *|         |  ---->|   Stream Command        |----> |          |
>> + *|         |       ---------------------------      |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|  HOST   |                                        | Firmware |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |       --------------------------       |          |
>> + *|         |  <----|  Global Response       |<----  |          |
>> + *|         |       --------------------------       |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |       --------------------------       |          |
>> + *|         |  <----|  Stream Response       |<----  |          |
>> + *|         |       --------------------------       |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *-----------                                        ------------
>> + */
>> +
>> +/*
> 
> Same comment about kernel doc
> 
Many thx, will update in the next patch>> + * @brief command ID format
>> + *        cmd_id is in the format of following type:
>> + *        type: indicate command type, global/stream commands.
>> + *        group: indicate the command group.
>> + *        id: A unique command identification in one type and group.
>> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
>> + *        |      type       |      group      |       id       |
>> + */
>> +
>> +#define CMD_TYPE_SHIFT (24)
>> +#define CMD_GROUP_SHIFT (16)
>> +#define CMD_TYPE_STREAM_CTRL ((u32)0x2 << CMD_TYPE_SHIFT)
>> +
>> +#define CMD_GROUP_STREAM_CTRL ((u32)0x1 << CMD_GROUP_SHIFT)
>> +#define CMD_GROUP_STREAM_BUFFER ((u32)0x4 << CMD_GROUP_SHIFT)
>> +
>> +/* Stream  Command */
>> +#define CMD_ID_SET_STREAM_CONFIG                        \
>> +    (CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x1)
>> +#define CMD_ID_SET_OUT_CHAN_PROP                        \
>> +    (CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x3)
>> +#define CMD_ID_ENABLE_OUT_CHAN                          \
>> +    (CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x5)
>> +#define CMD_ID_START_STREAM                             \
>> +    (CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x7)
>> +#define CMD_ID_STOP_STREAM                              \
>> +    (CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x8)
>> +
>> +/* Stream Buffer Command */
>> +#define CMD_ID_SEND_BUFFER                                \
>> +    (CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_BUFFER | 0x1)
>> +
>> +/*
> 
> Same comment about kernel doc
> 
Many thx, will update in the next patch>> + * @brief response ID format
>> + *        resp_id is in the format of following type:
>> + *        type: indicate command type, global/stream commands.
>> + *        group: indicate the command group.
>> + *        id: A unique command identification in one type and group.
>> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
>> + *        |      type       |      group      |       id       |
>> + */
>> +
>> +#define RESP_GROUP_SHIFT (16)
>> +#define RESP_GROUP_MASK  (0xff << RESP_GROUP_SHIFT)
>> +
>> +#define GET_RESP_GROUP_VALUE(resp_id)   \
>> +    (((resp_id) & RESP_GROUP_MASK) >> \
>> +     RESP_GROUP_SHIFT)
>> +#define GET_RESP_ID_VALUE(resp_id) ((resp_id) & 0xffff)
>> +
>> +#define RESP_GROUP_GENERAL (0x1 << RESP_GROUP_SHIFT)
>> +#define RESP_GROUP_NOTIFICATION (0x3 << RESP_GROUP_SHIFT)
>> +
>> +/* General  Response */
> Extra whitespace between words
Many thx, will update in the next patch

>> +#define RESP_ID_CMD_DONE (RESP_GROUP_GENERAL | 0x1)
>> +
>> +/* Notification */
>> +#define RESP_ID_NOTI_FRAME_DONE (RESP_GROUP_NOTIFICATION | 0x1)
>> +
>> +#define CMD_STATUS_SUCCESS (0)
>> +#define CMD_STATUS_FAIL (1)
>> +#define CMD_STATUS_SKIPPED (2)
>> +
>> +#define ADDR_SPACE_TYPE_GPU_VA 4
>> +
>> +#define FW_MEMORY_POOL_SIZE (200 * 1024 * 1024)
>> +
>> +/*
>> + * standard ISP mipicsi=>isp
>> + */
>> +#define MIPI0_ISP_PIPELINE_ID 0x5f91
>> +
>> +enum isp4fw_sensor_id {
>> +    SENSOR_ID_ON_MIPI0  = 0,  /* Sensor id for ISP input from MIPI 
>> port 0 */
>> +};
>> +
>> +enum isp4fw_stream_id {
>> +    STREAM_ID_INVALID = -1, /* STREAM_ID_INVALID. */
>> +    STREAM_ID_1 = 0,        /* STREAM_ID_1. */
>> +    STREAM_ID_2 = 1,        /* STREAM_ID_2. */
>> +    STREAM_ID_3 = 2,        /* STREAM_ID_3. */
>> +    STREAM_ID_MAXIMUM       /* STREAM_ID_MAXIMUM. */
>> +};
>> +
>> +enum isp4fw_image_format {
>> +    IMAGE_FORMAT_NV12 = 1,              /* 4:2:0,semi-planar, 8-bit */
>> +    IMAGE_FORMAT_YUV422INTERLEAVED = 7, /* interleave, 4:2:2, 8-bit */
>> +};
>> +
>> +enum isp4fw_pipe_out_ch {
>> +    ISP_PIPE_OUT_CH_PREVIEW = 0,
>> +};
>> +
>> +enum isp4fw_yuv_range {
>> +    ISP_YUV_RANGE_FULL = 0,     /* YUV value range in 0~255 */
>> +    ISP_YUV_RANGE_NARROW = 1,   /* YUV value range in 16~235 */
>> +    ISP_YUV_RANGE_MAX
>> +};
>> +
>> +enum isp4fw_buffer_type {
>> +    BUFFER_TYPE_PREVIEW = 8,
>> +    BUFFER_TYPE_META_INFO = 10,
>> +    BUFFER_TYPE_MEM_POOL = 15,
>> +};
>> +
>> +enum isp4fw_buffer_status {
>> +    BUFFER_STATUS_INVALID,  /* The buffer is INVALID */
>> +    BUFFER_STATUS_SKIPPED,  /* The buffer is not filled with image 
>> data */
>> +    BUFFER_STATUS_EXIST,    /* The buffer is exist and waiting for 
>> filled */
>> +    BUFFER_STATUS_DONE,     /* The buffer is filled with image data */
>> +    BUFFER_STATUS_LACK,     /* The buffer is unavailable */
>> +    BUFFER_STATUS_DIRTY,    /* The buffer is dirty, probably caused by
>> +                 * LMI leakage
>> +                 */
>> +    BUFFER_STATUS_MAX       /* The buffer STATUS_MAX */
>> +};
>> +
>> +enum isp4fw_buffer_source {
>> +    /* The buffer is from the stream buffer queue */
>> +    BUFFER_SOURCE_STREAM,
>> +};
>> +
>> +struct isp4fw_error_code {
>> +    u32 code1;
>> +    u32 code2;
>> +    u32 code3;
>> +    u32 code4;
>> +    u32 code5;
>> +};
>> +
>> +/*
>> + * Command Structure for FW
>> + */
>> +
>> +struct isp4fw_cmd {
>> +    u32 cmd_seq_num;
>> +    u32 cmd_id;
>> +    u32 cmd_param[12];
>> +    u16 cmd_stream_id;
>> +    u8 cmd_silent_resp;
>> +    u8 reserved;
>> +    u32 cmd_check_sum;
>> +};
>> +
>> +struct isp4fw_resp_cmd_done {
>> +    /* The host2fw command seqNum.
>> +     * To indicate which command this response refer to.
>> +     */
>> +    u32 cmd_seq_num;
>> +    /* The host2fw command id for host double check. */
>> +    u32 cmd_id;
>> +    /* Indicate the command process status.
>> +     * 0 means success. 1 means fail. 2 means skipped
>> +     */
>> +    u16 cmd_status;
>> +    /* If the cmd_status is 1, that means the command is processed 
>> fail, */
>> +    /* host can check the isp4fw_error_code to get the detail
>> +     * error information
>> +     */
>> +    u16 isp4fw_error_code;
>> +    /* The response payload will be in different struct type */
>> +    /* according to different cmd done response. */
>> +    u8 payload[36];
>> +};
>> +
>> +struct isp4fw_resp_param_package {
>> +    u32 package_addr_lo;    /* The low 32 bit addr of the pkg 
>> address. */
>> +    u32 package_addr_hi;    /* The high 32 bit addr of the pkg 
>> address. */
>> +    u32 package_size;    /* The total pkg size in bytes. */
>> +    u32 package_check_sum;    /* The byte sum of the pkg. */
>> +};
>> +
>> +struct isp4fw_resp {
>> +    u32 resp_seq_num;
>> +    u32 resp_id;
>> +    union {
>> +        struct isp4fw_resp_cmd_done cmd_done;
>> +        struct isp4fw_resp_param_package frame_done;
>> +        u32 resp_param[12];
>> +    } param;
>> +    u8  reserved[4];
>> +    u32 resp_check_sum;
>> +};
>> +
>> +struct isp4fw_mipi_pipe_path_cfg {
>> +    u32 b_enable;
>> +    enum isp4fw_sensor_id isp4fw_sensor_id;
>> +};
>> +
>> +struct isp4fw_isp_pipe_path_cfg {
>> +    u32  isp_pipe_id;    /* pipe ids for pipeline construction */
>> +};
>> +
>> +struct isp4fw_isp_stream_cfg {
>> +    /* Isp mipi path */
>> +    struct isp4fw_mipi_pipe_path_cfg mipi_pipe_path_cfg;
>> +    /* Isp pipe path */
>> +    struct isp4fw_isp_pipe_path_cfg  isp_pipe_path_cfg;
>> +    /* enable TNR */
>> +    u32 b_enable_tnr;
>> +    /* number of frame rta per-processing,
>> +     * set to 0 to use fw default value
>> +     */
>> +    u32 rta_frames_per_proc;
>> +};
>> +
>> +struct isp4fw_image_prop {
>> +    enum isp4fw_image_format image_format;    /* Image format */
>> +    u32 width;                /* Width */
>> +    u32 height;                /* Height */
>> +    u32 luma_pitch;                /* Luma pitch */
>> +    u32 chroma_pitch;            /* Chrom pitch */
>> +    enum isp4fw_yuv_range yuv_range;        /* YUV value range */
>> +};
>> +
>> +struct isp4fw_buffer {
>> +    /* A check num for debug usage, host need to */
>> +    /* set the buf_tags to different number */
>> +    u32 buf_tags;
>> +    union {
>> +        u32 value;
>> +        struct {
>> +            u32 space : 16;
>> +            u32 vmid  : 16;
>> +        } bit;
>> +    } vmid_space;
>> +    u32 buf_base_a_lo;        /* Low address of buffer A */
>> +    u32 buf_base_a_hi;        /* High address of buffer A */
>> +    u32 buf_size_a;            /* Buffer size of buffer A */
>> +
>> +    u32 buf_base_b_lo;        /* Low address of buffer B */
>> +    u32 buf_base_b_hi;        /* High address of buffer B */
>> +    u32 buf_size_b;            /* Buffer size of buffer B */
>> +
>> +    u32 buf_base_c_lo;        /* Low address of buffer C */
>> +    u32 buf_base_c_hi;        /* High address of buffer C */
>> +    u32 buf_size_c;            /* Buffer size of buffer C */
>> +};
>> +
>> +struct isp4fw_buffer_meta_info {
>> +    u32 enabled;                    /* enabled flag */
>> +    enum isp4fw_buffer_status status;        /* BufferStatus */
>> +    struct isp4fw_error_code err;            /* err code */
>> +    enum isp4fw_buffer_source source;        /* BufferSource */
>> +    struct isp4fw_image_prop image_prop;        /* image_prop */
>> +    struct isp4fw_buffer buffer;            /* buffer */
>> +};
>> +
>> +struct isp4fw_meta_info {
>> +    u32 poc;                /* frame id */
>> +    u32 fc_id;                /* frame ctl id */
>> +    u32 time_stamp_lo;            /* time_stamp_lo */
>> +    u32 time_stamp_hi;            /* time_stamp_hi */
>> +    struct isp4fw_buffer_meta_info preview;    /* preview 
>> BufferMetaInfo */
>> +};
>> +
>> +struct isp4fw_cmd_send_buffer {
>> +    enum isp4fw_buffer_type buffer_type;    /* buffer Type */
>> +    struct isp4fw_buffer buffer;        /* buffer info */
>> +};
>> +
>> +struct isp4fw_cmd_set_out_ch_prop {
>> +    enum isp4fw_pipe_out_ch ch;    /* ISP pipe out channel */
>> +    struct isp4fw_image_prop image_prop;    /* image property */
>> +};
>> +
>> +struct isp4fw_cmd_enable_out_ch {
>> +    enum isp4fw_pipe_out_ch ch;    /* ISP pipe out channel */
>> +    u32 is_enable;            /* If enable channel or not */
>> +};
>> +
>> +struct isp4fw_cmd_set_stream_cfg {
>> +    struct isp4fw_isp_stream_cfg stream_cfg; /* stream path config */
>> +};
>> +
>> +#endif
>> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/ 
>> drivers/media/platform/amd/isp4/isp4_interface.c
>> new file mode 100644
>> index 000000000000..0e1eb22a0de5
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_interface.c
>> @@ -0,0 +1,1052 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/mutex.h>
>> +
>> +#include "amdgpu_object.h"
>> +
>> +#include "isp4_fw_cmd_resp.h"
>> +#include "isp4_hw.h"
>> +#include "isp4_hw_reg.h"
>> +#include "isp4_interface.h"
>> +
>> +#define ISP4IF_FW_RESP_RB_IRQ_EN_MASK \
>> +    (ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK |  \
>> +     ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK | \
>> +     ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK | \
>> +     ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK)
>> +
>> +struct isp4if_rb_config {
>> +    const char *name;
>> +    u32 index;
>> +    u32 reg_rptr;
>> +    u32 reg_wptr;
>> +    u32 reg_base_lo;
>> +    u32 reg_base_hi;
>> +    u32 reg_size;
>> +    u32 val_size;
>> +    u64 base_mc_addr;
>> +    void *base_sys_addr;
>> +};
>> +
>> +/* FW cmd ring buffer configuration */
>> +static struct isp4if_rb_config
>> +    isp4if_cmd_rb_config[ISP4IF_STREAM_ID_MAX] = {
>> +    {
>> +        .name = "CMD_RB_GBL0",
>> +        .index = 3,
>> +        .reg_rptr = ISP_RB_RPTR4,
>> +        .reg_wptr = ISP_RB_WPTR4,
>> +        .reg_base_lo = ISP_RB_BASE_LO4,
>> +        .reg_base_hi = ISP_RB_BASE_HI4,
>> +        .reg_size = ISP_RB_SIZE4,
>> +    },
>> +    {
>> +        .name = "CMD_RB_STR1",
>> +        .index = 0,
>> +        .reg_rptr = ISP_RB_RPTR1,
>> +        .reg_wptr = ISP_RB_WPTR1,
>> +        .reg_base_lo = ISP_RB_BASE_LO1,
>> +        .reg_base_hi = ISP_RB_BASE_HI1,
>> +        .reg_size = ISP_RB_SIZE1,
>> +    },
>> +    {
>> +        .name = "CMD_RB_STR2",
>> +        .index = 1,
>> +        .reg_rptr = ISP_RB_RPTR2,
>> +        .reg_wptr = ISP_RB_WPTR2,
>> +        .reg_base_lo = ISP_RB_BASE_LO2,
>> +        .reg_base_hi = ISP_RB_BASE_HI2,
>> +        .reg_size = ISP_RB_SIZE2,
>> +    },
>> +    {
>> +        .name = "CMD_RB_STR3",
>> +        .index = 2,
>> +        .reg_rptr = ISP_RB_RPTR3,
>> +        .reg_wptr = ISP_RB_WPTR3,
>> +        .reg_base_lo = ISP_RB_BASE_LO3,
>> +        .reg_base_hi = ISP_RB_BASE_HI3,
>> +        .reg_size = ISP_RB_SIZE3,
>> +    },
>> +};
>> +
>> +/* FW resp ring buffer configuration */
>> +static struct isp4if_rb_config
>> +    isp4if_resp_rb_config[ISP4IF_STREAM_ID_MAX] = {
>> +    {
>> +        .name = "RES_RB_GBL0",
>> +        .index = 3,
>> +        .reg_rptr = ISP_RB_RPTR12,
>> +        .reg_wptr = ISP_RB_WPTR12,
>> +        .reg_base_lo = ISP_RB_BASE_LO12,
>> +        .reg_base_hi = ISP_RB_BASE_HI12,
>> +        .reg_size = ISP_RB_SIZE12,
>> +    },
>> +    {
>> +        .name = "RES_RB_STR1",
>> +        .index = 0,
>> +        .reg_rptr = ISP_RB_RPTR9,
>> +        .reg_wptr = ISP_RB_WPTR9,
>> +        .reg_base_lo = ISP_RB_BASE_LO9,
>> +        .reg_base_hi = ISP_RB_BASE_HI9,
>> +        .reg_size = ISP_RB_SIZE9,
>> +    },
>> +    {
>> +        .name = "RES_RB_STR2",
>> +        .index = 1,
>> +        .reg_rptr = ISP_RB_RPTR10,
>> +        .reg_wptr = ISP_RB_WPTR10,
>> +        .reg_base_lo = ISP_RB_BASE_LO10,
>> +        .reg_base_hi = ISP_RB_BASE_HI10,
>> +        .reg_size = ISP_RB_SIZE10,
>> +    },
>> +    {
>> +        .name = "RES_RB_STR3",
>> +        .index = 2,
>> +        .reg_rptr = ISP_RB_RPTR11,
>> +        .reg_wptr = ISP_RB_WPTR11,
>> +        .reg_base_lo = ISP_RB_BASE_LO11,
>> +        .reg_base_hi = ISP_RB_BASE_HI11,
>> +        .reg_size = ISP_RB_SIZE11,
>> +    },
>> +};
>> +
>> +/* FW log ring buffer configuration */
>> +static struct isp4if_rb_config isp4if_log_rb_config = {
>> +    .name = "LOG_RB",
>> +    .index = 0,
>> +    .reg_rptr = ISP_LOG_RB_RPTR0,
>> +    .reg_wptr = ISP_LOG_RB_WPTR0,
>> +    .reg_base_lo = ISP_LOG_RB_BASE_LO0,
>> +    .reg_base_hi = ISP_LOG_RB_BASE_HI0,
>> +    .reg_size = ISP_LOG_RB_SIZE0,
>> +};
>> +
>> +static struct isp4if_gpu_mem_info *isp4if_gpu_mem_alloc(struct 
>> isp4_interface
>> +                            *ispif,
>> +                            u32 mem_size)
>> +{
>> +    struct isp4if_gpu_mem_info *mem_info;
>> +    struct amdgpu_bo *bo = NULL;
>> +    struct amdgpu_device *adev;
>> +    struct device *dev;
>> +
>> +    void *cpu_ptr;
>> +    u64 gpu_addr;
>> +    u32 ret;
>> +
>> +    dev = ispif->dev;
>> +
>> +    if (!mem_size)
>> +        return NULL;
>> +
>> +    mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
>> +    if (!mem_info)
>> +        return NULL;
>> +
>> +    adev = (struct amdgpu_device *)ispif->adev;
>> +    mem_info->mem_size = mem_size;
>> +    mem_info->mem_align = ISP4IF_ISP_MC_ADDR_ALIGN;
>> +    mem_info->mem_domain = AMDGPU_GEM_DOMAIN_GTT;
>> +
>> +    ret = amdgpu_bo_create_kernel(adev,
>> +                      mem_info->mem_size,
>> +                      mem_info->mem_align,
>> +                      mem_info->mem_domain,
>> +                      &bo,
>> +                      &gpu_addr,
>> +                      &cpu_ptr);
> 
> IMO this is begging for an extra helper that has a true exported symbol 
> and kernel-wide header for use rather than hacking around the includes 
> for drm headers.
> 
> The kernel-wide header can describe the data types exchanged, so there 
> wouldn't be a need to have all the amdgpu headers included.

Many thanks, will double check. Seems amdgpu_bo_create_kernel is a true 
exported symbol from amdgpu. If there is kernel-wide header and 
functions to achieve the same, that'll be great. Any suggestions for this?

> 
>> +
>> +    if (!cpu_ptr || ret) {
>> +        dev_err(dev, "gpuvm buffer alloc fail, size %u\n", mem_size);
>> +        kfree(mem_info);
>> +        return NULL;
>> +    }
>> +
>> +    mem_info->sys_addr = cpu_ptr;
>> +    mem_info->gpu_mc_addr = gpu_addr;
>> +    mem_info->mem_handle = (void *)bo;
>> +
>> +    return mem_info;
>> +}
>> +
>> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
>> +                   struct isp4if_gpu_mem_info *mem_info)
>> +{
>> +    struct device *dev = ispif->dev;
>> +    struct amdgpu_bo *bo;
>> +
>> +    if (!mem_info) {
>> +        dev_err(dev, "invalid mem_info\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    bo = (struct amdgpu_bo *)mem_info->mem_handle;
>> +
>> +    amdgpu_bo_free_kernel(&bo, &mem_info->gpu_mc_addr, &mem_info- 
>> >sys_addr);
> 
> This also I think needs another helper
Many thx, same comments as above>
>> +
>> +    kfree(mem_info);
>> +
>> +    return 0;
>> +}
>> +
>> +static int isp4if_dealloc_fw_gpumem(struct isp4_interface *ispif)
>> +{
>> +    int i;
>> +
>> +    if (ispif->fw_mem_pool) {
>> +        isp4if_gpu_mem_free(ispif, ispif->fw_mem_pool);
>> +        ispif->fw_mem_pool = NULL;
>> +    }
>> +
>> +    if (ispif->fw_cmd_resp_buf) {
>> +        isp4if_gpu_mem_free(ispif, ispif->fw_cmd_resp_buf);
>> +        ispif->fw_cmd_resp_buf = NULL;
>> +    }
>> +
>> +    if (ispif->fw_log_buf) {
>> +        isp4if_gpu_mem_free(ispif, ispif->fw_log_buf);
>> +        ispif->fw_log_buf = NULL;
>> +    }
>> +
>> +    for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
>> +        if (ispif->metainfo_buf_pool[i]) {
>> +            isp4if_gpu_mem_free(ispif, ispif->metainfo_buf_pool[i]);
>> +            ispif->metainfo_buf_pool[i] = NULL;
>> +        }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif)
>> +{
>> +    struct device *dev = ispif->dev;
>> +    int i;
>> +
>> +    ispif->fw_mem_pool = isp4if_gpu_mem_alloc(ispif, 
>> FW_MEMORY_POOL_SIZE);
>> +    if (!ispif->fw_mem_pool)
>> +        goto error_no_memory;
>> +
>> +    ispif->fw_cmd_resp_buf =
>> +        isp4if_gpu_mem_alloc(ispif, ISP4IF_RB_PMBMAP_MEM_SIZE);
>> +    if (!ispif->fw_cmd_resp_buf)
>> +        goto error_no_memory;
>> +
>> +    ispif->fw_log_buf =
>> +        isp4if_gpu_mem_alloc(ispif, ISP4IF_FW_LOG_RINGBUF_SIZE);
>> +    if (!ispif->fw_log_buf)
>> +        goto error_no_memory;
>> +
>> +    for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
>> +        ispif->metainfo_buf_pool[i] =
>> +            isp4if_gpu_mem_alloc(ispif,
>> +                         ISP4IF_META_INFO_BUF_SIZE);
>> +        if (!ispif->metainfo_buf_pool[i])
>> +            goto error_no_memory;
>> +    }
>> +
>> +    return 0;
>> +
>> +error_no_memory:
>> +    dev_err(dev, "failed to allocate gpu memory");
> 
> I don't think the error message is necessary, checkpatch usually 
> complains about this.
Many thanks, actually checkpatch doesn't say anything about it.
Sure we can remove it if you think it better.

> 
>> +    return -ENOMEM;
>> +}
>> +
>> +static u32 isp4if_compute_check_sum(u8 *buf, u32 buf_size)
>> +{
>> +    u32 checksum = 0;
>> +    u8 *surplus_ptr;
>> +    u32 *buffer;
>> +    u32 i;
>> +
>> +    buffer = (u32 *)buf;
>> +    for (i = 0; i < buf_size / sizeof(u32); i++)
>> +        checksum += buffer[i];
>> +
>> +    surplus_ptr = (u8 *)&buffer[i];
>> +    /* add surplus data crc checksum */
>> +    for (i = 0; i < buf_size % sizeof(u32); i++)
>> +        checksum += surplus_ptr[i];
>> +
>> +    return checksum;
>> +}
>> +
>> +void isp4if_clear_cmdq(struct isp4_interface *ispif)
>> +{
>> +    struct isp4if_cmd_element *buf_node = NULL;
>> +    struct isp4if_cmd_element *tmp_node = NULL;
>> +
>> +    guard(mutex)(&ispif->cmdq_mutex);
>> +
>> +    list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
>> +        list_del(&buf_node->list);
>> +        kfree(buf_node);
>> +    }
>> +}
>> +
>> +static bool isp4if_is_cmdq_rb_full(struct isp4_interface *ispif,
>> +                   enum isp4if_stream_id cmd_buf_idx)
>> +{
>> +    struct isp4if_rb_config *rb_config;
>> +    u32 rd_ptr, wr_ptr;
>> +    u32 new_wr_ptr;
>> +    u32 rreg;
>> +    u32 wreg;
>> +    u32 len;
>> +
>> +    rb_config = &isp4if_cmd_rb_config[cmd_buf_idx];
>> +    rreg = rb_config->reg_rptr;
>> +    wreg = rb_config->reg_wptr;
>> +    len = rb_config->val_size;
>> +
>> +    rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
>> +    wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
>> +
>> +    new_wr_ptr = wr_ptr + sizeof(struct isp4fw_cmd);
>> +
>> +    if (wr_ptr >= rd_ptr) {
>> +        if (new_wr_ptr < len) {
>> +            return false;
>> +        } else if (new_wr_ptr == len) {
>> +            if (rd_ptr == 0)
>> +                return true;
>> +
>> +            return false;
>> +        }
>> +
>> +        new_wr_ptr -= len;
>> +        if (new_wr_ptr < rd_ptr)
>> +            return false;
>> +
>> +        return true;
>> +    }
>> +
>> +    if (new_wr_ptr < rd_ptr)
>> +        return false;
>> +
>> +    return true;
>> +}
>> +
>> +static struct isp4if_cmd_element *
>> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
>> +             struct isp4if_cmd_element *cmd_ele)
>> +{
>> +    struct isp4if_cmd_element *copy_command = NULL;
>> +
>> +    copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
>> +    if (!copy_command)
>> +        return NULL;
>> +
>> +    memcpy(copy_command, cmd_ele, sizeof(*copy_command));
>> +
>> +    guard(mutex)(&ispif->cmdq_mutex);
>> +
>> +    list_add_tail(&copy_command->list, &ispif->cmdq);
>> +
>> +    return copy_command;
>> +}
>> +
>> +struct isp4if_cmd_element *
>> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
>> +            u32 seq_num,
>> +            u32 cmd_id)
>> +{
>> +    struct isp4if_cmd_element *buf_node = NULL;
>> +    struct isp4if_cmd_element *tmp_node = NULL;
>> +
>> +    guard(mutex)(&ispif->cmdq_mutex);
>> +
>> +    list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
>> +        if (buf_node->seq_num == seq_num &&
>> +            buf_node->cmd_id == cmd_id) {
>> +            list_del(&buf_node->list);
>> +            return buf_node;
>> +        }
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
>> +                    enum isp4if_stream_id stream,
>> +                    struct isp4fw_cmd *cmd)
>> +{
>> +    struct isp4if_rb_config *rb_config;
>> +    struct device *dev = ispif->dev;
>> +    u64 mem_addr;
>> +    u64 mem_sys;
>> +    u32 wr_ptr;
>> +    u32 rd_ptr;
>> +    u32 rreg;
>> +    u32 wreg;
>> +    u32 len;
>> +
>> +    rb_config = &isp4if_cmd_rb_config[stream];
>> +    rreg = rb_config->reg_rptr;
>> +    wreg = rb_config->reg_wptr;
>> +    mem_sys = (u64)rb_config->base_sys_addr;
>> +    mem_addr = rb_config->base_mc_addr;
>> +    len = rb_config->val_size;
>> +
>> +    if (isp4if_is_cmdq_rb_full(ispif, stream)) {
>> +        dev_err(dev, "fail no cmdslot (%d)\n", stream);
>> +        return -EINVAL;
>> +    }
>> +
>> +    wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
>> +    rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
>> +
>> +    if (rd_ptr > len) {
>> +        dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
>> +            stream, rd_ptr, len, wr_ptr);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (wr_ptr > len) {
>> +        dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
>> +            stream, wr_ptr, len, rd_ptr);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (wr_ptr < rd_ptr) {
>> +        mem_addr += wr_ptr;
>> +
>> +        memcpy((u8 *)(mem_sys + wr_ptr),
>> +               (u8 *)cmd, sizeof(struct isp4fw_cmd));
>> +    } else {
>> +        if ((len - wr_ptr) >= (sizeof(struct isp4fw_cmd))) {
>> +            mem_addr += wr_ptr;
>> +
>> +            memcpy((u8 *)(mem_sys + wr_ptr),
>> +                   (u8 *)cmd, sizeof(struct isp4fw_cmd));
>> +        } else {
>> +            u32 size;
>> +            u8 *src;
>> +
>> +            src = (u8 *)cmd;
>> +            size = len - wr_ptr;
>> +
>> +            memcpy((u8 *)(mem_sys + wr_ptr), src, size);
>> +
>> +            src += size;
>> +            size = sizeof(struct isp4fw_cmd) - size;
>> +            memcpy((u8 *)(mem_sys), src, size);
>> +        }
>> +    }
>> +
>> +    wr_ptr += sizeof(struct isp4fw_cmd);
>> +    if (wr_ptr >= len)
>> +        wr_ptr -= len;
>> +
>> +    isp4hw_wreg(ispif->mmio, wreg, wr_ptr);
>> +
>> +    return 0;
>> +}
>> +
>> +static inline enum isp4if_stream_id isp4if_get_fw_stream(u32 cmd_id)
>> +{
>> +    return ISP4IF_STREAM_ID_1;
>> +}
>> +
>> +static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
>> +                  u32 cmd_id,
>> +                  void *package,
>> +                  u32 package_size,
>> +                  wait_queue_head_t *wq,
>> +                  u32 *wq_cond,
>> +                  u32 *seq)
>> +{
>> +    enum isp4if_stream_id stream = isp4if_get_fw_stream(cmd_id);
>> +    struct isp4if_cmd_element command_element = { 0 };
>> +    struct isp4if_gpu_mem_info *gpu_mem = NULL;
>> +    struct isp4if_cmd_element *cmd_ele = NULL;
>> +    struct isp4if_rb_config *rb_config;
>> +    struct device *dev = ispif->dev;
>> +    struct isp4fw_cmd cmd = {0};
>> +    u64 package_base = 0;
>> +    u32 sleep_count;
>> +    u32 seq_num;
>> +    u32 rreg;
>> +    u32 wreg;
>> +    int ret;
>> +
>> +    if (package_size > sizeof(cmd.cmd_param)) {
>> +        dev_err(dev, "fail pkgsize(%u)>%lu cmd:0x%x,stream %d\n",
>> +            package_size, sizeof(cmd.cmd_param), cmd_id, stream);
>> +        return -EINVAL;
>> +    }
>> +
>> +    sleep_count = 0;
>> +
>> +    rb_config = &isp4if_resp_rb_config[stream];
>> +    rreg = rb_config->reg_rptr;
>> +    wreg = rb_config->reg_wptr;
>> +
>> +    guard(mutex)(&ispif->isp4if_mutex);
>> +
>> +    while (1) {
>> +        if (isp4if_is_cmdq_rb_full(ispif, stream)) {
>> +            u32 rd_ptr, wr_ptr;
>> +
>> +            if (sleep_count < ISP4IF_MAX_SLEEP_COUNT) {
>> +                msleep(ISP4IF_MAX_SLEEP_TIME);
>> +                sleep_count++;
>> +                continue;
>> +            }
>> +            rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
>> +            wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
>> +            dev_err(dev, "fail to get cmdq slot,stream (%d), rd %u, 
>> wr %u\n",
>> +                stream, rd_ptr, wr_ptr);
>> +            return -ETIMEDOUT;
>> +        }
>> +        break;
>> +    }
>> +
>> +    cmd.cmd_id = cmd_id;
>> +    switch (stream) {
>> +    case ISP4IF_STREAM_ID_GLOBAL:
>> +        cmd.cmd_stream_id = (u16)STREAM_ID_INVALID;
>> +        break;
>> +    case ISP4IF_STREAM_ID_1:
>> +        cmd.cmd_stream_id = STREAM_ID_1;
>> +        break;
>> +    default:
>> +        dev_err(dev, "fail bad stream id %d\n", stream);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (package && package_size)
>> +        memcpy(cmd.cmd_param, package, package_size);
>> +
>> +    seq_num = ispif->host2fw_seq_num++;
>> +    cmd.cmd_seq_num = seq_num;
>> +    cmd.cmd_check_sum =
>> +        isp4if_compute_check_sum((u8 *)&cmd, sizeof(cmd) - 4);
>> +
>> +    if (seq)
>> +        *seq = seq_num;
>> +    command_element.seq_num = seq_num;
>> +    command_element.cmd_id = cmd_id;
>> +    command_element.mc_addr = package_base;
>> +    command_element.wq = wq;
>> +    command_element.wq_cond = wq_cond;
>> +    command_element.gpu_pkg = gpu_mem;
>> +    command_element.stream = stream;
>> +    /* only append the fw cmd to queue when its response needs to be
>> +     * waited for, currently there are only two such commands,
>> +     * disable channel and stop stream which are only sent after close
>> +     * camera
>> +     */
>> +    if (wq && wq_cond) {
>> +        cmd_ele = isp4if_append_cmd_2_cmdq(ispif, &command_element);
>> +        if (!cmd_ele) {
>> +            dev_err(dev, "fail for isp_append_cmd_2_cmdq\n");
>> +            return -ENOMEM;
>> +        }
>> +    }
>> +
>> +    ret = isp4if_insert_isp_fw_cmd(ispif, stream, &cmd);
>> +    if (ret) {
>> +        dev_err(dev, "fail for insert_isp_fw_cmd camId (0x%08x)\n",
>> +            cmd_id);
>> +        if (cmd_ele) {
>> +            isp4if_rm_cmd_from_cmdq(ispif, cmd_ele->seq_num,
>> +                        cmd_ele->cmd_id);
>> +            kfree(cmd_ele);
>> +        }
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +static int isp4if_send_buffer(struct isp4_interface *ispif,
>> +                  struct isp4if_img_buf_info *buf_info)
>> +{
>> +    struct isp4fw_cmd_send_buffer cmd;
>> +
>> +    memset(&cmd, 0, sizeof(cmd));
>> +    cmd.buffer_type = BUFFER_TYPE_PREVIEW;
>> +    cmd.buffer.vmid_space.bit.vmid = 0;
>> +    cmd.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA;
>> +    isp4if_split_addr64(buf_info->planes[0].mc_addr,
>> +                &cmd.buffer.buf_base_a_lo,
>> +                &cmd.buffer.buf_base_a_hi);
>> +    cmd.buffer.buf_size_a = buf_info->planes[0].len;
>> +
>> +    isp4if_split_addr64(buf_info->planes[1].mc_addr,
>> +                &cmd.buffer.buf_base_b_lo,
>> +                &cmd.buffer.buf_base_b_hi);
>> +    cmd.buffer.buf_size_b = buf_info->planes[1].len;
>> +
>> +    isp4if_split_addr64(buf_info->planes[2].mc_addr,
>> +                &cmd.buffer.buf_base_c_lo,
>> +                &cmd.buffer.buf_base_c_hi);
>> +    cmd.buffer.buf_size_c = buf_info->planes[2].len;
>> +
>> +    return isp4if_send_fw_cmd(ispif, CMD_ID_SEND_BUFFER, &cmd,
>> +                  sizeof(cmd), NULL, NULL, NULL);
>> +}
>> +
>> +static void isp4if_init_rb_config(struct isp4_interface *ispif,
>> +                  struct isp4if_rb_config *rb_config)
>> +{
>> +    u32 lo;
>> +    u32 hi;
>> +
>> +    isp4if_split_addr64(rb_config->base_mc_addr, &lo, &hi);
>> +
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +            rb_config->reg_rptr, 0x0);
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +            rb_config->reg_wptr, 0x0);
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +            rb_config->reg_base_lo, lo);
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +            rb_config->reg_base_hi, hi);
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +            rb_config->reg_size, rb_config->val_size);
>> +}
>> +
>> +static int isp4if_fw_init(struct isp4_interface *ispif)
>> +{
>> +    struct isp4if_rb_config *rb_config;
>> +    u32 offset;
>> +    int i;
>> +
>> +    /* initialize CMD_RB streams */
>> +    for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
>> +        rb_config = (isp4if_cmd_rb_config + i);
>> +        offset = ispif->aligned_rb_chunk_size *
>> +             (rb_config->index + ispif->cmd_rb_base_index);
>> +
>> +        rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
>> +        rb_config->base_sys_addr =
>> +            (u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
>> +        rb_config->base_mc_addr =
>> +            ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
>> +
>> +        isp4if_init_rb_config(ispif, rb_config);
>> +    }
>> +
>> +    /* initialize RESP_RB streams */
>> +    for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
>> +        rb_config = (isp4if_resp_rb_config + i);
>> +        offset = ispif->aligned_rb_chunk_size *
>> +             (rb_config->index + ispif->resp_rb_base_index);
>> +
>> +        rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
>> +        rb_config->base_sys_addr =
>> +            (u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
>> +        rb_config->base_mc_addr =
>> +            ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
>> +
>> +        isp4if_init_rb_config(ispif, rb_config);
>> +    }
>> +
>> +    /* initialize LOG_RB stream */
>> +    rb_config = &isp4if_log_rb_config;
>> +    rb_config->val_size = ISP4IF_FW_LOG_RINGBUF_SIZE;
>> +    rb_config->base_mc_addr = ispif->fw_log_buf->gpu_mc_addr;
>> +    rb_config->base_sys_addr = ispif->fw_log_buf->sys_addr;
>> +
>> +    isp4if_init_rb_config(ispif, rb_config);
>> +
>> +    return 0;
>> +}
>> +
>> +static int isp4if_wait_fw_ready(struct isp4_interface *ispif,
>> +                u32 isp_status_addr)
>> +{
>> +    struct device *dev = ispif->dev;
>> +    u32 fw_ready_timeout;
>> +    u32 timeout_ms = 100;
>> +    u32 interval_ms = 1;
>> +    u32 timeout = 0;
>> +    u32 reg_val;
>> +
>> +    fw_ready_timeout = timeout_ms / interval_ms;
>> +
>> +    /* wait for FW initialize done! */
>> +    while (timeout < fw_ready_timeout) {
>> +        reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif),
>> +                      isp_status_addr);
>> +        if (reg_val & ISP_STATUS__CCPU_REPORT_MASK)
>> +            return 0;
>> +
>> +        msleep(interval_ms);
>> +        timeout++;
>> +    }
>> +
>> +    dev_err(dev, "ISP CCPU FW boot failed\n");
>> +
>> +    return -ETIME;
>> +}
>> +
>> +static void isp4if_enable_ccpu(struct isp4_interface *ispif)
>> +{
>> +    u32 reg_val;
>> +
>> +    reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
>> +    reg_val &= (~ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK);
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
>> +
>> +    usleep_range(100, 150);
>> +
>> +    reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
>> +    reg_val &= (~ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK);
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
>> +}
>> +
>> +static void isp4if_disable_ccpu(struct isp4_interface *ispif)
>> +{
>> +    u32 reg_val;
>> +
>> +    reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
>> +    reg_val |= ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK;
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
>> +
>> +    usleep_range(100, 150);
>> +
>> +    reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
>> +    reg_val |= ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK;
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
>> +}
>> +
>> +static int isp4if_fw_boot(struct isp4_interface *ispif)
>> +{
>> +    struct device *dev = ispif->dev;
>> +
>> +    if (ispif->status != ISP4IF_STATUS_PWR_ON) {
>> +        dev_err(dev, "invalid isp power status %d\n", ispif->status);
>> +        return -EINVAL;
>> +    }
>> +
>> +    isp4if_disable_ccpu(ispif);
>> +
>> +    isp4if_fw_init(ispif);
>> +
>> +    /* clear ccpu status */
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_STATUS, 0x0);
>> +
>> +    isp4if_enable_ccpu(ispif);
>> +
>> +    if (isp4if_wait_fw_ready(ispif, ISP_STATUS)) {
>> +        isp4if_disable_ccpu(ispif);
>> +        return -EINVAL;
>> +    }
>> +
>> +    /* enable interrupts */
>> +    isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SYS_INT0_EN,
>> +            ISP4IF_FW_RESP_RB_IRQ_EN_MASK);
>> +
>> +    ispif->status = ISP4IF_STATUS_FW_RUNNING;
>> +
>> +    dev_dbg(dev, "ISP CCPU FW boot success\n");
>> +
>> +    return 0;
>> +}
>> +
>> +int isp4if_f2h_resp(struct isp4_interface *ispif,
>> +            enum isp4if_stream_id stream,
>> +            void *resp)
>> +{
>> +    struct isp4fw_resp *response = resp;
>> +    struct isp4if_rb_config *rb_config;
>> +    struct device *dev = ispif->dev;
>> +    u32 rd_ptr_dbg;
>> +    u32 wr_ptr_dbg;
>> +    void *mem_sys;
>> +    u64 mem_addr;
>> +    u32 checksum;
>> +    u32 rd_ptr;
>> +    u32 wr_ptr;
>> +    u32 rreg;
>> +    u32 wreg;
>> +    u32 len;
>> +
>> +    rb_config = &isp4if_resp_rb_config[stream];
>> +    rreg = rb_config->reg_rptr;
>> +    wreg = rb_config->reg_wptr;
>> +    mem_sys = rb_config->base_sys_addr;
>> +    mem_addr = rb_config->base_mc_addr;
>> +    len = rb_config->val_size;
>> +
>> +    rd_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), rreg);
>> +    wr_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), wreg);
>> +    rd_ptr_dbg = rd_ptr;
>> +    wr_ptr_dbg = wr_ptr;
>> +
>> +    if (rd_ptr > len) {
>> +        dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
>> +            stream, rd_ptr, len, wr_ptr);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (wr_ptr > len) {
>> +        dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
>> +            stream, wr_ptr, len, rd_ptr);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (rd_ptr < wr_ptr) {
>> +        if ((wr_ptr - rd_ptr) >= (sizeof(struct isp4fw_resp))) {
>> +            memcpy((u8 *)response, (u8 *)mem_sys + rd_ptr,
>> +                   sizeof(struct isp4fw_resp));
>> +
>> +            rd_ptr += sizeof(struct isp4fw_resp);
>> +            if (rd_ptr < len) {
>> +                isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +                        rreg, rd_ptr);
>> +            } else {
>> +                dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
>> +                    stream, rd_ptr, len, wr_ptr);
>> +                return -EINVAL;
>> +            }
>> +
>> +        } else {
>> +            dev_err(dev, "sth wrong with wptr and rptr\n");
>> +            return -EINVAL;
>> +        }
>> +    } else if (rd_ptr > wr_ptr) {
>> +        u32 size;
>> +        u8 *dst;
>> +
>> +        dst = (u8 *)response;
>> +
>> +        size = len - rd_ptr;
>> +        if (size > sizeof(struct isp4fw_resp)) {
>> +            mem_addr += rd_ptr;
>> +            memcpy((u8 *)response,
>> +                   (u8 *)(mem_sys) + rd_ptr,
>> +                   sizeof(struct isp4fw_resp));
>> +            rd_ptr += sizeof(struct isp4fw_resp);
>> +            if (rd_ptr < len) {
>> +                isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +                        rreg, rd_ptr);
>> +            } else {
>> +                dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
>> +                    stream, rd_ptr, len, wr_ptr);
>> +                return -EINVAL;
>> +            }
>> +
>> +        } else {
>> +            if ((size + wr_ptr) < (sizeof(struct isp4fw_resp))) {
>> +                dev_err(dev, "sth wrong with wptr and rptr1\n");
>> +                return -EINVAL;
>> +            }
>> +
>> +            memcpy(dst, (u8 *)(mem_sys) + rd_ptr, size);
>> +
>> +            dst += size;
>> +            size = sizeof(struct isp4fw_resp) - size;
>> +            if (size)
>> +                memcpy(dst, (u8 *)(mem_sys), size);
>> +            rd_ptr = size;
>> +            if (rd_ptr < len) {
>> +                isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +                        rreg, rd_ptr);
>> +            } else {
>> +                dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
>> +                    stream, rd_ptr, len, wr_ptr);
>> +                return -EINVAL;
>> +            }
>> +        }
>> +    } else {
>> +        return -ETIME;
>> +    }
>> +
>> +    checksum = isp4if_compute_check_sum((u8 *)response,
>> +                        (sizeof(struct isp4fw_resp) - 4));
>> +
>> +    if (checksum != response->resp_check_sum) {
>> +        dev_err(dev, "resp checksum 0x%x,should 0x%x,rptr %u,wptr %u\n",
>> +            checksum, response->resp_check_sum,
>> +            rd_ptr_dbg, wr_ptr_dbg);
>> +
>> +        dev_err(dev, "(%u), seqNo %u, resp_id (0x%x)\n",
>> +            stream,
>> +            response->resp_seq_num,
>> +            response->resp_id);
>> +
>> +        return -EINVAL;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +int isp4if_send_command(struct isp4_interface *ispif,
>> +            u32 cmd_id,
>> +            void *package,
>> +            u32 package_size)
>> +{
>> +    return isp4if_send_fw_cmd(ispif,
>> +                  cmd_id, package,
>> +                  package_size, NULL, NULL, NULL);
>> +}
>> +
>> +int isp4if_send_command_sync(struct isp4_interface *ispif,
>> +                 u32 cmd_id,
>> +                 void *package,
>> +                 u32 package_size,
>> +                 u32 timeout)
>> +{
>> +    struct device *dev = ispif->dev;
>> +    DECLARE_WAIT_QUEUE_HEAD(cmd_wq);
>> +    u32 wq_cond = 0;
>> +    int ret;
>> +    u32 seq;
>> +
>> +    ret = isp4if_send_fw_cmd(ispif,
>> +                 cmd_id, package,
>> +                 package_size, &cmd_wq, &wq_cond, &seq);
>> +
>> +    if (ret) {
>> +        dev_err(dev, "send fw cmd fail %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = wait_event_timeout(cmd_wq, wq_cond != 0,
>> +                 msecs_to_jiffies(timeout));
>> +
>> +    /* timeout occurred */
>> +    if (ret == 0) {
>> +        struct isp4if_cmd_element *ele;
>> +
>> +        ele = isp4if_rm_cmd_from_cmdq(ispif, seq, cmd_id);
>> +        kfree(ele);
>> +        return -ETIMEDOUT;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +void isp4if_clear_bufq(struct isp4_interface *ispif)
>> +{
>> +    struct isp4if_img_buf_node *buf_node = NULL;
>> +    struct isp4if_img_buf_node *tmp_node = NULL;
>> +
>> +    guard(mutex)(&ispif->bufq_mutex);
>> +
>> +    list_for_each_entry_safe(buf_node, tmp_node, &ispif->bufq,
>> +                 node) {
>> +        list_del(&buf_node->node);
>> +        kfree(buf_node);
>> +    }
>> +}
>> +
>> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node)
>> +{
>> +    kfree(buf_node);
>> +}
>> +
>> +struct isp4if_img_buf_node *
>> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info)
>> +{
>> +    struct isp4if_img_buf_node *node = NULL;
>> +
>> +    node = kmalloc(sizeof(*node), GFP_KERNEL);
>> +    if (node)
>> +        node->buf_info = *buf_info;
>> +
>> +    return node;
>> +};
>> +
>> +struct isp4if_img_buf_node *
>> +isp4if_dequeue_buffer(struct isp4_interface *ispif)
>> +{
>> +    struct isp4if_img_buf_node *buf_node = NULL;
>> +
>> +    guard(mutex)(&ispif->bufq_mutex);
>> +
>> +    buf_node = list_first_entry_or_null(&ispif->bufq,
>> +                        typeof(*buf_node),
>> +                        node);
>> +    if (buf_node)
>> +        list_del(&buf_node->node);
>> +
>> +    return buf_node;
>> +}
>> +
>> +int isp4if_queue_buffer(struct isp4_interface *ispif,
>> +            struct isp4if_img_buf_node *buf_node)
>> +{
>> +    int ret;
>> +
>> +    ret = isp4if_send_buffer(ispif, &buf_node->buf_info);
>> +    if (ret)
>> +        return ret;
>> +
>> +    guard(mutex)(&ispif->bufq_mutex);
>> +
>> +    list_add_tail(&buf_node->node, &ispif->bufq);
>> +
>> +    return 0;
>> +}
>> +
>> +int isp4if_stop(struct isp4_interface *ispif)
>> +{
>> +    isp4if_disable_ccpu(ispif);
>> +
>> +    isp4if_dealloc_fw_gpumem(ispif);
>> +
>> +    return 0;
>> +}
>> +
>> +int isp4if_start(struct isp4_interface *ispif)
>> +{
>> +    int ret;
>> +
>> +    ret = isp4if_alloc_fw_gpumem(ispif);
>> +    if (ret)
>> +        goto failed_gpumem_alloc;
>> +
>> +    ret = isp4if_fw_boot(ispif);
>> +    if (ret)
>> +        goto failed_fw_boot;
>> +
>> +    return 0;
>> +
>> +failed_gpumem_alloc:
>> +    return -ENOMEM;
>> +
>> +failed_fw_boot:
>> +    isp4if_dealloc_fw_gpumem(ispif);
>> +    return ret;
>> +}
>> +
>> +int isp4if_deinit(struct isp4_interface *ispif)
>> +{
>> +    isp4if_clear_cmdq(ispif);
>> +
>> +    isp4if_clear_bufq(ispif);
>> +
>> +    mutex_destroy(&ispif->cmdq_mutex);
>> +    mutex_destroy(&ispif->bufq_mutex);
>> +    mutex_destroy(&ispif->isp4if_mutex);
>> +
>> +    return 0;
>> +}
>> +
>> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
>> +        void *amdgpu_dev, void __iomem *isp_mmip)
>> +{
>> +    ispif->dev = dev;
>> +    ispif->adev = amdgpu_dev;
>> +    ispif->mmio = isp_mmip;
>> +
>> +    ispif->cmd_rb_base_index = 0;
>> +    ispif->resp_rb_base_index = ISP4IF_RESP_CHAN_TO_RB_OFFSET - 1;
>> +    ispif->aligned_rb_chunk_size = ISP4IF_RB_PMBMAP_MEM_CHUNK & 
>> 0xffffffc0;
>> +
>> +    mutex_init(&ispif->cmdq_mutex); /* used for cmdq access */
>> +    mutex_init(&ispif->bufq_mutex); /* used for bufq access */
>> +    mutex_init(&ispif->isp4if_mutex); /* used for commands sent to 
>> ispfw */
>> +
>> +    INIT_LIST_HEAD(&ispif->cmdq);
>> +    INIT_LIST_HEAD(&ispif->bufq);
>> +
>> +    return 0;
>> +}
>> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/ 
>> drivers/media/platform/amd/isp4/isp4_interface.h
>> new file mode 100644
>> index 000000000000..b2ca147b78b6
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_interface.h
>> @@ -0,0 +1,164 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_INTERFACE_
>> +#define _ISP4_INTERFACE_
>> +
>> +#define ISP4IF_RB_MAX (25)
>> +#define ISP4IF_RESP_CHAN_TO_RB_OFFSET (9)
>> +#define ISP4IF_RB_PMBMAP_MEM_SIZE (16 * 1024 * 1024 - 1)
>> +#define ISP4IF_RB_PMBMAP_MEM_CHUNK (ISP4IF_RB_PMBMAP_MEM_SIZE \
>> +    / (ISP4IF_RB_MAX - 1))
>> +#define ISP4IF_ISP_MC_ADDR_ALIGN (1024 * 32)
>> +#define ISP4IF_HOST2FW_COMMAND_SIZE (sizeof(struct isp4fw_cmd))
>> +#define ISP4IF_FW_CMD_BUF_COUNT 4
>> +#define ISP4IF_FW_RESP_BUF_COUNT 4
>> +#define ISP4IF_MAX_NUM_HOST2FW_COMMAND (40)
>> +#define ISP4IF_FW_CMD_BUF_SIZE (ISP4IF_MAX_NUM_HOST2FW_COMMAND \
>> +    * ISP4IF_HOST2FW_COMMAND_SIZE)
>> +#define ISP4IF_MAX_SLEEP_COUNT (10)
>> +#define ISP4IF_MAX_SLEEP_TIME (33)
>> +
>> +#define ISP4IF_META_INFO_BUF_SIZE ALIGN(sizeof(struct 
>> isp4fw_meta_info), 0x8000)
>> +#define ISP4IF_MAX_STREAM_META_BUF_COUNT 6
>> +
>> +#define ISP4IF_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
>> +
>> +#define ISP4IF_MAX_CMD_RESPONSE_BUF_SIZE (4 * 1024)
>> +
>> +#define GET_ISP4IF_REG_BASE(ispif) (((ispif))->mmio)
>> +
>> +enum isp4if_stream_id {
>> +    ISP4IF_STREAM_ID_GLOBAL = 0,
>> +    ISP4IF_STREAM_ID_1 = 1,
>> +    ISP4IF_STREAM_ID_MAX = 4
>> +};
>> +
>> +enum isp4if_status {
>> +    ISP4IF_STATUS_PWR_OFF,
>> +    ISP4IF_STATUS_PWR_ON,
>> +    ISP4IF_STATUS_FW_RUNNING,
>> +    ISP4IF_FSM_STATUS_MAX
>> +};
>> +
>> +struct isp4if_gpu_mem_info {
>> +    u32    mem_domain;
>> +    u64    mem_size;
>> +    u32    mem_align;
>> +    u64    gpu_mc_addr;
>> +    void    *sys_addr;
>> +    void    *mem_handle;
>> +};
>> +
>> +struct isp4if_img_buf_info {
>> +    struct {
>> +        void *sys_addr;
>> +        u64 mc_addr;
>> +        u32 len;
>> +    } planes[3];
>> +};
>> +
>> +struct isp4if_img_buf_node {
>> +    struct list_head node;
>> +    struct isp4if_img_buf_info buf_info;
>> +};
>> +
>> +struct isp4if_cmd_element {
>> +    struct list_head list;
>> +    u32 seq_num;
>> +    u32 cmd_id;
>> +    enum isp4if_stream_id stream;
>> +    u64 mc_addr;
>> +    wait_queue_head_t *wq;
>> +    u32 *wq_cond;
>> +    struct isp4if_gpu_mem_info *gpu_pkg;
>> +};
>> +
>> +struct isp4_interface {
>> +    struct amdgpu_device *adev;
>> +
>> +    struct device *dev;
>> +    void __iomem *mmio;
>> +
>> +    struct mutex cmdq_mutex; /* used for cmdq access */
>> +    struct mutex bufq_mutex; /* used for bufq access */
>> +    struct mutex isp4if_mutex; /* used to send fw cmd and read fw log */
>> +
>> +    struct list_head cmdq; /* commands sent to fw */
>> +    struct list_head bufq; /* buffers sent to fw */
>> +
>> +    enum isp4if_status status;
>> +    u32 host2fw_seq_num;
>> +
>> +    /* FW ring buffer configs */
>> +    u32 cmd_rb_base_index;
>> +    u32 resp_rb_base_index;
>> +    u32 aligned_rb_chunk_size;
>> +
>> +    /* ISP fw buffers */
>> +    struct isp4if_gpu_mem_info *fw_log_buf;
>> +    struct isp4if_gpu_mem_info *fw_cmd_resp_buf;
>> +    struct isp4if_gpu_mem_info *fw_mem_pool;
>> +    struct isp4if_gpu_mem_info *
>> +        metainfo_buf_pool[ISP4IF_MAX_STREAM_META_BUF_COUNT];
>> +};
>> +
>> +static inline void isp4if_split_addr64(u64 addr, u32 *lo, u32 *hi)
>> +{
>> +    if (lo)
>> +        *lo = (u32)(addr & 0xffffffff);
>> +    if (hi)
>> +        *hi = (u32)(addr >> 32);
>> +}
>> +
>> +static inline u64 isp4if_join_addr64(u32 lo, u32 hi)
>> +{
>> +    return (((u64)hi) << 32) | (u64)lo;
>> +}
>> +
>> +int isp4if_f2h_resp(struct isp4_interface *ispif,
>> +            enum isp4if_stream_id stream,
>> +            void *response);
>> +
>> +int isp4if_send_command(struct isp4_interface *ispif,
>> +            u32 cmd_id,
>> +            void *package,
>> +            u32 package_size);
>> +
>> +int isp4if_send_command_sync(struct isp4_interface *ispif,
>> +                 u32 cmd_id,
>> +                 void *package,
>> +                 u32 package_size,
>> +                 u32 timeout);
>> +
>> +struct isp4if_cmd_element *
>> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
>> +            u32 seq_num,
>> +            u32 cmd_id);
>> +
>> +void isp4if_clear_cmdq(struct isp4_interface *ispif);
>> +
>> +void isp4if_clear_bufq(struct isp4_interface *ispif);
>> +
>> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node);
>> +
>> +struct isp4if_img_buf_node *
>> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info);
>> +
>> +struct isp4if_img_buf_node *isp4if_dequeue_buffer(struct 
>> isp4_interface *ispif);
>> +
>> +int isp4if_queue_buffer(struct isp4_interface *ispif,
>> +            struct isp4if_img_buf_node *buf_node);
>> +
>> +int isp4if_stop(struct isp4_interface *ispif);
>> +
>> +int isp4if_start(struct isp4_interface *ispif);
>> +
>> +int isp4if_deinit(struct isp4_interface *ispif);
>> +
>> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
>> +        void *amdgpu_dev, void __iomem *isp_mmip);
>> +
>> +#endif
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-06-19  7:46     ` Du, Bin
@ 2025-06-19 13:00       ` Mario Limonciello
  2025-06-20  3:08         ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-06-19 13:00 UTC (permalink / raw)
  To: Du, Bin, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On 6/19/2025 2:46 AM, Du, Bin wrote:
> Many thx Mario for your comments, really helpful, will address all of 
> them in the next patch.
> Add inline for some of your comments, pls check
> 
> On 6/18/2025 11:58 PM, Mario Limonciello wrote:
>> On 6/18/2025 4:19 AM, Bin Du wrote:
>>> Amd isp4 capture is a v4l2 media device which implements media 
>>> controller
>>
>> AMD
>>
>>> interface.
>>> It has one sub-device (amd ISP4 sub-device) endpoint which can be 
>>> connected
>>
>> AMD
>>
>>> 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
>>
>> MAINTAINERS
>>
>>>
>>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>
>> Who actually developed?  If both are developers there should be a Co- 
>> developed-by tag.
>>
>>> ---
>>>   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 <bin.du@amd.com>
>>> +M:    Nirujogi Pratap <pratap.nirujogi@amd.com>
>>> +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 <Felix.Kuehling@amd.com>
>>>   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/
>>
>> Is this whole file alphabetical?  If so this is the wrong place.
>>
>>>   # 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
>>
>> I don't believe this should default 'y'.  Normally drivers need to be 
>> opt in.
>>
>>> +    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.
>>
>> 2025
>>
>>> +# 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
>>
>> As the directory is already conditional on CONFIG_AMD_ISP4 is this 
>> obj- $() needed?  Or should it really be obj-y?
>>
> Yes, it is needed, because AMD_ISP4 is trisate in Kconfig, it can be y or m

Got it, thanks for clarification.

> 
>>> +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
>>
>> Do you really need to enforce all these flags just for this driver?
>>
>> Was this just for development to avoid having to remember to call the 
>> build with W=1 or CONFIG_WERROR?
>>
> We found after patch submission, Media CI robot test will be triggered, 
> when it builds the patch it will set these flags, so adding these flags 
> to align with Media CI robot test to discover potential issue before 
> submission.

I believe you can just compile with CONFIG_WERROR and get same result, 
no?  If I'm wrong, nonetheless this should be set in your external build 
environment script not in the Makefile to be going upstream.

> 
>>> 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 <linux/pm_runtime.h>
>>> +#include <linux/vmalloc.h>
>>> +#include <media/v4l2-ioctl.h>
>>> +
>>> +#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;
>>
>> In patch 5 you change this function, including dropping the goto and 
>> label.
>>
>> So I suggest that for patch 1 you KISS:
>>
>> static irqreturn_t isp4_irq_handler(int irq, void *arg)
>> {
>>      return IRQ_HANDLED;
>> }
>>
>> Then in patch 5 add the extra conditional code and real handling.
>>
>>> +}
>>> +
>>> +/*
>>> + * amd capture module
>>> + */
>>
>> Pointless comment, no?
>>
>>> +static int isp4_capture_probe(struct platform_device *pdev)
>>> +{
>>> +    struct device *dev = &pdev->dev;
>>> +    struct isp4_device *isp_dev;
>>> +
>>
>> Why newline here?
>>
>>> +    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");
>>
>> As you have error handling in place with dev_err_probe() I think the 
>> lack of an error implies this message.  I'd say drop it.
>>
>>> +
>>> +    /* 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");
>>
>> As you have error handling in place with dev_err_probe() I think the 
>> lack of an error implies this message.  I'd say drop it.
>>
>>> +
>>> +    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");
>>
>> Probably not needed message anymore, right?
>>
>>> +}
>>> +
>>> +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 <bin.du@amd.com>");
>>> +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
>>> +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 <linux/mutex.h>
>>> +#include <media/v4l2-device.h>
>>> +#include <media/videobuf2-memops.h>
>>> +#include <media/videobuf2-vmalloc.h>
>>> +
>>> +#define ISP4_GET_ISP_REG_BASE(isp4sd) (((isp4sd))->mmio)
>>> +
>>> +struct isp4_platform_data {
>>> +    void *adev;
>>> +    void *bo;
>>> +    void *cpu_ptr;
>>
>> Will touch more on these in later patches, but I would say don't 
>> introduce them until the patch they're needed.
>>
>>> +    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 */
>>
>> /* ISP4_H */
>>
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-06-19  9:58     ` Du, Bin
@ 2025-06-19 15:11       ` Mario Limonciello
  2025-06-20  3:32         ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-06-19 15:11 UTC (permalink / raw)
  To: Du, Bin, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, Alex Deucher
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov,
	amd-gfx@lists.freedesktop.org

On 6/19/2025 4:58 AM, Du, Bin wrote:
> Thanks Mario, will fix in the next version and pls see some of my comments
> 
> On 6/19/2025 12:17 AM, Mario Limonciello wrote:
>> +Alex
>> +amd-gfx
>>
>> On 6/18/2025 4:19 AM, Bin Du wrote:
>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>>> called ccpu.
>>> The communication between ISP FW and driver is using commands and
>>> response messages sent through the ring buffer. Command buffers support
>>> either global setting that is not specific to the steam and support 
>>> stream
>>> specific parameters. Response buffers contains ISP FW notification
>>> information such as frame buffer done and command done. IRQ is used for
>>> receiving response buffer from ISP firmware, which is handled in the 
>>> main
>>> isp4 media device. ISP ccpu is booted up through the firmware loading
>>> helper function prior to stream start.
>>> Memory used for command buffer and response buffer needs to be allocated
>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>>
>>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>> ---
>>>   drivers/media/platform/amd/isp4/Makefile      |   12 +
>>>   .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
>>>   .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++++++
>>>   .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
>>>   4 files changed, 1546 insertions(+)
>>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
>>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
>>>
>>> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/ 
>>> media/ platform/amd/isp4/Makefile
>>> index 0e36201fbb30..c0166f954516 100644
>>> --- a/drivers/media/platform/amd/isp4/Makefile
>>> +++ b/drivers/media/platform/amd/isp4/Makefile
>>> @@ -5,10 +5,22 @@
>>>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>>>   amd_capture-objs := isp4.o    \
>>>               isp4_phy.o \
>>> +            isp4_interface.o \
>>>               isp4_hw.o    \
>>>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
>>> +ccflags-y += -I$(srctree)/include/drm
>>>   ccflags-y += -I$(srctree)/include
>>> +ccflags-y += -I$(srctree)/include/uapi/drm
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm
>>
>> IMO this feels like a hack and also fragile to be sharing so much 
>> across subsystems.
>>
>> Either there should be a kernel wide include/ header that can be used 
>> by both or there should be a helper exported to get just the data that 
>> is needed.
> 
> Yes, will refine to remove unnecessary ones in the next version, 
> actually isp driver needs to access function amdgpu_bo_create_kernel 
> which is exported by amdgpu and delared in amdgpu_object.h, because 
> amdgpu_object.h also includes other amd gpu header files, so have to add 
> these include path to avoid compilation error.
> It'll be greate if there is kernel wide include, any suggestion for this?
> 

Ah yeah I do see exports as of 
https://git.kernel.org/torvalds/c/ebbe34edc0a90

So based on what is in the tree right now what you did "makes sense", 
but I don't think it's "correct".  From another driver like the ISP 
driver I feel that the code should really just be something like:

#include <linux/amdgpu/isp.h>

I see a few ways forward.

1) A new set of helpers created for amdgpu that can take
opaque" data arguments (maybe the mfd device?) and return back a pointer 
to the new buffer.  Describe those new helpers in that isp.h header.

2) Manage the lifecycle of the buffers in sw_init/sw_fini of the ISP in 
amdgpu.  Store pointers to them for access in the mfd device, and let 
the ISP driver take references.  This only works if you don't need new 
buffers after the driver is loaded.

I personally prefer option 2 if it is feasible.

Alex or others might have some other ideas too.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-06-19 13:00       ` Mario Limonciello
@ 2025-06-20  3:08         ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-06-20  3:08 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Thanks Mario, just add one more comment for the CONFIG_WERROR

On 6/19/2025 9:00 PM, Mario Limonciello wrote:
> On 6/19/2025 2:46 AM, Du, Bin wrote:
>> Many thx Mario for your comments, really helpful, will address all of 
>> them in the next patch.
>> Add inline for some of your comments, pls check
>>
>> On 6/18/2025 11:58 PM, Mario Limonciello wrote:
>>> On 6/18/2025 4:19 AM, Bin Du wrote:
>>>> Amd isp4 capture is a v4l2 media device which implements media 
>>>> controller
>>>
>>> AMD
>>>
>>>> interface.
>>>> It has one sub-device (amd ISP4 sub-device) endpoint which can be 
>>>> connected
>>>
>>> AMD
>>>
>>>> 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
>>>
>>> MAINTAINERS
>>>
>>>>
>>>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>>
>>> Who actually developed?  If both are developers there should be a Co- 
>>> developed-by tag.
>>>
>>>> ---
>>>>   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 <bin.du@amd.com>
>>>> +M:    Nirujogi Pratap <pratap.nirujogi@amd.com>
>>>> +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 <Felix.Kuehling@amd.com>
>>>>   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/
>>>
>>> Is this whole file alphabetical?  If so this is the wrong place.
>>>
>>>>   # 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
>>>
>>> I don't believe this should default 'y'.  Normally drivers need to be 
>>> opt in.
>>>
>>>> +    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.
>>>
>>> 2025
>>>
>>>> +# 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
>>>
>>> As the directory is already conditional on CONFIG_AMD_ISP4 is this 
>>> obj- $() needed?  Or should it really be obj-y?
>>>
>> Yes, it is needed, because AMD_ISP4 is trisate in Kconfig, it can be y 
>> or m
> 
> Got it, thanks for clarification.
> 
>>
>>>> +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
>>>
>>> Do you really need to enforce all these flags just for this driver?
>>>
>>> Was this just for development to avoid having to remember to call the 
>>> build with W=1 or CONFIG_WERROR?
>>>
>> We found after patch submission, Media CI robot test will be 
>> triggered, when it builds the patch it will set these flags, so adding 
>> these flags to align with Media CI robot test to discover potential 
>> issue before submission.
> 
> I believe you can just compile with CONFIG_WERROR and get same result, 
> no?  If I'm wrong, nonetheless this should be set in your external build 
> environment script not in the Makefile to be going upstream.
> 
IMO, CONFIG_WERROR just treats warning as error, won't add other extra 
flags.
Sure, will remove them from the makefile and only add them to the local 
build environment.

>>
>>>> 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 <linux/pm_runtime.h>
>>>> +#include <linux/vmalloc.h>
>>>> +#include <media/v4l2-ioctl.h>
>>>> +
>>>> +#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;
>>>
>>> In patch 5 you change this function, including dropping the goto and 
>>> label.
>>>
>>> So I suggest that for patch 1 you KISS:
>>>
>>> static irqreturn_t isp4_irq_handler(int irq, void *arg)
>>> {
>>>      return IRQ_HANDLED;
>>> }
>>>
>>> Then in patch 5 add the extra conditional code and real handling.
>>>
>>>> +}
>>>> +
>>>> +/*
>>>> + * amd capture module
>>>> + */
>>>
>>> Pointless comment, no?
>>>
>>>> +static int isp4_capture_probe(struct platform_device *pdev)
>>>> +{
>>>> +    struct device *dev = &pdev->dev;
>>>> +    struct isp4_device *isp_dev;
>>>> +
>>>
>>> Why newline here?
>>>
>>>> +    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");
>>>
>>> As you have error handling in place with dev_err_probe() I think the 
>>> lack of an error implies this message.  I'd say drop it.
>>>
>>>> +
>>>> +    /* 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");
>>>
>>> As you have error handling in place with dev_err_probe() I think the 
>>> lack of an error implies this message.  I'd say drop it.
>>>
>>>> +
>>>> +    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");
>>>
>>> Probably not needed message anymore, right?
>>>
>>>> +}
>>>> +
>>>> +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 <bin.du@amd.com>");
>>>> +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
>>>> +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 <linux/mutex.h>
>>>> +#include <media/v4l2-device.h>
>>>> +#include <media/videobuf2-memops.h>
>>>> +#include <media/videobuf2-vmalloc.h>
>>>> +
>>>> +#define ISP4_GET_ISP_REG_BASE(isp4sd) (((isp4sd))->mmio)
>>>> +
>>>> +struct isp4_platform_data {
>>>> +    void *adev;
>>>> +    void *bo;
>>>> +    void *cpu_ptr;
>>>
>>> Will touch more on these in later patches, but I would say don't 
>>> introduce them until the patch they're needed.
>>>
>>>> +    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 */
>>>
>>> /* ISP4_H */
>>>
>>
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-06-19 15:11       ` Mario Limonciello
@ 2025-06-20  3:32         ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-06-20  3:32 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, Alex Deucher
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov,
	amd-gfx@lists.freedesktop.org

Thanks Mario, add more comments

On 6/19/2025 11:11 PM, Mario Limonciello wrote:
> On 6/19/2025 4:58 AM, Du, Bin wrote:
>> Thanks Mario, will fix in the next version and pls see some of my 
>> comments
>>
>> On 6/19/2025 12:17 AM, Mario Limonciello wrote:
>>> +Alex
>>> +amd-gfx
>>>
>>> On 6/18/2025 4:19 AM, Bin Du wrote:
>>>> ISP firmware controls ISP HW pipeline using dedicated embedded 
>>>> processor
>>>> called ccpu.
>>>> The communication between ISP FW and driver is using commands and
>>>> response messages sent through the ring buffer. Command buffers support
>>>> either global setting that is not specific to the steam and support 
>>>> stream
>>>> specific parameters. Response buffers contains ISP FW notification
>>>> information such as frame buffer done and command done. IRQ is used for
>>>> receiving response buffer from ISP firmware, which is handled in the 
>>>> main
>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
>>>> helper function prior to stream start.
>>>> Memory used for command buffer and response buffer needs to be 
>>>> allocated
>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>>>
>>>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>>> ---
>>>>   drivers/media/platform/amd/isp4/Makefile      |   12 +
>>>>   .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
>>>>   .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++ 
>>>> ++++
>>>>   .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
>>>>   4 files changed, 1546 insertions(+)
>>>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>>>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
>>>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
>>>>
>>>> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/ 
>>>> media/ platform/amd/isp4/Makefile
>>>> index 0e36201fbb30..c0166f954516 100644
>>>> --- a/drivers/media/platform/amd/isp4/Makefile
>>>> +++ b/drivers/media/platform/amd/isp4/Makefile
>>>> @@ -5,10 +5,22 @@
>>>>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>>>>   amd_capture-objs := isp4.o    \
>>>>               isp4_phy.o \
>>>> +            isp4_interface.o \
>>>>               isp4_hw.o    \
>>>>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
>>>> +ccflags-y += -I$(srctree)/include/drm
>>>>   ccflags-y += -I$(srctree)/include
>>>> +ccflags-y += -I$(srctree)/include/uapi/drm
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
>>>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm
>>>
>>> IMO this feels like a hack and also fragile to be sharing so much 
>>> across subsystems.
>>>
>>> Either there should be a kernel wide include/ header that can be used 
>>> by both or there should be a helper exported to get just the data 
>>> that is needed.
>>
>> Yes, will refine to remove unnecessary ones in the next version, 
>> actually isp driver needs to access function amdgpu_bo_create_kernel 
>> which is exported by amdgpu and delared in amdgpu_object.h, because 
>> amdgpu_object.h also includes other amd gpu header files, so have to 
>> add these include path to avoid compilation error.
>> It'll be greate if there is kernel wide include, any suggestion for this?
>>
> 
> Ah yeah I do see exports as of https://git.kernel.org/torvalds/c/ 
> ebbe34edc0a90
> 
> So based on what is in the tree right now what you did "makes sense", 
> but I don't think it's "correct".  From another driver like the ISP 
> driver I feel that the code should really just be something like:
> 
> #include <linux/amdgpu/isp.h>
> 
> I see a few ways forward.
> 
> 1) A new set of helpers created for amdgpu that can take
> opaque" data arguments (maybe the mfd device?) and return back a pointer 
> to the new buffer.  Describe those new helpers in that isp.h header.
> 
> 2) Manage the lifecycle of the buffers in sw_init/sw_fini of the ISP in 
> amdgpu.  Store pointers to them for access in the mfd device, and let 
> the ISP driver take references.  This only works if you don't need new 
> buffers after the driver is loaded.
> 
> I personally prefer option 2 if it is feasible.
> 
> Alex or others might have some other ideas too.
2 is not feasible, because the buffer size and number are decided by App 
at runtime.
1 is really a good idea, will have more investigation internally



^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-06-18 16:35   ` Mario Limonciello
@ 2025-06-20  9:31     ` Du, Bin
  2025-07-06 20:55       ` Mario Limonciello
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-06-20  9:31 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Thanks Mario, add some comments

On 6/19/2025 12:35 AM, Mario Limonciello wrote:
> On 6/18/2025 4:19 AM, Bin Du wrote:
>> 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 <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   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 <linux/pm_runtime.h>
>>   #include <linux/vmalloc.h>
>> +#include <media/v4l2-fwnode.h>
>>   #include <media/v4l2-ioctl.h>
>> -#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);
> 
> You're discarding ret here.  Shouldn't you return ret in the failure path?
Even if it fails, some Apps which doesn't depend on the media link can 
still work, so just print error message and ignore it so at least these 
Apps can still work, do you think it acceptible?>
>> +
>> +    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;
> 
> This isn't fatal?
> 
This call is just expose subdev node to user space, even if it fails, 
some Apps can still work, so just print error message and ignore it so 
at least these Apps can still work, do you think it acceptible?>> +    }
>> +
>> +    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");
> 
> Probably can drop this now
> 
I'd prefer to keeping this for quickly identifying possible camera open 
issue, do you think it acceptible?

>> +    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;
> 
> As mentioned in the first patch, avoid ping ponging the code.
>
Thanks, will remove the code ping ponging in next patch>> +
>> +    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:
> As mentioned in the first patch, avoid ping ponging the code.
Thanks, will remove the code ping ponging in next patch>>       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");
> 
> Don't ping pong this
> 
This log will be removed in next patch as you suggested in other comment
>> +
>> +    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 <linux/mutex.h>
>> -#include <media/v4l2-device.h>
>>   #include <media/videobuf2-memops.h>
>>   #include <media/videobuf2-vmalloc.h>
>> +#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 <linux/mutex.h>
>> +#include <linux/pm_domain.h>
>> +#include <linux/pm_runtime.h>
>> +
>> +#include "isp4_fw_cmd_resp.h"
>> +#include "isp4_hw.h"
>> +#include "isp4_interface.h"
>> +#include "isp4_phy.h"
>> +#include "isp4_subdev.h"
>> +#include <linux/units.h>
>> +
>> +#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 <linux/delay.h>
>> +#include <linux/firmware.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/types.h>
>> +#include <linux/debugfs.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/videobuf2-vmalloc.h>
>> +
>> +#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
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-06-20  9:31     ` Du, Bin
@ 2025-07-06 20:55       ` Mario Limonciello
  2025-07-07  6:22         ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Mario Limonciello @ 2025-07-06 20:55 UTC (permalink / raw)
  To: Du, Bin, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On 6/20/2025 5:31 AM, Du, Bin wrote:
> Thanks Mario, add some comments
> 
> On 6/19/2025 12:35 AM, Mario Limonciello wrote:
>> On 6/18/2025 4:19 AM, Bin Du wrote:
>>> 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 <Bin.Du@amd.com>
>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>> ---
>>>   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 <linux/pm_runtime.h>
>>>   #include <linux/vmalloc.h>
>>> +#include <media/v4l2-fwnode.h>
>>>   #include <media/v4l2-ioctl.h>
>>> -#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);
>>
>> You're discarding ret here.  Shouldn't you return ret in the failure 
>> path?
> Even if it fails, some Apps which doesn't depend on the media link can 
> still work, so just print error message and ignore it so at least these 
> Apps can still work, do you think it acceptible?>

I think it should be a warn or an info if it's an acceptable situation 
along with a comment to help us years later understand why the error 
handling is that way.

>>> +
>>> +    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;
>>
>> This isn't fatal?
>>
> This call is just expose subdev node to user space, even if it fails, 
> some Apps can still work, so just print error message and ignore it so 
> at least these Apps can still work, do you think it acceptible?>> +    }

I guess same comment as above.

>>> +
>>> +    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");
>>
>> Probably can drop this now
>>
> I'd prefer to keeping this for quickly identifying possible camera open 
> issue, do you think it acceptible?

Sure.

> 
>>> +    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;
>>
>> As mentioned in the first patch, avoid ping ponging the code.
>>
> Thanks, will remove the code ping ponging in next patch>> +
>>> +    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:
>> As mentioned in the first patch, avoid ping ponging the code.
> Thanks, will remove the code ping ponging in next patch>>       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");
>>
>> Don't ping pong this
>>
> This log will be removed in next patch as you suggested in other comment
>>> +
>>> +    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 <linux/mutex.h>
>>> -#include <media/v4l2-device.h>
>>>   #include <media/videobuf2-memops.h>
>>>   #include <media/videobuf2-vmalloc.h>
>>> +#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 <linux/mutex.h>
>>> +#include <linux/pm_domain.h>
>>> +#include <linux/pm_runtime.h>
>>> +
>>> +#include "isp4_fw_cmd_resp.h"
>>> +#include "isp4_hw.h"
>>> +#include "isp4_interface.h"
>>> +#include "isp4_phy.h"
>>> +#include "isp4_subdev.h"
>>> +#include <linux/units.h>
>>> +
>>> +#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 <linux/delay.h>
>>> +#include <linux/firmware.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/uaccess.h>
>>> +#include <linux/types.h>
>>> +#include <linux/debugfs.h>
>>> +#include <media/v4l2-device.h>
>>> +#include <media/videobuf2-vmalloc.h>
>>> +
>>> +#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
>>
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-07-06 20:55       ` Mario Limonciello
@ 2025-07-07  6:22         ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-07  6:22 UTC (permalink / raw)
  To: Mario Limonciello, mchehab, hverkuil, laurent.pinchart+renesas,
	bryan.odonoghue, sakari.ailus, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel
  Cc: pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov



On 7/7/2025 4:55 AM, Mario Limonciello wrote:
> On 6/20/2025 5:31 AM, Du, Bin wrote:
>> Thanks Mario, add some comments
>>
>> On 6/19/2025 12:35 AM, Mario Limonciello wrote:
>>> On 6/18/2025 4:19 AM, Bin Du wrote:
>>>> 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 <Bin.Du@amd.com>
>>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>>> ---
>>>>   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 <linux/pm_runtime.h>
>>>>   #include <linux/vmalloc.h>
>>>> +#include <media/v4l2-fwnode.h>
>>>>   #include <media/v4l2-ioctl.h>
>>>> -#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))
>>>>>>>> [snip]
>>>> >>>> +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);
>>>
>>> You're discarding ret here.  Shouldn't you return ret in the failure 
>>> path?
>> Even if it fails, some Apps which doesn't depend on the media link can 
>> still work, so just print error message and ignore it so at least 
>> these Apps can still work, do you think it acceptible?>
> 
> I think it should be a warn or an info if it's an acceptable situation 
> along with a comment to help us years later understand why the error 
> handling is that way.
> 
Sure, will make it warn and add comment>>>> +
>>>> +    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;
>>>
>>> This isn't fatal?
>>>
>> This call is just expose subdev node to user space, even if it fails, 
>> some Apps can still work, so just print error message and ignore it so 
>> at least these Apps can still work, do you think it acceptible?>> +    }
> 
> I guess same comment as above.
> 
Same as above>>>> +
>>>> +    return ret;
>>>> +}
>>>>
>>>> [snip]>>>>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-06-18  9:19 ` [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers " Bin Du
@ 2025-07-23 17:55   ` Sultan Alsawaf
  2025-07-24  5:14     ` Sultan Alsawaf
  2025-07-25  9:22     ` Du, Bin
  2025-07-28  7:04   ` Sultan Alsawaf
  1 sibling, 2 replies; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-23 17:55 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
> +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> +{
> +	struct isp4vid_vb2_buf *buf = mem_priv;
> +
> +	if (!buf) {
> +		pr_err("fail invalid buf handle\n");
> +		return;
> +	}
> +
> +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);

Variable declaration mixed with code, move the variable declaration to the top.

> +
> +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
> +		buf->gpu_addr, buf->size);
> +
> +	if (buf->vaddr)
> +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
> +
> +	// put dmabuf for exported ones
> +	dma_buf_put(buf->dbuf);

The dmabuf shouldn't be put from the detach_dmabuf memop. Remove this.

> +
> +	kfree(buf);
> +}

[snip]

> +static void isp4vid_vb2_dmabuf_ops_release(struct dma_buf *dbuf)
> +{
> +	struct isp4vid_vb2_buf *buf = dbuf->priv;
> +
> +	/* drop reference obtained in vb2_isp4vid_get_dmabuf */

s/vb2_isp4vid_get_dmabuf/isp4vid_vb2_get_dmabuf/

> +	if (buf->is_expbuf)
> +		isp4vid_vb2_put(dbuf->priv);
> +	else
> +		dev_dbg(buf->dev, "ignore buf release for implicit case");
> +}

[snip]

> +static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
> +					      void *buf_priv,
> +					      unsigned long flags)
> +{
> +	struct isp4vid_vb2_buf *buf = buf_priv;
> +	struct dma_buf *dbuf;
> +
> +	if (buf->dbuf) {
> +		dev_dbg(buf->dev,
> +			"dbuf already created, reuse implicit dbuf\n");
> +		dbuf = buf->dbuf;

The dmabuf is reused here without taking a reference to it. When the get_dmabuf
memop is called by vb2_core_expbuf(), it assumes that a reference to the dmabuf
is acquired. So you need to add `get_dma_buf(dbuf)` here.

> +	} else {
> +		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
> +		dev_dbg(buf->dev, "created new dbuf\n");
> +	}
> +	buf->is_expbuf = true;
> +	refcount_inc(&buf->refcount);
> +
> +	dev_dbg(buf->dev, "buf exported, refcount %d\n",
> +		buf->refcount.refs.counter);
> +
> +	return dbuf;
> +}

[snip]

> +static void *isp4vid_vb2_get_userptr(struct vb2_buffer *vb, struct device *dev,
> +				     unsigned long vaddr, unsigned long size)
> +{
> +	struct isp4vid_vb2_buf *buf;
> +	struct frame_vector *vec;
> +	int n_pages, offset, i;
> +	int ret = -ENOMEM;
> +
> +	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
> +	if (!buf)
> +		return ERR_PTR(-ENOMEM);
> +
> +	buf->dev = dev;
> +	buf->dma_dir = vb->vb2_queue->dma_dir;
> +	offset = vaddr & ~PAGE_MASK;
> +	buf->size = size;
> +	vec = vb2_create_framevec(vaddr, size,
> +				  buf->dma_dir == DMA_FROM_DEVICE ||
> +				  buf->dma_dir == DMA_BIDIRECTIONAL);
> +	if (IS_ERR(vec)) {
> +		kfree(buf);
> +		return vec;
> +	}

You can combine the error handling here with the error path at the bottom of the
function instead of duplicating the `kfree(buf)`.

> +	buf->vec = vec;
> +	n_pages = frame_vector_count(vec);
> +	if (frame_vector_to_pages(vec) < 0) {
> +		unsigned long *nums = frame_vector_pfns(vec);
> +
> +		/*
> +		 * We cannot get page pointers for these pfns. Check memory is
> +		 * physically contiguous and use direct mapping.
> +		 */
> +		for (i = 1; i < n_pages; i++)
> +			if (nums[i - 1] + 1 != nums[i])
> +				goto err_destroy_free;
> +		buf->vaddr = (__force void *)
> +			     ioremap(__pfn_to_phys(nums[0]), size + offset);
> +	} else {
> +		buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1);
> +	}
> +
> +	if (!buf->vaddr)
> +		goto err_destroy_free;
> +
> +	buf->vaddr = ((char *)buf->vaddr) + offset;
> +	return buf;
> +
> +err_destroy_free:
> +	vb2_destroy_framevec(vec);
> +	kfree(buf);
> +	return ERR_PTR(ret);
> +}
> +
> +static void isp4vid_vb2_put(void *buf_priv)
> +{
> +	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
> +	struct amdgpu_bo *bo = (struct amdgpu_bo *)buf->bo;
> +
> +	dev_dbg(buf->dev,
> +		"release isp user bo 0x%llx size %ld refcount %d is_expbuf %d",
> +		buf->gpu_addr, buf->size,
> +		buf->refcount.refs.counter, buf->is_expbuf);
> +
> +	if (refcount_dec_and_test(&buf->refcount)) {
> +		amdgpu_bo_free_isp_user(bo);
> +
> +		// put implicit dmabuf here, detach_dmabuf will not be called

Comment style (use /**/ instead of //).

> +		if (!buf->is_expbuf)
> +			dma_buf_put(buf->dbuf);
> +
> +		vfree(buf->vaddr);
> +		kfree(buf);
> +		buf = NULL;

`buf = NULL;` here is superfluous; you can remove it.

> +	} else {
> +		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
> +			 refcount_read(&buf->refcount));

This refcount_read() is a possible use-after-free because `buf` is accessed
after isp4vid_vb2_put() puts its reference to `buf`. So something else could put
the last reference to `buf` and free it after this refcount dec but before the
refcount_read(). Maybe just remove this dev_warn() entirely?

> +	}
> +}
> +
> +static void *isp4vid_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
> +			       unsigned long size)
> +{
> +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
> +	struct isp4vid_vb2_buf *buf = NULL;
> +	struct amdgpu_bo *bo;
> +	u64 gpu_addr;
> +	u32 ret;
> +
> +	buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags);
> +	if (!buf)
> +		return ERR_PTR(-ENOMEM);
> +
> +	buf->dev = dev;
> +	buf->size = size;
> +	buf->vaddr = vmalloc_user(buf->size);
> +	if (!buf->vaddr) {
> +		kfree(buf);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	buf->dma_dir = vb->vb2_queue->dma_dir;
> +	buf->handler.refcount = &buf->refcount;
> +	buf->handler.put = isp4vid_vb2_put;
> +	buf->handler.arg = buf;

What is buf->handler for? I don't see it used anywhere in the entire patchset; I
can delete `handler` from `struct isp4vid_vb2_buf` along with these lines and it
compiles. 

> +
> +	// get implicit dmabuf

Comment style.

> +	buf->dbuf = isp4vid_get_dmabuf(vb, buf, 0);
> +	if (!buf->dbuf) {
> +		dev_err(dev, "fail to get dmabuf\n");
> +		return ERR_PTR(-EINVAL);
> +	}

Doesn't free `buf` or `buf->vaddr` on error here. Also, comment style.

> +
> +	// create isp user BO and obtain gpu_addr

Comment style.

> +	ret = amdgpu_bo_create_isp_user(isp_vdev->amdgpu_dev, buf->dbuf,
> +					AMDGPU_GEM_DOMAIN_GTT, &bo, &gpu_addr);
> +	if (ret) {
> +		dev_err(dev, "fail to create BO\n");
> +		return ERR_PTR(-EINVAL);
> +	}

Doesn't free `buf` or `buf->vaddr` or put `buf->dbuf` on error here.

> +
> +	buf->bo = (void *)bo;
> +	buf->gpu_addr = gpu_addr;
> +
> +	refcount_set(&buf->refcount, 1);

This discards the refcount inc triggered from amdgpu_bo_create_isp_user() when
it calls get_dma_buf(), leading to a use-after-free. Move this refcount_set()
up, preferably right after vmalloc_user() or right after `buf` is allocated so
there's no risk of this issue occurring again in the future.

> +
> +	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d",
> +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> +
> +	return buf;
> +}

[snip]

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (7 preceding siblings ...)
  2025-06-18  9:19 ` [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver Bin Du
@ 2025-07-23 18:12 ` Sultan Alsawaf
  2025-07-25 10:22   ` Du, Bin
  2025-08-14  6:53 ` Sultan Alsawaf
  9 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-23 18:12 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
> AMD ISP4 is the AMD image processing gen 4 which can be found in HP ZBook Ultra G1a 14 inch Mobile Workstation PC ( Ryzen AI Max 385)
> (https://ubuntu.com/certified/202411-36043)
> This patch series introduces the initial driver support for the AMD ISP4.
> 
> Patch summary:
> - Powers up/off and initializes ISP HW
> - Configures and kicks off ISP FW
> - Interacts with APP using standard V4l2 interface by video node
> - Controls ISP HW and interacts with ISP FW to do image processing
> - Support enum/set output image format and resolution
> - Support queueing buffer from app and dequeueing ISP filled buffer to App
> - Starts/stops sensor and mipi csi when camera App starts/stops streaming.
> - It supports libcamera ver0.2 SimplePipeline
> - It is verified on qv4l2, cheese and qcam
> - It is verified together with following patches
> 	platform/x86: Add AMD ISP platform config for OV05C10 (https://lore.kernel.org/all/20250514215623.522746-1-pratap.nirujogi@amd.com/)
> 	media: i2c: Add OV05C10 camera sensor driver (https://lore.kernel.org/all/20250408221246.911508-1-pratap.nirujogi@amd.com/)
> 	pinctrl: amd: isp411: Add amdisp GPIO pinctrl (https://github.com/torvalds/linux/commit/e97435ab09f3ad7b6a588dd7c4e45a96699bbb4a)
> 	i2c: amd-isp: Add ISP i2c-designware driver (https://github.com/torvalds/linux/commit/d6263c468a761cd4c89887073614394ac48441e1)
> 	drm/amd/amdgpu: Add GPIO resources required for amdisp (https://gitlab.freedesktop.org/agd5f/linux/-/commit/ad0f5966ed8297aa47b3184192b00b7379ae0758)

Hi,

I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.

I cannot for the life of me get the webcam working under Linux. The webcam works
under Windows so it's not a hardware issue.

With this patchset and all of the patches you link here applied to 6.15, I get
the following errors:
  [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
  [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed

With the old ispkernel code from February [1] applied on 6.15, the webcam
indicator LED lights up but there's no image. I see these messages at boot:
  [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
  [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
  [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
  [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
  [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
  [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter

And then the kernel crashes due to the same use-after-free issues I pointed out
in my other email [2].

Any idea what's going on?

[1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
[2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box

Thanks,
Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-23 17:55   ` Sultan Alsawaf
@ 2025-07-24  5:14     ` Sultan Alsawaf
  2025-07-25  9:05       ` Du, Bin
  2025-07-25  9:22     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-24  5:14 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Wed, Jul 23, 2025 at 10:55:48AM -0700, Sultan Alsawaf wrote:
> On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
> > +
> > +	buf->bo = (void *)bo;
> > +	buf->gpu_addr = gpu_addr;
> > +
> > +	refcount_set(&buf->refcount, 1);
> 
> This discards the refcount inc triggered from amdgpu_bo_create_isp_user() when
> it calls get_dma_buf(), leading to a use-after-free. Move this refcount_set()
> up, preferably right after vmalloc_user() or right after `buf` is allocated so
> there's no risk of this issue occurring again in the future.

Following up to correct myself: please disregard this one comment from my
previous email since it's incorrect. Sorry for any confusion.

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-06-18  9:19 ` [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added Bin Du
  2025-06-18 16:35   ` Mario Limonciello
@ 2025-07-25  1:35   ` Sultan Alsawaf
  2025-07-25  9:03     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-25  1:35 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Wed, Jun 18, 2025 at 05:19:56PM +0800, Bin Du wrote:
> +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;

[snip]

> +err_fwnode:
> +	if (remote_ep)
> +		fwnode_handle_put(remote_ep);
> +	if (local_ep)
> +		fwnode_handle_put(remote_ep);

Copy/paste error: the second fwnode_handle_put() should put `local_ep`.

> +
> +	return ret;
> +}

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added
  2025-07-25  1:35   ` Sultan Alsawaf
@ 2025-07-25  9:03     ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-25  9:03 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Thanks Sultan, will fix it in the next patch

Regards,
Bin

On 7/25/2025 9:35 AM, Sultan Alsawaf wrote:
> On Wed, Jun 18, 2025 at 05:19:56PM +0800, Bin Du wrote:
>> +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;
> 
> [snip]
> 
>> +err_fwnode:
>> +	if (remote_ep)
>> +		fwnode_handle_put(remote_ep);
>> +	if (local_ep)
>> +		fwnode_handle_put(remote_ep);
> 
> Copy/paste error: the second fwnode_handle_put() should put `local_ep`.
> 
>> +
>> +	return ret;
>> +}
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-24  5:14     ` Sultan Alsawaf
@ 2025-07-25  9:05       ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-25  9:05 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Thanks Sultan, never mind.

Regards,
Bin

On 7/24/2025 1:14 PM, Sultan Alsawaf wrote:
> On Wed, Jul 23, 2025 at 10:55:48AM -0700, Sultan Alsawaf wrote:
>> On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
>>> +
>>> +	buf->bo = (void *)bo;
>>> +	buf->gpu_addr = gpu_addr;
>>> +
>>> +	refcount_set(&buf->refcount, 1);
>>
>> This discards the refcount inc triggered from amdgpu_bo_create_isp_user() when
>> it calls get_dma_buf(), leading to a use-after-free. Move this refcount_set()
>> up, preferably right after vmalloc_user() or right after `buf` is allocated so
>> there's no risk of this issue occurring again in the future.
> 
> Following up to correct myself: please disregard this one comment from my
> previous email since it's incorrect. Sorry for any confusion.
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-23 17:55   ` Sultan Alsawaf
  2025-07-24  5:14     ` Sultan Alsawaf
@ 2025-07-25  9:22     ` Du, Bin
  2025-07-26 21:41       ` Sultan Alsawaf
  1 sibling, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-25  9:22 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Sultan for your so careful review.

Regards,
Bin

On 7/24/2025 1:55 AM, Sultan Alsawaf wrote:
> On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
>> +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
>> +{
>> +	struct isp4vid_vb2_buf *buf = mem_priv;
>> +
>> +	if (!buf) {
>> +		pr_err("fail invalid buf handle\n");
>> +		return;
>> +	}
>> +
>> +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
> 
> Variable declaration mixed with code, move the variable declaration to the top.
Will fix in the next patch>
>> +
>> +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
>> +		buf->gpu_addr, buf->size);
>> +
>> +	if (buf->vaddr)
>> +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
>> +
>> +	// put dmabuf for exported ones
>> +	dma_buf_put(buf->dbuf);
> 
> The dmabuf shouldn't be put from the detach_dmabuf memop. Remove this.
> 
Will fix in the next patch>> +
>> +	kfree(buf);
>> +}
> 
> [snip]
> 
>> +static void isp4vid_vb2_dmabuf_ops_release(struct dma_buf *dbuf)
>> +{
>> +	struct isp4vid_vb2_buf *buf = dbuf->priv;
>> +
>> +	/* drop reference obtained in vb2_isp4vid_get_dmabuf */
> 
> s/vb2_isp4vid_get_dmabuf/isp4vid_vb2_get_dmabuf/
> 
Will fix in the next patch>> +	if (buf->is_expbuf)
>> +		isp4vid_vb2_put(dbuf->priv);
>> +	else
>> +		dev_dbg(buf->dev, "ignore buf release for implicit case");
>> +}
> 
> [snip]
> 
>> +static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
>> +					      void *buf_priv,
>> +					      unsigned long flags)
>> +{
>> +	struct isp4vid_vb2_buf *buf = buf_priv;
>> +	struct dma_buf *dbuf;
>> +
>> +	if (buf->dbuf) {
>> +		dev_dbg(buf->dev,
>> +			"dbuf already created, reuse implicit dbuf\n");
>> +		dbuf = buf->dbuf;
> 
> The dmabuf is reused here without taking a reference to it. When the get_dmabuf
> memop is called by vb2_core_expbuf(), it assumes that a reference to the dmabuf
> is acquired. So you need to add `get_dma_buf(dbuf)` here.
After test, we found we can't add get_dma_buf(dbuf) here because it will 
make cheese APP fail to open camera with following error:
amdgpu: [drm] *ERROR* failed to alloc gart kernel buffer (-28)>
>> +	} else {
>> +		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
>> +		dev_dbg(buf->dev, "created new dbuf\n");
>> +	}
>> +	buf->is_expbuf = true;
>> +	refcount_inc(&buf->refcount);
>> +
>> +	dev_dbg(buf->dev, "buf exported, refcount %d\n",
>> +		buf->refcount.refs.counter);
>> +
>> +	return dbuf;
>> +}
> 
> [snip]
> 
>> +static void *isp4vid_vb2_get_userptr(struct vb2_buffer *vb, struct device *dev,
>> +				     unsigned long vaddr, unsigned long size)
>> +{
>> +	struct isp4vid_vb2_buf *buf;
>> +	struct frame_vector *vec;
>> +	int n_pages, offset, i;
>> +	int ret = -ENOMEM;
>> +
>> +	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
>> +	if (!buf)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	buf->dev = dev;
>> +	buf->dma_dir = vb->vb2_queue->dma_dir;
>> +	offset = vaddr & ~PAGE_MASK;
>> +	buf->size = size;
>> +	vec = vb2_create_framevec(vaddr, size,
>> +				  buf->dma_dir == DMA_FROM_DEVICE ||
>> +				  buf->dma_dir == DMA_BIDIRECTIONAL);
>> +	if (IS_ERR(vec)) {
>> +		kfree(buf);
>> +		return vec;
>> +	}
> 
> You can combine the error handling here with the error path at the bottom of the
> function instead of duplicating the `kfree(buf)`.
> 
Will fix in the next patch>> +	buf->vec = vec;
>> +	n_pages = frame_vector_count(vec);
>> +	if (frame_vector_to_pages(vec) < 0) {
>> +		unsigned long *nums = frame_vector_pfns(vec);
>> +
>> +		/*
>> +		 * We cannot get page pointers for these pfns. Check memory is
>> +		 * physically contiguous and use direct mapping.
>> +		 */
>> +		for (i = 1; i < n_pages; i++)
>> +			if (nums[i - 1] + 1 != nums[i])
>> +				goto err_destroy_free;
>> +		buf->vaddr = (__force void *)
>> +			     ioremap(__pfn_to_phys(nums[0]), size + offset);
>> +	} else {
>> +		buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1);
>> +	}
>> +
>> +	if (!buf->vaddr)
>> +		goto err_destroy_free;
>> +
>> +	buf->vaddr = ((char *)buf->vaddr) + offset;
>> +	return buf;
>> +
>> +err_destroy_free:
>> +	vb2_destroy_framevec(vec);
>> +	kfree(buf);
>> +	return ERR_PTR(ret);
>> +}
>> +
>> +static void isp4vid_vb2_put(void *buf_priv)
>> +{
>> +	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
>> +	struct amdgpu_bo *bo = (struct amdgpu_bo *)buf->bo;
>> +
>> +	dev_dbg(buf->dev,
>> +		"release isp user bo 0x%llx size %ld refcount %d is_expbuf %d",
>> +		buf->gpu_addr, buf->size,
>> +		buf->refcount.refs.counter, buf->is_expbuf);
>> +
>> +	if (refcount_dec_and_test(&buf->refcount)) {
>> +		amdgpu_bo_free_isp_user(bo);
>> +
>> +		// put implicit dmabuf here, detach_dmabuf will not be called
> 
> Comment style (use /**/ instead of //).
> 
Will fix in the next patch>> +		if (!buf->is_expbuf)
>> +			dma_buf_put(buf->dbuf);
>> +
>> +		vfree(buf->vaddr);
>> +		kfree(buf);
>> +		buf = NULL;
> 
> `buf = NULL;` here is superfluous; you can remove it.
> 
Will fix in the next patch>> +	} else {
>> +		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
>> +			 refcount_read(&buf->refcount));
> 
> This refcount_read() is a possible use-after-free because `buf` is accessed
> after isp4vid_vb2_put() puts its reference to `buf`. So something else could put
> the last reference to `buf` and free it after this refcount dec but before the
> refcount_read(). Maybe just remove this dev_warn() entirely?
> 
The warning is important to debug mem related issue, plan to keep it but 
without accessing buf or buf->refcount here. Do you think it 
acceptible?>> +	}
>> +}
>> +
>> +static void *isp4vid_vb2_alloc(struct vb2_buffer *vb, struct device *dev,
>> +			       unsigned long size)
>> +{
>> +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
>> +	struct isp4vid_vb2_buf *buf = NULL;
>> +	struct amdgpu_bo *bo;
>> +	u64 gpu_addr;
>> +	u32 ret;
>> +
>> +	buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags);
>> +	if (!buf)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	buf->dev = dev;
>> +	buf->size = size;
>> +	buf->vaddr = vmalloc_user(buf->size);
>> +	if (!buf->vaddr) {
>> +		kfree(buf);
>> +		return ERR_PTR(-ENOMEM);
>> +	}
>> +
>> +	buf->dma_dir = vb->vb2_queue->dma_dir;
>> +	buf->handler.refcount = &buf->refcount;
>> +	buf->handler.put = isp4vid_vb2_put;
>> +	buf->handler.arg = buf;
> 
> What is buf->handler for? I don't see it used anywhere in the entire patchset; I
> can delete `handler` from `struct isp4vid_vb2_buf` along with these lines and it
> compiles.
> 
Yes, will remove it.>> +
>> +	// get implicit dmabuf
> 
> Comment style.
> 
>> +	buf->dbuf = isp4vid_get_dmabuf(vb, buf, 0);
>> +	if (!buf->dbuf) {
>> +		dev_err(dev, "fail to get dmabuf\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
> 
> Doesn't free `buf` or `buf->vaddr` on error here. Also, comment style.
> 
Will fix in the next patch>> +
>> +	// create isp user BO and obtain gpu_addr
> 
> Comment style.
> 
Will fix in the next patch>> +	ret = 
amdgpu_bo_create_isp_user(isp_vdev->amdgpu_dev, buf->dbuf,
>> +					AMDGPU_GEM_DOMAIN_GTT, &bo, &gpu_addr);
>> +	if (ret) {
>> +		dev_err(dev, "fail to create BO\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
> 
> Doesn't free `buf` or `buf->vaddr` or put `buf->dbuf` on error here.
> 
Will fix in the next patch>> +
>> +	buf->bo = (void *)bo;
>> +	buf->gpu_addr = gpu_addr;
>> +
>> +	refcount_set(&buf->refcount, 1);
> 
> This discards the refcount inc triggered from amdgpu_bo_create_isp_user() when
> it calls get_dma_buf(), leading to a use-after-free. Move this refcount_set()
> up, preferably right after vmalloc_user() or right after `buf` is allocated so
> there's no risk of this issue occurring again in the future.
> 
Ignore it as you did correction in another mail.>> +
>> +	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d",
>> +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
>> +
>> +	return buf;
>> +}
> 
> [snip]
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-23 18:12 ` [PATCH v2 0/8] Add AMD ISP4 driver Sultan Alsawaf
@ 2025-07-25 10:22   ` Du, Bin
  2025-07-26 22:31     ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-25 10:22 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov, bin.du

Hi Sultan,

[1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't 
verify on 6.15 but we are really glad to help, would you please provide 
some info,
1. Suppose you are using Ubuntu, right? What's the version?
2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?

After your confirmation, we'll see what we can do to enable your camera 
quickly and easily

Regards,
Bin

On 7/24/2025 2:12 AM, Sultan Alsawaf wrote:
> On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
>> AMD ISP4 is the AMD image processing gen 4 which can be found in HP ZBook Ultra G1a 14 inch Mobile Workstation PC ( Ryzen AI Max 385)
>> (https://ubuntu.com/certified/202411-36043)
>> This patch series introduces the initial driver support for the AMD ISP4.
>>
>> Patch summary:
>> - Powers up/off and initializes ISP HW
>> - Configures and kicks off ISP FW
>> - Interacts with APP using standard V4l2 interface by video node
>> - Controls ISP HW and interacts with ISP FW to do image processing
>> - Support enum/set output image format and resolution
>> - Support queueing buffer from app and dequeueing ISP filled buffer to App
>> - Starts/stops sensor and mipi csi when camera App starts/stops streaming.
>> - It supports libcamera ver0.2 SimplePipeline
>> - It is verified on qv4l2, cheese and qcam
>> - It is verified together with following patches
>> 	platform/x86: Add AMD ISP platform config for OV05C10 (https://lore.kernel.org/all/20250514215623.522746-1-pratap.nirujogi@amd.com/)
>> 	media: i2c: Add OV05C10 camera sensor driver (https://lore.kernel.org/all/20250408221246.911508-1-pratap.nirujogi@amd.com/)
>> 	pinctrl: amd: isp411: Add amdisp GPIO pinctrl (https://github.com/torvalds/linux/commit/e97435ab09f3ad7b6a588dd7c4e45a96699bbb4a)
>> 	i2c: amd-isp: Add ISP i2c-designware driver (https://github.com/torvalds/linux/commit/d6263c468a761cd4c89887073614394ac48441e1)
>> 	drm/amd/amdgpu: Add GPIO resources required for amdisp (https://gitlab.freedesktop.org/agd5f/linux/-/commit/ad0f5966ed8297aa47b3184192b00b7379ae0758)
> 
> Hi,
> 
> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> 
> I cannot for the life of me get the webcam working under Linux. The webcam works
> under Windows so it's not a hardware issue.
> 
> With this patchset and all of the patches you link here applied to 6.15, I get
> the following errors:
>    [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
>    [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
> 
> With the old ispkernel code from February [1] applied on 6.15, the webcam
> indicator LED lights up but there's no image. I see these messages at boot:
>    [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
>    [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
>    [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>    [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>    [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>    [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> 
> And then the kernel crashes due to the same use-after-free issues I pointed out
> in my other email [2].
> 
> Any idea what's going on?
> 
> [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> 
> Thanks,
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-25  9:22     ` Du, Bin
@ 2025-07-26 21:41       ` Sultan Alsawaf
  2025-07-26 21:50         ` Sultan Alsawaf
  2025-07-29  6:08         ` Du, Bin
  0 siblings, 2 replies; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-26 21:41 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Fri, Jul 25, 2025 at 05:22:41PM +0800, Du, Bin wrote:
> > > +static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
> > > +					      void *buf_priv,
> > > +					      unsigned long flags)
> > > +{
> > > +	struct isp4vid_vb2_buf *buf = buf_priv;
> > > +	struct dma_buf *dbuf;
> > > +
> > > +	if (buf->dbuf) {
> > > +		dev_dbg(buf->dev,
> > > +			"dbuf already created, reuse implicit dbuf\n");
> > > +		dbuf = buf->dbuf;
> > 
> > The dmabuf is reused here without taking a reference to it. When the get_dmabuf
> > memop is called by vb2_core_expbuf(), it assumes that a reference to the dmabuf
> > is acquired. So you need to add `get_dma_buf(dbuf)` here.
> After test, we found we can't add get_dma_buf(dbuf) here because it will
> make cheese APP fail to open camera with following error:
> amdgpu: [drm] *ERROR* failed to alloc gart kernel buffer (-28)

I see, it's because buf->is_expbuf is set to true even for the implicit dbuf, so
the initial reference on the implicit dbuf is never put, causing a leak.

Also, the refcount increment in isp4vid_vb2_get_dmabuf() is done every time even
when reusing the existing dbuf, but releasing the dbuf will only do a single
refcount decrement. This also causes a leak.

And, isp4vid_get_dmabuf() may fail but isp4vid_vb2_get_dmabuf() doesn't check
the return value, so there may be another leak when isp4vid_get_dmabuf() fails
because of the refcount increment. The refcount increment and setting of
buf->is_expbuf to true should only be done on success.

I have fixed all of these isp4vid_vb2_get_dmabuf() issues in the following diff,
please try it:

--- a/drivers/media/platform/amd/isp4/isp4_video.c
+++ b/drivers/media/platform/amd/isp4/isp4_video.c
@@ -476,18 +476,22 @@ static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
 					      unsigned long flags)
 {
 	struct isp4vid_vb2_buf *buf = buf_priv;
-	struct dma_buf *dbuf;
+	struct dma_buf *dbuf = buf->dbuf;
 
-	if (buf->dbuf) {
+	if (dbuf) {
 		dev_dbg(buf->dev,
-			"dbuf already created, reuse implicit dbuf\n");
-		dbuf = buf->dbuf;
+			"dbuf already created, reuse %s dbuf\n",
+			buf->is_expbuf ? "exported" : "implicit");
+		get_dma_buf(dbuf);
 	} else {
 		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
+		if (!dbuf)
+			return NULL;
+
 		dev_dbg(buf->dev, "created new dbuf\n");
+		buf->is_expbuf = true;
+		refcount_inc(&buf->refcount);
 	}
-	buf->is_expbuf = true;
-	refcount_inc(&buf->refcount);
 
 	dev_dbg(buf->dev, "buf exported, refcount %d\n",
 		buf->refcount.refs.counter);
--

> > > +		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
> > > +			 refcount_read(&buf->refcount));
> > 
> > This refcount_read() is a possible use-after-free because `buf` is accessed
> > after isp4vid_vb2_put() puts its reference to `buf`. So something else could put
> > the last reference to `buf` and free it after this refcount dec but before the
> > refcount_read(). Maybe just remove this dev_warn() entirely?
> > 
> The warning is important to debug mem related issue, plan to keep it but
> without accessing buf or buf->refcount here. Do you think it acceptible?

Yes, that sounds good. So something like this:
`dev_warn(buf->dev, "ignore buffer free, refcount > 0");`

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-26 21:41       ` Sultan Alsawaf
@ 2025-07-26 21:50         ` Sultan Alsawaf
  2025-07-29  6:12           ` Du, Bin
  2025-07-29  6:08         ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-26 21:50 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Sat, Jul 26, 2025 at 02:41:41PM -0700, Sultan Alsawaf wrote:
> On Fri, Jul 25, 2025 at 05:22:41PM +0800, Du, Bin wrote:
> > > > +		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
> > > > +			 refcount_read(&buf->refcount));
> > > 
> > > This refcount_read() is a possible use-after-free because `buf` is accessed
> > > after isp4vid_vb2_put() puts its reference to `buf`. So something else could put
> > > the last reference to `buf` and free it after this refcount dec but before the
> > > refcount_read(). Maybe just remove this dev_warn() entirely?
> > > 
> > The warning is important to debug mem related issue, plan to keep it but
> > without accessing buf or buf->refcount here. Do you think it acceptible?
> 
> Yes, that sounds good. So something like this:
> `dev_warn(buf->dev, "ignore buffer free, refcount > 0");`

Sorry, to fix the dev_warn() we need to make a copy of buf->dev first:

--- a/drivers/media/platform/amd/isp4/isp4_video.c
+++ b/drivers/media/platform/amd/isp4/isp4_video.c
@@ -584,8 +584,9 @@ static void isp4vid_vb2_put(void *buf_priv)
 {
 	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
 	struct amdgpu_bo *bo = (struct amdgpu_bo *)buf->bo;
+	struct device *dev = buf->dev;
 
-	dev_dbg(buf->dev,
+	dev_dbg(dev,
 		"release isp user bo 0x%llx size %ld refcount %d is_expbuf %d",
 		buf->gpu_addr, buf->size,
 		buf->refcount.refs.counter, buf->is_expbuf);
@@ -601,8 +602,7 @@ static void isp4vid_vb2_put(void *buf_priv)
 		kfree(buf);
 		buf = NULL;
 	} else {
-		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
-			 refcount_read(&buf->refcount));
+		dev_warn(dev, "ignore buffer free, refcount > 0\n");
 	}
 }
 
--

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-25 10:22   ` Du, Bin
@ 2025-07-26 22:31     ` Sultan Alsawaf
  2025-07-29  3:32       ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-26 22:31 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > 
> > I cannot for the life of me get the webcam working under Linux. The webcam works
> > under Windows so it's not a hardware issue.
> > 
> > With this patchset and all of the patches you link here applied to 6.15, I get
> > the following errors:
> >    [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
> >    [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
> > 
> > With the old ispkernel code from February [1] applied on 6.15, the webcam
> > indicator LED lights up but there's no image. I see these messages at boot:
> >    [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
> >    [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
> >    [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> >    [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> >    [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> >    [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > 
> > And then the kernel crashes due to the same use-after-free issues I pointed out
> > in my other email [2].
> > 
> > Any idea what's going on?
> > 
> > [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> Hi Sultan,
> 
> [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
> on 6.15 but we are really glad to help, would you please provide some info,
> 1. Suppose you are using Ubuntu, right? What's the version?
> 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
> 
> After your confirmation, we'll see what we can do to enable your camera
> quickly and easily
>
> Regards,
> Bin

Thank you, Bin!

1. I'm using Arch Linux with the ISP4-patched libcamera [1].
2. Yes, here is my kernel source [2].

I have some more findings:

Currently, the first blocking issue is that the I2C adapter fails to initialize.
This is because the ISP tile isn't powered on.

I noticed that in the old version of amd_isp_i2c_designware [3], there were
calls to isp_power_set(), which is available in the old ISP4 sources [4].
Without isp_power_set(), the I2C adapter always fails to initialize for me.

How is the ISP tile supposed to get powered on in the current ISP4 code?

Also, I noticed that the driver init ordering matters between all of the drivers
needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
must be initialized before amd_capture, otherwise amd_capture will fail to find
the fwnode properties for the OV05C10 device attached to the I2C bus.

But there is no driver init ordering enforced, which also caused some issues for
me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
to ensure each driver waits for its dependencies to init first?

[1] https://github.com/amd/Linux_ISP_libcamera/tree/3.0
[2] https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.15-sultan-isp4
[3] https://lore.kernel.org/all/20250228164519.3453927-1-pratap.nirujogi@amd.com
[4] https://github.com/amd/Linux_ISP_Kernel/blob/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4/drivers/media/platform/amd/isp4/isp_hwa.c#L378-L385

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-06-18  9:19 ` [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Bin Du
  2025-06-18 15:58   ` Mario Limonciello
@ 2025-07-28  5:54   ` Sakari Ailus
  2025-07-28  9:00     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sakari Ailus @ 2025-07-28  5:54 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Hi Bin,

On Wed, Jun 18, 2025 at 05:19:52PM +0800, Bin Du wrote:
> 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

You could rewrap the text and use the full lines here -- up to 75
characters per line.

> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>  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 <bin.du@amd.com>
> +M:	Nirujogi Pratap <pratap.nirujogi@amd.com>
> +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 <Felix.Kuehling@amd.com>
>  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

Do you need all these three? Most drivers need only one.

> +	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

Uh... does the driver actually depend on this?

> +
> +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 <linux/pm_runtime.h>
> +#include <linux/vmalloc.h>
> +#include <media/v4l2-ioctl.h>

Alphabetic order, please.

> +
> +#include "isp4.h"
> +
> +#define VIDEO_BUF_NUM 5

Unused.

> +
> +#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))

No need for the cast.

> +
> +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;
> +

Extra newline.

> +	int i, irq, ret;

unsigned int i?

> +
> +	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");

Please leave this out.

> +
> +	/* 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");

This doesn't seem useful.

> +
> +	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);

You'll need to enable runtime PM before registering any interfaces on UAPI.
Same goes for setting driver data for the device.

> +
> +	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");

I'd say this is redundant.

> +}
> +
> +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 <bin.du@amd.com>");
> +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
> +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 <linux/mutex.h>
> +#include <media/v4l2-device.h>
> +#include <media/videobuf2-memops.h>
> +#include <media/videobuf2-vmalloc.h>
> +
> +#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 */

Use the same name as for the macro here, please.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware
  2025-06-18  9:19 ` [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware Bin Du
  2025-06-18 16:00   ` Mario Limonciello
@ 2025-07-28  5:57   ` Sakari Ailus
  2025-07-28  9:24     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sakari Ailus @ 2025-07-28  5:57 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Hi Bin,

On Wed, Jun 18, 2025 at 05:19:53PM +0800, Bin Du wrote:
> Low level functions for access the registers and mapping to their ranges.
> This change also includes register definitions for ring buffer used to
> communicate with ISP Firmware.
> Ring buffer is the communication interface between driver and ISP Firmware.
> Command and responses are exchanged through the ring buffer.

Please rewrap this, the third line could well be longer.

> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>  drivers/media/platform/amd/isp4/Makefile      |   3 +-
>  drivers/media/platform/amd/isp4/isp4_hw.c     |  46 +++++++
>  drivers/media/platform/amd/isp4/isp4_hw.h     |  14 +++
>  drivers/media/platform/amd/isp4/isp4_hw_reg.h | 116 ++++++++++++++++++
>  4 files changed, 178 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.c
>  create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.h
>  create mode 100644 drivers/media/platform/amd/isp4/isp4_hw_reg.h
> 
> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
> index e9e84160517d..8ca1c4dfe246 100644
> --- a/drivers/media/platform/amd/isp4/Makefile
> +++ b/drivers/media/platform/amd/isp4/Makefile
> @@ -3,7 +3,8 @@
>  # Copyright (C) 2025 Advanced Micro Devices, Inc.
>  
>  obj-$(CONFIG_AMD_ISP4) += amd_capture.o
> -amd_capture-objs := isp4.o
> +amd_capture-objs := isp4.o	\
> +			isp4_hw.o	\
>  
>  ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>  ccflags-y += -I$(srctree)/include
> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.c b/drivers/media/platform/amd/isp4/isp4_hw.c
> new file mode 100644
> index 000000000000..e5315330a514
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_hw.c
> @@ -0,0 +1,46 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/types.h>
> +
> +#include "isp4_hw.h"
> +#include "isp4_hw_reg.h"
> +
> +#define RMMIO_SIZE 524288
> +
> +u32 isp4hw_rreg(void __iomem *base, u32 reg)
> +{
> +	void __iomem *reg_addr;
> +
> +	if (reg >= RMMIO_SIZE)
> +		return RREG_FAILED_VAL;
> +
> +	if (reg < ISP_MIPI_PHY0_REG0)
> +		reg_addr = base + reg;
> +	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
> +		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);

Redundant parentheses.

> +	else
> +		return RREG_FAILED_VAL;
> +
> +	return readl(reg_addr);
> +};
> +
> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val)
> +{
> +	void __iomem *reg_addr;
> +
> +	if (reg >= RMMIO_SIZE)
> +		return;
> +
> +	if (reg < ISP_MIPI_PHY0_REG0)
> +		reg_addr = base + reg;
> +	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
> +		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);

Ditto.

> +	else
> +		return;
> +
> +	writel(val, reg_addr);
> +};
> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.h b/drivers/media/platform/amd/isp4/isp4_hw.h
> new file mode 100644
> index 000000000000..072d135b9e3a
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_hw.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_HW_H_
> +#define _ISP4_HW_H_
> +
> +#define RREG_FAILED_VAL 0xFFFFFFFF
> +
> +u32 isp4hw_rreg(void __iomem *base, u32 reg);
> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val);
> +
> +#endif
> diff --git a/drivers/media/platform/amd/isp4/isp4_hw_reg.h b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
> new file mode 100644
> index 000000000000..b11f12ba6c56
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
> @@ -0,0 +1,116 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_HW_REG_H_
> +#define _ISP4_HW_REG_H_
> +
> +#define ISP_SOFT_RESET		0x62000
> +#define ISP_SYS_INT0_EN		0x62010
> +#define ISP_SYS_INT0_STATUS	0x62014
> +#define ISP_SYS_INT0_ACK	0x62018
> +#define ISP_CCPU_CNTL		0x62054
> +#define ISP_STATUS		0x62058
> +#define ISP_LOG_RB_BASE_LO0	0x62148
> +#define ISP_LOG_RB_BASE_HI0	0x6214C

Lower case hexadecimals, please.

> +#define ISP_LOG_RB_SIZE0	0x62150
> +#define ISP_LOG_RB_RPTR0	0x62154
> +#define ISP_LOG_RB_WPTR0	0x62158
> +#define ISP_RB_BASE_LO1		0x62170
> +#define ISP_RB_BASE_HI1		0x62174
> +#define ISP_RB_SIZE1		0x62178
> +#define ISP_RB_RPTR1		0x6217C
> +#define ISP_RB_WPTR1		0x62180
> +#define ISP_RB_BASE_LO2		0x62184
> +#define ISP_RB_BASE_HI2		0x62188
> +#define ISP_RB_SIZE2		0x6218C
> +#define ISP_RB_RPTR2		0x62190
> +#define ISP_RB_WPTR2		0x62194
> +#define ISP_RB_BASE_LO3		0x62198
> +#define ISP_RB_BASE_HI3		0x6219C
> +#define ISP_RB_SIZE3		0x621A0
> +#define ISP_RB_RPTR3		0x621A4
> +#define ISP_RB_WPTR3		0x621A8
> +#define ISP_RB_BASE_LO4		0x621AC
> +#define ISP_RB_BASE_HI4		0x621B0
> +#define ISP_RB_SIZE4		0x621B4
> +#define ISP_RB_RPTR4		0x621B8
> +#define ISP_RB_WPTR4		0x621BC
> +#define ISP_RB_BASE_LO5		0x621C0
> +#define ISP_RB_BASE_HI5		0x621C4
> +#define ISP_RB_SIZE5		0x621C8
> +#define ISP_RB_RPTR5		0x621CC
> +#define ISP_RB_WPTR5		0x621D0
> +#define ISP_RB_BASE_LO6		0x621D4
> +#define ISP_RB_BASE_HI6		0x621D8
> +#define ISP_RB_SIZE6		0x621DC
> +#define ISP_RB_RPTR6		0x621E0
> +#define ISP_RB_WPTR6		0x621E4
> +#define ISP_RB_BASE_LO7		0x621E8
> +#define ISP_RB_BASE_HI7		0x621EC
> +#define ISP_RB_SIZE7		0x621F0
> +#define ISP_RB_RPTR7		0x621F4
> +#define ISP_RB_WPTR7		0x621F8
> +#define ISP_RB_BASE_LO8		0x621FC
> +#define ISP_RB_BASE_HI8		0x62200
> +#define ISP_RB_SIZE8		0x62204
> +#define ISP_RB_RPTR8		0x62208
> +#define ISP_RB_WPTR8		0x6220C
> +#define ISP_RB_BASE_LO9		0x62210
> +#define ISP_RB_BASE_HI9		0x62214
> +#define ISP_RB_SIZE9		0x62218
> +#define ISP_RB_RPTR9		0x6221C
> +#define ISP_RB_WPTR9		0x62220
> +#define ISP_RB_BASE_LO10	0x62224
> +#define ISP_RB_BASE_HI10	0x62228
> +#define ISP_RB_SIZE10		0x6222C
> +#define ISP_RB_RPTR10		0x62230
> +#define ISP_RB_WPTR10		0x62234
> +#define ISP_RB_BASE_LO11	0x62238
> +#define ISP_RB_BASE_HI11	0x6223C
> +#define ISP_RB_SIZE11		0x62240
> +#define ISP_RB_RPTR11		0x62244
> +#define ISP_RB_WPTR11		0x62248
> +#define ISP_RB_BASE_LO12	0x6224C
> +#define ISP_RB_BASE_HI12	0x62250
> +#define ISP_RB_SIZE12		0x62254
> +#define ISP_RB_RPTR12		0x62258
> +#define ISP_RB_WPTR12		0x6225C
> +
> +#define ISP_POWER_STATUS	0x60000
> +
> +#define ISP_MIPI_PHY0_REG0	0x66700
> +#define ISP_MIPI_PHY1_REG0	0x66780
> +#define ISP_MIPI_PHY2_REG0	0x67400
> +
> +#define ISP_MIPI_PHY0_SIZE	0xD30
> +
> +/* ISP_SOFT_RESET */
> +#define ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK			0x00000001UL
> +
> +/* ISP_CCPU_CNTL */
> +#define ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK			0x00040000UL
> +
> +/* ISP_STATUS */
> +#define ISP_STATUS__CCPU_REPORT_MASK				0x000000feUL
> +
> +/* ISP_SYS_INT0_STATUS */
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK	0x00010000UL
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK	0x00040000UL
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK	0x00100000UL
> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK	0x00400000UL
> +
> +/* ISP_SYS_INT0_EN */
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK	0x00010000UL
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK	0x00040000UL
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK	0x00100000UL
> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK	0x00400000UL
> +
> +/* ISP_SYS_INT0_ACK */
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK	0x00010000UL
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT10_ACK_MASK	0x00040000UL
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT11_ACK_MASK	0x00100000UL
> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK	0x00400000UL
> +
> +#endif

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-06-18  9:19 ` [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy Bin Du
@ 2025-07-28  6:33   ` Sakari Ailus
  2025-08-05  9:53     ` Du, Bin
  2025-08-05 10:39     ` Laurent Pinchart
  2025-07-28  7:28   ` Sakari Ailus
  1 sibling, 2 replies; 96+ messages in thread
From: Sakari Ailus @ 2025-07-28  6:33 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Hi Bin,

On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
> 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 <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>  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 <linux/delay.h>
> +#include <linux/device.h>
> +
> +#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

Please align the macro bodies to the same column.

Also using a descriptive prefix for these (such as AMDISP4) would seem like
a reasonable idea. The same goes for the other macros used by the driver,
too.

Speaking of macro names, some of the names below look quite random. Are
these from a hardware datasheet (or something alike)? I might consider
sanitising them. Some are also not in form fit for use in drivers, e.g. if
you have many of something, then the number should be an argument to the
macro, not part of the macro name, e.g. configuration related to lanes --
if feasible.

> +
> +#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;

Please pad these -- I don't think the ABI otherwise requires they're in a
particular location of the container (u32).

> +	} 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;

u16 would seem appropriate here.

> +	} bit;
> +	u32 value;
> +};
> +
> +union isp4phy_mipi_ind_data {
> +	struct {
> +		u32 data : 16;

Ditto.

> +	} 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;

"reserved"?

> +	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,

That's an interesting way to prefill structs. I don't think these macros
expand to valid pointers.

> +};
> +
> +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)(&reg->isp_mipi_phy_ind_idx), addr);
> +	return (u16)isp4hw_rreg(base, (uintptr_t)(&reg->isp_mipi_phy_ind_data));

Redundant parentheses.

> +}
> +
> +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)(&reg->isp_mipi_phy_ind_idx), addr);
> +	isp4hw_wreg(base, (uintptr_t)(&reg->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);

__ffs()?

> +	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;

unsigned int?

> +	     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;

I think you could do this on a single line as well.

> +
> +	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);
> +	}

Could you do this using a loop instead? With a bit saner macros, that
should be quite a bit easier, too.

> +}
> +
> +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++)

Unsigned int for these, too, please.

> +		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;
> +	}

Please add an array for the values and implement this as a loop instead.

> +
> +	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;

Ditto. Or maybe use ilog2()?

> +
> +	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;

You could just as well do these without a temporary variable.

> +}
> +
> +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));

Would assigning phycfg to { } do the job?

> +
> +	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};

{ } is enough.


> +
> +	/* 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)*/

/* Single-line comment. */

> +	/** 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).
> +	 */

/*
 * Multi-line
 * comment.
 */

> +	/* 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);

Why uintptr_t btw.? This seems to be a recurring pattern.

> +		dev_dbg(dev, "Wait for phyReady: 0x%x\n",
> +			phy_reg.isp_mipi_phy7.value);
> +	} while (phy_reg.isp_mipi_phy7.bit.ready != 1);

Use read_poll_timeout() maybe?

> +
> +	/** 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,

How about using "amdisp4" as the prefix for the driver's symbol names? Just
"isp4" is very generic.

> +		  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");

Maybe use a similar format than for the 4-lane case?

> +		return -EINVAL;
> +	}
> +
> +	if (phy_id == 0 && lane_num > 4) {
> +		dev_err(dev, "fail invalid lane number %u for phy0\n",
> +			lane_num);
> +		return -EINVAL;
> +	}

Maybe a switch for phy_id?

> +
> +	return isp4phy_startup_seq_cdphy_rx(dev, base, phy_id, bit_rate, lane_num);

This line would benefit from wrapping.

> +}
> +
> +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));

Extra parentheses.

> +
> +	/* 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),

Redundant parentheses.

> +		    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

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-06-18  9:19 ` [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers " Bin Du
  2025-07-23 17:55   ` Sultan Alsawaf
@ 2025-07-28  7:04   ` Sultan Alsawaf
  2025-07-29  7:43     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-28  7:04 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

I found more refcounting issues in addition to the ones from my other emails
while trying to make my webcam work:

On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
> +static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
> +{
> +	struct isp4vid_vb2_buf *buf = buf_priv;
> +	int ret;
> +
> +	if (!buf) {
> +		pr_err("fail no memory to map\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
> +	if (ret) {
> +		dev_err(buf->dev, "fail remap vmalloc mem, %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Make sure that vm_areas for 2 buffers won't be merged together
> +	 */
> +	vm_flags_set(vma, VM_DONTEXPAND);
> +
> +	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
> +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);

Use refcount_read() instead of reading the refcount's atomic_t counter directly.
This is done in 3 other places; change those to refcount_read() as well.

This didn't cause any functional problems, but it should still be fixed.

> +
> +	return 0;
> +}

[snip]

> +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> +{
> +	struct isp4vid_vb2_buf *buf = mem_priv;
> +
> +	if (!buf) {
> +		pr_err("fail invalid buf handle\n");
> +		return;
> +	}
> +
> +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
> +
> +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
> +		buf->gpu_addr, buf->size);
> +
> +	if (buf->vaddr)
> +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
> +
> +	// put dmabuf for exported ones
> +	dma_buf_put(buf->dbuf);
> +
> +	kfree(buf);
> +}

As mentioned in the other email, the dma_buf_put() here needs to be removed. But
that's not all: the dma_buf_vunmap_unlocked() needs to be removed too because
vb2 will always unmap the buffer before detaching it. As a result, having the
dma_buf_vunmap_unlocked() call here results in a use-after-free when vb2 calls
the unmap_dmabuf memop.

Change this function to the following:

	static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
	{
		struct isp4vid_vb2_buf *buf = mem_priv;

		kfree(buf);
	}

> +static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
> +{
> +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
> +	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
> +
> +	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
> +		isp_vdev->vdev.name, vb->index, vb->memory);
> +
> +	if (!buf) {
> +		dev_err(isp_vdev->dev, "Invalid buf handle");
> +		return;
> +	}
> +
> +	// release implicit dmabuf reference here for vb2 buffer
> +	// of type MMAP and is exported
> +	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
> +		dma_buf_put(buf->dbuf);
> +		dev_dbg(isp_vdev->dev,
> +			"put dmabuf for vb->memory %d expbuf %d",
> +			vb->memory,
> +			buf->is_expbuf);
> +	}
> +}
> +

Remove the isp4vid_qops_buffer_cleanup() function. It causes a use-after-free by
doing an extra dma_buf_put(). This function isn't needed now that the refcount
issues are solved.

[snip]

> +static const struct vb2_ops isp4vid_qops = {
> +	.queue_setup = isp4vid_qops_queue_setup,
> +	.buf_cleanup = isp4vid_qops_buffer_cleanup,

Remove the .buf_cleanup hook too.

> +	.buf_queue = isp4vid_qops_buffer_queue,
> +	.start_streaming = isp4vid_qops_start_streaming,
> +	.stop_streaming = isp4vid_qops_stop_streaming,
> +	.wait_prepare = vb2_ops_wait_prepare,
> +	.wait_finish = vb2_ops_wait_finish,
> +};

[snip]

Along with the changes from my other emails, I believe this finally fixes all of
the refcounting issues. No more UaF or leaks here. :-)

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-06-18  9:19 ` [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface Bin Du
  2025-06-18 16:17   ` Mario Limonciello
@ 2025-07-28  7:23   ` Sakari Ailus
  2025-07-29  9:12     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sakari Ailus @ 2025-07-28  7:23 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Hi Bin,

On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
> ISP firmware controls ISP HW pipeline using dedicated embedded processor
> called ccpu.
> The communication between ISP FW and driver is using commands and
> response messages sent through the ring buffer. Command buffers support
> either global setting that is not specific to the steam and support stream
> specific parameters. Response buffers contains ISP FW notification
> information such as frame buffer done and command done. IRQ is used for
> receiving response buffer from ISP firmware, which is handled in the main
> isp4 media device. ISP ccpu is booted up through the firmware loading
> helper function prior to stream start.
> Memory used for command buffer and response buffer needs to be allocated
> from amdgpu buffer manager because isp4 is a child device of amdgpu.

Please rewrap this, some lines above are quite short.

> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>  drivers/media/platform/amd/isp4/Makefile      |   12 +
>  .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
>  .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++++++
>  .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
>  4 files changed, 1546 insertions(+)
>  create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>  create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
>  create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
> 
> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
> index 0e36201fbb30..c0166f954516 100644
> --- a/drivers/media/platform/amd/isp4/Makefile
> +++ b/drivers/media/platform/amd/isp4/Makefile
> @@ -5,10 +5,22 @@
>  obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>  amd_capture-objs := isp4.o	\
>  			isp4_phy.o \
> +			isp4_interface.o \
>  			isp4_hw.o	\
>  
>  ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
> +ccflags-y += -I$(srctree)/include/drm
>  ccflags-y += -I$(srctree)/include
> +ccflags-y += -I$(srctree)/include/uapi/drm
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm
>  
>  ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
>  	cc_stack_align := -mpreferred-stack-boundary=4
> diff --git a/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
> new file mode 100644
> index 000000000000..437d89469af2
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
> @@ -0,0 +1,318 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_CMD_RESP_H_
> +#define _ISP4_CMD_RESP_H_
> +
> +/*
> + * @brief Host and Firmware command & response channel.
> + *        Two types of command/response channel.
> + *          Type Global Command has one command/response channel.
> + *          Type Stream Command has one command/response channel.
> + *-----------                                        ------------
> + *|         |       ---------------------------      |          |
> + *|         |  ---->|  Global Command         |----> |          |
> + *|         |       ---------------------------      |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |       ---------------------------      |          |
> + *|         |  ---->|   Stream Command        |----> |          |
> + *|         |       ---------------------------      |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|  HOST   |                                        | Firmware |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |       --------------------------       |          |
> + *|         |  <----|  Global Response       |<----  |          |
> + *|         |       --------------------------       |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *|         |       --------------------------       |          |
> + *|         |  <----|  Stream Response       |<----  |          |
> + *|         |       --------------------------       |          |
> + *|         |                                        |          |
> + *|         |                                        |          |
> + *-----------                                        ------------
> + */
> +
> +/*
> + * @brief command ID format
> + *        cmd_id is in the format of following type:
> + *        type: indicate command type, global/stream commands.
> + *        group: indicate the command group.
> + *        id: A unique command identification in one type and group.
> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
> + *        |      type       |      group      |       id       |
> + */
> +
> +#define CMD_TYPE_SHIFT (24)
> +#define CMD_GROUP_SHIFT (16)

Redundant parentheses. Please remove all of them.

> +#define CMD_TYPE_STREAM_CTRL ((u32)0x2 << CMD_TYPE_SHIFT)

Maybe 0x2U << CMD_TYPE_SHIFT instead?

> +
> +#define CMD_GROUP_STREAM_CTRL ((u32)0x1 << CMD_GROUP_SHIFT)
> +#define CMD_GROUP_STREAM_BUFFER ((u32)0x4 << CMD_GROUP_SHIFT)
> +
> +/* Stream  Command */
> +#define CMD_ID_SET_STREAM_CONFIG                        \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x1)
> +#define CMD_ID_SET_OUT_CHAN_PROP                        \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x3)
> +#define CMD_ID_ENABLE_OUT_CHAN                          \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x5)
> +#define CMD_ID_START_STREAM                             \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x7)
> +#define CMD_ID_STOP_STREAM                              \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x8)
> +
> +/* Stream Buffer Command */
> +#define CMD_ID_SEND_BUFFER                                \
> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_BUFFER | 0x1)
> +
> +/*
> + * @brief response ID format
> + *        resp_id is in the format of following type:
> + *        type: indicate command type, global/stream commands.
> + *        group: indicate the command group.
> + *        id: A unique command identification in one type and group.
> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
> + *        |      type       |      group      |       id       |
> + */
> +
> +#define RESP_GROUP_SHIFT (16)
> +#define RESP_GROUP_MASK  (0xff << RESP_GROUP_SHIFT)
> +
> +#define GET_RESP_GROUP_VALUE(resp_id)   \
> +	(((resp_id) & RESP_GROUP_MASK) >> \
> +	 RESP_GROUP_SHIFT)
> +#define GET_RESP_ID_VALUE(resp_id) ((resp_id) & 0xffff)
> +
> +#define RESP_GROUP_GENERAL (0x1 << RESP_GROUP_SHIFT)
> +#define RESP_GROUP_NOTIFICATION (0x3 << RESP_GROUP_SHIFT)
> +
> +/* General  Response */
> +#define RESP_ID_CMD_DONE (RESP_GROUP_GENERAL | 0x1)
> +
> +/* Notification */
> +#define RESP_ID_NOTI_FRAME_DONE (RESP_GROUP_NOTIFICATION | 0x1)
> +
> +#define CMD_STATUS_SUCCESS (0)
> +#define CMD_STATUS_FAIL (1)
> +#define CMD_STATUS_SKIPPED (2)

Again, please align macro bodies.

> +
> +#define ADDR_SPACE_TYPE_GPU_VA 4
> +
> +#define FW_MEMORY_POOL_SIZE (200 * 1024 * 1024)
> +
> +/*
> + * standard ISP mipicsi=>isp
> + */
> +#define MIPI0_ISP_PIPELINE_ID 0x5f91
> +
> +enum isp4fw_sensor_id {
> +	SENSOR_ID_ON_MIPI0  = 0,  /* Sensor id for ISP input from MIPI port 0 */
> +};
> +
> +enum isp4fw_stream_id {
> +	STREAM_ID_INVALID = -1, /* STREAM_ID_INVALID. */
> +	STREAM_ID_1 = 0,        /* STREAM_ID_1. */
> +	STREAM_ID_2 = 1,        /* STREAM_ID_2. */
> +	STREAM_ID_3 = 2,        /* STREAM_ID_3. */
> +	STREAM_ID_MAXIMUM       /* STREAM_ID_MAXIMUM. */
> +};
> +
> +enum isp4fw_image_format {
> +	IMAGE_FORMAT_NV12 = 1,              /* 4:2:0,semi-planar, 8-bit */
> +	IMAGE_FORMAT_YUV422INTERLEAVED = 7, /* interleave, 4:2:2, 8-bit */
> +};
> +
> +enum isp4fw_pipe_out_ch {
> +	ISP_PIPE_OUT_CH_PREVIEW = 0,
> +};
> +
> +enum isp4fw_yuv_range {
> +	ISP_YUV_RANGE_FULL = 0,     /* YUV value range in 0~255 */
> +	ISP_YUV_RANGE_NARROW = 1,   /* YUV value range in 16~235 */
> +	ISP_YUV_RANGE_MAX
> +};
> +
> +enum isp4fw_buffer_type {
> +	BUFFER_TYPE_PREVIEW = 8,
> +	BUFFER_TYPE_META_INFO = 10,
> +	BUFFER_TYPE_MEM_POOL = 15,
> +};
> +
> +enum isp4fw_buffer_status {
> +	BUFFER_STATUS_INVALID,  /* The buffer is INVALID */
> +	BUFFER_STATUS_SKIPPED,  /* The buffer is not filled with image data */
> +	BUFFER_STATUS_EXIST,    /* The buffer is exist and waiting for filled */
> +	BUFFER_STATUS_DONE,     /* The buffer is filled with image data */
> +	BUFFER_STATUS_LACK,     /* The buffer is unavailable */
> +	BUFFER_STATUS_DIRTY,    /* The buffer is dirty, probably caused by
> +				 * LMI leakage
> +				 */
> +	BUFFER_STATUS_MAX       /* The buffer STATUS_MAX */
> +};
> +
> +enum isp4fw_buffer_source {
> +	/* The buffer is from the stream buffer queue */
> +	BUFFER_SOURCE_STREAM,
> +};
> +
> +struct isp4fw_error_code {
> +	u32 code1;
> +	u32 code2;
> +	u32 code3;
> +	u32 code4;
> +	u32 code5;
> +};
> +
> +/*
> + * Command Structure for FW
> + */
> +
> +struct isp4fw_cmd {
> +	u32 cmd_seq_num;
> +	u32 cmd_id;
> +	u32 cmd_param[12];
> +	u16 cmd_stream_id;
> +	u8 cmd_silent_resp;
> +	u8 reserved;
> +	u32 cmd_check_sum;
> +};
> +
> +struct isp4fw_resp_cmd_done {
> +	/* The host2fw command seqNum.
> +	 * To indicate which command this response refer to.
> +	 */
> +	u32 cmd_seq_num;
> +	/* The host2fw command id for host double check. */
> +	u32 cmd_id;
> +	/* Indicate the command process status.
> +	 * 0 means success. 1 means fail. 2 means skipped
> +	 */
> +	u16 cmd_status;
> +	/* If the cmd_status is 1, that means the command is processed fail, */
> +	/* host can check the isp4fw_error_code to get the detail
> +	 * error information
> +	 */
> +	u16 isp4fw_error_code;
> +	/* The response payload will be in different struct type */
> +	/* according to different cmd done response. */
> +	u8 payload[36];
> +};
> +
> +struct isp4fw_resp_param_package {
> +	u32 package_addr_lo;	/* The low 32 bit addr of the pkg address. */
> +	u32 package_addr_hi;	/* The high 32 bit addr of the pkg address. */
> +	u32 package_size;	/* The total pkg size in bytes. */
> +	u32 package_check_sum;	/* The byte sum of the pkg. */
> +};
> +
> +struct isp4fw_resp {
> +	u32 resp_seq_num;
> +	u32 resp_id;
> +	union {
> +		struct isp4fw_resp_cmd_done cmd_done;
> +		struct isp4fw_resp_param_package frame_done;
> +		u32 resp_param[12];
> +	} param;
> +	u8  reserved[4];
> +	u32 resp_check_sum;
> +};
> +
> +struct isp4fw_mipi_pipe_path_cfg {
> +	u32 b_enable;
> +	enum isp4fw_sensor_id isp4fw_sensor_id;
> +};
> +
> +struct isp4fw_isp_pipe_path_cfg {
> +	u32  isp_pipe_id;	/* pipe ids for pipeline construction */
> +};
> +
> +struct isp4fw_isp_stream_cfg {
> +	/* Isp mipi path */
> +	struct isp4fw_mipi_pipe_path_cfg mipi_pipe_path_cfg;
> +	/* Isp pipe path */
> +	struct isp4fw_isp_pipe_path_cfg  isp_pipe_path_cfg;
> +	/* enable TNR */
> +	u32 b_enable_tnr;
> +	/* number of frame rta per-processing,
> +	 * set to 0 to use fw default value
> +	 */
> +	u32 rta_frames_per_proc;
> +};
> +
> +struct isp4fw_image_prop {
> +	enum isp4fw_image_format image_format;	/* Image format */
> +	u32 width;				/* Width */
> +	u32 height;				/* Height */
> +	u32 luma_pitch;				/* Luma pitch */
> +	u32 chroma_pitch;			/* Chrom pitch */
> +	enum isp4fw_yuv_range yuv_range;		/* YUV value range */
> +};
> +
> +struct isp4fw_buffer {
> +	/* A check num for debug usage, host need to */
> +	/* set the buf_tags to different number */
> +	u32 buf_tags;
> +	union {
> +		u32 value;
> +		struct {
> +			u32 space : 16;
> +			u32 vmid  : 16;
> +		} bit;
> +	} vmid_space;
> +	u32 buf_base_a_lo;		/* Low address of buffer A */
> +	u32 buf_base_a_hi;		/* High address of buffer A */
> +	u32 buf_size_a;			/* Buffer size of buffer A */
> +
> +	u32 buf_base_b_lo;		/* Low address of buffer B */
> +	u32 buf_base_b_hi;		/* High address of buffer B */
> +	u32 buf_size_b;			/* Buffer size of buffer B */
> +
> +	u32 buf_base_c_lo;		/* Low address of buffer C */
> +	u32 buf_base_c_hi;		/* High address of buffer C */
> +	u32 buf_size_c;			/* Buffer size of buffer C */
> +};
> +
> +struct isp4fw_buffer_meta_info {
> +	u32 enabled;					/* enabled flag */
> +	enum isp4fw_buffer_status status;		/* BufferStatus */
> +	struct isp4fw_error_code err;			/* err code */
> +	enum isp4fw_buffer_source source;		/* BufferSource */
> +	struct isp4fw_image_prop image_prop;		/* image_prop */
> +	struct isp4fw_buffer buffer;			/* buffer */
> +};
> +
> +struct isp4fw_meta_info {
> +	u32 poc;				/* frame id */
> +	u32 fc_id;				/* frame ctl id */
> +	u32 time_stamp_lo;			/* time_stamp_lo */
> +	u32 time_stamp_hi;			/* time_stamp_hi */
> +	struct isp4fw_buffer_meta_info preview;	/* preview BufferMetaInfo */
> +};
> +
> +struct isp4fw_cmd_send_buffer {
> +	enum isp4fw_buffer_type buffer_type;	/* buffer Type */
> +	struct isp4fw_buffer buffer;		/* buffer info */
> +};
> +
> +struct isp4fw_cmd_set_out_ch_prop {
> +	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
> +	struct isp4fw_image_prop image_prop;	/* image property */
> +};
> +
> +struct isp4fw_cmd_enable_out_ch {
> +	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
> +	u32 is_enable;			/* If enable channel or not */
> +};
> +
> +struct isp4fw_cmd_set_stream_cfg {
> +	struct isp4fw_isp_stream_cfg stream_cfg; /* stream path config */
> +};
> +
> +#endif
> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c
> new file mode 100644
> index 000000000000..0e1eb22a0de5
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_interface.c
> @@ -0,0 +1,1052 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/mutex.h>
> +
> +#include "amdgpu_object.h"
> +
> +#include "isp4_fw_cmd_resp.h"
> +#include "isp4_hw.h"
> +#include "isp4_hw_reg.h"
> +#include "isp4_interface.h"
> +
> +#define ISP4IF_FW_RESP_RB_IRQ_EN_MASK \
> +	(ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK |  \
> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK | \
> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK | \
> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK)
> +
> +struct isp4if_rb_config {
> +	const char *name;
> +	u32 index;
> +	u32 reg_rptr;
> +	u32 reg_wptr;
> +	u32 reg_base_lo;
> +	u32 reg_base_hi;
> +	u32 reg_size;
> +	u32 val_size;
> +	u64 base_mc_addr;
> +	void *base_sys_addr;
> +};
> +
> +/* FW cmd ring buffer configuration */
> +static struct isp4if_rb_config
> +	isp4if_cmd_rb_config[ISP4IF_STREAM_ID_MAX] = {
> +	{
> +		.name = "CMD_RB_GBL0",
> +		.index = 3,
> +		.reg_rptr = ISP_RB_RPTR4,
> +		.reg_wptr = ISP_RB_WPTR4,
> +		.reg_base_lo = ISP_RB_BASE_LO4,
> +		.reg_base_hi = ISP_RB_BASE_HI4,
> +		.reg_size = ISP_RB_SIZE4,
> +	},
> +	{
> +		.name = "CMD_RB_STR1",
> +		.index = 0,
> +		.reg_rptr = ISP_RB_RPTR1,
> +		.reg_wptr = ISP_RB_WPTR1,
> +		.reg_base_lo = ISP_RB_BASE_LO1,
> +		.reg_base_hi = ISP_RB_BASE_HI1,
> +		.reg_size = ISP_RB_SIZE1,
> +	},
> +	{
> +		.name = "CMD_RB_STR2",
> +		.index = 1,
> +		.reg_rptr = ISP_RB_RPTR2,
> +		.reg_wptr = ISP_RB_WPTR2,
> +		.reg_base_lo = ISP_RB_BASE_LO2,
> +		.reg_base_hi = ISP_RB_BASE_HI2,
> +		.reg_size = ISP_RB_SIZE2,
> +	},
> +	{
> +		.name = "CMD_RB_STR3",
> +		.index = 2,
> +		.reg_rptr = ISP_RB_RPTR3,
> +		.reg_wptr = ISP_RB_WPTR3,
> +		.reg_base_lo = ISP_RB_BASE_LO3,
> +		.reg_base_hi = ISP_RB_BASE_HI3,
> +		.reg_size = ISP_RB_SIZE3,
> +	},
> +};
> +
> +/* FW resp ring buffer configuration */
> +static struct isp4if_rb_config
> +	isp4if_resp_rb_config[ISP4IF_STREAM_ID_MAX] = {
> +	{
> +		.name = "RES_RB_GBL0",
> +		.index = 3,
> +		.reg_rptr = ISP_RB_RPTR12,
> +		.reg_wptr = ISP_RB_WPTR12,
> +		.reg_base_lo = ISP_RB_BASE_LO12,
> +		.reg_base_hi = ISP_RB_BASE_HI12,
> +		.reg_size = ISP_RB_SIZE12,
> +	},
> +	{
> +		.name = "RES_RB_STR1",
> +		.index = 0,
> +		.reg_rptr = ISP_RB_RPTR9,
> +		.reg_wptr = ISP_RB_WPTR9,
> +		.reg_base_lo = ISP_RB_BASE_LO9,
> +		.reg_base_hi = ISP_RB_BASE_HI9,
> +		.reg_size = ISP_RB_SIZE9,
> +	},
> +	{
> +		.name = "RES_RB_STR2",
> +		.index = 1,
> +		.reg_rptr = ISP_RB_RPTR10,
> +		.reg_wptr = ISP_RB_WPTR10,
> +		.reg_base_lo = ISP_RB_BASE_LO10,
> +		.reg_base_hi = ISP_RB_BASE_HI10,
> +		.reg_size = ISP_RB_SIZE10,
> +	},
> +	{
> +		.name = "RES_RB_STR3",
> +		.index = 2,
> +		.reg_rptr = ISP_RB_RPTR11,
> +		.reg_wptr = ISP_RB_WPTR11,
> +		.reg_base_lo = ISP_RB_BASE_LO11,
> +		.reg_base_hi = ISP_RB_BASE_HI11,
> +		.reg_size = ISP_RB_SIZE11,
> +	},
> +};
> +
> +/* FW log ring buffer configuration */
> +static struct isp4if_rb_config isp4if_log_rb_config = {
> +	.name = "LOG_RB",
> +	.index = 0,
> +	.reg_rptr = ISP_LOG_RB_RPTR0,
> +	.reg_wptr = ISP_LOG_RB_WPTR0,
> +	.reg_base_lo = ISP_LOG_RB_BASE_LO0,
> +	.reg_base_hi = ISP_LOG_RB_BASE_HI0,
> +	.reg_size = ISP_LOG_RB_SIZE0,
> +};
> +
> +static struct isp4if_gpu_mem_info *isp4if_gpu_mem_alloc(struct isp4_interface
> +							*ispif,
> +							u32 mem_size)
> +{
> +	struct isp4if_gpu_mem_info *mem_info;
> +	struct amdgpu_bo *bo = NULL;
> +	struct amdgpu_device *adev;
> +	struct device *dev;
> +

Extra newline.

> +	void *cpu_ptr;
> +	u64 gpu_addr;
> +	u32 ret;
> +
> +	dev = ispif->dev;
> +
> +	if (!mem_size)
> +		return NULL;
> +
> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
> +	if (!mem_info)
> +		return NULL;
> +
> +	adev = (struct amdgpu_device *)ispif->adev;

Why the cast?

adev isn't a great name here as it's usually used for struct acpi_devices.

> +	mem_info->mem_size = mem_size;
> +	mem_info->mem_align = ISP4IF_ISP_MC_ADDR_ALIGN;
> +	mem_info->mem_domain = AMDGPU_GEM_DOMAIN_GTT;
> +
> +	ret = amdgpu_bo_create_kernel(adev,
> +				      mem_info->mem_size,
> +				      mem_info->mem_align,
> +				      mem_info->mem_domain,
> +				      &bo,
> +				      &gpu_addr,
> +				      &cpu_ptr);

This fits on fewer lines.

> +

Extra newline.

> +	if (!cpu_ptr || ret) {
> +		dev_err(dev, "gpuvm buffer alloc fail, size %u\n", mem_size);
> +		kfree(mem_info);
> +		return NULL;
> +	}
> +
> +	mem_info->sys_addr = cpu_ptr;
> +	mem_info->gpu_mc_addr = gpu_addr;
> +	mem_info->mem_handle = (void *)bo;
> +
> +	return mem_info;
> +}
> +
> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
> +			       struct isp4if_gpu_mem_info *mem_info)
> +{
> +	struct device *dev = ispif->dev;
> +	struct amdgpu_bo *bo;
> +
> +	if (!mem_info) {
> +		dev_err(dev, "invalid mem_info\n");
> +		return -EINVAL;
> +	}
> +
> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;

Why do you need to cast here?

> +
> +	amdgpu_bo_free_kernel(&bo, &mem_info->gpu_mc_addr, &mem_info->sys_addr);
> +
> +	kfree(mem_info);
> +
> +	return 0;
> +}
> +
> +static int isp4if_dealloc_fw_gpumem(struct isp4_interface *ispif)
> +{
> +	int i;
> +
> +	if (ispif->fw_mem_pool) {
> +		isp4if_gpu_mem_free(ispif, ispif->fw_mem_pool);
> +		ispif->fw_mem_pool = NULL;
> +	}
> +
> +	if (ispif->fw_cmd_resp_buf) {
> +		isp4if_gpu_mem_free(ispif, ispif->fw_cmd_resp_buf);
> +		ispif->fw_cmd_resp_buf = NULL;
> +	}
> +
> +	if (ispif->fw_log_buf) {
> +		isp4if_gpu_mem_free(ispif, ispif->fw_log_buf);
> +		ispif->fw_log_buf = NULL;
> +	}
> +
> +	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
> +		if (ispif->metainfo_buf_pool[i]) {
> +			isp4if_gpu_mem_free(ispif, ispif->metainfo_buf_pool[i]);
> +			ispif->metainfo_buf_pool[i] = NULL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif)
> +{
> +	struct device *dev = ispif->dev;
> +	int i;

Unsigned int, please.

> +
> +	ispif->fw_mem_pool = isp4if_gpu_mem_alloc(ispif, FW_MEMORY_POOL_SIZE);
> +	if (!ispif->fw_mem_pool)
> +		goto error_no_memory;
> +
> +	ispif->fw_cmd_resp_buf =
> +		isp4if_gpu_mem_alloc(ispif, ISP4IF_RB_PMBMAP_MEM_SIZE);
> +	if (!ispif->fw_cmd_resp_buf)
> +		goto error_no_memory;
> +
> +	ispif->fw_log_buf =
> +		isp4if_gpu_mem_alloc(ispif, ISP4IF_FW_LOG_RINGBUF_SIZE);
> +	if (!ispif->fw_log_buf)
> +		goto error_no_memory;
> +
> +	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
> +		ispif->metainfo_buf_pool[i] =
> +			isp4if_gpu_mem_alloc(ispif,
> +					     ISP4IF_META_INFO_BUF_SIZE);
> +		if (!ispif->metainfo_buf_pool[i])
> +			goto error_no_memory;
> +	}
> +
> +	return 0;
> +
> +error_no_memory:
> +	dev_err(dev, "failed to allocate gpu memory");
> +	return -ENOMEM;
> +}
> +
> +static u32 isp4if_compute_check_sum(u8 *buf, u32 buf_size)
> +{
> +	u32 checksum = 0;
> +	u8 *surplus_ptr;
> +	u32 *buffer;
> +	u32 i;
> +
> +	buffer = (u32 *)buf;
> +	for (i = 0; i < buf_size / sizeof(u32); i++)
> +		checksum += buffer[i];
> +
> +	surplus_ptr = (u8 *)&buffer[i];
> +	/* add surplus data crc checksum */
> +	for (i = 0; i < buf_size % sizeof(u32); i++)
> +		checksum += surplus_ptr[i];
> +
> +	return checksum;
> +}
> +
> +void isp4if_clear_cmdq(struct isp4_interface *ispif)
> +{
> +	struct isp4if_cmd_element *buf_node = NULL;
> +	struct isp4if_cmd_element *tmp_node = NULL;
> +
> +	guard(mutex)(&ispif->cmdq_mutex);
> +
> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
> +		list_del(&buf_node->list);
> +		kfree(buf_node);
> +	}
> +}
> +
> +static bool isp4if_is_cmdq_rb_full(struct isp4_interface *ispif,
> +				   enum isp4if_stream_id cmd_buf_idx)
> +{
> +	struct isp4if_rb_config *rb_config;
> +	u32 rd_ptr, wr_ptr;
> +	u32 new_wr_ptr;
> +	u32 rreg;
> +	u32 wreg;
> +	u32 len;
> +
> +	rb_config = &isp4if_cmd_rb_config[cmd_buf_idx];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +	len = rb_config->val_size;
> +
> +	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
> +	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
> +
> +	new_wr_ptr = wr_ptr + sizeof(struct isp4fw_cmd);
> +
> +	if (wr_ptr >= rd_ptr) {
> +		if (new_wr_ptr < len) {
> +			return false;
> +		} else if (new_wr_ptr == len) {
> +			if (rd_ptr == 0)
> +				return true;
> +
> +			return false;
> +		}
> +
> +		new_wr_ptr -= len;
> +		if (new_wr_ptr < rd_ptr)
> +			return false;
> +
> +		return true;
> +	}
> +
> +	if (new_wr_ptr < rd_ptr)
> +		return false;
> +
> +	return true;
> +}
> +
> +static struct isp4if_cmd_element *
> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
> +			 struct isp4if_cmd_element *cmd_ele)
> +{
> +	struct isp4if_cmd_element *copy_command = NULL;
> +
> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
> +	if (!copy_command)
> +		return NULL;
> +
> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));

kmemdup()?

> +
> +	guard(mutex)(&ispif->cmdq_mutex);
> +
> +	list_add_tail(&copy_command->list, &ispif->cmdq);
> +
> +	return copy_command;
> +}
> +
> +struct isp4if_cmd_element *
> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
> +			u32 seq_num,
> +			u32 cmd_id)
> +{
> +	struct isp4if_cmd_element *buf_node = NULL;
> +	struct isp4if_cmd_element *tmp_node = NULL;
> +
> +	guard(mutex)(&ispif->cmdq_mutex);
> +
> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
> +		if (buf_node->seq_num == seq_num &&
> +		    buf_node->cmd_id == cmd_id) {
> +			list_del(&buf_node->list);
> +			return buf_node;
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
> +				    enum isp4if_stream_id stream,
> +				    struct isp4fw_cmd *cmd)
> +{
> +	struct isp4if_rb_config *rb_config;
> +	struct device *dev = ispif->dev;
> +	u64 mem_addr;
> +	u64 mem_sys;
> +	u32 wr_ptr;
> +	u32 rd_ptr;
> +	u32 rreg;
> +	u32 wreg;
> +	u32 len;
> +
> +	rb_config = &isp4if_cmd_rb_config[stream];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +	mem_sys = (u64)rb_config->base_sys_addr;
> +	mem_addr = rb_config->base_mc_addr;
> +	len = rb_config->val_size;
> +
> +	if (isp4if_is_cmdq_rb_full(ispif, stream)) {
> +		dev_err(dev, "fail no cmdslot (%d)\n", stream);
> +		return -EINVAL;
> +	}
> +
> +	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
> +	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
> +
> +	if (rd_ptr > len) {
> +		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
> +			stream, rd_ptr, len, wr_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (wr_ptr > len) {
> +		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
> +			stream, wr_ptr, len, rd_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (wr_ptr < rd_ptr) {
> +		mem_addr += wr_ptr;
> +
> +		memcpy((u8 *)(mem_sys + wr_ptr),
> +		       (u8 *)cmd, sizeof(struct isp4fw_cmd));
> +	} else {
> +		if ((len - wr_ptr) >= (sizeof(struct isp4fw_cmd))) {
> +			mem_addr += wr_ptr;
> +
> +			memcpy((u8 *)(mem_sys + wr_ptr),
> +			       (u8 *)cmd, sizeof(struct isp4fw_cmd));
> +		} else {
> +			u32 size;
> +			u8 *src;
> +
> +			src = (u8 *)cmd;
> +			size = len - wr_ptr;
> +
> +			memcpy((u8 *)(mem_sys + wr_ptr), src, size);
> +
> +			src += size;
> +			size = sizeof(struct isp4fw_cmd) - size;
> +			memcpy((u8 *)(mem_sys), src, size);
> +		}
> +	}
> +
> +	wr_ptr += sizeof(struct isp4fw_cmd);
> +	if (wr_ptr >= len)
> +		wr_ptr -= len;
> +
> +	isp4hw_wreg(ispif->mmio, wreg, wr_ptr);
> +
> +	return 0;
> +}
> +
> +static inline enum isp4if_stream_id isp4if_get_fw_stream(u32 cmd_id)
> +{
> +	return ISP4IF_STREAM_ID_1;
> +}
> +
> +static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
> +			      u32 cmd_id,
> +			      void *package,
> +			      u32 package_size,
> +			      wait_queue_head_t *wq,
> +			      u32 *wq_cond,
> +			      u32 *seq)
> +{
> +	enum isp4if_stream_id stream = isp4if_get_fw_stream(cmd_id);
> +	struct isp4if_cmd_element command_element = { 0 };
> +	struct isp4if_gpu_mem_info *gpu_mem = NULL;
> +	struct isp4if_cmd_element *cmd_ele = NULL;
> +	struct isp4if_rb_config *rb_config;
> +	struct device *dev = ispif->dev;
> +	struct isp4fw_cmd cmd = {0};
> +	u64 package_base = 0;
> +	u32 sleep_count;
> +	u32 seq_num;
> +	u32 rreg;
> +	u32 wreg;
> +	int ret;
> +
> +	if (package_size > sizeof(cmd.cmd_param)) {
> +		dev_err(dev, "fail pkgsize(%u)>%lu cmd:0x%x,stream %d\n",
> +			package_size, sizeof(cmd.cmd_param), cmd_id, stream);
> +		return -EINVAL;
> +	}
> +
> +	sleep_count = 0;
> +
> +	rb_config = &isp4if_resp_rb_config[stream];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +
> +	guard(mutex)(&ispif->isp4if_mutex);
> +
> +	while (1) {
> +		if (isp4if_is_cmdq_rb_full(ispif, stream)) {
> +			u32 rd_ptr, wr_ptr;
> +
> +			if (sleep_count < ISP4IF_MAX_SLEEP_COUNT) {
> +				msleep(ISP4IF_MAX_SLEEP_TIME);
> +				sleep_count++;
> +				continue;
> +			}
> +			rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
> +			wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
> +			dev_err(dev, "fail to get cmdq slot,stream (%d), rd %u, wr %u\n",
> +				stream, rd_ptr, wr_ptr);
> +			return -ETIMEDOUT;
> +		}
> +		break;
> +	}

read_poll_timeout()?

> +
> +	cmd.cmd_id = cmd_id;
> +	switch (stream) {
> +	case ISP4IF_STREAM_ID_GLOBAL:
> +		cmd.cmd_stream_id = (u16)STREAM_ID_INVALID;

Is there a need to cast here?

> +		break;
> +	case ISP4IF_STREAM_ID_1:
> +		cmd.cmd_stream_id = STREAM_ID_1;
> +		break;
> +	default:
> +		dev_err(dev, "fail bad stream id %d\n", stream);
> +		return -EINVAL;
> +	}
> +
> +	if (package && package_size)
> +		memcpy(cmd.cmd_param, package, package_size);
> +
> +	seq_num = ispif->host2fw_seq_num++;
> +	cmd.cmd_seq_num = seq_num;
> +	cmd.cmd_check_sum =
> +		isp4if_compute_check_sum((u8 *)&cmd, sizeof(cmd) - 4);
> +
> +	if (seq)
> +		*seq = seq_num;
> +	command_element.seq_num = seq_num;
> +	command_element.cmd_id = cmd_id;
> +	command_element.mc_addr = package_base;
> +	command_element.wq = wq;
> +	command_element.wq_cond = wq_cond;
> +	command_element.gpu_pkg = gpu_mem;
> +	command_element.stream = stream;
> +	/* only append the fw cmd to queue when its response needs to be
> +	 * waited for, currently there are only two such commands,
> +	 * disable channel and stop stream which are only sent after close
> +	 * camera
> +	 */
> +	if (wq && wq_cond) {
> +		cmd_ele = isp4if_append_cmd_2_cmdq(ispif, &command_element);
> +		if (!cmd_ele) {
> +			dev_err(dev, "fail for isp_append_cmd_2_cmdq\n");
> +			return -ENOMEM;
> +		}
> +	}
> +
> +	ret = isp4if_insert_isp_fw_cmd(ispif, stream, &cmd);
> +	if (ret) {
> +		dev_err(dev, "fail for insert_isp_fw_cmd camId (0x%08x)\n",
> +			cmd_id);
> +		if (cmd_ele) {
> +			isp4if_rm_cmd_from_cmdq(ispif, cmd_ele->seq_num,
> +						cmd_ele->cmd_id);
> +			kfree(cmd_ele);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int isp4if_send_buffer(struct isp4_interface *ispif,
> +			      struct isp4if_img_buf_info *buf_info)
> +{
> +	struct isp4fw_cmd_send_buffer cmd;

= { };

And you can remove the memset.

> +
> +	memset(&cmd, 0, sizeof(cmd));
> +	cmd.buffer_type = BUFFER_TYPE_PREVIEW;
> +	cmd.buffer.vmid_space.bit.vmid = 0;
> +	cmd.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA;
> +	isp4if_split_addr64(buf_info->planes[0].mc_addr,
> +			    &cmd.buffer.buf_base_a_lo,
> +			    &cmd.buffer.buf_base_a_hi);
> +	cmd.buffer.buf_size_a = buf_info->planes[0].len;
> +
> +	isp4if_split_addr64(buf_info->planes[1].mc_addr,
> +			    &cmd.buffer.buf_base_b_lo,
> +			    &cmd.buffer.buf_base_b_hi);
> +	cmd.buffer.buf_size_b = buf_info->planes[1].len;
> +
> +	isp4if_split_addr64(buf_info->planes[2].mc_addr,
> +			    &cmd.buffer.buf_base_c_lo,
> +			    &cmd.buffer.buf_base_c_hi);
> +	cmd.buffer.buf_size_c = buf_info->planes[2].len;
> +
> +	return isp4if_send_fw_cmd(ispif, CMD_ID_SEND_BUFFER, &cmd,
> +				  sizeof(cmd), NULL, NULL, NULL);
> +}
> +
> +static void isp4if_init_rb_config(struct isp4_interface *ispif,
> +				  struct isp4if_rb_config *rb_config)
> +{
> +	u32 lo;
> +	u32 hi;
> +
> +	isp4if_split_addr64(rb_config->base_mc_addr, &lo, &hi);
> +
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_rptr, 0x0);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_wptr, 0x0);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_base_lo, lo);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_base_hi, hi);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +		    rb_config->reg_size, rb_config->val_size);
> +}
> +
> +static int isp4if_fw_init(struct isp4_interface *ispif)
> +{
> +	struct isp4if_rb_config *rb_config;
> +	u32 offset;
> +	int i;
> +
> +	/* initialize CMD_RB streams */
> +	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
> +		rb_config = (isp4if_cmd_rb_config + i);
> +		offset = ispif->aligned_rb_chunk_size *
> +			 (rb_config->index + ispif->cmd_rb_base_index);
> +
> +		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
> +		rb_config->base_sys_addr =
> +			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
> +		rb_config->base_mc_addr =
> +			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
> +
> +		isp4if_init_rb_config(ispif, rb_config);
> +	}
> +
> +	/* initialize RESP_RB streams */
> +	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
> +		rb_config = (isp4if_resp_rb_config + i);
> +		offset = ispif->aligned_rb_chunk_size *
> +			 (rb_config->index + ispif->resp_rb_base_index);
> +
> +		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
> +		rb_config->base_sys_addr =
> +			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
> +		rb_config->base_mc_addr =
> +			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
> +
> +		isp4if_init_rb_config(ispif, rb_config);
> +	}
> +
> +	/* initialize LOG_RB stream */
> +	rb_config = &isp4if_log_rb_config;
> +	rb_config->val_size = ISP4IF_FW_LOG_RINGBUF_SIZE;
> +	rb_config->base_mc_addr = ispif->fw_log_buf->gpu_mc_addr;
> +	rb_config->base_sys_addr = ispif->fw_log_buf->sys_addr;
> +
> +	isp4if_init_rb_config(ispif, rb_config);
> +
> +	return 0;
> +}
> +
> +static int isp4if_wait_fw_ready(struct isp4_interface *ispif,
> +				u32 isp_status_addr)
> +{
> +	struct device *dev = ispif->dev;
> +	u32 fw_ready_timeout;
> +	u32 timeout_ms = 100;
> +	u32 interval_ms = 1;
> +	u32 timeout = 0;
> +	u32 reg_val;
> +
> +	fw_ready_timeout = timeout_ms / interval_ms;
> +
> +	/* wait for FW initialize done! */
> +	while (timeout < fw_ready_timeout) {
> +		reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif),
> +				      isp_status_addr);
> +		if (reg_val & ISP_STATUS__CCPU_REPORT_MASK)
> +			return 0;
> +
> +		msleep(interval_ms);
> +		timeout++;
> +	}

read_poll_timeout()?

> +
> +	dev_err(dev, "ISP CCPU FW boot failed\n");
> +
> +	return -ETIME;
> +}
> +
> +static void isp4if_enable_ccpu(struct isp4_interface *ispif)
> +{
> +	u32 reg_val;
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
> +	reg_val &= (~ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
> +
> +	usleep_range(100, 150);
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
> +	reg_val &= (~ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK);
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
> +}
> +
> +static void isp4if_disable_ccpu(struct isp4_interface *ispif)
> +{
> +	u32 reg_val;
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
> +	reg_val |= ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK;
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
> +
> +	usleep_range(100, 150);
> +
> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
> +	reg_val |= ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK;
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
> +}
> +
> +static int isp4if_fw_boot(struct isp4_interface *ispif)
> +{
> +	struct device *dev = ispif->dev;
> +
> +	if (ispif->status != ISP4IF_STATUS_PWR_ON) {
> +		dev_err(dev, "invalid isp power status %d\n", ispif->status);
> +		return -EINVAL;
> +	}
> +
> +	isp4if_disable_ccpu(ispif);
> +
> +	isp4if_fw_init(ispif);
> +
> +	/* clear ccpu status */
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_STATUS, 0x0);
> +
> +	isp4if_enable_ccpu(ispif);
> +
> +	if (isp4if_wait_fw_ready(ispif, ISP_STATUS)) {
> +		isp4if_disable_ccpu(ispif);
> +		return -EINVAL;
> +	}
> +
> +	/* enable interrupts */
> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SYS_INT0_EN,
> +		    ISP4IF_FW_RESP_RB_IRQ_EN_MASK);
> +
> +	ispif->status = ISP4IF_STATUS_FW_RUNNING;
> +
> +	dev_dbg(dev, "ISP CCPU FW boot success\n");
> +
> +	return 0;
> +}
> +
> +int isp4if_f2h_resp(struct isp4_interface *ispif,
> +		    enum isp4if_stream_id stream,
> +		    void *resp)
> +{
> +	struct isp4fw_resp *response = resp;
> +	struct isp4if_rb_config *rb_config;
> +	struct device *dev = ispif->dev;
> +	u32 rd_ptr_dbg;
> +	u32 wr_ptr_dbg;
> +	void *mem_sys;
> +	u64 mem_addr;
> +	u32 checksum;
> +	u32 rd_ptr;
> +	u32 wr_ptr;
> +	u32 rreg;
> +	u32 wreg;
> +	u32 len;
> +
> +	rb_config = &isp4if_resp_rb_config[stream];
> +	rreg = rb_config->reg_rptr;
> +	wreg = rb_config->reg_wptr;
> +	mem_sys = rb_config->base_sys_addr;
> +	mem_addr = rb_config->base_mc_addr;
> +	len = rb_config->val_size;
> +
> +	rd_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), rreg);
> +	wr_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), wreg);
> +	rd_ptr_dbg = rd_ptr;
> +	wr_ptr_dbg = wr_ptr;
> +
> +	if (rd_ptr > len) {
> +		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
> +			stream, rd_ptr, len, wr_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (wr_ptr > len) {
> +		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
> +			stream, wr_ptr, len, rd_ptr);
> +		return -EINVAL;
> +	}
> +
> +	if (rd_ptr < wr_ptr) {
> +		if ((wr_ptr - rd_ptr) >= (sizeof(struct isp4fw_resp))) {
> +			memcpy((u8 *)response, (u8 *)mem_sys + rd_ptr,
> +			       sizeof(struct isp4fw_resp));
> +
> +			rd_ptr += sizeof(struct isp4fw_resp);
> +			if (rd_ptr < len) {
> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +					    rreg, rd_ptr);
> +			} else {
> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
> +					stream, rd_ptr, len, wr_ptr);
> +				return -EINVAL;
> +			}
> +
> +		} else {
> +			dev_err(dev, "sth wrong with wptr and rptr\n");
> +			return -EINVAL;
> +		}
> +	} else if (rd_ptr > wr_ptr) {
> +		u32 size;
> +		u8 *dst;
> +
> +		dst = (u8 *)response;
> +
> +		size = len - rd_ptr;
> +		if (size > sizeof(struct isp4fw_resp)) {
> +			mem_addr += rd_ptr;
> +			memcpy((u8 *)response,
> +			       (u8 *)(mem_sys) + rd_ptr,
> +			       sizeof(struct isp4fw_resp));
> +			rd_ptr += sizeof(struct isp4fw_resp);
> +			if (rd_ptr < len) {
> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +					    rreg, rd_ptr);
> +			} else {
> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
> +					stream, rd_ptr, len, wr_ptr);
> +				return -EINVAL;
> +			}
> +
> +		} else {
> +			if ((size + wr_ptr) < (sizeof(struct isp4fw_resp))) {
> +				dev_err(dev, "sth wrong with wptr and rptr1\n");
> +				return -EINVAL;
> +			}
> +
> +			memcpy(dst, (u8 *)(mem_sys) + rd_ptr, size);
> +
> +			dst += size;
> +			size = sizeof(struct isp4fw_resp) - size;
> +			if (size)
> +				memcpy(dst, (u8 *)(mem_sys), size);
> +			rd_ptr = size;
> +			if (rd_ptr < len) {
> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
> +					    rreg, rd_ptr);
> +			} else {
> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
> +					stream, rd_ptr, len, wr_ptr);
> +				return -EINVAL;
> +			}
> +		}
> +	} else {
> +		return -ETIME;
> +	}
> +
> +	checksum = isp4if_compute_check_sum((u8 *)response,
> +					    (sizeof(struct isp4fw_resp) - 4));

Redundant parentheses again.

> +
> +	if (checksum != response->resp_check_sum) {
> +		dev_err(dev, "resp checksum 0x%x,should 0x%x,rptr %u,wptr %u\n",
> +			checksum, response->resp_check_sum,
> +			rd_ptr_dbg, wr_ptr_dbg);
> +
> +		dev_err(dev, "(%u), seqNo %u, resp_id (0x%x)\n",
> +			stream,
> +			response->resp_seq_num,
> +			response->resp_id);

Fits on fewer lines.

> +
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int isp4if_send_command(struct isp4_interface *ispif,
> +			u32 cmd_id,
> +			void *package,
> +			u32 package_size)

Ditto.

> +{
> +	return isp4if_send_fw_cmd(ispif,
> +				  cmd_id, package,
> +				  package_size, NULL, NULL, NULL);

Ditto.

> +}
> +
> +int isp4if_send_command_sync(struct isp4_interface *ispif,
> +			     u32 cmd_id,
> +			     void *package,
> +			     u32 package_size,
> +			     u32 timeout)

Ditto.

> +{
> +	struct device *dev = ispif->dev;
> +	DECLARE_WAIT_QUEUE_HEAD(cmd_wq);
> +	u32 wq_cond = 0;
> +	int ret;
> +	u32 seq;
> +
> +	ret = isp4if_send_fw_cmd(ispif,
> +				 cmd_id, package,

Ditto.

> +				 package_size, &cmd_wq, &wq_cond, &seq);
> +
> +	if (ret) {
> +		dev_err(dev, "send fw cmd fail %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = wait_event_timeout(cmd_wq, wq_cond != 0,
> +				 msecs_to_jiffies(timeout));
> +

Extra newline.

> +	/* timeout occurred */

Redundant comment.

> +	if (ret == 0) {
> +		struct isp4if_cmd_element *ele;
> +
> +		ele = isp4if_rm_cmd_from_cmdq(ispif, seq, cmd_id);
> +		kfree(ele);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +void isp4if_clear_bufq(struct isp4_interface *ispif)
> +{
> +	struct isp4if_img_buf_node *buf_node = NULL;
> +	struct isp4if_img_buf_node *tmp_node = NULL;
> +
> +	guard(mutex)(&ispif->bufq_mutex);
> +
> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->bufq,
> +				 node) {

Please rewrap.

> +		list_del(&buf_node->node);
> +		kfree(buf_node);
> +	}
> +}
> +
> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node)
> +{
> +	kfree(buf_node);
> +}
> +
> +struct isp4if_img_buf_node *
> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info)
> +{
> +	struct isp4if_img_buf_node *node = NULL;
> +
> +	node = kmalloc(sizeof(*node), GFP_KERNEL);
> +	if (node)
> +		node->buf_info = *buf_info;
> +
> +	return node;
> +};
> +
> +struct isp4if_img_buf_node *
> +isp4if_dequeue_buffer(struct isp4_interface *ispif)
> +{
> +	struct isp4if_img_buf_node *buf_node = NULL;
> +
> +	guard(mutex)(&ispif->bufq_mutex);
> +
> +	buf_node = list_first_entry_or_null(&ispif->bufq,
> +					    typeof(*buf_node),
> +					    node);

Ditto.

> +	if (buf_node)
> +		list_del(&buf_node->node);
> +
> +	return buf_node;
> +}
> +
> +int isp4if_queue_buffer(struct isp4_interface *ispif,
> +			struct isp4if_img_buf_node *buf_node)
> +{
> +	int ret;
> +
> +	ret = isp4if_send_buffer(ispif, &buf_node->buf_info);
> +	if (ret)
> +		return ret;
> +
> +	guard(mutex)(&ispif->bufq_mutex);
> +
> +	list_add_tail(&buf_node->node, &ispif->bufq);
> +
> +	return 0;
> +}
> +
> +int isp4if_stop(struct isp4_interface *ispif)
> +{
> +	isp4if_disable_ccpu(ispif);
> +
> +	isp4if_dealloc_fw_gpumem(ispif);
> +
> +	return 0;
> +}
> +
> +int isp4if_start(struct isp4_interface *ispif)
> +{
> +	int ret;
> +
> +	ret = isp4if_alloc_fw_gpumem(ispif);
> +	if (ret)
> +		goto failed_gpumem_alloc;
> +
> +	ret = isp4if_fw_boot(ispif);
> +	if (ret)
> +		goto failed_fw_boot;
> +
> +	return 0;
> +
> +failed_gpumem_alloc:
> +	return -ENOMEM;

No label needed for this.

> +
> +failed_fw_boot:
> +	isp4if_dealloc_fw_gpumem(ispif);
> +	return ret;
> +}
> +
> +int isp4if_deinit(struct isp4_interface *ispif)
> +{
> +	isp4if_clear_cmdq(ispif);
> +
> +	isp4if_clear_bufq(ispif);
> +
> +	mutex_destroy(&ispif->cmdq_mutex);
> +	mutex_destroy(&ispif->bufq_mutex);
> +	mutex_destroy(&ispif->isp4if_mutex);
> +
> +	return 0;
> +}
> +
> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
> +		void *amdgpu_dev, void __iomem *isp_mmip)
> +{
> +	ispif->dev = dev;
> +	ispif->adev = amdgpu_dev;
> +	ispif->mmio = isp_mmip;
> +
> +	ispif->cmd_rb_base_index = 0;
> +	ispif->resp_rb_base_index = ISP4IF_RESP_CHAN_TO_RB_OFFSET - 1;
> +	ispif->aligned_rb_chunk_size = ISP4IF_RB_PMBMAP_MEM_CHUNK & 0xffffffc0;
> +
> +	mutex_init(&ispif->cmdq_mutex); /* used for cmdq access */
> +	mutex_init(&ispif->bufq_mutex); /* used for bufq access */
> +	mutex_init(&ispif->isp4if_mutex); /* used for commands sent to ispfw */
> +
> +	INIT_LIST_HEAD(&ispif->cmdq);
> +	INIT_LIST_HEAD(&ispif->bufq);
> +
> +	return 0;
> +}
> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/drivers/media/platform/amd/isp4/isp4_interface.h
> new file mode 100644
> index 000000000000..b2ca147b78b6
> --- /dev/null
> +++ b/drivers/media/platform/amd/isp4/isp4_interface.h
> @@ -0,0 +1,164 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
> + */
> +
> +#ifndef _ISP4_INTERFACE_
> +#define _ISP4_INTERFACE_
> +
> +#define ISP4IF_RB_MAX (25)
> +#define ISP4IF_RESP_CHAN_TO_RB_OFFSET (9)
> +#define ISP4IF_RB_PMBMAP_MEM_SIZE (16 * 1024 * 1024 - 1)
> +#define ISP4IF_RB_PMBMAP_MEM_CHUNK (ISP4IF_RB_PMBMAP_MEM_SIZE \
> +	/ (ISP4IF_RB_MAX - 1))
> +#define ISP4IF_ISP_MC_ADDR_ALIGN (1024 * 32)
> +#define ISP4IF_HOST2FW_COMMAND_SIZE (sizeof(struct isp4fw_cmd))
> +#define ISP4IF_FW_CMD_BUF_COUNT 4
> +#define ISP4IF_FW_RESP_BUF_COUNT 4
> +#define ISP4IF_MAX_NUM_HOST2FW_COMMAND (40)
> +#define ISP4IF_FW_CMD_BUF_SIZE (ISP4IF_MAX_NUM_HOST2FW_COMMAND \
> +	* ISP4IF_HOST2FW_COMMAND_SIZE)
> +#define ISP4IF_MAX_SLEEP_COUNT (10)
> +#define ISP4IF_MAX_SLEEP_TIME (33)
> +
> +#define ISP4IF_META_INFO_BUF_SIZE ALIGN(sizeof(struct isp4fw_meta_info), 0x8000)
> +#define ISP4IF_MAX_STREAM_META_BUF_COUNT 6
> +
> +#define ISP4IF_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
> +
> +#define ISP4IF_MAX_CMD_RESPONSE_BUF_SIZE (4 * 1024)
> +
> +#define GET_ISP4IF_REG_BASE(ispif) (((ispif))->mmio)
> +
> +enum isp4if_stream_id {
> +	ISP4IF_STREAM_ID_GLOBAL = 0,
> +	ISP4IF_STREAM_ID_1 = 1,
> +	ISP4IF_STREAM_ID_MAX = 4
> +};
> +
> +enum isp4if_status {
> +	ISP4IF_STATUS_PWR_OFF,
> +	ISP4IF_STATUS_PWR_ON,
> +	ISP4IF_STATUS_FW_RUNNING,
> +	ISP4IF_FSM_STATUS_MAX
> +};
> +
> +struct isp4if_gpu_mem_info {
> +	u32	mem_domain;
> +	u64	mem_size;
> +	u32	mem_align;
> +	u64	gpu_mc_addr;
> +	void	*sys_addr;
> +	void	*mem_handle;
> +};
> +
> +struct isp4if_img_buf_info {
> +	struct {
> +		void *sys_addr;
> +		u64 mc_addr;
> +		u32 len;
> +	} planes[3];
> +};
> +
> +struct isp4if_img_buf_node {
> +	struct list_head node;
> +	struct isp4if_img_buf_info buf_info;
> +};
> +
> +struct isp4if_cmd_element {
> +	struct list_head list;
> +	u32 seq_num;
> +	u32 cmd_id;
> +	enum isp4if_stream_id stream;
> +	u64 mc_addr;
> +	wait_queue_head_t *wq;
> +	u32 *wq_cond;
> +	struct isp4if_gpu_mem_info *gpu_pkg;
> +};
> +
> +struct isp4_interface {
> +	struct amdgpu_device *adev;
> +
> +	struct device *dev;
> +	void __iomem *mmio;
> +
> +	struct mutex cmdq_mutex; /* used for cmdq access */
> +	struct mutex bufq_mutex; /* used for bufq access */
> +	struct mutex isp4if_mutex; /* used to send fw cmd and read fw log */
> +
> +	struct list_head cmdq; /* commands sent to fw */
> +	struct list_head bufq; /* buffers sent to fw */
> +
> +	enum isp4if_status status;
> +	u32 host2fw_seq_num;
> +
> +	/* FW ring buffer configs */
> +	u32 cmd_rb_base_index;
> +	u32 resp_rb_base_index;
> +	u32 aligned_rb_chunk_size;
> +
> +	/* ISP fw buffers */
> +	struct isp4if_gpu_mem_info *fw_log_buf;
> +	struct isp4if_gpu_mem_info *fw_cmd_resp_buf;
> +	struct isp4if_gpu_mem_info *fw_mem_pool;
> +	struct isp4if_gpu_mem_info *
> +		metainfo_buf_pool[ISP4IF_MAX_STREAM_META_BUF_COUNT];
> +};
> +
> +static inline void isp4if_split_addr64(u64 addr, u32 *lo, u32 *hi)
> +{
> +	if (lo)
> +		*lo = (u32)(addr & 0xffffffff);

Redundant and and cast, too.

> +	if (hi)
> +		*hi = (u32)(addr >> 32);

Redundant cast.

> +}
> +
> +static inline u64 isp4if_join_addr64(u32 lo, u32 hi)
> +{
> +	return (((u64)hi) << 32) | (u64)lo;
> +}
> +
> +int isp4if_f2h_resp(struct isp4_interface *ispif,
> +		    enum isp4if_stream_id stream,
> +		    void *response);
> +
> +int isp4if_send_command(struct isp4_interface *ispif,
> +			u32 cmd_id,
> +			void *package,
> +			u32 package_size);
> +
> +int isp4if_send_command_sync(struct isp4_interface *ispif,
> +			     u32 cmd_id,
> +			     void *package,
> +			     u32 package_size,
> +			     u32 timeout);
> +
> +struct isp4if_cmd_element *
> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
> +			u32 seq_num,
> +			u32 cmd_id);
> +
> +void isp4if_clear_cmdq(struct isp4_interface *ispif);
> +
> +void isp4if_clear_bufq(struct isp4_interface *ispif);
> +
> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node);
> +
> +struct isp4if_img_buf_node *
> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info);
> +
> +struct isp4if_img_buf_node *isp4if_dequeue_buffer(struct isp4_interface *ispif);
> +
> +int isp4if_queue_buffer(struct isp4_interface *ispif,
> +			struct isp4if_img_buf_node *buf_node);
> +
> +int isp4if_stop(struct isp4_interface *ispif);
> +
> +int isp4if_start(struct isp4_interface *ispif);
> +
> +int isp4if_deinit(struct isp4_interface *ispif);
> +
> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
> +		void *amdgpu_dev, void __iomem *isp_mmip);
> +
> +#endif

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-06-18  9:19 ` [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy Bin Du
  2025-07-28  6:33   ` Sakari Ailus
@ 2025-07-28  7:28   ` Sakari Ailus
  2025-07-31  9:31     ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sakari Ailus @ 2025-07-28  7:28 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Hi Bin,

On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
> +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;
> +};

One more thing. Is there an endianness issue here?

Overall the CPU endianness may be big or little while the device endianness
is little, presumably. You should use __le* types and functions to convert
the endianness when dealing with the messages to and from the device.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver
  2025-07-28  5:54   ` Sakari Ailus
@ 2025-07-28  9:00     ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-28  9:00 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Askari Alius for your careful review.

On 7/28/2025 1:54 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Wed, Jun 18, 2025 at 05:19:52PM +0800, Bin Du wrote:
>> 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
> 
> You could rewrap the text and use the full lines here -- up to 75
> characters per line.
> 
Sure, will do in the next patch>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   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 <bin.du@amd.com>
>> +M:	Nirujogi Pratap <pratap.nirujogi@amd.com>
>> +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 <Felix.Kuehling@amd.com>
>>   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
> 
> Do you need all these three? Most drivers need only one.
> 
After double check, yes, none of theam are used in our code, will remove 
them and also the header files included>> +	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
> 
> Uh... does the driver actually depend on this?
> 
Yes, other comments also mentioned this, will update in the next patch>> +
>> +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 <linux/pm_runtime.h>
>> +#include <linux/vmalloc.h>
>> +#include <media/v4l2-ioctl.h>
> 
> Alphabetic order, please.
> 
Sorry, seems it's already in alphabetic order, an example in 
drivers/media/v4l2-core/v4l2-ioctl.c is like
#include <linux/v4l2-subdev.h>
#include <linux/videodev2.h>

#include <media/media-device.h> /* for media_set_bus_info() */
#include <media/v4l2-common.h>
Suppose i can add an empty line before #include <media/v4l2-ioctl.h>>> +
>> +#include "isp4.h"
>> +
>> +#define VIDEO_BUF_NUM 5
> 
> Unused.
> 
Yes, other comments also mentioned this, will remove it in the next 
patch>> +
>> +#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))
> 
> No need for the cast.
> 
Sure, will remove the cast in the next patch>> +
>> +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;
>> +
> 
> Extra newline.
> 
Yes, other comments also mentioned this, will remove it in the next 
patch>> +	int i, irq, ret;
> 
> unsigned int i?
> 
Weired, no compile warning about this, will change it to size_t i in the 
next patch.>> +
>> +	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");
> 
> Please leave this out.
> 
Yes, other comments also mentioned this, will remove it in the next 
patch>> +
>> +	/* 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");
> 
> This doesn't seem useful.
> 
Yes, other comments also mentioned this, will remove it in the next 
patch>> +
>> +	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);
> 
> You'll need to enable runtime PM before registering any interfaces on UAPI.
> Same goes for setting driver data for the device.
> 
Sure, will modify in the next patch>> +
>> +	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");
> 
> I'd say this is redundant.
> 
Yes, other comments also mentioned this, will remove it in the next 
patch>> +}
>> +
>> +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 <bin.du@amd.com>");
>> +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
>> +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 <linux/mutex.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/videobuf2-memops.h>
>> +#include <media/videobuf2-vmalloc.h>
>> +
>> +#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 */
> 
> Use the same name as for the macro here, please.
> 
Yes, other comments also mentioned this, will modify in the next patch

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware
  2025-07-28  5:57   ` Sakari Ailus
@ 2025-07-28  9:24     ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-28  9:24 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Sakari Ailus for the review.

On 7/28/2025 1:57 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Wed, Jun 18, 2025 at 05:19:53PM +0800, Bin Du wrote:
>> Low level functions for access the registers and mapping to their ranges.
>> This change also includes register definitions for ring buffer used to
>> communicate with ISP Firmware.
>> Ring buffer is the communication interface between driver and ISP Firmware.
>> Command and responses are exchanged through the ring buffer.
> 
> Please rewrap this, the third line could well be longer.
> 
Sure, will do in the next patch

>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   drivers/media/platform/amd/isp4/Makefile      |   3 +-
>>   drivers/media/platform/amd/isp4/isp4_hw.c     |  46 +++++++
>>   drivers/media/platform/amd/isp4/isp4_hw.h     |  14 +++
>>   drivers/media/platform/amd/isp4/isp4_hw_reg.h | 116 ++++++++++++++++++
>>   4 files changed, 178 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.c
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw.h
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_hw_reg.h
>>
>> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
>> index e9e84160517d..8ca1c4dfe246 100644
>> --- a/drivers/media/platform/amd/isp4/Makefile
>> +++ b/drivers/media/platform/amd/isp4/Makefile
>> @@ -3,7 +3,8 @@
>>   # Copyright (C) 2025 Advanced Micro Devices, Inc.
>>   
>>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>> -amd_capture-objs := isp4.o
>> +amd_capture-objs := isp4.o	\
>> +			isp4_hw.o	\
>>   
>>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>>   ccflags-y += -I$(srctree)/include
>> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.c b/drivers/media/platform/amd/isp4/isp4_hw.c
>> new file mode 100644
>> index 000000000000..e5315330a514
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_hw.c
>> @@ -0,0 +1,46 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/io.h>
>> +#include <linux/types.h>
>> +
>> +#include "isp4_hw.h"
>> +#include "isp4_hw_reg.h"
>> +
>> +#define RMMIO_SIZE 524288
>> +
>> +u32 isp4hw_rreg(void __iomem *base, u32 reg)
>> +{
>> +	void __iomem *reg_addr;
>> +
>> +	if (reg >= RMMIO_SIZE)
>> +		return RREG_FAILED_VAL;
>> +
>> +	if (reg < ISP_MIPI_PHY0_REG0)
>> +		reg_addr = base + reg;
>> +	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
>> +		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
> 
> Redundant parentheses.
> 
Sure, will remove it in the next patch

>> +	else
>> +		return RREG_FAILED_VAL;
>> +
>> +	return readl(reg_addr);
>> +};
>> +
>> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val)
>> +{
>> +	void __iomem *reg_addr;
>> +
>> +	if (reg >= RMMIO_SIZE)
>> +		return;
>> +
>> +	if (reg < ISP_MIPI_PHY0_REG0)
>> +		reg_addr = base + reg;
>> +	else if (reg <= ISP_MIPI_PHY0_REG0 + ISP_MIPI_PHY0_SIZE)
>> +		reg_addr = base + (reg - ISP_MIPI_PHY0_REG0);
> 
> Ditto.
> 
Sure, will remove it in the next patch

>> +	else
>> +		return;
>> +
>> +	writel(val, reg_addr);
>> +};
>> diff --git a/drivers/media/platform/amd/isp4/isp4_hw.h b/drivers/media/platform/amd/isp4/isp4_hw.h
>> new file mode 100644
>> index 000000000000..072d135b9e3a
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_hw.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_HW_H_
>> +#define _ISP4_HW_H_
>> +
>> +#define RREG_FAILED_VAL 0xFFFFFFFF
>> +
>> +u32 isp4hw_rreg(void __iomem *base, u32 reg);
>> +void isp4hw_wreg(void __iomem *base, u32 reg, u32 val);
>> +
>> +#endif
>> diff --git a/drivers/media/platform/amd/isp4/isp4_hw_reg.h b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
>> new file mode 100644
>> index 000000000000..b11f12ba6c56
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_hw_reg.h
>> @@ -0,0 +1,116 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_HW_REG_H_
>> +#define _ISP4_HW_REG_H_
>> +
>> +#define ISP_SOFT_RESET		0x62000
>> +#define ISP_SYS_INT0_EN		0x62010
>> +#define ISP_SYS_INT0_STATUS	0x62014
>> +#define ISP_SYS_INT0_ACK	0x62018
>> +#define ISP_CCPU_CNTL		0x62054
>> +#define ISP_STATUS		0x62058
>> +#define ISP_LOG_RB_BASE_LO0	0x62148
>> +#define ISP_LOG_RB_BASE_HI0	0x6214C
> 
> Lower case hexadecimals, please.
> 
Sure, will modify in the next patch

>> +#define ISP_LOG_RB_SIZE0	0x62150
>> +#define ISP_LOG_RB_RPTR0	0x62154
>> +#define ISP_LOG_RB_WPTR0	0x62158
>> +#define ISP_RB_BASE_LO1		0x62170
>> +#define ISP_RB_BASE_HI1		0x62174
>> +#define ISP_RB_SIZE1		0x62178
>> +#define ISP_RB_RPTR1		0x6217C
>> +#define ISP_RB_WPTR1		0x62180
>> +#define ISP_RB_BASE_LO2		0x62184
>> +#define ISP_RB_BASE_HI2		0x62188
>> +#define ISP_RB_SIZE2		0x6218C
>> +#define ISP_RB_RPTR2		0x62190
>> +#define ISP_RB_WPTR2		0x62194
>> +#define ISP_RB_BASE_LO3		0x62198
>> +#define ISP_RB_BASE_HI3		0x6219C
>> +#define ISP_RB_SIZE3		0x621A0
>> +#define ISP_RB_RPTR3		0x621A4
>> +#define ISP_RB_WPTR3		0x621A8
>> +#define ISP_RB_BASE_LO4		0x621AC
>> +#define ISP_RB_BASE_HI4		0x621B0
>> +#define ISP_RB_SIZE4		0x621B4
>> +#define ISP_RB_RPTR4		0x621B8
>> +#define ISP_RB_WPTR4		0x621BC
>> +#define ISP_RB_BASE_LO5		0x621C0
>> +#define ISP_RB_BASE_HI5		0x621C4
>> +#define ISP_RB_SIZE5		0x621C8
>> +#define ISP_RB_RPTR5		0x621CC
>> +#define ISP_RB_WPTR5		0x621D0
>> +#define ISP_RB_BASE_LO6		0x621D4
>> +#define ISP_RB_BASE_HI6		0x621D8
>> +#define ISP_RB_SIZE6		0x621DC
>> +#define ISP_RB_RPTR6		0x621E0
>> +#define ISP_RB_WPTR6		0x621E4
>> +#define ISP_RB_BASE_LO7		0x621E8
>> +#define ISP_RB_BASE_HI7		0x621EC
>> +#define ISP_RB_SIZE7		0x621F0
>> +#define ISP_RB_RPTR7		0x621F4
>> +#define ISP_RB_WPTR7		0x621F8
>> +#define ISP_RB_BASE_LO8		0x621FC
>> +#define ISP_RB_BASE_HI8		0x62200
>> +#define ISP_RB_SIZE8		0x62204
>> +#define ISP_RB_RPTR8		0x62208
>> +#define ISP_RB_WPTR8		0x6220C
>> +#define ISP_RB_BASE_LO9		0x62210
>> +#define ISP_RB_BASE_HI9		0x62214
>> +#define ISP_RB_SIZE9		0x62218
>> +#define ISP_RB_RPTR9		0x6221C
>> +#define ISP_RB_WPTR9		0x62220
>> +#define ISP_RB_BASE_LO10	0x62224
>> +#define ISP_RB_BASE_HI10	0x62228
>> +#define ISP_RB_SIZE10		0x6222C
>> +#define ISP_RB_RPTR10		0x62230
>> +#define ISP_RB_WPTR10		0x62234
>> +#define ISP_RB_BASE_LO11	0x62238
>> +#define ISP_RB_BASE_HI11	0x6223C
>> +#define ISP_RB_SIZE11		0x62240
>> +#define ISP_RB_RPTR11		0x62244
>> +#define ISP_RB_WPTR11		0x62248
>> +#define ISP_RB_BASE_LO12	0x6224C
>> +#define ISP_RB_BASE_HI12	0x62250
>> +#define ISP_RB_SIZE12		0x62254
>> +#define ISP_RB_RPTR12		0x62258
>> +#define ISP_RB_WPTR12		0x6225C
>> +
>> +#define ISP_POWER_STATUS	0x60000
>> +
>> +#define ISP_MIPI_PHY0_REG0	0x66700
>> +#define ISP_MIPI_PHY1_REG0	0x66780
>> +#define ISP_MIPI_PHY2_REG0	0x67400
>> +
>> +#define ISP_MIPI_PHY0_SIZE	0xD30
>> +
>> +/* ISP_SOFT_RESET */
>> +#define ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK			0x00000001UL
>> +
>> +/* ISP_CCPU_CNTL */
>> +#define ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK			0x00040000UL
>> +
>> +/* ISP_STATUS */
>> +#define ISP_STATUS__CCPU_REPORT_MASK				0x000000feUL
>> +
>> +/* ISP_SYS_INT0_STATUS */
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK	0x00010000UL
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT10_INT_MASK	0x00040000UL
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT11_INT_MASK	0x00100000UL
>> +#define ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK	0x00400000UL
>> +
>> +/* ISP_SYS_INT0_EN */
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK	0x00010000UL
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK	0x00040000UL
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK	0x00100000UL
>> +#define ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK	0x00400000UL
>> +
>> +/* ISP_SYS_INT0_ACK */
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK	0x00010000UL
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT10_ACK_MASK	0x00040000UL
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT11_ACK_MASK	0x00100000UL
>> +#define ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK	0x00400000UL
>> +
>> +#endif
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-26 22:31     ` Sultan Alsawaf
@ 2025-07-29  3:32       ` Du, Bin
  2025-07-29  7:42         ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-29  3:32 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Thanks Sultan, please see my comments

On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>
>>> I cannot for the life of me get the webcam working under Linux. The webcam works
>>> under Windows so it's not a hardware issue.
>>>
>>> With this patchset and all of the patches you link here applied to 6.15, I get
>>> the following errors:
>>>     [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
>>>     [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
>>>
>>> With the old ispkernel code from February [1] applied on 6.15, the webcam
>>> indicator LED lights up but there's no image. I see these messages at boot:
>>>     [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
>>>     [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
>>>     [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>     [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>     [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>     [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>
>>> And then the kernel crashes due to the same use-after-free issues I pointed out
>>> in my other email [2].
>>>
>>> Any idea what's going on?
>>>
>>> [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>> Hi Sultan,
>>
>> [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
>> on 6.15 but we are really glad to help, would you please provide some info,
>> 1. Suppose you are using Ubuntu, right? What's the version?
>> 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
>>
>> After your confirmation, we'll see what we can do to enable your camera
>> quickly and easily
>>
>> Regards,
>> Bin
> 
> Thank you, Bin!
> 
> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> 2. Yes, here is my kernel source [2].
> 
> I have some more findings:
> 
> Currently, the first blocking issue is that the I2C adapter fails to initialize.
> This is because the ISP tile isn't powered on.
> 
> I noticed that in the old version of amd_isp_i2c_designware [3], there were
> calls to isp_power_set(), which is available in the old ISP4 sources [4].
> Without isp_power_set(), the I2C adapter always fails to initialize for me.
> 
> How is the ISP tile supposed to get powered on in the current ISP4 code?
> 
You are correct, yes, i believe the I2C adapter failure is caused by ISP 
not being powered up. Currently in latest code, isp_power_set is no 
longer available, instead, we implemented genPD for ISP in amdgpu
https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
Both amd_isp_i2c and amd_isp_capture are in the power domain and use the 
standard runtime PM API to do the power control

> Also, I noticed that the driver init ordering matters between all of the drivers
> needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
> must be initialized before amd_capture, otherwise amd_capture will fail to find
> the fwnode properties for the OV05C10 device attached to the I2C bus.
> 
> But there is no driver init ordering enforced, which also caused some issues for
> me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
> to ensure each driver waits for its dependencies to init first?
> 
amd_isp_capture only has dependency on amd_isp4 which is the ACPI 
platform driver, it is init before amd_isp_catpure.
Do you see in your side the amd_capture probe failure caused by failing 
to read fwnode properties? If that's the case please help to check if 
amd_isp4 is loaded successfully

> [1] https://github.com/amd/Linux_ISP_libcamera/tree/3.0
> [2] https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.15-sultan-isp4
> [3] https://lore.kernel.org/all/20250228164519.3453927-1-pratap.nirujogi@amd.com
> [4] https://github.com/amd/Linux_ISP_Kernel/blob/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4/drivers/media/platform/amd/isp4/isp_hwa.c#L378-L385
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-26 21:41       ` Sultan Alsawaf
  2025-07-26 21:50         ` Sultan Alsawaf
@ 2025-07-29  6:08         ` Du, Bin
  1 sibling, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-29  6:08 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Sultan, will try your modifications in this and other mails 
together and let you know the result

On 7/27/2025 5:41 AM, Sultan Alsawaf wrote:
> On Fri, Jul 25, 2025 at 05:22:41PM +0800, Du, Bin wrote:
>>>> +static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
>>>> +					      void *buf_priv,
>>>> +					      unsigned long flags)
>>>> +{
>>>> +	struct isp4vid_vb2_buf *buf = buf_priv;
>>>> +	struct dma_buf *dbuf;
>>>> +
>>>> +	if (buf->dbuf) {
>>>> +		dev_dbg(buf->dev,
>>>> +			"dbuf already created, reuse implicit dbuf\n");
>>>> +		dbuf = buf->dbuf;
>>>
>>> The dmabuf is reused here without taking a reference to it. When the get_dmabuf
>>> memop is called by vb2_core_expbuf(), it assumes that a reference to the dmabuf
>>> is acquired. So you need to add `get_dma_buf(dbuf)` here.
>> After test, we found we can't add get_dma_buf(dbuf) here because it will
>> make cheese APP fail to open camera with following error:
>> amdgpu: [drm] *ERROR* failed to alloc gart kernel buffer (-28)
> 
> I see, it's because buf->is_expbuf is set to true even for the implicit dbuf, so
> the initial reference on the implicit dbuf is never put, causing a leak.
> 
> Also, the refcount increment in isp4vid_vb2_get_dmabuf() is done every time even
> when reusing the existing dbuf, but releasing the dbuf will only do a single
> refcount decrement. This also causes a leak.
> 
> And, isp4vid_get_dmabuf() may fail but isp4vid_vb2_get_dmabuf() doesn't check
> the return value, so there may be another leak when isp4vid_get_dmabuf() fails
> because of the refcount increment. The refcount increment and setting of
> buf->is_expbuf to true should only be done on success.
> 
> I have fixed all of these isp4vid_vb2_get_dmabuf() issues in the following diff,
> please try it:
> 
> --- a/drivers/media/platform/amd/isp4/isp4_video.c
> +++ b/drivers/media/platform/amd/isp4/isp4_video.c
> @@ -476,18 +476,22 @@ static struct dma_buf *isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
>   					      unsigned long flags)
>   {
>   	struct isp4vid_vb2_buf *buf = buf_priv;
> -	struct dma_buf *dbuf;
> +	struct dma_buf *dbuf = buf->dbuf;
>   
> -	if (buf->dbuf) {
> +	if (dbuf) {
>   		dev_dbg(buf->dev,
> -			"dbuf already created, reuse implicit dbuf\n");
> -		dbuf = buf->dbuf;
> +			"dbuf already created, reuse %s dbuf\n",
> +			buf->is_expbuf ? "exported" : "implicit");
> +		get_dma_buf(dbuf);
>   	} else {
>   		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
> +		if (!dbuf)
> +			return NULL;
> +
>   		dev_dbg(buf->dev, "created new dbuf\n");
> +		buf->is_expbuf = true;
> +		refcount_inc(&buf->refcount);
>   	}
> -	buf->is_expbuf = true;
> -	refcount_inc(&buf->refcount);
>   
>   	dev_dbg(buf->dev, "buf exported, refcount %d\n",
>   		buf->refcount.refs.counter);
> --
> 
>>>> +		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
>>>> +			 refcount_read(&buf->refcount));
>>>
>>> This refcount_read() is a possible use-after-free because `buf` is accessed
>>> after isp4vid_vb2_put() puts its reference to `buf`. So something else could put
>>> the last reference to `buf` and free it after this refcount dec but before the
>>> refcount_read(). Maybe just remove this dev_warn() entirely?
>>>
>> The warning is important to debug mem related issue, plan to keep it but
>> without accessing buf or buf->refcount here. Do you think it acceptible?
> 
> Yes, that sounds good. So something like this:
> `dev_warn(buf->dev, "ignore buffer free, refcount > 0");`
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-26 21:50         ` Sultan Alsawaf
@ 2025-07-29  6:12           ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-29  6:12 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Sultan, will try your changes in this and other mails 
together and let you know the result

On 7/27/2025 5:50 AM, Sultan Alsawaf wrote:
> On Sat, Jul 26, 2025 at 02:41:41PM -0700, Sultan Alsawaf wrote:
>> On Fri, Jul 25, 2025 at 05:22:41PM +0800, Du, Bin wrote:
>>>>> +		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
>>>>> +			 refcount_read(&buf->refcount));
>>>>
>>>> This refcount_read() is a possible use-after-free because `buf` is accessed
>>>> after isp4vid_vb2_put() puts its reference to `buf`. So something else could put
>>>> the last reference to `buf` and free it after this refcount dec but before the
>>>> refcount_read(). Maybe just remove this dev_warn() entirely?
>>>>
>>> The warning is important to debug mem related issue, plan to keep it but
>>> without accessing buf or buf->refcount here. Do you think it acceptible?
>>
>> Yes, that sounds good. So something like this:
>> `dev_warn(buf->dev, "ignore buffer free, refcount > 0");`
> 
> Sorry, to fix the dev_warn() we need to make a copy of buf->dev first:
> 
> --- a/drivers/media/platform/amd/isp4/isp4_video.c
> +++ b/drivers/media/platform/amd/isp4/isp4_video.c
> @@ -584,8 +584,9 @@ static void isp4vid_vb2_put(void *buf_priv)
>   {
>   	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
>   	struct amdgpu_bo *bo = (struct amdgpu_bo *)buf->bo;
> +	struct device *dev = buf->dev;
>   
> -	dev_dbg(buf->dev,
> +	dev_dbg(dev,
>   		"release isp user bo 0x%llx size %ld refcount %d is_expbuf %d",
>   		buf->gpu_addr, buf->size,
>   		buf->refcount.refs.counter, buf->is_expbuf);
> @@ -601,8 +602,7 @@ static void isp4vid_vb2_put(void *buf_priv)
>   		kfree(buf);
>   		buf = NULL;
>   	} else {
> -		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0",
> -			 refcount_read(&buf->refcount));
> +		dev_warn(dev, "ignore buffer free, refcount > 0\n");
>   	}
>   }
>   
> --
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-29  3:32       ` Du, Bin
@ 2025-07-29  7:42         ` Sultan Alsawaf
  2025-07-29  7:45           ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-29  7:42 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

[-- Attachment #1: Type: text/plain, Size: 4885 bytes --]

On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> Thanks Sultan, please see my comments
> 
> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > 
> > > > I cannot for the life of me get the webcam working under Linux. The webcam works
> > > > under Windows so it's not a hardware issue.
> > > > 
> > > > With this patchset and all of the patches you link here applied to 6.15, I get
> > > > the following errors:
> > > >     [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
> > > >     [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
> > > > 
> > > > With the old ispkernel code from February [1] applied on 6.15, the webcam
> > > > indicator LED lights up but there's no image. I see these messages at boot:
> > > >     [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
> > > >     [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
> > > >     [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > >     [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > >     [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > >     [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > 
> > > > And then the kernel crashes due to the same use-after-free issues I pointed out
> > > > in my other email [2].
> > > > 
> > > > Any idea what's going on?
> > > > 
> > > > [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > Hi Sultan,
> > > 
> > > [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
> > > on 6.15 but we are really glad to help, would you please provide some info,
> > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
> > > 
> > > After your confirmation, we'll see what we can do to enable your camera
> > > quickly and easily
> > > 
> > > Regards,
> > > Bin
> > 
> > Thank you, Bin!
> > 
> > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > 2. Yes, here is my kernel source [2].
> > 
> > I have some more findings:
> > 
> > Currently, the first blocking issue is that the I2C adapter fails to initialize.
> > This is because the ISP tile isn't powered on.
> > 
> > I noticed that in the old version of amd_isp_i2c_designware [3], there were
> > calls to isp_power_set(), which is available in the old ISP4 sources [4].
> > Without isp_power_set(), the I2C adapter always fails to initialize for me.
> > 
> > How is the ISP tile supposed to get powered on in the current ISP4 code?
> > 
> You are correct, yes, i believe the I2C adapter failure is caused by ISP not
> being powered up. Currently in latest code, isp_power_set is no longer
> available, instead, we implemented genPD for ISP in amdgpu
> https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
> Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
> standard runtime PM API to do the power control

Thanks for that link, I found it along with another patch on the list to make
the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").

> > Also, I noticed that the driver init ordering matters between all of the drivers
> > needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
> > must be initialized before amd_capture, otherwise amd_capture will fail to find
> > the fwnode properties for the OV05C10 device attached to the I2C bus.
> > 
> > But there is no driver init ordering enforced, which also caused some issues for
> > me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
> > to ensure each driver waits for its dependencies to init first?
> > 
> amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
> driver, it is init before amd_isp_catpure.
> Do you see in your side the amd_capture probe failure caused by failing to
> read fwnode properties? If that's the case please help to check if amd_isp4
> is loaded successfully

I got much further now: there aren't any driver initialization errors, but when
I open the camera, there's no image. The camera LED turns on so it's active.

And then shortly afterwards, amdgpu dies and the entire system freezes.

I've attached my full dmesg, please let me know what you think. Thanks!

Sultan

[-- Attachment #2: isp4-amdgpu-dies-dmesg.txt --]
[-- Type: text/plain, Size: 193328 bytes --]

[    4.221499] kernel: Linux version 6.16.0-00020-g541e951a4e8a (sultan@sultan-box) (gcc (GCC) 15.1.1 20250425, GNU ld (GNU Binutils) 2.44.0) #1 SMP PREEMPT_DYNAMIC Mon Jul 28 23:17:19 PDT 2025
[    4.221530] kernel: Command line: BOOT_IMAGE=/vmlinuz-linux-sultan root=UUID=18516d14-ae39-4b89-8899-95270912d67b rw module_blacklist=nouveau,pcspkr,ntfs3 quiet cryptdevice=UUID=086cda6b-894f-4a2b-b380-335846421e3f:cryptroot:allow-discards,no-read-workqueue,no-write-workqueue root=/dev/mapper/cryptroot audit=0 psi=0 init_on_alloc=0 tsx=off memory_corruption_check=0 noirqdebug zswap.enabled=0 iwlmvm.power_scheme=3 pcie_aspm=force split_lock_detect=off asus_wmi.fnlock_default=false efi_pstore.pstore_disable=0
[    4.221535] kernel: x86/split lock detection: disabled
[    4.221539] kernel: BIOS-provided physical RAM map:
[    4.221543] kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009efff] usable
[    4.221546] kernel: BIOS-e820: [mem 0x000000000009f000-0x000000000009ffff] reserved
[    4.221549] kernel: BIOS-e820: [mem 0x0000000000100000-0x0000000009efffff] usable
[    4.221553] kernel: BIOS-e820: [mem 0x0000000009f00000-0x0000000009f87fff] ACPI NVS
[    4.221556] kernel: BIOS-e820: [mem 0x0000000009f88000-0x0000000044bcffff] usable
[    4.221559] kernel: BIOS-e820: [mem 0x0000000044bd0000-0x00000000451cffff] type 20
[    4.221562] kernel: BIOS-e820: [mem 0x00000000451d0000-0x000000004899bfff] reserved
[    4.221566] kernel: BIOS-e820: [mem 0x000000004899c000-0x000000004909bfff] ACPI NVS
[    4.221569] kernel: BIOS-e820: [mem 0x000000004909c000-0x000000004913dfff] ACPI data
[    4.221572] kernel: BIOS-e820: [mem 0x000000004913e000-0x0000000052bd1fff] usable
[    4.221576] kernel: BIOS-e820: [mem 0x0000000052bd2000-0x0000000052bd2fff] reserved
[    4.221579] kernel: BIOS-e820: [mem 0x0000000052bd3000-0x0000000052bdbfff] usable
[    4.221582] kernel: BIOS-e820: [mem 0x0000000052bdc000-0x0000000052bdcfff] reserved
[    4.221585] kernel: BIOS-e820: [mem 0x0000000052bdd000-0x000000005d133fff] usable
[    4.221588] kernel: BIOS-e820: [mem 0x000000005d134000-0x000000005d138fff] reserved
[    4.221590] kernel: BIOS-e820: [mem 0x000000005d139000-0x0000000077ffffff] usable
[    4.221593] kernel: BIOS-e820: [mem 0x0000000078000000-0x000000007bffffff] reserved
[    4.221597] kernel: BIOS-e820: [mem 0x000000007d675000-0x000000007d6fffff] reserved
[    4.221599] kernel: BIOS-e820: [mem 0x000000007d800000-0x000000007fffffff] reserved
[    4.221602] kernel: BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
[    4.221605] kernel: BIOS-e820: [mem 0x00000000fd300000-0x00000000fd3fffff] reserved
[    4.221608] kernel: BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
[    4.221611] kernel: BIOS-e820: [mem 0x00000000fec10000-0x00000000fec10fff] reserved
[    4.221614] kernel: BIOS-e820: [mem 0x00000000fed80000-0x00000000fed80fff] reserved
[    4.221617] kernel: BIOS-e820: [mem 0x00000000fedf1000-0x00000000fedf1fff] reserved
[    4.221620] kernel: BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    4.221622] kernel: BIOS-e820: [mem 0x0000000100000000-0x0000000f7e0bffff] usable
[    4.221625] kernel: BIOS-e820: [mem 0x0000000f7e0c0000-0x00000010b01fffff] reserved
[    4.221628] kernel: BIOS-e820: [mem 0x000000fd00000000-0x000000fd01ffffff] reserved
[    4.221630] kernel: NX (Execute Disable) protection: active
[    4.221633] kernel: APIC: Static calls initialized
[    4.221636] kernel: efi: EFI v2.8 by HP
[    4.221639] kernel: efi: ACPI=0x4913d000 ACPI 2.0=0x4913d014 SMBIOS=0x45ea0000 SMBIOS 3.0=0x45e9e000 ESRT=0x45e9c118 RTPROP=0x45e9c798 MEMATTR=0x37f04698 
[    4.221642] kernel: efi: Remove mem65: MMIO range=[0xe0000000-0xefffffff] (256MB) from e820 map
[    4.221645] kernel: e820: remove [mem 0xe0000000-0xefffffff] reserved
[    4.221648] kernel: efi: Remove mem66: MMIO range=[0xfd300000-0xfd3fffff] (1MB) from e820 map
[    4.221652] kernel: e820: remove [mem 0xfd300000-0xfd3fffff] reserved
[    4.221655] kernel: efi: Not removing mem67: MMIO range=[0xfec00000-0xfec00fff] (4KB) from e820 map
[    4.221658] kernel: efi: Not removing mem68: MMIO range=[0xfec10000-0xfec10fff] (4KB) from e820 map
[    4.221661] kernel: efi: Not removing mem69: MMIO range=[0xfed80000-0xfed80fff] (4KB) from e820 map
[    4.221664] kernel: efi: Not removing mem70: MMIO range=[0xfedf1000-0xfedf1fff] (4KB) from e820 map
[    4.221666] kernel: efi: Not removing mem71: MMIO range=[0xfee00000-0xfee00fff] (4KB) from e820 map
[    4.221669] kernel: efi: Remove mem73: MMIO range=[0x1090000000-0x10b01fffff] (514MB) from e820 map
[    4.221672] kernel: e820: remove [mem 0x1090000000-0x10b01fffff] reserved
[    4.221675] kernel: efi: Remove mem74: MMIO range=[0xfd00000000-0xfd01ffffff] (32MB) from e820 map
[    4.221678] kernel: e820: remove [mem 0xfd00000000-0xfd01ffffff] reserved
[    4.221681] kernel: SMBIOS 3.4.0 present.
[    4.221684] kernel: DMI: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[    4.221687] kernel: DMI: Memory slots populated: 8/8
[    4.221690] kernel: tsc: Fast TSC calibration using PIT
[    4.221694] kernel: tsc: Detected 2994.065 MHz processor
[    4.221697] kernel: e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
[    4.221700] kernel: e820: remove [mem 0x000a0000-0x000fffff] usable
[    4.221704] kernel: last_pfn = 0xf7e0c0 max_arch_pfn = 0x400000000
[    4.221707] kernel: MTRR map: 8 entries (3 fixed + 5 variable; max 20), built from 9 variable MTRRs
[    4.221710] kernel: x86/PAT: Configuration [0-7]: WB  WC  UC- UC  WB  WP  UC- WT  
[    4.221713] kernel: last_pfn = 0x78000 max_arch_pfn = 0x400000000
[    4.221716] kernel: esrt: Reserving ESRT space from 0x0000000045e9c118 to 0x0000000045e9c128.
[    4.221720] kernel: Using GB pages for direct mapping
[    4.221723] kernel: Secure boot disabled
[    4.221726] kernel: RAMDISK: [mem 0x2fc19000-0x33e03fff]
[    4.221730] kernel: ACPI: Early table checksum verification disabled
[    4.221733] kernel: ACPI: RSDP 0x000000004913D014 000024 (v02 HPQOEM)
[    4.221736] kernel: ACPI: XSDT 0x00000000490C1228 00019C (v01 HPQOEM SLIC-BPC 00000001      01000013)
[    4.221739] kernel: ACPI: FACP 0x0000000049129000 00010C (v05 HPQOEM SLIC-BPC 00000001 HP   00000001)
[    4.221742] kernel: ACPI: DSDT 0x0000000049108000 01A94C (v02 HPQOEM 8D01     00000000 INTL 20200717)
[    4.221745] kernel: ACPI: FACS 0x0000000048D43000 000040
[    4.221748] kernel: ACPI: SSDT 0x000000004913B000 000353 (v02 HP     NVTEC    00000001 INTL 20200717)
[    4.221752] kernel: ACPI: SSDT 0x000000004913A000 00013E (v02 HP     ShmTable 00000001 INTL 20200717)
[    4.221755] kernel: ACPI: ASF! 0x0000000049139000 000085 (v32 HPQOEM EDK2     00000002      01000013)
[    4.221758] kernel: ACPI: SSDT 0x0000000049130000 00848D (v02 AMD    AmdTable 00000002 MSFT 04000000)
[    4.221761] kernel: ACPI: RTMA 0x000000004912F000 00009E (v01 HP     _HBMART_ 00001000 HP   00000001)
[    4.221765] kernel: ACPI: SSDT 0x000000004912D000 001A39 (v02 HP     UcsiAcpi 00000001 INTL 20200717)
[    4.221768] kernel: ACPI: SSDT 0x000000004912C000 0000FB (v02 HP     UcsiCntr 00000001 INTL 20200717)
[    4.221771] kernel: ACPI: SSDT 0x000000004912B000 0000BC (v01 HP     OPALPWD  00000001 INTL 20200717)
[    4.221774] kernel: ACPI: OEML 0x000000004912A000 000028 (v03 HPQOEM EDK2     00000002      01000013)
[    4.221777] kernel: ACPI: MSDM 0x0000000049128000 000055 (v03 HPQOEM SLIC-BPC 00000000 HP   00000001)
[    4.221780] kernel: ACPI: WSMT 0x0000000049127000 000028 (v01 HPQOEM 8D01     00000001 HP   00000001)
[    4.221783] kernel: ACPI: ASF! 0x0000000049126000 00006E (v32 HPQOEM 8D01     00000001 HP   00000001)
[    4.221787] kernel: ACPI: HPET 0x0000000049125000 000038 (v01 HPQOEM 8D01     00000001 HP   00000001)
[    4.221790] kernel: ACPI: APIC 0x0000000049124000 000222 (v02 HPQOEM 8D01     00000001 HP   00000001)
[    4.221817] kernel: ACPI: MCFG 0x0000000049123000 00003C (v01 HPQOEM 8D01     00000001 HP   00000001)
[    4.221820] kernel: ACPI: SSDT 0x0000000049107000 00014A (v01 HPQOEM AMDNFCI2 00000001 INTL 20200717)
[    4.221823] kernel: ACPI: SSDT 0x00000000490FC000 00A8CE (v02 AMD    AMD CPU  00000001 AMD  00000001)
[    4.221827] kernel: ACPI: FPDT 0x00000000490FB000 000044 (v01 HPQOEM EDK2     00000002      01000013)
[    4.221830] kernel: ACPI: SSDT 0x00000000490FA000 000045 (v02 HP     HPNBCONV 00001000 INTL 20200717)
[    4.221833] kernel: ACPI: SSDT 0x00000000490F9000 00061A (v01 HP     AMDTPL   00001000 INTL 20200717)
[    4.221836] kernel: ACPI: SSDT 0x00000000490F3000 004430 (v02 HP     HPAMD_WL 00001000 INTL 20200717)
[    4.221840] kernel: ACPI: SSDT 0x000000004913C000 000032 (v02 HP     HPCONDEV 00001000 INTL 20200717)
[    4.221843] kernel: ACPI: SSDT 0x00000000490F2000 000EE0 (v02 HPQOEM HPPATT   00001000 INTL 20200717)
[    4.221846] kernel: ACPI: VFCT 0x00000000490ED000 004484 (v01 HPQOEM SLIC-BPC 00000001 AMD  33504F47)
[    4.221849] kernel: ACPI: SSDT 0x00000000490EB000 0017CA (v02 AMD    OEMACP   00000001 INTL 20200717)
[    4.221853] kernel: ACPI: SSDT 0x00000000490E9000 001152 (v02 AMD    OEMPMF   00000001 INTL 20200717)
[    4.221856] kernel: ACPI: SSDT 0x00000000490E7000 001DB7 (v02 AMD    CPMPMF   00000001 INTL 20200717)
[    4.221859] kernel: ACPI: SSDT 0x00000000490E6000 00047A (v02 AMD    CPMWBH   00000001 INTL 20200717)
[    4.221863] kernel: ACPI: SSDT 0x00000000490DC000 009A93 (v02 AMD    CPMCMN   00000001 INTL 20200717)
[    4.221866] kernel: ACPI: BGRT 0x00000000490DB000 000038 (v01 HPQOEM EDK2     00000002      01000013)
[    4.221869] kernel: ACPI: SSDT 0x00000000490DA000 000612 (v02 AMD    CAM11    00000001 INTL 20200717)
[    4.221872] kernel: ACPI: SSDT 0x00000000490D9000 000A7F (v02 AMD    SDCR     00000001 INTL 20200717)
[    4.221876] kernel: ACPI: SSDT 0x00000000490D8000 000A34 (v02 AMD    LOM      00000001 INTL 20200717)
[    4.221879] kernel: ACPI: SSDT 0x00000000490D7000 000DB4 (v02 AMD    NVME     00000001 INTL 20200717)
[    4.221882] kernel: ACPI: SSDT 0x00000000490D5000 001672 (v02 AMD    UPEP     00000001 INTL 20200717)
[    4.221886] kernel: ACPI: SSDT 0x00000000490D3000 0010BB (v02 AMD    GPP_PME_ 00000001 INTL 20200717)
[    4.221889] kernel: ACPI: SSDT 0x00000000490C9000 0097A5 (v02 AMD    INTBUSC_ 00000001 INTL 20200717)
[    4.221892] kernel: ACPI: SSDT 0x00000000490C4000 0046FB (v02 AMD    INTGPPA_ 00000001 INTL 20200717)
[    4.221895] kernel: ACPI: SSDT 0x00000000490C3000 000AE6 (v02 AMD    CPMGPIO0 00000001 INTL 20200717)
[    4.221898] kernel: ACPI: SSDT 0x00000000490C2000 000051 (v02 AMD    DRTM     00000001 INTL 20200717)
[    4.221902] kernel: ACPI: IVRS 0x00000000490F8000 0001F6 (v02 AMD    AmdTable 00000001 AMD  00000001)
[    4.221905] kernel: ACPI: SSDT 0x00000000490C0000 000500 (v02 AMD    MEMTOOL0 00000002 INTL 20200717)
[    4.221908] kernel: ACPI: SSDT 0x00000000490BF000 0009D0 (v02 AMD    CPMMSOSC 00000001 INTL 20200717)
[    4.221911] kernel: ACPI: SSDT 0x00000000490BE000 00008D (v02 AMD    CPMMSLPI 00000001 INTL 20200717)
[    4.221914] kernel: ACPI: SSDT 0x00000000490BD000 000509 (v02 AMD    CPMSFAML 00000001 INTL 20200717)
[    4.221918] kernel: ACPI: SSDT 0x00000000490BC000 000F5C (v02 AMD    CPMACPV8 00000001 INTL 20200717)
[    4.221921] kernel: ACPI: Reserving FACP table memory at [mem 0x49129000-0x4912910b]
[    4.221926] kernel: ACPI: Reserving DSDT table memory at [mem 0x49108000-0x4912294b]
[    4.221929] kernel: ACPI: Reserving FACS table memory at [mem 0x48d43000-0x48d4303f]
[    4.221932] kernel: ACPI: Reserving SSDT table memory at [mem 0x4913b000-0x4913b352]
[    4.221935] kernel: ACPI: Reserving SSDT table memory at [mem 0x4913a000-0x4913a13d]
[    4.221938] kernel: ACPI: Reserving ASF! table memory at [mem 0x49139000-0x49139084]
[    4.221941] kernel: ACPI: Reserving SSDT table memory at [mem 0x49130000-0x4913848c]
[    4.221944] kernel: ACPI: Reserving RTMA table memory at [mem 0x4912f000-0x4912f09d]
[    4.221946] kernel: ACPI: Reserving SSDT table memory at [mem 0x4912d000-0x4912ea38]
[    4.221950] kernel: ACPI: Reserving SSDT table memory at [mem 0x4912c000-0x4912c0fa]
[    4.221953] kernel: ACPI: Reserving SSDT table memory at [mem 0x4912b000-0x4912b0bb]
[    4.221955] kernel: ACPI: Reserving OEML table memory at [mem 0x4912a000-0x4912a027]
[    4.221958] kernel: ACPI: Reserving MSDM table memory at [mem 0x49128000-0x49128054]
[    4.221961] kernel: ACPI: Reserving WSMT table memory at [mem 0x49127000-0x49127027]
[    4.221964] kernel: ACPI: Reserving ASF! table memory at [mem 0x49126000-0x4912606d]
[    4.221967] kernel: ACPI: Reserving HPET table memory at [mem 0x49125000-0x49125037]
[    4.221970] kernel: ACPI: Reserving APIC table memory at [mem 0x49124000-0x49124221]
[    4.221974] kernel: ACPI: Reserving MCFG table memory at [mem 0x49123000-0x4912303b]
[    4.221977] kernel: ACPI: Reserving SSDT table memory at [mem 0x49107000-0x49107149]
[    4.221980] kernel: ACPI: Reserving SSDT table memory at [mem 0x490fc000-0x491068cd]
[    4.221983] kernel: ACPI: Reserving FPDT table memory at [mem 0x490fb000-0x490fb043]
[    4.221986] kernel: ACPI: Reserving SSDT table memory at [mem 0x490fa000-0x490fa044]
[    4.221989] kernel: ACPI: Reserving SSDT table memory at [mem 0x490f9000-0x490f9619]
[    4.221992] kernel: ACPI: Reserving SSDT table memory at [mem 0x490f3000-0x490f742f]
[    4.221995] kernel: ACPI: Reserving SSDT table memory at [mem 0x4913c000-0x4913c031]
[    4.221998] kernel: ACPI: Reserving SSDT table memory at [mem 0x490f2000-0x490f2edf]
[    4.222003] kernel: ACPI: Reserving VFCT table memory at [mem 0x490ed000-0x490f1483]
[    4.222007] kernel: ACPI: Reserving SSDT table memory at [mem 0x490eb000-0x490ec7c9]
[    4.222012] kernel: ACPI: Reserving SSDT table memory at [mem 0x490e9000-0x490ea151]
[    4.222015] kernel: ACPI: Reserving SSDT table memory at [mem 0x490e7000-0x490e8db6]
[    4.222018] kernel: ACPI: Reserving SSDT table memory at [mem 0x490e6000-0x490e6479]
[    4.222022] kernel: ACPI: Reserving SSDT table memory at [mem 0x490dc000-0x490e5a92]
[    4.222025] kernel: ACPI: Reserving BGRT table memory at [mem 0x490db000-0x490db037]
[    4.222028] kernel: ACPI: Reserving SSDT table memory at [mem 0x490da000-0x490da611]
[    4.222030] kernel: ACPI: Reserving SSDT table memory at [mem 0x490d9000-0x490d9a7e]
[    4.222034] kernel: ACPI: Reserving SSDT table memory at [mem 0x490d8000-0x490d8a33]
[    4.222037] kernel: ACPI: Reserving SSDT table memory at [mem 0x490d7000-0x490d7db3]
[    4.222040] kernel: ACPI: Reserving SSDT table memory at [mem 0x490d5000-0x490d6671]
[    4.222043] kernel: ACPI: Reserving SSDT table memory at [mem 0x490d3000-0x490d40ba]
[    4.222046] kernel: ACPI: Reserving SSDT table memory at [mem 0x490c9000-0x490d27a4]
[    4.222049] kernel: ACPI: Reserving SSDT table memory at [mem 0x490c4000-0x490c86fa]
[    4.222052] kernel: ACPI: Reserving SSDT table memory at [mem 0x490c3000-0x490c3ae5]
[    4.222055] kernel: ACPI: Reserving SSDT table memory at [mem 0x490c2000-0x490c2050]
[    4.222057] kernel: ACPI: Reserving IVRS table memory at [mem 0x490f8000-0x490f81f5]
[    4.222061] kernel: ACPI: Reserving SSDT table memory at [mem 0x490c0000-0x490c04ff]
[    4.222064] kernel: ACPI: Reserving SSDT table memory at [mem 0x490bf000-0x490bf9cf]
[    4.222067] kernel: ACPI: Reserving SSDT table memory at [mem 0x490be000-0x490be08c]
[    4.222070] kernel: ACPI: Reserving SSDT table memory at [mem 0x490bd000-0x490bd508]
[    4.222073] kernel: ACPI: Reserving SSDT table memory at [mem 0x490bc000-0x490bcf5b]
[    4.222076] kernel: No NUMA configuration found
[    4.222079] kernel: Faking a node at [mem 0x0000000000000000-0x0000000f7e0bffff]
[    4.222083] kernel: NODE_DATA(0) allocated [mem 0xf7e095280-0xf7e0bffff]
[    4.222086] kernel: Zone ranges:
[    4.222089] kernel:   DMA      [mem 0x0000000000001000-0x0000000000ffffff]
[    4.222092] kernel:   DMA32    [mem 0x0000000001000000-0x00000000ffffffff]
[    4.222096] kernel:   Normal   [mem 0x0000000100000000-0x0000000f7e0bffff]
[    4.222099] kernel:   Device   empty
[    4.222102] kernel: Movable zone start for each node
[    4.222105] kernel: Early memory node ranges
[    4.222109] kernel:   node   0: [mem 0x0000000000001000-0x000000000009efff]
[    4.222112] kernel:   node   0: [mem 0x0000000000100000-0x0000000009efffff]
[    4.222115] kernel:   node   0: [mem 0x0000000009f88000-0x0000000044bcffff]
[    4.222118] kernel:   node   0: [mem 0x000000004913e000-0x0000000052bd1fff]
[    4.222121] kernel:   node   0: [mem 0x0000000052bd3000-0x0000000052bdbfff]
[    4.222124] kernel:   node   0: [mem 0x0000000052bdd000-0x000000005d133fff]
[    4.222127] kernel:   node   0: [mem 0x000000005d139000-0x0000000077ffffff]
[    4.222131] kernel:   node   0: [mem 0x0000000100000000-0x0000000f7e0bffff]
[    4.222134] kernel: Initmem setup node 0 [mem 0x0000000000001000-0x0000000f7e0bffff]
[    4.222137] kernel: On node 0, zone DMA: 1 pages in unavailable ranges
[    4.222140] kernel: On node 0, zone DMA: 97 pages in unavailable ranges
[    4.222143] kernel: On node 0, zone DMA32: 136 pages in unavailable ranges
[    4.222146] kernel: On node 0, zone DMA32: 17774 pages in unavailable ranges
[    4.222150] kernel: On node 0, zone DMA32: 1 pages in unavailable ranges
[    4.222153] kernel: On node 0, zone DMA32: 1 pages in unavailable ranges
[    4.222156] kernel: On node 0, zone DMA32: 5 pages in unavailable ranges
[    4.222159] kernel: On node 0, zone Normal: 8000 pages in unavailable ranges
[    4.222162] kernel: ACPI: PM-Timer IO Port: 0x408
[    4.222165] kernel: ACPI: LAPIC_NMI (acpi_id[0x00] high edge lint[0x1])
[    4.222168] kernel: ACPI: LAPIC_NMI (acpi_id[0x01] high edge lint[0x1])
[    4.222171] kernel: ACPI: LAPIC_NMI (acpi_id[0x02] high edge lint[0x1])
[    4.222174] kernel: ACPI: LAPIC_NMI (acpi_id[0x03] high edge lint[0x1])
[    4.222177] kernel: ACPI: LAPIC_NMI (acpi_id[0x04] high edge lint[0x1])
[    4.222180] kernel: ACPI: LAPIC_NMI (acpi_id[0x05] high edge lint[0x1])
[    4.222183] kernel: ACPI: LAPIC_NMI (acpi_id[0x06] high edge lint[0x1])
[    4.222186] kernel: ACPI: LAPIC_NMI (acpi_id[0x07] high edge lint[0x1])
[    4.222189] kernel: ACPI: LAPIC_NMI (acpi_id[0x08] high edge lint[0x1])
[    4.222192] kernel: ACPI: LAPIC_NMI (acpi_id[0x09] high edge lint[0x1])
[    4.222195] kernel: ACPI: LAPIC_NMI (acpi_id[0x0a] high edge lint[0x1])
[    4.222198] kernel: ACPI: LAPIC_NMI (acpi_id[0x0b] high edge lint[0x1])
[    4.222201] kernel: ACPI: LAPIC_NMI (acpi_id[0x0c] high edge lint[0x1])
[    4.222204] kernel: ACPI: LAPIC_NMI (acpi_id[0x0d] high edge lint[0x1])
[    4.222207] kernel: ACPI: LAPIC_NMI (acpi_id[0x0e] high edge lint[0x1])
[    4.222210] kernel: ACPI: LAPIC_NMI (acpi_id[0x0f] high edge lint[0x1])
[    4.222213] kernel: ACPI: LAPIC_NMI (acpi_id[0x10] high edge lint[0x1])
[    4.222216] kernel: ACPI: LAPIC_NMI (acpi_id[0x11] high edge lint[0x1])
[    4.222219] kernel: ACPI: LAPIC_NMI (acpi_id[0x12] high edge lint[0x1])
[    4.222221] kernel: ACPI: LAPIC_NMI (acpi_id[0x13] high edge lint[0x1])
[    4.222224] kernel: ACPI: LAPIC_NMI (acpi_id[0x14] high edge lint[0x1])
[    4.222227] kernel: ACPI: LAPIC_NMI (acpi_id[0x15] high edge lint[0x1])
[    4.222231] kernel: ACPI: LAPIC_NMI (acpi_id[0x16] high edge lint[0x1])
[    4.222234] kernel: ACPI: LAPIC_NMI (acpi_id[0x17] high edge lint[0x1])
[    4.222237] kernel: ACPI: LAPIC_NMI (acpi_id[0x18] high edge lint[0x1])
[    4.222241] kernel: ACPI: LAPIC_NMI (acpi_id[0x19] high edge lint[0x1])
[    4.222244] kernel: ACPI: LAPIC_NMI (acpi_id[0x1a] high edge lint[0x1])
[    4.222247] kernel: ACPI: LAPIC_NMI (acpi_id[0x1b] high edge lint[0x1])
[    4.222250] kernel: ACPI: LAPIC_NMI (acpi_id[0x1c] high edge lint[0x1])
[    4.222253] kernel: ACPI: LAPIC_NMI (acpi_id[0x1d] high edge lint[0x1])
[    4.222256] kernel: ACPI: LAPIC_NMI (acpi_id[0x1e] high edge lint[0x1])
[    4.222259] kernel: ACPI: LAPIC_NMI (acpi_id[0x1f] high edge lint[0x1])
[    4.222261] kernel: IOAPIC[0]: apic_id 4, version 33, address 0xfec00000, GSI 0-23
[    4.222265] kernel: IOAPIC[1]: apic_id 5, version 33, address 0xfec01000, GSI 24-55
[    4.222268] kernel: ACPI: INT_SRC_OVR (bus 0 bus_irq 1 global_irq 1 low edge)
[    4.222271] kernel: ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl)
[    4.222275] kernel: ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level)
[    4.222278] kernel: ACPI: Using ACPI (MADT) for SMP configuration information
[    4.222281] kernel: ACPI: HPET id: 0x10228210 base: 0xfed00000
[    4.222284] kernel: e820: update [mem 0x37bee000-0x37dfdfff] usable ==> reserved
[    4.222287] kernel: CPU topo: Max. logical packages:   1
[    4.222291] kernel: CPU topo: Max. logical dies:       2
[    4.222294] kernel: CPU topo: Max. dies per package:   2
[    4.222296] kernel: CPU topo: Max. threads per core:   2
[    4.222300] kernel: CPU topo: Num. cores per package:    16
[    4.222303] kernel: CPU topo: Num. threads per package:  32
[    4.222306] kernel: CPU topo: Allowing 32 present CPUs plus 0 hotplug CPUs
[    4.222309] kernel: PM: hibernation: Registered nosave memory: [mem 0x00000000-0x00000fff]
[    4.222313] kernel: PM: hibernation: Registered nosave memory: [mem 0x0009f000-0x000fffff]
[    4.222318] kernel: PM: hibernation: Registered nosave memory: [mem 0x09f00000-0x09f87fff]
[    4.222321] kernel: PM: hibernation: Registered nosave memory: [mem 0x37bee000-0x37dfdfff]
[    4.222325] kernel: PM: hibernation: Registered nosave memory: [mem 0x44bd0000-0x4913dfff]
[    4.222328] kernel: PM: hibernation: Registered nosave memory: [mem 0x52bd2000-0x52bd2fff]
[    4.222332] kernel: PM: hibernation: Registered nosave memory: [mem 0x52bdc000-0x52bdcfff]
[    4.222337] kernel: PM: hibernation: Registered nosave memory: [mem 0x5d134000-0x5d138fff]
[    4.222340] kernel: PM: hibernation: Registered nosave memory: [mem 0x78000000-0xffffffff]
[    4.222343] kernel: [mem 0x80000000-0xfebfffff] available for PCI devices
[    4.222348] kernel: Booting paravirtualized kernel on bare hardware
[    4.222351] kernel: clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1910969940391419 ns
[    4.222355] kernel: setup_percpu: NR_CPUS:8192 nr_cpumask_bits:32 nr_cpu_ids:32 nr_node_ids:1
[    4.222358] kernel: percpu: Embedded 62 pages/cpu s217088 r8192 d28672 u262144
[    4.222363] kernel: pcpu-alloc: s217088 r8192 d28672 u262144 alloc=1*2097152
[    4.222367] kernel: pcpu-alloc: [0] 00 01 02 03 04 05 06 07 [0] 08 09 10 11 12 13 14 15 
[    4.222370] kernel: pcpu-alloc: [0] 16 17 18 19 20 21 22 23 [0] 24 25 26 27 28 29 30 31 
[    4.222374] kernel: Kernel command line: BOOT_IMAGE=/vmlinuz-linux-sultan root=UUID=18516d14-ae39-4b89-8899-95270912d67b rw module_blacklist=nouveau,pcspkr,ntfs3 quiet cryptdevice=UUID=086cda6b-894f-4a2b-b380-335846421e3f:cryptroot:allow-discards,no-read-workqueue,no-write-workqueue root=/dev/mapper/cryptroot audit=0 psi=0 init_on_alloc=0 tsx=off memory_corruption_check=0 noirqdebug zswap.enabled=0 iwlmvm.power_scheme=3 pcie_aspm=force split_lock_detect=off asus_wmi.fnlock_default=false efi_pstore.pstore_disable=0
[    4.222380] kernel: audit: disabled (until reboot)
[    4.222384] kernel: IRQ lockup detection disabled
[    4.222389] kernel: PCIe ASPM is forcibly enabled
[    4.222392] kernel: Unknown kernel command line parameters "BOOT_IMAGE=/vmlinuz-linux-sultan cryptdevice=UUID=086cda6b-894f-4a2b-b380-335846421e3f:cryptroot:allow-discards,no-read-workqueue,no-write-workqueue tsx=off split_lock_detect=off", will be passed to user space.
[    4.222396] kernel: random: crng init done
[    4.222400] kernel: printk: log_buf_len individual max cpu contribution: 4096 bytes
[    4.222403] kernel: printk: log_buf_len total cpu_extra contributions: 126976 bytes
[    4.222406] kernel: printk: log_buf_len min size: 131072 bytes
[    4.222409] kernel: printk: log buffer data + meta data: 262144 + 917504 = 1179648 bytes
[    4.222412] kernel: printk: early log buf free: 110568(84%)
[    4.222416] kernel: Dentry cache hash table entries: 8388608 (order: 14, 67108864 bytes, linear)
[    4.222419] kernel: Inode-cache hash table entries: 4194304 (order: 13, 33554432 bytes, linear)
[    4.222422] kernel: software IO TLB: area num 32.
[    4.222425] kernel: Fallback order for Node 0: 0 
[    4.222429] kernel: Built 1 zonelists, mobility grouping on.  Total pages: 15669857
[    4.222432] kernel: Policy zone: Normal
[    4.222435] kernel: mem auto-init: stack:all(zero), heap alloc:off, heap free:off
[    4.222438] kernel: SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=32, Nodes=1
[    4.222442] kernel: ftrace: allocating 55816 entries in 220 pages
[    4.222445] kernel: ftrace: allocated 220 pages with 5 groups
[    4.222448] kernel: Dynamic Preempt: full
[    4.222451] kernel: rcu: Preemptible hierarchical RCU implementation.
[    4.222455] kernel: rcu:         RCU restricting CPUs from NR_CPUS=8192 to nr_cpu_ids=32.
[    4.222459] kernel: rcu:         RCU priority boosting: priority 1 delay 500 ms.
[    4.222463] kernel:         Trampoline variant of Tasks RCU enabled.
[    4.222466] kernel:         Rude variant of Tasks RCU enabled.
[    4.222470] kernel:         Tracing variant of Tasks RCU enabled.
[    4.222473] kernel: rcu: RCU calculated value of scheduler-enlistment delay is 100 jiffies.
[    4.222476] kernel: rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=32
[    4.222479] kernel: RCU Tasks: Setting shift to 5 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=32.
[    4.222482] kernel: RCU Tasks Rude: Setting shift to 5 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=32.
[    4.222485] kernel: RCU Tasks Trace: Setting shift to 5 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=32.
[    4.222489] kernel: NR_IRQS: 524544, nr_irqs: 1224, preallocated irqs: 16
[    4.222492] kernel: rcu: srcu_init: Setting srcu_struct sizes based on contention.
[    4.222496] kernel: kfence: initialized - using 2097152 bytes for 255 objects at 0x(____ptrval____)-0x(____ptrval____)
[    4.222501] kernel: Console: colour dummy device 80x25
[    4.222504] kernel: printk: legacy console [tty0] enabled
[    4.222507] kernel: ACPI: Core revision 20250404
[    4.222511] kernel: clocksource: hpet: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 133484873504 ns
[    4.222516] kernel: APIC: Switch to symmetric I/O mode setup
[    4.222519] kernel: AMD-Vi: ivrs, add hid:AMDI0020, uid:ID00, rdevid:0xa0
[    4.222523] kernel: AMD-Vi: ivrs, add hid:AMDI0020, uid:ID01, rdevid:0xa0
[    4.222526] kernel: AMD-Vi: ivrs, add hid:AMDI0020, uid:ID02, rdevid:0xa0
[    4.222530] kernel: AMD-Vi: ivrs, add hid:AMDI0020, uid:ID03, rdevid:0xa0
[    4.222533] kernel: AMD-Vi: ivrs, add hid:MSFT0201, uid:1, rdevid:0x60
[    4.222536] kernel: AMD-Vi: ivrs, add hid:AMDI0020, uid:ID04, rdevid:0xa0
[    4.222539] kernel: AMD-Vi: Using global IVHD EFR:0x246577efa2254afa, EFR2:0x10
[    4.222542] kernel: ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
[    4.222547] kernel: clocksource: tsc-early: mask: 0xffffffffffffffff max_cycles: 0x2b285e92338, max_idle_ns: 440795203718 ns
[    4.222551] kernel: Calibrating delay loop (skipped), value calculated using timer frequency.. 5988.13 BogoMIPS (lpj=2994065)
[    4.222556] kernel: x86/cpu: User Mode Instruction Prevention (UMIP) activated
[    4.222561] kernel: LVT offset 1 assigned for vector 0xf9
[    4.222564] kernel: LVT offset 2 assigned for vector 0xf4
[    4.222567] kernel: Last level iTLB entries: 4KB 64, 2MB 64, 4MB 32
[    4.222571] kernel: Last level dTLB entries: 4KB 128, 2MB 128, 4MB 64, 1GB 0
[    4.222574] kernel: process: using mwait in idle threads
[    4.222577] kernel: Speculative Store Bypass: Mitigation: Speculative Store Bypass disabled via prctl
[    4.222580] kernel: Spectre V2 : Mitigation: Enhanced / Automatic IBRS
[    4.222583] kernel: Spectre V2 : User space: Mitigation: STIBP always-on protection
[    4.222587] kernel: Speculative Return Stack Overflow: Mitigation: IBPB on VMEXIT only
[    4.222590] kernel: Spectre V1 : Mitigation: usercopy/swapgs barriers and __user pointer sanitization
[    4.222594] kernel: Spectre V2 : mitigation: Enabling conditional Indirect Branch Prediction Barrier
[    4.222597] kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[    4.222600] kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[    4.222603] kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[    4.222606] kernel: x86/fpu: Supporting XSAVE feature 0x020: 'AVX-512 opmask'
[    4.222609] kernel: x86/fpu: Supporting XSAVE feature 0x040: 'AVX-512 Hi256'
[    4.222612] kernel: x86/fpu: Supporting XSAVE feature 0x080: 'AVX-512 ZMM_Hi256'
[    4.222616] kernel: x86/fpu: Supporting XSAVE feature 0x200: 'Protection Keys User registers'
[    4.222619] kernel: x86/fpu: Supporting XSAVE feature 0x800: 'Control-flow User registers'
[    4.222622] kernel: x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256
[    4.222626] kernel: x86/fpu: xstate_offset[5]:  832, xstate_sizes[5]:   64
[    4.222629] kernel: x86/fpu: xstate_offset[6]:  896, xstate_sizes[6]:  512
[    4.222632] kernel: x86/fpu: xstate_offset[7]: 1408, xstate_sizes[7]: 1024
[    4.222635] kernel: x86/fpu: xstate_offset[9]: 2432, xstate_sizes[9]:    8
[    4.222638] kernel: x86/fpu: xstate_offset[11]: 2440, xstate_sizes[11]:   16
[    4.222641] kernel: x86/fpu: Enabled xstate features 0xae7, context size is 2456 bytes, using 'compacted' format.
[    4.222644] kernel: Freeing SMP alternatives memory: 56K
[    4.222648] kernel: pid_max: default: 32768 minimum: 301
[    4.222651] kernel: LSM: initializing lsm=capability,landlock,lockdown,yama,bpf
[    4.222654] kernel: landlock: Up and running.
[    4.222657] kernel: Yama: becoming mindful.
[    4.222660] kernel: LSM support for eBPF active
[    4.222663] kernel: Mount-cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)
[    4.222666] kernel: Mountpoint-cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)
[    4.222670] kernel: smpboot: CPU0: AMD RYZEN AI MAX+ PRO 395 w/ Radeon 8060S (family: 0x1a, model: 0x70, stepping: 0x0)
[    4.222674] kernel: Performance Events: Fam17h+ 16-deep LBR, core perfctr, AMD PMU driver.
[    4.222677] kernel: ... version:                2
[    4.222680] kernel: ... bit width:              48
[    4.222684] kernel: ... generic registers:      6
[    4.222687] kernel: ... value mask:             0000ffffffffffff
[    4.222690] kernel: ... max period:             00007fffffffffff
[    4.222693] kernel: ... fixed-purpose events:   0
[    4.222699] kernel: ... event mask:             000000000000003f
[    4.222703] kernel: signal: max sigframe size: 3376
[    4.222706] kernel: rcu: Hierarchical SRCU implementation.
[    4.222709] kernel: rcu:         Max phase no-delay instances is 400.
[    4.222712] kernel: Timer migration: 2 hierarchy levels; 8 children per group; 2 crossnode level
[    4.222715] kernel: MCE: In-kernel MCE decoding enabled.
[    4.222718] kernel: NMI watchdog: Enabled. Permanently consumes one hw-PMU counter.
[    4.222721] kernel: smp: Bringing up secondary CPUs ...
[    4.222724] kernel: smpboot: x86: Booting SMP configuration:
[    4.222728] kernel: .... node  #0, CPUs:        #2  #4  #6  #8 #10 #12 #14 #16 #18 #20 #22 #24 #26 #28 #30  #1  #3  #5  #7  #9 #11 #13 #15 #17 #19 #21 #23 #25 #27 #29 #31
[    4.222731] kernel: Spectre V2 : Update user space SMT mitigation: STIBP always-on
[    4.222734] kernel: smp: Brought up 1 node, 32 CPUs
[    4.222737] kernel: smpboot: Total of 32 processors activated (191620.16 BogoMIPS)
[    4.222740] kernel: Memory: 61357380K/62679428K available (19619K kernel code, 2940K rwdata, 15820K rodata, 4644K init, 5040K bss, 1283092K reserved, 0K cma-reserved)
[    4.222743] kernel: devtmpfs: initialized
[    4.222747] kernel: x86/mm: Memory block size: 128MB
[    4.222752] kernel: ACPI: PM: Registering ACPI NVS region [mem 0x09f00000-0x09f87fff] (557056 bytes)
[    4.222757] kernel: ACPI: PM: Registering ACPI NVS region [mem 0x4899c000-0x4909bfff] (7340032 bytes)
[    4.222760] kernel: clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275000 ns
[    4.222763] kernel: posixtimers hash table entries: 16384 (order: 6, 262144 bytes, linear)
[    4.222766] kernel: futex hash table entries: 8192 (524288 bytes on 1 NUMA nodes, total 512 KiB, linear).
[    4.222769] kernel: pinctrl core: initialized pinctrl subsystem
[    4.222772] kernel: PM: RTC time: 06:54:06, date: 2025-07-29
[    4.222775] kernel: NET: Registered PF_NETLINK/PF_ROUTE protocol family
[    4.222778] kernel: DMA: preallocated 4096 KiB GFP_KERNEL pool for atomic allocations
[    4.222782] kernel: DMA: preallocated 4096 KiB GFP_KERNEL|GFP_DMA pool for atomic allocations
[    4.222785] kernel: DMA: preallocated 4096 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations
[    4.222788] kernel: thermal_sys: Registered thermal governor 'fair_share'
[    4.222791] kernel: thermal_sys: Registered thermal governor 'bang_bang'
[    4.222794] kernel: thermal_sys: Registered thermal governor 'step_wise'
[    4.222798] kernel: thermal_sys: Registered thermal governor 'user_space'
[    4.222801] kernel: thermal_sys: Registered thermal governor 'power_allocator'
[    4.222803] kernel: cpuidle: using governor ladder
[    4.222807] kernel: cpuidle: using governor menu
[    4.222811] kernel: ACPI FADT declares the system doesn't support PCIe ASPM, so disable it
[    4.222814] kernel: acpiphp: ACPI Hot Plug PCI Controller Driver version: 0.5
[    4.222817] kernel: PCI: ECAM [mem 0xe0000000-0xefffffff] (base 0xe0000000) for domain 0000 [bus 00-ff]
[    4.222820] kernel: PCI: Using configuration type 1 for base access
[    4.222824] kernel: kprobes: kprobe jump-optimization is enabled. All kprobes are optimized if possible.
[    4.222827] kernel: HugeTLB: allocation took 0ms with hugepage_allocation_threads=8
[    4.222830] kernel: HugeTLB: registered 1.00 GiB page size, pre-allocated 0 pages
[    4.222833] kernel: HugeTLB: 16380 KiB vmemmap can be freed for a 1.00 GiB page
[    4.222836] kernel: HugeTLB: registered 2.00 MiB page size, pre-allocated 0 pages
[    4.222840] kernel: HugeTLB: 28 KiB vmemmap can be freed for a 2.00 MiB page
[    4.222843] kernel: raid6: skipped pq benchmark and selected avx512x4
[    4.222846] kernel: raid6: using avx512x2 recovery algorithm
[    4.222849] kernel: ACPI: Added _OSI(Module Device)
[    4.222852] kernel: ACPI: Added _OSI(Processor Device)
[    4.222856] kernel: ACPI: Added _OSI(Processor Aggregator Device)
[    4.222859] kernel: ACPI: 34 ACPI AML tables successfully acquired and loaded
[    4.222862] kernel: ACPI: [Firmware Bug]: BIOS _OSI(Linux) query ignored
[    4.222865] kernel: ACPI: USB4 _OSC: OS supports USB3+ DisplayPort+ PCIe+ XDomain+
[    4.222868] kernel: ACPI: USB4 _OSC: OS controls USB3+ DisplayPort+ PCIe+ XDomain+
[    4.222872] kernel: ACPI: EC: EC started
[    4.222875] kernel: ACPI: EC: interrupt blocked
[    4.222878] kernel: ACPI: EC: EC_CMD/EC_SC=0x66, EC_DATA=0x62
[    4.222881] kernel: ACPI: \_SB_.PCI0.LPCB.EC0_: Boot DSDT EC used to handle transactions
[    4.222884] kernel: ACPI: Interpreter enabled
[    4.222888] kernel: ACPI: PM: (supports S0 S4 S5)
[    4.222891] kernel: ACPI: Using IOAPIC for interrupt routing
[    4.222894] kernel: PCI: Using host bridge windows from ACPI; if necessary, use "pci=nocrs" and report a bug
[    4.222897] kernel: PCI: Ignoring E820 reservations for host bridge windows
[    4.222901] kernel: ACPI: Enabled 6 GPEs in block 00 to 1F
[    4.222904] kernel: ACPI: \_SB_.PCI0.GP11.PWRS: New power resource
[    4.222907] kernel: ACPI: \_SB_.PCI0.GP11.SWUS.PWRS: New power resource
[    4.222910] kernel: ACPI: \_SB_.PCI0.GP12.PWRS: New power resource
[    4.222913] kernel: ACPI: \_SB_.PCI0.GP12.SWUS.PWRS: New power resource
[    4.222916] kernel: ACPI: \_SB_.PCI0.GP21.PWRS: New power resource
[    4.222919] kernel: ACPI: \_SB_.PCI0.GP22.PWRS: New power resource
[    4.222922] kernel: ACPI: \_SB_.PCI0.GP23.NCRD.WRST: New power resource
[    4.222926] kernel: ACPI: \_SB_.PCI0.GP25.P0NV: New power resource
[    4.222929] kernel: ACPI: \_SB_.PCI0.GPPA.PWRS: New power resource
[    4.222932] kernel: ACPI: \_SB_.PCI0.GPPA.GFX0.PWRS: New power resource
[    4.222935] kernel: ACPI: \_SB_.PCI0.GPPA.HDAU.PWRS: New power resource
[    4.222938] kernel: ACPI: \_SB_.PCI0.GPPA.XHC1.PWRS: New power resource
[    4.222941] kernel: ACPI: \_SB_.PCI0.GPPA.ACP_.PWRS: New power resource
[    4.222945] kernel: ACPI: \_SB_.PCI0.GPPA.HDEF.PWRS: New power resource
[    4.222948] kernel: ACPI: \_SB_.PCI0.BUSC.XHC0.PWRS: New power resource
[    4.222952] kernel: ACPI: \_SB_.PCI0.BUSC.XHC0.RHUB.HS05.DBTR: New power resource
[    4.222955] kernel: ACPI: \_SB_.PCI0.BUSC.XHC3.PWRS: New power resource
[    4.222958] kernel: ACPI: \_SB_.PCI0.BUSC.XHC4.PWRS: New power resource
[    4.222961] kernel: ACPI: \_SB_.PCI0.BUSC.NHI0.PWRS: New power resource
[    4.222965] kernel: ACPI: \_SB_.PCI0.BUSC.NHI1.PWRS: New power resource
[    4.222968] kernel: ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff])
[    4.223054] kernel: acpi PNP0A08:00: _OSC: OS supports [ExtendedConfig ASPM ClockPM Segments MSI EDR HPX-Type3]
[    4.223094] kernel: acpi PNP0A08:00: _OSC: platform does not support [SHPCHotplug AER]
[    4.223129] kernel: acpi PNP0A08:00: _OSC: OS now controls [PCIeHotplug PME PCIeCapability LTR DPC]
[    4.223163] kernel: acpi PNP0A08:00: FADT indicates ASPM is unsupported, using BIOS configuration
[    4.223167] kernel: PCI host bridge to bus 0000:00
[    4.223206] kernel: pci_bus 0000:00: root bus resource [io  0x0000-0x0cf7 window]
[    4.223237] kernel: pci_bus 0000:00: root bus resource [io  0x0d00-0xffff window]
[    4.223267] kernel: pci_bus 0000:00: root bus resource [mem 0x000a0000-0x000bffff window]
[    4.223297] kernel: pci_bus 0000:00: root bus resource [mem 0x000c0000-0x000cffff window]
[    4.223327] kernel: pci_bus 0000:00: root bus resource [mem 0x000d0000-0x000effff window]
[    4.223357] kernel: pci_bus 0000:00: root bus resource [mem 0x80000000-0xefffffff window]
[    4.223387] kernel: pci_bus 0000:00: root bus resource [mem 0xfed45000-0xfed814ff window]
[    4.223416] kernel: pci_bus 0000:00: root bus resource [mem 0xfed81900-0xfed81fff window]
[    4.223446] kernel: pci_bus 0000:00: root bus resource [mem 0xfedc0000-0xfedc0fff window]
[    4.223476] kernel: pci_bus 0000:00: root bus resource [mem 0xfedc6000-0xfedc6fff window]
[    4.223506] kernel: pci_bus 0000:00: root bus resource [mem 0xf7e0c0000-0x108fffffff window]
[    4.223535] kernel: pci_bus 0000:00: root bus resource [mem 0x10b0200000-0x8b4fffffff window]
[    4.223564] kernel: pci_bus 0000:00: root bus resource [bus 00-ff]
[    4.223605] kernel: pci 0000:00:00.0: [1022:1507] type 00 class 0x060000 conventional PCI endpoint
[    4.223642] kernel: pci 0000:00:00.2: [1022:1508] type 00 class 0x080600 conventional PCI endpoint
[    4.223678] kernel: pci 0000:00:01.0: [1022:1509] type 00 class 0x060000 conventional PCI endpoint
[    4.223714] kernel: pci 0000:00:01.1: [1022:150a] type 01 class 0x060400 PCIe Root Port
[    4.223749] kernel: pci 0000:00:01.1: PCI bridge to [bus 01-60]
[    4.223782] kernel: pci 0000:00:01.1:   bridge window [io  0x6000-0x9fff]
[    4.223816] kernel: pci 0000:00:01.1:   bridge window [mem 0xbc000000-0xd3ffffff]
[    4.223852] kernel: pci 0000:00:01.1:   bridge window [mem 0x3800000000-0x57ffffffff 64bit pref]
[    4.223885] kernel: pci 0000:00:01.1: PME# supported from D0 D3hot D3cold
[    4.223920] kernel: pci 0000:00:01.2: [1022:150a] type 01 class 0x060400 PCIe Root Port
[    4.223954] kernel: pci 0000:00:01.2: PCI bridge to [bus 61-c0]
[    4.223987] kernel: pci 0000:00:01.2:   bridge window [io  0x2000-0x5fff]
[    4.224025] kernel: pci 0000:00:01.2:   bridge window [mem 0xa4000000-0xbbffffff]
[    4.224060] kernel: pci 0000:00:01.2:   bridge window [mem 0x1800000000-0x37ffffffff 64bit pref]
[    4.224092] kernel: pci 0000:00:01.2: PME# supported from D0 D3hot D3cold
[    4.224127] kernel: pci 0000:00:02.0: [1022:1509] type 00 class 0x060000 conventional PCI endpoint
[    4.224162] kernel: pci 0000:00:02.3: [1022:150b] type 01 class 0x060400 PCIe Root Port
[    4.224197] kernel: pci 0000:00:02.3: PCI bridge to [bus c1]
[    4.224230] kernel: pci 0000:00:02.3:   bridge window [mem 0xd4000000-0xd42fffff]
[    4.224263] kernel: pci 0000:00:02.3: PME# supported from D0 D3hot D3cold
[    4.224298] kernel: pci 0000:00:02.5: [1022:150b] type 01 class 0x060400 PCIe Root Port
[    4.224332] kernel: pci 0000:00:02.5: PCI bridge to [bus c2]
[    4.224366] kernel: pci 0000:00:02.5:   bridge window [mem 0xd4900000-0xd49fffff]
[    4.224399] kernel: pci 0000:00:02.5: PME# supported from D0 D3hot D3cold
[    4.224433] kernel: pci 0000:00:03.0: [1022:1509] type 00 class 0x060000 conventional PCI endpoint
[    4.224469] kernel: pci 0000:00:08.0: [1022:1509] type 00 class 0x060000 conventional PCI endpoint
[    4.224503] kernel: pci 0000:00:08.1: [1022:150c] type 01 class 0x060400 PCIe Root Port
[    4.224537] kernel: pci 0000:00:08.1: PCI bridge to [bus c3]
[    4.224571] kernel: pci 0000:00:08.1:   bridge window [io  0x1000-0x1fff]
[    4.224604] kernel: pci 0000:00:08.1:   bridge window [mem 0x90000000-0xa04fffff]
[    4.224638] kernel: pci 0000:00:08.1:   bridge window [mem 0x5800000000-0x59007fffff 64bit pref]
[    4.224672] kernel: pci 0000:00:08.1: enabling Extended Tags
[    4.224705] kernel: pci 0000:00:08.1: PME# supported from D0 D3hot D3cold
[    4.224739] kernel: pci 0000:00:08.2: [1022:150c] type 01 class 0x060400 PCIe Root Port
[    4.224772] kernel: pci 0000:00:08.2: PCI bridge to [bus c4]
[    4.224805] kernel: pci 0000:00:08.2:   bridge window [mem 0xd4700000-0xd48fffff]
[    4.224840] kernel: pci 0000:00:08.2:   bridge window [mem 0x5900800000-0x59008fffff 64bit pref]
[    4.224873] kernel: pci 0000:00:08.2: enabling Extended Tags
[    4.224907] kernel: pci 0000:00:08.2: PME# supported from D0 D3hot D3cold
[    4.224941] kernel: pci 0000:00:08.3: [1022:150c] type 01 class 0x060400 PCIe Root Port
[    4.224975] kernel: pci 0000:00:08.3: PCI bridge to [bus c5]
[    4.225012] kernel: pci 0000:00:08.3:   bridge window [mem 0xd4300000-0xd46fffff]
[    4.225045] kernel: pci 0000:00:08.3: enabling Extended Tags
[    4.225079] kernel: pci 0000:00:08.3: PME# supported from D0 D3hot D3cold
[    4.225113] kernel: pci 0000:00:14.0: [1022:790b] type 00 class 0x0c0500 conventional PCI endpoint
[    4.225147] kernel: pci 0000:00:14.3: [1022:790e] type 00 class 0x060100 conventional PCI endpoint
[    4.225181] kernel: pci 0000:00:18.0: [1022:12b8] type 00 class 0x060000 conventional PCI endpoint
[    4.225216] kernel: pci 0000:00:18.1: [1022:12b9] type 00 class 0x060000 conventional PCI endpoint
[    4.225250] kernel: pci 0000:00:18.2: [1022:12ba] type 00 class 0x060000 conventional PCI endpoint
[    4.225286] kernel: pci 0000:00:18.3: [1022:12bb] type 00 class 0x060000 conventional PCI endpoint
[    4.225321] kernel: pci 0000:00:18.4: [1022:12bc] type 00 class 0x060000 conventional PCI endpoint
[    4.225356] kernel: pci 0000:00:18.5: [1022:12bd] type 00 class 0x060000 conventional PCI endpoint
[    4.225391] kernel: pci 0000:00:18.6: [1022:12be] type 00 class 0x060000 conventional PCI endpoint
[    4.225429] kernel: pci 0000:00:18.7: [1022:12bf] type 00 class 0x060000 conventional PCI endpoint
[    4.225464] kernel: pci 0000:00:01.1: PCI bridge to [bus 01-60]
[    4.225498] kernel: pci 0000:00:01.2: PCI bridge to [bus 61-c0]
[    4.225537] kernel: pci 0000:c1:00.0: [14c3:7925] type 00 class 0x028000 PCIe Endpoint
[    4.225572] kernel: pci 0000:c1:00.0: BAR 0 [mem 0xd4000000-0xd41fffff 64bit]
[    4.225607] kernel: pci 0000:c1:00.0: BAR 2 [mem 0xd4200000-0xd4207fff 64bit]
[    4.225655] kernel: pci 0000:c1:00.0: PME# supported from D0 D3hot D3cold
[    4.225689] kernel: pci 0000:00:02.3: PCI bridge to [bus c1]
[    4.225725] kernel: pci 0000:c2:00.0: [144d:a80c] type 00 class 0x010802 PCIe Endpoint
[    4.225760] kernel: pci 0000:c2:00.0: BAR 0 [mem 0xd4900000-0xd4903fff 64bit]
[    4.225794] kernel: pci 0000:00:02.5: PCI bridge to [bus c2]
[    4.225829] kernel: pci 0000:c3:00.0: [1002:1586] type 00 class 0x038000 PCIe Legacy Endpoint
[    4.225863] kernel: pci 0000:c3:00.0: BAR 0 [mem 0x5800000000-0x58ffffffff 64bit pref]
[    4.225897] kernel: pci 0000:c3:00.0: BAR 2 [mem 0x90000000-0x9fffffff 64bit pref]
[    4.225931] kernel: pci 0000:c3:00.0: BAR 4 [io  0x1000-0x10ff]
[    4.225966] kernel: pci 0000:c3:00.0: BAR 5 [mem 0xa0300000-0xa03fffff]
[    4.226001] kernel: pci 0000:c3:00.0: enabling Extended Tags
[    4.226038] kernel: pci 0000:c3:00.0: PME# supported from D1 D2 D3hot D3cold
[    4.226073] kernel: pci 0000:c3:00.1: [1002:1640] type 00 class 0x040300 PCIe Legacy Endpoint
[    4.226107] kernel: pci 0000:c3:00.1: BAR 0 [mem 0xa0448000-0xa044bfff]
[    4.226140] kernel: pci 0000:c3:00.1: enabling Extended Tags
[    4.226173] kernel: pci 0000:c3:00.1: PME# supported from D1 D2 D3hot D3cold
[    4.226209] kernel: pci 0000:c3:00.2: [1022:17e0] type 00 class 0x108000 PCIe Endpoint
[    4.226243] kernel: pci 0000:c3:00.2: BAR 2 [mem 0xa0200000-0xa02fffff]
[    4.226278] kernel: pci 0000:c3:00.2: BAR 5 [mem 0xa044e000-0xa044ffff]
[    4.226312] kernel: pci 0000:c3:00.2: enabling Extended Tags
[    4.226348] kernel: pci 0000:c3:00.4: [1022:1587] type 00 class 0x0c0330 PCIe Endpoint
[    4.226382] kernel: pci 0000:c3:00.4: BAR 0 [mem 0xa0000000-0xa00fffff 64bit]
[    4.226416] kernel: pci 0000:c3:00.4: enabling Extended Tags
[    4.226450] kernel: pci 0000:c3:00.4: PME# supported from D0 D3hot D3cold
[    4.226485] kernel: pci 0000:c3:00.5: [1022:15e2] type 00 class 0x048000 PCIe Endpoint
[    4.226520] kernel: pci 0000:c3:00.5: BAR 0 [mem 0xa0400000-0xa043ffff]
[    4.226554] kernel: pci 0000:c3:00.5: BAR 2 [mem 0x5900000000-0x59007fffff 64bit pref]
[    4.226587] kernel: pci 0000:c3:00.5: enabling Extended Tags
[    4.226621] kernel: pci 0000:c3:00.5: PME# supported from D0 D3hot D3cold
[    4.226655] kernel: pci 0000:c3:00.6: [1022:15e3] type 00 class 0x040300 PCIe Endpoint
[    4.226689] kernel: pci 0000:c3:00.6: BAR 0 [mem 0xa0440000-0xa0447fff]
[    4.226723] kernel: pci 0000:c3:00.6: enabling Extended Tags
[    4.226756] kernel: pci 0000:c3:00.6: PME# supported from D0 D3hot D3cold
[    4.226792] kernel: pci 0000:c3:00.7: [1022:164a] type 00 class 0x118000 PCIe Endpoint
[    4.226826] kernel: pci 0000:c3:00.7: BAR 2 [mem 0xa0100000-0xa01fffff]
[    4.226859] kernel: pci 0000:c3:00.7: BAR 5 [mem 0xa044c000-0xa044dfff]
[    4.226893] kernel: pci 0000:c3:00.7: enabling Extended Tags
[    4.226925] kernel: pci 0000:00:08.1: PCI bridge to [bus c3]
[    4.226960] kernel: pci 0000:c4:00.0: [1022:150d] type 00 class 0x130000 PCIe Endpoint
[    4.226995] kernel: pci 0000:c4:00.0: enabling Extended Tags
[    4.227041] kernel: pci 0000:c4:00.1: [1022:17f0] type 00 class 0x118000 PCIe Endpoint
[    4.227077] kernel: pci 0000:c4:00.1: BAR 0 [mem 0xd4700000-0xd47fffff]
[    4.227110] kernel: pci 0000:c4:00.1: BAR 1 [mem 0xd4800000-0xd4801fff]
[    4.227143] kernel: pci 0000:c4:00.1: BAR 2 [mem 0x5900800000-0x590087ffff 64bit pref]
[    4.227177] kernel: pci 0000:c4:00.1: BAR 4 [mem 0xd4803000-0xd4803fff]
[    4.227210] kernel: pci 0000:c4:00.1: BAR 5 [mem 0xd4802000-0xd4802fff]
[    4.227244] kernel: pci 0000:c4:00.1: enabling Extended Tags
[    4.227277] kernel: pci 0000:00:08.2: PCI bridge to [bus c4]
[    4.227312] kernel: pci 0000:c5:00.0: [1022:1588] type 00 class 0x0c0330 PCIe Endpoint
[    4.227347] kernel: pci 0000:c5:00.0: BAR 0 [mem 0xd4300000-0xd43fffff 64bit]
[    4.227382] kernel: pci 0000:c5:00.0: enabling Extended Tags
[    4.227417] kernel: pci 0000:c5:00.0: PME# supported from D0 D3hot D3cold
[    4.227452] kernel: pci 0000:c5:00.3: [1022:1589] type 00 class 0x0c0330 PCIe Endpoint
[    4.227486] kernel: pci 0000:c5:00.3: BAR 0 [mem 0xd4400000-0xd44fffff 64bit]
[    4.227520] kernel: pci 0000:c5:00.3: enabling Extended Tags
[    4.227555] kernel: pci 0000:c5:00.3: PME# supported from D0 D3hot D3cold
[    4.227591] kernel: pci 0000:c5:00.4: [1022:158b] type 00 class 0x0c0330 PCIe Endpoint
[    4.227627] kernel: pci 0000:c5:00.4: BAR 0 [mem 0xd4500000-0xd45fffff 64bit]
[    4.227660] kernel: pci 0000:c5:00.4: enabling Extended Tags
[    4.227695] kernel: pci 0000:c5:00.4: PME# supported from D0 D3hot D3cold
[    4.227732] kernel: pci 0000:c5:00.5: [1022:158d] type 00 class 0x0c0340 PCIe Endpoint
[    4.227766] kernel: pci 0000:c5:00.5: BAR 0 [mem 0xd4600000-0xd467ffff 64bit]
[    4.227801] kernel: pci 0000:c5:00.5: Max Payload Size set to 128 (was 256, max 256)
[    4.227835] kernel: pci 0000:c5:00.5: enabling Extended Tags
[    4.227869] kernel: pci 0000:c5:00.5: PME# supported from D0 D3hot D3cold
[    4.227906] kernel: pci 0000:c5:00.6: [1022:158e] type 00 class 0x0c0340 PCIe Endpoint
[    4.227942] kernel: pci 0000:c5:00.6: BAR 0 [mem 0xd4680000-0xd46fffff 64bit]
[    4.227976] kernel: pci 0000:c5:00.6: Max Payload Size set to 128 (was 256, max 256)
[    4.228014] kernel: pci 0000:c5:00.6: enabling Extended Tags
[    4.228049] kernel: pci 0000:c5:00.6: PME# supported from D0 D3hot D3cold
[    4.228083] kernel: pci 0000:00:08.3: PCI bridge to [bus c5]
[    4.228087] kernel: Low-power S0 idle used by default for system suspend
[    4.228091] kernel: ACPI: PCI: Interrupt link LNKA configured for IRQ 0
[    4.228095] kernel: ACPI: PCI: Interrupt link LNKA disabled
[    4.228099] kernel: ACPI: PCI: Interrupt link LNKB configured for IRQ 0
[    4.228102] kernel: ACPI: PCI: Interrupt link LNKB disabled
[    4.228106] kernel: ACPI: PCI: Interrupt link LNKC configured for IRQ 0
[    4.228110] kernel: ACPI: PCI: Interrupt link LNKC disabled
[    4.228113] kernel: ACPI: PCI: Interrupt link LNKD configured for IRQ 0
[    4.228117] kernel: ACPI: PCI: Interrupt link LNKD disabled
[    4.228120] kernel: ACPI: PCI: Interrupt link LNKE configured for IRQ 0
[    4.228124] kernel: ACPI: PCI: Interrupt link LNKE disabled
[    4.228127] kernel: ACPI: PCI: Interrupt link LNKF configured for IRQ 0
[    4.228131] kernel: ACPI: PCI: Interrupt link LNKF disabled
[    4.228133] kernel: ACPI: PCI: Interrupt link LNKG configured for IRQ 0
[    4.228137] kernel: ACPI: PCI: Interrupt link LNKG disabled
[    4.228140] kernel: ACPI: PCI: Interrupt link LNKH configured for IRQ 0
[    4.228143] kernel: ACPI: PCI: Interrupt link LNKH disabled
[    4.228147] kernel: ACPI: EC: interrupt unblocked
[    4.228151] kernel: ACPI: EC: event unblocked
[    4.228154] kernel: ACPI: EC: EC_CMD/EC_SC=0x66, EC_DATA=0x62
[    4.228158] kernel: ACPI: EC: GPE=0x3
[    4.228162] kernel: ACPI: \_SB_.PCI0.LPCB.EC0_: Boot DSDT EC initialization complete
[    4.228165] kernel: ACPI: \_SB_.PCI0.LPCB.EC0_: EC: Used to handle transactions and events
[    4.228169] kernel: iommu: Default domain type: Translated
[    4.228172] kernel: iommu: DMA domain TLB invalidation policy: lazy mode
[    4.228178] kernel: SCSI subsystem initialized
[    4.228182] kernel: libata version 3.00 loaded.
[    4.228185] kernel: ACPI: bus type USB registered
[    4.228188] kernel: usbcore: registered new interface driver usbfs
[    4.228192] kernel: usbcore: registered new interface driver hub
[    4.228195] kernel: usbcore: registered new device driver usb
[    4.228198] kernel: EDAC MC: Ver: 3.0.0
[    4.228202] kernel: efivars: Registered efivars operations
[    4.228205] kernel: NetLabel: Initializing
[    4.228209] kernel: NetLabel:  domain hash size = 128
[    4.228212] kernel: NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO
[    4.228215] kernel: NetLabel:  unlabeled traffic allowed by default
[    4.228219] kernel: mctp: management component transport protocol core
[    4.228222] kernel: NET: Registered PF_MCTP protocol family
[    4.228226] kernel: PCI: Using ACPI for IRQ routing
[    4.228230] kernel: PCI: pci_cache_line_size set to 64 bytes
[    4.228233] kernel: e820: reserve RAM buffer [mem 0x0009f000-0x0009ffff]
[    4.228237] kernel: e820: reserve RAM buffer [mem 0x09f00000-0x0bffffff]
[    4.228240] kernel: e820: reserve RAM buffer [mem 0x37bee000-0x37ffffff]
[    4.228244] kernel: e820: reserve RAM buffer [mem 0x44bd0000-0x47ffffff]
[    4.228247] kernel: e820: reserve RAM buffer [mem 0x52bd2000-0x53ffffff]
[    4.228250] kernel: e820: reserve RAM buffer [mem 0x52bdc000-0x53ffffff]
[    4.228253] kernel: e820: reserve RAM buffer [mem 0x5d134000-0x5fffffff]
[    4.228257] kernel: e820: reserve RAM buffer [mem 0xf7e0c0000-0xf7fffffff]
[    4.228261] kernel: vgaarb: loaded
[    4.228264] kernel: hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0
[    4.228267] kernel: hpet0: 3 comparators, 32-bit 14.318180 MHz counter
[    4.228270] kernel: clocksource: Switched to clocksource tsc-early
[    4.228274] kernel: VFS: Disk quotas dquot_6.6.0
[    4.228278] kernel: VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    4.228281] kernel: pnp: PnP ACPI init
[    4.228317] kernel: system 00:01: [io  0x0400-0x04cf] has been reserved
[    4.228350] kernel: system 00:01: [io  0x04d0-0x04d1] has been reserved
[    4.228382] kernel: system 00:01: [io  0x04d6] has been reserved
[    4.228413] kernel: system 00:01: [io  0x0680-0x06ff] has been reserved
[    4.228445] kernel: system 00:01: [io  0x077a] has been reserved
[    4.228475] kernel: system 00:01: [io  0x0c00-0x0c01] has been reserved
[    4.228507] kernel: system 00:01: [io  0x0c14] has been reserved
[    4.228538] kernel: system 00:01: [io  0x0c50-0x0c52] has been reserved
[    4.228568] kernel: system 00:01: [io  0x0c6c] has been reserved
[    4.228599] kernel: system 00:01: [io  0x0c6f] has been reserved
[    4.228629] kernel: system 00:01: [io  0x0cd0-0x0cdb] has been reserved
[    4.228660] kernel: system 00:01: [io  0x0840-0x0847] has been reserved
[    4.228692] kernel: system 00:02: [mem 0x000e0000-0x000fffff] could not be reserved
[    4.228725] kernel: system 00:04: [io  0x0600-0x067f] has been reserved
[    4.228756] kernel: system 00:04: [mem 0xfedf1000-0xfedf1fff] has been reserved
[    4.228788] kernel: system 00:05: [mem 0xfec00000-0xfec00fff] could not be reserved
[    4.228819] kernel: system 00:05: [mem 0xfee00000-0xfee00fff] has been reserved
[    4.228850] kernel: system 00:05: [mem 0xfec20000-0xfec20fff] has been reserved
[    4.228883] kernel: system 00:06: [mem 0xfed40000-0xfed44fff] has been reserved
[    4.228887] kernel: pnp: PnP ACPI: found 7 devices
[    4.228891] kernel: clocksource: acpi_pm: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 2085701024 ns
[    4.228894] kernel: NET: Registered PF_INET protocol family
[    4.228898] kernel: IP idents hash table entries: 262144 (order: 9, 2097152 bytes, linear)
[    4.228901] kernel: tcp_listen_portaddr_hash hash table entries: 32768 (order: 7, 524288 bytes, linear)
[    4.228904] kernel: Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    4.228908] kernel: TCP established hash table entries: 524288 (order: 10, 4194304 bytes, linear)
[    4.228912] kernel: TCP bind hash table entries: 65536 (order: 9, 2097152 bytes, linear)
[    4.228915] kernel: TCP: Hash tables configured (established 524288 bind 65536)
[    4.228918] kernel: MPTCP token hash table entries: 65536 (order: 8, 1572864 bytes, linear)
[    4.228922] kernel: UDP hash table entries: 32768 (order: 9, 2097152 bytes, linear)
[    4.228925] kernel: UDP-Lite hash table entries: 32768 (order: 9, 2097152 bytes, linear)
[    4.228929] kernel: NET: Registered PF_UNIX/PF_LOCAL protocol family
[    4.228933] kernel: NET: Registered PF_XDP protocol family
[    4.228966] kernel: pci 0000:00:01.1: PCI bridge to [bus 01-60]
[    4.229001] kernel: pci 0000:00:01.1:   bridge window [io  0x6000-0x9fff]
[    4.229037] kernel: pci 0000:00:01.1:   bridge window [mem 0xbc000000-0xd3ffffff]
[    4.229070] kernel: pci 0000:00:01.1:   bridge window [mem 0x3800000000-0x57ffffffff 64bit pref]
[    4.229104] kernel: pci 0000:00:01.2: PCI bridge to [bus 61-c0]
[    4.229136] kernel: pci 0000:00:01.2:   bridge window [io  0x2000-0x5fff]
[    4.229171] kernel: pci 0000:00:01.2:   bridge window [mem 0xa4000000-0xbbffffff]
[    4.229204] kernel: pci 0000:00:01.2:   bridge window [mem 0x1800000000-0x37ffffffff 64bit pref]
[    4.229237] kernel: pci 0000:00:02.3: PCI bridge to [bus c1]
[    4.229269] kernel: pci 0000:00:02.3:   bridge window [mem 0xd4000000-0xd42fffff]
[    4.229302] kernel: pci 0000:00:02.5: PCI bridge to [bus c2]
[    4.229335] kernel: pci 0000:00:02.5:   bridge window [mem 0xd4900000-0xd49fffff]
[    4.229369] kernel: pci 0000:00:08.1: PCI bridge to [bus c3]
[    4.229402] kernel: pci 0000:00:08.1:   bridge window [io  0x1000-0x1fff]
[    4.229435] kernel: pci 0000:00:08.1:   bridge window [mem 0x90000000-0xa04fffff]
[    4.229468] kernel: pci 0000:00:08.1:   bridge window [mem 0x5800000000-0x59007fffff 64bit pref]
[    4.229502] kernel: pci 0000:00:08.2: PCI bridge to [bus c4]
[    4.229535] kernel: pci 0000:00:08.2:   bridge window [mem 0xd4700000-0xd48fffff]
[    4.229567] kernel: pci 0000:00:08.2:   bridge window [mem 0x5900800000-0x59008fffff 64bit pref]
[    4.229600] kernel: pci 0000:00:08.3: PCI bridge to [bus c5]
[    4.229633] kernel: pci 0000:00:08.3:   bridge window [mem 0xd4300000-0xd46fffff]
[    4.229665] kernel: pci_bus 0000:00: resource 4 [io  0x0000-0x0cf7 window]
[    4.229696] kernel: pci_bus 0000:00: resource 5 [io  0x0d00-0xffff window]
[    4.229726] kernel: pci_bus 0000:00: resource 6 [mem 0x000a0000-0x000bffff window]
[    4.229755] kernel: pci_bus 0000:00: resource 7 [mem 0x000c0000-0x000cffff window]
[    4.229784] kernel: pci_bus 0000:00: resource 8 [mem 0x000d0000-0x000effff window]
[    4.229814] kernel: pci_bus 0000:00: resource 9 [mem 0x80000000-0xefffffff window]
[    4.229843] kernel: pci_bus 0000:00: resource 10 [mem 0xfed45000-0xfed814ff window]
[    4.229873] kernel: pci_bus 0000:00: resource 11 [mem 0xfed81900-0xfed81fff window]
[    4.229901] kernel: pci_bus 0000:00: resource 12 [mem 0xfedc0000-0xfedc0fff window]
[    4.229931] kernel: pci_bus 0000:00: resource 13 [mem 0xfedc6000-0xfedc6fff window]
[    4.229960] kernel: pci_bus 0000:00: resource 14 [mem 0xf7e0c0000-0x108fffffff window]
[    4.229989] kernel: pci_bus 0000:00: resource 15 [mem 0x10b0200000-0x8b4fffffff window]
[    4.230071] kernel: pci_bus 0000:01: resource 0 [io  0x6000-0x9fff]
[    4.230102] kernel: pci_bus 0000:01: resource 1 [mem 0xbc000000-0xd3ffffff]
[    4.230134] kernel: pci_bus 0000:01: resource 2 [mem 0x3800000000-0x57ffffffff 64bit pref]
[    4.230169] kernel: pci_bus 0000:61: resource 0 [io  0x2000-0x5fff]
[    4.230200] kernel: pci_bus 0000:61: resource 1 [mem 0xa4000000-0xbbffffff]
[    4.230230] kernel: pci_bus 0000:61: resource 2 [mem 0x1800000000-0x37ffffffff 64bit pref]
[    4.230265] kernel: pci_bus 0000:c1: resource 1 [mem 0xd4000000-0xd42fffff]
[    4.230301] kernel: pci_bus 0000:c2: resource 1 [mem 0xd4900000-0xd49fffff]
[    4.230338] kernel: pci_bus 0000:c3: resource 0 [io  0x1000-0x1fff]
[    4.230369] kernel: pci_bus 0000:c3: resource 1 [mem 0x90000000-0xa04fffff]
[    4.230401] kernel: pci_bus 0000:c3: resource 2 [mem 0x5800000000-0x59007fffff 64bit pref]
[    4.230437] kernel: pci_bus 0000:c4: resource 1 [mem 0xd4700000-0xd48fffff]
[    4.230467] kernel: pci_bus 0000:c4: resource 2 [mem 0x5900800000-0x59008fffff 64bit pref]
[    4.230503] kernel: pci_bus 0000:c5: resource 1 [mem 0xd4300000-0xd46fffff]
[    4.230538] kernel: pci 0000:c3:00.1: D0 power state depends on 0000:c3:00.0
[    4.230574] kernel: pci 0000:c3:00.4: enabling device (0000 -> 0002)
[    4.230609] kernel: pci 0000:c5:00.0: enabling device (0000 -> 0002)
[    4.230643] kernel: pci 0000:c5:00.3: enabling device (0000 -> 0002)
[    4.230677] kernel: pci 0000:c5:00.4: enabling device (0000 -> 0002)
[    4.230682] kernel: PCI: CLS 0 bytes, default 64
[    4.230715] kernel: pci 0000:00:00.2: AMD-Vi: IOMMU performance counters supported
[    4.230719] kernel: Trying to unpack rootfs image as initramfs...
[    4.230753] kernel: pci 0000:00:00.0: Adding to iommu group 0
[    4.230787] kernel: pci 0000:00:01.0: Adding to iommu group 1
[    4.230822] kernel: pci 0000:00:01.1: Adding to iommu group 2
[    4.230854] kernel: pci 0000:00:01.2: Adding to iommu group 3
[    4.230887] kernel: pci 0000:00:02.0: Adding to iommu group 4
[    4.230920] kernel: pci 0000:00:02.3: Adding to iommu group 5
[    4.230953] kernel: pci 0000:00:02.5: Adding to iommu group 6
[    4.230986] kernel: pci 0000:00:03.0: Adding to iommu group 7
[    4.231022] kernel: pci 0000:00:08.0: Adding to iommu group 8
[    4.231056] kernel: pci 0000:00:08.1: Adding to iommu group 9
[    4.231090] kernel: pci 0000:00:08.2: Adding to iommu group 10
[    4.231123] kernel: pci 0000:00:08.3: Adding to iommu group 11
[    4.231156] kernel: pci 0000:00:14.0: Adding to iommu group 12
[    4.231189] kernel: pci 0000:00:14.3: Adding to iommu group 12
[    4.231222] kernel: pci 0000:00:18.0: Adding to iommu group 13
[    4.231255] kernel: pci 0000:00:18.1: Adding to iommu group 13
[    4.231288] kernel: pci 0000:00:18.2: Adding to iommu group 13
[    4.231321] kernel: pci 0000:00:18.3: Adding to iommu group 13
[    4.231355] kernel: pci 0000:00:18.4: Adding to iommu group 13
[    4.231388] kernel: pci 0000:00:18.5: Adding to iommu group 13
[    4.231422] kernel: pci 0000:00:18.6: Adding to iommu group 13
[    4.231455] kernel: pci 0000:00:18.7: Adding to iommu group 13
[    4.231488] kernel: pci 0000:c1:00.0: Adding to iommu group 14
[    4.231523] kernel: pci 0000:c2:00.0: Adding to iommu group 15
[    4.231556] kernel: pci 0000:c3:00.0: Adding to iommu group 16
[    4.231591] kernel: pci 0000:c3:00.1: Adding to iommu group 17
[    4.231625] kernel: pci 0000:c3:00.2: Adding to iommu group 18
[    4.231660] kernel: pci 0000:c3:00.4: Adding to iommu group 19
[    4.231694] kernel: pci 0000:c3:00.5: Adding to iommu group 20
[    4.231728] kernel: pci 0000:c3:00.6: Adding to iommu group 21
[    4.231763] kernel: pci 0000:c3:00.7: Adding to iommu group 22
[    4.231797] kernel: pci 0000:c4:00.0: Adding to iommu group 23
[    4.231831] kernel: pci 0000:c4:00.1: Adding to iommu group 24
[    4.231865] kernel: pci 0000:c5:00.0: Adding to iommu group 25
[    4.231900] kernel: pci 0000:c5:00.3: Adding to iommu group 26
[    4.231934] kernel: pci 0000:c5:00.4: Adding to iommu group 27
[    4.231967] kernel: pci 0000:c5:00.5: Adding to iommu group 28
[    4.232002] kernel: pci 0000:c5:00.6: Adding to iommu group 29
[    4.232008] kernel: AMD-Vi: Extended features (0x246577efa2254afa, 0x10): PPR NX GT [5] IA GA PC GA_vAPIC
[    4.232014] kernel: AMD-Vi: Interrupt remapping enabled
[    4.232019] kernel: AMD-Vi: Virtual APIC enabled
[    4.232024] kernel: PCI-DMA: Using software bounce buffering for IO (SWIOTLB)
[    4.232029] kernel: software IO TLB: mapped [mem 0x0000000074000000-0x0000000078000000] (64MB)
[    4.232034] kernel: LVT offset 0 assigned for vector 0x400
[    4.232038] kernel: perf: AMD IBS detected (0x00081bff)
[    4.232042] kernel: perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).
[    4.232046] kernel: Initialise system trusted keyrings
[    4.232050] kernel: Key type blacklist registered
[    4.232054] kernel: workingset: timestamp_bits=36 max_order=24 bucket_order=0
[    4.232057] kernel: fuse: init (API version 7.44)
[    4.232061] kernel: integrity: Platform Keyring initialized
[    4.232065] kernel: integrity: Machine keyring initialized
[    4.232068] kernel: xor: automatically using best checksumming function   avx       
[    4.232072] kernel: Key type asymmetric registered
[    4.232076] kernel: Asymmetric key parser 'x509' registered
[    4.232079] kernel: Block layer SCSI generic (bsg) driver version 0.4 loaded (major 246)
[    4.232083] kernel: io scheduler mq-deadline registered
[    4.232086] kernel: io scheduler kyber registered
[    4.232090] kernel: io scheduler bfq registered
[    4.232094] kernel: Freeing initrd memory: 67500K
[    4.232097] kernel: ledtrig-cpu: registered to indicate activity on CPUs
[    4.232129] kernel: pcieport 0000:00:01.1: PME: Signaling with IRQ 32
[    4.232163] kernel: pcieport 0000:00:01.1: pciehp: Slot #0 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
[    4.232198] kernel: pcieport 0000:00:01.2: PME: Signaling with IRQ 33
[    4.232231] kernel: pcieport 0000:00:01.2: pciehp: Slot #0 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
[    4.232264] kernel: pcieport 0000:00:02.3: PME: Signaling with IRQ 34
[    4.232298] kernel: pcieport 0000:00:02.5: PME: Signaling with IRQ 35
[    4.232331] kernel: pcieport 0000:00:08.1: PME: Signaling with IRQ 36
[    4.232363] kernel: pcieport 0000:00:08.2: PME: Signaling with IRQ 37
[    4.232396] kernel: pcieport 0000:00:08.3: PME: Signaling with IRQ 38
[    4.232400] kernel: ACPI: AC: AC Adapter [AC] (off-line)
[    4.232403] kernel: input: Power Button as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input0
[    4.232407] kernel: ACPI: button: Power Button [PWRB]
[    4.232410] kernel: input: Sleep Button as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0E:00/input/input1
[    4.232414] kernel: ACPI: button: Sleep Button [SLPB]
[    4.232418] kernel: input: Lid Switch as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0D:00/input/input2
[    4.232421] kernel: ACPI: button: Lid Switch [LID]
[    4.232424] kernel: input: Power Button as /devices/LNXSYSTM:00/LNXPWRBN:00/input/input3
[    4.232428] kernel: ACPI: button: Power Button [PWRF]
[    4.232431] kernel: Monitor-Mwait will be used to enter C-1 state
[    4.232435] kernel: Estimated ratio of average max frequency by base frequency (times 1024): 1397
[    4.232471] kernel: thermal LNXTHERM:00: registered as thermal_zone0
[    4.232477] kernel: ACPI: thermal: Thermal Zone [CPUZ] (49 C)
[    4.232512] kernel: thermal LNXTHERM:01: registered as thermal_zone1
[    4.232517] kernel: ACPI: thermal: Thermal Zone [GFXZ] (25 C)
[    4.232551] kernel: thermal LNXTHERM:02: registered as thermal_zone2
[    4.232556] kernel: ACPI: thermal: Thermal Zone [EXTZ] (0 C)
[    4.232591] kernel: thermal LNXTHERM:03: registered as thermal_zone3
[    4.232596] kernel: ACPI: thermal: Thermal Zone [LOCZ] (47 C)
[    4.232630] kernel: thermal LNXTHERM:04: registered as thermal_zone4
[    4.232636] kernel: ACPI: thermal: Thermal Zone [BATZ] (30 C)
[    4.232670] kernel: thermal LNXTHERM:05: registered as thermal_zone5
[    4.232675] kernel: ACPI: thermal: Thermal Zone [CHGZ] (45 C)
[    4.232709] kernel: thermal LNXTHERM:06: registered as thermal_zone6
[    4.232714] kernel: ACPI: thermal: Thermal Zone [MSHZ] (30 C)
[    4.232717] kernel: Serial: 8250/16550 driver, 32 ports, IRQ sharing enabled
[    4.232721] kernel: Non-volatile memory driver v1.3
[    4.232724] kernel: Linux agpgart interface v0.103
[    4.232728] kernel: ACPI: bus type drm_connector registered
[    4.232762] kernel: xhci_hcd 0000:c3:00.4: xHCI Host Controller
[    4.232798] kernel: xhci_hcd 0000:c3:00.4: new USB bus registered, assigned bus number 1
[    4.232832] kernel: xhci_hcd 0000:c3:00.4: hcc params 0x0118ffc5 hci version 0x120 quirks 0x0000000200000010
[    4.232866] kernel: xhci_hcd 0000:c3:00.4: xHCI Host Controller
[    4.232900] kernel: xhci_hcd 0000:c3:00.4: new USB bus registered, assigned bus number 2
[    4.232935] kernel: xhci_hcd 0000:c3:00.4: Host supports USB 3.1 Enhanced SuperSpeed
[    4.232972] kernel: usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.16
[    4.233004] kernel: usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.233032] kernel: usb usb1: Product: xHCI Host Controller
[    4.233059] kernel: usb usb1: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.233086] kernel: usb usb1: SerialNumber: 0000:c3:00.4
[    4.233130] kernel: hub 1-0:1.0: USB hub found
[    4.233173] kernel: hub 1-0:1.0: 1 port detected
[    4.233214] kernel: usb usb2: We don't know the algorithms for LPM for this host, disabling LPM.
[    4.233245] kernel: usb usb2: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.16
[    4.233272] kernel: usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.233299] kernel: usb usb2: Product: xHCI Host Controller
[    4.233324] kernel: usb usb2: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.233350] kernel: usb usb2: SerialNumber: 0000:c3:00.4
[    4.233389] kernel: hub 2-0:1.0: USB hub found
[    4.233426] kernel: hub 2-0:1.0: 1 port detected
[    4.233462] kernel: xhci_hcd 0000:c5:00.0: xHCI Host Controller
[    4.233496] kernel: xhci_hcd 0000:c5:00.0: new USB bus registered, assigned bus number 3
[    4.233530] kernel: xhci_hcd 0000:c5:00.0: hcc params 0x0128ffc5 hci version 0x120 quirks 0x0000000200000010
[    4.233564] kernel: xhci_hcd 0000:c5:00.0: xHCI Host Controller
[    4.233598] kernel: xhci_hcd 0000:c5:00.0: new USB bus registered, assigned bus number 4
[    4.233633] kernel: xhci_hcd 0000:c5:00.0: Host supports USB 3.1 Enhanced SuperSpeed
[    4.233663] kernel: usb usb3: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.16
[    4.233690] kernel: usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.233718] kernel: usb usb3: Product: xHCI Host Controller
[    4.233743] kernel: usb usb3: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.233770] kernel: usb usb3: SerialNumber: 0000:c5:00.0
[    4.233808] kernel: hub 3-0:1.0: USB hub found
[    4.233845] kernel: hub 3-0:1.0: 5 ports detected
[    4.233885] kernel: usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
[    4.233914] kernel: usb usb4: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.16
[    4.233942] kernel: usb usb4: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.233968] kernel: usb usb4: Product: xHCI Host Controller
[    4.233995] kernel: usb usb4: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.234026] kernel: usb usb4: SerialNumber: 0000:c5:00.0
[    4.234066] kernel: hub 4-0:1.0: USB hub found
[    4.234104] kernel: hub 4-0:1.0: 2 ports detected
[    4.234139] kernel: xhci_hcd 0000:c5:00.3: xHCI Host Controller
[    4.234175] kernel: xhci_hcd 0000:c5:00.3: new USB bus registered, assigned bus number 5
[    4.234209] kernel: xhci_hcd 0000:c5:00.3: hcc params 0x0118ffc5 hci version 0x120 quirks 0x0000000200000010
[    4.234245] kernel: xhci_hcd 0000:c5:00.3: xHCI Host Controller
[    4.234279] kernel: xhci_hcd 0000:c5:00.3: new USB bus registered, assigned bus number 6
[    4.234313] kernel: xhci_hcd 0000:c5:00.3: Host supports USB 3.1 Enhanced SuperSpeed
[    4.234344] kernel: usb usb5: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.16
[    4.234372] kernel: usb usb5: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.234399] kernel: usb usb5: Product: xHCI Host Controller
[    4.234426] kernel: usb usb5: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.234452] kernel: usb usb5: SerialNumber: 0000:c5:00.3
[    4.234491] kernel: hub 5-0:1.0: USB hub found
[    4.234528] kernel: hub 5-0:1.0: 1 port detected
[    4.234569] kernel: usb usb6: We don't know the algorithms for LPM for this host, disabling LPM.
[    4.234598] kernel: usb usb6: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.16
[    4.234626] kernel: usb usb6: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.234653] kernel: usb usb6: Product: xHCI Host Controller
[    4.234679] kernel: usb usb6: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.234705] kernel: usb usb6: SerialNumber: 0000:c5:00.3
[    4.234744] kernel: hub 6-0:1.0: USB hub found
[    4.234780] kernel: hub 6-0:1.0: 1 port detected
[    4.234815] kernel: xhci_hcd 0000:c5:00.4: xHCI Host Controller
[    4.234849] kernel: xhci_hcd 0000:c5:00.4: new USB bus registered, assigned bus number 7
[    4.234884] kernel: xhci_hcd 0000:c5:00.4: hcc params 0x0118ffc5 hci version 0x120 quirks 0x0000000200000010
[    4.234919] kernel: xhci_hcd 0000:c5:00.4: xHCI Host Controller
[    4.234953] kernel: xhci_hcd 0000:c5:00.4: new USB bus registered, assigned bus number 8
[    4.234989] kernel: xhci_hcd 0000:c5:00.4: Host supports USB 3.1 Enhanced SuperSpeed
[    4.235023] kernel: usb usb7: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.16
[    4.235052] kernel: usb usb7: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.235079] kernel: usb usb7: Product: xHCI Host Controller
[    4.235105] kernel: usb usb7: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.235132] kernel: usb usb7: SerialNumber: 0000:c5:00.4
[    4.235170] kernel: hub 7-0:1.0: USB hub found
[    4.235208] kernel: hub 7-0:1.0: 1 port detected
[    4.235247] kernel: usb usb8: We don't know the algorithms for LPM for this host, disabling LPM.
[    4.235276] kernel: usb usb8: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.16
[    4.235303] kernel: usb usb8: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    4.235328] kernel: usb usb8: Product: xHCI Host Controller
[    4.235354] kernel: usb usb8: Manufacturer: Linux 6.16.0-00020-g541e951a4e8a xhci-hcd
[    4.235380] kernel: usb usb8: SerialNumber: 0000:c5:00.4
[    4.235419] kernel: hub 8-0:1.0: USB hub found
[    4.235458] kernel: hub 8-0:1.0: 1 port detected
[    4.235462] kernel: usbcore: registered new interface driver usbserial_generic
[    4.235466] kernel: usbserial: USB Serial support registered for generic
[    4.235469] kernel: i8042: PNP: PS/2 Controller [PNP0303:KBC0] at 0x60,0x64 irq 1
[    4.235473] kernel: i8042: PNP: PS/2 appears to have AUX port disabled, if this is incorrect please boot with i8042.nopnp
[    4.235477] kernel: serio: i8042 KBD port at 0x60,0x64 irq 1
[    4.235510] kernel: rtc_cmos 00:00: RTC can wake from S4
[    4.235542] kernel: rtc_cmos 00:00: registered as rtc0
[    4.235573] kernel: rtc_cmos 00:00: setting system clock to 2025-07-29T06:54:06 UTC (1753772046)
[    4.235604] kernel: rtc_cmos 00:00: alarms up to one month, y3k, 114 bytes nvram
[    4.235608] kernel: ACPI: battery: Slot [BAT0] (battery present)
[    4.235650] kernel: simple-framebuffer simple-framebuffer.0: [drm] Registered 1 planes with drm panic
[    4.235655] kernel: [drm] Initialized simpledrm 1.0.0 for simple-framebuffer.0 on minor 0
[    4.235659] kernel: fbcon: Deferring console take-over
[    4.235693] kernel: simple-framebuffer simple-framebuffer.0: [drm] fb0: simpledrmdrmfb frame buffer device
[    4.235698] kernel: pstore: Using crash dump compression: deflate
[    4.235702] kernel: pstore: Registered efi_pstore as persistent store backend
[    4.235706] kernel: hid: raw HID events driver (C) Jiri Kosina
[    4.235710] kernel: usbcore: registered new interface driver usbhid
[    4.235713] kernel: usbhid: USB HID core driver
[    4.235717] kernel: drop_monitor: Initializing network drop monitor service
[    4.235720] kernel: NET: Registered PF_INET6 protocol family
[    4.235724] kernel: Segment Routing with IPv6
[    4.235728] kernel: RPL Segment Routing with IPv6
[    4.235731] kernel: In-situ OAM (IOAM) with IPv6
[    4.235735] kernel: NET: Registered PF_PACKET protocol family
[    4.235738] kernel: x86/amd: Previous system reset reason [0x00180800]: software wrote 0x6 to reset control register 0xCF9
[    4.235742] kernel: x86/amd: Previous system reset reason [0x00180800]: software wrote 0xE to reset control register 0xCF9
[    4.235745] kernel: microcode: Current revision: 0x0b700032
[    4.235749] kernel: resctrl: L3 allocation detected
[    4.235752] kernel: resctrl: MB allocation detected
[    4.235755] kernel: resctrl: SMBA allocation detected
[    4.235759] kernel: resctrl: L3 monitoring detected
[    4.235763] kernel: IPI shorthand broadcast: enabled
[    4.235766] kernel: sched_clock: Marking stable (466093501, 1406194)->(489944784, -22445089)
[    4.235769] kernel: registered taskstats version 1
[    4.235773] kernel: Loading compiled-in X.509 certificates
[    4.235777] kernel: input: AT Translated Set 2 keyboard as /devices/platform/i8042/serio0/input/input4
[    4.235780] kernel: Loaded X.509 cert 'Build time autogenerated kernel key: ed3e664c1852a069aadf6897aea0bb6fd2a49d18'
[    4.235784] kernel: Demotion targets for Node 0: null
[    4.235787] kernel: Key type .fscrypt registered
[    4.235791] kernel: Key type fscrypt-provisioning registered
[    4.235795] kernel: Btrfs loaded, zoned=yes, fsverity=yes
[    4.235799] kernel: Key type big_key registered
[    4.235802] kernel: integrity: Loading X.509 certificate: UEFI:db
[    4.235805] kernel: integrity: Loaded X.509 cert 'HP Inc.: HP UEFI Secure Boot DB 2017: d9c01b50cfcae89d3b05345c163aa76e5dd589e7'
[    4.235809] kernel: integrity: Loading X.509 certificate: UEFI:db
[    4.235812] kernel: integrity: Loaded X.509 cert 'HP Inc.: HP UEFI Secure Boot DB 2024: 9031be8bd10636d7ed703b1ec5807354b05cd8ee'
[    4.235816] kernel: integrity: Loading X.509 certificate: UEFI:db
[    4.235819] kernel: integrity: Loaded X.509 cert 'Microsoft Corporation: Windows UEFI CA 2023: aefc5fbbbe055d8f8daa585473499417ab5a5272'
[    4.235823] kernel: integrity: Loading X.509 certificate: UEFI:db
[    4.235826] kernel: integrity: Loaded X.509 cert 'Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53'
[    4.235830] kernel: PM:   Magic number: 1:711:924
[    4.235870] kernel: clockevents clockevent17: hash matches
[    4.235902] kernel: msr msr19: hash matches
[    4.235942] kernel: memory memory351: hash matches
[    4.235947] kernel: RAS: Correctable Errors collector initialized.
[    4.235952] kernel: clk: Disabling unused clocks
[    4.235955] kernel: PM: genpd: Disabling unused power domains
[    4.235959] kernel: Freeing unused decrypted memory: 2028K
[    4.235962] kernel: Freeing unused kernel image (initmem) memory: 4644K
[    4.235966] kernel: Write protecting the kernel read-only data: 36864k
[    4.235969] kernel: Freeing unused kernel image (text/rodata gap) memory: 860K
[    4.235973] kernel: Freeing unused kernel image (rodata/data gap) memory: 564K
[    4.235976] kernel: x86/mm: Checked W+X mappings: passed, no W+X pages found.
[    4.235980] kernel: rodata_test: all tests were successful
[    4.235984] kernel: Run /init as init process
[    4.235988] kernel:   with arguments:
[    4.235991] kernel:     /init
[    4.235994] kernel:   with environment:
[    4.235997] kernel:     HOME=/
[    4.236003] kernel:     TERM=linux
[    4.236007] kernel:     BOOT_IMAGE=/vmlinuz-linux-sultan
[    4.236012] kernel:     cryptdevice=UUID=086cda6b-894f-4a2b-b380-335846421e3f:cryptroot:allow-discards,no-read-workqueue,no-write-workqueue
[    4.236016] kernel:     tsx=off
[    4.236020] kernel:     split_lock_detect=off
[    4.236023] kernel: Key type psk registered
[    4.236059] kernel: ccp 0000:c3:00.2: tee enabled
[    4.236094] kernel: ccp 0000:c3:00.2: psp: TSME enabled
[    4.236128] kernel: ccp 0000:c3:00.2: psp enabled
[    4.236164] kernel: nvme 0000:c2:00.0: platform quirk: setting simple suspend
[    4.236198] kernel: nvme nvme0: pci function 0000:c2:00.0
[    4.236224] kernel: nvme nvme0: D3 entry latency set to 10 seconds
[    4.236250] kernel: nvme nvme0: 16/0/0 default/read/poll queues
[    4.236255] kernel:  nvme0n1: p1 p2 p3
[    4.236295] kernel: usb 3-5: new high-speed USB device number 2 using xhci_hcd
[    4.236325] kernel: usb 3-5: New USB device found, idVendor=0e8d, idProduct=8c38, bcdDevice= 1.00
[    4.236354] kernel: usb 3-5: New USB device strings: Mfr=5, Product=6, SerialNumber=7
[    4.236381] kernel: usb 3-5: Product: Wireless_Device
[    4.236408] kernel: usb 3-5: Manufacturer: MediaTek Inc.
[    4.236436] kernel: usb 3-5: SerialNumber: 000000000
[    4.236440] kernel: device-mapper: uevent: version 1.0.3
[    4.236444] kernel: device-mapper: ioctl: 4.50.0-ioctl (2025-04-28) initialised: dm-devel@lists.linux.dev
[    4.236448] kernel: Key type encrypted registered
[    4.236451] kernel: fbcon: Taking over console
[    4.236455] kernel: Console: switching to colour frame buffer device 180x56
[    4.236459] kernel: tsc: Refined TSC clocksource calibration: 2994.413 MHz
[    4.236463] kernel: clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2b29a7619ca, max_idle_ns: 440795265835 ns
[    4.236466] kernel: clocksource: Switched to clocksource tsc
[    4.236470] kernel: EXT4-fs (dm-0): mounted filesystem 18516d14-ae39-4b89-8899-95270912d67b r/w with ordered data mode. Quota mode: none.
[    4.236476] systemd[1]: systemd 257.7-1-arch running in system mode (+PAM +AUDIT -SELINUX -APPARMOR -IMA +IPE +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK +BTF +XKBCOMMON +UTMP -SYSVINIT +LIBARCHIVE)
[    4.236482] systemd[1]: Detected architecture x86-64.
[    4.236486] systemd[1]: Hostname set to <sultan-box>.
[    4.236490] systemd[1]: bpf-restrict-fs: LSM BPF program attached
[    4.236494] systemd[1]: Queued start job for default target Graphical Interface.
[    4.236498] systemd[1]: Created slice Slice /system/dirmngr.
[    4.236502] systemd[1]: Created slice Slice /system/getty.
[    4.236506] systemd[1]: Created slice Slice /system/gpg-agent.
[    4.236510] systemd[1]: Created slice Slice /system/gpg-agent-browser.
[    4.236514] systemd[1]: Created slice Slice /system/gpg-agent-extra.
[    4.236517] systemd[1]: Created slice Slice /system/gpg-agent-ssh.
[    4.236521] systemd[1]: Created slice Slice /system/keyboxd.
[    4.236525] systemd[1]: Created slice Slice /system/modprobe.
[    4.236529] systemd[1]: Created slice Slice /system/systemd-fsck.
[    4.236533] systemd[1]: Created slice User and Session Slice.
[    4.236538] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[    4.236542] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[    4.236546] systemd[1]: Expecting device /dev/disk/by-uuid/1eac7954-5ada-45c6-a3bf-a282774abc56...
[    4.236550] systemd[1]: Expecting device /dev/disk/by-uuid/4D03-55DF...
[    4.236553] systemd[1]: Reached target Login Prompts.
[    4.236557] systemd[1]: Reached target Local Integrity Protected Volumes.
[    4.236561] systemd[1]: Reached target Remote File Systems.
[    4.236565] systemd[1]: Reached target Slice Units.
[    4.236568] systemd[1]: Reached target Swaps.
[    4.236573] systemd[1]: Reached target Local Verity Protected Volumes.
[    4.236576] systemd[1]: Listening on Device-mapper event daemon FIFOs.
[    4.236580] systemd[1]: Listening on LVM2 poll daemon socket.
[    4.236583] systemd[1]: Listening on Process Core Dump Socket.
[    4.236587] systemd[1]: Listening on Credential Encryption/Decryption.
[    4.236590] systemd[1]: Listening on Journal Socket (/dev/log).
[    4.236594] systemd[1]: Listening on Journal Sockets.
[    4.236598] systemd[1]: TPM PCR Measurements was skipped because of an unmet condition check (ConditionSecurity=measured-uki).
[    4.236601] systemd[1]: Make TPM PCR Policy was skipped because of an unmet condition check (ConditionSecurity=measured-uki).
[    4.236606] systemd[1]: Listening on udev Control Socket.
[    4.236609] systemd[1]: Listening on udev Kernel Socket.
[    4.236613] systemd[1]: Mounting Huge Pages File System...
[    4.236617] systemd[1]: Mounting POSIX Message Queue File System...
[    4.236621] systemd[1]: Mounting Kernel Debug File System...
[    4.236624] systemd[1]: Mounting Kernel Trace File System...
[    4.236628] systemd[1]: tmp.mount: Directory /tmp to mount over is not empty, mounting anyway.
[    4.236632] systemd[1]: Mounting Temporary Directory /tmp...
[    4.236636] systemd[1]: Starting Create List of Static Device Nodes...
[    4.236640] systemd[1]: Starting Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling...
[    4.236644] systemd[1]: Starting Load Kernel Module configfs...
[    4.236650] systemd[1]: Starting Load Kernel Module dm_mod...
[    4.236655] systemd[1]: Starting Load Kernel Module drm...
[    4.236659] systemd[1]: Starting Load Kernel Module efi_pstore...
[    4.236662] systemd[1]: Starting Load Kernel Module fuse...
[    4.236666] systemd[1]: Starting Load Kernel Module loop...
[    4.236669] systemd[1]: File System Check on Root Device was skipped because of an unmet condition check (ConditionPathIsReadWrite=!/).
[    4.236673] systemd[1]: Clear Stale Hibernate Storage Info was skipped because of an unmet condition check (ConditionPathExists=/sys/firmware/efi/efivars/HibernateLocation-8cf2644b-4b0b-428f-9387-6d876050dc67).
[    4.236677] systemd[1]: Starting Journal Service...
[    4.236681] systemd[1]: Starting Load Kernel Modules...
[    4.236685] systemd[1]: TPM PCR Machine ID Measurement was skipped because of an unmet condition check (ConditionSecurity=measured-uki).
[    4.236689] systemd[1]: Starting Remount Root and Kernel File Systems...
[    4.236693] systemd[1]: Early TPM SRK Setup was skipped because of an unmet condition check (ConditionSecurity=measured-uki).
[    4.236697] systemd[1]: Starting Load udev Rules from Credentials...
[    4.236701] systemd[1]: Starting Coldplug All udev Devices...
[    4.236705] systemd[1]: Starting Virtual Console Setup...
[    4.236708] systemd[1]: Mounted Huge Pages File System.
[    4.236712] systemd[1]: Mounted POSIX Message Queue File System.
[    4.236715] systemd[1]: Mounted Kernel Debug File System.
[    4.236720] systemd[1]: Mounted Kernel Trace File System.
[    4.236724] systemd[1]: Mounted Temporary Directory /tmp.
[    4.236727] systemd[1]: Finished Create List of Static Device Nodes.
[    4.236731] kernel: loop: module loaded
[    4.236734] systemd[1]: modprobe@configfs.service: Deactivated successfully.
[    4.236738] systemd[1]: Finished Load Kernel Module configfs.
[    4.236742] systemd[1]: modprobe@dm_mod.service: Deactivated successfully.
[    4.236746] systemd[1]: Finished Load Kernel Module dm_mod.
[    4.236750] systemd[1]: modprobe@drm.service: Deactivated successfully.
[    4.236754] systemd[1]: Finished Load Kernel Module drm.
[    4.236757] systemd[1]: modprobe@efi_pstore.service: Deactivated successfully.
[    4.236761] systemd[1]: Finished Load Kernel Module efi_pstore.
[    4.236765] systemd[1]: modprobe@fuse.service: Deactivated successfully.
[    4.236769] systemd[1]: Finished Load Kernel Module fuse.
[    4.236772] systemd[1]: modprobe@loop.service: Deactivated successfully.
[    4.236776] systemd[1]: Finished Load Kernel Module loop.
[    4.236779] systemd[1]: Mounting FUSE Control File System...
[    4.236783] systemd[1]: Mounting Kernel Configuration File System...
[    4.236787] systemd[1]: Repartition Root Disk was skipped because no trigger condition checks were met.
[    4.236791] systemd[1]: Starting Create Static Device Nodes in /dev gracefully...
[    4.236795] systemd[1]: Finished Load udev Rules from Credentials.
[    4.236798] systemd[1]: Mounted FUSE Control File System.
[    4.236811] systemd-journald[542]: Collecting audit messages is disabled.
[    4.236823] systemd[1]: Mounted Kernel Configuration File System.
[    4.236826] kernel: i2c_dev: i2c /dev entries driver
[    4.236830] systemd[1]: Finished Load Kernel Modules.
[    4.236834] systemd[1]: Starting Apply Kernel Variables...
[    4.236838] systemd[1]: Finished Virtual Console Setup.
[    4.236841] systemd[1]: Finished Apply Kernel Variables.
[    4.236845] systemd[1]: Finished Create Static Device Nodes in /dev gracefully.
[    4.237005] systemd[1]: Started Journal Service.
[    4.240039] kernel: EXT4-fs (dm-0): re-mounted 18516d14-ae39-4b89-8899-95270912d67b.
[    4.303571] systemd-journald[542]: Received client request to flush runtime journal.
[    4.386009] kernel: Serial bus multi instantiate pseudo device driver CSC3554:00: Instantiated 5 I2C devices.
[    4.402025] kernel: Module pcspkr is blacklisted
[    4.402225] kernel: input: Wireless hotkeys as /devices/virtual/input/input5
[    4.409728] kernel: RAPL PMU: API unit is 2^-32 Joules, 2 fixed counters, 163840 ms ovfl timer
[    4.409792] kernel: RAPL PMU: hw unit of domain package 2^-16 Joules
[    4.409812] kernel: RAPL PMU: hw unit of domain core 2^-16 Joules
[    4.411013] kernel: wmi_bus wmi_bus-PNP0C14:00: [Firmware Info]: DF4E63B6-3BBC-4858-9737-C74F82F821F3 has zero instances
[    4.411872] kernel: wmi_bus wmi_bus-PNP0C14:00: [Firmware Info]: 8F1F6436-9F42-42C8-BADC-0E9424F20C9A has zero instances
[    4.412069] kernel: pcie_mp2_amd 0000:c3:00.7: enabling device (0000 -> 0002)
[    4.416008] kernel: piix4_smbus 0000:00:14.0: SMBus Host Controller at 0xb00, revision 0
[    4.416153] kernel: piix4_smbus 0000:00:14.0: Using register 0x02 for SMBus port selection
[    4.421016] kernel: piix4_smbus 0000:00:14.0: Auxiliary SMBus Host Controller at 0xb20
[    4.421161] kernel: i2c i2c-6: Successfully instantiated SPD at 0x50
[    4.422019] kernel: i2c i2c-6: Successfully instantiated SPD at 0x51
[    4.422176] kernel: i2c i2c-6: Successfully instantiated SPD at 0x52
[    4.423010] kernel: i2c i2c-6: Successfully instantiated SPD at 0x53
[    4.423181] kernel: i2c i2c-6: Successfully instantiated SPD at 0x54
[    4.424009] kernel: i2c i2c-6: Successfully instantiated SPD at 0x55
[    4.424163] kernel: i2c i2c-6: Successfully instantiated SPD at 0x56
[    4.425009] kernel: i2c i2c-6: Successfully instantiated SPD at 0x57
[    4.435005] kernel: ACPI: bus type thunderbolt registered
[    4.507023] kernel: Bluetooth: Core ver 2.22
[    4.507126] kernel: NET: Registered PF_BLUETOOTH protocol family
[    4.507138] kernel: Bluetooth: HCI device and connection manager initialized
[    4.507147] kernel: Bluetooth: HCI socket layer initialized
[    4.507159] kernel: Bluetooth: L2CAP socket layer initialized
[    4.507169] kernel: Bluetooth: SCO socket layer initialized
[    4.555036] kernel: input: SYNA3133:00 06CB:CFE2 Mouse as /devices/platform/AMDI0010:00/i2c-0/i2c-SYNA3133:00/0018:06CB:CFE2.0001/input/input6
[    4.555236] kernel: input: SYNA3133:00 06CB:CFE2 Touchpad as /devices/platform/AMDI0010:00/i2c-0/i2c-SYNA3133:00/0018:06CB:CFE2.0001/input/input7
[    4.555281] kernel: hid-generic 0018:06CB:CFE2.0001: input,hidraw0: I2C HID v1.00 Mouse [SYNA3133:00 06CB:CFE2] on i2c-SYNA3133:00
[    4.564011] kernel: sp5100_tco: SP5100/SB800 TCO WatchDog Timer Driver
[    4.564050] kernel: sp5100-tco sp5100-tco: Using 0xfeb00000 for watchdog MMIO address
[    4.564260] kernel: sp5100-tco sp5100-tco: initialized. heartbeat=60 sec (nowayout=0)
[    4.564437] kernel: ACPI: video: Video Device [GFX0] (multi-head: yes  rom: no  post: no)
[    4.564469] kernel: input: Video Bus as /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:13/LNXVIDEO:00/input/input9
[    4.577024] kernel: amdxdna 0000:c4:00.1: enabling device (0000 -> 0002)
[    4.578085] kernel: hp_wmi: query 0x4 returned error 0x5
[    4.588008] kernel: usbcore: registered new interface driver btusb
[    4.589007] kernel: input: HP WMI hotkeys as /devices/virtual/input/input10
[    4.590007] kernel: Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20250526153203
[    4.594007] kernel: snd_acp_pci 0000:c3:00.5: enabling device (0000 -> 0002)
[    4.596018] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: Cirrus Logic CS35L54 Rev B0 OTP4 fw:3.4.4 (patched=0)
[    4.610337] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: DSP system name: '103C8D01', amp name: 'AMP1'
[    4.613007] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: Reset GPIO busy, assume shared reset
[    4.620008] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: Cirrus Logic CS35L54 Rev B0 OTP4 fw:3.4.4 (patched=0)
[    4.620184] kernel: input: SYNA3133:00 06CB:CFE2 Mouse as /devices/platform/AMDI0010:00/i2c-0/i2c-SYNA3133:00/0018:06CB:CFE2.0001/input/input11
[    4.621010] kernel: input: SYNA3133:00 06CB:CFE2 Touchpad as /devices/platform/AMDI0010:00/i2c-0/i2c-SYNA3133:00/0018:06CB:CFE2.0001/input/input12
[    4.621033] kernel: hid-multitouch 0018:06CB:CFE2.0001: input,hidraw0: I2C HID v1.00 Mouse [SYNA3133:00 06CB:CFE2] on i2c-SYNA3133:00
[    4.636013] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: DSP system name: '103C8D01', amp name: 'AMP2'
[    4.638007] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: Reset GPIO busy, assume shared reset
[    4.646019] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: Cirrus Logic CS35L54 Rev B0 OTP4 fw:3.4.4 (patched=0)
[    4.653007] kernel: cfg80211: Loading compiled-in X.509 certificates for regulatory database
[    4.653044] kernel: snd_hda_intel 0000:c3:00.1: enabling device (0000 -> 0002)
[    4.653176] kernel: snd_hda_intel 0000:c3:00.6: enabling device (0000 -> 0002)
[    4.655015] kernel: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[    4.655034] kernel: Loaded X.509 cert 'wens: 61c038651aabdcf94bd0ac7ff06c7248db18c600'
[    4.660016] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: DSP system name: '103C8D01', amp name: 'AMP3'
[    4.662016] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: Reset GPIO busy, assume shared reset
[    4.665008] kernel: mousedev: PS/2 mouse device common for all mice
[    4.667009] kernel: input: HD-Audio Generic HDMI/DP,pcm=3 as /devices/pci0000:00/0000:00:08.1/0000:c3:00.1/sound/card0/input14
[    4.667028] kernel: input: HD-Audio Generic HDMI/DP,pcm=7 as /devices/pci0000:00/0000:00:08.1/0000:c3:00.1/sound/card0/input15
[    4.667039] kernel: input: HD-Audio Generic HDMI/DP,pcm=8 as /devices/pci0000:00/0000:00:08.1/0000:c3:00.1/sound/card0/input16
[    4.667047] kernel: input: HD-Audio Generic HDMI/DP,pcm=9 as /devices/pci0000:00/0000:00:08.1/0000:c3:00.1/sound/card0/input17
[    4.670007] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: Cirrus Logic CS35L54 Rev B0 OTP4 fw:3.4.4 (patched=0)
[    4.679021] kernel: [drm] Initialized amdxdna_accel_driver 0.0.0 for 0000:c4:00.1 on minor 0
[    4.680007] kernel: snd_hda_codec_realtek hdaudioC1D0: ALC245: picked fixup  for PCI SSID 103c:8d01
[    4.680144] kernel: snd_hda_codec_realtek hdaudioC1D0: Found 4 CSC3554 on i2c (-%s:00-cs35l54-hda.%d)
[    4.681019] kernel: snd_hda_codec_realtek hdaudioC1D0: autoconfig for ALC245: line_outs=1 (0x17/0x0/0x0/0x0/0x0) type:speaker
[    4.681174] kernel: snd_hda_codec_realtek hdaudioC1D0:    speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
[    4.681225] kernel: snd_hda_codec_realtek hdaudioC1D0:    hp_outs=1 (0x21/0x0/0x0/0x0/0x0)
[    4.681265] kernel: snd_hda_codec_realtek hdaudioC1D0:    mono: mono_out=0x0
[    4.681306] kernel: snd_hda_codec_realtek hdaudioC1D0:    inputs:
[    4.681353] kernel: snd_hda_codec_realtek hdaudioC1D0:      Mic=0x19
[    4.683016] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: DSP system name: '103C8D01', amp name: 'AMP4'
[    4.684024] kernel: kvm_amd: TSC scaling supported
[    4.684043] kernel: kvm_amd: Nested Virtualization enabled
[    4.684052] kernel: kvm_amd: Nested Paging enabled
[    4.684061] kernel: kvm_amd: LBR virtualization supported
[    4.684069] kernel: kvm_amd: Virtual VMLOAD VMSAVE supported
[    4.684078] kernel: kvm_amd: Virtual GIF supported
[    4.684082] kernel: kvm_amd: Virtual NMI enabled
[    4.686008] kernel: snd_hda_codec_realtek hdaudioC1D0: bound i2c-CSC3554:00-cs35l54-hda.0 (ops cs35l56_hda_comp_ops [snd_hda_scodec_cs35l56])
[    4.686232] kernel: snd_hda_codec_realtek hdaudioC1D0: bound i2c-CSC3554:00-cs35l54-hda.1 (ops cs35l56_hda_comp_ops [snd_hda_scodec_cs35l56])
[    4.686309] kernel: snd_hda_codec_realtek hdaudioC1D0: bound i2c-CSC3554:00-cs35l54-hda.2 (ops cs35l56_hda_comp_ops [snd_hda_scodec_cs35l56])
[    4.686452] kernel: input: PMF-TA output events as /devices/platform/AMDI0105:00/input/input18
[    4.686469] kernel: snd_hda_codec_realtek hdaudioC1D0: bound i2c-CSC3554:00-cs35l54-hda.3 (ops cs35l56_hda_comp_ops [snd_hda_scodec_cs35l56])
[    4.686532] kernel: amd-pmf AMDI0105:00: registered PMF device successfully
[    4.691016] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: format 3 timestamp 0x66300c2d
[    4.691140] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: Mon 29 Apr 2024 22:07:57 GMT Daylight Time
[    4.691199] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: format 3 timestamp 0x66300c2d
[    4.691260] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: Mon 29 Apr 2024 22:07:57 GMT Daylight Time
[    4.691313] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: format 3 timestamp 0x66300c2d
[    4.691370] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: Mon 29 Apr 2024 22:07:57 GMT Daylight Time
[    4.691421] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: format 3 timestamp 0x66300c2d
[    4.691477] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01.wmfw: Mon 29 Apr 2024 22:07:57 GMT Daylight Time
[    4.815026] kernel: input: HD-Audio Generic Mic as /devices/pci0000:00/0000:00:08.1/0000:c3:00.6/sound/card1/input19
[    4.815116] kernel: input: HD-Audio Generic Headphone as /devices/pci0000:00/0000:00:08.1/0000:c3:00.6/sound/card1/input20
[    4.823021] kernel: intel_rapl_common: Found RAPL domain package
[    4.823125] kernel: intel_rapl_common: Found RAPL domain core
[    4.824024] kernel: amd_atl: AMD Address Translation Library initialized
[    4.868029] kernel: mt7925e 0000:c1:00.0: enabling device (0000 -> 0002)
[    4.873014] kernel: mt7925e 0000:c1:00.0: ASIC revision: 79250000
[    4.948042] kernel: mt7925e 0000:c1:00.0: HW/SW Version: 0x8a108a10, Build Time: 20250526152947a
[    5.430042] kernel: mt7925e 0000:c1:00.0: WM Firmware Version: ____000000, Build Time: 20250526153043
[    5.673027] kernel: EXT4-fs (nvme0n1p2): mounted filesystem 1eac7954-5ada-45c6-a3bf-a282774abc56 r/w with ordered data mode. Quota mode: none.
[    5.679024] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: DSP1: Firmware: 1a00d6 vendor: 0x2 v3.11.18, 41 algorithms
[    5.679256] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: DSP1: Firmware: 1a00d6 vendor: 0x2 v3.11.18, 41 algorithms
[    5.680021] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: DSP1: Firmware: 1a00d6 vendor: 0x2 v3.11.18, 41 algorithms
[    5.681022] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: DSP1: Firmware: 1a00d6 vendor: 0x2 v3.11.18, 41 algorithms
[    5.697021] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01-amp2.bin: v3.11.18
[    5.697172] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: DSP1: misc: C:\ProductSetting\HP\Chiron\Tuning_Relese\20250216\init\Left_Tweeter (131118.360300.80216)-init.bin
[    5.712029] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01-amp4.bin: v3.11.18
[    5.712227] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: DSP1: misc: C:\ProductSetting\HP\Chiron\Tuning_Relese\20250216\init\Right_Woofer (131118.360000.80216)-init.bin
[    5.727021] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01-amp3.bin: v3.11.18
[    5.727174] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: DSP1: misc: C:\ProductSetting\HP\Chiron\Tuning_Relese\20250216\init\Right_Tweeter (131118.360100.80216)-init.bin
[    5.742022] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: DSP1: cirrus/cs35l54-b0-dsp1-misc-103c8d01-amp1.bin: v3.11.18
[    5.742167] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: DSP1: misc: C:\ProductSetting\HP\Chiron\Tuning_Relese\20250216\init\Left_Woofer (131118.360200.80216)-init.bin
[    6.199031] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: Calibration applied
[    6.199209] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: Calibration applied
[    6.199323] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: Calibration applied
[    6.200023] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: Calibration applied
[    6.201020] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.1: Tuning PID: 0x131118, SID: 0x360300, TID: 0x80216
[    6.201172] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.3: Tuning PID: 0x131118, SID: 0x360000, TID: 0x80216
[    6.201283] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.2: Tuning PID: 0x131118, SID: 0x360100, TID: 0x80216
[    6.201394] kernel: cs35l56-hda i2c-CSC3554:00-cs35l54-hda.0: Tuning PID: 0x131118, SID: 0x360200, TID: 0x80216
[    6.228021] kernel: mt7925e 0000:c1:00.0 wlp193s0: renamed from wlan0
[    6.387021] kernel: Bluetooth: hci0: Device setup in 1757092 usecs
[    6.387057] kernel: Bluetooth: hci0: HCI Enhanced Setup Synchronous Connection command is advertised, but not supported.
[    6.474033] kernel: Bluetooth: hci0: AOSP extensions version v1.00
[    6.474067] kernel: Bluetooth: hci0: AOSP quality report is supported
[    6.703024] kernel: [drm] amdgpu kernel modesetting enabled.
[    6.704013] kernel: amdgpu: Virtual CRAT table created for CPU
[    6.704027] kernel: amdgpu: Topology: Add CPU node
[    6.706310] kernel: [drm] initializing kernel modesetting (IP DISCOVERY 0x1002:0x1586 0x103C:0x8D01 0xD1).
[    6.706319] kernel: [drm] register mmio base: 0xA0300000
[    6.706327] kernel: [drm] register mmio size: 1048576
[    6.707034] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 0 <soc21_common>
[    6.707303] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 1 <gmc_v11_0>
[    6.707448] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 2 <ih_v6_1>
[    6.707572] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 3 <psp>
[    6.707699] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 4 <smu>
[    6.707840] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 5 <dm>
[    6.707966] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 6 <gfx_v11_0>
[    6.708050] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 7 <sdma_v6_0>
[    6.708115] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 8 <vcn_v4_0_5>
[    6.708175] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 9 <jpeg_v4_0_5>
[    6.708235] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 10 <mes_v11_0>
[    6.708295] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 11 <vpe_v6_1>
[    6.708356] kernel: amdgpu 0000:c3:00.0: amdgpu: detected ip block number 12 <isp_ip>
[    6.708424] kernel: amdgpu 0000:c3:00.0: amdgpu: Fetched VBIOS from VFCT
[    6.708487] kernel: amdgpu: ATOM BIOS: 113-STRXLGEN-001
[    6.716132] kernel: amdgpu 0000:c3:00.0: amdgpu: VPE: collaborate mode true
[    6.755045] kernel: Console: switching to colour dummy device 80x25
[    6.770009] kernel: amdgpu 0000:c3:00.0: amdgpu: Trusted Memory Zone (TMZ) feature disabled as experimental (default)
[    6.770299] kernel: [drm] vm size is 262144 GB, 4 levels, block size is 9-bit, fragment size is 9-bit
[    6.770318] kernel: amdgpu 0000:c3:00.0: amdgpu: VRAM: 4096M 0x0000008000000000 - 0x00000080FFFFFFFF (4096M used)
[    6.770478] kernel: amdgpu 0000:c3:00.0: amdgpu: GART: 512M 0x00007FFF00000000 - 0x00007FFF1FFFFFFF
[    6.770609] kernel: [drm] Detected VRAM RAM=4096M, BAR=4096M
[    6.770624] kernel: [drm] RAM width 256bits LPDDR5
[    6.770639] kernel: [drm] amdgpu: 4096M of VRAM memory ready
[    6.770656] kernel: [drm] amdgpu: 30015M of GTT memory ready.
[    6.770673] kernel: [drm] GART: num cpu pages 131072, num gpu pages 131072
[    6.771024] kernel: [drm] PCIE GART of 512M enabled (table at 0x00000080FFB00000).
[    6.772023] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] Loading DMUB firmware via PSP: version=0x09002600
[    6.772231] kernel: amdgpu 0000:c3:00.0: amdgpu: Found VCN firmware Version ENC: 1.24 DEC: 9 VEP: 0 Revision: 11
[    6.772297] kernel: amdgpu 0000:c3:00.0: amdgpu: Found VCN firmware Version ENC: 1.24 DEC: 9 VEP: 0 Revision: 11
[    6.795005] kernel: amdgpu 0000:c3:00.0: amdgpu: reserve 0x8c00000 from 0x80e0000000 for PSP TMR
[    6.925005] kernel: input: keyd virtual keyboard as /devices/virtual/input/input21
[    6.937015] kernel: Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[    6.937034] kernel: Bluetooth: BNEP filters: protocol multicast
[    6.937040] kernel: Bluetooth: BNEP socket layer initialized
[    6.938006] kernel: Bluetooth: MGMT ver 1.23
[    6.944017] kernel: NET: Registered PF_ALG protocol family
[    7.005053] kernel: input: keyd virtual pointer as /devices/virtual/input/input22
[    7.534315] kernel: amdgpu 0000:c3:00.0: amdgpu: RAS: optional ras ta ucode is not available
[    7.537354] kernel: amdgpu 0000:c3:00.0: amdgpu: RAP: optional rap ta ucode is not available
[    7.537882] kernel: amdgpu 0000:c3:00.0: amdgpu: SECUREDISPLAY: optional securedisplay ta ucode is not available
[    7.575033] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU is initialized successfully!
[    7.578030] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] Display Core v3.2.334 initialized on DCN 3.5.1
[    7.578210] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] DP-HDMI FRL PCON supported
[    7.581020] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] DMUB hardware initialized: version=0x09002600
[    7.599030] kernel: snd_hda_intel 0000:c3:00.1: bound 0000:c3:00.0 (ops amdgpu_dm_audio_component_bind_ops [amdgpu])
[    7.660021] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] Using ACPI provided EDID for eDP-1
[    7.663029] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 1, DC PSR ver 0, sink PSR ver 4 DPCD caps 0x3a su_y_granularity 4
[    7.663302] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.663454] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.663588] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.663718] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.663843] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.663969] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.664119] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.664196] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] PSR support 0, DC PSR ver -1, sink PSR ver 0 DPCD caps 0x0 su_y_granularity 0
[    7.677050] kernel: kfd kfd: amdgpu: Allocated 3969056 bytes on gart
[    7.677463] kernel: kfd kfd: amdgpu: Total number of KFD nodes to be created: 1
[    7.679018] kernel: amdgpu: Virtual CRAT table created for GPU
[    7.680016] kernel: amdgpu: Topology: Add dGPU node [0x1586:0x1002]
[    7.680034] kernel: kfd kfd: amdgpu: added device 1002:1586
[    7.680123] kernel: amdgpu 0000:c3:00.0: amdgpu: SE 2, SH per SE 2, CU per SH 10, active_cu_number 40
[    7.680184] kernel: amdgpu 0000:c3:00.0: amdgpu: ring gfx_0.0.0 uses VM inv eng 0 on hub 0
[    7.680231] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.0.0 uses VM inv eng 1 on hub 0
[    7.680279] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.1.0 uses VM inv eng 4 on hub 0
[    7.680323] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.2.0 uses VM inv eng 6 on hub 0
[    7.680365] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.3.0 uses VM inv eng 7 on hub 0
[    7.680413] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.0.1 uses VM inv eng 8 on hub 0
[    7.680460] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.1.1 uses VM inv eng 9 on hub 0
[    7.680502] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.2.1 uses VM inv eng 10 on hub 0
[    7.680545] kernel: amdgpu 0000:c3:00.0: amdgpu: ring comp_1.3.1 uses VM inv eng 11 on hub 0
[    7.680592] kernel: amdgpu 0000:c3:00.0: amdgpu: ring sdma0 uses VM inv eng 12 on hub 0
[    7.680634] kernel: amdgpu 0000:c3:00.0: amdgpu: ring vcn_unified_0 uses VM inv eng 0 on hub 8
[    7.680679] kernel: amdgpu 0000:c3:00.0: amdgpu: ring vcn_unified_1 uses VM inv eng 1 on hub 8
[    7.680721] kernel: amdgpu 0000:c3:00.0: amdgpu: ring jpeg_dec_0 uses VM inv eng 4 on hub 8
[    7.680767] kernel: amdgpu 0000:c3:00.0: amdgpu: ring jpeg_dec_1 uses VM inv eng 6 on hub 8
[    7.680808] kernel: amdgpu 0000:c3:00.0: amdgpu: ring mes_kiq_3.1.0 uses VM inv eng 13 on hub 0
[    7.680849] kernel: amdgpu 0000:c3:00.0: amdgpu: ring vpe uses VM inv eng 7 on hub 8
[    7.680892] kernel: amdgpu 0000:c3:00.0: amdgpu: Runtime PM not available
[    7.680941] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] Using custom brightness curve
[    7.682002] kernel: amdgpu 0000:c3:00.0: [drm] Registered 4 planes with drm panic
[    7.682051] kernel: [drm] Initialized amdgpu 3.64.0 for 0000:c3:00.0 on minor 1
[    7.688032] kernel: [drm] pre_validate_dsc:1627 MST_DSC dsc precompute is not needed
[    8.665043] kernel: Console: switching to colour frame buffer device 180x56
[    8.675028] kernel: amdgpu 0000:c3:00.0: [drm] fb0: amdgpudrmfb frame buffer device
[    8.697010] kernel: mc: Linux media interface: v0.10
[    8.720021] kernel: videodev: Linux video capture interface: v2.00
[   11.850388] kernel: Unknown laptop placement
[   13.293020] kernel: Bluetooth: RFCOMM TTY layer initialized
[   13.293092] kernel: Bluetooth: RFCOMM socket layer initialized
[   13.293113] kernel: Bluetooth: RFCOMM ver 1.11
[   14.073385] kernel: hid-generic 0020:1022:0001.0002: hidraw1: SENSOR HUB HID v0.00 Device [hid-amdsfh 1022:0001] on pcie_mp2_amd
[   14.074230] kernel: hid-generic 0020:1022:0001.0003: hidraw2: SENSOR HUB HID v0.00 Device [hid-amdsfh 1022:0001] on pcie_mp2_amd
[   14.081109] kernel: hid-sensor-hub 0020:1022:0001.0002: hidraw1: SENSOR HUB HID v0.00 Device [hid-amdsfh 1022:0001] on pcie_mp2_amd
[   14.081875] kernel: hid-sensor-hub 0020:1022:0001.0003: hidraw2: SENSOR HUB HID v0.00 Device [hid-amdsfh 1022:0001] on pcie_mp2_amd
[   14.856025] kernel: nvme nvme0: using unchecked data buffer
[   26.531033] kernel: wlp193s0: authenticate with 1c:0b:8b:00:0f:94 (local address=38:8d:3d:6d:2f:48)
[   26.880023] kernel: wlp193s0: send auth to 1c:0b:8b:00:0f:94 (try 1/3)
[   26.905030] kernel: wlp193s0: authenticate with 1c:0b:8b:00:0f:94 (local address=38:8d:3d:6d:2f:48)
[   26.917023] kernel: wlp193s0: send auth to 1c:0b:8b:00:0f:94 (try 1/3)
[   26.921033] kernel: wlp193s0: authenticated
[   26.926034] kernel: wlp193s0: associate with 1c:0b:8b:00:0f:94 (try 1/3)
[   26.960039] kernel: wlp193s0: RX AssocResp from 1c:0b:8b:00:0f:94 (capab=0x1111 status=0 aid=2)
[   26.995035] kernel: wlp193s0: associated
[   27.251036] kernel: wlp193s0: Limiting TX power to 24 (24 - 0) dBm as advertised by 1c:0b:8b:00:0f:94
[  313.742472] kernel: usb 3-1: new high-speed USB device number 3 using xhci_hcd
[  316.121425] kernel: usb 3-1: New USB device found, idVendor=090c, idProduct=1000, bcdDevice=11.00
[  316.122292] kernel: usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  316.122412] kernel: usb 3-1: Product: Flash Drive FIT
[  316.122501] kernel: usb 3-1: Manufacturer: Samsung
[  316.122587] kernel: usb 3-1: SerialNumber: 0375119060019940
[  316.155021] kernel: usb-storage 3-1:1.0: USB Mass Storage device detected
[  316.155405] kernel: scsi host0: usb-storage 3-1:1.0
[  316.155525] kernel: usbcore: registered new interface driver usb-storage
[  316.159012] kernel: usbcore: registered new interface driver uas
[  317.489118] kernel: scsi 0:0:0:0: Direct-Access     Samsung  Flash Drive FIT  1100 PQ: 0 ANSI: 6
[  317.490027] kernel: sd 0:0:0:0: [sda] 62656641 512-byte logical blocks: (32.1 GB/29.9 GiB)
[  317.490208] kernel: sd 0:0:0:0: [sda] Write Protect is off
[  317.490265] kernel: sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
[  317.490337] kernel: sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  317.903035] kernel:  sda: sda1
[  317.903096] kernel: sd 0:0:0:0: [sda] Attached SCSI removable disk
[  339.555049] kernel: FAT-fs (sda1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[  356.145026] kernel: sda: detected capacity change from 62656641 to 0
[  356.872031] kernel: usb 3-1: USB disconnect, device number 3
[  899.237063] kernel: amd_isp_capture amd_isp_capture: fail to disable stream
[  899.741037] kernel: amd_isp_capture amd_isp_capture: fail to stop steam
[  899.741200] kernel: amd_isp_capture amd_isp_capture: disabling streaming failed (-110)
[  899.758024] kernel: amd-pmf AMDI0105:00: SMU response timed out
[  899.842012] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  900.862011] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  901.745014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  901.805024] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  902.645021] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  902.742022] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  902.742218] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  903.413051] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  903.853026] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  904.276023] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  905.377032] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  905.723023] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  905.723229] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  905.902023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  906.381012] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  907.338014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  907.949015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  908.355015] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  908.692013] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  908.692096] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  909.359014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  909.997014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  910.350012] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  911.254038] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  911.667030] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  911.667213] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  912.045032] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  912.140028] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  913.191024] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  914.093025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  914.440012] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  914.637025] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  914.637247] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  915.431014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  916.141014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  916.428014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  917.347014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  917.696013] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  917.696105] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  918.155855] kernel: BUG: kernel NULL pointer dereference, address: 0000000000000008
[  918.156334] kernel: #PF: supervisor read access in kernel mode
[  918.556330] kernel: #PF: error_code(0x0000) - not-present page
[  918.562283] kernel: PGD 0 P4D 0 
[  918.562340] kernel: Oops: Oops: 0000 [#1] SMP NOPTI
[  918.562363] kernel: CPU: 4 UID: 0 PID: 5002 Comm: amd_isp4_thread Not tainted 6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[  918.562383] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[  918.562417] kernel: RIP: 0010:isp_fw_log_print+0x3b/0x240 [amd_capture]
[  918.562436] kernel: Code: 55 53 48 83 ec 38 4c 8b b7 60 0b 00 00 80 bf 58 0b 00 00 01 0f 85 fb 00 00 00 4d 85 f6 0f 84 f2 00 00 00 48 8b 87 30 02 00 00 <4c> 8b 68 08 48 8b 40 20 44 89 6c 24 08 48 89 44 24 10 48 85 c0 0f
[  918.562457] kernel: RSP: 0018:ffffcf864dc7fd40 EFLAGS: 00010286
[  918.562475] kernel: RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000
[  918.562499] kernel: RDX: ffff8d5b56872180 RSI: ffff8d5b4267b810 RDI: ffff8d5b6c14f0a0
[  918.562521] kernel: RBP: ffff8d5b6c14f0a0 R08: 000000d5a123c41d R09: ffff8d69bd932340
[  918.562540] kernel: R10: 00000000ffffffff R11: 0000000000000008 R12: ffffcf864dc7fdd8
[  918.562561] kernel: R13: ffff8d5b6c14f0a0 R14: ffff8d5b8b400028 R15: 0000000000000000
[  918.562580] kernel: FS:  0000000000000000(0000) GS:ffff8d6a13031000(0000) knlGS:0000000000000000
[  918.562598] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  918.562619] kernel: CR2: 0000000000000008 CR3: 0000000137868000 CR4: 0000000000f50ef0
[  918.562639] kernel: PKRU: 55555554
[  918.562655] kernel: Call Trace:
[  918.562680] kernel:  <TASK>
[  918.562699] kernel:  isp4sd_fw_resp_func+0x58/0x1d0 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  918.562725] kernel:  ? lock_timer_base+0x70/0x90
[  918.562751] kernel:  isp4sd_fw_resp_thread_wrapper+0xdf/0x210 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  918.562768] kernel:  ? __pfx_autoremove_wake_function+0x10/0x10
[  918.562787] kernel:  ? __pfx_isp4sd_fw_resp_thread_wrapper+0x10/0x10 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  918.562806] kernel:  kthread+0xf9/0x240
[  918.562822] kernel:  ? __pfx_kthread+0x10/0x10
[  918.562842] kernel:  ret_from_fork+0x198/0x1d0
[  918.562861] kernel:  ? __pfx_kthread+0x10/0x10
[  918.562879] kernel:  ret_from_fork_asm+0x1a/0x30
[  918.562902] kernel:  </TASK>
[  918.562920] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[  918.563752] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[  918.563807] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[  918.563824] kernel: CR2: 0000000000000008
[  918.563845] kernel: ---[ end trace 0000000000000000 ]---
[  918.563868] kernel: BUG: kernel NULL pointer dereference, address: 0000000000000008
[  918.563926] kernel: #PF: supervisor read access in kernel mode
[  918.564027] kernel: #PF: error_code(0x0000) - not-present page
[  918.564094] kernel: PGD 0 P4D 0 
[  918.564149] kernel: Oops: Oops: 0000 [#2] SMP NOPTI
[  918.564168] kernel: CPU: 12 UID: 0 PID: 5001 Comm: amd_isp4_thread Tainted: G      D             6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[  918.564186] kernel: Tainted: [D]=DIE
[  918.564204] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[  918.564219] kernel: RIP: 0010:isp_fw_log_print+0x3b/0x240 [amd_capture]
[  918.564237] kernel: Code: 55 53 48 83 ec 38 4c 8b b7 60 0b 00 00 80 bf 58 0b 00 00 01 0f 85 fb 00 00 00 4d 85 f6 0f 84 f2 00 00 00 48 8b 87 30 02 00 00 <4c> 8b 68 08 48 8b 40 20 44 89 6c 24 08 48 89 44 24 10 48 85 c0 0f
[  918.564256] kernel: RSP: 0018:ffffcf864dc67d40 EFLAGS: 00010286
[  918.564278] kernel: RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[  918.564296] kernel: RDX: ffff8d5b7585a180 RSI: ffff8d5b4267b810 RDI: ffff8d5b6c14f0a0
[  918.564313] kernel: RBP: ffff8d5b6c14f0a0 R08: 000000d5a29239c3 R09: ffff8d69bdb32340
[  918.564332] kernel: R10: 000000d5ac9cef00 R11: 00000000019f972a R12: ffffcf864dc67dd8
[  918.564346] kernel: R13: ffff8d5b6c14f0a0 R14: ffff8d5b8b400028 R15: 0000000000000000
[  918.564363] kernel: FS:  0000000000000000(0000) GS:ffff8d6a13231000(0000) knlGS:0000000000000000
[  918.564378] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  918.564395] kernel: CR2: 0000000000000008 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  918.564415] kernel: PKRU: 55555554
[  918.564431] kernel: Call Trace:
[  918.564445] kernel:  <TASK>
[  918.564459] kernel:  isp4sd_fw_resp_func+0x58/0x1d0 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  918.564476] kernel:  ? lock_timer_base+0x70/0x90
[  918.564492] kernel:  isp4sd_fw_resp_thread_wrapper+0xdf/0x210 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  918.564506] kernel:  ? __pfx_autoremove_wake_function+0x10/0x10
[  918.564522] kernel:  ? __pfx_isp4sd_fw_resp_thread_wrapper+0x10/0x10 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  918.564536] kernel:  kthread+0xf9/0x240
[  918.564550] kernel:  ? __pfx_kthread+0x10/0x10
[  918.564563] kernel:  ret_from_fork+0x198/0x1d0
[  918.564577] kernel:  ? __pfx_kthread+0x10/0x10
[  918.564591] kernel:  ret_from_fork_asm+0x1a/0x30
[  918.564606] kernel:  </TASK>
[  918.564621] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[  918.564710] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[  918.564737] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[  918.564754] kernel: CR2: 0000000000000008
[  918.564769] kernel: ---[ end trace 0000000000000000 ]---
[  918.564782] kernel: RIP: 0010:isp_fw_log_print+0x3b/0x240 [amd_capture]
[  918.564799] kernel: Code: 55 53 48 83 ec 38 4c 8b b7 60 0b 00 00 80 bf 58 0b 00 00 01 0f 85 fb 00 00 00 4d 85 f6 0f 84 f2 00 00 00 48 8b 87 30 02 00 00 <4c> 8b 68 08 48 8b 40 20 44 89 6c 24 08 48 89 44 24 10 48 85 c0 0f
[  918.564814] kernel: RSP: 0018:ffffcf864dc7fd40 EFLAGS: 00010286
[  918.564827] kernel: RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000
[  918.564845] kernel: RDX: ffff8d5b56872180 RSI: ffff8d5b4267b810 RDI: ffff8d5b6c14f0a0
[  918.564859] kernel: RBP: ffff8d5b6c14f0a0 R08: 000000d5a123c41d R09: ffff8d69bd932340
[  918.564878] kernel: R10: 00000000ffffffff R11: 0000000000000008 R12: ffffcf864dc7fdd8
[  918.564893] kernel: R13: ffff8d5b6c14f0a0 R14: ffff8d5b8b400028 R15: 0000000000000000
[  918.564908] kernel: FS:  0000000000000000(0000) GS:ffff8d6a13031000(0000) knlGS:0000000000000000
[  918.564920] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  918.564934] kernel: CR2: 0000000000000008 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  918.564950] kernel: PKRU: 55555554
[  918.564963] kernel: note: amd_isp4_thread[5002] exited with irqs disabled
[  918.564981] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  918.565375] kernel: RIP: 0010:isp_fw_log_print+0x3b/0x240 [amd_capture]
[  918.565394] kernel: Code: 55 53 48 83 ec 38 4c 8b b7 60 0b 00 00 80 bf 58 0b 00 00 01 0f 85 fb 00 00 00 4d 85 f6 0f 84 f2 00 00 00 48 8b 87 30 02 00 00 <4c> 8b 68 08 48 8b 40 20 44 89 6c 24 08 48 89 44 24 10 48 85 c0 0f
[  918.565408] kernel: RSP: 0018:ffffcf864dc7fd40 EFLAGS: 00010286
[  918.565421] kernel: RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000
[  918.565433] kernel: RDX: ffff8d5b56872180 RSI: ffff8d5b4267b810 RDI: ffff8d5b6c14f0a0
[  918.565447] kernel: RBP: ffff8d5b6c14f0a0 R08: 000000d5a123c41d R09: ffff8d69bd932340
[  918.565461] kernel: R10: 00000000ffffffff R11: 0000000000000008 R12: ffffcf864dc7fdd8
[  918.565479] kernel: R13: ffff8d5b6c14f0a0 R14: ffff8d5b8b400028 R15: 0000000000000000
[  918.565494] kernel: FS:  0000000000000000(0000) GS:ffff8d6a13231000(0000) knlGS:0000000000000000
[  918.565507] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  918.565521] kernel: CR2: 0000000000000008 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  918.565533] kernel: PKRU: 55555554
[  918.565547] kernel: note: amd_isp4_thread[5001] exited with irqs disabled
[  919.077018] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  920.089013] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  920.238023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  920.646036] kernel: amdgpu 0000:c3:00.0: amdgpu: Dumping IP State
[  921.021024] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  921.508024] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  921.508222] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  921.848028] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  922.285023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  922.682036] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  923.515180] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  924.333010] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  924.350015] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  924.496016] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  924.496305] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  925.185029] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  926.009022] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  926.381025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  926.838030] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  927.459023] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  927.459268] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  927.678029] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  928.430030] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  928.515027] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  929.351027] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  930.184022] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[  930.439023] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  930.439235] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  930.477023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  932.529902] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  933.404022] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  933.404261] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  934.573027] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  936.382034] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  936.389961] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  936.621027] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  938.669025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  939.355032] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  939.355290] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  940.035030] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[  940.041755] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to disable gfxoff!
[  940.613039] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* [CRTC:86:crtc-0] flip_done timed out
[  940.717023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  942.321041] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  942.327940] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  942.765015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  944.813026] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  946.861152] kernel: amdgpu 0000:c3:00.0: amdgpu: MES failed to respond to msg=MISC (WAIT_REG_MEM)
[  946.868267] kernel: amdgpu 0000:c3:00.0: amdgpu: failed to reg_write_reg_wait
[  946.868449] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  948.157403] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[  948.909023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  950.957023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  951.028997] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[  953.006023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  953.900577] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[  953.950623] kernel: ------------[ cut here ]------------
[  953.950710] kernel: refcount_t: addition on 0; use-after-free.
[  953.950738] kernel: WARNING: CPU: 7 PID: 4999 at lib/refcount.c:25 refcount_warn_saturate+0xe5/0x110
[  953.950764] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[  953.950881] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[  953.950916] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[  953.950943] kernel: CPU: 7 UID: 1000 PID: 4999 Comm: cheese Tainted: G      D             6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[  953.950981] kernel: Tainted: [D]=DIE
[  953.951012] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[  953.951036] kernel: RIP: 0010:refcount_warn_saturate+0xe5/0x110
[  953.951060] kernel: Code: 6b 81 ff 0f 0b c3 cc cc cc cc 80 3d 25 dd b4 01 00 0f 85 5e ff ff ff 48 c7 c7 c0 0f 37 a9 c6 05 11 dd b4 01 01 e8 5b 6b 81 ff <0f> 0b c3 cc cc cc cc 48 c7 c7 18 10 37 a9 c6 05 f5 dc b4 01 01 e8
[  953.951342] kernel: RSP: 0018:ffffcf864d31fa00 EFLAGS: 00010246
[  953.972367] kernel: RAX: 0000000000000000 RBX: ffff8d5b7585a180 RCX: 0000000000000027
[  953.972390] kernel: RDX: ffff8d69bd9dcf88 RSI: 0000000000000001 RDI: ffff8d69bd9dcf80
[  953.972411] kernel: RBP: ffff8d5b4267b810 R08: 0000000000000000 R09: 00000000ffffdfff
[  953.972439] kernel: R10: ffffffffaa972880 R11: ffffcf864d31f898 R12: 0000000000000000
[  953.972462] kernel: R13: 00000000ffffffff R14: ffff8d5b6c14f318 R15: 0000000000000000
[  953.972483] kernel: FS:  0000000000000000(0000) GS:ffff8d6a130f1000(0000) knlGS:0000000000000000
[  953.972503] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  953.972524] kernel: CR2: 0000564608b1b0f0 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  953.972554] kernel: PKRU: 55555554
[  953.972574] kernel: Call Trace:
[  953.972597] kernel:  <TASK>
[  953.972618] kernel:  kthread_stop+0x16c/0x180
[  953.972644] kernel:  isp4sd_pwroff_and_deinit+0x6b/0x150 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  953.972670] kernel:  pipeline_pm_power_one+0x116/0x120 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.972692] kernel:  pipeline_pm_power+0x59/0xa0 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.972714] kernel:  v4l2_pipeline_pm_use+0x40/0x70 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.972737] kernel:  v4l2_pipeline_pm_put+0x10/0x20 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.972758] kernel:  isp4vid_qops_stop_streaming+0xb7/0x230 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  953.972776] kernel:  __vb2_queue_cancel+0x2a/0x2c0 [videobuf2_common 6dc0659913c788cb8cc89c12dbbcfa4a2ba9594f]
[  953.972798] kernel:  vb2_core_queue_release+0x22/0x80 [videobuf2_common 6dc0659913c788cb8cc89c12dbbcfa4a2ba9594f]
[  953.972822] kernel:  _vb2_fop_release+0x58/0xb0 [videobuf2_v4l2 aca25aacea650e334c13a3d6e210e973c75ec146]
[  953.972843] kernel:  v4l2_release+0xc0/0xd0 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.972871] kernel:  __fput+0xe3/0x2a0
[  953.972891] kernel:  task_work_run+0x5a/0x90
[  953.972916] kernel:  do_exit+0x29c/0xa80
[  953.972938] kernel:  do_group_exit+0x2d/0xc0
[  953.972959] kernel:  ? _raw_spin_lock_irq+0x2f/0x40
[  953.972981] kernel:  get_signal+0x81c/0x840
[  953.973007] kernel:  arch_do_signal_or_restart+0x3f/0x280
[  953.973038] kernel:  exit_to_user_mode_loop+0x7e/0x150
[  953.973072] kernel:  do_syscall_64+0x1dd/0x970
[  953.973090] kernel:  ? __x64_sys_ioctl+0xb1/0xe0
[  953.973115] kernel:  ? do_syscall_64+0x81/0x970
[  953.973137] kernel:  ? exit_to_user_mode_loop+0xcf/0x150
[  953.973155] kernel:  ? do_syscall_64+0x215/0x970
[  953.973174] kernel:  ? do_syscall_64+0x81/0x970
[  953.973193] kernel:  ? do_syscall_64+0x81/0x970
[  953.973209] kernel:  ? do_syscall_64+0x81/0x970
[  953.973224] kernel:  ? do_syscall_64+0x81/0x970
[  953.973241] kernel:  ? do_syscall_64+0x81/0x970
[  953.973259] kernel:  ? exc_page_fault+0x7e/0x1a0
[  953.973282] kernel:  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  953.973300] kernel: RIP: 0033:0x7f2743d88e22
[  953.973323] kernel: Code: Unable to access opcode bytes at 0x7f2743d88df8.
[  953.973599] kernel: RSP: 002b:00007f26df3fe438 EFLAGS: 00000246 ORIG_RAX: 000000000000010f
[  953.994671] kernel: RAX: fffffffffffffdfe RBX: 0000000000000000 RCX: 00007f2743d88e22
[  953.994693] kernel: RDX: 0000000000000000 RSI: 0000000000000003 RDI: 00007f26b401e4e0
[  953.994721] kernel: RBP: 00007f26df3fe470 R08: 0000000000000008 R09: 0000000000000000
[  953.994739] kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 00007f26d8015f60
[  953.994765] kernel: R13: 00007ffe1c359ef0 R14: 00007f26df3ffcdc R15: 00007f26d8015f60
[  953.994786] kernel:  </TASK>
[  953.994808] kernel: ---[ end trace 0000000000000000 ]---
[  953.994826] kernel: ------------[ cut here ]------------
[  953.994843] kernel: WARNING: CPU: 7 PID: 4999 at kernel/kthread.c:84 kthread_stop+0x144/0x180
[  953.994862] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[  953.994894] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[  953.994923] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[  953.994937] kernel: CPU: 7 UID: 1000 PID: 4999 Comm: cheese Tainted: G      D W           6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[  953.994954] kernel: Tainted: [D]=DIE, [W]=WARN
[  953.994984] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[  953.995004] kernel: RIP: 0010:kthread_stop+0x144/0x180
[  953.995022] kernel: Code: e9 64 ff ff ff 48 89 df e8 c9 7e fc ff e9 55 ff ff ff be 01 00 00 00 48 8d 7b 28 e8 76 4c 7b 00 f6 43 2e 20 0f 85 f5 fe ff ff <0f> 0b e9 ee fe ff ff be 03 00 00 00 48 8d 7b 28 e8 57 4c 7b 00 e9
[  953.995043] kernel: RSP: 0018:ffffcf864d31fa08 EFLAGS: 00010246
[  953.995059] kernel: RAX: 0000000000000000 RBX: ffff8d5b7585a180 RCX: 0000000000000027
[  953.995076] kernel: RDX: ffff8d69bd9dcf88 RSI: 0000000000000001 RDI: ffff8d69bd9dcf80
[  953.995090] kernel: RBP: ffff8d5b4267b810 R08: 0000000000000000 R09: 00000000ffffdfff
[  953.995112] kernel: R10: ffffffffaa972880 R11: ffffcf864d31f898 R12: 0000000000000000
[  953.995128] kernel: R13: 00000000ffffffff R14: ffff8d5b6c14f318 R15: 0000000000000000
[  953.995145] kernel: FS:  0000000000000000(0000) GS:ffff8d6a130f1000(0000) knlGS:0000000000000000
[  953.995165] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  953.995179] kernel: CR2: 0000564608b1b0f0 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  953.995196] kernel: PKRU: 55555554
[  953.995211] kernel: Call Trace:
[  953.995228] kernel:  <TASK>
[  953.995240] kernel:  isp4sd_pwroff_and_deinit+0x6b/0x150 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  953.995254] kernel:  pipeline_pm_power_one+0x116/0x120 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.995271] kernel:  pipeline_pm_power+0x59/0xa0 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.995285] kernel:  v4l2_pipeline_pm_use+0x40/0x70 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.995301] kernel:  v4l2_pipeline_pm_put+0x10/0x20 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.995313] kernel:  isp4vid_qops_stop_streaming+0xb7/0x230 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  953.995329] kernel:  __vb2_queue_cancel+0x2a/0x2c0 [videobuf2_common 6dc0659913c788cb8cc89c12dbbcfa4a2ba9594f]
[  953.995343] kernel:  vb2_core_queue_release+0x22/0x80 [videobuf2_common 6dc0659913c788cb8cc89c12dbbcfa4a2ba9594f]
[  953.995356] kernel:  _vb2_fop_release+0x58/0xb0 [videobuf2_v4l2 aca25aacea650e334c13a3d6e210e973c75ec146]
[  953.995368] kernel:  v4l2_release+0xc0/0xd0 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  953.995387] kernel:  __fput+0xe3/0x2a0
[  953.995401] kernel:  task_work_run+0x5a/0x90
[  953.995414] kernel:  do_exit+0x29c/0xa80
[  953.995428] kernel:  do_group_exit+0x2d/0xc0
[  953.995439] kernel:  ? _raw_spin_lock_irq+0x2f/0x40
[  953.995451] kernel:  get_signal+0x81c/0x840
[  953.995466] kernel:  arch_do_signal_or_restart+0x3f/0x280
[  953.995480] kernel:  exit_to_user_mode_loop+0x7e/0x150
[  953.995497] kernel:  do_syscall_64+0x1dd/0x970
[  953.995510] kernel:  ? __x64_sys_ioctl+0xb1/0xe0
[  953.995522] kernel:  ? do_syscall_64+0x81/0x970
[  953.995536] kernel:  ? exit_to_user_mode_loop+0xcf/0x150
[  953.995548] kernel:  ? do_syscall_64+0x215/0x970
[  953.995568] kernel:  ? do_syscall_64+0x81/0x970
[  953.995580] kernel:  ? do_syscall_64+0x81/0x970
[  953.995599] kernel:  ? do_syscall_64+0x81/0x970
[  953.995613] kernel:  ? do_syscall_64+0x81/0x970
[  953.995861] kernel:  ? do_syscall_64+0x81/0x970
[  954.017430] kernel:  ? exc_page_fault+0x7e/0x1a0
[  954.017445] kernel:  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  954.017487] kernel: RIP: 0033:0x7f2743d88e22
[  954.017513] kernel: Code: Unable to access opcode bytes at 0x7f2743d88df8.
[  954.017522] kernel: RSP: 002b:00007f26df3fe438 EFLAGS: 00000246 ORIG_RAX: 000000000000010f
[  954.017532] kernel: RAX: fffffffffffffdfe RBX: 0000000000000000 RCX: 00007f2743d88e22
[  954.017539] kernel: RDX: 0000000000000000 RSI: 0000000000000003 RDI: 00007f26b401e4e0
[  954.017543] kernel: RBP: 00007f26df3fe470 R08: 0000000000000008 R09: 0000000000000000
[  954.017547] kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 00007f26d8015f60
[  954.017557] kernel: R13: 00007ffe1c359ef0 R14: 00007f26df3ffcdc R15: 00007f26d8015f60
[  954.017563] kernel:  </TASK>
[  954.017570] kernel: ---[ end trace 0000000000000000 ]---
[  954.017577] kernel: BUG: kernel NULL pointer dereference, address: 0000000000000000
[  954.017701] kernel: #PF: supervisor write access in kernel mode
[  954.017792] kernel: #PF: error_code(0x0002) - not-present page
[  954.017878] kernel: PGD 0 P4D 0 
[  954.017944] kernel: Oops: Oops: 0002 [#3] SMP NOPTI
[  954.017955] kernel: CPU: 7 UID: 1000 PID: 4999 Comm: cheese Tainted: G      D W           6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[  954.017962] kernel: Tainted: [D]=DIE, [W]=WARN
[  954.017968] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[  954.017972] kernel: RIP: 0010:kthread_stop+0x40/0x180
[  954.017985] kernel: Code: 00 f0 0f c1 43 28 85 c0 0f 84 3a 01 00 00 8d 50 01 09 c2 0f 88 fd 00 00 00 f6 43 2e 20 0f 84 0b 01 00 00 48 8b ab a8 0b 00 00 <f0> 80 4d 00 02 48 89 df e8 a3 fe ff ff f0 80 4b 02 02 48 89 df e8
[  954.017998] kernel: RSP: 0018:ffffcf864d31fa08 EFLAGS: 00010246
[  954.018011] kernel: RAX: 0000000000000000 RBX: ffff8d5b7585a180 RCX: 0000000000000027
[  954.018025] kernel: RDX: ffff8d69bd9dcf88 RSI: 0000000000000001 RDI: ffff8d69bd9dcf80
[  954.018031] kernel: RBP: 0000000000000000 R08: 0000000000000000 R09: 00000000ffffdfff
[  954.018038] kernel: R10: ffffffffaa972880 R11: ffffcf864d31f898 R12: 0000000000000000
[  954.018045] kernel: R13: 00000000ffffffff R14: ffff8d5b6c14f318 R15: 0000000000000000
[  954.018051] kernel: FS:  0000000000000000(0000) GS:ffff8d6a130f1000(0000) knlGS:0000000000000000
[  954.018062] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  954.018067] kernel: CR2: 0000000000000000 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  954.018074] kernel: PKRU: 55555554
[  954.018082] kernel: Call Trace:
[  954.018088] kernel:  <TASK>
[  954.018094] kernel:  isp4sd_pwroff_and_deinit+0x6b/0x150 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  954.018100] kernel:  pipeline_pm_power_one+0x116/0x120 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  954.018105] kernel:  pipeline_pm_power+0x59/0xa0 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  954.018113] kernel:  v4l2_pipeline_pm_use+0x40/0x70 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  954.018120] kernel:  v4l2_pipeline_pm_put+0x10/0x20 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  954.018125] kernel:  isp4vid_qops_stop_streaming+0xb7/0x230 [amd_capture 00147f32a555e0c4384c29b5a17f76e9c9e1a01b]
[  954.018135] kernel:  __vb2_queue_cancel+0x2a/0x2c0 [videobuf2_common 6dc0659913c788cb8cc89c12dbbcfa4a2ba9594f]
[  954.018142] kernel:  vb2_core_queue_release+0x22/0x80 [videobuf2_common 6dc0659913c788cb8cc89c12dbbcfa4a2ba9594f]
[  954.018150] kernel:  _vb2_fop_release+0x58/0xb0 [videobuf2_v4l2 aca25aacea650e334c13a3d6e210e973c75ec146]
[  954.018154] kernel:  v4l2_release+0xc0/0xd0 [videodev 6ca953d590d5f834b55197bf3baeb0b473c0bf30]
[  954.018160] kernel:  __fput+0xe3/0x2a0
[  954.018167] kernel:  task_work_run+0x5a/0x90
[  954.018175] kernel:  do_exit+0x29c/0xa80
[  954.018181] kernel:  do_group_exit+0x2d/0xc0
[  954.018187] kernel:  ? _raw_spin_lock_irq+0x2f/0x40
[  954.018193] kernel:  get_signal+0x81c/0x840
[  954.018199] kernel:  arch_do_signal_or_restart+0x3f/0x280
[  954.018203] kernel:  exit_to_user_mode_loop+0x7e/0x150
[  954.018207] kernel:  do_syscall_64+0x1dd/0x970
[  954.018213] kernel:  ? __x64_sys_ioctl+0xb1/0xe0
[  954.018219] kernel:  ? do_syscall_64+0x81/0x970
[  954.018224] kernel:  ? exit_to_user_mode_loop+0xcf/0x150
[  954.018229] kernel:  ? do_syscall_64+0x215/0x970
[  954.018236] kernel:  ? do_syscall_64+0x81/0x970
[  954.018244] kernel:  ? do_syscall_64+0x81/0x970
[  954.018251] kernel:  ? do_syscall_64+0x81/0x970
[  954.018260] kernel:  ? do_syscall_64+0x81/0x970
[  954.018264] kernel:  ? do_syscall_64+0x81/0x970
[  954.018274] kernel:  ? exc_page_fault+0x7e/0x1a0
[  954.018278] kernel:  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  954.018283] kernel: RIP: 0033:0x7f2743d88e22
[  954.018290] kernel: Code: Unable to access opcode bytes at 0x7f2743d88df8.
[  954.018296] kernel: RSP: 002b:00007f26df3fe438 EFLAGS: 00000246 ORIG_RAX: 000000000000010f
[  954.018301] kernel: RAX: fffffffffffffdfe RBX: 0000000000000000 RCX: 00007f2743d88e22
[  954.018306] kernel: RDX: 0000000000000000 RSI: 0000000000000003 RDI: 00007f26b401e4e0
[  954.018564] kernel: RBP: 00007f26df3fe470 R08: 0000000000000008 R09: 0000000000000000
[  954.018572] kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 00007f26d8015f60
[  954.018579] kernel: R13: 00007ffe1c359ef0 R14: 00007f26df3ffcdc R15: 00007f26d8015f60
[  954.018587] kernel:  </TASK>
[  954.018594] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[  954.040885] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[  954.040898] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[  954.040908] kernel: CR2: 0000000000000000
[  954.040919] kernel: ---[ end trace 0000000000000000 ]---
[  954.285065] kernel: RIP: 0010:isp_fw_log_print+0x3b/0x240 [amd_capture]
[  954.285380] kernel: Code: 55 53 48 83 ec 38 4c 8b b7 60 0b 00 00 80 bf 58 0b 00 00 01 0f 85 fb 00 00 00 4d 85 f6 0f 84 f2 00 00 00 48 8b 87 30 02 00 00 <4c> 8b 68 08 48 8b 40 20 44 89 6c 24 08 48 89 44 24 10 48 85 c0 0f
[  954.285399] kernel: RSP: 0018:ffffcf864dc7fd40 EFLAGS: 00010286
[  954.285414] kernel: RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000
[  954.285433] kernel: RDX: ffff8d5b56872180 RSI: ffff8d5b4267b810 RDI: ffff8d5b6c14f0a0
[  954.285442] kernel: RBP: ffff8d5b6c14f0a0 R08: 000000d5a123c41d R09: ffff8d69bd932340
[  954.285532] kernel: R10: 00000000ffffffff R11: 0000000000000008 R12: ffffcf864dc7fdd8
[  954.285543] kernel: R13: ffff8d5b6c14f0a0 R14: ffff8d5b8b400028 R15: 0000000000000000
[  954.285555] kernel: FS:  0000000000000000(0000) GS:ffff8d6a130f1000(0000) knlGS:0000000000000000
[  954.285571] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  954.285583] kernel: CR2: 0000000000000000 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[  954.285594] kernel: PKRU: 55555554
[  954.285605] kernel: note: cheese[4999] exited with irqs disabled
[  954.285621] kernel: Fixing recursive fault but reboot is needed!
[  954.285730] kernel: BUG: scheduling while atomic: cheese/4999/0x00000000
[  954.285783] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[  954.285852] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[  954.285872] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[  954.285882] kernel: CPU: 7 UID: 1000 PID: 4999 Comm: cheese Tainted: G      D W           6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[  954.285895] kernel: Tainted: [D]=DIE, [W]=WARN
[  954.285905] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[  954.285914] kernel: Call Trace:
[  954.285934] kernel:  <TASK>
[  954.285942] kernel:  dump_stack_lvl+0x5d/0x80
[  954.285955] kernel:  __schedule_bug.cold+0x42/0x4e
[  954.285962] kernel:  __schedule+0x1080/0x1320
[  954.285980] kernel:  ? irq_work_queue+0x2d/0x50
[  954.285993] kernel:  ? _printk+0x6b/0x90
[  954.286015] kernel:  do_task_dead+0x4b/0xb0
[  954.286026] kernel:  make_task_dead.cold+0x10a/0x116
[  954.286035] kernel:  rewind_stack_and_make_dead+0x16/0x20
[  954.286047] kernel: RIP: 0033:0x7f2743d88e22
[  954.286054] kernel: Code: Unable to access opcode bytes at 0x7f2743d88df8.
[  954.286066] kernel: RSP: 002b:00007f26df3fe438 EFLAGS: 00000246 ORIG_RAX: 000000000000010f
[  954.286075] kernel: RAX: fffffffffffffdfe RBX: 0000000000000000 RCX: 00007f2743d88e22
[  954.286088] kernel: RDX: 0000000000000000 RSI: 0000000000000003 RDI: 00007f26b401e4e0
[  954.286096] kernel: RBP: 00007f26df3fe470 R08: 0000000000000008 R09: 0000000000000000
[  954.286108] kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 00007f26d8015f60
[  954.286113] kernel: R13: 00007ffe1c359ef0 R14: 00007f26df3ffcdc R15: 00007f26d8015f60
[  954.286123] kernel:  </TASK>
[  955.116025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  957.165016] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  959.213013] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  961.261015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  962.901024] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[  962.908194] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to disable gfxoff!
[  963.309015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  965.357018] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  967.405013] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  969.453017] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  971.501015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  973.549019] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  975.597021] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  977.645020] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  979.693019] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  981.741032] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  983.789025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  985.837015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  986.139012] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[  986.139115] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to disable gfxoff!
[  987.885014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  989.933024] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  991.981023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  994.029029] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  996.077027] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[  998.125027] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1000.173011] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1002.221031] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1004.269023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1006.317028] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1008.365025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1009.189023] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[ 1009.195852] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to disable gfxoff!
[ 1009.196050] kernel: amdgpu 0000:c3:00.0: amdgpu: Dumping IP State Completed
[ 1009.196194] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] AMDGPU device coredump file has been created
[ 1009.196325] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] Check your /sys/class/drm/card1/device/devcoredump/data
[ 1009.196454] kernel: amdgpu 0000:c3:00.0: amdgpu: ring sdma0 timeout, signaled seq=30914, emitted seq=30917
[ 1009.196584] kernel: amdgpu 0000:c3:00.0: amdgpu: Starting sdma0 ring reset
[ 1009.196709] kernel: amdgpu 0000:c3:00.0: amdgpu: reset sdma queue (0:0:0)
[ 1009.372022] kernel: amdgpu 0000:c3:00.0: [drm:amdgpu_ring_test_helper [amdgpu]] *ERROR* ring sdma0 test failed (-110)
[ 1009.372212] kernel: amdgpu 0000:c3:00.0: amdgpu: Ring sdma0 reset failure
[ 1009.372349] kernel: amdgpu 0000:c3:00.0: amdgpu: GPU reset begin!
[ 1010.413028] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1012.461014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1014.509018] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1016.557019] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1032.645275] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[ 1032.650837] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to power ungate VPE!
[ 1032.650911] kernel: [drm:vpe_set_powergating_state [amdgpu]] *ERROR* Dpm enable vpe failed, ret = -62.
[ 1046.080016] kernel: ACPI Error: Aborting method \_SB.A018 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086586] kernel: ACPI Error: Aborting method \_SB.A032 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086630] kernel: ACPI Error: Aborting method \_SB.ALIB due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086659] kernel: ACPI Error: Aborting method \_SB.PLOV due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086697] kernel: ACPI Error: Aborting method \_SB.APX8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086726] kernel: ACPI Error: Aborting method \_SB.PMF.PMF8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086750] kernel: ACPI Error: Aborting method \_SB.PMF.APMF due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1046.086771] kernel: amd-pmf AMDI0105:00: APMF method:8 call failed
[ 1050.097014] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[ 1050.103571] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to disable gfxoff!
[ 1050.920019] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1051.743015] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1052.610015] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1053.541011] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1054.474015] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1055.397014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1056.503015] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1057.392014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1058.479014] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1059.348027] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1076.091014] kernel: ACPI Error: Aborting method \_SB.A018 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097404] kernel: ACPI Error: Aborting method \_SB.A032 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097424] kernel: ACPI Error: Aborting method \_SB.ALIB due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097439] kernel: ACPI Error: Aborting method \_SB.PLOV due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097451] kernel: ACPI Error: Aborting method \_SB.APX8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097464] kernel: ACPI Error: Aborting method \_SB.PMF.PMF8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097475] kernel: ACPI Error: Aborting method \_SB.PMF.APMF due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1076.097486] kernel: amd-pmf AMDI0105:00: APMF method:8 call failed
[ 1077.092016] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1079.149015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1081.197014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1083.245014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1085.293014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1087.341014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1089.389014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1091.437013] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1093.485014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1093.967013] kernel: ------------[ cut here ]------------
[ 1093.973545] kernel: WARNING: CPU: 6 PID: 3965 at drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn35/dcn35_smu.c:175 dcn35_smu_send_msg_with_param+0x10c/0x1d0 [amdgpu]
[ 1093.973564] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[ 1093.973646] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[ 1093.973668] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[ 1093.973686] kernel: CPU: 6 UID: 0 PID: 3965 Comm: kworker/u128:3 Tainted: G      D W           6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[ 1093.973704] kernel: Tainted: [D]=DIE, [W]=WARN
[ 1093.973721] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[ 1093.973731] kernel: Workqueue: amdgpu-reset-dev drm_sched_job_timedout [gpu_sched]
[ 1093.973744] kernel: RIP: 0010:dcn35_smu_send_msg_with_param+0x10c/0x1d0 [amdgpu]
[ 1093.973761] kernel: Code: cd 48 8b 3b 3d ff 00 00 00 0f 84 8a 00 00 00 48 83 c4 08 48 c7 c2 10 21 27 c2 be 93 62 01 00 5b 5d 41 5c 41 5d e9 94 b3 ee ff <0f> 0b bd 80 84 1e 00 48 c7 c2 f0 1f 27 c2 be 9b 62 01 00 e8 7c b3
[ 1093.973776] kernel: RSP: 0018:ffffcf864dabf818 EFLAGS: 00010246
[ 1093.973790] kernel: RAX: 0000000000000000 RBX: ffff8d5b477bfc00 RCX: 0000000000000006
[ 1093.973803] kernel: RDX: 0000000000007ddc RSI: 00000000000074f5 RDI: ffff8d5b47f8eb00
[ 1093.973817] kernel: RBP: 00000000ffffffff R08: ffffcf864dabf81c R09: 0000000000000016
[ 1093.973830] kernel: R10: 00000000000039bc R11: 00000000000039ba R12: 0000000000000015
[ 1093.973843] kernel: R13: 0000000000000700 R14: ffff8d5b477bfc00 R15: ffff8d5c6dc00000
[ 1093.973855] kernel: FS:  0000000000000000(0000) GS:ffff8d6a130b1000(0000) knlGS:0000000000000000
[ 1093.973868] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1093.973878] kernel: CR2: 00007fd9b32edce8 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[ 1093.973888] kernel: PKRU: 55555554
[ 1093.973898] kernel: Call Trace:
[ 1093.973913] kernel:  <TASK>
[ 1093.973926] kernel:  dcn35_smu_set_zstate_support+0x58/0x190 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.973940] kernel:  dcn35_update_clocks+0xc8/0x620 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.973951] kernel:  dcn20_optimize_bandwidth+0x119/0x220 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.973964] kernel:  dcn35_optimize_bandwidth+0x58/0xd0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.973975] kernel:  dc_commit_state_no_check+0xd0b/0xf70 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.973986] kernel:  dc_commit_streams+0x2c9/0x480 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974010] kernel:  dm_suspend+0x221/0x280 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974022] kernel:  amdgpu_ip_block_suspend+0x24/0x50 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974071] kernel:  amdgpu_device_ip_suspend_phase1+0xaa/0xc0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974122] kernel:  amdgpu_device_ip_suspend+0x2c/0x80 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974140] kernel:  ? amdgpu_device_ip_need_full_reset+0x16/0x80 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974162] kernel:  amdgpu_device_pre_asic_reset+0xe9/0x2c0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974179] kernel:  amdgpu_device_asic_reset+0x56/0x46f [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974202] kernel:  amdgpu_device_gpu_recover.cold+0x1e3/0x238 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974221] kernel:  amdgpu_job_timedout.cold+0x20a/0x450 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1093.974240] kernel:  drm_sched_job_timedout+0x85/0x120 [gpu_sched ba418b4c7d9c20d3d2bb52ba3c60dabf01715081]
[ 1093.974272] kernel:  process_one_work+0x190/0x350
[ 1093.974295] kernel:  worker_thread+0x2d7/0x410
[ 1093.974312] kernel:  ? __pfx_worker_thread+0x10/0x10
[ 1093.974335] kernel:  kthread+0xf9/0x240
[ 1093.974356] kernel:  ? __pfx_kthread+0x10/0x10
[ 1093.974373] kernel:  ? __pfx_kthread+0x10/0x10
[ 1093.974390] kernel:  ret_from_fork+0x198/0x1d0
[ 1093.974406] kernel:  ? __pfx_kthread+0x10/0x10
[ 1093.974421] kernel:  ret_from_fork_asm+0x1a/0x30
[ 1093.974439] kernel:  </TASK>
[ 1093.974458] kernel: ---[ end trace 0000000000000000 ]---
[ 1095.533025] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1097.581015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1099.629026] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1129.274032] kernel: amdgpu 0000:c3:00.0: [drm] SMU response after wait: 0, msg id = 21
[ 1130.666029] kernel: ACPI Error: Aborting method \_SB.A018 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670760] kernel: ACPI Error: Aborting method \_SB.A032 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670795] kernel: ACPI Error: Aborting method \_SB.ALIB due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670818] kernel: ACPI Error: Aborting method \_SB.PLOV due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670840] kernel: ACPI Error: Aborting method \_SB.APX8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670863] kernel: ACPI Error: Aborting method \_SB.PMF.PMF8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670883] kernel: ACPI Error: Aborting method \_SB.PMF.APMF due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1130.670904] kernel: amd-pmf AMDI0105:00: APMF method:8 call failed
[ 1131.674023] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1160.678035] kernel: ACPI Error: Aborting method \_SB.A018 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684188] kernel: ACPI Error: Aborting method \_SB.A032 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684221] kernel: ACPI Error: Aborting method \_SB.ALIB due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684242] kernel: ACPI Error: Aborting method \_SB.PLOV due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684265] kernel: ACPI Error: Aborting method \_SB.APX8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684288] kernel: ACPI Error: Aborting method \_SB.PMF.PMF8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684309] kernel: ACPI Error: Aborting method \_SB.PMF.APMF due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1160.684329] kernel: amd-pmf AMDI0105:00: APMF method:8 call failed
[ 1162.733014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1164.033051] kernel: ------------[ cut here ]------------
[ 1164.039477] kernel: WARNING: CPU: 14 PID: 3965 at drivers/gpu/drm/amd/amdgpu/../display/dc/clk_mgr/dcn35/dcn35_smu.c:143 dcn35_smu_send_msg_with_param+0x164/0x1d0 [amdgpu]
[ 1164.039523] kernel: Modules linked in: uas usb_storage ccm hid_sensor_gyro_3d hid_sensor_prox hid_sensor_trigger industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm snd_seq_dummy snd_hrtimer snd_seq snd_seq_device ov05c10 v4l2_cci amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev mc i2c_designware_amdisp pinctrl_amdisp cmac algif_hash algif_skcipher af_alg bnep uinput nls_iso8859_1 vfat fat amdgpu mt7925e mt7925_common mt792x_lib snd_acp_legacy_mach mt76_connac_lib snd_acp_mach snd_soc_nau8821 mt76 snd_acp3x_rn snd_acp70 amd_atl intel_rapl_msr snd_acp_i2s intel_rapl_common snd_acp_pdm snd_acp_pcm snd_soc_dmic snd_sof_amd_acp70 snd_sof_amd_acp63 mac80211 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_sof_xtensa_dsp snd_sof snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi snd_hda_scodec_cs35l56_spi soundwire_amd snd_ctl_led amdxcp soundwire_generic_allocation kvm_amd
[ 1164.039628] kernel:  drm_panel_backlight_quirks snd_hda_codec_realtek soundwire_bus drm_buddy drm_exec snd_hda_codec_generic drm_suballoc_helper snd_soc_sdca joydev drm_ttm_helper snd_hda_scodec_component libarc4 snd_hda_codec_hdmi mousedev snd_soc_core kvm snd_hda_intel ttm snd_intel_dspcfg cfg80211 snd_intel_sdw_acpi snd_compress i2c_algo_bit ac97_bus snd_hda_codec drm_display_helper snd_pcm_dmaengine snd_rpl_pci_acp6x snd_acp_pci snd_hda_core snd_amd_acpi_mach cec btusb snd_hda_scodec_cs35l56_i2c snd_acp_legacy_common snd_hda_scodec_cs35l56 btrtl snd_hwdep snd_pci_acp6x ucsi_acpi snd_hda_cirrus_scodec btintel snd_pcm typec_ucsi snd_soc_cs35l56_shared amd_pmf amdxdna snd_pci_acp5x spd5118 snd_soc_cs_amp_lib btbcm hp_wmi snd_rn_pci_acp3x typec wmi_bmof amdtee cs_dsp hid_multitouch snd_acp_config snd_timer btmtk video sparse_keymap sp5100_tco irqbypass roles bluetooth thunderbolt snd snd_soc_acpi i2c_piix4 gpu_sched amd_sfh rfkill rapl soundcore i2c_hid_acpi wmi platform_profile snd_pci_acp3x i2c_smbus wireless_hotkey
[ 1164.039665] kernel:  amd_isp4 i2c_hid amd_pmc serial_multi_instantiate mac_hid i2c_dev crypto_user loop nfnetlink ip_tables x_tables dm_crypt encrypted_keys trusted asn1_encoder tee dm_mod nvme nvme_core polyval_clmulni ghash_clmulni_intel ccp sha512_ssse3 sha1_ssse3 aesni_intel nvme_keyring serio_raw nvme_auth
[ 1164.039688] kernel: CPU: 14 UID: 0 PID: 3965 Comm: kworker/u128:3 Tainted: G      D W           6.16.0-00020-g541e951a4e8a #1 PREEMPT(full)  ec39f80096e0b20fee1b3472ffc6dfe32b18badd
[ 1164.039714] kernel: Tainted: [D]=DIE, [W]=WARN
[ 1164.039739] kernel: Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[ 1164.039768] kernel: Workqueue: amdgpu-reset-dev drm_sched_job_timedout [gpu_sched]
[ 1164.039793] kernel: RIP: 0010:dcn35_smu_send_msg_with_param+0x164/0x1d0 [amdgpu]
[ 1164.039816] kernel: Code: 3b 48 8b 17 48 89 f8 0f b6 92 ca 01 00 00 01 ea 8d 6a ff 75 c4 48 8b 40 10 48 8b 38 48 85 ff 0f 85 8a 17 27 00 e9 89 17 27 00 <0f> 0b 48 8b 57 10 48 8b 3a 48 85 ff 0f 84 4f 17 27 00 e9 46 17 27
[ 1164.039849] kernel: RSP: 0018:ffffcf864dabf820 EFLAGS: 00010246
[ 1164.039876] kernel: RAX: 0000000000000000 RBX: ffff8d5b477bfc00 RCX: 000000000000000e
[ 1164.039896] kernel: RDX: 0000000000007fda RSI: 00000000000074f5 RDI: ffff8d5b47f8eb00
[ 1164.039917] kernel: RBP: 00000000ffffffff R08: 0000000000000000 R09: ffff8d5b4bf47540
[ 1164.039934] kernel: R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000004
[ 1164.039961] kernel: R13: 0000000000000032 R14: ffff8d5b477bfc00 R15: ffff8d5c6dc00000
[ 1164.039981] kernel: FS:  0000000000000000(0000) GS:ffff8d6a132b1000(0000) knlGS:0000000000000000
[ 1164.040016] kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1164.040039] kernel: CR2: 00007fd9b3cdc7c4 CR3: 0000000f4c424000 CR4: 0000000000f50ef0
[ 1164.040072] kernel: PKRU: 55555554
[ 1164.040095] kernel: Call Trace:
[ 1164.040116] kernel:  <TASK>
[ 1164.040137] kernel:  ? amdgpu_dm_is_headless+0x7a/0xb0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040158] kernel:  dcn35_smu_set_dispclk+0x44/0x90 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040177] kernel:  dcn35_update_clocks+0x270/0x620 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040194] kernel:  dcn20_optimize_bandwidth+0x119/0x220 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040216] kernel:  dcn35_optimize_bandwidth+0x58/0xd0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040233] kernel:  dc_commit_state_no_check+0xd0b/0xf70 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040258] kernel:  dc_commit_streams+0x2c9/0x480 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040276] kernel:  dm_suspend+0x221/0x280 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040289] kernel:  amdgpu_ip_block_suspend+0x24/0x50 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040305] kernel:  amdgpu_device_ip_suspend_phase1+0xaa/0xc0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040322] kernel:  amdgpu_device_ip_suspend+0x2c/0x80 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040348] kernel:  ? amdgpu_device_ip_need_full_reset+0x16/0x80 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040367] kernel:  amdgpu_device_pre_asic_reset+0xe9/0x2c0 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040385] kernel:  amdgpu_device_asic_reset+0x56/0x46f [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040398] kernel:  amdgpu_device_gpu_recover.cold+0x1e3/0x238 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040417] kernel:  amdgpu_job_timedout.cold+0x20a/0x450 [amdgpu 983cbf93452e2aff0ee5d819daca7797cd468da1]
[ 1164.040435] kernel:  drm_sched_job_timedout+0x85/0x120 [gpu_sched ba418b4c7d9c20d3d2bb52ba3c60dabf01715081]
[ 1164.040450] kernel:  process_one_work+0x190/0x350
[ 1164.040469] kernel:  worker_thread+0x2d7/0x410
[ 1164.040486] kernel:  ? __pfx_worker_thread+0x10/0x10
[ 1164.040501] kernel:  kthread+0xf9/0x240
[ 1164.040523] kernel:  ? __pfx_kthread+0x10/0x10
[ 1164.040544] kernel:  ? __pfx_kthread+0x10/0x10
[ 1164.040562] kernel:  ret_from_fork+0x198/0x1d0
[ 1164.040580] kernel:  ? __pfx_kthread+0x10/0x10
[ 1164.040595] kernel:  ret_from_fork_asm+0x1a/0x30
[ 1164.040613] kernel:  </TASK>
[ 1164.040634] kernel: ---[ end trace 0000000000000000 ]---
[ 1164.040648] kernel: amdgpu 0000:c3:00.0: [drm] SMU response after wait: 0, msg id = 4
[ 1164.781033] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1166.829016] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1168.877014] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1170.925015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1172.973015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1175.021015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1177.069015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1179.117015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1181.165015] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1183.213013] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1185.261024] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1198.250025] kernel: amdgpu 0000:c3:00.0: [drm] SMU response after wait: 0, msg id = 6
[ 1199.058025] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* dc_dmub_srv_log_diagnostic_data: DMCUB error - collecting diagnostic data
[ 1199.571025] kernel: [drm] Register(0) [regVPEC_QUEUE_RESET_REQ_6_1_1] failed to reach value 0x00000000 != 0x00000001n
[ 1199.582725] kernel: amdgpu 0000:c3:00.0: amdgpu: VPE queue reset failed
[ 1200.110027] kernel: [drm] Register(1) [regVPEC_QUEUE_RESET_REQ_6_1_1] failed to reach value 0x00000000 != 0x00000001n
[ 1200.110100] kernel: amdgpu 0000:c3:00.0: amdgpu: VPE queue reset failed
[ 1202.991904] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1205.862193] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1208.732549] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1211.601321] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1214.470739] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1215.241048] kernel: ACPI Error: Aborting method \_SB.A018 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247590] kernel: ACPI Error: Aborting method \_SB.A032 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247631] kernel: ACPI Error: Aborting method \_SB.ALIB due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247654] kernel: ACPI Error: Aborting method \_SB.PLOV due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247676] kernel: ACPI Error: Aborting method \_SB.APX8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247694] kernel: ACPI Error: Aborting method \_SB.PMF.PMF8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247715] kernel: ACPI Error: Aborting method \_SB.PMF.APMF due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1215.247740] kernel: amd-pmf AMDI0105:00: APMF method:8 call failed
[ 1217.343433] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1220.215993] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1223.087728] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1225.959234] kernel: amdgpu 0000:c3:00.0: amdgpu: MES ring buffer is full.
[ 1225.965756] kernel: amdgpu 0000:c3:00.0: amdgpu: MODE2 reset
[ 1237.536018] kernel: amdgpu 0000:c3:00.0: amdgpu: SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x0000001A SMN_C2PMSG_82:0x00000000
[ 1237.544616] kernel: amdgpu 0000:c3:00.0: amdgpu: Failed to mode2 reset!
[ 1237.544694] kernel: amdgpu 0000:c3:00.0: amdgpu: Mode2 reset failed!
[ 1237.544755] kernel: amdgpu 0000:c3:00.0: amdgpu: ASIC reset failed with error, -62 for drm dev, 0000:c3:00.0
[ 1237.544814] kernel: amdgpu 0000:c3:00.0: amdgpu: GPU reset end with ret = -62
[ 1237.544872] kernel: amdgpu 0000:c3:00.0: amdgpu: GPU Recovery Failed: -62
[ 1239.621017] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* flip_done timed out
[ 1239.627828] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* [CRTC:86:crtc-0] commit wait timed out
[ 1245.253013] kernel: ACPI Error: Aborting method \_SB.A018 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261324] kernel: ACPI Error: Aborting method \_SB.A032 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261343] kernel: ACPI Error: Aborting method \_SB.ALIB due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261357] kernel: ACPI Error: Aborting method \_SB.PLOV due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261371] kernel: ACPI Error: Aborting method \_SB.APX8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261383] kernel: ACPI Error: Aborting method \_SB.PMF.PMF8 due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261396] kernel: ACPI Error: Aborting method \_SB.PMF.APMF due to previous error (AE_AML_LOOP_TIMEOUT) (20250404/psparse-529)
[ 1245.261409] kernel: amd-pmf AMDI0105:00: APMF method:8 call failed
[ 1246.263009] kernel: amd-pmf AMDI0105:00: failed to talk to SMU
[ 1247.813039] kernel: amdgpu 0000:c3:00.0: amdgpu: Dumping IP State
[ 1247.820272] kernel: amdgpu 0000:c3:00.0: amdgpu: Dumping IP State Completed
[ 1247.820347] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] AMDGPU device coredump file has been created
[ 1247.820402] kernel: amdgpu 0000:c3:00.0: amdgpu: [drm] Check your /sys/class/drm/card1/device/devcoredump/data
[ 1247.820454] kernel: amdgpu 0000:c3:00.0: amdgpu: ring sdma0 timeout, signaled seq=30914, emitted seq=30917
[ 1247.820502] kernel: amdgpu 0000:c3:00.0: amdgpu: Starting sdma0 ring reset
[ 1247.820553] kernel: amdgpu 0000:c3:00.0: amdgpu: reset sdma queue (0:0:0)
[ 1247.996012] kernel: amdgpu 0000:c3:00.0: [drm:amdgpu_ring_test_helper [amdgpu]] *ERROR* ring sdma0 test failed (-110)
[ 1247.996248] kernel: amdgpu 0000:c3:00.0: amdgpu: Ring sdma0 reset failure
[ 1247.996396] kernel: amdgpu 0000:c3:00.0: amdgpu: GPU reset begin!
[ 1249.861028] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* flip_done timed out
[ 1249.870138] kernel: amdgpu 0000:c3:00.0: [drm] *ERROR* [PLANE:59:plane-3] commit wait timed out

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-28  7:04   ` Sultan Alsawaf
@ 2025-07-29  7:43     ` Du, Bin
  2025-07-31  0:34       ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-29  7:43 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Hi Sultan, really appreciate your time and effort

On 7/28/2025 3:04 PM, Sultan Alsawaf wrote:
> I found more refcounting issues in addition to the ones from my other emails
> while trying to make my webcam work:
> 
> On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
>> +static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
>> +{
>> +	struct isp4vid_vb2_buf *buf = buf_priv;
>> +	int ret;
>> +
>> +	if (!buf) {
>> +		pr_err("fail no memory to map\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
>> +	if (ret) {
>> +		dev_err(buf->dev, "fail remap vmalloc mem, %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * Make sure that vm_areas for 2 buffers won't be merged together
>> +	 */
>> +	vm_flags_set(vma, VM_DONTEXPAND);
>> +
>> +	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
>> +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> 
> Use refcount_read() instead of reading the refcount's atomic_t counter directly.
> This is done in 3 other places; change those to refcount_read() as well.
> 
> This didn't cause any functional problems, but it should still be fixed.
> 
>> +
>> +	return 0;
>> +}
> 
Sure, will fix it

> [snip]
> 
>> +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
>> +{
>> +	struct isp4vid_vb2_buf *buf = mem_priv;
>> +
>> +	if (!buf) {
>> +		pr_err("fail invalid buf handle\n");
>> +		return;
>> +	}
>> +
>> +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
>> +
>> +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
>> +		buf->gpu_addr, buf->size);
>> +
>> +	if (buf->vaddr)
>> +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
>> +
>> +	// put dmabuf for exported ones
>> +	dma_buf_put(buf->dbuf);
>> +
>> +	kfree(buf);
>> +}
> 
> As mentioned in the other email, the dma_buf_put() here needs to be removed. But
> that's not all: the dma_buf_vunmap_unlocked() needs to be removed too because
> vb2 will always unmap the buffer before detaching it. As a result, having the
> dma_buf_vunmap_unlocked() call here results in a use-after-free when vb2 calls
> the unmap_dmabuf memop.
> 
> Change this function to the following:
> 
> 	static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> 	{
> 		struct isp4vid_vb2_buf *buf = mem_priv;
> 
> 		kfree(buf);
> 	}
> 
Will have a try

>> +static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
>> +{
>> +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
>> +	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
>> +
>> +	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
>> +		isp_vdev->vdev.name, vb->index, vb->memory);
>> +
>> +	if (!buf) {
>> +		dev_err(isp_vdev->dev, "Invalid buf handle");
>> +		return;
>> +	}
>> +
>> +	// release implicit dmabuf reference here for vb2 buffer
>> +	// of type MMAP and is exported
>> +	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
>> +		dma_buf_put(buf->dbuf);
>> +		dev_dbg(isp_vdev->dev,
>> +			"put dmabuf for vb->memory %d expbuf %d",
>> +			vb->memory,
>> +			buf->is_expbuf);
>> +	}
>> +}
>> +
> 
> Remove the isp4vid_qops_buffer_cleanup() function. It causes a use-after-free by
> doing an extra dma_buf_put(). This function isn't needed now that the refcount
> issues are solved.
> 
Will have a try

> [snip]
> 
>> +static const struct vb2_ops isp4vid_qops = {
>> +	.queue_setup = isp4vid_qops_queue_setup,
>> +	.buf_cleanup = isp4vid_qops_buffer_cleanup,
> 
> Remove the .buf_cleanup hook too.
> 
Will have a try

>> +	.buf_queue = isp4vid_qops_buffer_queue,
>> +	.start_streaming = isp4vid_qops_start_streaming,
>> +	.stop_streaming = isp4vid_qops_stop_streaming,
>> +	.wait_prepare = vb2_ops_wait_prepare,
>> +	.wait_finish = vb2_ops_wait_finish,
>> +};
> 
> [snip]
> 
> Along with the changes from my other emails, I believe this finally fixes all of
> the refcounting issues. No more UaF or leaks here. :-)
> 
> Sultan
Tried changes in this and other two mails together, found the kernel 
will crash when re-open cheese App (means open cheese, close it and then 
open it again), the crash stack dump is shown below

[   38.008686] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
[   38.032693] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
[   38.060866] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
[   38.060877] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to 
performance state 1 suc
[   38.425284] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none 
to state 0
[   38.448631] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
[   38.508368] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
[   38.538525] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
[   38.568839] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
[   38.568851] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to 
performance state 1 suc
[   38.997779] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none 
to state 0
[   39.029297] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
[   39.084010] BUG: kernel NULL pointer dereference, address: 
0000000000000008
[   39.084024] #PF: supervisor read access in kernel mode
[   39.084028] #PF: error_code(0x0000) - not-present page
[   39.084031] PGD 0 P4D 0
[   39.084037] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
[   39.084042] CPU: 3 UID: 1000 PID: 3119 Comm: viewfinderbin-q Not 
tainted 6.14.0-rc2+ #944
[   39.084046] Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile 
Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
[   39.084049] RIP: 0010:validate_page_before_insert+0x5/0xc0
[   39.084060] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 
00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 
00 <48> 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
[   39.084064] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
[   39.084067] RAX: 0000000000000000 RBX: 8000000000000025 RCX: 
0000000000000000
[   39.084069] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 
ffff9efa10e400b8
[   39.084071] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09: 
0000000000000000
[   39.084072] R10: 0000000000000000 R11: 0000000000000000 R12: 
ffff9efa10e400b8
[   39.084074] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15: 
0000000000000000
[   39.084076] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000) 
knlGS:0000000000000000
[   39.084078] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   39.084080] CR2: 0000000000000008 CR3: 0000000137bba000 CR4: 
0000000000750ef0
[   39.084083] PKRU: 55555554
[   39.084084] Call Trace:
[   39.084087]  <TASK>
[   39.084093]  ? show_regs+0x71/0x90
[   39.084099]  ? __die+0x25/0x80
[   39.084102]  ? page_fault_oops+0x15c/0x570
[   39.084108]  ? do_user_addr_fault+0x4a9/0x810
[   39.084111]  ? __mod_memcg_lruvec_state+0xde/0x280
[   39.084117]  ? exc_page_fault+0x83/0x1d0
[   39.084123]  ? asm_exc_page_fault+0x27/0x30
[   39.084131]  ? validate_page_before_insert+0x5/0xc0
[   39.084134]  ? vm_insert_page+0xd4/0x1a0
[   39.084139]  remap_vmalloc_range_partial+0xe3/0x160
[   39.084145]  remap_vmalloc_range+0x21/0x40
[   39.084153]  isp4vid_vb2_mmap+0x2d/0x130 [amd_capture]
[   39.084164]  isp4vid_vb2_dmabuf_ops_mmap+0x12/0x20 [amd_capture]
[   39.084168]  dma_buf_mmap_internal+0x41/0x70
[   39.084173]  __mmap_region+0x62f/0xbc0
[   39.084179]  mmap_region+0x67/0xe0
[   39.084181]  do_mmap+0x52b/0x650
[   39.084187]  vm_mmap_pgoff+0xf4/0x1c0
[   39.084194]  ksys_mmap_pgoff+0x182/0x250
[   39.084198]  __x64_sys_mmap+0x33/0x70
[   39.084202]  x64_sys_call+0x2541/0x26f0
[   39.084206]  do_syscall_64+0x70/0x130
[   39.084212]  ? __rseq_handle_notify_resume+0xa4/0x520
[   39.084216]  ? do_futex+0x17f/0x220
[   39.084220]  ? restore_fpregs_from_fpstate+0x3d/0xd0
[   39.084225]  ? switch_fpu_return+0x50/0xe0
[   39.084229]  ? syscall_exit_to_user_mode+0x18c/0x1c0
[   39.084234]  ? do_syscall_64+0x7c/0x130
[   39.084237]  ? __pfx_futex_wake_mark+0x10/0x10
[   39.084241]  ? hrtimer_cancel+0x15/0x50
[   39.084246]  ? futex_wait+0x7c/0x120
[   39.084249]  ? __pfx_hrtimer_wakeup+0x10/0x10
[   39.084254]  ? __rseq_handle_notify_resume+0xa4/0x520
[   39.084256]  ? do_futex+0x17f/0x220
[   39.084258]  ? restore_fpregs_from_fpstate+0x3d/0xd0
[   39.084261]  ? switch_fpu_return+0x50/0xe0
[   39.084264]  ? syscall_exit_to_user_mode+0x18c/0x1c0
[   39.084268]  ? do_syscall_64+0x7c/0x130
[   39.084272]  ? __count_memcg_events+0xcd/0x190
[   39.084276]  ? count_memcg_events.constprop.0+0x2a/0x50
[   39.084279]  ? handle_mm_fault+0x1ef/0x2d0
[   39.084284]  ? do_user_addr_fault+0x58d/0x810
[   39.084286]  ? irqentry_exit_to_user_mode+0x33/0x180
[   39.084291]  ? irqentry_exit+0x43/0x50
[   39.084294]  ? exc_page_fault+0x94/0x1d0
[   39.084298]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[   39.084302] RIP: 0033:0x7fa463b2531c
[   39.084305] Code: 1e fa 41 f7 c1 ff 0f 00 00 75 33 55 48 89 e5 41 54 
41 89 cc 53 48 89 fb 48 85 ff 74 41 45 89 e2 48 89 df b8 09 00 00 00 0f 
05 <48> 3d 00 f0 ff ff 77 7c 5b 41 5c 5d c3 0f 1f 80 00 00 00 00 48 8b
[   39.084308] RSP: 002b:00007fa3f4bf79e0 EFLAGS: 00000246 ORIG_RAX: 
0000000000000009
[   39.084311] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 
00007fa463b2531c
[   39.084312] RDX: 0000000000000001 RSI: 00000000007782c0 RDI: 
0000000000000000
[   39.084314] RBP: 00007fa3f4bf79f0 R08: 0000000000000047 R09: 
0000000000000000
[   39.084315] R10: 0000000000000001 R11: 0000000000000246 R12: 
0000000000000001
[   39.084317] R13: 0000000000000000 R14: 00007fa3f8019b48 R15: 
00007fa3f4bf7b60
[   39.084320]  </TASK>
[   39.084321] Modules linked in: snd_seq_dummy snd_hrtimer 
hid_sensor_prox hid_sensor_gyro_3d hid_sensor_trigger 
industrialio_triggered_buffer kfifo_buf hid_sensor_iio_common 
industrialio hid_sensor_hub rfcomm cmac algif_hash algif_skcipher af_alg 
hid_logitech_hidpp ov05c10 v4l2_cci amd_capture v4l2_fwnode 
videobuf2_memops videobuf2_v4l2 videobuf2_common v4l2_async videodev 
pinctrl_amdisp i2c_designware_amdisp qrtr bnep btusb btrtl btintel btbcm 
btmtk bluetooth hid_logitech_dj intel_rapl_msr amd_atl intel_rapl_common 
binfmt_misc nls_iso8859_1 snd_acp_legacy_mach snd_acp_mach 
snd_soc_nau8821 snd_acp3x_rn amdgpu edac_mce_amd snd_ctl_led 
snd_hda_codec_realtek snd_acp70 snd_hda_codec_generic snd_acp_i2s 
snd_acp_pdm snd_hda_scodec_component snd_soc_dmic snd_acp_pcm 
snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci 
snd_sof_xtensa_dsp snd_hda_codec_hdmi snd_sof snd_sof_utils snd_pci_ps 
snd_soc_acpi_amd_match snd_amd_sdw_acpi soundwire_amd 
soundwire_generic_allocation soundwire_bus snd_hda_intel kvm_amd
[   39.084385]  snd_soc_sdca snd_intel_dspcfg snd_intel_sdw_acpi 
snd_soc_core snd_hda_codec amdxcp kvm snd_compress 
drm_panel_backlight_quirks snd_hda_core snd_usb_audio gpu_sched ac97_bus 
polyval_clmulni snd_pcm_dmaengine polyval_generic ghash_clmulni_intel 
drm_buddy snd_usbmidi_lib snd_seq_midi snd_rpl_pci_acp6x sha256_ssse3 
snd_ump drm_ttm_helper snd_seq_midi_event snd_hwdep sha1_ssse3 ttm 
aesni_intel drm_exec snd_rawmidi drm_suballoc_helper snd_acp_pci mc 
crypto_simd snd_acp_legacy_common drm_client_lib cryptd 
drm_display_helper snd_pci_acp6x snd_seq rapl hp_wmi cec wmi_bmof 
snd_pcm sparse_keymap snd_seq_device rc_core snd_timer snd_pci_acp5x 
drm_kms_helper snd_rn_pci_acp3x amd_pmf snd i2c_algo_bit snd_acp_config 
i2c_piix4 snd_soc_acpi amdtee soundcore snd_pci_acp3x i2c_smbus ccp 
joydev tee input_leds serial_multi_instantiate amd_pmc platform_profile 
wireless_hotkey mac_hid serio_raw sch_fq_codel msr parport_pc ppdev lp 
parport efi_pstore nfnetlink dmi_sysfs ip_tables x_tables autofs4 r8152 
mii usbhid hid_multitouch
[   39.084451]  hid_generic nvme ucsi_acpi i2c_hid_acpi video typec_ucsi 
i2c_hid amd_sfh thunderbolt hid nvme_core typec wmi drm
[   39.084465] CR2: 0000000000000008
[   39.084468] ---[ end trace 0000000000000000 ]---
[   39.116114] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
[   39.159519] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
[   39.201325] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
[   39.201334] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to 
performance state 1 suc
[   39.343894] RIP: 0010:validate_page_before_insert+0x5/0xc0
[   39.343907] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 
00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 
00 <48> 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
[   39.343909] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
[   39.343911] RAX: 0000000000000000 RBX: 8000000000000025 RCX: 
0000000000000000
[   39.343913] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 
ffff9efa10e400b8
[   39.343913] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09: 
0000000000000000
[   39.343914] R10: 0000000000000000 R11: 0000000000000000 R12: 
ffff9efa10e400b8
[   39.343915] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15: 
0000000000000000
[   39.343916] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000) 
knlGS:0000000000000000
[   39.343917] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   39.343918] CR2: 0000000000000008 CR3: 0000000137bba000 CR4: 
0000000000750ef0
[   39.343919] PKRU: 55555554
[   39.343920] note: viewfinderbin-q[3119] exited with irqs disabled

This is the patch, it should have contained all your changes

 From b0a61b6b7500635928166516d5563e6de50300bb Mon Sep 17 00:00:00 2001
From: Bin Du <Bin.Du@amd.com>
Date: Mon, 28 Jul 2025 14:18:04 +0800
Subject: [PATCH] add comment from community

Change-Id: I06fff629c0dc691eaeaa9d9b81e6af27cbb6adb2
---
  drivers/media/platform/amd/isp4/isp4_video.c | 59 ++++++--------------
  1 file changed, 17 insertions(+), 42 deletions(-)

diff --git a/drivers/media/platform/amd/isp4/isp4_video.c 
b/drivers/media/platform/amd/isp4/isp4_video.c
index a1376498c246..b210a0b1e49b 100644
--- a/drivers/media/platform/amd/isp4/isp4_video.c
+++ b/drivers/media/platform/amd/isp4/isp4_video.c
@@ -183,7 +183,7 @@ static int isp4vid_vb2_mmap(void *buf_priv, struct 
vm_area_struct *vma)
  	vm_flags_set(vma, VM_DONTEXPAND);

  	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
-		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
+		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));

  	return 0;
  }
@@ -214,14 +214,9 @@ static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
  		return;
  	}

-	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
-
  	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
  		buf->gpu_addr, buf->size);

-	if (buf->vaddr)
-		dma_buf_vunmap_unlocked(buf->dbuf, &map);
-
  	kfree(buf);
  }

@@ -470,21 +465,25 @@ static struct dma_buf 
*isp4vid_vb2_get_dmabuf(struct vb2_buffer *vb,
  					      unsigned long flags)
  {
  	struct isp4vid_vb2_buf *buf = buf_priv;
-	struct dma_buf *dbuf;
+	struct dma_buf *dbuf = buf->dbuf;
+
+	if (dbuf) {
+		dev_dbg(buf->dev, "dbuf already created, reuse %s dbuf\n",
+			buf->is_expbuf ? "exported" : "implicit");
+		get_dma_buf(dbuf);

-	if (buf->dbuf) {
-		dev_dbg(buf->dev, "dbuf already created, reuse implicit dbuf\n");
-		dbuf = buf->dbuf;
  	} else {
  		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
+		if (!dbuf)
+			return NULL;
+
  		dev_dbg(buf->dev, "created new dbuf\n");
+		buf->is_expbuf = true;
+		refcount_inc(&buf->refcount);
  	}

-	buf->is_expbuf = true;
-	refcount_inc(&buf->refcount);
-
  	dev_dbg(buf->dev, "buf exported, refcount %d\n",
-		buf->refcount.refs.counter);
+		refcount_read(&buf->refcount));

  	return dbuf;
  }
@@ -579,8 +578,9 @@ static void isp4vid_vb2_put(void *buf_priv)
  {
  	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
  	unsigned int ref_cnt = refcount_read(&buf->refcount);
+	struct device *dev = buf->dev;

-	dev_dbg(buf->dev,
+	dev_dbg(dev,
  		"release isp user bo 0x%llx size %ld refcount %u is_expbuf %d\n",
  		buf->gpu_addr, buf->size,
  		ref_cnt, buf->is_expbuf);
@@ -598,7 +598,7 @@ static void isp4vid_vb2_put(void *buf_priv)
  		/* the ref_cnt - 1 is just a predicted value as reference, can't
  		 * guarantee it's the actual value now
  		 */
-		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
+		dev_warn(dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
  	}
  }

@@ -642,7 +642,7 @@ static void *isp4vid_vb2_alloc(struct vb2_buffer 
*vb, struct device *dev,
  	refcount_set(&buf->refcount, 1);

  	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d\n",
-		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
+		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));

  	return buf;
  err_free:
@@ -1140,30 +1140,6 @@ static void isp4vid_qops_buffer_queue(struct 
vb2_buffer *vb)
  	mutex_unlock(&isp_vdev->buf_list_lock);
  }

-static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
-{
-	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
-	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
-
-	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
-		isp_vdev->vdev.name, vb->index, vb->memory);
-
-	if (!buf) {
-		dev_err(isp_vdev->dev, "Invalid buf handle");
-		return;
-	}
-
-	// release implicit dmabuf reference here for vb2 buffer
-	// of type MMAP and is exported
-	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
-		dma_buf_put(buf->dbuf);
-		dev_dbg(isp_vdev->dev,
-			"put dmabuf for vb->memory %d expbuf %d",
-			vb->memory,
-			buf->is_expbuf);
-	}
-}
-
  static int isp4vid_qops_start_streaming(struct vb2_queue *vq,
  					unsigned int count)
  {
@@ -1343,7 +1319,6 @@ static int isp4vid_fill_buffer_size(struct 
isp4vid_dev *isp_vdev)

  static const struct vb2_ops isp4vid_qops = {
  	.queue_setup = isp4vid_qops_queue_setup,
-	.buf_cleanup = isp4vid_qops_buffer_cleanup,
  	.buf_queue = isp4vid_qops_buffer_queue,
  	.start_streaming = isp4vid_qops_start_streaming,
  	.stop_streaming = isp4vid_qops_stop_streaming,
-- 
2.34.1

Regards,
Bin



^ permalink raw reply related	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-29  7:42         ` Sultan Alsawaf
@ 2025-07-29  7:45           ` Sultan Alsawaf
  2025-07-29 10:13             ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-29  7:45 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > Thanks Sultan, please see my comments
> > 
> > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > 
> > > > > I cannot for the life of me get the webcam working under Linux. The webcam works
> > > > > under Windows so it's not a hardware issue.
> > > > > 
> > > > > With this patchset and all of the patches you link here applied to 6.15, I get
> > > > > the following errors:
> > > > >     [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
> > > > >     [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
> > > > > 
> > > > > With the old ispkernel code from February [1] applied on 6.15, the webcam
> > > > > indicator LED lights up but there's no image. I see these messages at boot:
> > > > >     [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
> > > > >     [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
> > > > >     [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > > >     [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > >     [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > > >     [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > > 
> > > > > And then the kernel crashes due to the same use-after-free issues I pointed out
> > > > > in my other email [2].
> > > > > 
> > > > > Any idea what's going on?
> > > > > 
> > > > > [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > Hi Sultan,
> > > > 
> > > > [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
> > > > on 6.15 but we are really glad to help, would you please provide some info,
> > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
> > > > 
> > > > After your confirmation, we'll see what we can do to enable your camera
> > > > quickly and easily
> > > > 
> > > > Regards,
> > > > Bin
> > > 
> > > Thank you, Bin!
> > > 
> > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > 2. Yes, here is my kernel source [2].
> > > 
> > > I have some more findings:
> > > 
> > > Currently, the first blocking issue is that the I2C adapter fails to initialize.
> > > This is because the ISP tile isn't powered on.
> > > 
> > > I noticed that in the old version of amd_isp_i2c_designware [3], there were
> > > calls to isp_power_set(), which is available in the old ISP4 sources [4].
> > > Without isp_power_set(), the I2C adapter always fails to initialize for me.
> > > 
> > > How is the ISP tile supposed to get powered on in the current ISP4 code?
> > > 
> > You are correct, yes, i believe the I2C adapter failure is caused by ISP not
> > being powered up. Currently in latest code, isp_power_set is no longer
> > available, instead, we implemented genPD for ISP in amdgpu
> > https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
> > Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
> > standard runtime PM API to do the power control
> 
> Thanks for that link, I found it along with another patch on the list to make
> the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").
> 
> > > Also, I noticed that the driver init ordering matters between all of the drivers
> > > needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
> > > must be initialized before amd_capture, otherwise amd_capture will fail to find
> > > the fwnode properties for the OV05C10 device attached to the I2C bus.
> > > 
> > > But there is no driver init ordering enforced, which also caused some issues for
> > > me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
> > > to ensure each driver waits for its dependencies to init first?
> > > 
> > amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
> > driver, it is init before amd_isp_catpure.
> > Do you see in your side the amd_capture probe failure caused by failing to
> > read fwnode properties? If that's the case please help to check if amd_isp4
> > is loaded successfully
> 
> I got much further now: there aren't any driver initialization errors, but when
> I open the camera, there's no image. The camera LED turns on so it's active.
> 
> And then shortly afterwards, amdgpu dies and the entire system freezes.
> 
> I've attached my full dmesg, please let me know what you think. Thanks!

I almost forgot, here is my current kernel tree:
https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-sultan-isp4

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-07-28  7:23   ` Sakari Ailus
@ 2025-07-29  9:12     ` Du, Bin
  2025-08-11 11:46       ` Sakari Ailus
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-29  9:12 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Askari Ailus for your careful review

On 7/28/2025 3:23 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>> called ccpu.
>> The communication between ISP FW and driver is using commands and
>> response messages sent through the ring buffer. Command buffers support
>> either global setting that is not specific to the steam and support stream
>> specific parameters. Response buffers contains ISP FW notification
>> information such as frame buffer done and command done. IRQ is used for
>> receiving response buffer from ISP firmware, which is handled in the main
>> isp4 media device. ISP ccpu is booted up through the firmware loading
>> helper function prior to stream start.
>> Memory used for command buffer and response buffer needs to be allocated
>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
> 
> Please rewrap this, some lines above are quite short.
>
Thanks, the line after the short line is supposed to be a new paragraph? 
Should we put all the description in one paragraph?

>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   drivers/media/platform/amd/isp4/Makefile      |   12 +
>>   .../platform/amd/isp4/isp4_fw_cmd_resp.h      |  318 +++++
>>   .../media/platform/amd/isp4/isp4_interface.c  | 1052 +++++++++++++++++
>>   .../media/platform/amd/isp4/isp4_interface.h  |  164 +++
>>   4 files changed, 1546 insertions(+)
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.c
>>   create mode 100644 drivers/media/platform/amd/isp4/isp4_interface.h
>>
>> diff --git a/drivers/media/platform/amd/isp4/Makefile b/drivers/media/platform/amd/isp4/Makefile
>> index 0e36201fbb30..c0166f954516 100644
>> --- a/drivers/media/platform/amd/isp4/Makefile
>> +++ b/drivers/media/platform/amd/isp4/Makefile
>> @@ -5,10 +5,22 @@
>>   obj-$(CONFIG_AMD_ISP4) += amd_capture.o
>>   amd_capture-objs := isp4.o	\
>>   			isp4_phy.o \
>> +			isp4_interface.o \
>>   			isp4_hw.o	\
>>   
>>   ccflags-y += -I$(srctree)/drivers/media/platform/amd/isp4
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/include
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/amdgpu
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/pm/inc
>> +ccflags-y += -I$(srctree)/include/drm
>>   ccflags-y += -I$(srctree)/include
>> +ccflags-y += -I$(srctree)/include/uapi/drm
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/acp/include
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/include
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/modules/inc
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/dc
>> +ccflags-y += -I$(srctree)/drivers/gpu/drm/amd/display/amdgpu_dm
>>   
>>   ifneq ($(call cc-option, -mpreferred-stack-boundary=4),)
>>   	cc_stack_align := -mpreferred-stack-boundary=4
>> diff --git a/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>> new file mode 100644
>> index 000000000000..437d89469af2
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_fw_cmd_resp.h
>> @@ -0,0 +1,318 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_CMD_RESP_H_
>> +#define _ISP4_CMD_RESP_H_
>> +
>> +/*
>> + * @brief Host and Firmware command & response channel.
>> + *        Two types of command/response channel.
>> + *          Type Global Command has one command/response channel.
>> + *          Type Stream Command has one command/response channel.
>> + *-----------                                        ------------
>> + *|         |       ---------------------------      |          |
>> + *|         |  ---->|  Global Command         |----> |          |
>> + *|         |       ---------------------------      |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |       ---------------------------      |          |
>> + *|         |  ---->|   Stream Command        |----> |          |
>> + *|         |       ---------------------------      |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|  HOST   |                                        | Firmware |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |       --------------------------       |          |
>> + *|         |  <----|  Global Response       |<----  |          |
>> + *|         |       --------------------------       |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *|         |       --------------------------       |          |
>> + *|         |  <----|  Stream Response       |<----  |          |
>> + *|         |       --------------------------       |          |
>> + *|         |                                        |          |
>> + *|         |                                        |          |
>> + *-----------                                        ------------
>> + */
>> +
>> +/*
>> + * @brief command ID format
>> + *        cmd_id is in the format of following type:
>> + *        type: indicate command type, global/stream commands.
>> + *        group: indicate the command group.
>> + *        id: A unique command identification in one type and group.
>> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
>> + *        |      type       |      group      |       id       |
>> + */
>> +
>> +#define CMD_TYPE_SHIFT (24)
>> +#define CMD_GROUP_SHIFT (16)
> 
> Redundant parentheses. Please remove all of them.
> 
Sure, will remove them in the next patch

>> +#define CMD_TYPE_STREAM_CTRL ((u32)0x2 << CMD_TYPE_SHIFT)
> 
> Maybe 0x2U << CMD_TYPE_SHIFT instead?
> 
Sure, will modify in the next patch

>> +
>> +#define CMD_GROUP_STREAM_CTRL ((u32)0x1 << CMD_GROUP_SHIFT)
>> +#define CMD_GROUP_STREAM_BUFFER ((u32)0x4 << CMD_GROUP_SHIFT)
>> +
>> +/* Stream  Command */
>> +#define CMD_ID_SET_STREAM_CONFIG                        \
>> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x1)
>> +#define CMD_ID_SET_OUT_CHAN_PROP                        \
>> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x3)
>> +#define CMD_ID_ENABLE_OUT_CHAN                          \
>> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x5)
>> +#define CMD_ID_START_STREAM                             \
>> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x7)
>> +#define CMD_ID_STOP_STREAM                              \
>> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_CTRL | 0x8)
>> +
>> +/* Stream Buffer Command */
>> +#define CMD_ID_SEND_BUFFER                                \
>> +	(CMD_TYPE_STREAM_CTRL | CMD_GROUP_STREAM_BUFFER | 0x1)
>> +
>> +/*
>> + * @brief response ID format
>> + *        resp_id is in the format of following type:
>> + *        type: indicate command type, global/stream commands.
>> + *        group: indicate the command group.
>> + *        id: A unique command identification in one type and group.
>> + *        |<-Bit31 ~ Bit24->|<-Bit23 ~ Bit16->|<-Bit15 ~ Bit0->|
>> + *        |      type       |      group      |       id       |
>> + */
>> +
>> +#define RESP_GROUP_SHIFT (16)
>> +#define RESP_GROUP_MASK  (0xff << RESP_GROUP_SHIFT)
>> +
>> +#define GET_RESP_GROUP_VALUE(resp_id)   \
>> +	(((resp_id) & RESP_GROUP_MASK) >> \
>> +	 RESP_GROUP_SHIFT)
>> +#define GET_RESP_ID_VALUE(resp_id) ((resp_id) & 0xffff)
>> +
>> +#define RESP_GROUP_GENERAL (0x1 << RESP_GROUP_SHIFT)
>> +#define RESP_GROUP_NOTIFICATION (0x3 << RESP_GROUP_SHIFT)
>> +
>> +/* General  Response */
>> +#define RESP_ID_CMD_DONE (RESP_GROUP_GENERAL | 0x1)
>> +
>> +/* Notification */
>> +#define RESP_ID_NOTI_FRAME_DONE (RESP_GROUP_NOTIFICATION | 0x1)
>> +
>> +#define CMD_STATUS_SUCCESS (0)
>> +#define CMD_STATUS_FAIL (1)
>> +#define CMD_STATUS_SKIPPED (2)
> 
> Again, please align macro bodies.
> 
Sure, will modify in the next patch

>> +
>> +#define ADDR_SPACE_TYPE_GPU_VA 4
>> +
>> +#define FW_MEMORY_POOL_SIZE (200 * 1024 * 1024)
>> +
>> +/*
>> + * standard ISP mipicsi=>isp
>> + */
>> +#define MIPI0_ISP_PIPELINE_ID 0x5f91
>> +
>> +enum isp4fw_sensor_id {
>> +	SENSOR_ID_ON_MIPI0  = 0,  /* Sensor id for ISP input from MIPI port 0 */
>> +};
>> +
>> +enum isp4fw_stream_id {
>> +	STREAM_ID_INVALID = -1, /* STREAM_ID_INVALID. */
>> +	STREAM_ID_1 = 0,        /* STREAM_ID_1. */
>> +	STREAM_ID_2 = 1,        /* STREAM_ID_2. */
>> +	STREAM_ID_3 = 2,        /* STREAM_ID_3. */
>> +	STREAM_ID_MAXIMUM       /* STREAM_ID_MAXIMUM. */
>> +};
>> +
>> +enum isp4fw_image_format {
>> +	IMAGE_FORMAT_NV12 = 1,              /* 4:2:0,semi-planar, 8-bit */
>> +	IMAGE_FORMAT_YUV422INTERLEAVED = 7, /* interleave, 4:2:2, 8-bit */
>> +};
>> +
>> +enum isp4fw_pipe_out_ch {
>> +	ISP_PIPE_OUT_CH_PREVIEW = 0,
>> +};
>> +
>> +enum isp4fw_yuv_range {
>> +	ISP_YUV_RANGE_FULL = 0,     /* YUV value range in 0~255 */
>> +	ISP_YUV_RANGE_NARROW = 1,   /* YUV value range in 16~235 */
>> +	ISP_YUV_RANGE_MAX
>> +};
>> +
>> +enum isp4fw_buffer_type {
>> +	BUFFER_TYPE_PREVIEW = 8,
>> +	BUFFER_TYPE_META_INFO = 10,
>> +	BUFFER_TYPE_MEM_POOL = 15,
>> +};
>> +
>> +enum isp4fw_buffer_status {
>> +	BUFFER_STATUS_INVALID,  /* The buffer is INVALID */
>> +	BUFFER_STATUS_SKIPPED,  /* The buffer is not filled with image data */
>> +	BUFFER_STATUS_EXIST,    /* The buffer is exist and waiting for filled */
>> +	BUFFER_STATUS_DONE,     /* The buffer is filled with image data */
>> +	BUFFER_STATUS_LACK,     /* The buffer is unavailable */
>> +	BUFFER_STATUS_DIRTY,    /* The buffer is dirty, probably caused by
>> +				 * LMI leakage
>> +				 */
>> +	BUFFER_STATUS_MAX       /* The buffer STATUS_MAX */
>> +};
>> +
>> +enum isp4fw_buffer_source {
>> +	/* The buffer is from the stream buffer queue */
>> +	BUFFER_SOURCE_STREAM,
>> +};
>> +
>> +struct isp4fw_error_code {
>> +	u32 code1;
>> +	u32 code2;
>> +	u32 code3;
>> +	u32 code4;
>> +	u32 code5;
>> +};
>> +
>> +/*
>> + * Command Structure for FW
>> + */
>> +
>> +struct isp4fw_cmd {
>> +	u32 cmd_seq_num;
>> +	u32 cmd_id;
>> +	u32 cmd_param[12];
>> +	u16 cmd_stream_id;
>> +	u8 cmd_silent_resp;
>> +	u8 reserved;
>> +	u32 cmd_check_sum;
>> +};
>> +
>> +struct isp4fw_resp_cmd_done {
>> +	/* The host2fw command seqNum.
>> +	 * To indicate which command this response refer to.
>> +	 */
>> +	u32 cmd_seq_num;
>> +	/* The host2fw command id for host double check. */
>> +	u32 cmd_id;
>> +	/* Indicate the command process status.
>> +	 * 0 means success. 1 means fail. 2 means skipped
>> +	 */
>> +	u16 cmd_status;
>> +	/* If the cmd_status is 1, that means the command is processed fail, */
>> +	/* host can check the isp4fw_error_code to get the detail
>> +	 * error information
>> +	 */
>> +	u16 isp4fw_error_code;
>> +	/* The response payload will be in different struct type */
>> +	/* according to different cmd done response. */
>> +	u8 payload[36];
>> +};
>> +
>> +struct isp4fw_resp_param_package {
>> +	u32 package_addr_lo;	/* The low 32 bit addr of the pkg address. */
>> +	u32 package_addr_hi;	/* The high 32 bit addr of the pkg address. */
>> +	u32 package_size;	/* The total pkg size in bytes. */
>> +	u32 package_check_sum;	/* The byte sum of the pkg. */
>> +};
>> +
>> +struct isp4fw_resp {
>> +	u32 resp_seq_num;
>> +	u32 resp_id;
>> +	union {
>> +		struct isp4fw_resp_cmd_done cmd_done;
>> +		struct isp4fw_resp_param_package frame_done;
>> +		u32 resp_param[12];
>> +	} param;
>> +	u8  reserved[4];
>> +	u32 resp_check_sum;
>> +};
>> +
>> +struct isp4fw_mipi_pipe_path_cfg {
>> +	u32 b_enable;
>> +	enum isp4fw_sensor_id isp4fw_sensor_id;
>> +};
>> +
>> +struct isp4fw_isp_pipe_path_cfg {
>> +	u32  isp_pipe_id;	/* pipe ids for pipeline construction */
>> +};
>> +
>> +struct isp4fw_isp_stream_cfg {
>> +	/* Isp mipi path */
>> +	struct isp4fw_mipi_pipe_path_cfg mipi_pipe_path_cfg;
>> +	/* Isp pipe path */
>> +	struct isp4fw_isp_pipe_path_cfg  isp_pipe_path_cfg;
>> +	/* enable TNR */
>> +	u32 b_enable_tnr;
>> +	/* number of frame rta per-processing,
>> +	 * set to 0 to use fw default value
>> +	 */
>> +	u32 rta_frames_per_proc;
>> +};
>> +
>> +struct isp4fw_image_prop {
>> +	enum isp4fw_image_format image_format;	/* Image format */
>> +	u32 width;				/* Width */
>> +	u32 height;				/* Height */
>> +	u32 luma_pitch;				/* Luma pitch */
>> +	u32 chroma_pitch;			/* Chrom pitch */
>> +	enum isp4fw_yuv_range yuv_range;		/* YUV value range */
>> +};
>> +
>> +struct isp4fw_buffer {
>> +	/* A check num for debug usage, host need to */
>> +	/* set the buf_tags to different number */
>> +	u32 buf_tags;
>> +	union {
>> +		u32 value;
>> +		struct {
>> +			u32 space : 16;
>> +			u32 vmid  : 16;
>> +		} bit;
>> +	} vmid_space;
>> +	u32 buf_base_a_lo;		/* Low address of buffer A */
>> +	u32 buf_base_a_hi;		/* High address of buffer A */
>> +	u32 buf_size_a;			/* Buffer size of buffer A */
>> +
>> +	u32 buf_base_b_lo;		/* Low address of buffer B */
>> +	u32 buf_base_b_hi;		/* High address of buffer B */
>> +	u32 buf_size_b;			/* Buffer size of buffer B */
>> +
>> +	u32 buf_base_c_lo;		/* Low address of buffer C */
>> +	u32 buf_base_c_hi;		/* High address of buffer C */
>> +	u32 buf_size_c;			/* Buffer size of buffer C */
>> +};
>> +
>> +struct isp4fw_buffer_meta_info {
>> +	u32 enabled;					/* enabled flag */
>> +	enum isp4fw_buffer_status status;		/* BufferStatus */
>> +	struct isp4fw_error_code err;			/* err code */
>> +	enum isp4fw_buffer_source source;		/* BufferSource */
>> +	struct isp4fw_image_prop image_prop;		/* image_prop */
>> +	struct isp4fw_buffer buffer;			/* buffer */
>> +};
>> +
>> +struct isp4fw_meta_info {
>> +	u32 poc;				/* frame id */
>> +	u32 fc_id;				/* frame ctl id */
>> +	u32 time_stamp_lo;			/* time_stamp_lo */
>> +	u32 time_stamp_hi;			/* time_stamp_hi */
>> +	struct isp4fw_buffer_meta_info preview;	/* preview BufferMetaInfo */
>> +};
>> +
>> +struct isp4fw_cmd_send_buffer {
>> +	enum isp4fw_buffer_type buffer_type;	/* buffer Type */
>> +	struct isp4fw_buffer buffer;		/* buffer info */
>> +};
>> +
>> +struct isp4fw_cmd_set_out_ch_prop {
>> +	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
>> +	struct isp4fw_image_prop image_prop;	/* image property */
>> +};
>> +
>> +struct isp4fw_cmd_enable_out_ch {
>> +	enum isp4fw_pipe_out_ch ch;	/* ISP pipe out channel */
>> +	u32 is_enable;			/* If enable channel or not */
>> +};
>> +
>> +struct isp4fw_cmd_set_stream_cfg {
>> +	struct isp4fw_isp_stream_cfg stream_cfg; /* stream path config */
>> +};
>> +
>> +#endif
>> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c
>> new file mode 100644
>> index 000000000000..0e1eb22a0de5
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_interface.c
>> @@ -0,0 +1,1052 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/mutex.h>
>> +
>> +#include "amdgpu_object.h"
>> +
>> +#include "isp4_fw_cmd_resp.h"
>> +#include "isp4_hw.h"
>> +#include "isp4_hw_reg.h"
>> +#include "isp4_interface.h"
>> +
>> +#define ISP4IF_FW_RESP_RB_IRQ_EN_MASK \
>> +	(ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK |  \
>> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT10_EN_MASK | \
>> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT11_EN_MASK | \
>> +	 ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK)
>> +
>> +struct isp4if_rb_config {
>> +	const char *name;
>> +	u32 index;
>> +	u32 reg_rptr;
>> +	u32 reg_wptr;
>> +	u32 reg_base_lo;
>> +	u32 reg_base_hi;
>> +	u32 reg_size;
>> +	u32 val_size;
>> +	u64 base_mc_addr;
>> +	void *base_sys_addr;
>> +};
>> +
>> +/* FW cmd ring buffer configuration */
>> +static struct isp4if_rb_config
>> +	isp4if_cmd_rb_config[ISP4IF_STREAM_ID_MAX] = {
>> +	{
>> +		.name = "CMD_RB_GBL0",
>> +		.index = 3,
>> +		.reg_rptr = ISP_RB_RPTR4,
>> +		.reg_wptr = ISP_RB_WPTR4,
>> +		.reg_base_lo = ISP_RB_BASE_LO4,
>> +		.reg_base_hi = ISP_RB_BASE_HI4,
>> +		.reg_size = ISP_RB_SIZE4,
>> +	},
>> +	{
>> +		.name = "CMD_RB_STR1",
>> +		.index = 0,
>> +		.reg_rptr = ISP_RB_RPTR1,
>> +		.reg_wptr = ISP_RB_WPTR1,
>> +		.reg_base_lo = ISP_RB_BASE_LO1,
>> +		.reg_base_hi = ISP_RB_BASE_HI1,
>> +		.reg_size = ISP_RB_SIZE1,
>> +	},
>> +	{
>> +		.name = "CMD_RB_STR2",
>> +		.index = 1,
>> +		.reg_rptr = ISP_RB_RPTR2,
>> +		.reg_wptr = ISP_RB_WPTR2,
>> +		.reg_base_lo = ISP_RB_BASE_LO2,
>> +		.reg_base_hi = ISP_RB_BASE_HI2,
>> +		.reg_size = ISP_RB_SIZE2,
>> +	},
>> +	{
>> +		.name = "CMD_RB_STR3",
>> +		.index = 2,
>> +		.reg_rptr = ISP_RB_RPTR3,
>> +		.reg_wptr = ISP_RB_WPTR3,
>> +		.reg_base_lo = ISP_RB_BASE_LO3,
>> +		.reg_base_hi = ISP_RB_BASE_HI3,
>> +		.reg_size = ISP_RB_SIZE3,
>> +	},
>> +};
>> +
>> +/* FW resp ring buffer configuration */
>> +static struct isp4if_rb_config
>> +	isp4if_resp_rb_config[ISP4IF_STREAM_ID_MAX] = {
>> +	{
>> +		.name = "RES_RB_GBL0",
>> +		.index = 3,
>> +		.reg_rptr = ISP_RB_RPTR12,
>> +		.reg_wptr = ISP_RB_WPTR12,
>> +		.reg_base_lo = ISP_RB_BASE_LO12,
>> +		.reg_base_hi = ISP_RB_BASE_HI12,
>> +		.reg_size = ISP_RB_SIZE12,
>> +	},
>> +	{
>> +		.name = "RES_RB_STR1",
>> +		.index = 0,
>> +		.reg_rptr = ISP_RB_RPTR9,
>> +		.reg_wptr = ISP_RB_WPTR9,
>> +		.reg_base_lo = ISP_RB_BASE_LO9,
>> +		.reg_base_hi = ISP_RB_BASE_HI9,
>> +		.reg_size = ISP_RB_SIZE9,
>> +	},
>> +	{
>> +		.name = "RES_RB_STR2",
>> +		.index = 1,
>> +		.reg_rptr = ISP_RB_RPTR10,
>> +		.reg_wptr = ISP_RB_WPTR10,
>> +		.reg_base_lo = ISP_RB_BASE_LO10,
>> +		.reg_base_hi = ISP_RB_BASE_HI10,
>> +		.reg_size = ISP_RB_SIZE10,
>> +	},
>> +	{
>> +		.name = "RES_RB_STR3",
>> +		.index = 2,
>> +		.reg_rptr = ISP_RB_RPTR11,
>> +		.reg_wptr = ISP_RB_WPTR11,
>> +		.reg_base_lo = ISP_RB_BASE_LO11,
>> +		.reg_base_hi = ISP_RB_BASE_HI11,
>> +		.reg_size = ISP_RB_SIZE11,
>> +	},
>> +};
>> +
>> +/* FW log ring buffer configuration */
>> +static struct isp4if_rb_config isp4if_log_rb_config = {
>> +	.name = "LOG_RB",
>> +	.index = 0,
>> +	.reg_rptr = ISP_LOG_RB_RPTR0,
>> +	.reg_wptr = ISP_LOG_RB_WPTR0,
>> +	.reg_base_lo = ISP_LOG_RB_BASE_LO0,
>> +	.reg_base_hi = ISP_LOG_RB_BASE_HI0,
>> +	.reg_size = ISP_LOG_RB_SIZE0,
>> +};
>> +
>> +static struct isp4if_gpu_mem_info *isp4if_gpu_mem_alloc(struct isp4_interface
>> +							*ispif,
>> +							u32 mem_size)
>> +{
>> +	struct isp4if_gpu_mem_info *mem_info;
>> +	struct amdgpu_bo *bo = NULL;
>> +	struct amdgpu_device *adev;
>> +	struct device *dev;
>> +
> 
> Extra newline.
> 
Sure, will remove in the next patch

>> +	void *cpu_ptr;
>> +	u64 gpu_addr;
>> +	u32 ret;
>> +
>> +	dev = ispif->dev;
>> +
>> +	if (!mem_size)
>> +		return NULL;
>> +
>> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
>> +	if (!mem_info)
>> +		return NULL;
>> +
>> +	adev = (struct amdgpu_device *)ispif->adev;
> 
> Why the cast?
> 
> adev isn't a great name here as it's usually used for struct acpi_devices.
> 
In the next patch, will use new helper function for this and will no 
longer use amdgpu_device

>> +	mem_info->mem_size = mem_size;
>> +	mem_info->mem_align = ISP4IF_ISP_MC_ADDR_ALIGN;
>> +	mem_info->mem_domain = AMDGPU_GEM_DOMAIN_GTT;
>> +
>> +	ret = amdgpu_bo_create_kernel(adev,
>> +				      mem_info->mem_size,
>> +				      mem_info->mem_align,
>> +				      mem_info->mem_domain,
>> +				      &bo,
>> +				      &gpu_addr,
>> +				      &cpu_ptr);
> 
> This fits on fewer lines.
> 
>> +
> 
Sure, will modify in the next patch

> Extra newline.
> 
Sure, will modify in the next patch

>> +	if (!cpu_ptr || ret) {
>> +		dev_err(dev, "gpuvm buffer alloc fail, size %u\n", mem_size);
>> +		kfree(mem_info);
>> +		return NULL;
>> +	}
>> +
>> +	mem_info->sys_addr = cpu_ptr;
>> +	mem_info->gpu_mc_addr = gpu_addr;
>> +	mem_info->mem_handle = (void *)bo;
>> +
>> +	return mem_info;
>> +}
>> +
>> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
>> +			       struct isp4if_gpu_mem_info *mem_info)
>> +{
>> +	struct device *dev = ispif->dev;
>> +	struct amdgpu_bo *bo;
>> +
>> +	if (!mem_info) {
>> +		dev_err(dev, "invalid mem_info\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
> 
> Why do you need to cast here?
> 
In the next patch, will use new helper function for this and will no 
longer use amdgpu_bo

>> +
>> +	amdgpu_bo_free_kernel(&bo, &mem_info->gpu_mc_addr, &mem_info->sys_addr);
>> +
>> +	kfree(mem_info);
>> +
>> +	return 0;
>> +}
>> +
>> +static int isp4if_dealloc_fw_gpumem(struct isp4_interface *ispif)
>> +{
>> +	int i;
>> +
>> +	if (ispif->fw_mem_pool) {
>> +		isp4if_gpu_mem_free(ispif, ispif->fw_mem_pool);
>> +		ispif->fw_mem_pool = NULL;
>> +	}
>> +
>> +	if (ispif->fw_cmd_resp_buf) {
>> +		isp4if_gpu_mem_free(ispif, ispif->fw_cmd_resp_buf);
>> +		ispif->fw_cmd_resp_buf = NULL;
>> +	}
>> +
>> +	if (ispif->fw_log_buf) {
>> +		isp4if_gpu_mem_free(ispif, ispif->fw_log_buf);
>> +		ispif->fw_log_buf = NULL;
>> +	}
>> +
>> +	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
>> +		if (ispif->metainfo_buf_pool[i]) {
>> +			isp4if_gpu_mem_free(ispif, ispif->metainfo_buf_pool[i]);
>> +			ispif->metainfo_buf_pool[i] = NULL;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif)
>> +{
>> +	struct device *dev = ispif->dev;
>> +	int i;
> 
> Unsigned int, please.
> 
Sure, will modify in the next patch

>> +
>> +	ispif->fw_mem_pool = isp4if_gpu_mem_alloc(ispif, FW_MEMORY_POOL_SIZE);
>> +	if (!ispif->fw_mem_pool)
>> +		goto error_no_memory;
>> +
>> +	ispif->fw_cmd_resp_buf =
>> +		isp4if_gpu_mem_alloc(ispif, ISP4IF_RB_PMBMAP_MEM_SIZE);
>> +	if (!ispif->fw_cmd_resp_buf)
>> +		goto error_no_memory;
>> +
>> +	ispif->fw_log_buf =
>> +		isp4if_gpu_mem_alloc(ispif, ISP4IF_FW_LOG_RINGBUF_SIZE);
>> +	if (!ispif->fw_log_buf)
>> +		goto error_no_memory;
>> +
>> +	for (i = 0; i < ISP4IF_MAX_STREAM_META_BUF_COUNT; i++) {
>> +		ispif->metainfo_buf_pool[i] =
>> +			isp4if_gpu_mem_alloc(ispif,
>> +					     ISP4IF_META_INFO_BUF_SIZE);
>> +		if (!ispif->metainfo_buf_pool[i])
>> +			goto error_no_memory;
>> +	}
>> +
>> +	return 0;
>> +
>> +error_no_memory:
>> +	dev_err(dev, "failed to allocate gpu memory");
>> +	return -ENOMEM;
>> +}
>> +
>> +static u32 isp4if_compute_check_sum(u8 *buf, u32 buf_size)
>> +{
>> +	u32 checksum = 0;
>> +	u8 *surplus_ptr;
>> +	u32 *buffer;
>> +	u32 i;
>> +
>> +	buffer = (u32 *)buf;
>> +	for (i = 0; i < buf_size / sizeof(u32); i++)
>> +		checksum += buffer[i];
>> +
>> +	surplus_ptr = (u8 *)&buffer[i];
>> +	/* add surplus data crc checksum */
>> +	for (i = 0; i < buf_size % sizeof(u32); i++)
>> +		checksum += surplus_ptr[i];
>> +
>> +	return checksum;
>> +}
>> +
>> +void isp4if_clear_cmdq(struct isp4_interface *ispif)
>> +{
>> +	struct isp4if_cmd_element *buf_node = NULL;
>> +	struct isp4if_cmd_element *tmp_node = NULL;
>> +
>> +	guard(mutex)(&ispif->cmdq_mutex);
>> +
>> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
>> +		list_del(&buf_node->list);
>> +		kfree(buf_node);
>> +	}
>> +}
>> +
>> +static bool isp4if_is_cmdq_rb_full(struct isp4_interface *ispif,
>> +				   enum isp4if_stream_id cmd_buf_idx)
>> +{
>> +	struct isp4if_rb_config *rb_config;
>> +	u32 rd_ptr, wr_ptr;
>> +	u32 new_wr_ptr;
>> +	u32 rreg;
>> +	u32 wreg;
>> +	u32 len;
>> +
>> +	rb_config = &isp4if_cmd_rb_config[cmd_buf_idx];
>> +	rreg = rb_config->reg_rptr;
>> +	wreg = rb_config->reg_wptr;
>> +	len = rb_config->val_size;
>> +
>> +	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
>> +	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
>> +
>> +	new_wr_ptr = wr_ptr + sizeof(struct isp4fw_cmd);
>> +
>> +	if (wr_ptr >= rd_ptr) {
>> +		if (new_wr_ptr < len) {
>> +			return false;
>> +		} else if (new_wr_ptr == len) {
>> +			if (rd_ptr == 0)
>> +				return true;
>> +
>> +			return false;
>> +		}
>> +
>> +		new_wr_ptr -= len;
>> +		if (new_wr_ptr < rd_ptr)
>> +			return false;
>> +
>> +		return true;
>> +	}
>> +
>> +	if (new_wr_ptr < rd_ptr)
>> +		return false;
>> +
>> +	return true;
>> +}
>> +
>> +static struct isp4if_cmd_element *
>> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
>> +			 struct isp4if_cmd_element *cmd_ele)
>> +{
>> +	struct isp4if_cmd_element *copy_command = NULL;
>> +
>> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
>> +	if (!copy_command)
>> +		return NULL;
>> +
>> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
> 
> kmemdup()?
> 
Kmemdup is to allocate memory and copy, can't be used here.

>> +
>> +	guard(mutex)(&ispif->cmdq_mutex);
>> +
>> +	list_add_tail(&copy_command->list, &ispif->cmdq);
>> +
>> +	return copy_command;
>> +}
>> +
>> +struct isp4if_cmd_element *
>> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
>> +			u32 seq_num,
>> +			u32 cmd_id)
>> +{
>> +	struct isp4if_cmd_element *buf_node = NULL;
>> +	struct isp4if_cmd_element *tmp_node = NULL;
>> +
>> +	guard(mutex)(&ispif->cmdq_mutex);
>> +
>> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->cmdq, list) {
>> +		if (buf_node->seq_num == seq_num &&
>> +		    buf_node->cmd_id == cmd_id) {
>> +			list_del(&buf_node->list);
>> +			return buf_node;
>> +		}
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static int isp4if_insert_isp_fw_cmd(struct isp4_interface *ispif,
>> +				    enum isp4if_stream_id stream,
>> +				    struct isp4fw_cmd *cmd)
>> +{
>> +	struct isp4if_rb_config *rb_config;
>> +	struct device *dev = ispif->dev;
>> +	u64 mem_addr;
>> +	u64 mem_sys;
>> +	u32 wr_ptr;
>> +	u32 rd_ptr;
>> +	u32 rreg;
>> +	u32 wreg;
>> +	u32 len;
>> +
>> +	rb_config = &isp4if_cmd_rb_config[stream];
>> +	rreg = rb_config->reg_rptr;
>> +	wreg = rb_config->reg_wptr;
>> +	mem_sys = (u64)rb_config->base_sys_addr;
>> +	mem_addr = rb_config->base_mc_addr;
>> +	len = rb_config->val_size;
>> +
>> +	if (isp4if_is_cmdq_rb_full(ispif, stream)) {
>> +		dev_err(dev, "fail no cmdslot (%d)\n", stream);
>> +		return -EINVAL;
>> +	}
>> +
>> +	wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
>> +	rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
>> +
>> +	if (rd_ptr > len) {
>> +		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
>> +			stream, rd_ptr, len, wr_ptr);
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (wr_ptr > len) {
>> +		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
>> +			stream, wr_ptr, len, rd_ptr);
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (wr_ptr < rd_ptr) {
>> +		mem_addr += wr_ptr;
>> +
>> +		memcpy((u8 *)(mem_sys + wr_ptr),
>> +		       (u8 *)cmd, sizeof(struct isp4fw_cmd));
>> +	} else {
>> +		if ((len - wr_ptr) >= (sizeof(struct isp4fw_cmd))) {
>> +			mem_addr += wr_ptr;
>> +
>> +			memcpy((u8 *)(mem_sys + wr_ptr),
>> +			       (u8 *)cmd, sizeof(struct isp4fw_cmd));
>> +		} else {
>> +			u32 size;
>> +			u8 *src;
>> +
>> +			src = (u8 *)cmd;
>> +			size = len - wr_ptr;
>> +
>> +			memcpy((u8 *)(mem_sys + wr_ptr), src, size);
>> +
>> +			src += size;
>> +			size = sizeof(struct isp4fw_cmd) - size;
>> +			memcpy((u8 *)(mem_sys), src, size);
>> +		}
>> +	}
>> +
>> +	wr_ptr += sizeof(struct isp4fw_cmd);
>> +	if (wr_ptr >= len)
>> +		wr_ptr -= len;
>> +
>> +	isp4hw_wreg(ispif->mmio, wreg, wr_ptr);
>> +
>> +	return 0;
>> +}
>> +
>> +static inline enum isp4if_stream_id isp4if_get_fw_stream(u32 cmd_id)
>> +{
>> +	return ISP4IF_STREAM_ID_1;
>> +}
>> +
>> +static int isp4if_send_fw_cmd(struct isp4_interface *ispif,
>> +			      u32 cmd_id,
>> +			      void *package,
>> +			      u32 package_size,
>> +			      wait_queue_head_t *wq,
>> +			      u32 *wq_cond,
>> +			      u32 *seq)
>> +{
>> +	enum isp4if_stream_id stream = isp4if_get_fw_stream(cmd_id);
>> +	struct isp4if_cmd_element command_element = { 0 };
>> +	struct isp4if_gpu_mem_info *gpu_mem = NULL;
>> +	struct isp4if_cmd_element *cmd_ele = NULL;
>> +	struct isp4if_rb_config *rb_config;
>> +	struct device *dev = ispif->dev;
>> +	struct isp4fw_cmd cmd = {0};
>> +	u64 package_base = 0;
>> +	u32 sleep_count;
>> +	u32 seq_num;
>> +	u32 rreg;
>> +	u32 wreg;
>> +	int ret;
>> +
>> +	if (package_size > sizeof(cmd.cmd_param)) {
>> +		dev_err(dev, "fail pkgsize(%u)>%lu cmd:0x%x,stream %d\n",
>> +			package_size, sizeof(cmd.cmd_param), cmd_id, stream);
>> +		return -EINVAL;
>> +	}
>> +
>> +	sleep_count = 0;
>> +
>> +	rb_config = &isp4if_resp_rb_config[stream];
>> +	rreg = rb_config->reg_rptr;
>> +	wreg = rb_config->reg_wptr;
>> +
>> +	guard(mutex)(&ispif->isp4if_mutex);
>> +
>> +	while (1) {
>> +		if (isp4if_is_cmdq_rb_full(ispif, stream)) {
>> +			u32 rd_ptr, wr_ptr;
>> +
>> +			if (sleep_count < ISP4IF_MAX_SLEEP_COUNT) {
>> +				msleep(ISP4IF_MAX_SLEEP_TIME);
>> +				sleep_count++;
>> +				continue;
>> +			}
>> +			rd_ptr = isp4hw_rreg(ispif->mmio, rreg);
>> +			wr_ptr = isp4hw_rreg(ispif->mmio, wreg);
>> +			dev_err(dev, "fail to get cmdq slot,stream (%d), rd %u, wr %u\n",
>> +				stream, rd_ptr, wr_ptr);
>> +			return -ETIMEDOUT;
>> +		}
>> +		break;
>> +	}
> 
> read_poll_timeout()?
> 
Sure, will modify in the next patch

>> +
>> +	cmd.cmd_id = cmd_id;
>> +	switch (stream) {
>> +	case ISP4IF_STREAM_ID_GLOBAL:
>> +		cmd.cmd_stream_id = (u16)STREAM_ID_INVALID;
> 
> Is there a need to cast here?
> 
Sure, will remove it in the next patch

>> +		break;
>> +	case ISP4IF_STREAM_ID_1:
>> +		cmd.cmd_stream_id = STREAM_ID_1;
>> +		break;
>> +	default:
>> +		dev_err(dev, "fail bad stream id %d\n", stream);
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (package && package_size)
>> +		memcpy(cmd.cmd_param, package, package_size);
>> +
>> +	seq_num = ispif->host2fw_seq_num++;
>> +	cmd.cmd_seq_num = seq_num;
>> +	cmd.cmd_check_sum =
>> +		isp4if_compute_check_sum((u8 *)&cmd, sizeof(cmd) - 4);
>> +
>> +	if (seq)
>> +		*seq = seq_num;
>> +	command_element.seq_num = seq_num;
>> +	command_element.cmd_id = cmd_id;
>> +	command_element.mc_addr = package_base;
>> +	command_element.wq = wq;
>> +	command_element.wq_cond = wq_cond;
>> +	command_element.gpu_pkg = gpu_mem;
>> +	command_element.stream = stream;
>> +	/* only append the fw cmd to queue when its response needs to be
>> +	 * waited for, currently there are only two such commands,
>> +	 * disable channel and stop stream which are only sent after close
>> +	 * camera
>> +	 */
>> +	if (wq && wq_cond) {
>> +		cmd_ele = isp4if_append_cmd_2_cmdq(ispif, &command_element);
>> +		if (!cmd_ele) {
>> +			dev_err(dev, "fail for isp_append_cmd_2_cmdq\n");
>> +			return -ENOMEM;
>> +		}
>> +	}
>> +
>> +	ret = isp4if_insert_isp_fw_cmd(ispif, stream, &cmd);
>> +	if (ret) {
>> +		dev_err(dev, "fail for insert_isp_fw_cmd camId (0x%08x)\n",
>> +			cmd_id);
>> +		if (cmd_ele) {
>> +			isp4if_rm_cmd_from_cmdq(ispif, cmd_ele->seq_num,
>> +						cmd_ele->cmd_id);
>> +			kfree(cmd_ele);
>> +		}
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int isp4if_send_buffer(struct isp4_interface *ispif,
>> +			      struct isp4if_img_buf_info *buf_info)
>> +{
>> +	struct isp4fw_cmd_send_buffer cmd;
> 
> = { };
> 
> And you can remove the memset.
> 
Sure, will modify in the next patch

>> +
>> +	memset(&cmd, 0, sizeof(cmd));
>> +	cmd.buffer_type = BUFFER_TYPE_PREVIEW;
>> +	cmd.buffer.vmid_space.bit.vmid = 0;
>> +	cmd.buffer.vmid_space.bit.space = ADDR_SPACE_TYPE_GPU_VA;
>> +	isp4if_split_addr64(buf_info->planes[0].mc_addr,
>> +			    &cmd.buffer.buf_base_a_lo,
>> +			    &cmd.buffer.buf_base_a_hi);
>> +	cmd.buffer.buf_size_a = buf_info->planes[0].len;
>> +
>> +	isp4if_split_addr64(buf_info->planes[1].mc_addr,
>> +			    &cmd.buffer.buf_base_b_lo,
>> +			    &cmd.buffer.buf_base_b_hi);
>> +	cmd.buffer.buf_size_b = buf_info->planes[1].len;
>> +
>> +	isp4if_split_addr64(buf_info->planes[2].mc_addr,
>> +			    &cmd.buffer.buf_base_c_lo,
>> +			    &cmd.buffer.buf_base_c_hi);
>> +	cmd.buffer.buf_size_c = buf_info->planes[2].len;
>> +
>> +	return isp4if_send_fw_cmd(ispif, CMD_ID_SEND_BUFFER, &cmd,
>> +				  sizeof(cmd), NULL, NULL, NULL);
>> +}
>> +
>> +static void isp4if_init_rb_config(struct isp4_interface *ispif,
>> +				  struct isp4if_rb_config *rb_config)
>> +{
>> +	u32 lo;
>> +	u32 hi;
>> +
>> +	isp4if_split_addr64(rb_config->base_mc_addr, &lo, &hi);
>> +
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +		    rb_config->reg_rptr, 0x0);
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +		    rb_config->reg_wptr, 0x0);
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +		    rb_config->reg_base_lo, lo);
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +		    rb_config->reg_base_hi, hi);
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +		    rb_config->reg_size, rb_config->val_size);
>> +}
>> +
>> +static int isp4if_fw_init(struct isp4_interface *ispif)
>> +{
>> +	struct isp4if_rb_config *rb_config;
>> +	u32 offset;
>> +	int i;
>> +
>> +	/* initialize CMD_RB streams */
>> +	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
>> +		rb_config = (isp4if_cmd_rb_config + i);
>> +		offset = ispif->aligned_rb_chunk_size *
>> +			 (rb_config->index + ispif->cmd_rb_base_index);
>> +
>> +		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
>> +		rb_config->base_sys_addr =
>> +			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
>> +		rb_config->base_mc_addr =
>> +			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
>> +
>> +		isp4if_init_rb_config(ispif, rb_config);
>> +	}
>> +
>> +	/* initialize RESP_RB streams */
>> +	for (i = 0; i < ISP4IF_STREAM_ID_MAX; i++) {
>> +		rb_config = (isp4if_resp_rb_config + i);
>> +		offset = ispif->aligned_rb_chunk_size *
>> +			 (rb_config->index + ispif->resp_rb_base_index);
>> +
>> +		rb_config->val_size = ISP4IF_FW_CMD_BUF_SIZE;
>> +		rb_config->base_sys_addr =
>> +			(u8 *)ispif->fw_cmd_resp_buf->sys_addr + offset;
>> +		rb_config->base_mc_addr =
>> +			ispif->fw_cmd_resp_buf->gpu_mc_addr + offset;
>> +
>> +		isp4if_init_rb_config(ispif, rb_config);
>> +	}
>> +
>> +	/* initialize LOG_RB stream */
>> +	rb_config = &isp4if_log_rb_config;
>> +	rb_config->val_size = ISP4IF_FW_LOG_RINGBUF_SIZE;
>> +	rb_config->base_mc_addr = ispif->fw_log_buf->gpu_mc_addr;
>> +	rb_config->base_sys_addr = ispif->fw_log_buf->sys_addr;
>> +
>> +	isp4if_init_rb_config(ispif, rb_config);
>> +
>> +	return 0;
>> +}
>> +
>> +static int isp4if_wait_fw_ready(struct isp4_interface *ispif,
>> +				u32 isp_status_addr)
>> +{
>> +	struct device *dev = ispif->dev;
>> +	u32 fw_ready_timeout;
>> +	u32 timeout_ms = 100;
>> +	u32 interval_ms = 1;
>> +	u32 timeout = 0;
>> +	u32 reg_val;
>> +
>> +	fw_ready_timeout = timeout_ms / interval_ms;
>> +
>> +	/* wait for FW initialize done! */
>> +	while (timeout < fw_ready_timeout) {
>> +		reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif),
>> +				      isp_status_addr);
>> +		if (reg_val & ISP_STATUS__CCPU_REPORT_MASK)
>> +			return 0;
>> +
>> +		msleep(interval_ms);
>> +		timeout++;
>> +	}
> 
> read_poll_timeout()?
> 
Sure, will modify in the next patch

>> +
>> +	dev_err(dev, "ISP CCPU FW boot failed\n");
>> +
>> +	return -ETIME;
>> +}
>> +
>> +static void isp4if_enable_ccpu(struct isp4_interface *ispif)
>> +{
>> +	u32 reg_val;
>> +
>> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
>> +	reg_val &= (~ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK);
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
>> +
>> +	usleep_range(100, 150);
>> +
>> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
>> +	reg_val &= (~ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK);
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
>> +}
>> +
>> +static void isp4if_disable_ccpu(struct isp4_interface *ispif)
>> +{
>> +	u32 reg_val;
>> +
>> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL);
>> +	reg_val |= ISP_CCPU_CNTL__CCPU_HOST_SOFT_RST_MASK;
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_CCPU_CNTL, reg_val);
>> +
>> +	usleep_range(100, 150);
>> +
>> +	reg_val = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET);
>> +	reg_val |= ISP_SOFT_RESET__CCPU_SOFT_RESET_MASK;
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SOFT_RESET, reg_val);
>> +}
>> +
>> +static int isp4if_fw_boot(struct isp4_interface *ispif)
>> +{
>> +	struct device *dev = ispif->dev;
>> +
>> +	if (ispif->status != ISP4IF_STATUS_PWR_ON) {
>> +		dev_err(dev, "invalid isp power status %d\n", ispif->status);
>> +		return -EINVAL;
>> +	}
>> +
>> +	isp4if_disable_ccpu(ispif);
>> +
>> +	isp4if_fw_init(ispif);
>> +
>> +	/* clear ccpu status */
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_STATUS, 0x0);
>> +
>> +	isp4if_enable_ccpu(ispif);
>> +
>> +	if (isp4if_wait_fw_ready(ispif, ISP_STATUS)) {
>> +		isp4if_disable_ccpu(ispif);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* enable interrupts */
>> +	isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif), ISP_SYS_INT0_EN,
>> +		    ISP4IF_FW_RESP_RB_IRQ_EN_MASK);
>> +
>> +	ispif->status = ISP4IF_STATUS_FW_RUNNING;
>> +
>> +	dev_dbg(dev, "ISP CCPU FW boot success\n");
>> +
>> +	return 0;
>> +}
>> +
>> +int isp4if_f2h_resp(struct isp4_interface *ispif,
>> +		    enum isp4if_stream_id stream,
>> +		    void *resp)
>> +{
>> +	struct isp4fw_resp *response = resp;
>> +	struct isp4if_rb_config *rb_config;
>> +	struct device *dev = ispif->dev;
>> +	u32 rd_ptr_dbg;
>> +	u32 wr_ptr_dbg;
>> +	void *mem_sys;
>> +	u64 mem_addr;
>> +	u32 checksum;
>> +	u32 rd_ptr;
>> +	u32 wr_ptr;
>> +	u32 rreg;
>> +	u32 wreg;
>> +	u32 len;
>> +
>> +	rb_config = &isp4if_resp_rb_config[stream];
>> +	rreg = rb_config->reg_rptr;
>> +	wreg = rb_config->reg_wptr;
>> +	mem_sys = rb_config->base_sys_addr;
>> +	mem_addr = rb_config->base_mc_addr;
>> +	len = rb_config->val_size;
>> +
>> +	rd_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), rreg);
>> +	wr_ptr = isp4hw_rreg(GET_ISP4IF_REG_BASE(ispif), wreg);
>> +	rd_ptr_dbg = rd_ptr;
>> +	wr_ptr_dbg = wr_ptr;
>> +
>> +	if (rd_ptr > len) {
>> +		dev_err(dev, "fail (%u),rd_ptr %u(should<=%u),wr_ptr %u\n",
>> +			stream, rd_ptr, len, wr_ptr);
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (wr_ptr > len) {
>> +		dev_err(dev, "fail (%u),wr_ptr %u(should<=%u), rd_ptr %u\n",
>> +			stream, wr_ptr, len, rd_ptr);
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (rd_ptr < wr_ptr) {
>> +		if ((wr_ptr - rd_ptr) >= (sizeof(struct isp4fw_resp))) {
>> +			memcpy((u8 *)response, (u8 *)mem_sys + rd_ptr,
>> +			       sizeof(struct isp4fw_resp));
>> +
>> +			rd_ptr += sizeof(struct isp4fw_resp);
>> +			if (rd_ptr < len) {
>> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +					    rreg, rd_ptr);
>> +			} else {
>> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
>> +					stream, rd_ptr, len, wr_ptr);
>> +				return -EINVAL;
>> +			}
>> +
>> +		} else {
>> +			dev_err(dev, "sth wrong with wptr and rptr\n");
>> +			return -EINVAL;
>> +		}
>> +	} else if (rd_ptr > wr_ptr) {
>> +		u32 size;
>> +		u8 *dst;
>> +
>> +		dst = (u8 *)response;
>> +
>> +		size = len - rd_ptr;
>> +		if (size > sizeof(struct isp4fw_resp)) {
>> +			mem_addr += rd_ptr;
>> +			memcpy((u8 *)response,
>> +			       (u8 *)(mem_sys) + rd_ptr,
>> +			       sizeof(struct isp4fw_resp));
>> +			rd_ptr += sizeof(struct isp4fw_resp);
>> +			if (rd_ptr < len) {
>> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +					    rreg, rd_ptr);
>> +			} else {
>> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
>> +					stream, rd_ptr, len, wr_ptr);
>> +				return -EINVAL;
>> +			}
>> +
>> +		} else {
>> +			if ((size + wr_ptr) < (sizeof(struct isp4fw_resp))) {
>> +				dev_err(dev, "sth wrong with wptr and rptr1\n");
>> +				return -EINVAL;
>> +			}
>> +
>> +			memcpy(dst, (u8 *)(mem_sys) + rd_ptr, size);
>> +
>> +			dst += size;
>> +			size = sizeof(struct isp4fw_resp) - size;
>> +			if (size)
>> +				memcpy(dst, (u8 *)(mem_sys), size);
>> +			rd_ptr = size;
>> +			if (rd_ptr < len) {
>> +				isp4hw_wreg(GET_ISP4IF_REG_BASE(ispif),
>> +					    rreg, rd_ptr);
>> +			} else {
>> +				dev_err(dev, "(%u),rd %u(should<=%u),wr %u\n",
>> +					stream, rd_ptr, len, wr_ptr);
>> +				return -EINVAL;
>> +			}
>> +		}
>> +	} else {
>> +		return -ETIME;
>> +	}
>> +
>> +	checksum = isp4if_compute_check_sum((u8 *)response,
>> +					    (sizeof(struct isp4fw_resp) - 4));
> 
> Redundant parentheses again.
> 
Sure, will modify in the next patch

>> +
>> +	if (checksum != response->resp_check_sum) {
>> +		dev_err(dev, "resp checksum 0x%x,should 0x%x,rptr %u,wptr %u\n",
>> +			checksum, response->resp_check_sum,
>> +			rd_ptr_dbg, wr_ptr_dbg);
>> +
>> +		dev_err(dev, "(%u), seqNo %u, resp_id (0x%x)\n",
>> +			stream,
>> +			response->resp_seq_num,
>> +			response->resp_id);
> 
> Fits on fewer lines.
> 
Sure, will modify in the next patch

>> +
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int isp4if_send_command(struct isp4_interface *ispif,
>> +			u32 cmd_id,
>> +			void *package,
>> +			u32 package_size)
> 
> Ditto.
> 
Ditto

>> +{
>> +	return isp4if_send_fw_cmd(ispif,
>> +				  cmd_id, package,
>> +				  package_size, NULL, NULL, NULL);
> 
> Ditto.
> 
Ditto

>> +}
>> +
>> +int isp4if_send_command_sync(struct isp4_interface *ispif,
>> +			     u32 cmd_id,
>> +			     void *package,
>> +			     u32 package_size,
>> +			     u32 timeout)
> 
> Ditto.
> 
Ditto

>> +{
>> +	struct device *dev = ispif->dev;
>> +	DECLARE_WAIT_QUEUE_HEAD(cmd_wq);
>> +	u32 wq_cond = 0;
>> +	int ret;
>> +	u32 seq;
>> +
>> +	ret = isp4if_send_fw_cmd(ispif,
>> +				 cmd_id, package,
> 
> Ditto.
> 
Ditto

>> +				 package_size, &cmd_wq, &wq_cond, &seq);
>> +
>> +	if (ret) {
>> +		dev_err(dev, "send fw cmd fail %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = wait_event_timeout(cmd_wq, wq_cond != 0,
>> +				 msecs_to_jiffies(timeout));
>> +
> 
> Extra newline.
> 
>> +	/* timeout occurred */
> 
> Redundant comment.
> 
Sure, will modify in the next patch

>> +	if (ret == 0) {
>> +		struct isp4if_cmd_element *ele;
>> +
>> +		ele = isp4if_rm_cmd_from_cmdq(ispif, seq, cmd_id);
>> +		kfree(ele);
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +void isp4if_clear_bufq(struct isp4_interface *ispif)
>> +{
>> +	struct isp4if_img_buf_node *buf_node = NULL;
>> +	struct isp4if_img_buf_node *tmp_node = NULL;
>> +
>> +	guard(mutex)(&ispif->bufq_mutex);
>> +
>> +	list_for_each_entry_safe(buf_node, tmp_node, &ispif->bufq,
>> +				 node) {
> 
> Please rewrap.
> 
Sure, will modify in the next patch

>> +		list_del(&buf_node->node);
>> +		kfree(buf_node);
>> +	}
>> +}
>> +
>> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node)
>> +{
>> +	kfree(buf_node);
>> +}
>> +
>> +struct isp4if_img_buf_node *
>> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info)
>> +{
>> +	struct isp4if_img_buf_node *node = NULL;
>> +
>> +	node = kmalloc(sizeof(*node), GFP_KERNEL);
>> +	if (node)
>> +		node->buf_info = *buf_info;
>> +
>> +	return node;
>> +};
>> +
>> +struct isp4if_img_buf_node *
>> +isp4if_dequeue_buffer(struct isp4_interface *ispif)
>> +{
>> +	struct isp4if_img_buf_node *buf_node = NULL;
>> +
>> +	guard(mutex)(&ispif->bufq_mutex);
>> +
>> +	buf_node = list_first_entry_or_null(&ispif->bufq,
>> +					    typeof(*buf_node),
>> +					    node);
> 
> Ditto.
> 
Sure, will modify in the next patch

>> +	if (buf_node)
>> +		list_del(&buf_node->node);
>> +
>> +	return buf_node;
>> +}
>> +
>> +int isp4if_queue_buffer(struct isp4_interface *ispif,
>> +			struct isp4if_img_buf_node *buf_node)
>> +{
>> +	int ret;
>> +
>> +	ret = isp4if_send_buffer(ispif, &buf_node->buf_info);
>> +	if (ret)
>> +		return ret;
>> +
>> +	guard(mutex)(&ispif->bufq_mutex);
>> +
>> +	list_add_tail(&buf_node->node, &ispif->bufq);
>> +
>> +	return 0;
>> +}
>> +
>> +int isp4if_stop(struct isp4_interface *ispif)
>> +{
>> +	isp4if_disable_ccpu(ispif);
>> +
>> +	isp4if_dealloc_fw_gpumem(ispif);
>> +
>> +	return 0;
>> +}
>> +
>> +int isp4if_start(struct isp4_interface *ispif)
>> +{
>> +	int ret;
>> +
>> +	ret = isp4if_alloc_fw_gpumem(ispif);
>> +	if (ret)
>> +		goto failed_gpumem_alloc;
>> +
>> +	ret = isp4if_fw_boot(ispif);
>> +	if (ret)
>> +		goto failed_fw_boot;
>> +
>> +	return 0;
>> +
>> +failed_gpumem_alloc:
>> +	return -ENOMEM;
> 
> No label needed for this.
> 
Sure, will modify in the next patch

>> +
>> +failed_fw_boot:
>> +	isp4if_dealloc_fw_gpumem(ispif);
>> +	return ret;
>> +}
>> +
>> +int isp4if_deinit(struct isp4_interface *ispif)
>> +{
>> +	isp4if_clear_cmdq(ispif);
>> +
>> +	isp4if_clear_bufq(ispif);
>> +
>> +	mutex_destroy(&ispif->cmdq_mutex);
>> +	mutex_destroy(&ispif->bufq_mutex);
>> +	mutex_destroy(&ispif->isp4if_mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
>> +		void *amdgpu_dev, void __iomem *isp_mmip)
>> +{
>> +	ispif->dev = dev;
>> +	ispif->adev = amdgpu_dev;
>> +	ispif->mmio = isp_mmip;
>> +
>> +	ispif->cmd_rb_base_index = 0;
>> +	ispif->resp_rb_base_index = ISP4IF_RESP_CHAN_TO_RB_OFFSET - 1;
>> +	ispif->aligned_rb_chunk_size = ISP4IF_RB_PMBMAP_MEM_CHUNK & 0xffffffc0;
>> +
>> +	mutex_init(&ispif->cmdq_mutex); /* used for cmdq access */
>> +	mutex_init(&ispif->bufq_mutex); /* used for bufq access */
>> +	mutex_init(&ispif->isp4if_mutex); /* used for commands sent to ispfw */
>> +
>> +	INIT_LIST_HEAD(&ispif->cmdq);
>> +	INIT_LIST_HEAD(&ispif->bufq);
>> +
>> +	return 0;
>> +}
>> diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/drivers/media/platform/amd/isp4/isp4_interface.h
>> new file mode 100644
>> index 000000000000..b2ca147b78b6
>> --- /dev/null
>> +++ b/drivers/media/platform/amd/isp4/isp4_interface.h
>> @@ -0,0 +1,164 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Copyright (C) 2025 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#ifndef _ISP4_INTERFACE_
>> +#define _ISP4_INTERFACE_
>> +
>> +#define ISP4IF_RB_MAX (25)
>> +#define ISP4IF_RESP_CHAN_TO_RB_OFFSET (9)
>> +#define ISP4IF_RB_PMBMAP_MEM_SIZE (16 * 1024 * 1024 - 1)
>> +#define ISP4IF_RB_PMBMAP_MEM_CHUNK (ISP4IF_RB_PMBMAP_MEM_SIZE \
>> +	/ (ISP4IF_RB_MAX - 1))
>> +#define ISP4IF_ISP_MC_ADDR_ALIGN (1024 * 32)
>> +#define ISP4IF_HOST2FW_COMMAND_SIZE (sizeof(struct isp4fw_cmd))
>> +#define ISP4IF_FW_CMD_BUF_COUNT 4
>> +#define ISP4IF_FW_RESP_BUF_COUNT 4
>> +#define ISP4IF_MAX_NUM_HOST2FW_COMMAND (40)
>> +#define ISP4IF_FW_CMD_BUF_SIZE (ISP4IF_MAX_NUM_HOST2FW_COMMAND \
>> +	* ISP4IF_HOST2FW_COMMAND_SIZE)
>> +#define ISP4IF_MAX_SLEEP_COUNT (10)
>> +#define ISP4IF_MAX_SLEEP_TIME (33)
>> +
>> +#define ISP4IF_META_INFO_BUF_SIZE ALIGN(sizeof(struct isp4fw_meta_info), 0x8000)
>> +#define ISP4IF_MAX_STREAM_META_BUF_COUNT 6
>> +
>> +#define ISP4IF_FW_LOG_RINGBUF_SIZE (2 * 1024 * 1024)
>> +
>> +#define ISP4IF_MAX_CMD_RESPONSE_BUF_SIZE (4 * 1024)
>> +
>> +#define GET_ISP4IF_REG_BASE(ispif) (((ispif))->mmio)
>> +
>> +enum isp4if_stream_id {
>> +	ISP4IF_STREAM_ID_GLOBAL = 0,
>> +	ISP4IF_STREAM_ID_1 = 1,
>> +	ISP4IF_STREAM_ID_MAX = 4
>> +};
>> +
>> +enum isp4if_status {
>> +	ISP4IF_STATUS_PWR_OFF,
>> +	ISP4IF_STATUS_PWR_ON,
>> +	ISP4IF_STATUS_FW_RUNNING,
>> +	ISP4IF_FSM_STATUS_MAX
>> +};
>> +
>> +struct isp4if_gpu_mem_info {
>> +	u32	mem_domain;
>> +	u64	mem_size;
>> +	u32	mem_align;
>> +	u64	gpu_mc_addr;
>> +	void	*sys_addr;
>> +	void	*mem_handle;
>> +};
>> +
>> +struct isp4if_img_buf_info {
>> +	struct {
>> +		void *sys_addr;
>> +		u64 mc_addr;
>> +		u32 len;
>> +	} planes[3];
>> +};
>> +
>> +struct isp4if_img_buf_node {
>> +	struct list_head node;
>> +	struct isp4if_img_buf_info buf_info;
>> +};
>> +
>> +struct isp4if_cmd_element {
>> +	struct list_head list;
>> +	u32 seq_num;
>> +	u32 cmd_id;
>> +	enum isp4if_stream_id stream;
>> +	u64 mc_addr;
>> +	wait_queue_head_t *wq;
>> +	u32 *wq_cond;
>> +	struct isp4if_gpu_mem_info *gpu_pkg;
>> +};
>> +
>> +struct isp4_interface {
>> +	struct amdgpu_device *adev;
>> +
>> +	struct device *dev;
>> +	void __iomem *mmio;
>> +
>> +	struct mutex cmdq_mutex; /* used for cmdq access */
>> +	struct mutex bufq_mutex; /* used for bufq access */
>> +	struct mutex isp4if_mutex; /* used to send fw cmd and read fw log */
>> +
>> +	struct list_head cmdq; /* commands sent to fw */
>> +	struct list_head bufq; /* buffers sent to fw */
>> +
>> +	enum isp4if_status status;
>> +	u32 host2fw_seq_num;
>> +
>> +	/* FW ring buffer configs */
>> +	u32 cmd_rb_base_index;
>> +	u32 resp_rb_base_index;
>> +	u32 aligned_rb_chunk_size;
>> +
>> +	/* ISP fw buffers */
>> +	struct isp4if_gpu_mem_info *fw_log_buf;
>> +	struct isp4if_gpu_mem_info *fw_cmd_resp_buf;
>> +	struct isp4if_gpu_mem_info *fw_mem_pool;
>> +	struct isp4if_gpu_mem_info *
>> +		metainfo_buf_pool[ISP4IF_MAX_STREAM_META_BUF_COUNT];
>> +};
>> +
>> +static inline void isp4if_split_addr64(u64 addr, u32 *lo, u32 *hi)
>> +{
>> +	if (lo)
>> +		*lo = (u32)(addr & 0xffffffff);
> 
> Redundant and and cast, too.
> 
>> +	if (hi)
>> +		*hi = (u32)(addr >> 32);
> 
> Redundant cast.
> 
Sure, will modify in the next patch

>> +}
>> +
>> +static inline u64 isp4if_join_addr64(u32 lo, u32 hi)
>> +{
>> +	return (((u64)hi) << 32) | (u64)lo;
>> +}
>> +
>> +int isp4if_f2h_resp(struct isp4_interface *ispif,
>> +		    enum isp4if_stream_id stream,
>> +		    void *response);
>> +
>> +int isp4if_send_command(struct isp4_interface *ispif,
>> +			u32 cmd_id,
>> +			void *package,
>> +			u32 package_size);
>> +
>> +int isp4if_send_command_sync(struct isp4_interface *ispif,
>> +			     u32 cmd_id,
>> +			     void *package,
>> +			     u32 package_size,
>> +			     u32 timeout);
>> +
>> +struct isp4if_cmd_element *
>> +isp4if_rm_cmd_from_cmdq(struct isp4_interface *ispif,
>> +			u32 seq_num,
>> +			u32 cmd_id);
>> +
>> +void isp4if_clear_cmdq(struct isp4_interface *ispif);
>> +
>> +void isp4if_clear_bufq(struct isp4_interface *ispif);
>> +
>> +void isp4if_dealloc_buffer_node(struct isp4if_img_buf_node *buf_node);
>> +
>> +struct isp4if_img_buf_node *
>> +isp4if_alloc_buffer_node(struct isp4if_img_buf_info *buf_info);
>> +
>> +struct isp4if_img_buf_node *isp4if_dequeue_buffer(struct isp4_interface *ispif);
>> +
>> +int isp4if_queue_buffer(struct isp4_interface *ispif,
>> +			struct isp4if_img_buf_node *buf_node);
>> +
>> +int isp4if_stop(struct isp4_interface *ispif);
>> +
>> +int isp4if_start(struct isp4_interface *ispif);
>> +
>> +int isp4if_deinit(struct isp4_interface *ispif);
>> +
>> +int isp4if_init(struct isp4_interface *ispif, struct device *dev,
>> +		void *amdgpu_dev, void __iomem *isp_mmip);
>> +
>> +#endif
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-29  7:45           ` Sultan Alsawaf
@ 2025-07-29 10:13             ` Du, Bin
  2025-07-30  5:38               ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-29 10:13 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Thanks Sultan, yes, seems much close to the final success. Will have 
some internal discussion.

On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>> Thanks Sultan, please see my comments
>>>
>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>
>>>>>> I cannot for the life of me get the webcam working under Linux. The webcam works
>>>>>> under Windows so it's not a hardware issue.
>>>>>>
>>>>>> With this patchset and all of the patches you link here applied to 6.15, I get
>>>>>> the following errors:
>>>>>>      [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
>>>>>>      [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
>>>>>>
>>>>>> With the old ispkernel code from February [1] applied on 6.15, the webcam
>>>>>> indicator LED lights up but there's no image. I see these messages at boot:
>>>>>>      [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
>>>>>>      [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
>>>>>>      [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>>>>      [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>      [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>>>>      [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>
>>>>>> And then the kernel crashes due to the same use-after-free issues I pointed out
>>>>>> in my other email [2].
>>>>>>
>>>>>> Any idea what's going on?
>>>>>>
>>>>>> [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>> Hi Sultan,
>>>>>
>>>>> [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
>>>>> on 6.15 but we are really glad to help, would you please provide some info,
>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>> 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
>>>>>
>>>>> After your confirmation, we'll see what we can do to enable your camera
>>>>> quickly and easily
>>>>>
>>>>> Regards,
>>>>> Bin
>>>>
>>>> Thank you, Bin!
>>>>
>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>> 2. Yes, here is my kernel source [2].
>>>>
>>>> I have some more findings:
>>>>
>>>> Currently, the first blocking issue is that the I2C adapter fails to initialize.
>>>> This is because the ISP tile isn't powered on.
>>>>
>>>> I noticed that in the old version of amd_isp_i2c_designware [3], there were
>>>> calls to isp_power_set(), which is available in the old ISP4 sources [4].
>>>> Without isp_power_set(), the I2C adapter always fails to initialize for me.
>>>>
>>>> How is the ISP tile supposed to get powered on in the current ISP4 code?
>>>>
>>> You are correct, yes, i believe the I2C adapter failure is caused by ISP not
>>> being powered up. Currently in latest code, isp_power_set is no longer
>>> available, instead, we implemented genPD for ISP in amdgpu
>>> https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
>>> Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
>>> standard runtime PM API to do the power control
>>
>> Thanks for that link, I found it along with another patch on the list to make
>> the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").
>>
>>>> Also, I noticed that the driver init ordering matters between all of the drivers
>>>> needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
>>>> must be initialized before amd_capture, otherwise amd_capture will fail to find
>>>> the fwnode properties for the OV05C10 device attached to the I2C bus.
>>>>
>>>> But there is no driver init ordering enforced, which also caused some issues for
>>>> me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
>>>> to ensure each driver waits for its dependencies to init first?
>>>>
>>> amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
>>> driver, it is init before amd_isp_catpure.
>>> Do you see in your side the amd_capture probe failure caused by failing to
>>> read fwnode properties? If that's the case please help to check if amd_isp4
>>> is loaded successfully
>>
>> I got much further now: there aren't any driver initialization errors, but when
>> I open the camera, there's no image. The camera LED turns on so it's active.
>>
>> And then shortly afterwards, amdgpu dies and the entire system freezes.
>>
>> I've attached my full dmesg, please let me know what you think. Thanks!
> 
> I almost forgot, here is my current kernel tree:
> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-sultan-isp4
> 
> Sultan


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-29 10:13             ` Du, Bin
@ 2025-07-30  5:38               ` Sultan Alsawaf
  2025-07-30  9:53                 ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-30  5:38 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> > On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> > > On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > > > Thanks Sultan, please see my comments
> > > > 
> > > > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > > > 
> > > > > > > I cannot for the life of me get the webcam working under Linux. The webcam works
> > > > > > > under Windows so it's not a hardware issue.
> > > > > > > 
> > > > > > > With this patchset and all of the patches you link here applied to 6.15, I get
> > > > > > > the following errors:
> > > > > > >      [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
> > > > > > >      [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
> > > > > > > 
> > > > > > > With the old ispkernel code from February [1] applied on 6.15, the webcam
> > > > > > > indicator LED lights up but there's no image. I see these messages at boot:
> > > > > > >      [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
> > > > > > >      [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
> > > > > > >      [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > > > > >      [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > > > >      [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > > > > >      [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > > > > 
> > > > > > > And then the kernel crashes due to the same use-after-free issues I pointed out
> > > > > > > in my other email [2].
> > > > > > > 
> > > > > > > Any idea what's going on?
> > > > > > > 
> > > > > > > [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > > > Hi Sultan,
> > > > > > 
> > > > > > [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
> > > > > > on 6.15 but we are really glad to help, would you please provide some info,
> > > > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > > > 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
> > > > > > 
> > > > > > After your confirmation, we'll see what we can do to enable your camera
> > > > > > quickly and easily
> > > > > > 
> > > > > > Regards,
> > > > > > Bin
> > > > > 
> > > > > Thank you, Bin!
> > > > > 
> > > > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > > > 2. Yes, here is my kernel source [2].
> > > > > 
> > > > > I have some more findings:
> > > > > 
> > > > > Currently, the first blocking issue is that the I2C adapter fails to initialize.
> > > > > This is because the ISP tile isn't powered on.
> > > > > 
> > > > > I noticed that in the old version of amd_isp_i2c_designware [3], there were
> > > > > calls to isp_power_set(), which is available in the old ISP4 sources [4].
> > > > > Without isp_power_set(), the I2C adapter always fails to initialize for me.
> > > > > 
> > > > > How is the ISP tile supposed to get powered on in the current ISP4 code?
> > > > > 
> > > > You are correct, yes, i believe the I2C adapter failure is caused by ISP not
> > > > being powered up. Currently in latest code, isp_power_set is no longer
> > > > available, instead, we implemented genPD for ISP in amdgpu
> > > > https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
> > > > Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
> > > > standard runtime PM API to do the power control
> > > 
> > > Thanks for that link, I found it along with another patch on the list to make
> > > the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").
> > > 
> > > > > Also, I noticed that the driver init ordering matters between all of the drivers
> > > > > needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
> > > > > must be initialized before amd_capture, otherwise amd_capture will fail to find
> > > > > the fwnode properties for the OV05C10 device attached to the I2C bus.
> > > > > 
> > > > > But there is no driver init ordering enforced, which also caused some issues for
> > > > > me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
> > > > > to ensure each driver waits for its dependencies to init first?
> > > > > 
> > > > amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
> > > > driver, it is init before amd_isp_catpure.
> > > > Do you see in your side the amd_capture probe failure caused by failing to
> > > > read fwnode properties? If that's the case please help to check if amd_isp4
> > > > is loaded successfully
> > > 
> > > I got much further now: there aren't any driver initialization errors, but when
> > > I open the camera, there's no image. The camera LED turns on so it's active.
> > > 
> > > And then shortly afterwards, amdgpu dies and the entire system freezes.
> > > 
> > > I've attached my full dmesg, please let me know what you think. Thanks!
> > 
> > I almost forgot, here is my current kernel tree:
> > https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-sultan-isp4
> > 
> > Sultan
> 
> Thanks Sultan, yes, seems much close to the final success. Will have some
> internal discussion.

I got the webcam working. The same bug happened when I tried Ubuntu's linux-oem
kernel, which made me think that the issue was firmware.

And indeed, the culprit was a firmware update from February. I bisected
linux-firmware and found the commit which broke the webcam for me:

	commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
	Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
	Date:   Wed Feb 19 12:16:51 2025 -0500

	    amdgpu: Update ISP FW for isp v4.1.1
	    
	    From internal git commit:
	    5058202443e08a673b6772ea6339efb50853be28
	    
	    Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>

	 amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
	 1 file changed, 0 insertions(+), 0 deletions(-)

Downgrading firmware to before that commit fixes the webcam. Any idea why?

Thanks,
Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-30  5:38               ` Sultan Alsawaf
@ 2025-07-30  9:53                 ` Du, Bin
  2025-07-31  0:30                   ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-30  9:53 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Hi Sultan, really glad to hear that you got your camera working

On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
> On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
>> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
>>> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>>>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>>>> Thanks Sultan, please see my comments
>>>>>
>>>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>>>
>>>>>>>> I cannot for the life of me get the webcam working under Linux. The webcam works
>>>>>>>> under Windows so it's not a hardware issue.
>>>>>>>>
>>>>>>>> With this patchset and all of the patches you link here applied to 6.15, I get
>>>>>>>> the following errors:
>>>>>>>>       [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
>>>>>>>>       [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
>>>>>>>>
>>>>>>>> With the old ispkernel code from February [1] applied on 6.15, the webcam
>>>>>>>> indicator LED lights up but there's no image. I see these messages at boot:
>>>>>>>>       [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
>>>>>>>>       [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
>>>>>>>>       [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>>>>>>       [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>>>       [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>>>>>>       [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>>>
>>>>>>>> And then the kernel crashes due to the same use-after-free issues I pointed out
>>>>>>>> in my other email [2].
>>>>>>>>
>>>>>>>> Any idea what's going on?
>>>>>>>>
>>>>>>>> [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>>>> Hi Sultan,
>>>>>>>
>>>>>>> [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
>>>>>>> on 6.15 but we are really glad to help, would you please provide some info,
>>>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>>>> 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
>>>>>>>
>>>>>>> After your confirmation, we'll see what we can do to enable your camera
>>>>>>> quickly and easily
>>>>>>>
>>>>>>> Regards,
>>>>>>> Bin
>>>>>>
>>>>>> Thank you, Bin!
>>>>>>
>>>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>>>> 2. Yes, here is my kernel source [2].
>>>>>>
>>>>>> I have some more findings:
>>>>>>
>>>>>> Currently, the first blocking issue is that the I2C adapter fails to initialize.
>>>>>> This is because the ISP tile isn't powered on.
>>>>>>
>>>>>> I noticed that in the old version of amd_isp_i2c_designware [3], there were
>>>>>> calls to isp_power_set(), which is available in the old ISP4 sources [4].
>>>>>> Without isp_power_set(), the I2C adapter always fails to initialize for me.
>>>>>>
>>>>>> How is the ISP tile supposed to get powered on in the current ISP4 code?
>>>>>>
>>>>> You are correct, yes, i believe the I2C adapter failure is caused by ISP not
>>>>> being powered up. Currently in latest code, isp_power_set is no longer
>>>>> available, instead, we implemented genPD for ISP in amdgpu
>>>>> https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
>>>>> Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
>>>>> standard runtime PM API to do the power control
>>>>
>>>> Thanks for that link, I found it along with another patch on the list to make
>>>> the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").
>>>>
>>>>>> Also, I noticed that the driver init ordering matters between all of the drivers
>>>>>> needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
>>>>>> must be initialized before amd_capture, otherwise amd_capture will fail to find
>>>>>> the fwnode properties for the OV05C10 device attached to the I2C bus.
>>>>>>
>>>>>> But there is no driver init ordering enforced, which also caused some issues for
>>>>>> me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
>>>>>> to ensure each driver waits for its dependencies to init first?
>>>>>>
>>>>> amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
>>>>> driver, it is init before amd_isp_catpure.
>>>>> Do you see in your side the amd_capture probe failure caused by failing to
>>>>> read fwnode properties? If that's the case please help to check if amd_isp4
>>>>> is loaded successfully
>>>>
>>>> I got much further now: there aren't any driver initialization errors, but when
>>>> I open the camera, there's no image. The camera LED turns on so it's active.
>>>>
>>>> And then shortly afterwards, amdgpu dies and the entire system freezes.
>>>>
>>>> I've attached my full dmesg, please let me know what you think. Thanks!
>>>
>>> I almost forgot, here is my current kernel tree:
>>> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-sultan-isp4
>>>
>>> Sultan
>>
>> Thanks Sultan, yes, seems much close to the final success. Will have some
>> internal discussion.
> 
> I got the webcam working. The same bug happened when I tried Ubuntu's linux-oem
> kernel, which made me think that the issue was firmware.
> 
> And indeed, the culprit was a firmware update from February. I bisected
> linux-firmware and found the commit which broke the webcam for me:
> 
> 	commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
> 	Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
> 	Date:   Wed Feb 19 12:16:51 2025 -0500
> 
> 	    amdgpu: Update ISP FW for isp v4.1.1
> 	
> 	    From internal git commit:
> 	    5058202443e08a673b6772ea6339efb50853be28
> 	
> 	    Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> 
> 	 amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
> 	 1 file changed, 0 insertions(+), 0 deletions(-)
> 
> Downgrading firmware to before that commit fixes the webcam. Any idea why?
> 
> Thanks,
> Sultan

So, can i say the working firmware binary is this one?

Commit 8f070131
amdgpu: Update ISP FW for isp v4.1.1

 From internal git commit:
39b007366cc76ef8c65e3bc6220ccb213f4861fb

Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>

There are too many changes between them, so i can't tell exactly which 
change caused this. So, from my side
1. Will try these two firmware to see if we have the same issue.
2. It has been quite a long time since last release, will see if need to 
release a latest one.

Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-30  9:53                 ` Du, Bin
@ 2025-07-31  0:30                   ` Sultan Alsawaf
  2025-07-31 10:04                     ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-31  0:30 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
> On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
> > On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
> > > On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> > > > On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> > > > > On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > > > > > Thanks Sultan, please see my comments
> > > > > > 
> > > > > > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > > > > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > > > > > 
> > > > > > > > > I cannot for the life of me get the webcam working under Linux. The webcam works
> > > > > > > > > under Windows so it's not a hardware issue.
> > > > > > > > > 
> > > > > > > > > With this patchset and all of the patches you link here applied to 6.15, I get
> > > > > > > > > the following errors:
> > > > > > > > >       [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
> > > > > > > > >       [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
> > > > > > > > > 
> > > > > > > > > With the old ispkernel code from February [1] applied on 6.15, the webcam
> > > > > > > > > indicator LED lights up but there's no image. I see these messages at boot:
> > > > > > > > >       [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
> > > > > > > > >       [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
> > > > > > > > >       [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > > > > > > >       [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > > > > > >       [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
> > > > > > > > >       [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
> > > > > > > > > 
> > > > > > > > > And then the kernel crashes due to the same use-after-free issues I pointed out
> > > > > > > > > in my other email [2].
> > > > > > > > > 
> > > > > > > > > Any idea what's going on?
> > > > > > > > > 
> > > > > > > > > [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > > > > > Hi Sultan,
> > > > > > > > 
> > > > > > > > [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
> > > > > > > > on 6.15 but we are really glad to help, would you please provide some info,
> > > > > > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > > > > > 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
> > > > > > > > 
> > > > > > > > After your confirmation, we'll see what we can do to enable your camera
> > > > > > > > quickly and easily
> > > > > > > > 
> > > > > > > > Regards,
> > > > > > > > Bin
> > > > > > > 
> > > > > > > Thank you, Bin!
> > > > > > > 
> > > > > > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > > > > > 2. Yes, here is my kernel source [2].
> > > > > > > 
> > > > > > > I have some more findings:
> > > > > > > 
> > > > > > > Currently, the first blocking issue is that the I2C adapter fails to initialize.
> > > > > > > This is because the ISP tile isn't powered on.
> > > > > > > 
> > > > > > > I noticed that in the old version of amd_isp_i2c_designware [3], there were
> > > > > > > calls to isp_power_set(), which is available in the old ISP4 sources [4].
> > > > > > > Without isp_power_set(), the I2C adapter always fails to initialize for me.
> > > > > > > 
> > > > > > > How is the ISP tile supposed to get powered on in the current ISP4 code?
> > > > > > > 
> > > > > > You are correct, yes, i believe the I2C adapter failure is caused by ISP not
> > > > > > being powered up. Currently in latest code, isp_power_set is no longer
> > > > > > available, instead, we implemented genPD for ISP in amdgpu
> > > > > > https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
> > > > > > Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
> > > > > > standard runtime PM API to do the power control
> > > > > 
> > > > > Thanks for that link, I found it along with another patch on the list to make
> > > > > the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").
> > > > > 
> > > > > > > Also, I noticed that the driver init ordering matters between all of the drivers
> > > > > > > needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
> > > > > > > must be initialized before amd_capture, otherwise amd_capture will fail to find
> > > > > > > the fwnode properties for the OV05C10 device attached to the I2C bus.
> > > > > > > 
> > > > > > > But there is no driver init ordering enforced, which also caused some issues for
> > > > > > > me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
> > > > > > > to ensure each driver waits for its dependencies to init first?
> > > > > > > 
> > > > > > amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
> > > > > > driver, it is init before amd_isp_catpure.
> > > > > > Do you see in your side the amd_capture probe failure caused by failing to
> > > > > > read fwnode properties? If that's the case please help to check if amd_isp4
> > > > > > is loaded successfully
> > > > > 
> > > > > I got much further now: there aren't any driver initialization errors, but when
> > > > > I open the camera, there's no image. The camera LED turns on so it's active.
> > > > > 
> > > > > And then shortly afterwards, amdgpu dies and the entire system freezes.
> > > > > 
> > > > > I've attached my full dmesg, please let me know what you think. Thanks!
> > > > 
> > > > I almost forgot, here is my current kernel tree:
> > > > https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-sultan-isp4
> > > > 
> > > > Sultan
> > > 
> > > Thanks Sultan, yes, seems much close to the final success. Will have some
> > > internal discussion.
> > 
> > I got the webcam working. The same bug happened when I tried Ubuntu's linux-oem
> > kernel, which made me think that the issue was firmware.
> > 
> > And indeed, the culprit was a firmware update from February. I bisected
> > linux-firmware and found the commit which broke the webcam for me:
> > 
> > 	commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
> > 	Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > 	Date:   Wed Feb 19 12:16:51 2025 -0500
> > 
> > 	    amdgpu: Update ISP FW for isp v4.1.1
> > 	
> > 	    From internal git commit:
> > 	    5058202443e08a673b6772ea6339efb50853be28
> > 	
> > 	    Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > 
> > 	 amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
> > 	 1 file changed, 0 insertions(+), 0 deletions(-)
> > 
> > Downgrading firmware to before that commit fixes the webcam. Any idea why?
> > 
> > Thanks,
> > Sultan
> 
> So, can i say the working firmware binary is this one?
> 
> Commit 8f070131
> amdgpu: Update ISP FW for isp v4.1.1
> 
> From internal git commit:
> 39b007366cc76ef8c65e3bc6220ccb213f4861fb
> 
> Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>

Correct.

> There are too many changes between them, so i can't tell exactly which
> change caused this. So, from my side
> 1. Will try these two firmware to see if we have the same issue.
> 2. It has been quite a long time since last release, will see if need to
> release a latest one.

Thanks. It was a quick bisect for me, so I'm happy to help test if a bisect
between those two internal git commits is needed.

In case it makes a difference, I have the laptop with the 2.8K OLED display. I'm
aware there is one other display variant on other SKUs, which is a WUXGA IPS.

Also, with that old firmware, my camera only works with the old isp4 driver from
that Linux_ISP_Kernel repo (which is the same isp4 driver used in Ubuntu's
linux-oem kernel). Does the new isp4 driver you've submitted here require newer
firmware than the old driver located in Linux_ISP_Kernel?

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-29  7:43     ` Du, Bin
@ 2025-07-31  0:34       ` Sultan Alsawaf
  2025-07-31  9:45         ` Du, Bin
  2025-08-11  6:02         ` Sultan Alsawaf
  0 siblings, 2 replies; 96+ messages in thread
From: Sultan Alsawaf @ 2025-07-31  0:34 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Tue, Jul 29, 2025 at 03:43:14PM +0800, Du, Bin wrote:
> Hi Sultan, really appreciate your time and effort
> 
> On 7/28/2025 3:04 PM, Sultan Alsawaf wrote:
> > I found more refcounting issues in addition to the ones from my other emails
> > while trying to make my webcam work:
> > 
> > On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
> > > +static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
> > > +{
> > > +	struct isp4vid_vb2_buf *buf = buf_priv;
> > > +	int ret;
> > > +
> > > +	if (!buf) {
> > > +		pr_err("fail no memory to map\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
> > > +	if (ret) {
> > > +		dev_err(buf->dev, "fail remap vmalloc mem, %d\n", ret);
> > > +		return ret;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Make sure that vm_areas for 2 buffers won't be merged together
> > > +	 */
> > > +	vm_flags_set(vma, VM_DONTEXPAND);
> > > +
> > > +	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
> > > +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> > 
> > Use refcount_read() instead of reading the refcount's atomic_t counter directly.
> > This is done in 3 other places; change those to refcount_read() as well.
> > 
> > This didn't cause any functional problems, but it should still be fixed.
> > 
> > > +
> > > +	return 0;
> > > +}
> > 
> Sure, will fix it
> 
> > [snip]
> > 
> > > +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> > > +{
> > > +	struct isp4vid_vb2_buf *buf = mem_priv;
> > > +
> > > +	if (!buf) {
> > > +		pr_err("fail invalid buf handle\n");
> > > +		return;
> > > +	}
> > > +
> > > +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
> > > +
> > > +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
> > > +		buf->gpu_addr, buf->size);
> > > +
> > > +	if (buf->vaddr)
> > > +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
> > > +
> > > +	// put dmabuf for exported ones
> > > +	dma_buf_put(buf->dbuf);
> > > +
> > > +	kfree(buf);
> > > +}
> > 
> > As mentioned in the other email, the dma_buf_put() here needs to be removed. But
> > that's not all: the dma_buf_vunmap_unlocked() needs to be removed too because
> > vb2 will always unmap the buffer before detaching it. As a result, having the
> > dma_buf_vunmap_unlocked() call here results in a use-after-free when vb2 calls
> > the unmap_dmabuf memop.
> > 
> > Change this function to the following:
> > 
> > 	static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> > 	{
> > 		struct isp4vid_vb2_buf *buf = mem_priv;
> > 
> > 		kfree(buf);
> > 	}
> > 
> Will have a try
> 
> > > +static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
> > > +{
> > > +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
> > > +	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
> > > +
> > > +	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
> > > +		isp_vdev->vdev.name, vb->index, vb->memory);
> > > +
> > > +	if (!buf) {
> > > +		dev_err(isp_vdev->dev, "Invalid buf handle");
> > > +		return;
> > > +	}
> > > +
> > > +	// release implicit dmabuf reference here for vb2 buffer
> > > +	// of type MMAP and is exported
> > > +	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
> > > +		dma_buf_put(buf->dbuf);
> > > +		dev_dbg(isp_vdev->dev,
> > > +			"put dmabuf for vb->memory %d expbuf %d",
> > > +			vb->memory,
> > > +			buf->is_expbuf);
> > > +	}
> > > +}
> > > +
> > 
> > Remove the isp4vid_qops_buffer_cleanup() function. It causes a use-after-free by
> > doing an extra dma_buf_put(). This function isn't needed now that the refcount
> > issues are solved.
> > 
> Will have a try
> 
> > [snip]
> > 
> > > +static const struct vb2_ops isp4vid_qops = {
> > > +	.queue_setup = isp4vid_qops_queue_setup,
> > > +	.buf_cleanup = isp4vid_qops_buffer_cleanup,
> > 
> > Remove the .buf_cleanup hook too.
> > 
> Will have a try
> 
> > > +	.buf_queue = isp4vid_qops_buffer_queue,
> > > +	.start_streaming = isp4vid_qops_start_streaming,
> > > +	.stop_streaming = isp4vid_qops_stop_streaming,
> > > +	.wait_prepare = vb2_ops_wait_prepare,
> > > +	.wait_finish = vb2_ops_wait_finish,
> > > +};
> > 
> > [snip]
> > 
> > Along with the changes from my other emails, I believe this finally fixes all of
> > the refcounting issues. No more UaF or leaks here. :-)
> > 
> > Sultan
> Tried changes in this and other two mails together, found the kernel will
> crash when re-open cheese App (means open cheese, close it and then open it
> again), the crash stack dump is shown below
> 
> [   38.008686] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
> [   38.032693] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
> [   38.060866] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
> [   38.060877] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
> performance state 1 suc
> [   38.425284] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none to
> state 0
> [   38.448631] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
> [   38.508368] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
> [   38.538525] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
> [   38.568839] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
> [   38.568851] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
> performance state 1 suc
> [   38.997779] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none to
> state 0
> [   39.029297] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
> [   39.084010] BUG: kernel NULL pointer dereference, address:
> 0000000000000008
> [   39.084024] #PF: supervisor read access in kernel mode
> [   39.084028] #PF: error_code(0x0000) - not-present page
> [   39.084031] PGD 0 P4D 0
> [   39.084037] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
> [   39.084042] CPU: 3 UID: 1000 PID: 3119 Comm: viewfinderbin-q Not tainted
> 6.14.0-rc2+ #944
> [   39.084046] Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile
> Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
> [   39.084049] RIP: 0010:validate_page_before_insert+0x5/0xc0
> [   39.084060] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 00
> 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 <48>
> 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
> [   39.084064] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
> [   39.084067] RAX: 0000000000000000 RBX: 8000000000000025 RCX:
> 0000000000000000
> [   39.084069] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
> ffff9efa10e400b8
> [   39.084071] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09:
> 0000000000000000
> [   39.084072] R10: 0000000000000000 R11: 0000000000000000 R12:
> ffff9efa10e400b8
> [   39.084074] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15:
> 0000000000000000
> [   39.084076] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000)
> knlGS:0000000000000000
> [   39.084078] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   39.084080] CR2: 0000000000000008 CR3: 0000000137bba000 CR4:
> 0000000000750ef0
> [   39.084083] PKRU: 55555554
> [   39.084084] Call Trace:
> [   39.084087]  <TASK>
> [   39.084093]  ? show_regs+0x71/0x90
> [   39.084099]  ? __die+0x25/0x80
> [   39.084102]  ? page_fault_oops+0x15c/0x570
> [   39.084108]  ? do_user_addr_fault+0x4a9/0x810
> [   39.084111]  ? __mod_memcg_lruvec_state+0xde/0x280
> [   39.084117]  ? exc_page_fault+0x83/0x1d0
> [   39.084123]  ? asm_exc_page_fault+0x27/0x30
> [   39.084131]  ? validate_page_before_insert+0x5/0xc0
> [   39.084134]  ? vm_insert_page+0xd4/0x1a0
> [   39.084139]  remap_vmalloc_range_partial+0xe3/0x160
> [   39.084145]  remap_vmalloc_range+0x21/0x40
> [   39.084153]  isp4vid_vb2_mmap+0x2d/0x130 [amd_capture]
> [   39.084164]  isp4vid_vb2_dmabuf_ops_mmap+0x12/0x20 [amd_capture]
> [   39.084168]  dma_buf_mmap_internal+0x41/0x70
> [   39.084173]  __mmap_region+0x62f/0xbc0
> [   39.084179]  mmap_region+0x67/0xe0
> [   39.084181]  do_mmap+0x52b/0x650
> [   39.084187]  vm_mmap_pgoff+0xf4/0x1c0
> [   39.084194]  ksys_mmap_pgoff+0x182/0x250
> [   39.084198]  __x64_sys_mmap+0x33/0x70
> [   39.084202]  x64_sys_call+0x2541/0x26f0
> [   39.084206]  do_syscall_64+0x70/0x130
> [   39.084212]  ? __rseq_handle_notify_resume+0xa4/0x520
> [   39.084216]  ? do_futex+0x17f/0x220
> [   39.084220]  ? restore_fpregs_from_fpstate+0x3d/0xd0
> [   39.084225]  ? switch_fpu_return+0x50/0xe0
> [   39.084229]  ? syscall_exit_to_user_mode+0x18c/0x1c0
> [   39.084234]  ? do_syscall_64+0x7c/0x130
> [   39.084237]  ? __pfx_futex_wake_mark+0x10/0x10
> [   39.084241]  ? hrtimer_cancel+0x15/0x50
> [   39.084246]  ? futex_wait+0x7c/0x120
> [   39.084249]  ? __pfx_hrtimer_wakeup+0x10/0x10
> [   39.084254]  ? __rseq_handle_notify_resume+0xa4/0x520
> [   39.084256]  ? do_futex+0x17f/0x220
> [   39.084258]  ? restore_fpregs_from_fpstate+0x3d/0xd0
> [   39.084261]  ? switch_fpu_return+0x50/0xe0
> [   39.084264]  ? syscall_exit_to_user_mode+0x18c/0x1c0
> [   39.084268]  ? do_syscall_64+0x7c/0x130
> [   39.084272]  ? __count_memcg_events+0xcd/0x190
> [   39.084276]  ? count_memcg_events.constprop.0+0x2a/0x50
> [   39.084279]  ? handle_mm_fault+0x1ef/0x2d0
> [   39.084284]  ? do_user_addr_fault+0x58d/0x810
> [   39.084286]  ? irqentry_exit_to_user_mode+0x33/0x180
> [   39.084291]  ? irqentry_exit+0x43/0x50
> [   39.084294]  ? exc_page_fault+0x94/0x1d0
> [   39.084298]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
> [   39.084302] RIP: 0033:0x7fa463b2531c
> [   39.084305] Code: 1e fa 41 f7 c1 ff 0f 00 00 75 33 55 48 89 e5 41 54 41
> 89 cc 53 48 89 fb 48 85 ff 74 41 45 89 e2 48 89 df b8 09 00 00 00 0f 05 <48>
> 3d 00 f0 ff ff 77 7c 5b 41 5c 5d c3 0f 1f 80 00 00 00 00 48 8b
> [   39.084308] RSP: 002b:00007fa3f4bf79e0 EFLAGS: 00000246 ORIG_RAX:
> 0000000000000009
> [   39.084311] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
> 00007fa463b2531c
> [   39.084312] RDX: 0000000000000001 RSI: 00000000007782c0 RDI:
> 0000000000000000
> [   39.084314] RBP: 00007fa3f4bf79f0 R08: 0000000000000047 R09:
> 0000000000000000
> [   39.084315] R10: 0000000000000001 R11: 0000000000000246 R12:
> 0000000000000001
> [   39.084317] R13: 0000000000000000 R14: 00007fa3f8019b48 R15:
> 00007fa3f4bf7b60
> [   39.084320]  </TASK>
> [   39.084321] Modules linked in: snd_seq_dummy snd_hrtimer hid_sensor_prox
> hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer
> kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm cmac
> algif_hash algif_skcipher af_alg hid_logitech_hidpp ov05c10 v4l2_cci
> amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common
> v4l2_async videodev pinctrl_amdisp i2c_designware_amdisp qrtr bnep btusb
> btrtl btintel btbcm btmtk bluetooth hid_logitech_dj intel_rapl_msr amd_atl
> intel_rapl_common binfmt_misc nls_iso8859_1 snd_acp_legacy_mach snd_acp_mach
> snd_soc_nau8821 snd_acp3x_rn amdgpu edac_mce_amd snd_ctl_led
> snd_hda_codec_realtek snd_acp70 snd_hda_codec_generic snd_acp_i2s
> snd_acp_pdm snd_hda_scodec_component snd_soc_dmic snd_acp_pcm
> snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci
> snd_sof_xtensa_dsp snd_hda_codec_hdmi snd_sof snd_sof_utils snd_pci_ps
> snd_soc_acpi_amd_match snd_amd_sdw_acpi soundwire_amd
> soundwire_generic_allocation soundwire_bus snd_hda_intel kvm_amd
> [   39.084385]  snd_soc_sdca snd_intel_dspcfg snd_intel_sdw_acpi
> snd_soc_core snd_hda_codec amdxcp kvm snd_compress
> drm_panel_backlight_quirks snd_hda_core snd_usb_audio gpu_sched ac97_bus
> polyval_clmulni snd_pcm_dmaengine polyval_generic ghash_clmulni_intel
> drm_buddy snd_usbmidi_lib snd_seq_midi snd_rpl_pci_acp6x sha256_ssse3
> snd_ump drm_ttm_helper snd_seq_midi_event snd_hwdep sha1_ssse3 ttm
> aesni_intel drm_exec snd_rawmidi drm_suballoc_helper snd_acp_pci mc
> crypto_simd snd_acp_legacy_common drm_client_lib cryptd drm_display_helper
> snd_pci_acp6x snd_seq rapl hp_wmi cec wmi_bmof snd_pcm sparse_keymap
> snd_seq_device rc_core snd_timer snd_pci_acp5x drm_kms_helper
> snd_rn_pci_acp3x amd_pmf snd i2c_algo_bit snd_acp_config i2c_piix4
> snd_soc_acpi amdtee soundcore snd_pci_acp3x i2c_smbus ccp joydev tee
> input_leds serial_multi_instantiate amd_pmc platform_profile wireless_hotkey
> mac_hid serio_raw sch_fq_codel msr parport_pc ppdev lp parport efi_pstore
> nfnetlink dmi_sysfs ip_tables x_tables autofs4 r8152 mii usbhid
> hid_multitouch
> [   39.084451]  hid_generic nvme ucsi_acpi i2c_hid_acpi video typec_ucsi
> i2c_hid amd_sfh thunderbolt hid nvme_core typec wmi drm
> [   39.084465] CR2: 0000000000000008
> [   39.084468] ---[ end trace 0000000000000000 ]---
> [   39.116114] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
> [   39.159519] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
> [   39.201325] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
> [   39.201334] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
> performance state 1 suc
> [   39.343894] RIP: 0010:validate_page_before_insert+0x5/0xc0
> [   39.343907] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 00
> 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 <48>
> 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
> [   39.343909] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
> [   39.343911] RAX: 0000000000000000 RBX: 8000000000000025 RCX:
> 0000000000000000
> [   39.343913] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
> ffff9efa10e400b8
> [   39.343913] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09:
> 0000000000000000
> [   39.343914] R10: 0000000000000000 R11: 0000000000000000 R12:
> ffff9efa10e400b8
> [   39.343915] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15:
> 0000000000000000
> [   39.343916] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000)
> knlGS:0000000000000000
> [   39.343917] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   39.343918] CR2: 0000000000000008 CR3: 0000000137bba000 CR4:
> 0000000000750ef0
> [   39.343919] PKRU: 55555554
> [   39.343920] note: viewfinderbin-q[3119] exited with irqs disabled
> 
> This is the patch, it should have contained all your changes
> 
> From b0a61b6b7500635928166516d5563e6de50300bb Mon Sep 17 00:00:00 2001
> From: Bin Du <Bin.Du@amd.com>
> Date: Mon, 28 Jul 2025 14:18:04 +0800
> Subject: [PATCH] add comment from community
> 
> Change-Id: I06fff629c0dc691eaeaa9d9b81e6af27cbb6adb2
> ---
>  drivers/media/platform/amd/isp4/isp4_video.c | 59 ++++++--------------
>  1 file changed, 17 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/media/platform/amd/isp4/isp4_video.c
> b/drivers/media/platform/amd/isp4/isp4_video.c
> index a1376498c246..b210a0b1e49b 100644
> --- a/drivers/media/platform/amd/isp4/isp4_video.c
> +++ b/drivers/media/platform/amd/isp4/isp4_video.c
> @@ -183,7 +183,7 @@ static int isp4vid_vb2_mmap(void *buf_priv, struct
> vm_area_struct *vma)
>  	vm_flags_set(vma, VM_DONTEXPAND);
> 
>  	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
> -		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> +		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));
> 
>  	return 0;
>  }
> @@ -214,14 +214,9 @@ static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
>  		return;
>  	}
> 
> -	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
> -
>  	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
>  		buf->gpu_addr, buf->size);
> 
> -	if (buf->vaddr)
> -		dma_buf_vunmap_unlocked(buf->dbuf, &map);
> -
>  	kfree(buf);
>  }
> 
> @@ -470,21 +465,25 @@ static struct dma_buf *isp4vid_vb2_get_dmabuf(struct
> vb2_buffer *vb,
>  					      unsigned long flags)
>  {
>  	struct isp4vid_vb2_buf *buf = buf_priv;
> -	struct dma_buf *dbuf;
> +	struct dma_buf *dbuf = buf->dbuf;
> +
> +	if (dbuf) {
> +		dev_dbg(buf->dev, "dbuf already created, reuse %s dbuf\n",
> +			buf->is_expbuf ? "exported" : "implicit");
> +		get_dma_buf(dbuf);
> 
> -	if (buf->dbuf) {
> -		dev_dbg(buf->dev, "dbuf already created, reuse implicit dbuf\n");
> -		dbuf = buf->dbuf;
>  	} else {
>  		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
> +		if (!dbuf)
> +			return NULL;
> +
>  		dev_dbg(buf->dev, "created new dbuf\n");
> +		buf->is_expbuf = true;
> +		refcount_inc(&buf->refcount);
>  	}
> 
> -	buf->is_expbuf = true;
> -	refcount_inc(&buf->refcount);
> -
>  	dev_dbg(buf->dev, "buf exported, refcount %d\n",
> -		buf->refcount.refs.counter);
> +		refcount_read(&buf->refcount));
> 
>  	return dbuf;
>  }
> @@ -579,8 +578,9 @@ static void isp4vid_vb2_put(void *buf_priv)
>  {
>  	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
>  	unsigned int ref_cnt = refcount_read(&buf->refcount);
> +	struct device *dev = buf->dev;
> 
> -	dev_dbg(buf->dev,
> +	dev_dbg(dev,
>  		"release isp user bo 0x%llx size %ld refcount %u is_expbuf %d\n",
>  		buf->gpu_addr, buf->size,
>  		ref_cnt, buf->is_expbuf);
> @@ -598,7 +598,7 @@ static void isp4vid_vb2_put(void *buf_priv)
>  		/* the ref_cnt - 1 is just a predicted value as reference, can't
>  		 * guarantee it's the actual value now
>  		 */
> -		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
> +		dev_warn(dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
>  	}
>  }
> 
> @@ -642,7 +642,7 @@ static void *isp4vid_vb2_alloc(struct vb2_buffer *vb,
> struct device *dev,
>  	refcount_set(&buf->refcount, 1);
> 
>  	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d\n",
> -		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> +		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));
> 
>  	return buf;
>  err_free:
> @@ -1140,30 +1140,6 @@ static void isp4vid_qops_buffer_queue(struct
> vb2_buffer *vb)
>  	mutex_unlock(&isp_vdev->buf_list_lock);
>  }
> 
> -static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
> -{
> -	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
> -	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
> -
> -	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
> -		isp_vdev->vdev.name, vb->index, vb->memory);
> -
> -	if (!buf) {
> -		dev_err(isp_vdev->dev, "Invalid buf handle");
> -		return;
> -	}
> -
> -	// release implicit dmabuf reference here for vb2 buffer
> -	// of type MMAP and is exported
> -	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
> -		dma_buf_put(buf->dbuf);
> -		dev_dbg(isp_vdev->dev,
> -			"put dmabuf for vb->memory %d expbuf %d",
> -			vb->memory,
> -			buf->is_expbuf);
> -	}
> -}
> -
>  static int isp4vid_qops_start_streaming(struct vb2_queue *vq,
>  					unsigned int count)
>  {
> @@ -1343,7 +1319,6 @@ static int isp4vid_fill_buffer_size(struct isp4vid_dev
> *isp_vdev)
> 
>  static const struct vb2_ops isp4vid_qops = {
>  	.queue_setup = isp4vid_qops_queue_setup,
> -	.buf_cleanup = isp4vid_qops_buffer_cleanup,
>  	.buf_queue = isp4vid_qops_buffer_queue,
>  	.start_streaming = isp4vid_qops_start_streaming,
>  	.stop_streaming = isp4vid_qops_stop_streaming,
> -- 
> 2.34.1

The patch looks correct. I will get back to you on this after doing some testing
myself.

FYI, I can only test these changes with the old isp4 driver right now, since the
new isp4 driver doesn't work for me as mentioned in my other email. So far,
something does seem wrong after these changes I suggested because they break the
camera on the old isp4 driver too.

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-07-28  7:28   ` Sakari Ailus
@ 2025-07-31  9:31     ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-31  9:31 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Sakari Ailus for your review

On 7/28/2025 3:28 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
>> +struct isp4phy_mipi_reg_seq {
>> +	u16 addr;
>> +	u16 mask;
>> +	u16 data;
>> +};
>> +

[snip]

>> +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;
>> +};
> 
> One more thing. Is there an endianness issue here?
> 
> Overall the CPU endianness may be big or little while the device endianness
> is little, presumably. You should use __le* types and functions to convert
> the endianness when dealing with the messages to and from the device.
> 
Good consideration, no endianness issue here because AMD APU is little 
endian x64 arch which aligns with the device endianness, so, no extra 
conversion is needed

Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-31  0:34       ` Sultan Alsawaf
@ 2025-07-31  9:45         ` Du, Bin
  2025-08-11  6:02         ` Sultan Alsawaf
  1 sibling, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-07-31  9:45 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Thanks Sultan.

On 7/31/2025 8:34 AM, Sultan Alsawaf wrote:
> On Tue, Jul 29, 2025 at 03:43:14PM +0800, Du, Bin wrote:
>> Hi Sultan, really appreciate your time and effort
>>
>> On 7/28/2025 3:04 PM, Sultan Alsawaf wrote:
>>> I found more refcounting issues in addition to the ones from my other emails
>>> while trying to make my webcam work:
>>>

[snip]
>>   static const struct vb2_ops isp4vid_qops = {
>>   	.queue_setup = isp4vid_qops_queue_setup,
>> -	.buf_cleanup = isp4vid_qops_buffer_cleanup,
>>   	.buf_queue = isp4vid_qops_buffer_queue,
>>   	.start_streaming = isp4vid_qops_start_streaming,
>>   	.stop_streaming = isp4vid_qops_stop_streaming,
>> -- 
>> 2.34.1
> 
> The patch looks correct. I will get back to you on this after doing some testing
> myself.
> 
> FYI, I can only test these changes with the old isp4 driver right now, since the
> new isp4 driver doesn't work for me as mentioned in my other email. So far,
> something does seem wrong after these changes I suggested because they break the
> camera on the old isp4 driver too.
> 
> Sultan
Yes, seems so. At the same time, we are checking the new upstream isp4 
driver

Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-31  0:30                   ` Sultan Alsawaf
@ 2025-07-31 10:04                     ` Du, Bin
  2025-08-04  3:32                       ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-07-31 10:04 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Thanks Sultan for your test

On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
> On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
>> On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
>>> On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
>>>> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
>>>>> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>>>>>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>>>>>> Thanks Sultan, please see my comments
>>>>>>>
>>>>>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>>>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>>>>>
>>>>>>>>>> I cannot for the life of me get the webcam working under Linux. The webcam works
>>>>>>>>>> under Windows so it's not a hardware issue.
>>>>>>>>>>
>>>>>>>>>> With this patchset and all of the patches you link here applied to 6.15, I get
>>>>>>>>>> the following errors:
>>>>>>>>>>        [   11.970038] amd_isp_i2c_designware amd_isp_i2c_designware: Unknown Synopsys component type: 0xffffffff
>>>>>>>>>>        [   11.973162] amd_isp_i2c_designware amd_isp_i2c_designware: error -19: i2c_dw_probe failed
>>>>>>>>>>
>>>>>>>>>> With the old ispkernel code from February [1] applied on 6.15, the webcam
>>>>>>>>>> indicator LED lights up but there's no image. I see these messages at boot:
>>>>>>>>>>        [    9.449005] amd_isp_capture amd_isp_capture.1.auto: amdgpu: AMD ISP v4l2 device registered
>>>>>>>>>>        [    9.489005] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: The OV05 sensor device is added to the ISP I2C bus
>>>>>>>>>>        [    9.529012] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>>>>>>>>        [    9.554046] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>>>>>        [    9.554174] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout while trying to abort current transfer
>>>>>>>>>>        [    9.580022] amd_isp_i2c_designware amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>>>>>
>>>>>>>>>> And then the kernel crashes due to the same use-after-free issues I pointed out
>>>>>>>>>> in my other email [2].
>>>>>>>>>>
>>>>>>>>>> Any idea what's going on?
>>>>>>>>>>
>>>>>>>>>> [1] https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>>>>>> Hi Sultan,
>>>>>>>>>
>>>>>>>>> [1] is for kernel 6.8, believe it can't be applied to 6.15. We didn't verify
>>>>>>>>> on 6.15 but we are really glad to help, would you please provide some info,
>>>>>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>>>>>> 2. 6.15, do you mean https://github.com/torvalds/linux/tree/v6.15 ?
>>>>>>>>>
>>>>>>>>> After your confirmation, we'll see what we can do to enable your camera
>>>>>>>>> quickly and easily
>>>>>>>>>
>>>>>>>>> Regards,
>>>>>>>>> Bin
>>>>>>>>
>>>>>>>> Thank you, Bin!
>>>>>>>>
>>>>>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>>>>>> 2. Yes, here is my kernel source [2].
>>>>>>>>
>>>>>>>> I have some more findings:
>>>>>>>>
>>>>>>>> Currently, the first blocking issue is that the I2C adapter fails to initialize.
>>>>>>>> This is because the ISP tile isn't powered on.
>>>>>>>>
>>>>>>>> I noticed that in the old version of amd_isp_i2c_designware [3], there were
>>>>>>>> calls to isp_power_set(), which is available in the old ISP4 sources [4].
>>>>>>>> Without isp_power_set(), the I2C adapter always fails to initialize for me.
>>>>>>>>
>>>>>>>> How is the ISP tile supposed to get powered on in the current ISP4 code?
>>>>>>>>
>>>>>>> You are correct, yes, i believe the I2C adapter failure is caused by ISP not
>>>>>>> being powered up. Currently in latest code, isp_power_set is no longer
>>>>>>> available, instead, we implemented genPD for ISP in amdgpu
>>>>>>> https://lore.kernel.org/all/20250618221923.3944751-1-pratap.nirujogi@amd.com/
>>>>>>> Both amd_isp_i2c and amd_isp_capture are in the power domain and use the
>>>>>>> standard runtime PM API to do the power control
>>>>>>
>>>>>> Thanks for that link, I found it along with another patch on the list to make
>>>>>> the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD device").
>>>>>>
>>>>>>>> Also, I noticed that the driver init ordering matters between all of the drivers
>>>>>>>> needed for the ISP4 camera. In particular, amd_isp_i2c_designware and amd_isp4
>>>>>>>> must be initialized before amd_capture, otherwise amd_capture will fail to find
>>>>>>>> the fwnode properties for the OV05C10 device attached to the I2C bus.
>>>>>>>>
>>>>>>>> But there is no driver init ordering enforced, which also caused some issues for
>>>>>>>> me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) should be used
>>>>>>>> to ensure each driver waits for its dependencies to init first?
>>>>>>>>
>>>>>>> amd_isp_capture only has dependency on amd_isp4 which is the ACPI platform
>>>>>>> driver, it is init before amd_isp_catpure.
>>>>>>> Do you see in your side the amd_capture probe failure caused by failing to
>>>>>>> read fwnode properties? If that's the case please help to check if amd_isp4
>>>>>>> is loaded successfully
>>>>>>
>>>>>> I got much further now: there aren't any driver initialization errors, but when
>>>>>> I open the camera, there's no image. The camera LED turns on so it's active.
>>>>>>
>>>>>> And then shortly afterwards, amdgpu dies and the entire system freezes.
>>>>>>
>>>>>> I've attached my full dmesg, please let me know what you think. Thanks!
>>>>>
>>>>> I almost forgot, here is my current kernel tree:
>>>>> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-sultan-isp4
>>>>>
>>>>> Sultan
>>>>
>>>> Thanks Sultan, yes, seems much close to the final success. Will have some
>>>> internal discussion.
>>>
>>> I got the webcam working. The same bug happened when I tried Ubuntu's linux-oem
>>> kernel, which made me think that the issue was firmware.
>>>
>>> And indeed, the culprit was a firmware update from February. I bisected
>>> linux-firmware and found the commit which broke the webcam for me:
>>>
>>> 	commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
>>> 	Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>> 	Date:   Wed Feb 19 12:16:51 2025 -0500
>>>
>>> 	    amdgpu: Update ISP FW for isp v4.1.1
>>> 	
>>> 	    From internal git commit:
>>> 	    5058202443e08a673b6772ea6339efb50853be28
>>> 	
>>> 	    Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>
>>> 	 amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
>>> 	 1 file changed, 0 insertions(+), 0 deletions(-)
>>>
>>> Downgrading firmware to before that commit fixes the webcam. Any idea why?
>>>
>>> Thanks,
>>> Sultan
>>
>> So, can i say the working firmware binary is this one?
>>
>> Commit 8f070131
>> amdgpu: Update ISP FW for isp v4.1.1
>>
>>  From internal git commit:
>> 39b007366cc76ef8c65e3bc6220ccb213f4861fb
>>
>> Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> 
> Correct.
> 
>> There are too many changes between them, so i can't tell exactly which
>> change caused this. So, from my side
>> 1. Will try these two firmware to see if we have the same issue.
>> 2. It has been quite a long time since last release, will see if need to
>> release a latest one.
> 
> Thanks. It was a quick bisect for me, so I'm happy to help test if a bisect
> between those two internal git commits is needed.
> 
Really appreciate your test.
> In case it makes a difference, I have the laptop with the 2.8K OLED display. I'm
> aware there is one other display variant on other SKUs, which is a WUXGA IPS.
> 
Good to know, I believe it won't make any difference for ISP

> Also, with that old firmware, my camera only works with the old isp4 driver from
> that Linux_ISP_Kernel repo (which is the same isp4 driver used in Ubuntu's
> linux-oem kernel). Does the new isp4 driver you've submitted here require newer
> firmware than the old driver located in Linux_ISP_Kernel?
> 
> Sultan

We had a try, yes, both of the old FW can't work on the new ISP4 driver, 
as you know, for the last months, we did lots of driver modifications 
for upstream and cause it incompatible with old FW.
Now, under internal discussion to upstream a new FW to support the new 
ISP driver

Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-07-31 10:04                     ` Du, Bin
@ 2025-08-04  3:32                       ` Du, Bin
  2025-08-04  4:25                         ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-04  3:32 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

Hi Sultan,

This is the conclusion of your test,
Driver: 
https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
[1] It works on FW      8f070131(ext):39b00736(int)
[2] It can't work on FW 1cc8c1bf(ext):50582024(int)

Would you please help to check if CONFIG_VIDEO_OV05C is defined not in 
the .config file when building the kernel? Our assumption is to make [1] 
work, CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work, 
CONFIG_VIDEO_OV05C should be defined.

Regards,
Bin

On 7/31/2025 6:04 PM, Du, Bin wrote:
> Thanks Sultan for your test
> 
> On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
>> On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
>>> On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
>>>> On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
>>>>> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
>>>>>> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>>>>>>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>>>>>>> Thanks Sultan, please see my comments
>>>>>>>>
>>>>>>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>>>>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>>>>>>
>>>>>>>>>>> I cannot for the life of me get the webcam working under 
>>>>>>>>>>> Linux. The webcam works
>>>>>>>>>>> under Windows so it's not a hardware issue.
>>>>>>>>>>>
>>>>>>>>>>> With this patchset and all of the patches you link here 
>>>>>>>>>>> applied to 6.15, I get
>>>>>>>>>>> the following errors:
>>>>>>>>>>>        [   11.970038] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware: Unknown Synopsys component type: 
>>>>>>>>>>> 0xffffffff
>>>>>>>>>>>        [   11.973162] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware: error -19: i2c_dw_probe failed
>>>>>>>>>>>
>>>>>>>>>>> With the old ispkernel code from February [1] applied on 
>>>>>>>>>>> 6.15, the webcam
>>>>>>>>>>> indicator LED lights up but there's no image. I see these 
>>>>>>>>>>> messages at boot:
>>>>>>>>>>>        [    9.449005] amd_isp_capture amd_isp_capture.1.auto: 
>>>>>>>>>>> amdgpu: AMD ISP v4l2 device registered
>>>>>>>>>>>        [    9.489005] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware.2.auto: The OV05 sensor device is 
>>>>>>>>>>> added to the ISP I2C bus
>>>>>>>>>>>        [    9.529012] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware.2.auto: timeout while trying to abort 
>>>>>>>>>>> current transfer
>>>>>>>>>>>        [    9.554046] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>>>>>>        [    9.554174] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware.2.auto: timeout while trying to abort 
>>>>>>>>>>> current transfer
>>>>>>>>>>>        [    9.580022] amd_isp_i2c_designware 
>>>>>>>>>>> amd_isp_i2c_designware.2.auto: timeout in disabling adapter
>>>>>>>>>>>
>>>>>>>>>>> And then the kernel crashes due to the same use-after-free 
>>>>>>>>>>> issues I pointed out
>>>>>>>>>>> in my other email [2].
>>>>>>>>>>>
>>>>>>>>>>> Any idea what's going on?
>>>>>>>>>>>
>>>>>>>>>>> [1] https://github.com/amd/Linux_ISP_Kernel/commit/ 
>>>>>>>>>>> c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>>>>>>> Hi Sultan,
>>>>>>>>>>
>>>>>>>>>> [1] is for kernel 6.8, believe it can't be applied to 6.15. We 
>>>>>>>>>> didn't verify
>>>>>>>>>> on 6.15 but we are really glad to help, would you please 
>>>>>>>>>> provide some info,
>>>>>>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>>>>>>> 2. 6.15, do you mean https://github.com/torvalds/linux/tree/ 
>>>>>>>>>> v6.15 ?
>>>>>>>>>>
>>>>>>>>>> After your confirmation, we'll see what we can do to enable 
>>>>>>>>>> your camera
>>>>>>>>>> quickly and easily
>>>>>>>>>>
>>>>>>>>>> Regards,
>>>>>>>>>> Bin
>>>>>>>>>
>>>>>>>>> Thank you, Bin!
>>>>>>>>>
>>>>>>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>>>>>>> 2. Yes, here is my kernel source [2].
>>>>>>>>>
>>>>>>>>> I have some more findings:
>>>>>>>>>
>>>>>>>>> Currently, the first blocking issue is that the I2C adapter 
>>>>>>>>> fails to initialize.
>>>>>>>>> This is because the ISP tile isn't powered on.
>>>>>>>>>
>>>>>>>>> I noticed that in the old version of amd_isp_i2c_designware 
>>>>>>>>> [3], there were
>>>>>>>>> calls to isp_power_set(), which is available in the old ISP4 
>>>>>>>>> sources [4].
>>>>>>>>> Without isp_power_set(), the I2C adapter always fails to 
>>>>>>>>> initialize for me.
>>>>>>>>>
>>>>>>>>> How is the ISP tile supposed to get powered on in the current 
>>>>>>>>> ISP4 code?
>>>>>>>>>
>>>>>>>> You are correct, yes, i believe the I2C adapter failure is 
>>>>>>>> caused by ISP not
>>>>>>>> being powered up. Currently in latest code, isp_power_set is no 
>>>>>>>> longer
>>>>>>>> available, instead, we implemented genPD for ISP in amdgpu
>>>>>>>> https://lore.kernel.org/all/20250618221923.3944751-1- 
>>>>>>>> pratap.nirujogi@amd.com/
>>>>>>>> Both amd_isp_i2c and amd_isp_capture are in the power domain and 
>>>>>>>> use the
>>>>>>>> standard runtime PM API to do the power control
>>>>>>>
>>>>>>> Thanks for that link, I found it along with another patch on the 
>>>>>>> list to make
>>>>>>> the fwnode work ("drm/amd/amdgpu: Initialize swnode for ISP MFD 
>>>>>>> device").
>>>>>>>
>>>>>>>>> Also, I noticed that the driver init ordering matters between 
>>>>>>>>> all of the drivers
>>>>>>>>> needed for the ISP4 camera. In particular, 
>>>>>>>>> amd_isp_i2c_designware and amd_isp4
>>>>>>>>> must be initialized before amd_capture, otherwise amd_capture 
>>>>>>>>> will fail to find
>>>>>>>>> the fwnode properties for the OV05C10 device attached to the 
>>>>>>>>> I2C bus.
>>>>>>>>>
>>>>>>>>> But there is no driver init ordering enforced, which also 
>>>>>>>>> caused some issues for
>>>>>>>>> me until I figured it out. Maybe probe deferral (-EPROBE_DEFER) 
>>>>>>>>> should be used
>>>>>>>>> to ensure each driver waits for its dependencies to init first?
>>>>>>>>>
>>>>>>>> amd_isp_capture only has dependency on amd_isp4 which is the 
>>>>>>>> ACPI platform
>>>>>>>> driver, it is init before amd_isp_catpure.
>>>>>>>> Do you see in your side the amd_capture probe failure caused by 
>>>>>>>> failing to
>>>>>>>> read fwnode properties? If that's the case please help to check 
>>>>>>>> if amd_isp4
>>>>>>>> is loaded successfully
>>>>>>>
>>>>>>> I got much further now: there aren't any driver initialization 
>>>>>>> errors, but when
>>>>>>> I open the camera, there's no image. The camera LED turns on so 
>>>>>>> it's active.
>>>>>>>
>>>>>>> And then shortly afterwards, amdgpu dies and the entire system 
>>>>>>> freezes.
>>>>>>>
>>>>>>> I've attached my full dmesg, please let me know what you think. 
>>>>>>> Thanks!
>>>>>>
>>>>>> I almost forgot, here is my current kernel tree:
>>>>>> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16- 
>>>>>> sultan-isp4
>>>>>>
>>>>>> Sultan
>>>>>
>>>>> Thanks Sultan, yes, seems much close to the final success. Will 
>>>>> have some
>>>>> internal discussion.
>>>>
>>>> I got the webcam working. The same bug happened when I tried 
>>>> Ubuntu's linux-oem
>>>> kernel, which made me think that the issue was firmware.
>>>>
>>>> And indeed, the culprit was a firmware update from February. I bisected
>>>> linux-firmware and found the commit which broke the webcam for me:
>>>>
>>>>     commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
>>>>     Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>     Date:   Wed Feb 19 12:16:51 2025 -0500
>>>>
>>>>         amdgpu: Update ISP FW for isp v4.1.1
>>>>
>>>>         From internal git commit:
>>>>         5058202443e08a673b6772ea6339efb50853be28
>>>>
>>>>         Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>
>>>>      amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
>>>>      1 file changed, 0 insertions(+), 0 deletions(-)
>>>>
>>>> Downgrading firmware to before that commit fixes the webcam. Any 
>>>> idea why?
>>>>
>>>> Thanks,
>>>> Sultan
>>>
>>> So, can i say the working firmware binary is this one?
>>>
>>> Commit 8f070131
>>> amdgpu: Update ISP FW for isp v4.1.1
>>>
>>>  From internal git commit:
>>> 39b007366cc76ef8c65e3bc6220ccb213f4861fb
>>>
>>> Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>
>> Correct.
>>
>>> There are too many changes between them, so i can't tell exactly which
>>> change caused this. So, from my side
>>> 1. Will try these two firmware to see if we have the same issue.
>>> 2. It has been quite a long time since last release, will see if need to
>>> release a latest one.
>>
>> Thanks. It was a quick bisect for me, so I'm happy to help test if a 
>> bisect
>> between those two internal git commits is needed.
>>
> Really appreciate your test.
>> In case it makes a difference, I have the laptop with the 2.8K OLED 
>> display. I'm
>> aware there is one other display variant on other SKUs, which is a 
>> WUXGA IPS.
>>
> Good to know, I believe it won't make any difference for ISP
> 
>> Also, with that old firmware, my camera only works with the old isp4 
>> driver from
>> that Linux_ISP_Kernel repo (which is the same isp4 driver used in 
>> Ubuntu's
>> linux-oem kernel). Does the new isp4 driver you've submitted here 
>> require newer
>> firmware than the old driver located in Linux_ISP_Kernel?
>>
>> Sultan
> 
> We had a try, yes, both of the old FW can't work on the new ISP4 driver, 
> as you know, for the last months, we did lots of driver modifications 
> for upstream and cause it incompatible with old FW.
> Now, under internal discussion to upstream a new FW to support the new 
> ISP driver
> 
> Regards,
> Bin
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-04  3:32                       ` Du, Bin
@ 2025-08-04  4:25                         ` Sultan Alsawaf
  2025-08-08  9:11                           ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-04  4:25 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
> On 7/31/2025 6:04 PM, Du, Bin wrote:
> > Thanks Sultan for your test
> > 
> > On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
> > > On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
> > > > On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
> > > > > On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
> > > > > > On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> > > > > > > On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> > > > > > > > On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > > > > > > > > Thanks Sultan, please see my comments
> > > > > > > > > 
> > > > > > > > > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > > > > > > > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > > > > > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > > > > > > > > 
> > > > > > > > > > > > I cannot for the life of me get
> > > > > > > > > > > > the webcam working under Linux.
> > > > > > > > > > > > The webcam works
> > > > > > > > > > > > under Windows so it's not a hardware issue.
> > > > > > > > > > > > 
> > > > > > > > > > > > With this patchset and all of
> > > > > > > > > > > > the patches you link here
> > > > > > > > > > > > applied to 6.15, I get
> > > > > > > > > > > > the following errors:
> > > > > > > > > > > >        [   11.970038]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware: Unknown
> > > > > > > > > > > > Synopsys component type:
> > > > > > > > > > > > 0xffffffff
> > > > > > > > > > > >        [   11.973162]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware: error
> > > > > > > > > > > > -19: i2c_dw_probe failed
> > > > > > > > > > > > 
> > > > > > > > > > > > With the old ispkernel code from
> > > > > > > > > > > > February [1] applied on 6.15,
> > > > > > > > > > > > the webcam
> > > > > > > > > > > > indicator LED lights up but
> > > > > > > > > > > > there's no image. I see these
> > > > > > > > > > > > messages at boot:
> > > > > > > > > > > >        [    9.449005]
> > > > > > > > > > > > amd_isp_capture
> > > > > > > > > > > > amd_isp_capture.1.auto: amdgpu:
> > > > > > > > > > > > AMD ISP v4l2 device registered
> > > > > > > > > > > >        [    9.489005]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > The OV05 sensor device is added
> > > > > > > > > > > > to the ISP I2C bus
> > > > > > > > > > > >        [    9.529012]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > current transfer
> > > > > > > > > > > >        [    9.554046]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > >        [    9.554174]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > current transfer
> > > > > > > > > > > >        [    9.580022]
> > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > 
> > > > > > > > > > > > And then the kernel crashes due
> > > > > > > > > > > > to the same use-after-free
> > > > > > > > > > > > issues I pointed out
> > > > > > > > > > > > in my other email [2].
> > > > > > > > > > > > 
> > > > > > > > > > > > Any idea what's going on?
> > > > > > > > > > > > 
> > > > > > > > > > > > [1]
> > > > > > > > > > > > https://github.com/amd/Linux_ISP_Kernel/commit/
> > > > > > > > > > > > c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > > > > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > > > > > > > > Hi Sultan,
> > > > > > > > > > > 
> > > > > > > > > > > [1] is for kernel 6.8, believe it
> > > > > > > > > > > can't be applied to 6.15. We didn't
> > > > > > > > > > > verify
> > > > > > > > > > > on 6.15 but we are really glad to
> > > > > > > > > > > help, would you please provide some
> > > > > > > > > > > info,
> > > > > > > > > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > > > > > > > > 2. 6.15, do you mean
> > > > > > > > > > > https://github.com/torvalds/linux/tree/
> > > > > > > > > > > v6.15 ?
> > > > > > > > > > > 
> > > > > > > > > > > After your confirmation, we'll see
> > > > > > > > > > > what we can do to enable your camera
> > > > > > > > > > > quickly and easily
> > > > > > > > > > > 
> > > > > > > > > > > Regards,
> > > > > > > > > > > Bin
> > > > > > > > > > 
> > > > > > > > > > Thank you, Bin!
> > > > > > > > > > 
> > > > > > > > > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > > > > > > > > 2. Yes, here is my kernel source [2].
> > > > > > > > > > 
> > > > > > > > > > I have some more findings:
> > > > > > > > > > 
> > > > > > > > > > Currently, the first blocking issue is
> > > > > > > > > > that the I2C adapter fails to
> > > > > > > > > > initialize.
> > > > > > > > > > This is because the ISP tile isn't powered on.
> > > > > > > > > > 
> > > > > > > > > > I noticed that in the old version of
> > > > > > > > > > amd_isp_i2c_designware [3], there were
> > > > > > > > > > calls to isp_power_set(), which is
> > > > > > > > > > available in the old ISP4 sources [4].
> > > > > > > > > > Without isp_power_set(), the I2C adapter
> > > > > > > > > > always fails to initialize for me.
> > > > > > > > > > 
> > > > > > > > > > How is the ISP tile supposed to get
> > > > > > > > > > powered on in the current ISP4 code?
> > > > > > > > > > 
> > > > > > > > > You are correct, yes, i believe the I2C
> > > > > > > > > adapter failure is caused by ISP not
> > > > > > > > > being powered up. Currently in latest code,
> > > > > > > > > isp_power_set is no longer
> > > > > > > > > available, instead, we implemented genPD for ISP in amdgpu
> > > > > > > > > https://lore.kernel.org/all/20250618221923.3944751-1-
> > > > > > > > > pratap.nirujogi@amd.com/
> > > > > > > > > Both amd_isp_i2c and amd_isp_capture are in
> > > > > > > > > the power domain and use the
> > > > > > > > > standard runtime PM API to do the power control
> > > > > > > > 
> > > > > > > > Thanks for that link, I found it along with
> > > > > > > > another patch on the list to make
> > > > > > > > the fwnode work ("drm/amd/amdgpu: Initialize
> > > > > > > > swnode for ISP MFD device").
> > > > > > > > 
> > > > > > > > > > Also, I noticed that the driver init
> > > > > > > > > > ordering matters between all of the
> > > > > > > > > > drivers
> > > > > > > > > > needed for the ISP4 camera. In
> > > > > > > > > > particular, amd_isp_i2c_designware and
> > > > > > > > > > amd_isp4
> > > > > > > > > > must be initialized before amd_capture,
> > > > > > > > > > otherwise amd_capture will fail to find
> > > > > > > > > > the fwnode properties for the OV05C10
> > > > > > > > > > device attached to the I2C bus.
> > > > > > > > > > 
> > > > > > > > > > But there is no driver init ordering
> > > > > > > > > > enforced, which also caused some issues
> > > > > > > > > > for
> > > > > > > > > > me until I figured it out. Maybe probe
> > > > > > > > > > deferral (-EPROBE_DEFER) should be used
> > > > > > > > > > to ensure each driver waits for its dependencies to init first?
> > > > > > > > > > 
> > > > > > > > > amd_isp_capture only has dependency on
> > > > > > > > > amd_isp4 which is the ACPI platform
> > > > > > > > > driver, it is init before amd_isp_catpure.
> > > > > > > > > Do you see in your side the amd_capture
> > > > > > > > > probe failure caused by failing to
> > > > > > > > > read fwnode properties? If that's the case
> > > > > > > > > please help to check if amd_isp4
> > > > > > > > > is loaded successfully
> > > > > > > > 
> > > > > > > > I got much further now: there aren't any driver
> > > > > > > > initialization errors, but when
> > > > > > > > I open the camera, there's no image. The camera
> > > > > > > > LED turns on so it's active.
> > > > > > > > 
> > > > > > > > And then shortly afterwards, amdgpu dies and the
> > > > > > > > entire system freezes.
> > > > > > > > 
> > > > > > > > I've attached my full dmesg, please let me know
> > > > > > > > what you think. Thanks!
> > > > > > > 
> > > > > > > I almost forgot, here is my current kernel tree:
> > > > > > > https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
> > > > > > > sultan-isp4
> > > > > > > 
> > > > > > > Sultan
> > > > > > 
> > > > > > Thanks Sultan, yes, seems much close to the final
> > > > > > success. Will have some
> > > > > > internal discussion.
> > > > > 
> > > > > I got the webcam working. The same bug happened when I tried
> > > > > Ubuntu's linux-oem
> > > > > kernel, which made me think that the issue was firmware.
> > > > > 
> > > > > And indeed, the culprit was a firmware update from February. I bisected
> > > > > linux-firmware and found the commit which broke the webcam for me:
> > > > > 
> > > > >     commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
> > > > >     Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > >     Date:   Wed Feb 19 12:16:51 2025 -0500
> > > > > 
> > > > >         amdgpu: Update ISP FW for isp v4.1.1
> > > > > 
> > > > >         From internal git commit:
> > > > >         5058202443e08a673b6772ea6339efb50853be28
> > > > > 
> > > > >         Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > 
> > > > >      amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
> > > > >      1 file changed, 0 insertions(+), 0 deletions(-)
> > > > > 
> > > > > Downgrading firmware to before that commit fixes the webcam.
> > > > > Any idea why?
> > > > > 
> > > > > Thanks,
> > > > > Sultan
> > > > 
> > > > So, can i say the working firmware binary is this one?
> > > > 
> > > > Commit 8f070131
> > > > amdgpu: Update ISP FW for isp v4.1.1
> > > > 
> > > >  From internal git commit:
> > > > 39b007366cc76ef8c65e3bc6220ccb213f4861fb
> > > > 
> > > > Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > 
> > > Correct.
> > > 
> > > > There are too many changes between them, so i can't tell exactly which
> > > > change caused this. So, from my side
> > > > 1. Will try these two firmware to see if we have the same issue.
> > > > 2. It has been quite a long time since last release, will see if need to
> > > > release a latest one.
> > > 
> > > Thanks. It was a quick bisect for me, so I'm happy to help test if a
> > > bisect
> > > between those two internal git commits is needed.
> > > 
> > Really appreciate your test.
> > > In case it makes a difference, I have the laptop with the 2.8K OLED
> > > display. I'm
> > > aware there is one other display variant on other SKUs, which is a
> > > WUXGA IPS.
> > > 
> > Good to know, I believe it won't make any difference for ISP
> > 
> > > Also, with that old firmware, my camera only works with the old isp4
> > > driver from
> > > that Linux_ISP_Kernel repo (which is the same isp4 driver used in
> > > Ubuntu's
> > > linux-oem kernel). Does the new isp4 driver you've submitted here
> > > require newer
> > > firmware than the old driver located in Linux_ISP_Kernel?
> > > 
> > > Sultan
> > 
> > We had a try, yes, both of the old FW can't work on the new ISP4 driver,
> > as you know, for the last months, we did lots of driver modifications
> > for upstream and cause it incompatible with old FW.
> > Now, under internal discussion to upstream a new FW to support the new
> > ISP driver
> > 
> > Regards,
> > Bin
> > 
> > Hi Sultan,
> 
> This is the conclusion of your test,
> Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> [1] It works on FW      8f070131(ext):39b00736(int)
> [2] It can't work on FW 1cc8c1bf(ext):50582024(int)

Correct.

> Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
> .config file when building the kernel? Our assumption is to make [1] work,
> CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
> CONFIG_VIDEO_OV05C should be defined.

Yes, it is enabled and I have only tested with it enabled:

    $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config 
    CONFIG_VIDEO_OV05C=m

That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
I tested by running the following commands:

    git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
    cd linux-oem-6.14
    python debian/scripts/misc/annotations -e --arch amd64 > .config
    make olddefconfig

Let me know if that works.

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-07-28  6:33   ` Sakari Ailus
@ 2025-08-05  9:53     ` Du, Bin
  2025-08-05 10:53       ` Laurent Pinchart
  2025-08-05 10:39     ` Laurent Pinchart
  1 sibling, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-05  9:53 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Many thanks Sakari Ailus for your careful review

On 7/28/2025 2:33 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
>> 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 <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   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 <linux/delay.h>
>> +#include <linux/device.h>
>> +
>> +#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
> 
> Please align the macro bodies to the same column.
> 

Sure, will do that in the next patch

> Also using a descriptive prefix for these (such as AMDISP4) would seem like
> a reasonable idea. The same goes for the other macros used by the driver,
> too.
> 

Sure, will add prefix ISP4PHY_ as prefix of all macros in this file. 
Macros in other files follow the same naming convension(using file name 
as prefix).

> Speaking of macro names, some of the names below look quite random. Are
> these from a hardware datasheet (or something alike)? I might consider
> sanitising them. Some are also not in form fit for use in drivers, e.g. if
> you have many of something, then the number should be an argument to the
> macro, not part of the macro name, e.g. configuration related to lanes --
> if feasible.
> 

Yes, they are from HW datasheet and reference. Not sure if I got your 
point, different number in the macro makes different macro standing for 
different registers or fields, no idea how to make the number as 
parameter. Would you mind to give a detailed sample based on current code?

>> +
>> +#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;
> 
> Please pad these -- I don't think the ABI otherwise requires they're in a
> particular location of the container (u32).
> 

Sure, will do that in the next patch

>> +	} 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;
> 
> u16 would seem appropriate here.
> 

I think u32 here is similar as u32 enableclk : 1 or u32 rxdatawidthhs_0 
: 2, indicate an unsigned value, if change to u16, : 16 will be no need, 
So prefer to keeping it and adding u32 reserved : 16 after it.

>> +	} bit;
>> +	u32 value;
>> +};
>> +
>> +union isp4phy_mipi_ind_data {
>> +	struct {
>> +		u32 data : 16;
> 
> Ditto.
> 

Ditto

>> +	} 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;
> 
> "reserved"?
> 

Sure, will fix it in the next patch

>> +	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,
> 
> That's an interesting way to prefill structs. I don't think these macros
> expand to valid pointers.
> 

Yes, these are valid pointers, but they are not pointing to system 
memory, they are phy registers address, can be accessed by adding the 
mmio base.

>> +};
>> +
>> +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)(&reg->isp_mipi_phy_ind_idx), addr);
>> +	return (u16)isp4hw_rreg(base, (uintptr_t)(&reg->isp_mipi_phy_ind_data));
> 
> Redundant parentheses.
> 

Sure, will remove it and all others in the next patch

>> +}
>> +
>> +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)(&reg->isp_mipi_phy_ind_idx), addr);
>> +	isp4hw_wreg(base, (uintptr_t)(&reg->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);
> 
> __ffs()?
> 

Sure, will do that in the next patch

>> +	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;
> 
> unsigned int?
> 

Sure, will modify to use size_t in the next patch

>> +	     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;
> 
> I think you could do this on a single line as well.
> 

Sure, will do that in the next patch

>> +
>> +	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);
>> +	}
> 
> Could you do this using a loop instead? With a bit saner macros, that
> should be quite a bit easier, too.
> 

No very sure how, would you mind to give a sample?

>> +}
>> +
>> +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++)
> 
> Unsigned int for these, too, please.
>

Sure, will modify to use size_t in the next patch
>> +		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;
>> +	}
> 
> Please add an array for the values and implement this as a loop instead.
> 

Sure, will do that in the next patch

>> +
>> +	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;
> 
> Ditto. Or maybe use ilog2()?
> 

I'd prefer to using the hex value directly because it's more readable, 
what do you think?

>> +
>> +	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;
> 
> You could just as well do these without a temporary variable.
> 

Sure, will remove it in the next patch

>> +}
>> +
>> +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));
> 
> Would assigning phycfg to { } do the job?
> 

Sure, will do that in the next patch

>> +
>> +	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};
> 
> { } is enough.
> 
> 

Sure, will do that in the next patch

>> +
>> +	/* 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)*/
> 
> /* Single-line comment. */
> 

Sure, will modify in the next patch

>> +	/** 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).
>> +	 */
> 
> /*
>   * Multi-line
>   * comment.
>   */
> 

Sure, will modify in the next patch

>> +	/* 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);
> 
> Why uintptr_t btw.? This seems to be a recurring pattern.
> 

To make safe conversion between pointer and big enough integer, removing 
it will result in compiling warning.

>> +		dev_dbg(dev, "Wait for phyReady: 0x%x\n",
>> +			phy_reg.isp_mipi_phy7.value);
>> +	} while (phy_reg.isp_mipi_phy7.bit.ready != 1);
> 
> Use read_poll_timeout() maybe?
> 

Sure, will modify in the next patch

>> +
>> +	/** 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,
> 
> How about using "amdisp4" as the prefix for the driver's symbol names? Just
> "isp4" is very generic.
> 

Actually all symbols in this driver follow the same convention, just use 
file name as prefix, the reason of not adding amd is 1. All files are 
located under amd folder, so no confusion. 2. To make symbol name short 
3. No export symbol from this driver, if there is, the export symbol 
should add amd as part of prefix. Is that acceptible to you?

>> +		  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");
> 
> Maybe use a similar format than for the 4-lane case?
> 

Not very sure your meaning, will rewrithe this part using switch like
switch (phy_id) {
	case ISP_MIPI_PHY_ID_0:
	case ISP_MIPI_PHY_ID_1:
		if (lane_num > 4) {
			dev_err(dev, "fail invalid lane number %u for phy%d\n", lane_num, 
phy_id);
			return -EINVAL;
		}
		break;
	case ISP_MIPI_PHY_ID_2:
		if (lane_num > 2) {
			dev_err(dev, "fail invalid lane number %u for phy%d\n", lane_num, 
phy_id);
			return -EINVAL;
		}
		break;
	default:
		dev_err(dev, "fail invalid phy id %d\n", phy_id);
		return -EINVAL;

>> +		return -EINVAL;
>> +	}
>> +
>> +	if (phy_id == 0 && lane_num > 4) {
>> +		dev_err(dev, "fail invalid lane number %u for phy0\n",
>> +			lane_num);
>> +		return -EINVAL;
>> +	}
> 
> Maybe a switch for phy_id?
> 

Sure, as shown above, will do it in the next patch

>> +
>> +	return isp4phy_startup_seq_cdphy_rx(dev, base, phy_id, bit_rate, lane_num);
> 
> This line would benefit from wrapping.
> 

Do you mean wrap it into two lines? Seems oneline is better.

>> +}
>> +
>> +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));
> 
> Extra parentheses.
> 

Sure, will remove it in the next patch

>> +
>> +	/* 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),
> 
> Redundant parentheses.
> 

Sure, will remove it in the next patch

>> +		    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
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-07-28  6:33   ` Sakari Ailus
  2025-08-05  9:53     ` Du, Bin
@ 2025-08-05 10:39     ` Laurent Pinchart
  2025-08-06  9:45       ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Laurent Pinchart @ 2025-08-05 10:39 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Bin Du, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Mon, Jul 28, 2025 at 06:33:30AM +0000, Sakari Ailus wrote:
> On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
> > 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 <Bin.Du@amd.com>
> > Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> > ---
> >  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

[snip]

> > 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 @@

[snip]

> > +union isp4phy_mipi_0 {
> > +	struct {
> > +		u32 shutdownz : 1;
> > +		u32 rstz : 1;
> > +	} bit;
> > +	u32 value;
> > +};
> > +
> > +union isp4phy_mipi_1 {
> > +	struct {
> > +		u32 mode : 1;
> 
> Please pad these -- I don't think the ABI otherwise requires they're in a
> particular location of the container (u32).

Or better, ditch the structures, and use macros to define register
fields like all other drivers do.

> > +	} 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;
> 
> u16 would seem appropriate here.
> 
> > +	} bit;
> > +	u32 value;
> > +};
> > +
> > +union isp4phy_mipi_ind_data {
> > +	struct {
> > +		u32 data : 16;
> 
> Ditto.
> 
> > +	} bit;
> > +	u32 value;
> > +};
> > +
> > +union isp4phy_mipi_ind_wack {
> > +	struct {
> > +		u32 ack : 1;
> > +		u32 pslverr : 1;
> > +	} bit;
> > +	u32 value;
> > +};

[snip]

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-08-05  9:53     ` Du, Bin
@ 2025-08-05 10:53       ` Laurent Pinchart
  2025-08-06  9:56         ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Laurent Pinchart @ 2025-08-05 10:53 UTC (permalink / raw)
  To: Du, Bin
  Cc: Sakari Ailus, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Tue, Aug 05, 2025 at 05:53:30PM +0800, Du, Bin wrote:
> On 7/28/2025 2:33 PM, Sakari Ailus wrote:
> > On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
> >> 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 <Bin.Du@amd.com>
> >> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> >> ---
> >>   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 <linux/delay.h>
> >> +#include <linux/device.h>
> >> +
> >> +#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
> > 
> > Please align the macro bodies to the same column.
> > 
> 
> Sure, will do that in the next patch
> 
> > Also using a descriptive prefix for these (such as AMDISP4) would seem like
> > a reasonable idea. The same goes for the other macros used by the driver,
> > too.
> > 
> 
> Sure, will add prefix ISP4PHY_ as prefix of all macros in this file. 
> Macros in other files follow the same naming convension(using file name 
> as prefix).
> 
> > Speaking of macro names, some of the names below look quite random. Are
> > these from a hardware datasheet (or something alike)? I might consider
> > sanitising them. Some are also not in form fit for use in drivers, e.g. if
> > you have many of something, then the number should be an argument to the
> > macro, not part of the macro name, e.g. configuration related to lanes --
> > if feasible.
> > 
> 
> Yes, they are from HW datasheet and reference. Not sure if I got your 
> point, different number in the macro makes different macro standing for 
> different registers or fields, no idea how to make the number as 
> parameter. Would you mind to give a detailed sample based on current code?
> 
> >> +
> >> +#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;
> > 
> > Please pad these -- I don't think the ABI otherwise requires they're in a
> > particular location of the container (u32).
> > 
> 
> Sure, will do that in the next patch
> 
> >> +	} 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;
> > 
> > u16 would seem appropriate here.
> > 
> 
> I think u32 here is similar as u32 enableclk : 1 or u32 rxdatawidthhs_0 
> : 2, indicate an unsigned value, if change to u16, : 16 will be no need, 
> So prefer to keeping it and adding u32 reserved : 16 after it.
> 
> >> +	} bit;
> >> +	u32 value;
> >> +};
> >> +
> >> +union isp4phy_mipi_ind_data {
> >> +	struct {
> >> +		u32 data : 16;
> > 
> > Ditto.
> > 
> 
> Ditto
> 
> >> +	} 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;
> > 
> > "reserved"?
> > 
> 
> Sure, will fix it in the next patch
> 
> >> +	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,
> > 
> > That's an interesting way to prefill structs. I don't think these macros
> > expand to valid pointers.
> 
> Yes, these are valid pointers, but they are not pointing to system 
> memory, they are phy registers address, can be accessed by adding the 
> mmio base.

Please don't do that. Store register addresses in macros, and use them
through the code as appropriate. Stop passing the base mmio address
around through functions, store it in a PHY object, and pass that object
to the isp4phy_start() instead of a dev pointer, base pointer and phy
id.

> >> +};
> >> +
> >> +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)(&reg->isp_mipi_phy_ind_idx), addr);
> >> +	return (u16)isp4hw_rreg(base, (uintptr_t)(&reg->isp_mipi_phy_ind_data));
> > 
> > Redundant parentheses.
> > 
> 
> Sure, will remove it and all others in the next patch
> 
> >> +}
> >> +
> >> +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)(&reg->isp_mipi_phy_ind_idx), addr);
> >> +	isp4hw_wreg(base, (uintptr_t)(&reg->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);
> > 
> > __ffs()?
> > 
> 
> Sure, will do that in the next patch
> 
> >> +	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;
> > 
> > unsigned int?
> > 
> 
> Sure, will modify to use size_t in the next patch
> 
> >> +	     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;
> > 
> > I think you could do this on a single line as well.
> > 
> 
> Sure, will do that in the next patch
> 
> >> +
> >> +	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);
> >> +	}
> > 
> > Could you do this using a loop instead? With a bit saner macros, that
> > should be quite a bit easier, too.
> > 
> 
> No very sure how, would you mind to give a sample?
> 
> >> +}
> >> +
> >> +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++)
> > 
> > Unsigned int for these, too, please.
> >
> 
> Sure, will modify to use size_t in the next patch
> >> +		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;
> >> +	}
> > 
> > Please add an array for the values and implement this as a loop instead.
> > 
> 
> Sure, will do that in the next patch
> 
> >> +
> >> +	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;
> > 
> > Ditto. Or maybe use ilog2()?
> > 
> 
> I'd prefer to using the hex value directly because it's more readable, 
> what do you think?
> 
> >> +
> >> +	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;
> > 
> > You could just as well do these without a temporary variable.
> > 
> 
> Sure, will remove it in the next patch
> 
> >> +}
> >> +
> >> +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));
> > 
> > Would assigning phycfg to { } do the job?
> > 
> 
> Sure, will do that in the next patch
> 
> >> +
> >> +	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};
> > 
> > { } is enough.
> > 
> > 
> 
> Sure, will do that in the next patch
> 
> >> +
> >> +	/* 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)*/
> > 
> > /* Single-line comment. */
> > 
> 
> Sure, will modify in the next patch
> 
> >> +	/** 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).
> >> +	 */
> > 
> > /*
> >   * Multi-line
> >   * comment.
> >   */
> > 
> 
> Sure, will modify in the next patch
> 
> >> +	/* 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);
> > 
> > Why uintptr_t btw.? This seems to be a recurring pattern.
> > 
> 
> To make safe conversion between pointer and big enough integer, removing 
> it will result in compiling warning.
> 
> >> +		dev_dbg(dev, "Wait for phyReady: 0x%x\n",
> >> +			phy_reg.isp_mipi_phy7.value);
> >> +	} while (phy_reg.isp_mipi_phy7.bit.ready != 1);
> > 
> > Use read_poll_timeout() maybe?
> > 
> 
> Sure, will modify in the next patch
> 
> >> +
> >> +	/** 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,
> > 
> > How about using "amdisp4" as the prefix for the driver's symbol names? Just
> > "isp4" is very generic.
> > 
> 
> Actually all symbols in this driver follow the same convention, just use 
> file name as prefix, the reason of not adding amd is 1. All files are 
> located under amd folder, so no confusion. 2. To make symbol name short 
> 3. No export symbol from this driver, if there is, the export symbol 
> should add amd as part of prefix. Is that acceptible to you?
> 
> >> +		  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");
> > 
> > Maybe use a similar format than for the 4-lane case?
> > 
> 
> Not very sure your meaning, will rewrithe this part using switch like
> switch (phy_id) {
> 	case ISP_MIPI_PHY_ID_0:
> 	case ISP_MIPI_PHY_ID_1:
> 		if (lane_num > 4) {
> 			dev_err(dev, "fail invalid lane number %u for phy%d\n", lane_num, 
> phy_id);
> 			return -EINVAL;
> 		}
> 		break;
> 	case ISP_MIPI_PHY_ID_2:
> 		if (lane_num > 2) {
> 			dev_err(dev, "fail invalid lane number %u for phy%d\n", lane_num, 
> phy_id);
> 			return -EINVAL;
> 		}
> 		break;
> 	default:
> 		dev_err(dev, "fail invalid phy id %d\n", phy_id);
> 		return -EINVAL;
> 
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	if (phy_id == 0 && lane_num > 4) {
> >> +		dev_err(dev, "fail invalid lane number %u for phy0\n",
> >> +			lane_num);
> >> +		return -EINVAL;
> >> +	}
> > 
> > Maybe a switch for phy_id?
> > 
> 
> Sure, as shown above, will do it in the next patch
> 
> >> +
> >> +	return isp4phy_startup_seq_cdphy_rx(dev, base, phy_id, bit_rate, lane_num);
> > 
> > This line would benefit from wrapping.
> > 
> 
> Do you mean wrap it into two lines? Seems oneline is better.
> 
> >> +}
> >> +
> >> +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));
> > 
> > Extra parentheses.
> > 
> 
> Sure, will remove it in the next patch
> 
> >> +
> >> +	/* 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),
> > 
> > Redundant parentheses.
> > 
> 
> Sure, will remove it in the next patch
> 
> >> +		    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

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-06-18  9:19 ` [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver Bin Du
@ 2025-08-05 11:37   ` Laurent Pinchart
  2025-08-12  1:36     ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Laurent Pinchart @ 2025-08-05 11:37 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, bryan.odonoghue, sakari.ailus,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Wed, Jun 18, 2025 at 05:19:59PM +0800, Bin Du wrote:
> Add documentation for AMD isp 4 and describe the main components
> 
> Signed-off-by: Bin Du <Bin.Du@amd.com>
> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> ---
>  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:: <isonum.txt>
> +
> +====================================
> +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:
> +
> +- <capture video device: capture device for retrieving images.
> +
> +
> +  - ISP4 Image Signal Processing Subdevice Node
> +-----------------------------------------------
> +
> +The isp4 is represented as a single V4L2 subdev, the sub-device does not
> +provide interface to the user space.

Doesn't it ? The driver sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the
subdev, and calls v4l2_device_register_subdev_nodes().

As far as I understand, the camera is exposed by the firmware with a
webcam-like interface. We need to better understand your plans with this
driver. If everything is handled by the firmware, why are the sensor and
subdev exposed to userspace ? Why can't you expose a single video
capture device, with a media device, and handle everything behind the
scene ? I assume there may be more features coming later. Please
document the plan, we can't provide feedback on the architecture
otherwise.

> The sub-device is connected to one video node
> +(isp4_capture) with immutable active link. The isp entity is connected
> +to sensor pad 0 and receives the frames using CSI-2 protocol. The sub-device is
> +also responsible to configure CSI2-2 receiver.
> +The sub-device processes bayer raw data from the connected sensor and output
> +them to different YUV formats. The isp also has scaling capabilities.
> +
> +  - isp4_capture - Frames Capture Video Node
> +--------------------------------------------
> +
> +Isp4_capture is a capture device to capture frames to memory.
> +This entity is the DMA engine that write the frames to memory.
> +The entity is connected to isp4 sub-device.
> +
> +Capturing Video Frames Example
> +==============================
> +
> +.. code-block:: bash
> +
> +         # set the links

This seems very under-documented.

> +
> +         # start streaming:
> +         v4l2-ctl "-d" "/dev/video0" "--set-fmt-video=width=1920,height=1080,pixelformat=NV12" "--stream-mmap" "--stream-count=10"
> diff --git a/Documentation/admin-guide/media/amdisp4.dot b/Documentation/admin-guide/media/amdisp4.dot
> new file mode 100644
> index 000000000000..a4c2f0cceb30
> --- /dev/null
> +++ b/Documentation/admin-guide/media/amdisp4.dot
> @@ -0,0 +1,8 @@
> +digraph board {
> +	rankdir=TB
> +	n00000001 [label="{{<port0> 0} | amd isp4\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
> +	n00000001:port1 -> n00000004 [style=bold]
> +	n00000004 [label="Preview\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
> +	n0000000a [label="{{} | ov05c10 22-0010\n/dev/v4l-subdev0 | {<port0> 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 <pratap.nirujogi@amd.com>
>  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/*

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-08-05 10:39     ` Laurent Pinchart
@ 2025-08-06  9:45       ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-06  9:45 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus
  Cc: mchehab, hverkuil, bryan.odonoghue, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, pratap.nirujogi, benjamin.chan,
	king.li, gjorgji.rosikopulos, Phil.Jawich, Dominic.Antony, bin.du

Thanks Laurent Pinchart for your review

On 8/5/2025 6:39 PM, Laurent Pinchart wrote:
> On Mon, Jul 28, 2025 at 06:33:30AM +0000, Sakari Ailus wrote:
>> On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
>>> 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 <Bin.Du@amd.com>
>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>> ---
>>>   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
> 
> [snip]
> 
>>> 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 @@
> 
> [snip]
> 
>>> +union isp4phy_mipi_0 {
>>> +	struct {
>>> +		u32 shutdownz : 1;
>>> +		u32 rstz : 1;
>>> +	} bit;
>>> +	u32 value;
>>> +};
>>> +
>>> +union isp4phy_mipi_1 {
>>> +	struct {
>>> +		u32 mode : 1;
>>
>> Please pad these -- I don't think the ABI otherwise requires they're in a
>> particular location of the container (u32).
> 
> Or better, ditch the structures, and use macros to define register
> fields like all other drivers do.
> 

Sure, will look into it and update in the next patch

>>> +	} 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;
>>
>> u16 would seem appropriate here.
>>
>>> +	} bit;
>>> +	u32 value;
>>> +};
>>> +
>>> +union isp4phy_mipi_ind_data {
>>> +	struct {
>>> +		u32 data : 16;
>>
>> Ditto.
>>
>>> +	} bit;
>>> +	u32 value;
>>> +};
>>> +
>>> +union isp4phy_mipi_ind_wack {
>>> +	struct {
>>> +		u32 ack : 1;
>>> +		u32 pslverr : 1;
>>> +	} bit;
>>> +	u32 value;
>>> +};
> 
> [snip]
> 

Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy
  2025-08-05 10:53       ` Laurent Pinchart
@ 2025-08-06  9:56         ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-06  9:56 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sakari Ailus, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Thanks Laurent Pinchart for the review.

On 8/5/2025 6:53 PM, Laurent Pinchart wrote:
> On Tue, Aug 05, 2025 at 05:53:30PM +0800, Du, Bin wrote:
>> On 7/28/2025 2:33 PM, Sakari Ailus wrote:
>>> On Wed, Jun 18, 2025 at 05:19:54PM +0800, Bin Du wrote:
>>>> 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 <Bin.Du@amd.com>
>>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>>> ---
>>>>    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

[snip]

>>>> +
>>>> +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,
>>>
>>> That's an interesting way to prefill structs. I don't think these macros
>>> expand to valid pointers.
>>
>> Yes, these are valid pointers, but they are not pointing to system
>> memory, they are phy registers address, can be accessed by adding the
>> mmio base.
> 
> Please don't do that. Store register addresses in macros, and use them
> through the code as appropriate. Stop passing the base mmio address
> around through functions, store it in a PHY object, and pass that object
> to the isp4phy_start() instead of a dev pointer, base pointer and phy
> id.
> 

Sure, will do that and update in the next patch

>>>> +};
>>>> +
>>>> +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
>>>> +	},

[snip]

--
Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-04  4:25                         ` Sultan Alsawaf
@ 2025-08-08  9:11                           ` Du, Bin
  2025-08-11  5:49                             ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-08  9:11 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du

Thanks Sultan.

On 8/4/2025 12:25 PM, Sultan Alsawaf wrote:
> On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
>> On 7/31/2025 6:04 PM, Du, Bin wrote:
>>> Thanks Sultan for your test
>>>
>>> On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
>>>> On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
>>>>> On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
>>>>>> On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
>>>>>>> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
>>>>>>>> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>>>>>>>>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>>>>>>>>> Thanks Sultan, please see my comments
>>>>>>>>>>
>>>>>>>>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>>>>>>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>>>>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I cannot for the life of me get
>>>>>>>>>>>>> the webcam working under Linux.
>>>>>>>>>>>>> The webcam works
>>>>>>>>>>>>> under Windows so it's not a hardware issue.
>>>>>>>>>>>>>
>>>>>>>>>>>>> With this patchset and all of
>>>>>>>>>>>>> the patches you link here
>>>>>>>>>>>>> applied to 6.15, I get
>>>>>>>>>>>>> the following errors:
>>>>>>>>>>>>>         [   11.970038]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware: Unknown
>>>>>>>>>>>>> Synopsys component type:
>>>>>>>>>>>>> 0xffffffff
>>>>>>>>>>>>>         [   11.973162]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware: error
>>>>>>>>>>>>> -19: i2c_dw_probe failed
>>>>>>>>>>>>>
>>>>>>>>>>>>> With the old ispkernel code from
>>>>>>>>>>>>> February [1] applied on 6.15,
>>>>>>>>>>>>> the webcam
>>>>>>>>>>>>> indicator LED lights up but
>>>>>>>>>>>>> there's no image. I see these
>>>>>>>>>>>>> messages at boot:
>>>>>>>>>>>>>         [    9.449005]
>>>>>>>>>>>>> amd_isp_capture
>>>>>>>>>>>>> amd_isp_capture.1.auto: amdgpu:
>>>>>>>>>>>>> AMD ISP v4l2 device registered
>>>>>>>>>>>>>         [    9.489005]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>> The OV05 sensor device is added
>>>>>>>>>>>>> to the ISP I2C bus
>>>>>>>>>>>>>         [    9.529012]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>> timeout while trying to abort
>>>>>>>>>>>>> current transfer
>>>>>>>>>>>>>         [    9.554046]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>> timeout in disabling adapter
>>>>>>>>>>>>>         [    9.554174]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>> timeout while trying to abort
>>>>>>>>>>>>> current transfer
>>>>>>>>>>>>>         [    9.580022]
>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>> timeout in disabling adapter
>>>>>>>>>>>>>
>>>>>>>>>>>>> And then the kernel crashes due
>>>>>>>>>>>>> to the same use-after-free
>>>>>>>>>>>>> issues I pointed out
>>>>>>>>>>>>> in my other email [2].
>>>>>>>>>>>>>
>>>>>>>>>>>>> Any idea what's going on?
>>>>>>>>>>>>>
>>>>>>>>>>>>> [1]
>>>>>>>>>>>>> https://github.com/amd/Linux_ISP_Kernel/commit/
>>>>>>>>>>>>> c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>>>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>>>>>>>>> Hi Sultan,
>>>>>>>>>>>>
>>>>>>>>>>>> [1] is for kernel 6.8, believe it
>>>>>>>>>>>> can't be applied to 6.15. We didn't
>>>>>>>>>>>> verify
>>>>>>>>>>>> on 6.15 but we are really glad to
>>>>>>>>>>>> help, would you please provide some
>>>>>>>>>>>> info,
>>>>>>>>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>>>>>>>>> 2. 6.15, do you mean
>>>>>>>>>>>> https://github.com/torvalds/linux/tree/
>>>>>>>>>>>> v6.15 ?
>>>>>>>>>>>>
>>>>>>>>>>>> After your confirmation, we'll see
>>>>>>>>>>>> what we can do to enable your camera
>>>>>>>>>>>> quickly and easily
>>>>>>>>>>>>
>>>>>>>>>>>> Regards,
>>>>>>>>>>>> Bin
>>>>>>>>>>>
>>>>>>>>>>> Thank you, Bin!
>>>>>>>>>>>
>>>>>>>>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>>>>>>>>> 2. Yes, here is my kernel source [2].
>>>>>>>>>>>
>>>>>>>>>>> I have some more findings:
>>>>>>>>>>>
>>>>>>>>>>> Currently, the first blocking issue is
>>>>>>>>>>> that the I2C adapter fails to
>>>>>>>>>>> initialize.
>>>>>>>>>>> This is because the ISP tile isn't powered on.
>>>>>>>>>>>
>>>>>>>>>>> I noticed that in the old version of
>>>>>>>>>>> amd_isp_i2c_designware [3], there were
>>>>>>>>>>> calls to isp_power_set(), which is
>>>>>>>>>>> available in the old ISP4 sources [4].
>>>>>>>>>>> Without isp_power_set(), the I2C adapter
>>>>>>>>>>> always fails to initialize for me.
>>>>>>>>>>>
>>>>>>>>>>> How is the ISP tile supposed to get
>>>>>>>>>>> powered on in the current ISP4 code?
>>>>>>>>>>>
>>>>>>>>>> You are correct, yes, i believe the I2C
>>>>>>>>>> adapter failure is caused by ISP not
>>>>>>>>>> being powered up. Currently in latest code,
>>>>>>>>>> isp_power_set is no longer
>>>>>>>>>> available, instead, we implemented genPD for ISP in amdgpu
>>>>>>>>>> https://lore.kernel.org/all/20250618221923.3944751-1-
>>>>>>>>>> pratap.nirujogi@amd.com/
>>>>>>>>>> Both amd_isp_i2c and amd_isp_capture are in
>>>>>>>>>> the power domain and use the
>>>>>>>>>> standard runtime PM API to do the power control
>>>>>>>>>
>>>>>>>>> Thanks for that link, I found it along with
>>>>>>>>> another patch on the list to make
>>>>>>>>> the fwnode work ("drm/amd/amdgpu: Initialize
>>>>>>>>> swnode for ISP MFD device").
>>>>>>>>>
>>>>>>>>>>> Also, I noticed that the driver init
>>>>>>>>>>> ordering matters between all of the
>>>>>>>>>>> drivers
>>>>>>>>>>> needed for the ISP4 camera. In
>>>>>>>>>>> particular, amd_isp_i2c_designware and
>>>>>>>>>>> amd_isp4
>>>>>>>>>>> must be initialized before amd_capture,
>>>>>>>>>>> otherwise amd_capture will fail to find
>>>>>>>>>>> the fwnode properties for the OV05C10
>>>>>>>>>>> device attached to the I2C bus.
>>>>>>>>>>>
>>>>>>>>>>> But there is no driver init ordering
>>>>>>>>>>> enforced, which also caused some issues
>>>>>>>>>>> for
>>>>>>>>>>> me until I figured it out. Maybe probe
>>>>>>>>>>> deferral (-EPROBE_DEFER) should be used
>>>>>>>>>>> to ensure each driver waits for its dependencies to init first?
>>>>>>>>>>>
>>>>>>>>>> amd_isp_capture only has dependency on
>>>>>>>>>> amd_isp4 which is the ACPI platform
>>>>>>>>>> driver, it is init before amd_isp_catpure.
>>>>>>>>>> Do you see in your side the amd_capture
>>>>>>>>>> probe failure caused by failing to
>>>>>>>>>> read fwnode properties? If that's the case
>>>>>>>>>> please help to check if amd_isp4
>>>>>>>>>> is loaded successfully
>>>>>>>>>
>>>>>>>>> I got much further now: there aren't any driver
>>>>>>>>> initialization errors, but when
>>>>>>>>> I open the camera, there's no image. The camera
>>>>>>>>> LED turns on so it's active.
>>>>>>>>>
>>>>>>>>> And then shortly afterwards, amdgpu dies and the
>>>>>>>>> entire system freezes.
>>>>>>>>>
>>>>>>>>> I've attached my full dmesg, please let me know
>>>>>>>>> what you think. Thanks!
>>>>>>>>
>>>>>>>> I almost forgot, here is my current kernel tree:
>>>>>>>> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
>>>>>>>> sultan-isp4
>>>>>>>>
>>>>>>>> Sultan
>>>>>>>
>>>>>>> Thanks Sultan, yes, seems much close to the final
>>>>>>> success. Will have some
>>>>>>> internal discussion.
>>>>>>
>>>>>> I got the webcam working. The same bug happened when I tried
>>>>>> Ubuntu's linux-oem
>>>>>> kernel, which made me think that the issue was firmware.
>>>>>>
>>>>>> And indeed, the culprit was a firmware update from February. I bisected
>>>>>> linux-firmware and found the commit which broke the webcam for me:
>>>>>>
>>>>>>      commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
>>>>>>      Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>      Date:   Wed Feb 19 12:16:51 2025 -0500
>>>>>>
>>>>>>          amdgpu: Update ISP FW for isp v4.1.1
>>>>>>
>>>>>>          From internal git commit:
>>>>>>          5058202443e08a673b6772ea6339efb50853be28
>>>>>>
>>>>>>          Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>
>>>>>>       amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
>>>>>>       1 file changed, 0 insertions(+), 0 deletions(-)
>>>>>>
>>>>>> Downgrading firmware to before that commit fixes the webcam.
>>>>>> Any idea why?
>>>>>>
>>>>>> Thanks,
>>>>>> Sultan
>>>>>
>>>>> So, can i say the working firmware binary is this one?
>>>>>
>>>>> Commit 8f070131
>>>>> amdgpu: Update ISP FW for isp v4.1.1
>>>>>
>>>>>   From internal git commit:
>>>>> 39b007366cc76ef8c65e3bc6220ccb213f4861fb
>>>>>
>>>>> Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>
>>>> Correct.
>>>>
>>>>> There are too many changes between them, so i can't tell exactly which
>>>>> change caused this. So, from my side
>>>>> 1. Will try these two firmware to see if we have the same issue.
>>>>> 2. It has been quite a long time since last release, will see if need to
>>>>> release a latest one.
>>>>
>>>> Thanks. It was a quick bisect for me, so I'm happy to help test if a
>>>> bisect
>>>> between those two internal git commits is needed.
>>>>
>>> Really appreciate your test.
>>>> In case it makes a difference, I have the laptop with the 2.8K OLED
>>>> display. I'm
>>>> aware there is one other display variant on other SKUs, which is a
>>>> WUXGA IPS.
>>>>
>>> Good to know, I believe it won't make any difference for ISP
>>>
>>>> Also, with that old firmware, my camera only works with the old isp4
>>>> driver from
>>>> that Linux_ISP_Kernel repo (which is the same isp4 driver used in
>>>> Ubuntu's
>>>> linux-oem kernel). Does the new isp4 driver you've submitted here
>>>> require newer
>>>> firmware than the old driver located in Linux_ISP_Kernel?
>>>>
>>>> Sultan
>>>
>>> We had a try, yes, both of the old FW can't work on the new ISP4 driver,
>>> as you know, for the last months, we did lots of driver modifications
>>> for upstream and cause it incompatible with old FW.
>>> Now, under internal discussion to upstream a new FW to support the new
>>> ISP driver
>>>
>>> Regards,
>>> Bin
>>>
>>> Hi Sultan,
>>
>> This is the conclusion of your test,
>> Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>> [1] It works on FW      8f070131(ext):39b00736(int)
>> [2] It can't work on FW 1cc8c1bf(ext):50582024(int)
> 
> Correct.
> 
>> Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
>> .config file when building the kernel? Our assumption is to make [1] work,
>> CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
>> CONFIG_VIDEO_OV05C should be defined.
> 
> Yes, it is enabled and I have only tested with it enabled:
> 
>      $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config
>      CONFIG_VIDEO_OV05C=m
> 
> That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
> I tested by running the following commands:
> 
>      git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
>      cd linux-oem-6.14
>      python debian/scripts/misc/annotations -e --arch amd64 > .config
>      make olddefconfig
> 
> Let me know if that works.
> 
> Sultan

Thanks Sultan for the details, yes, we can reproduce the same issue on 
old isp driver 4.0 release on FW 1cc8c1bf(ext):50582024(int), after 
debug, the cause is
   - ov05c sensor device is added by amd i2c driver
   - When ov05c sensor driver probes, it will try to get gpio 
description but it will fail because the amd-pinctl driver which creates 
the gpio resource hasn't been loaded yet.
   - the ov05c sensor driver probe failure will finally make sensor not 
able to work when start streaming

Add following patch is supposed to fix this issue to make it work on FW 
1cc8c1bf(ext):50582024(int) when CONFIG_VIDEO_OV05C is defined.

@@ -1121,6 +1129,7 @@ static struct i2c_driver ov05_i2c_driver = {

module_i2c_driver(ov05_i2c_driver);

+MODULE_SOFTDEP("pre: pinctrl-amdisp");
MODULE_ALIAS("ov05");
MODULE_DESCRIPTION("OmniVision OV05 sensor driver");
MODULE_LICENSE("GPL and additional rights");

Please help to see if it works if you get time.

Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-08  9:11                           ` Du, Bin
@ 2025-08-11  5:49                             ` Sultan Alsawaf
  2025-08-11  8:35                               ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-11  5:49 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Fri, Aug 08, 2025 at 05:11:39PM +0800, Du, Bin wrote:
> On 8/4/2025 12:25 PM, Sultan Alsawaf wrote:
> > On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
> > > On 7/31/2025 6:04 PM, Du, Bin wrote:
> > > > Thanks Sultan for your test
> > > > 
> > > > On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
> > > > > On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
> > > > > > On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
> > > > > > > On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
> > > > > > > > On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> > > > > > > > > On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> > > > > > > > > > On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > > > > > > > > > > Thanks Sultan, please see my comments
> > > > > > > > > > > 
> > > > > > > > > > > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > > > > > > > > > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > > > > > > > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I cannot for the life of me get
> > > > > > > > > > > > > > the webcam working under Linux.
> > > > > > > > > > > > > > The webcam works
> > > > > > > > > > > > > > under Windows so it's not a hardware issue.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > With this patchset and all of
> > > > > > > > > > > > > > the patches you link here
> > > > > > > > > > > > > > applied to 6.15, I get
> > > > > > > > > > > > > > the following errors:
> > > > > > > > > > > > > >         [   11.970038]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware: Unknown
> > > > > > > > > > > > > > Synopsys component type:
> > > > > > > > > > > > > > 0xffffffff
> > > > > > > > > > > > > >         [   11.973162]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware: error
> > > > > > > > > > > > > > -19: i2c_dw_probe failed
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > With the old ispkernel code from
> > > > > > > > > > > > > > February [1] applied on 6.15,
> > > > > > > > > > > > > > the webcam
> > > > > > > > > > > > > > indicator LED lights up but
> > > > > > > > > > > > > > there's no image. I see these
> > > > > > > > > > > > > > messages at boot:
> > > > > > > > > > > > > >         [    9.449005]
> > > > > > > > > > > > > > amd_isp_capture
> > > > > > > > > > > > > > amd_isp_capture.1.auto: amdgpu:
> > > > > > > > > > > > > > AMD ISP v4l2 device registered
> > > > > > > > > > > > > >         [    9.489005]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > The OV05 sensor device is added
> > > > > > > > > > > > > > to the ISP I2C bus
> > > > > > > > > > > > > >         [    9.529012]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > > > current transfer
> > > > > > > > > > > > > >         [    9.554046]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > > >         [    9.554174]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > > > current transfer
> > > > > > > > > > > > > >         [    9.580022]
> > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > And then the kernel crashes due
> > > > > > > > > > > > > > to the same use-after-free
> > > > > > > > > > > > > > issues I pointed out
> > > > > > > > > > > > > > in my other email [2].
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Any idea what's going on?
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > [1]
> > > > > > > > > > > > > > https://github.com/amd/Linux_ISP_Kernel/commit/
> > > > > > > > > > > > > > c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > > > > > > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > > > > > > > > > > Hi Sultan,
> > > > > > > > > > > > > 
> > > > > > > > > > > > > [1] is for kernel 6.8, believe it
> > > > > > > > > > > > > can't be applied to 6.15. We didn't
> > > > > > > > > > > > > verify
> > > > > > > > > > > > > on 6.15 but we are really glad to
> > > > > > > > > > > > > help, would you please provide some
> > > > > > > > > > > > > info,
> > > > > > > > > > > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > > > > > > > > > > 2. 6.15, do you mean
> > > > > > > > > > > > > https://github.com/torvalds/linux/tree/
> > > > > > > > > > > > > v6.15 ?
> > > > > > > > > > > > > 
> > > > > > > > > > > > > After your confirmation, we'll see
> > > > > > > > > > > > > what we can do to enable your camera
> > > > > > > > > > > > > quickly and easily
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Regards,
> > > > > > > > > > > > > Bin
> > > > > > > > > > > > 
> > > > > > > > > > > > Thank you, Bin!
> > > > > > > > > > > > 
> > > > > > > > > > > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > > > > > > > > > > 2. Yes, here is my kernel source [2].
> > > > > > > > > > > > 
> > > > > > > > > > > > I have some more findings:
> > > > > > > > > > > > 
> > > > > > > > > > > > Currently, the first blocking issue is
> > > > > > > > > > > > that the I2C adapter fails to
> > > > > > > > > > > > initialize.
> > > > > > > > > > > > This is because the ISP tile isn't powered on.
> > > > > > > > > > > > 
> > > > > > > > > > > > I noticed that in the old version of
> > > > > > > > > > > > amd_isp_i2c_designware [3], there were
> > > > > > > > > > > > calls to isp_power_set(), which is
> > > > > > > > > > > > available in the old ISP4 sources [4].
> > > > > > > > > > > > Without isp_power_set(), the I2C adapter
> > > > > > > > > > > > always fails to initialize for me.
> > > > > > > > > > > > 
> > > > > > > > > > > > How is the ISP tile supposed to get
> > > > > > > > > > > > powered on in the current ISP4 code?
> > > > > > > > > > > > 
> > > > > > > > > > > You are correct, yes, i believe the I2C
> > > > > > > > > > > adapter failure is caused by ISP not
> > > > > > > > > > > being powered up. Currently in latest code,
> > > > > > > > > > > isp_power_set is no longer
> > > > > > > > > > > available, instead, we implemented genPD for ISP in amdgpu
> > > > > > > > > > > https://lore.kernel.org/all/20250618221923.3944751-1-
> > > > > > > > > > > pratap.nirujogi@amd.com/
> > > > > > > > > > > Both amd_isp_i2c and amd_isp_capture are in
> > > > > > > > > > > the power domain and use the
> > > > > > > > > > > standard runtime PM API to do the power control
> > > > > > > > > > 
> > > > > > > > > > Thanks for that link, I found it along with
> > > > > > > > > > another patch on the list to make
> > > > > > > > > > the fwnode work ("drm/amd/amdgpu: Initialize
> > > > > > > > > > swnode for ISP MFD device").
> > > > > > > > > > 
> > > > > > > > > > > > Also, I noticed that the driver init
> > > > > > > > > > > > ordering matters between all of the
> > > > > > > > > > > > drivers
> > > > > > > > > > > > needed for the ISP4 camera. In
> > > > > > > > > > > > particular, amd_isp_i2c_designware and
> > > > > > > > > > > > amd_isp4
> > > > > > > > > > > > must be initialized before amd_capture,
> > > > > > > > > > > > otherwise amd_capture will fail to find
> > > > > > > > > > > > the fwnode properties for the OV05C10
> > > > > > > > > > > > device attached to the I2C bus.
> > > > > > > > > > > > 
> > > > > > > > > > > > But there is no driver init ordering
> > > > > > > > > > > > enforced, which also caused some issues
> > > > > > > > > > > > for
> > > > > > > > > > > > me until I figured it out. Maybe probe
> > > > > > > > > > > > deferral (-EPROBE_DEFER) should be used
> > > > > > > > > > > > to ensure each driver waits for its dependencies to init first?
> > > > > > > > > > > > 
> > > > > > > > > > > amd_isp_capture only has dependency on
> > > > > > > > > > > amd_isp4 which is the ACPI platform
> > > > > > > > > > > driver, it is init before amd_isp_catpure.
> > > > > > > > > > > Do you see in your side the amd_capture
> > > > > > > > > > > probe failure caused by failing to
> > > > > > > > > > > read fwnode properties? If that's the case
> > > > > > > > > > > please help to check if amd_isp4
> > > > > > > > > > > is loaded successfully
> > > > > > > > > > 
> > > > > > > > > > I got much further now: there aren't any driver
> > > > > > > > > > initialization errors, but when
> > > > > > > > > > I open the camera, there's no image. The camera
> > > > > > > > > > LED turns on so it's active.
> > > > > > > > > > 
> > > > > > > > > > And then shortly afterwards, amdgpu dies and the
> > > > > > > > > > entire system freezes.
> > > > > > > > > > 
> > > > > > > > > > I've attached my full dmesg, please let me know
> > > > > > > > > > what you think. Thanks!
> > > > > > > > > 
> > > > > > > > > I almost forgot, here is my current kernel tree:
> > > > > > > > > https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
> > > > > > > > > sultan-isp4
> > > > > > > > > 
> > > > > > > > > Sultan
> > > > > > > > 
> > > > > > > > Thanks Sultan, yes, seems much close to the final
> > > > > > > > success. Will have some
> > > > > > > > internal discussion.
> > > > > > > 
> > > > > > > I got the webcam working. The same bug happened when I tried
> > > > > > > Ubuntu's linux-oem
> > > > > > > kernel, which made me think that the issue was firmware.
> > > > > > > 
> > > > > > > And indeed, the culprit was a firmware update from February. I bisected
> > > > > > > linux-firmware and found the commit which broke the webcam for me:
> > > > > > > 
> > > > > > >      commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
> > > > > > >      Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > >      Date:   Wed Feb 19 12:16:51 2025 -0500
> > > > > > > 
> > > > > > >          amdgpu: Update ISP FW for isp v4.1.1
> > > > > > > 
> > > > > > >          From internal git commit:
> > > > > > >          5058202443e08a673b6772ea6339efb50853be28
> > > > > > > 
> > > > > > >          Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > 
> > > > > > >       amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
> > > > > > >       1 file changed, 0 insertions(+), 0 deletions(-)
> > > > > > > 
> > > > > > > Downgrading firmware to before that commit fixes the webcam.
> > > > > > > Any idea why?
> > > > > > > 
> > > > > > > Thanks,
> > > > > > > Sultan
> > > > > > 
> > > > > > So, can i say the working firmware binary is this one?
> > > > > > 
> > > > > > Commit 8f070131
> > > > > > amdgpu: Update ISP FW for isp v4.1.1
> > > > > > 
> > > > > >   From internal git commit:
> > > > > > 39b007366cc76ef8c65e3bc6220ccb213f4861fb
> > > > > > 
> > > > > > Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > 
> > > > > Correct.
> > > > > 
> > > > > > There are too many changes between them, so i can't tell exactly which
> > > > > > change caused this. So, from my side
> > > > > > 1. Will try these two firmware to see if we have the same issue.
> > > > > > 2. It has been quite a long time since last release, will see if need to
> > > > > > release a latest one.
> > > > > 
> > > > > Thanks. It was a quick bisect for me, so I'm happy to help test if a
> > > > > bisect
> > > > > between those two internal git commits is needed.
> > > > > 
> > > > Really appreciate your test.
> > > > > In case it makes a difference, I have the laptop with the 2.8K OLED
> > > > > display. I'm
> > > > > aware there is one other display variant on other SKUs, which is a
> > > > > WUXGA IPS.
> > > > > 
> > > > Good to know, I believe it won't make any difference for ISP
> > > > 
> > > > > Also, with that old firmware, my camera only works with the old isp4
> > > > > driver from
> > > > > that Linux_ISP_Kernel repo (which is the same isp4 driver used in
> > > > > Ubuntu's
> > > > > linux-oem kernel). Does the new isp4 driver you've submitted here
> > > > > require newer
> > > > > firmware than the old driver located in Linux_ISP_Kernel?
> > > > > 
> > > > > Sultan
> > > > 
> > > > We had a try, yes, both of the old FW can't work on the new ISP4 driver,
> > > > as you know, for the last months, we did lots of driver modifications
> > > > for upstream and cause it incompatible with old FW.
> > > > Now, under internal discussion to upstream a new FW to support the new
> > > > ISP driver
> > > > 
> > > > Regards,
> > > > Bin
> > > > 
> > > > Hi Sultan,
> > > 
> > > This is the conclusion of your test,
> > > Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > [1] It works on FW      8f070131(ext):39b00736(int)
> > > [2] It can't work on FW 1cc8c1bf(ext):50582024(int)
> > 
> > Correct.
> > 
> > > Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
> > > .config file when building the kernel? Our assumption is to make [1] work,
> > > CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
> > > CONFIG_VIDEO_OV05C should be defined.
> > 
> > Yes, it is enabled and I have only tested with it enabled:
> > 
> >      $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config
> >      CONFIG_VIDEO_OV05C=m
> > 
> > That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
> > I tested by running the following commands:
> > 
> >      git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
> >      cd linux-oem-6.14
> >      python debian/scripts/misc/annotations -e --arch amd64 > .config
> >      make olddefconfig
> > 
> > Let me know if that works.
> > 
> > Sultan
> 
> Thanks Sultan for the details, yes, we can reproduce the same issue on old
> isp driver 4.0 release on FW 1cc8c1bf(ext):50582024(int), after debug, the
> cause is
>   - ov05c sensor device is added by amd i2c driver
>   - When ov05c sensor driver probes, it will try to get gpio description but
> it will fail because the amd-pinctl driver which creates the gpio resource
> hasn't been loaded yet.
>   - the ov05c sensor driver probe failure will finally make sensor not able
> to work when start streaming
> 
> Add following patch is supposed to fix this issue to make it work on FW
> 1cc8c1bf(ext):50582024(int) when CONFIG_VIDEO_OV05C is defined.
> 
> @@ -1121,6 +1129,7 @@ static struct i2c_driver ov05_i2c_driver = {
> 
> module_i2c_driver(ov05_i2c_driver);
> 
> +MODULE_SOFTDEP("pre: pinctrl-amdisp");
> MODULE_ALIAS("ov05");
> MODULE_DESCRIPTION("OmniVision OV05 sensor driver");
> MODULE_LICENSE("GPL and additional rights");
> 
> Please help to see if it works if you get time.

There is no difference I'm afraid. I applied the patch and tested with FW
1cc8c1bf(ext):50582024(int) and the webcam is still broken on that FW:

  [   19.523006] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
  [   19.537000] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
  [   19.537009] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
  [   19.537050] PHY register access test success!
  [   19.537901] Termination calibration observability: 0x0
  [   19.539926] Wait for phyReady: 0x0
  [   19.541932] Wait for phyReady: 0x1
  [   20.901654] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
  [   22.070676] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
  ...
  [   28.769372] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
  [   28.769388] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
  [   28.769868] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
  [   28.771799] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-07-31  0:34       ` Sultan Alsawaf
  2025-07-31  9:45         ` Du, Bin
@ 2025-08-11  6:02         ` Sultan Alsawaf
  2025-08-11  9:05           ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-11  6:02 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Wed, Jul 30, 2025 at 05:34:22PM -0700, Sultan Alsawaf wrote:
> On Tue, Jul 29, 2025 at 03:43:14PM +0800, Du, Bin wrote:
> > Hi Sultan, really appreciate your time and effort
> > 
> > On 7/28/2025 3:04 PM, Sultan Alsawaf wrote:
> > > I found more refcounting issues in addition to the ones from my other emails
> > > while trying to make my webcam work:
> > > 
> > > On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
> > > > +static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
> > > > +{
> > > > +	struct isp4vid_vb2_buf *buf = buf_priv;
> > > > +	int ret;
> > > > +
> > > > +	if (!buf) {
> > > > +		pr_err("fail no memory to map\n");
> > > > +		return -EINVAL;
> > > > +	}
> > > > +
> > > > +	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
> > > > +	if (ret) {
> > > > +		dev_err(buf->dev, "fail remap vmalloc mem, %d\n", ret);
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	/*
> > > > +	 * Make sure that vm_areas for 2 buffers won't be merged together
> > > > +	 */
> > > > +	vm_flags_set(vma, VM_DONTEXPAND);
> > > > +
> > > > +	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
> > > > +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> > > 
> > > Use refcount_read() instead of reading the refcount's atomic_t counter directly.
> > > This is done in 3 other places; change those to refcount_read() as well.
> > > 
> > > This didn't cause any functional problems, but it should still be fixed.
> > > 
> > > > +
> > > > +	return 0;
> > > > +}
> > > 
> > Sure, will fix it
> > 
> > > [snip]
> > > 
> > > > +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> > > > +{
> > > > +	struct isp4vid_vb2_buf *buf = mem_priv;
> > > > +
> > > > +	if (!buf) {
> > > > +		pr_err("fail invalid buf handle\n");
> > > > +		return;
> > > > +	}
> > > > +
> > > > +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
> > > > +
> > > > +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
> > > > +		buf->gpu_addr, buf->size);
> > > > +
> > > > +	if (buf->vaddr)
> > > > +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
> > > > +
> > > > +	// put dmabuf for exported ones
> > > > +	dma_buf_put(buf->dbuf);
> > > > +
> > > > +	kfree(buf);
> > > > +}
> > > 
> > > As mentioned in the other email, the dma_buf_put() here needs to be removed. But
> > > that's not all: the dma_buf_vunmap_unlocked() needs to be removed too because
> > > vb2 will always unmap the buffer before detaching it. As a result, having the
> > > dma_buf_vunmap_unlocked() call here results in a use-after-free when vb2 calls
> > > the unmap_dmabuf memop.
> > > 
> > > Change this function to the following:
> > > 
> > > 	static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> > > 	{
> > > 		struct isp4vid_vb2_buf *buf = mem_priv;
> > > 
> > > 		kfree(buf);
> > > 	}
> > > 
> > Will have a try
> > 
> > > > +static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
> > > > +{
> > > > +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
> > > > +	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
> > > > +
> > > > +	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
> > > > +		isp_vdev->vdev.name, vb->index, vb->memory);
> > > > +
> > > > +	if (!buf) {
> > > > +		dev_err(isp_vdev->dev, "Invalid buf handle");
> > > > +		return;
> > > > +	}
> > > > +
> > > > +	// release implicit dmabuf reference here for vb2 buffer
> > > > +	// of type MMAP and is exported
> > > > +	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
> > > > +		dma_buf_put(buf->dbuf);
> > > > +		dev_dbg(isp_vdev->dev,
> > > > +			"put dmabuf for vb->memory %d expbuf %d",
> > > > +			vb->memory,
> > > > +			buf->is_expbuf);
> > > > +	}
> > > > +}
> > > > +
> > > 
> > > Remove the isp4vid_qops_buffer_cleanup() function. It causes a use-after-free by
> > > doing an extra dma_buf_put(). This function isn't needed now that the refcount
> > > issues are solved.
> > > 
> > Will have a try
> > 
> > > [snip]
> > > 
> > > > +static const struct vb2_ops isp4vid_qops = {
> > > > +	.queue_setup = isp4vid_qops_queue_setup,
> > > > +	.buf_cleanup = isp4vid_qops_buffer_cleanup,
> > > 
> > > Remove the .buf_cleanup hook too.
> > > 
> > Will have a try
> > 
> > > > +	.buf_queue = isp4vid_qops_buffer_queue,
> > > > +	.start_streaming = isp4vid_qops_start_streaming,
> > > > +	.stop_streaming = isp4vid_qops_stop_streaming,
> > > > +	.wait_prepare = vb2_ops_wait_prepare,
> > > > +	.wait_finish = vb2_ops_wait_finish,
> > > > +};
> > > 
> > > [snip]
> > > 
> > > Along with the changes from my other emails, I believe this finally fixes all of
> > > the refcounting issues. No more UaF or leaks here. :-)
> > > 
> > > Sultan
> > Tried changes in this and other two mails together, found the kernel will
> > crash when re-open cheese App (means open cheese, close it and then open it
> > again), the crash stack dump is shown below
> > 
> > [   38.008686] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
> > [   38.032693] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
> > [   38.060866] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
> > [   38.060877] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
> > performance state 1 suc
> > [   38.425284] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none to
> > state 0
> > [   38.448631] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
> > [   38.508368] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
> > [   38.538525] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
> > [   38.568839] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
> > [   38.568851] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
> > performance state 1 suc
> > [   38.997779] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none to
> > state 0
> > [   39.029297] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
> > [   39.084010] BUG: kernel NULL pointer dereference, address:
> > 0000000000000008
> > [   39.084024] #PF: supervisor read access in kernel mode
> > [   39.084028] #PF: error_code(0x0000) - not-present page
> > [   39.084031] PGD 0 P4D 0
> > [   39.084037] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
> > [   39.084042] CPU: 3 UID: 1000 PID: 3119 Comm: viewfinderbin-q Not tainted
> > 6.14.0-rc2+ #944
> > [   39.084046] Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile
> > Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
> > [   39.084049] RIP: 0010:validate_page_before_insert+0x5/0xc0
> > [   39.084060] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 00
> > 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 <48>
> > 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
> > [   39.084064] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
> > [   39.084067] RAX: 0000000000000000 RBX: 8000000000000025 RCX:
> > 0000000000000000
> > [   39.084069] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
> > ffff9efa10e400b8
> > [   39.084071] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09:
> > 0000000000000000
> > [   39.084072] R10: 0000000000000000 R11: 0000000000000000 R12:
> > ffff9efa10e400b8
> > [   39.084074] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15:
> > 0000000000000000
> > [   39.084076] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000)
> > knlGS:0000000000000000
> > [   39.084078] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [   39.084080] CR2: 0000000000000008 CR3: 0000000137bba000 CR4:
> > 0000000000750ef0
> > [   39.084083] PKRU: 55555554
> > [   39.084084] Call Trace:
> > [   39.084087]  <TASK>
> > [   39.084093]  ? show_regs+0x71/0x90
> > [   39.084099]  ? __die+0x25/0x80
> > [   39.084102]  ? page_fault_oops+0x15c/0x570
> > [   39.084108]  ? do_user_addr_fault+0x4a9/0x810
> > [   39.084111]  ? __mod_memcg_lruvec_state+0xde/0x280
> > [   39.084117]  ? exc_page_fault+0x83/0x1d0
> > [   39.084123]  ? asm_exc_page_fault+0x27/0x30
> > [   39.084131]  ? validate_page_before_insert+0x5/0xc0
> > [   39.084134]  ? vm_insert_page+0xd4/0x1a0
> > [   39.084139]  remap_vmalloc_range_partial+0xe3/0x160
> > [   39.084145]  remap_vmalloc_range+0x21/0x40
> > [   39.084153]  isp4vid_vb2_mmap+0x2d/0x130 [amd_capture]
> > [   39.084164]  isp4vid_vb2_dmabuf_ops_mmap+0x12/0x20 [amd_capture]
> > [   39.084168]  dma_buf_mmap_internal+0x41/0x70
> > [   39.084173]  __mmap_region+0x62f/0xbc0
> > [   39.084179]  mmap_region+0x67/0xe0
> > [   39.084181]  do_mmap+0x52b/0x650
> > [   39.084187]  vm_mmap_pgoff+0xf4/0x1c0
> > [   39.084194]  ksys_mmap_pgoff+0x182/0x250
> > [   39.084198]  __x64_sys_mmap+0x33/0x70
> > [   39.084202]  x64_sys_call+0x2541/0x26f0
> > [   39.084206]  do_syscall_64+0x70/0x130
> > [   39.084212]  ? __rseq_handle_notify_resume+0xa4/0x520
> > [   39.084216]  ? do_futex+0x17f/0x220
> > [   39.084220]  ? restore_fpregs_from_fpstate+0x3d/0xd0
> > [   39.084225]  ? switch_fpu_return+0x50/0xe0
> > [   39.084229]  ? syscall_exit_to_user_mode+0x18c/0x1c0
> > [   39.084234]  ? do_syscall_64+0x7c/0x130
> > [   39.084237]  ? __pfx_futex_wake_mark+0x10/0x10
> > [   39.084241]  ? hrtimer_cancel+0x15/0x50
> > [   39.084246]  ? futex_wait+0x7c/0x120
> > [   39.084249]  ? __pfx_hrtimer_wakeup+0x10/0x10
> > [   39.084254]  ? __rseq_handle_notify_resume+0xa4/0x520
> > [   39.084256]  ? do_futex+0x17f/0x220
> > [   39.084258]  ? restore_fpregs_from_fpstate+0x3d/0xd0
> > [   39.084261]  ? switch_fpu_return+0x50/0xe0
> > [   39.084264]  ? syscall_exit_to_user_mode+0x18c/0x1c0
> > [   39.084268]  ? do_syscall_64+0x7c/0x130
> > [   39.084272]  ? __count_memcg_events+0xcd/0x190
> > [   39.084276]  ? count_memcg_events.constprop.0+0x2a/0x50
> > [   39.084279]  ? handle_mm_fault+0x1ef/0x2d0
> > [   39.084284]  ? do_user_addr_fault+0x58d/0x810
> > [   39.084286]  ? irqentry_exit_to_user_mode+0x33/0x180
> > [   39.084291]  ? irqentry_exit+0x43/0x50
> > [   39.084294]  ? exc_page_fault+0x94/0x1d0
> > [   39.084298]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
> > [   39.084302] RIP: 0033:0x7fa463b2531c
> > [   39.084305] Code: 1e fa 41 f7 c1 ff 0f 00 00 75 33 55 48 89 e5 41 54 41
> > 89 cc 53 48 89 fb 48 85 ff 74 41 45 89 e2 48 89 df b8 09 00 00 00 0f 05 <48>
> > 3d 00 f0 ff ff 77 7c 5b 41 5c 5d c3 0f 1f 80 00 00 00 00 48 8b
> > [   39.084308] RSP: 002b:00007fa3f4bf79e0 EFLAGS: 00000246 ORIG_RAX:
> > 0000000000000009
> > [   39.084311] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
> > 00007fa463b2531c
> > [   39.084312] RDX: 0000000000000001 RSI: 00000000007782c0 RDI:
> > 0000000000000000
> > [   39.084314] RBP: 00007fa3f4bf79f0 R08: 0000000000000047 R09:
> > 0000000000000000
> > [   39.084315] R10: 0000000000000001 R11: 0000000000000246 R12:
> > 0000000000000001
> > [   39.084317] R13: 0000000000000000 R14: 00007fa3f8019b48 R15:
> > 00007fa3f4bf7b60
> > [   39.084320]  </TASK>
> > [   39.084321] Modules linked in: snd_seq_dummy snd_hrtimer hid_sensor_prox
> > hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer
> > kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm cmac
> > algif_hash algif_skcipher af_alg hid_logitech_hidpp ov05c10 v4l2_cci
> > amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common
> > v4l2_async videodev pinctrl_amdisp i2c_designware_amdisp qrtr bnep btusb
> > btrtl btintel btbcm btmtk bluetooth hid_logitech_dj intel_rapl_msr amd_atl
> > intel_rapl_common binfmt_misc nls_iso8859_1 snd_acp_legacy_mach snd_acp_mach
> > snd_soc_nau8821 snd_acp3x_rn amdgpu edac_mce_amd snd_ctl_led
> > snd_hda_codec_realtek snd_acp70 snd_hda_codec_generic snd_acp_i2s
> > snd_acp_pdm snd_hda_scodec_component snd_soc_dmic snd_acp_pcm
> > snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci
> > snd_sof_xtensa_dsp snd_hda_codec_hdmi snd_sof snd_sof_utils snd_pci_ps
> > snd_soc_acpi_amd_match snd_amd_sdw_acpi soundwire_amd
> > soundwire_generic_allocation soundwire_bus snd_hda_intel kvm_amd
> > [   39.084385]  snd_soc_sdca snd_intel_dspcfg snd_intel_sdw_acpi
> > snd_soc_core snd_hda_codec amdxcp kvm snd_compress
> > drm_panel_backlight_quirks snd_hda_core snd_usb_audio gpu_sched ac97_bus
> > polyval_clmulni snd_pcm_dmaengine polyval_generic ghash_clmulni_intel
> > drm_buddy snd_usbmidi_lib snd_seq_midi snd_rpl_pci_acp6x sha256_ssse3
> > snd_ump drm_ttm_helper snd_seq_midi_event snd_hwdep sha1_ssse3 ttm
> > aesni_intel drm_exec snd_rawmidi drm_suballoc_helper snd_acp_pci mc
> > crypto_simd snd_acp_legacy_common drm_client_lib cryptd drm_display_helper
> > snd_pci_acp6x snd_seq rapl hp_wmi cec wmi_bmof snd_pcm sparse_keymap
> > snd_seq_device rc_core snd_timer snd_pci_acp5x drm_kms_helper
> > snd_rn_pci_acp3x amd_pmf snd i2c_algo_bit snd_acp_config i2c_piix4
> > snd_soc_acpi amdtee soundcore snd_pci_acp3x i2c_smbus ccp joydev tee
> > input_leds serial_multi_instantiate amd_pmc platform_profile wireless_hotkey
> > mac_hid serio_raw sch_fq_codel msr parport_pc ppdev lp parport efi_pstore
> > nfnetlink dmi_sysfs ip_tables x_tables autofs4 r8152 mii usbhid
> > hid_multitouch
> > [   39.084451]  hid_generic nvme ucsi_acpi i2c_hid_acpi video typec_ucsi
> > i2c_hid amd_sfh thunderbolt hid nvme_core typec wmi drm
> > [   39.084465] CR2: 0000000000000008
> > [   39.084468] ---[ end trace 0000000000000000 ]---
> > [   39.116114] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
> > [   39.159519] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
> > [   39.201325] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
> > [   39.201334] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
> > performance state 1 suc
> > [   39.343894] RIP: 0010:validate_page_before_insert+0x5/0xc0
> > [   39.343907] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 00
> > 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 <48>
> > 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
> > [   39.343909] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
> > [   39.343911] RAX: 0000000000000000 RBX: 8000000000000025 RCX:
> > 0000000000000000
> > [   39.343913] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
> > ffff9efa10e400b8
> > [   39.343913] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09:
> > 0000000000000000
> > [   39.343914] R10: 0000000000000000 R11: 0000000000000000 R12:
> > ffff9efa10e400b8
> > [   39.343915] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15:
> > 0000000000000000
> > [   39.343916] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000)
> > knlGS:0000000000000000
> > [   39.343917] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [   39.343918] CR2: 0000000000000008 CR3: 0000000137bba000 CR4:
> > 0000000000750ef0
> > [   39.343919] PKRU: 55555554
> > [   39.343920] note: viewfinderbin-q[3119] exited with irqs disabled
> > 
> > This is the patch, it should have contained all your changes
> > 
> > From b0a61b6b7500635928166516d5563e6de50300bb Mon Sep 17 00:00:00 2001
> > From: Bin Du <Bin.Du@amd.com>
> > Date: Mon, 28 Jul 2025 14:18:04 +0800
> > Subject: [PATCH] add comment from community
> > 
> > Change-Id: I06fff629c0dc691eaeaa9d9b81e6af27cbb6adb2
> > ---
> >  drivers/media/platform/amd/isp4/isp4_video.c | 59 ++++++--------------
> >  1 file changed, 17 insertions(+), 42 deletions(-)
> > 
> > diff --git a/drivers/media/platform/amd/isp4/isp4_video.c
> > b/drivers/media/platform/amd/isp4/isp4_video.c
> > index a1376498c246..b210a0b1e49b 100644
> > --- a/drivers/media/platform/amd/isp4/isp4_video.c
> > +++ b/drivers/media/platform/amd/isp4/isp4_video.c
> > @@ -183,7 +183,7 @@ static int isp4vid_vb2_mmap(void *buf_priv, struct
> > vm_area_struct *vma)
> >  	vm_flags_set(vma, VM_DONTEXPAND);
> > 
> >  	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
> > -		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> > +		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));
> > 
> >  	return 0;
> >  }
> > @@ -214,14 +214,9 @@ static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
> >  		return;
> >  	}
> > 
> > -	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
> > -
> >  	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
> >  		buf->gpu_addr, buf->size);
> > 
> > -	if (buf->vaddr)
> > -		dma_buf_vunmap_unlocked(buf->dbuf, &map);
> > -
> >  	kfree(buf);
> >  }
> > 
> > @@ -470,21 +465,25 @@ static struct dma_buf *isp4vid_vb2_get_dmabuf(struct
> > vb2_buffer *vb,
> >  					      unsigned long flags)
> >  {
> >  	struct isp4vid_vb2_buf *buf = buf_priv;
> > -	struct dma_buf *dbuf;
> > +	struct dma_buf *dbuf = buf->dbuf;
> > +
> > +	if (dbuf) {
> > +		dev_dbg(buf->dev, "dbuf already created, reuse %s dbuf\n",
> > +			buf->is_expbuf ? "exported" : "implicit");
> > +		get_dma_buf(dbuf);
> > 
> > -	if (buf->dbuf) {
> > -		dev_dbg(buf->dev, "dbuf already created, reuse implicit dbuf\n");
> > -		dbuf = buf->dbuf;
> >  	} else {
> >  		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
> > +		if (!dbuf)
> > +			return NULL;
> > +
> >  		dev_dbg(buf->dev, "created new dbuf\n");
> > +		buf->is_expbuf = true;
> > +		refcount_inc(&buf->refcount);
> >  	}
> > 
> > -	buf->is_expbuf = true;
> > -	refcount_inc(&buf->refcount);
> > -
> >  	dev_dbg(buf->dev, "buf exported, refcount %d\n",
> > -		buf->refcount.refs.counter);
> > +		refcount_read(&buf->refcount));
> > 
> >  	return dbuf;
> >  }
> > @@ -579,8 +578,9 @@ static void isp4vid_vb2_put(void *buf_priv)
> >  {
> >  	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
> >  	unsigned int ref_cnt = refcount_read(&buf->refcount);
> > +	struct device *dev = buf->dev;
> > 
> > -	dev_dbg(buf->dev,
> > +	dev_dbg(dev,
> >  		"release isp user bo 0x%llx size %ld refcount %u is_expbuf %d\n",
> >  		buf->gpu_addr, buf->size,
> >  		ref_cnt, buf->is_expbuf);
> > @@ -598,7 +598,7 @@ static void isp4vid_vb2_put(void *buf_priv)
> >  		/* the ref_cnt - 1 is just a predicted value as reference, can't
> >  		 * guarantee it's the actual value now
> >  		 */
> > -		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
> > +		dev_warn(dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
> >  	}
> >  }
> > 
> > @@ -642,7 +642,7 @@ static void *isp4vid_vb2_alloc(struct vb2_buffer *vb,
> > struct device *dev,
> >  	refcount_set(&buf->refcount, 1);
> > 
> >  	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d\n",
> > -		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
> > +		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));
> > 
> >  	return buf;
> >  err_free:
> > @@ -1140,30 +1140,6 @@ static void isp4vid_qops_buffer_queue(struct
> > vb2_buffer *vb)
> >  	mutex_unlock(&isp_vdev->buf_list_lock);
> >  }
> > 
> > -static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
> > -{
> > -	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
> > -	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
> > -
> > -	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
> > -		isp_vdev->vdev.name, vb->index, vb->memory);
> > -
> > -	if (!buf) {
> > -		dev_err(isp_vdev->dev, "Invalid buf handle");
> > -		return;
> > -	}
> > -
> > -	// release implicit dmabuf reference here for vb2 buffer
> > -	// of type MMAP and is exported
> > -	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
> > -		dma_buf_put(buf->dbuf);
> > -		dev_dbg(isp_vdev->dev,
> > -			"put dmabuf for vb->memory %d expbuf %d",
> > -			vb->memory,
> > -			buf->is_expbuf);
> > -	}
> > -}
> > -
> >  static int isp4vid_qops_start_streaming(struct vb2_queue *vq,
> >  					unsigned int count)
> >  {
> > @@ -1343,7 +1319,6 @@ static int isp4vid_fill_buffer_size(struct isp4vid_dev
> > *isp_vdev)
> > 
> >  static const struct vb2_ops isp4vid_qops = {
> >  	.queue_setup = isp4vid_qops_queue_setup,
> > -	.buf_cleanup = isp4vid_qops_buffer_cleanup,
> >  	.buf_queue = isp4vid_qops_buffer_queue,
> >  	.start_streaming = isp4vid_qops_start_streaming,
> >  	.stop_streaming = isp4vid_qops_stop_streaming,
> > -- 
> > 2.34.1
> 
> The patch looks correct. I will get back to you on this after doing some testing
> myself.
> 
> FYI, I can only test these changes with the old isp4 driver right now, since the
> new isp4 driver doesn't work for me as mentioned in my other email. So far,
> something does seem wrong after these changes I suggested because they break the
> camera on the old isp4 driver too.

Following up on this: there were several more issues hiding in the driver that
needed to be fixed unfortunately. I ended up making a lot of changes to fix all
of the buffer lifetime issues, and I created individual commits for this work
because it was getting hard to keep track of all the changes.

I think I'll have this completed tomorrow and will provide a link to my tree
with my commits. Hopefully your internal branch hasn't diverged too much from
this patchset submission, otherwise there may be some conflicts to resolve.

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-11  5:49                             ` Sultan Alsawaf
@ 2025-08-11  8:35                               ` Du, Bin
  2025-08-11 21:48                                 ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-11  8:35 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

Thanks Sultan.

On 8/11/2025 1:49 PM, Sultan Alsawaf wrote:
> On Fri, Aug 08, 2025 at 05:11:39PM +0800, Du, Bin wrote:
>> On 8/4/2025 12:25 PM, Sultan Alsawaf wrote:
>>> On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
>>>> On 7/31/2025 6:04 PM, Du, Bin wrote:
>>>>> Thanks Sultan for your test
>>>>>
>>>>> On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
>>>>>> On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
>>>>>>> On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
>>>>>>>> On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
>>>>>>>>> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
>>>>>>>>>> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>>>>>>>>>>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>>>>>>>>>>> Thanks Sultan, please see my comments
>>>>>>>>>>>>
>>>>>>>>>>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>>>>>>>>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>>>>>>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I cannot for the life of me get
>>>>>>>>>>>>>>> the webcam working under Linux.
>>>>>>>>>>>>>>> The webcam works
>>>>>>>>>>>>>>> under Windows so it's not a hardware issue.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> With this patchset and all of
>>>>>>>>>>>>>>> the patches you link here
>>>>>>>>>>>>>>> applied to 6.15, I get
>>>>>>>>>>>>>>> the following errors:
>>>>>>>>>>>>>>>          [   11.970038]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware: Unknown
>>>>>>>>>>>>>>> Synopsys component type:
>>>>>>>>>>>>>>> 0xffffffff
>>>>>>>>>>>>>>>          [   11.973162]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware: error
>>>>>>>>>>>>>>> -19: i2c_dw_probe failed
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> With the old ispkernel code from
>>>>>>>>>>>>>>> February [1] applied on 6.15,
>>>>>>>>>>>>>>> the webcam
>>>>>>>>>>>>>>> indicator LED lights up but
>>>>>>>>>>>>>>> there's no image. I see these
>>>>>>>>>>>>>>> messages at boot:
>>>>>>>>>>>>>>>          [    9.449005]
>>>>>>>>>>>>>>> amd_isp_capture
>>>>>>>>>>>>>>> amd_isp_capture.1.auto: amdgpu:
>>>>>>>>>>>>>>> AMD ISP v4l2 device registered
>>>>>>>>>>>>>>>          [    9.489005]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>> The OV05 sensor device is added
>>>>>>>>>>>>>>> to the ISP I2C bus
>>>>>>>>>>>>>>>          [    9.529012]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>> timeout while trying to abort
>>>>>>>>>>>>>>> current transfer
>>>>>>>>>>>>>>>          [    9.554046]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>> timeout in disabling adapter
>>>>>>>>>>>>>>>          [    9.554174]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>> timeout while trying to abort
>>>>>>>>>>>>>>> current transfer
>>>>>>>>>>>>>>>          [    9.580022]
>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>> timeout in disabling adapter
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> And then the kernel crashes due
>>>>>>>>>>>>>>> to the same use-after-free
>>>>>>>>>>>>>>> issues I pointed out
>>>>>>>>>>>>>>> in my other email [2].
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Any idea what's going on?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> [1]
>>>>>>>>>>>>>>> https://github.com/amd/Linux_ISP_Kernel/commit/
>>>>>>>>>>>>>>> c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>>>>>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>>>>>>>>>>> Hi Sultan,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> [1] is for kernel 6.8, believe it
>>>>>>>>>>>>>> can't be applied to 6.15. We didn't
>>>>>>>>>>>>>> verify
>>>>>>>>>>>>>> on 6.15 but we are really glad to
>>>>>>>>>>>>>> help, would you please provide some
>>>>>>>>>>>>>> info,
>>>>>>>>>>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>>>>>>>>>>> 2. 6.15, do you mean
>>>>>>>>>>>>>> https://github.com/torvalds/linux/tree/
>>>>>>>>>>>>>> v6.15 ?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> After your confirmation, we'll see
>>>>>>>>>>>>>> what we can do to enable your camera
>>>>>>>>>>>>>> quickly and easily
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Regards,
>>>>>>>>>>>>>> Bin
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thank you, Bin!
>>>>>>>>>>>>>
>>>>>>>>>>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>>>>>>>>>>> 2. Yes, here is my kernel source [2].
>>>>>>>>>>>>>
>>>>>>>>>>>>> I have some more findings:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Currently, the first blocking issue is
>>>>>>>>>>>>> that the I2C adapter fails to
>>>>>>>>>>>>> initialize.
>>>>>>>>>>>>> This is because the ISP tile isn't powered on.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I noticed that in the old version of
>>>>>>>>>>>>> amd_isp_i2c_designware [3], there were
>>>>>>>>>>>>> calls to isp_power_set(), which is
>>>>>>>>>>>>> available in the old ISP4 sources [4].
>>>>>>>>>>>>> Without isp_power_set(), the I2C adapter
>>>>>>>>>>>>> always fails to initialize for me.
>>>>>>>>>>>>>
>>>>>>>>>>>>> How is the ISP tile supposed to get
>>>>>>>>>>>>> powered on in the current ISP4 code?
>>>>>>>>>>>>>
>>>>>>>>>>>> You are correct, yes, i believe the I2C
>>>>>>>>>>>> adapter failure is caused by ISP not
>>>>>>>>>>>> being powered up. Currently in latest code,
>>>>>>>>>>>> isp_power_set is no longer
>>>>>>>>>>>> available, instead, we implemented genPD for ISP in amdgpu
>>>>>>>>>>>> https://lore.kernel.org/all/20250618221923.3944751-1-
>>>>>>>>>>>> pratap.nirujogi@amd.com/
>>>>>>>>>>>> Both amd_isp_i2c and amd_isp_capture are in
>>>>>>>>>>>> the power domain and use the
>>>>>>>>>>>> standard runtime PM API to do the power control
>>>>>>>>>>>
>>>>>>>>>>> Thanks for that link, I found it along with
>>>>>>>>>>> another patch on the list to make
>>>>>>>>>>> the fwnode work ("drm/amd/amdgpu: Initialize
>>>>>>>>>>> swnode for ISP MFD device").
>>>>>>>>>>>
>>>>>>>>>>>>> Also, I noticed that the driver init
>>>>>>>>>>>>> ordering matters between all of the
>>>>>>>>>>>>> drivers
>>>>>>>>>>>>> needed for the ISP4 camera. In
>>>>>>>>>>>>> particular, amd_isp_i2c_designware and
>>>>>>>>>>>>> amd_isp4
>>>>>>>>>>>>> must be initialized before amd_capture,
>>>>>>>>>>>>> otherwise amd_capture will fail to find
>>>>>>>>>>>>> the fwnode properties for the OV05C10
>>>>>>>>>>>>> device attached to the I2C bus.
>>>>>>>>>>>>>
>>>>>>>>>>>>> But there is no driver init ordering
>>>>>>>>>>>>> enforced, which also caused some issues
>>>>>>>>>>>>> for
>>>>>>>>>>>>> me until I figured it out. Maybe probe
>>>>>>>>>>>>> deferral (-EPROBE_DEFER) should be used
>>>>>>>>>>>>> to ensure each driver waits for its dependencies to init first?
>>>>>>>>>>>>>
>>>>>>>>>>>> amd_isp_capture only has dependency on
>>>>>>>>>>>> amd_isp4 which is the ACPI platform
>>>>>>>>>>>> driver, it is init before amd_isp_catpure.
>>>>>>>>>>>> Do you see in your side the amd_capture
>>>>>>>>>>>> probe failure caused by failing to
>>>>>>>>>>>> read fwnode properties? If that's the case
>>>>>>>>>>>> please help to check if amd_isp4
>>>>>>>>>>>> is loaded successfully
>>>>>>>>>>>
>>>>>>>>>>> I got much further now: there aren't any driver
>>>>>>>>>>> initialization errors, but when
>>>>>>>>>>> I open the camera, there's no image. The camera
>>>>>>>>>>> LED turns on so it's active.
>>>>>>>>>>>
>>>>>>>>>>> And then shortly afterwards, amdgpu dies and the
>>>>>>>>>>> entire system freezes.
>>>>>>>>>>>
>>>>>>>>>>> I've attached my full dmesg, please let me know
>>>>>>>>>>> what you think. Thanks!
>>>>>>>>>>
>>>>>>>>>> I almost forgot, here is my current kernel tree:
>>>>>>>>>> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
>>>>>>>>>> sultan-isp4
>>>>>>>>>>
>>>>>>>>>> Sultan
>>>>>>>>>
>>>>>>>>> Thanks Sultan, yes, seems much close to the final
>>>>>>>>> success. Will have some
>>>>>>>>> internal discussion.
>>>>>>>>
>>>>>>>> I got the webcam working. The same bug happened when I tried
>>>>>>>> Ubuntu's linux-oem
>>>>>>>> kernel, which made me think that the issue was firmware.
>>>>>>>>
>>>>>>>> And indeed, the culprit was a firmware update from February. I bisected
>>>>>>>> linux-firmware and found the commit which broke the webcam for me:
>>>>>>>>
>>>>>>>>       commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
>>>>>>>>       Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>>>       Date:   Wed Feb 19 12:16:51 2025 -0500
>>>>>>>>
>>>>>>>>           amdgpu: Update ISP FW for isp v4.1.1
>>>>>>>>
>>>>>>>>           From internal git commit:
>>>>>>>>           5058202443e08a673b6772ea6339efb50853be28
>>>>>>>>
>>>>>>>>           Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>>>
>>>>>>>>        amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
>>>>>>>>        1 file changed, 0 insertions(+), 0 deletions(-)
>>>>>>>>
>>>>>>>> Downgrading firmware to before that commit fixes the webcam.
>>>>>>>> Any idea why?
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Sultan
>>>>>>>
>>>>>>> So, can i say the working firmware binary is this one?
>>>>>>>
>>>>>>> Commit 8f070131
>>>>>>> amdgpu: Update ISP FW for isp v4.1.1
>>>>>>>
>>>>>>>    From internal git commit:
>>>>>>> 39b007366cc76ef8c65e3bc6220ccb213f4861fb
>>>>>>>
>>>>>>> Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>
>>>>>> Correct.
>>>>>>
>>>>>>> There are too many changes between them, so i can't tell exactly which
>>>>>>> change caused this. So, from my side
>>>>>>> 1. Will try these two firmware to see if we have the same issue.
>>>>>>> 2. It has been quite a long time since last release, will see if need to
>>>>>>> release a latest one.
>>>>>>
>>>>>> Thanks. It was a quick bisect for me, so I'm happy to help test if a
>>>>>> bisect
>>>>>> between those two internal git commits is needed.
>>>>>>
>>>>> Really appreciate your test.
>>>>>> In case it makes a difference, I have the laptop with the 2.8K OLED
>>>>>> display. I'm
>>>>>> aware there is one other display variant on other SKUs, which is a
>>>>>> WUXGA IPS.
>>>>>>
>>>>> Good to know, I believe it won't make any difference for ISP
>>>>>
>>>>>> Also, with that old firmware, my camera only works with the old isp4
>>>>>> driver from
>>>>>> that Linux_ISP_Kernel repo (which is the same isp4 driver used in
>>>>>> Ubuntu's
>>>>>> linux-oem kernel). Does the new isp4 driver you've submitted here
>>>>>> require newer
>>>>>> firmware than the old driver located in Linux_ISP_Kernel?
>>>>>>
>>>>>> Sultan
>>>>>
>>>>> We had a try, yes, both of the old FW can't work on the new ISP4 driver,
>>>>> as you know, for the last months, we did lots of driver modifications
>>>>> for upstream and cause it incompatible with old FW.
>>>>> Now, under internal discussion to upstream a new FW to support the new
>>>>> ISP driver
>>>>>
>>>>> Regards,
>>>>> Bin
>>>>>
>>>>> Hi Sultan,
>>>>
>>>> This is the conclusion of your test,
>>>> Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>> [1] It works on FW      8f070131(ext):39b00736(int)
>>>> [2] It can't work on FW 1cc8c1bf(ext):50582024(int)
>>>
>>> Correct.
>>>
>>>> Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
>>>> .config file when building the kernel? Our assumption is to make [1] work,
>>>> CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
>>>> CONFIG_VIDEO_OV05C should be defined.
>>>
>>> Yes, it is enabled and I have only tested with it enabled:
>>>
>>>       $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config
>>>       CONFIG_VIDEO_OV05C=m
>>>
>>> That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
>>> I tested by running the following commands:
>>>
>>>       git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
>>>       cd linux-oem-6.14
>>>       python debian/scripts/misc/annotations -e --arch amd64 > .config
>>>       make olddefconfig
>>>
>>> Let me know if that works.
>>>
>>> Sultan
>>
>> Thanks Sultan for the details, yes, we can reproduce the same issue on old
>> isp driver 4.0 release on FW 1cc8c1bf(ext):50582024(int), after debug, the
>> cause is
>>    - ov05c sensor device is added by amd i2c driver
>>    - When ov05c sensor driver probes, it will try to get gpio description but
>> it will fail because the amd-pinctl driver which creates the gpio resource
>> hasn't been loaded yet.
>>    - the ov05c sensor driver probe failure will finally make sensor not able
>> to work when start streaming
>>
>> Add following patch is supposed to fix this issue to make it work on FW
>> 1cc8c1bf(ext):50582024(int) when CONFIG_VIDEO_OV05C is defined.
>>
>> @@ -1121,6 +1129,7 @@ static struct i2c_driver ov05_i2c_driver = {
>>
>> module_i2c_driver(ov05_i2c_driver);
>>
>> +MODULE_SOFTDEP("pre: pinctrl-amdisp");
>> MODULE_ALIAS("ov05");
>> MODULE_DESCRIPTION("OmniVision OV05 sensor driver");
>> MODULE_LICENSE("GPL and additional rights");
>>
>> Please help to see if it works if you get time.
> 
> There is no difference I'm afraid. I applied the patch and tested with FW
> 1cc8c1bf(ext):50582024(int) and the webcam is still broken on that FW:
> 
>    [   19.523006] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
>    [   19.537000] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
>    [   19.537009] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
>    [   19.537050] PHY register access test success!
>    [   19.537901] Termination calibration observability: 0x0
>    [   19.539926] Wait for phyReady: 0x0
>    [   19.541932] Wait for phyReady: 0x1
>    [   20.901654] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
>    [   22.070676] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
>    ...
>    [   28.769372] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
>    [   28.769388] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
>    [   28.769868] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
>    [   28.771799] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]
> 
> Sultan

That's really weird, I tested kernel built from 
https://github.com/amd/Linux_ISP_Kernel/tree/4.0 with 
CONFIG_VIDEO_OV05C=m and above sensor driver probe failure patch on FW 
c8c1bf(ext):50582024(int), camera APPs like cheese, qv4l2, Camera all 
work well.

Your failure still looks like sensor related, Would you help to add log 
to sensor driver drivers/media/i2c/ov05c.c to see if its probe function 
gets called and succeeds? Here is the log in success case,

amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
PHY register access test success!
Termination calibration observability: 0x0
Wait for phyReady: 0x0
Wait for phyReady: 0x1
amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting camera sensor
amd_isp_capture amd_isp_capture.1.auto: isp_intf_start_stream,cid:0,sid:0


Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-08-11  6:02         ` Sultan Alsawaf
@ 2025-08-11  9:05           ` Du, Bin
  2025-08-12  5:51             ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-11  9:05 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

Thanks Sultan.

On 8/11/2025 2:02 PM, Sultan Alsawaf wrote:
> On Wed, Jul 30, 2025 at 05:34:22PM -0700, Sultan Alsawaf wrote:
>> On Tue, Jul 29, 2025 at 03:43:14PM +0800, Du, Bin wrote:
>>> Hi Sultan, really appreciate your time and effort
>>>
>>> On 7/28/2025 3:04 PM, Sultan Alsawaf wrote:
>>>> I found more refcounting issues in addition to the ones from my other emails
>>>> while trying to make my webcam work:
>>>>
>>>> On Wed, Jun 18, 2025 at 05:19:57PM +0800, Bin Du wrote:
>>>>> +static int isp4vid_vb2_mmap(void *buf_priv, struct vm_area_struct *vma)
>>>>> +{
>>>>> +	struct isp4vid_vb2_buf *buf = buf_priv;
>>>>> +	int ret;
>>>>> +
>>>>> +	if (!buf) {
>>>>> +		pr_err("fail no memory to map\n");
>>>>> +		return -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	ret = remap_vmalloc_range(vma, buf->vaddr, 0);
>>>>> +	if (ret) {
>>>>> +		dev_err(buf->dev, "fail remap vmalloc mem, %d\n", ret);
>>>>> +		return ret;
>>>>> +	}
>>>>> +
>>>>> +	/*
>>>>> +	 * Make sure that vm_areas for 2 buffers won't be merged together
>>>>> +	 */
>>>>> +	vm_flags_set(vma, VM_DONTEXPAND);
>>>>> +
>>>>> +	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
>>>>> +		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
>>>>
>>>> Use refcount_read() instead of reading the refcount's atomic_t counter directly.
>>>> This is done in 3 other places; change those to refcount_read() as well.
>>>>
>>>> This didn't cause any functional problems, but it should still be fixed.
>>>>
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>
>>> Sure, will fix it
>>>
>>>> [snip]
>>>>
>>>>> +static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
>>>>> +{
>>>>> +	struct isp4vid_vb2_buf *buf = mem_priv;
>>>>> +
>>>>> +	if (!buf) {
>>>>> +		pr_err("fail invalid buf handle\n");
>>>>> +		return;
>>>>> +	}
>>>>> +
>>>>> +	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
>>>>> +
>>>>> +	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
>>>>> +		buf->gpu_addr, buf->size);
>>>>> +
>>>>> +	if (buf->vaddr)
>>>>> +		dma_buf_vunmap_unlocked(buf->dbuf, &map);
>>>>> +
>>>>> +	// put dmabuf for exported ones
>>>>> +	dma_buf_put(buf->dbuf);
>>>>> +
>>>>> +	kfree(buf);
>>>>> +}
>>>>
>>>> As mentioned in the other email, the dma_buf_put() here needs to be removed. But
>>>> that's not all: the dma_buf_vunmap_unlocked() needs to be removed too because
>>>> vb2 will always unmap the buffer before detaching it. As a result, having the
>>>> dma_buf_vunmap_unlocked() call here results in a use-after-free when vb2 calls
>>>> the unmap_dmabuf memop.
>>>>
>>>> Change this function to the following:
>>>>
>>>> 	static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
>>>> 	{
>>>> 		struct isp4vid_vb2_buf *buf = mem_priv;
>>>>
>>>> 		kfree(buf);
>>>> 	}
>>>>
>>> Will have a try
>>>
>>>>> +static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
>>>>> +{
>>>>> +	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
>>>>> +	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
>>>>> +
>>>>> +	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
>>>>> +		isp_vdev->vdev.name, vb->index, vb->memory);
>>>>> +
>>>>> +	if (!buf) {
>>>>> +		dev_err(isp_vdev->dev, "Invalid buf handle");
>>>>> +		return;
>>>>> +	}
>>>>> +
>>>>> +	// release implicit dmabuf reference here for vb2 buffer
>>>>> +	// of type MMAP and is exported
>>>>> +	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
>>>>> +		dma_buf_put(buf->dbuf);
>>>>> +		dev_dbg(isp_vdev->dev,
>>>>> +			"put dmabuf for vb->memory %d expbuf %d",
>>>>> +			vb->memory,
>>>>> +			buf->is_expbuf);
>>>>> +	}
>>>>> +}
>>>>> +
>>>>
>>>> Remove the isp4vid_qops_buffer_cleanup() function. It causes a use-after-free by
>>>> doing an extra dma_buf_put(). This function isn't needed now that the refcount
>>>> issues are solved.
>>>>
>>> Will have a try
>>>
>>>> [snip]
>>>>
>>>>> +static const struct vb2_ops isp4vid_qops = {
>>>>> +	.queue_setup = isp4vid_qops_queue_setup,
>>>>> +	.buf_cleanup = isp4vid_qops_buffer_cleanup,
>>>>
>>>> Remove the .buf_cleanup hook too.
>>>>
>>> Will have a try
>>>
>>>>> +	.buf_queue = isp4vid_qops_buffer_queue,
>>>>> +	.start_streaming = isp4vid_qops_start_streaming,
>>>>> +	.stop_streaming = isp4vid_qops_stop_streaming,
>>>>> +	.wait_prepare = vb2_ops_wait_prepare,
>>>>> +	.wait_finish = vb2_ops_wait_finish,
>>>>> +};
>>>>
>>>> [snip]
>>>>
>>>> Along with the changes from my other emails, I believe this finally fixes all of
>>>> the refcounting issues. No more UaF or leaks here. :-)
>>>>
>>>> Sultan
>>> Tried changes in this and other two mails together, found the kernel will
>>> crash when re-open cheese App (means open cheese, close it and then open it
>>> again), the crash stack dump is shown below
>>>
>>> [   38.008686] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
>>> [   38.032693] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
>>> [   38.060866] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
>>> [   38.060877] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
>>> performance state 1 suc
>>> [   38.425284] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none to
>>> state 0
>>> [   38.448631] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
>>> [   38.508368] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
>>> [   38.538525] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
>>> [   38.568839] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
>>> [   38.568851] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
>>> performance state 1 suc
>>> [   38.997779] amdgpu 0000:c3:00.0: amdgpu: isp set performance do none to
>>> state 0
>>> [   39.029297] amdgpu 0000:c3:00.0: amdgpu: power off isp suc
>>> [   39.084010] BUG: kernel NULL pointer dereference, address:
>>> 0000000000000008
>>> [   39.084024] #PF: supervisor read access in kernel mode
>>> [   39.084028] #PF: error_code(0x0000) - not-present page
>>> [   39.084031] PGD 0 P4D 0
>>> [   39.084037] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
>>> [   39.084042] CPU: 3 UID: 1000 PID: 3119 Comm: viewfinderbin-q Not tainted
>>> 6.14.0-rc2+ #944
>>> [   39.084046] Hardware name: HP HP ZBook Ultra G1a 14 inch Mobile
>>> Workstation PC/8D01, BIOS X89 Ver. 01.03.00 04/25/2025
>>> [   39.084049] RIP: 0010:validate_page_before_insert+0x5/0xc0
>>> [   39.084060] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 00
>>> 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 <48>
>>> 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
>>> [   39.084064] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
>>> [   39.084067] RAX: 0000000000000000 RBX: 8000000000000025 RCX:
>>> 0000000000000000
>>> [   39.084069] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
>>> ffff9efa10e400b8
>>> [   39.084071] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09:
>>> 0000000000000000
>>> [   39.084072] R10: 0000000000000000 R11: 0000000000000000 R12:
>>> ffff9efa10e400b8
>>> [   39.084074] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15:
>>> 0000000000000000
>>> [   39.084076] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000)
>>> knlGS:0000000000000000
>>> [   39.084078] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>> [   39.084080] CR2: 0000000000000008 CR3: 0000000137bba000 CR4:
>>> 0000000000750ef0
>>> [   39.084083] PKRU: 55555554
>>> [   39.084084] Call Trace:
>>> [   39.084087]  <TASK>
>>> [   39.084093]  ? show_regs+0x71/0x90
>>> [   39.084099]  ? __die+0x25/0x80
>>> [   39.084102]  ? page_fault_oops+0x15c/0x570
>>> [   39.084108]  ? do_user_addr_fault+0x4a9/0x810
>>> [   39.084111]  ? __mod_memcg_lruvec_state+0xde/0x280
>>> [   39.084117]  ? exc_page_fault+0x83/0x1d0
>>> [   39.084123]  ? asm_exc_page_fault+0x27/0x30
>>> [   39.084131]  ? validate_page_before_insert+0x5/0xc0
>>> [   39.084134]  ? vm_insert_page+0xd4/0x1a0
>>> [   39.084139]  remap_vmalloc_range_partial+0xe3/0x160
>>> [   39.084145]  remap_vmalloc_range+0x21/0x40
>>> [   39.084153]  isp4vid_vb2_mmap+0x2d/0x130 [amd_capture]
>>> [   39.084164]  isp4vid_vb2_dmabuf_ops_mmap+0x12/0x20 [amd_capture]
>>> [   39.084168]  dma_buf_mmap_internal+0x41/0x70
>>> [   39.084173]  __mmap_region+0x62f/0xbc0
>>> [   39.084179]  mmap_region+0x67/0xe0
>>> [   39.084181]  do_mmap+0x52b/0x650
>>> [   39.084187]  vm_mmap_pgoff+0xf4/0x1c0
>>> [   39.084194]  ksys_mmap_pgoff+0x182/0x250
>>> [   39.084198]  __x64_sys_mmap+0x33/0x70
>>> [   39.084202]  x64_sys_call+0x2541/0x26f0
>>> [   39.084206]  do_syscall_64+0x70/0x130
>>> [   39.084212]  ? __rseq_handle_notify_resume+0xa4/0x520
>>> [   39.084216]  ? do_futex+0x17f/0x220
>>> [   39.084220]  ? restore_fpregs_from_fpstate+0x3d/0xd0
>>> [   39.084225]  ? switch_fpu_return+0x50/0xe0
>>> [   39.084229]  ? syscall_exit_to_user_mode+0x18c/0x1c0
>>> [   39.084234]  ? do_syscall_64+0x7c/0x130
>>> [   39.084237]  ? __pfx_futex_wake_mark+0x10/0x10
>>> [   39.084241]  ? hrtimer_cancel+0x15/0x50
>>> [   39.084246]  ? futex_wait+0x7c/0x120
>>> [   39.084249]  ? __pfx_hrtimer_wakeup+0x10/0x10
>>> [   39.084254]  ? __rseq_handle_notify_resume+0xa4/0x520
>>> [   39.084256]  ? do_futex+0x17f/0x220
>>> [   39.084258]  ? restore_fpregs_from_fpstate+0x3d/0xd0
>>> [   39.084261]  ? switch_fpu_return+0x50/0xe0
>>> [   39.084264]  ? syscall_exit_to_user_mode+0x18c/0x1c0
>>> [   39.084268]  ? do_syscall_64+0x7c/0x130
>>> [   39.084272]  ? __count_memcg_events+0xcd/0x190
>>> [   39.084276]  ? count_memcg_events.constprop.0+0x2a/0x50
>>> [   39.084279]  ? handle_mm_fault+0x1ef/0x2d0
>>> [   39.084284]  ? do_user_addr_fault+0x58d/0x810
>>> [   39.084286]  ? irqentry_exit_to_user_mode+0x33/0x180
>>> [   39.084291]  ? irqentry_exit+0x43/0x50
>>> [   39.084294]  ? exc_page_fault+0x94/0x1d0
>>> [   39.084298]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
>>> [   39.084302] RIP: 0033:0x7fa463b2531c
>>> [   39.084305] Code: 1e fa 41 f7 c1 ff 0f 00 00 75 33 55 48 89 e5 41 54 41
>>> 89 cc 53 48 89 fb 48 85 ff 74 41 45 89 e2 48 89 df b8 09 00 00 00 0f 05 <48>
>>> 3d 00 f0 ff ff 77 7c 5b 41 5c 5d c3 0f 1f 80 00 00 00 00 48 8b
>>> [   39.084308] RSP: 002b:00007fa3f4bf79e0 EFLAGS: 00000246 ORIG_RAX:
>>> 0000000000000009
>>> [   39.084311] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
>>> 00007fa463b2531c
>>> [   39.084312] RDX: 0000000000000001 RSI: 00000000007782c0 RDI:
>>> 0000000000000000
>>> [   39.084314] RBP: 00007fa3f4bf79f0 R08: 0000000000000047 R09:
>>> 0000000000000000
>>> [   39.084315] R10: 0000000000000001 R11: 0000000000000246 R12:
>>> 0000000000000001
>>> [   39.084317] R13: 0000000000000000 R14: 00007fa3f8019b48 R15:
>>> 00007fa3f4bf7b60
>>> [   39.084320]  </TASK>
>>> [   39.084321] Modules linked in: snd_seq_dummy snd_hrtimer hid_sensor_prox
>>> hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer
>>> kfifo_buf hid_sensor_iio_common industrialio hid_sensor_hub rfcomm cmac
>>> algif_hash algif_skcipher af_alg hid_logitech_hidpp ov05c10 v4l2_cci
>>> amd_capture v4l2_fwnode videobuf2_memops videobuf2_v4l2 videobuf2_common
>>> v4l2_async videodev pinctrl_amdisp i2c_designware_amdisp qrtr bnep btusb
>>> btrtl btintel btbcm btmtk bluetooth hid_logitech_dj intel_rapl_msr amd_atl
>>> intel_rapl_common binfmt_misc nls_iso8859_1 snd_acp_legacy_mach snd_acp_mach
>>> snd_soc_nau8821 snd_acp3x_rn amdgpu edac_mce_amd snd_ctl_led
>>> snd_hda_codec_realtek snd_acp70 snd_hda_codec_generic snd_acp_i2s
>>> snd_acp_pdm snd_hda_scodec_component snd_soc_dmic snd_acp_pcm
>>> snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci
>>> snd_sof_xtensa_dsp snd_hda_codec_hdmi snd_sof snd_sof_utils snd_pci_ps
>>> snd_soc_acpi_amd_match snd_amd_sdw_acpi soundwire_amd
>>> soundwire_generic_allocation soundwire_bus snd_hda_intel kvm_amd
>>> [   39.084385]  snd_soc_sdca snd_intel_dspcfg snd_intel_sdw_acpi
>>> snd_soc_core snd_hda_codec amdxcp kvm snd_compress
>>> drm_panel_backlight_quirks snd_hda_core snd_usb_audio gpu_sched ac97_bus
>>> polyval_clmulni snd_pcm_dmaengine polyval_generic ghash_clmulni_intel
>>> drm_buddy snd_usbmidi_lib snd_seq_midi snd_rpl_pci_acp6x sha256_ssse3
>>> snd_ump drm_ttm_helper snd_seq_midi_event snd_hwdep sha1_ssse3 ttm
>>> aesni_intel drm_exec snd_rawmidi drm_suballoc_helper snd_acp_pci mc
>>> crypto_simd snd_acp_legacy_common drm_client_lib cryptd drm_display_helper
>>> snd_pci_acp6x snd_seq rapl hp_wmi cec wmi_bmof snd_pcm sparse_keymap
>>> snd_seq_device rc_core snd_timer snd_pci_acp5x drm_kms_helper
>>> snd_rn_pci_acp3x amd_pmf snd i2c_algo_bit snd_acp_config i2c_piix4
>>> snd_soc_acpi amdtee soundcore snd_pci_acp3x i2c_smbus ccp joydev tee
>>> input_leds serial_multi_instantiate amd_pmc platform_profile wireless_hotkey
>>> mac_hid serio_raw sch_fq_codel msr parport_pc ppdev lp parport efi_pstore
>>> nfnetlink dmi_sysfs ip_tables x_tables autofs4 r8152 mii usbhid
>>> hid_multitouch
>>> [   39.084451]  hid_generic nvme ucsi_acpi i2c_hid_acpi video typec_ucsi
>>> i2c_hid amd_sfh thunderbolt hid nvme_core typec wmi drm
>>> [   39.084465] CR2: 0000000000000008
>>> [   39.084468] ---[ end trace 0000000000000000 ]---
>>> [   39.116114] amdgpu 0000:c3:00.0: amdgpu: power on isp suc
>>> [   39.159519] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 suc, reg_val 800
>>> [   39.201325] amdgpu 0000:c3:00.0: amdgpu: set iclk 788 suc, reg_val 792
>>> [   39.201334] amdgpu 0000:c3:00.0: amdgpu: set xclk 788 iclk 788 to
>>> performance state 1 suc
>>> [   39.343894] RIP: 0010:validate_page_before_insert+0x5/0xc0
>>> [   39.343907] Code: 31 c9 31 ff 45 31 c0 c3 cc cc cc cc 66 0f 1f 84 00 00
>>> 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 <48>
>>> 8b 46 08 a8 01 75 7a 66 90 48 89 f0 8b 50 34 85 d2 0f 84 8c 00
>>> [   39.343909] RSP: 0018:ffffb95e05e7b6a0 EFLAGS: 00010202
>>> [   39.343911] RAX: 0000000000000000 RBX: 8000000000000025 RCX:
>>> 0000000000000000
>>> [   39.343913] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
>>> ffff9efa10e400b8
>>> [   39.343913] RBP: ffffb95e05e7b6e0 R08: 0000000000000000 R09:
>>> 0000000000000000
>>> [   39.343914] R10: 0000000000000000 R11: 0000000000000000 R12:
>>> ffff9efa10e400b8
>>> [   39.343915] R13: ffffb95e0e055000 R14: 00007fa3d6119000 R15:
>>> 0000000000000000
>>> [   39.343916] FS:  00007fa3f4bf96c0(0000) GS:ffff9f050d780000(0000)
>>> knlGS:0000000000000000
>>> [   39.343917] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>> [   39.343918] CR2: 0000000000000008 CR3: 0000000137bba000 CR4:
>>> 0000000000750ef0
>>> [   39.343919] PKRU: 55555554
>>> [   39.343920] note: viewfinderbin-q[3119] exited with irqs disabled
>>>
>>> This is the patch, it should have contained all your changes
>>>
>>>  From b0a61b6b7500635928166516d5563e6de50300bb Mon Sep 17 00:00:00 2001
>>> From: Bin Du <Bin.Du@amd.com>
>>> Date: Mon, 28 Jul 2025 14:18:04 +0800
>>> Subject: [PATCH] add comment from community
>>>
>>> Change-Id: I06fff629c0dc691eaeaa9d9b81e6af27cbb6adb2
>>> ---
>>>   drivers/media/platform/amd/isp4/isp4_video.c | 59 ++++++--------------
>>>   1 file changed, 17 insertions(+), 42 deletions(-)
>>>
>>> diff --git a/drivers/media/platform/amd/isp4/isp4_video.c
>>> b/drivers/media/platform/amd/isp4/isp4_video.c
>>> index a1376498c246..b210a0b1e49b 100644
>>> --- a/drivers/media/platform/amd/isp4/isp4_video.c
>>> +++ b/drivers/media/platform/amd/isp4/isp4_video.c
>>> @@ -183,7 +183,7 @@ static int isp4vid_vb2_mmap(void *buf_priv, struct
>>> vm_area_struct *vma)
>>>   	vm_flags_set(vma, VM_DONTEXPAND);
>>>
>>>   	dev_dbg(buf->dev, "mmap isp user bo 0x%llx size %ld refcount %d\n",
>>> -		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
>>> +		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));
>>>
>>>   	return 0;
>>>   }
>>> @@ -214,14 +214,9 @@ static void isp4vid_vb2_detach_dmabuf(void *mem_priv)
>>>   		return;
>>>   	}
>>>
>>> -	struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
>>> -
>>>   	dev_dbg(buf->dev, "detach dmabuf of isp user bo 0x%llx size %ld",
>>>   		buf->gpu_addr, buf->size);
>>>
>>> -	if (buf->vaddr)
>>> -		dma_buf_vunmap_unlocked(buf->dbuf, &map);
>>> -
>>>   	kfree(buf);
>>>   }
>>>
>>> @@ -470,21 +465,25 @@ static struct dma_buf *isp4vid_vb2_get_dmabuf(struct
>>> vb2_buffer *vb,
>>>   					      unsigned long flags)
>>>   {
>>>   	struct isp4vid_vb2_buf *buf = buf_priv;
>>> -	struct dma_buf *dbuf;
>>> +	struct dma_buf *dbuf = buf->dbuf;
>>> +
>>> +	if (dbuf) {
>>> +		dev_dbg(buf->dev, "dbuf already created, reuse %s dbuf\n",
>>> +			buf->is_expbuf ? "exported" : "implicit");
>>> +		get_dma_buf(dbuf);
>>>
>>> -	if (buf->dbuf) {
>>> -		dev_dbg(buf->dev, "dbuf already created, reuse implicit dbuf\n");
>>> -		dbuf = buf->dbuf;
>>>   	} else {
>>>   		dbuf = isp4vid_get_dmabuf(vb, buf_priv, flags);
>>> +		if (!dbuf)
>>> +			return NULL;
>>> +
>>>   		dev_dbg(buf->dev, "created new dbuf\n");
>>> +		buf->is_expbuf = true;
>>> +		refcount_inc(&buf->refcount);
>>>   	}
>>>
>>> -	buf->is_expbuf = true;
>>> -	refcount_inc(&buf->refcount);
>>> -
>>>   	dev_dbg(buf->dev, "buf exported, refcount %d\n",
>>> -		buf->refcount.refs.counter);
>>> +		refcount_read(&buf->refcount));
>>>
>>>   	return dbuf;
>>>   }
>>> @@ -579,8 +578,9 @@ static void isp4vid_vb2_put(void *buf_priv)
>>>   {
>>>   	struct isp4vid_vb2_buf *buf = (struct isp4vid_vb2_buf *)buf_priv;
>>>   	unsigned int ref_cnt = refcount_read(&buf->refcount);
>>> +	struct device *dev = buf->dev;
>>>
>>> -	dev_dbg(buf->dev,
>>> +	dev_dbg(dev,
>>>   		"release isp user bo 0x%llx size %ld refcount %u is_expbuf %d\n",
>>>   		buf->gpu_addr, buf->size,
>>>   		ref_cnt, buf->is_expbuf);
>>> @@ -598,7 +598,7 @@ static void isp4vid_vb2_put(void *buf_priv)
>>>   		/* the ref_cnt - 1 is just a predicted value as reference, can't
>>>   		 * guarantee it's the actual value now
>>>   		 */
>>> -		dev_warn(buf->dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
>>> +		dev_warn(dev, "ignore buffer free, refcount %u > 0\n", ref_cnt - 1);
>>>   	}
>>>   }
>>>
>>> @@ -642,7 +642,7 @@ static void *isp4vid_vb2_alloc(struct vb2_buffer *vb,
>>> struct device *dev,
>>>   	refcount_set(&buf->refcount, 1);
>>>
>>>   	dev_dbg(dev, "allocated isp user bo 0x%llx size %ld refcount %d\n",
>>> -		buf->gpu_addr, buf->size, buf->refcount.refs.counter);
>>> +		buf->gpu_addr, buf->size, refcount_read(&buf->refcount));
>>>
>>>   	return buf;
>>>   err_free:
>>> @@ -1140,30 +1140,6 @@ static void isp4vid_qops_buffer_queue(struct
>>> vb2_buffer *vb)
>>>   	mutex_unlock(&isp_vdev->buf_list_lock);
>>>   }
>>>
>>> -static void isp4vid_qops_buffer_cleanup(struct vb2_buffer *vb)
>>> -{
>>> -	struct isp4vid_dev *isp_vdev = vb2_get_drv_priv(vb->vb2_queue);
>>> -	struct isp4vid_vb2_buf *buf = vb->planes[0].mem_priv;
>>> -
>>> -	dev_dbg(isp_vdev->dev, "%s|index=%u vb->memory %u",
>>> -		isp_vdev->vdev.name, vb->index, vb->memory);
>>> -
>>> -	if (!buf) {
>>> -		dev_err(isp_vdev->dev, "Invalid buf handle");
>>> -		return;
>>> -	}
>>> -
>>> -	// release implicit dmabuf reference here for vb2 buffer
>>> -	// of type MMAP and is exported
>>> -	if (vb->memory == VB2_MEMORY_MMAP && buf->is_expbuf) {
>>> -		dma_buf_put(buf->dbuf);
>>> -		dev_dbg(isp_vdev->dev,
>>> -			"put dmabuf for vb->memory %d expbuf %d",
>>> -			vb->memory,
>>> -			buf->is_expbuf);
>>> -	}
>>> -}
>>> -
>>>   static int isp4vid_qops_start_streaming(struct vb2_queue *vq,
>>>   					unsigned int count)
>>>   {
>>> @@ -1343,7 +1319,6 @@ static int isp4vid_fill_buffer_size(struct isp4vid_dev
>>> *isp_vdev)
>>>
>>>   static const struct vb2_ops isp4vid_qops = {
>>>   	.queue_setup = isp4vid_qops_queue_setup,
>>> -	.buf_cleanup = isp4vid_qops_buffer_cleanup,
>>>   	.buf_queue = isp4vid_qops_buffer_queue,
>>>   	.start_streaming = isp4vid_qops_start_streaming,
>>>   	.stop_streaming = isp4vid_qops_stop_streaming,
>>> -- 
>>> 2.34.1
>>
>> The patch looks correct. I will get back to you on this after doing some testing
>> myself.
>>
>> FYI, I can only test these changes with the old isp4 driver right now, since the
>> new isp4 driver doesn't work for me as mentioned in my other email. So far,
>> something does seem wrong after these changes I suggested because they break the
>> camera on the old isp4 driver too.
> 
> Following up on this: there were several more issues hiding in the driver that
> needed to be fixed unfortunately. I ended up making a lot of changes to fix all
> of the buffer lifetime issues, and I created individual commits for this work
> because it was getting hard to keep track of all the changes.
> 
> I think I'll have this completed tomorrow and will provide a link to my tree
> with my commits. Hopefully your internal branch hasn't diverged too much from
> this patchset submission, otherwise there may be some conflicts to resolve.
> 
> Sultan

Really appreciate your time and effort. Yes, big code changes happen in 
our internal branch to address upstream comments, but i believe your 
commits will be extremely valuable. We can check and test after fixing 
possbile conflict.

Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-07-29  9:12     ` Du, Bin
@ 2025-08-11 11:46       ` Sakari Ailus
  2025-08-11 12:31         ` Laurent Pinchart
  2025-08-12  2:44         ` Du, Bin
  0 siblings, 2 replies; 96+ messages in thread
From: Sakari Ailus @ 2025-08-11 11:46 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

Hi Bin,

On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
> Many thanks Askari Ailus for your careful review
> 
> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
> > Hi Bin,
> > 
> > On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
> > > ISP firmware controls ISP HW pipeline using dedicated embedded processor
> > > called ccpu.
> > > The communication between ISP FW and driver is using commands and
> > > response messages sent through the ring buffer. Command buffers support
> > > either global setting that is not specific to the steam and support stream
> > > specific parameters. Response buffers contains ISP FW notification
> > > information such as frame buffer done and command done. IRQ is used for
> > > receiving response buffer from ISP firmware, which is handled in the main
> > > isp4 media device. ISP ccpu is booted up through the firmware loading
> > > helper function prior to stream start.
> > > Memory used for command buffer and response buffer needs to be allocated
> > > from amdgpu buffer manager because isp4 is a child device of amdgpu.
> > 
> > Please rewrap this, some lines above are quite short.
> > 
> Thanks, the line after the short line is supposed to be a new paragraph?
> Should we put all the description in one paragraph?

One or more paragraphs work fine, but a new paragraph is separated from the
previous one by another newline.

...

> > > +	void *cpu_ptr;
> > > +	u64 gpu_addr;
> > > +	u32 ret;
> > > +
> > > +	dev = ispif->dev;
> > > +
> > > +	if (!mem_size)
> > > +		return NULL;
> > > +
> > > +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
> > > +	if (!mem_info)
> > > +		return NULL;
> > > +
> > > +	adev = (struct amdgpu_device *)ispif->adev;
> > 
> > Why the cast?
> > 
> > adev isn't a great name here as it's usually used for struct acpi_devices.
> > 
> In the next patch, will use new helper function for this and will no longer
> use amdgpu_device

Use correct types when you can; either way this doesn't seem to be changed
by the further patches in the set.

...

> > > +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
> > > +			       struct isp4if_gpu_mem_info *mem_info)
> > > +{
> > > +	struct device *dev = ispif->dev;
> > > +	struct amdgpu_bo *bo;
> > > +
> > > +	if (!mem_info) {
> > > +		dev_err(dev, "invalid mem_info\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
> > 
> > Why do you need to cast here?
> > 
> In the next patch, will use new helper function for this and will no longer
> use amdgpu_bo

Not quite, on top of this patch number 6 adds more of the same.

...

> > > +static struct isp4if_cmd_element *
> > > +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
> > > +			 struct isp4if_cmd_element *cmd_ele)
> > > +{
> > > +	struct isp4if_cmd_element *copy_command = NULL;
> > > +
> > > +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
> > > +	if (!copy_command)
> > > +		return NULL;
> > > +
> > > +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
> > 
> > kmemdup()?
> > 
> Kmemdup is to allocate memory and copy, can't be used here.

Isn't that what you're doing above?

> 
> > > +
> > > +	guard(mutex)(&ispif->cmdq_mutex);
> > > +
> > > +	list_add_tail(&copy_command->list, &ispif->cmdq);
> > > +
> > > +	return copy_command;
> > > +}

-- 
Regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-11 11:46       ` Sakari Ailus
@ 2025-08-11 12:31         ` Laurent Pinchart
  2025-08-12  3:36           ` Du, Bin
  2025-08-12  2:44         ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Laurent Pinchart @ 2025-08-11 12:31 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Du, Bin, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Mon, Aug 11, 2025 at 11:46:27AM +0000, Sakari Ailus wrote:
> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
> > On 7/28/2025 3:23 PM, Sakari Ailus wrote:
> > > On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
> > > > ISP firmware controls ISP HW pipeline using dedicated embedded processor
> > > > called ccpu.
> > > > The communication between ISP FW and driver is using commands and
> > > > response messages sent through the ring buffer. Command buffers support
> > > > either global setting that is not specific to the steam and support stream
> > > > specific parameters. Response buffers contains ISP FW notification
> > > > information such as frame buffer done and command done. IRQ is used for
> > > > receiving response buffer from ISP firmware, which is handled in the main
> > > > isp4 media device. ISP ccpu is booted up through the firmware loading
> > > > helper function prior to stream start.
> > > > Memory used for command buffer and response buffer needs to be allocated
> > > > from amdgpu buffer manager because isp4 is a child device of amdgpu.
> > > 
> > > Please rewrap this, some lines above are quite short.
> > > 
> > Thanks, the line after the short line is supposed to be a new paragraph?
> > Should we put all the description in one paragraph?
> 
> One or more paragraphs work fine, but a new paragraph is separated from the
> previous one by another newline.
> 
> ...

Paragraphs are defined as a block of text that convey one idea. They
should be visually separated by a space. As we can't have fractional
line spacing in plain text, paragraphs need to be separated by a blank
line. This is a typography rule that maximizes readability. There should
be no line break between sentences in a single paragraph.

Whether you write commit messages, formal documentation or comments in
code, typography is important to give the best experience to readers.
After all, a block of text that wouldn't focus on the readers would have
no reason to exist.


Now compare the above with


Paragraphs are defined as a block of text that convey one idea. They
should be visually separated by a space.
As we can't have fractional line spacing in plain text, paragraphs need
to be separated by a blank line.
This is a typography rule that maximizes readability. There should be no
line break between sentences in a single paragraph. Whether you write
commit messages, formal documentation or comments in code, typography is
important to give the best experience to readers.
After all, a block of text that wouldn't focus on the readers would have
no reason to exist.

> > > > +	void *cpu_ptr;
> > > > +	u64 gpu_addr;
> > > > +	u32 ret;
> > > > +
> > > > +	dev = ispif->dev;
> > > > +
> > > > +	if (!mem_size)
> > > > +		return NULL;
> > > > +
> > > > +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
> > > > +	if (!mem_info)
> > > > +		return NULL;
> > > > +
> > > > +	adev = (struct amdgpu_device *)ispif->adev;
> > > 
> > > Why the cast?
> > > 
> > > adev isn't a great name here as it's usually used for struct acpi_devices.
> > > 
> > In the next patch, will use new helper function for this and will no longer
> > use amdgpu_device
> 
> Use correct types when you can; either way this doesn't seem to be changed
> by the further patches in the set.
> 
> ...
> 
> > > > +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
> > > > +			       struct isp4if_gpu_mem_info *mem_info)
> > > > +{
> > > > +	struct device *dev = ispif->dev;
> > > > +	struct amdgpu_bo *bo;
> > > > +
> > > > +	if (!mem_info) {
> > > > +		dev_err(dev, "invalid mem_info\n");
> > > > +		return -EINVAL;
> > > > +	}
> > > > +
> > > > +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
> > > 
> > > Why do you need to cast here?
> > > 
> > In the next patch, will use new helper function for this and will no longer
> > use amdgpu_bo
> 
> Not quite, on top of this patch number 6 adds more of the same.
> 
> ...
> 
> > > > +static struct isp4if_cmd_element *
> > > > +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
> > > > +			 struct isp4if_cmd_element *cmd_ele)
> > > > +{
> > > > +	struct isp4if_cmd_element *copy_command = NULL;
> > > > +
> > > > +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
> > > > +	if (!copy_command)
> > > > +		return NULL;
> > > > +
> > > > +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
> > > 
> > > kmemdup()?
> > > 
> > Kmemdup is to allocate memory and copy, can't be used here.
> 
> Isn't that what you're doing above?
> 
> > > > +
> > > > +	guard(mutex)(&ispif->cmdq_mutex);
> > > > +
> > > > +	list_add_tail(&copy_command->list, &ispif->cmdq);
> > > > +
> > > > +	return copy_command;
> > > > +}

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-11  8:35                               ` Du, Bin
@ 2025-08-11 21:48                                 ` Sultan Alsawaf
  2025-08-11 22:17                                   ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-11 21:48 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Mon, Aug 11, 2025 at 04:35:10PM +0800, Du, Bin wrote:
> On 8/11/2025 1:49 PM, Sultan Alsawaf wrote:
> > On Fri, Aug 08, 2025 at 05:11:39PM +0800, Du, Bin wrote:
> > > On 8/4/2025 12:25 PM, Sultan Alsawaf wrote:
> > > > On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
> > > > > On 7/31/2025 6:04 PM, Du, Bin wrote:
> > > > > > Thanks Sultan for your test
> > > > > > 
> > > > > > On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
> > > > > > > On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
> > > > > > > > On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
> > > > > > > > > On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
> > > > > > > > > > On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> > > > > > > > > > > On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> > > > > > > > > > > > On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > > > > > > > > > > > > Thanks Sultan, please see my comments
> > > > > > > > > > > > > 
> > > > > > > > > > > > > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > > > > > > > > > > > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > > > > > > > > > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > I cannot for the life of me get
> > > > > > > > > > > > > > > > the webcam working under Linux.
> > > > > > > > > > > > > > > > The webcam works
> > > > > > > > > > > > > > > > under Windows so it's not a hardware issue.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > With this patchset and all of
> > > > > > > > > > > > > > > > the patches you link here
> > > > > > > > > > > > > > > > applied to 6.15, I get
> > > > > > > > > > > > > > > > the following errors:
> > > > > > > > > > > > > > > >          [   11.970038]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware: Unknown
> > > > > > > > > > > > > > > > Synopsys component type:
> > > > > > > > > > > > > > > > 0xffffffff
> > > > > > > > > > > > > > > >          [   11.973162]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware: error
> > > > > > > > > > > > > > > > -19: i2c_dw_probe failed
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > With the old ispkernel code from
> > > > > > > > > > > > > > > > February [1] applied on 6.15,
> > > > > > > > > > > > > > > > the webcam
> > > > > > > > > > > > > > > > indicator LED lights up but
> > > > > > > > > > > > > > > > there's no image. I see these
> > > > > > > > > > > > > > > > messages at boot:
> > > > > > > > > > > > > > > >          [    9.449005]
> > > > > > > > > > > > > > > > amd_isp_capture
> > > > > > > > > > > > > > > > amd_isp_capture.1.auto: amdgpu:
> > > > > > > > > > > > > > > > AMD ISP v4l2 device registered
> > > > > > > > > > > > > > > >          [    9.489005]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > The OV05 sensor device is added
> > > > > > > > > > > > > > > > to the ISP I2C bus
> > > > > > > > > > > > > > > >          [    9.529012]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > > > > > current transfer
> > > > > > > > > > > > > > > >          [    9.554046]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > > > > >          [    9.554174]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > > > > > current transfer
> > > > > > > > > > > > > > > >          [    9.580022]
> > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > And then the kernel crashes due
> > > > > > > > > > > > > > > > to the same use-after-free
> > > > > > > > > > > > > > > > issues I pointed out
> > > > > > > > > > > > > > > > in my other email [2].
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Any idea what's going on?
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > [1]
> > > > > > > > > > > > > > > > https://github.com/amd/Linux_ISP_Kernel/commit/
> > > > > > > > > > > > > > > > c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > > > > > > > > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > > > > > > > > > > > > Hi Sultan,
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > [1] is for kernel 6.8, believe it
> > > > > > > > > > > > > > > can't be applied to 6.15. We didn't
> > > > > > > > > > > > > > > verify
> > > > > > > > > > > > > > > on 6.15 but we are really glad to
> > > > > > > > > > > > > > > help, would you please provide some
> > > > > > > > > > > > > > > info,
> > > > > > > > > > > > > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > > > > > > > > > > > > 2. 6.15, do you mean
> > > > > > > > > > > > > > > https://github.com/torvalds/linux/tree/
> > > > > > > > > > > > > > > v6.15 ?
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > After your confirmation, we'll see
> > > > > > > > > > > > > > > what we can do to enable your camera
> > > > > > > > > > > > > > > quickly and easily
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Regards,
> > > > > > > > > > > > > > > Bin
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Thank you, Bin!
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > > > > > > > > > > > > 2. Yes, here is my kernel source [2].
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I have some more findings:
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Currently, the first blocking issue is
> > > > > > > > > > > > > > that the I2C adapter fails to
> > > > > > > > > > > > > > initialize.
> > > > > > > > > > > > > > This is because the ISP tile isn't powered on.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I noticed that in the old version of
> > > > > > > > > > > > > > amd_isp_i2c_designware [3], there were
> > > > > > > > > > > > > > calls to isp_power_set(), which is
> > > > > > > > > > > > > > available in the old ISP4 sources [4].
> > > > > > > > > > > > > > Without isp_power_set(), the I2C adapter
> > > > > > > > > > > > > > always fails to initialize for me.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > How is the ISP tile supposed to get
> > > > > > > > > > > > > > powered on in the current ISP4 code?
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > You are correct, yes, i believe the I2C
> > > > > > > > > > > > > adapter failure is caused by ISP not
> > > > > > > > > > > > > being powered up. Currently in latest code,
> > > > > > > > > > > > > isp_power_set is no longer
> > > > > > > > > > > > > available, instead, we implemented genPD for ISP in amdgpu
> > > > > > > > > > > > > https://lore.kernel.org/all/20250618221923.3944751-1-
> > > > > > > > > > > > > pratap.nirujogi@amd.com/
> > > > > > > > > > > > > Both amd_isp_i2c and amd_isp_capture are in
> > > > > > > > > > > > > the power domain and use the
> > > > > > > > > > > > > standard runtime PM API to do the power control
> > > > > > > > > > > > 
> > > > > > > > > > > > Thanks for that link, I found it along with
> > > > > > > > > > > > another patch on the list to make
> > > > > > > > > > > > the fwnode work ("drm/amd/amdgpu: Initialize
> > > > > > > > > > > > swnode for ISP MFD device").
> > > > > > > > > > > > 
> > > > > > > > > > > > > > Also, I noticed that the driver init
> > > > > > > > > > > > > > ordering matters between all of the
> > > > > > > > > > > > > > drivers
> > > > > > > > > > > > > > needed for the ISP4 camera. In
> > > > > > > > > > > > > > particular, amd_isp_i2c_designware and
> > > > > > > > > > > > > > amd_isp4
> > > > > > > > > > > > > > must be initialized before amd_capture,
> > > > > > > > > > > > > > otherwise amd_capture will fail to find
> > > > > > > > > > > > > > the fwnode properties for the OV05C10
> > > > > > > > > > > > > > device attached to the I2C bus.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > But there is no driver init ordering
> > > > > > > > > > > > > > enforced, which also caused some issues
> > > > > > > > > > > > > > for
> > > > > > > > > > > > > > me until I figured it out. Maybe probe
> > > > > > > > > > > > > > deferral (-EPROBE_DEFER) should be used
> > > > > > > > > > > > > > to ensure each driver waits for its dependencies to init first?
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > amd_isp_capture only has dependency on
> > > > > > > > > > > > > amd_isp4 which is the ACPI platform
> > > > > > > > > > > > > driver, it is init before amd_isp_catpure.
> > > > > > > > > > > > > Do you see in your side the amd_capture
> > > > > > > > > > > > > probe failure caused by failing to
> > > > > > > > > > > > > read fwnode properties? If that's the case
> > > > > > > > > > > > > please help to check if amd_isp4
> > > > > > > > > > > > > is loaded successfully
> > > > > > > > > > > > 
> > > > > > > > > > > > I got much further now: there aren't any driver
> > > > > > > > > > > > initialization errors, but when
> > > > > > > > > > > > I open the camera, there's no image. The camera
> > > > > > > > > > > > LED turns on so it's active.
> > > > > > > > > > > > 
> > > > > > > > > > > > And then shortly afterwards, amdgpu dies and the
> > > > > > > > > > > > entire system freezes.
> > > > > > > > > > > > 
> > > > > > > > > > > > I've attached my full dmesg, please let me know
> > > > > > > > > > > > what you think. Thanks!
> > > > > > > > > > > 
> > > > > > > > > > > I almost forgot, here is my current kernel tree:
> > > > > > > > > > > https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
> > > > > > > > > > > sultan-isp4
> > > > > > > > > > > 
> > > > > > > > > > > Sultan
> > > > > > > > > > 
> > > > > > > > > > Thanks Sultan, yes, seems much close to the final
> > > > > > > > > > success. Will have some
> > > > > > > > > > internal discussion.
> > > > > > > > > 
> > > > > > > > > I got the webcam working. The same bug happened when I tried
> > > > > > > > > Ubuntu's linux-oem
> > > > > > > > > kernel, which made me think that the issue was firmware.
> > > > > > > > > 
> > > > > > > > > And indeed, the culprit was a firmware update from February. I bisected
> > > > > > > > > linux-firmware and found the commit which broke the webcam for me:
> > > > > > > > > 
> > > > > > > > >       commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
> > > > > > > > >       Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > > >       Date:   Wed Feb 19 12:16:51 2025 -0500
> > > > > > > > > 
> > > > > > > > >           amdgpu: Update ISP FW for isp v4.1.1
> > > > > > > > > 
> > > > > > > > >           From internal git commit:
> > > > > > > > >           5058202443e08a673b6772ea6339efb50853be28
> > > > > > > > > 
> > > > > > > > >           Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > > > 
> > > > > > > > >        amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
> > > > > > > > >        1 file changed, 0 insertions(+), 0 deletions(-)
> > > > > > > > > 
> > > > > > > > > Downgrading firmware to before that commit fixes the webcam.
> > > > > > > > > Any idea why?
> > > > > > > > > 
> > > > > > > > > Thanks,
> > > > > > > > > Sultan
> > > > > > > > 
> > > > > > > > So, can i say the working firmware binary is this one?
> > > > > > > > 
> > > > > > > > Commit 8f070131
> > > > > > > > amdgpu: Update ISP FW for isp v4.1.1
> > > > > > > > 
> > > > > > > >    From internal git commit:
> > > > > > > > 39b007366cc76ef8c65e3bc6220ccb213f4861fb
> > > > > > > > 
> > > > > > > > Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > 
> > > > > > > Correct.
> > > > > > > 
> > > > > > > > There are too many changes between them, so i can't tell exactly which
> > > > > > > > change caused this. So, from my side
> > > > > > > > 1. Will try these two firmware to see if we have the same issue.
> > > > > > > > 2. It has been quite a long time since last release, will see if need to
> > > > > > > > release a latest one.
> > > > > > > 
> > > > > > > Thanks. It was a quick bisect for me, so I'm happy to help test if a
> > > > > > > bisect
> > > > > > > between those two internal git commits is needed.
> > > > > > > 
> > > > > > Really appreciate your test.
> > > > > > > In case it makes a difference, I have the laptop with the 2.8K OLED
> > > > > > > display. I'm
> > > > > > > aware there is one other display variant on other SKUs, which is a
> > > > > > > WUXGA IPS.
> > > > > > > 
> > > > > > Good to know, I believe it won't make any difference for ISP
> > > > > > 
> > > > > > > Also, with that old firmware, my camera only works with the old isp4
> > > > > > > driver from
> > > > > > > that Linux_ISP_Kernel repo (which is the same isp4 driver used in
> > > > > > > Ubuntu's
> > > > > > > linux-oem kernel). Does the new isp4 driver you've submitted here
> > > > > > > require newer
> > > > > > > firmware than the old driver located in Linux_ISP_Kernel?
> > > > > > > 
> > > > > > > Sultan
> > > > > > 
> > > > > > We had a try, yes, both of the old FW can't work on the new ISP4 driver,
> > > > > > as you know, for the last months, we did lots of driver modifications
> > > > > > for upstream and cause it incompatible with old FW.
> > > > > > Now, under internal discussion to upstream a new FW to support the new
> > > > > > ISP driver
> > > > > > 
> > > > > > Regards,
> > > > > > Bin
> > > > > > 
> > > > > > Hi Sultan,
> > > > > 
> > > > > This is the conclusion of your test,
> > > > > Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > [1] It works on FW      8f070131(ext):39b00736(int)
> > > > > [2] It can't work on FW 1cc8c1bf(ext):50582024(int)
> > > > 
> > > > Correct.
> > > > 
> > > > > Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
> > > > > .config file when building the kernel? Our assumption is to make [1] work,
> > > > > CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
> > > > > CONFIG_VIDEO_OV05C should be defined.
> > > > 
> > > > Yes, it is enabled and I have only tested with it enabled:
> > > > 
> > > >       $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config
> > > >       CONFIG_VIDEO_OV05C=m
> > > > 
> > > > That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
> > > > I tested by running the following commands:
> > > > 
> > > >       git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
> > > >       cd linux-oem-6.14
> > > >       python debian/scripts/misc/annotations -e --arch amd64 > .config
> > > >       make olddefconfig
> > > > 
> > > > Let me know if that works.
> > > > 
> > > > Sultan
> > > 
> > > Thanks Sultan for the details, yes, we can reproduce the same issue on old
> > > isp driver 4.0 release on FW 1cc8c1bf(ext):50582024(int), after debug, the
> > > cause is
> > >    - ov05c sensor device is added by amd i2c driver
> > >    - When ov05c sensor driver probes, it will try to get gpio description but
> > > it will fail because the amd-pinctl driver which creates the gpio resource
> > > hasn't been loaded yet.
> > >    - the ov05c sensor driver probe failure will finally make sensor not able
> > > to work when start streaming
> > > 
> > > Add following patch is supposed to fix this issue to make it work on FW
> > > 1cc8c1bf(ext):50582024(int) when CONFIG_VIDEO_OV05C is defined.
> > > 
> > > @@ -1121,6 +1129,7 @@ static struct i2c_driver ov05_i2c_driver = {
> > > 
> > > module_i2c_driver(ov05_i2c_driver);
> > > 
> > > +MODULE_SOFTDEP("pre: pinctrl-amdisp");
> > > MODULE_ALIAS("ov05");
> > > MODULE_DESCRIPTION("OmniVision OV05 sensor driver");
> > > MODULE_LICENSE("GPL and additional rights");
> > > 
> > > Please help to see if it works if you get time.
> > 
> > There is no difference I'm afraid. I applied the patch and tested with FW
> > 1cc8c1bf(ext):50582024(int) and the webcam is still broken on that FW:
> > 
> >    [   19.523006] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
> >    [   19.537000] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
> >    [   19.537009] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
> >    [   19.537050] PHY register access test success!
> >    [   19.537901] Termination calibration observability: 0x0
> >    [   19.539926] Wait for phyReady: 0x0
> >    [   19.541932] Wait for phyReady: 0x1
> >    [   20.901654] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
> >    [   22.070676] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
> >    ...
> >    [   28.769372] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
> >    [   28.769388] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
> >    [   28.769868] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
> >    [   28.771799] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]
> > 
> > Sultan
> 
> That's really weird, I tested kernel built from
> https://github.com/amd/Linux_ISP_Kernel/tree/4.0 with CONFIG_VIDEO_OV05C=m
> and above sensor driver probe failure patch on FW c8c1bf(ext):50582024(int),
> camera APPs like cheese, qv4l2, Camera all work well.
> 
> Your failure still looks like sensor related, Would you help to add log to
> sensor driver drivers/media/i2c/ov05c.c to see if its probe function gets
> called and succeeds? Here is the log in success case,
> 
> amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
> PHY register access test success!
> Termination calibration observability: 0x0
> Wait for phyReady: 0x0
> Wait for phyReady: 0x1
> amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting camera sensor
> amd_isp_capture amd_isp_capture.1.auto: isp_intf_start_stream,cid:0,sid:0

Debug log output:

$ dmesg | rg SARU
[    4.565697] amd-isp4 OMNI5C10:00: SARU: amd_isp_probe started...
[    4.565753] amd-isp4 OMNI5C10:00: SARU: amd_isp_probe completed successfully
[    6.937077] amd_isp_i2c_designware amd_isp_i2c_designware: SARU: amd_isp_dw_i2c_plat_probe started...
[    6.937522] amdisp-pinctrl amdisp-pinctrl: SARU: amdisp_pinctrl_probe started...
[    6.941264] amdisp-pinctrl amdisp-pinctrl: SARU: amdisp_pinctrl_probe completed successfully
[    6.951967] amd_isp_i2c_designware amd_isp_i2c_designware: SARU: amd_isp_dw_i2c_plat_probe completed successfully

Log output when opening cheese:

[   46.957925] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
[   46.979797] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
[   46.979812] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
[   46.979860] PHY register access test success!
[   46.980565] Termination calibration observability: 0x0
[   46.982598] Wait for phyReady: 0x0
[   46.984634] Wait for phyReady: 0x1
[   48.340154] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
[   49.509505] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
[   51.823498] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
[   51.823513] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
[   51.823962] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
[   51.825358] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]

Patch applied to tree:

--- a/drivers/i2c/busses/i2c-designware-amdisp.c
+++ b/drivers/i2c/busses/i2c-designware-amdisp.c
@@ -42,2 +42,3 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
 	pdev->dev.init_name = DRV_NAME;
+	dev_info(&pdev->dev, "SARU: %s started...", __func__);
 
@@ -95,2 +96,3 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
 
+	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
 	return 0;
--- a/drivers/media/i2c/ov05c.c
+++ b/drivers/media/i2c/ov05c.c
@@ -1031,2 +1031,3 @@ static int ov05_probe(struct i2c_client *client)
 
+	dev_info(&client->dev, "SARU: %s started...", __func__);
 	ov05c = devm_kzalloc(&client->dev, sizeof(*ov05c), GFP_KERNEL);
@@ -1081,2 +1082,3 @@ static int ov05_probe(struct i2c_client *client)
 
+	dev_info(&client->dev, "SARU: %s completed successfully", __func__);
 	return 0;
@@ -1123,2 +1125,3 @@ module_i2c_driver(ov05_i2c_driver);
 
+MODULE_SOFTDEP("pre: pinctrl-amdisp");
 MODULE_ALIAS("ov05");
--- a/drivers/pinctrl/pinctrl-amdisp.c
+++ b/drivers/pinctrl/pinctrl-amdisp.c
@@ -183,2 +183,3 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev)
 	pdev->dev.init_name = DRV_NAME;
+	dev_info(&pdev->dev, "SARU: %s started...", __func__);
 
@@ -215,2 +216,3 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev)
 
+	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
 	return 0;
--- a/drivers/platform/x86/amd/amd_isp4.c
+++ b/drivers/platform/x86/amd/amd_isp4.c
@@ -365,2 +365,3 @@ static int amd_isp_probe(struct platform_device *pdev)
 
+	dev_info(&pdev->dev, "SARU: %s started...", __func__);
 	pinfo = device_get_match_data(&pdev->dev);
@@ -388,2 +389,3 @@ static int amd_isp_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, isp4_platform);
+	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
 	return 0;

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-11 21:48                                 ` Sultan Alsawaf
@ 2025-08-11 22:17                                   ` Sultan Alsawaf
  2025-08-12  2:02                                     ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-11 22:17 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Mon, Aug 11, 2025 at 02:48:42PM -0700, Sultan Alsawaf wrote:
> On Mon, Aug 11, 2025 at 04:35:10PM +0800, Du, Bin wrote:
> > On 8/11/2025 1:49 PM, Sultan Alsawaf wrote:
> > > On Fri, Aug 08, 2025 at 05:11:39PM +0800, Du, Bin wrote:
> > > > On 8/4/2025 12:25 PM, Sultan Alsawaf wrote:
> > > > > On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
> > > > > > On 7/31/2025 6:04 PM, Du, Bin wrote:
> > > > > > > Thanks Sultan for your test
> > > > > > > 
> > > > > > > On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
> > > > > > > > On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
> > > > > > > > > On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
> > > > > > > > > > On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
> > > > > > > > > > > On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
> > > > > > > > > > > > On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
> > > > > > > > > > > > > On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
> > > > > > > > > > > > > > Thanks Sultan, please see my comments
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
> > > > > > > > > > > > > > > On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
> > > > > > > > > > > > > > > > > I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > I cannot for the life of me get
> > > > > > > > > > > > > > > > > the webcam working under Linux.
> > > > > > > > > > > > > > > > > The webcam works
> > > > > > > > > > > > > > > > > under Windows so it's not a hardware issue.
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > With this patchset and all of
> > > > > > > > > > > > > > > > > the patches you link here
> > > > > > > > > > > > > > > > > applied to 6.15, I get
> > > > > > > > > > > > > > > > > the following errors:
> > > > > > > > > > > > > > > > >          [   11.970038]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware: Unknown
> > > > > > > > > > > > > > > > > Synopsys component type:
> > > > > > > > > > > > > > > > > 0xffffffff
> > > > > > > > > > > > > > > > >          [   11.973162]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware: error
> > > > > > > > > > > > > > > > > -19: i2c_dw_probe failed
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > With the old ispkernel code from
> > > > > > > > > > > > > > > > > February [1] applied on 6.15,
> > > > > > > > > > > > > > > > > the webcam
> > > > > > > > > > > > > > > > > indicator LED lights up but
> > > > > > > > > > > > > > > > > there's no image. I see these
> > > > > > > > > > > > > > > > > messages at boot:
> > > > > > > > > > > > > > > > >          [    9.449005]
> > > > > > > > > > > > > > > > > amd_isp_capture
> > > > > > > > > > > > > > > > > amd_isp_capture.1.auto: amdgpu:
> > > > > > > > > > > > > > > > > AMD ISP v4l2 device registered
> > > > > > > > > > > > > > > > >          [    9.489005]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > > The OV05 sensor device is added
> > > > > > > > > > > > > > > > > to the ISP I2C bus
> > > > > > > > > > > > > > > > >          [    9.529012]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > > > > > > current transfer
> > > > > > > > > > > > > > > > >          [    9.554046]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > > > > > >          [    9.554174]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > > timeout while trying to abort
> > > > > > > > > > > > > > > > > current transfer
> > > > > > > > > > > > > > > > >          [    9.580022]
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware
> > > > > > > > > > > > > > > > > amd_isp_i2c_designware.2.auto:
> > > > > > > > > > > > > > > > > timeout in disabling adapter
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > And then the kernel crashes due
> > > > > > > > > > > > > > > > > to the same use-after-free
> > > > > > > > > > > > > > > > > issues I pointed out
> > > > > > > > > > > > > > > > > in my other email [2].
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > Any idea what's going on?
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > [1]
> > > > > > > > > > > > > > > > > https://github.com/amd/Linux_ISP_Kernel/commit/
> > > > > > > > > > > > > > > > > c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > > > > > > > > > > > > [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
> > > > > > > > > > > > > > > > Hi Sultan,
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > [1] is for kernel 6.8, believe it
> > > > > > > > > > > > > > > > can't be applied to 6.15. We didn't
> > > > > > > > > > > > > > > > verify
> > > > > > > > > > > > > > > > on 6.15 but we are really glad to
> > > > > > > > > > > > > > > > help, would you please provide some
> > > > > > > > > > > > > > > > info,
> > > > > > > > > > > > > > > > 1. Suppose you are using Ubuntu, right? What's the version?
> > > > > > > > > > > > > > > > 2. 6.15, do you mean
> > > > > > > > > > > > > > > > https://github.com/torvalds/linux/tree/
> > > > > > > > > > > > > > > > v6.15 ?
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > After your confirmation, we'll see
> > > > > > > > > > > > > > > > what we can do to enable your camera
> > > > > > > > > > > > > > > > quickly and easily
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Regards,
> > > > > > > > > > > > > > > > Bin
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Thank you, Bin!
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
> > > > > > > > > > > > > > > 2. Yes, here is my kernel source [2].
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I have some more findings:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Currently, the first blocking issue is
> > > > > > > > > > > > > > > that the I2C adapter fails to
> > > > > > > > > > > > > > > initialize.
> > > > > > > > > > > > > > > This is because the ISP tile isn't powered on.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I noticed that in the old version of
> > > > > > > > > > > > > > > amd_isp_i2c_designware [3], there were
> > > > > > > > > > > > > > > calls to isp_power_set(), which is
> > > > > > > > > > > > > > > available in the old ISP4 sources [4].
> > > > > > > > > > > > > > > Without isp_power_set(), the I2C adapter
> > > > > > > > > > > > > > > always fails to initialize for me.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > How is the ISP tile supposed to get
> > > > > > > > > > > > > > > powered on in the current ISP4 code?
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > You are correct, yes, i believe the I2C
> > > > > > > > > > > > > > adapter failure is caused by ISP not
> > > > > > > > > > > > > > being powered up. Currently in latest code,
> > > > > > > > > > > > > > isp_power_set is no longer
> > > > > > > > > > > > > > available, instead, we implemented genPD for ISP in amdgpu
> > > > > > > > > > > > > > https://lore.kernel.org/all/20250618221923.3944751-1-
> > > > > > > > > > > > > > pratap.nirujogi@amd.com/
> > > > > > > > > > > > > > Both amd_isp_i2c and amd_isp_capture are in
> > > > > > > > > > > > > > the power domain and use the
> > > > > > > > > > > > > > standard runtime PM API to do the power control
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Thanks for that link, I found it along with
> > > > > > > > > > > > > another patch on the list to make
> > > > > > > > > > > > > the fwnode work ("drm/amd/amdgpu: Initialize
> > > > > > > > > > > > > swnode for ISP MFD device").
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Also, I noticed that the driver init
> > > > > > > > > > > > > > > ordering matters between all of the
> > > > > > > > > > > > > > > drivers
> > > > > > > > > > > > > > > needed for the ISP4 camera. In
> > > > > > > > > > > > > > > particular, amd_isp_i2c_designware and
> > > > > > > > > > > > > > > amd_isp4
> > > > > > > > > > > > > > > must be initialized before amd_capture,
> > > > > > > > > > > > > > > otherwise amd_capture will fail to find
> > > > > > > > > > > > > > > the fwnode properties for the OV05C10
> > > > > > > > > > > > > > > device attached to the I2C bus.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > But there is no driver init ordering
> > > > > > > > > > > > > > > enforced, which also caused some issues
> > > > > > > > > > > > > > > for
> > > > > > > > > > > > > > > me until I figured it out. Maybe probe
> > > > > > > > > > > > > > > deferral (-EPROBE_DEFER) should be used
> > > > > > > > > > > > > > > to ensure each driver waits for its dependencies to init first?
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > amd_isp_capture only has dependency on
> > > > > > > > > > > > > > amd_isp4 which is the ACPI platform
> > > > > > > > > > > > > > driver, it is init before amd_isp_catpure.
> > > > > > > > > > > > > > Do you see in your side the amd_capture
> > > > > > > > > > > > > > probe failure caused by failing to
> > > > > > > > > > > > > > read fwnode properties? If that's the case
> > > > > > > > > > > > > > please help to check if amd_isp4
> > > > > > > > > > > > > > is loaded successfully
> > > > > > > > > > > > > 
> > > > > > > > > > > > > I got much further now: there aren't any driver
> > > > > > > > > > > > > initialization errors, but when
> > > > > > > > > > > > > I open the camera, there's no image. The camera
> > > > > > > > > > > > > LED turns on so it's active.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > And then shortly afterwards, amdgpu dies and the
> > > > > > > > > > > > > entire system freezes.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > I've attached my full dmesg, please let me know
> > > > > > > > > > > > > what you think. Thanks!
> > > > > > > > > > > > 
> > > > > > > > > > > > I almost forgot, here is my current kernel tree:
> > > > > > > > > > > > https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
> > > > > > > > > > > > sultan-isp4
> > > > > > > > > > > > 
> > > > > > > > > > > > Sultan
> > > > > > > > > > > 
> > > > > > > > > > > Thanks Sultan, yes, seems much close to the final
> > > > > > > > > > > success. Will have some
> > > > > > > > > > > internal discussion.
> > > > > > > > > > 
> > > > > > > > > > I got the webcam working. The same bug happened when I tried
> > > > > > > > > > Ubuntu's linux-oem
> > > > > > > > > > kernel, which made me think that the issue was firmware.
> > > > > > > > > > 
> > > > > > > > > > And indeed, the culprit was a firmware update from February. I bisected
> > > > > > > > > > linux-firmware and found the commit which broke the webcam for me:
> > > > > > > > > > 
> > > > > > > > > >       commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
> > > > > > > > > >       Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > > > >       Date:   Wed Feb 19 12:16:51 2025 -0500
> > > > > > > > > > 
> > > > > > > > > >           amdgpu: Update ISP FW for isp v4.1.1
> > > > > > > > > > 
> > > > > > > > > >           From internal git commit:
> > > > > > > > > >           5058202443e08a673b6772ea6339efb50853be28
> > > > > > > > > > 
> > > > > > > > > >           Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > > > > 
> > > > > > > > > >        amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
> > > > > > > > > >        1 file changed, 0 insertions(+), 0 deletions(-)
> > > > > > > > > > 
> > > > > > > > > > Downgrading firmware to before that commit fixes the webcam.
> > > > > > > > > > Any idea why?
> > > > > > > > > > 
> > > > > > > > > > Thanks,
> > > > > > > > > > Sultan
> > > > > > > > > 
> > > > > > > > > So, can i say the working firmware binary is this one?
> > > > > > > > > 
> > > > > > > > > Commit 8f070131
> > > > > > > > > amdgpu: Update ISP FW for isp v4.1.1
> > > > > > > > > 
> > > > > > > > >    From internal git commit:
> > > > > > > > > 39b007366cc76ef8c65e3bc6220ccb213f4861fb
> > > > > > > > > 
> > > > > > > > > Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
> > > > > > > > 
> > > > > > > > Correct.
> > > > > > > > 
> > > > > > > > > There are too many changes between them, so i can't tell exactly which
> > > > > > > > > change caused this. So, from my side
> > > > > > > > > 1. Will try these two firmware to see if we have the same issue.
> > > > > > > > > 2. It has been quite a long time since last release, will see if need to
> > > > > > > > > release a latest one.
> > > > > > > > 
> > > > > > > > Thanks. It was a quick bisect for me, so I'm happy to help test if a
> > > > > > > > bisect
> > > > > > > > between those two internal git commits is needed.
> > > > > > > > 
> > > > > > > Really appreciate your test.
> > > > > > > > In case it makes a difference, I have the laptop with the 2.8K OLED
> > > > > > > > display. I'm
> > > > > > > > aware there is one other display variant on other SKUs, which is a
> > > > > > > > WUXGA IPS.
> > > > > > > > 
> > > > > > > Good to know, I believe it won't make any difference for ISP
> > > > > > > 
> > > > > > > > Also, with that old firmware, my camera only works with the old isp4
> > > > > > > > driver from
> > > > > > > > that Linux_ISP_Kernel repo (which is the same isp4 driver used in
> > > > > > > > Ubuntu's
> > > > > > > > linux-oem kernel). Does the new isp4 driver you've submitted here
> > > > > > > > require newer
> > > > > > > > firmware than the old driver located in Linux_ISP_Kernel?
> > > > > > > > 
> > > > > > > > Sultan
> > > > > > > 
> > > > > > > We had a try, yes, both of the old FW can't work on the new ISP4 driver,
> > > > > > > as you know, for the last months, we did lots of driver modifications
> > > > > > > for upstream and cause it incompatible with old FW.
> > > > > > > Now, under internal discussion to upstream a new FW to support the new
> > > > > > > ISP driver
> > > > > > > 
> > > > > > > Regards,
> > > > > > > Bin
> > > > > > > 
> > > > > > > Hi Sultan,
> > > > > > 
> > > > > > This is the conclusion of your test,
> > > > > > Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
> > > > > > [1] It works on FW      8f070131(ext):39b00736(int)
> > > > > > [2] It can't work on FW 1cc8c1bf(ext):50582024(int)
> > > > > 
> > > > > Correct.
> > > > > 
> > > > > > Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
> > > > > > .config file when building the kernel? Our assumption is to make [1] work,
> > > > > > CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
> > > > > > CONFIG_VIDEO_OV05C should be defined.
> > > > > 
> > > > > Yes, it is enabled and I have only tested with it enabled:
> > > > > 
> > > > >       $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config
> > > > >       CONFIG_VIDEO_OV05C=m
> > > > > 
> > > > > That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
> > > > > I tested by running the following commands:
> > > > > 
> > > > >       git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
> > > > >       cd linux-oem-6.14
> > > > >       python debian/scripts/misc/annotations -e --arch amd64 > .config
> > > > >       make olddefconfig
> > > > > 
> > > > > Let me know if that works.
> > > > > 
> > > > > Sultan
> > > > 
> > > > Thanks Sultan for the details, yes, we can reproduce the same issue on old
> > > > isp driver 4.0 release on FW 1cc8c1bf(ext):50582024(int), after debug, the
> > > > cause is
> > > >    - ov05c sensor device is added by amd i2c driver
> > > >    - When ov05c sensor driver probes, it will try to get gpio description but
> > > > it will fail because the amd-pinctl driver which creates the gpio resource
> > > > hasn't been loaded yet.
> > > >    - the ov05c sensor driver probe failure will finally make sensor not able
> > > > to work when start streaming
> > > > 
> > > > Add following patch is supposed to fix this issue to make it work on FW
> > > > 1cc8c1bf(ext):50582024(int) when CONFIG_VIDEO_OV05C is defined.
> > > > 
> > > > @@ -1121,6 +1129,7 @@ static struct i2c_driver ov05_i2c_driver = {
> > > > 
> > > > module_i2c_driver(ov05_i2c_driver);
> > > > 
> > > > +MODULE_SOFTDEP("pre: pinctrl-amdisp");
> > > > MODULE_ALIAS("ov05");
> > > > MODULE_DESCRIPTION("OmniVision OV05 sensor driver");
> > > > MODULE_LICENSE("GPL and additional rights");
> > > > 
> > > > Please help to see if it works if you get time.
> > > 
> > > There is no difference I'm afraid. I applied the patch and tested with FW
> > > 1cc8c1bf(ext):50582024(int) and the webcam is still broken on that FW:
> > > 
> > >    [   19.523006] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
> > >    [   19.537000] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
> > >    [   19.537009] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
> > >    [   19.537050] PHY register access test success!
> > >    [   19.537901] Termination calibration observability: 0x0
> > >    [   19.539926] Wait for phyReady: 0x0
> > >    [   19.541932] Wait for phyReady: 0x1
> > >    [   20.901654] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
> > >    [   22.070676] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
> > >    ...
> > >    [   28.769372] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
> > >    [   28.769388] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
> > >    [   28.769868] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
> > >    [   28.771799] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]
> > > 
> > > Sultan
> > 
> > That's really weird, I tested kernel built from
> > https://github.com/amd/Linux_ISP_Kernel/tree/4.0 with CONFIG_VIDEO_OV05C=m
> > and above sensor driver probe failure patch on FW c8c1bf(ext):50582024(int),
> > camera APPs like cheese, qv4l2, Camera all work well.
> > 
> > Your failure still looks like sensor related, Would you help to add log to
> > sensor driver drivers/media/i2c/ov05c.c to see if its probe function gets
> > called and succeeds? Here is the log in success case,
> > 
> > amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
> > PHY register access test success!
> > Termination calibration observability: 0x0
> > Wait for phyReady: 0x0
> > Wait for phyReady: 0x1
> > amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting camera sensor
> > amd_isp_capture amd_isp_capture.1.auto: isp_intf_start_stream,cid:0,sid:0
> 
> Debug log output:
> 
> $ dmesg | rg SARU
> [    4.565697] amd-isp4 OMNI5C10:00: SARU: amd_isp_probe started...
> [    4.565753] amd-isp4 OMNI5C10:00: SARU: amd_isp_probe completed successfully
> [    6.937077] amd_isp_i2c_designware amd_isp_i2c_designware: SARU: amd_isp_dw_i2c_plat_probe started...
> [    6.937522] amdisp-pinctrl amdisp-pinctrl: SARU: amdisp_pinctrl_probe started...
> [    6.941264] amdisp-pinctrl amdisp-pinctrl: SARU: amdisp_pinctrl_probe completed successfully
> [    6.951967] amd_isp_i2c_designware amd_isp_i2c_designware: SARU: amd_isp_dw_i2c_plat_probe completed successfully
> 
> Log output when opening cheese:
> 
> [   46.957925] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
> [   46.979797] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
> [   46.979812] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
> [   46.979860] PHY register access test success!
> [   46.980565] Termination calibration observability: 0x0
> [   46.982598] Wait for phyReady: 0x0
> [   46.984634] Wait for phyReady: 0x1
> [   48.340154] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
> [   49.509505] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
> [   51.823498] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
> [   51.823513] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
> [   51.823962] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
> [   51.825358] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]
> 
> Patch applied to tree:
> 
> --- a/drivers/i2c/busses/i2c-designware-amdisp.c
> +++ b/drivers/i2c/busses/i2c-designware-amdisp.c
> @@ -42,2 +42,3 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
>  	pdev->dev.init_name = DRV_NAME;
> +	dev_info(&pdev->dev, "SARU: %s started...", __func__);
>  
> @@ -95,2 +96,3 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
>  
> +	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
>  	return 0;
> --- a/drivers/media/i2c/ov05c.c
> +++ b/drivers/media/i2c/ov05c.c
> @@ -1031,2 +1031,3 @@ static int ov05_probe(struct i2c_client *client)
>  
> +	dev_info(&client->dev, "SARU: %s started...", __func__);
>  	ov05c = devm_kzalloc(&client->dev, sizeof(*ov05c), GFP_KERNEL);
> @@ -1081,2 +1082,3 @@ static int ov05_probe(struct i2c_client *client)
>  
> +	dev_info(&client->dev, "SARU: %s completed successfully", __func__);
>  	return 0;
> @@ -1123,2 +1125,3 @@ module_i2c_driver(ov05_i2c_driver);
>  
> +MODULE_SOFTDEP("pre: pinctrl-amdisp");
>  MODULE_ALIAS("ov05");
> --- a/drivers/pinctrl/pinctrl-amdisp.c
> +++ b/drivers/pinctrl/pinctrl-amdisp.c
> @@ -183,2 +183,3 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev)
>  	pdev->dev.init_name = DRV_NAME;
> +	dev_info(&pdev->dev, "SARU: %s started...", __func__);
>  
> @@ -215,2 +216,3 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev)
>  
> +	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
>  	return 0;
> --- a/drivers/platform/x86/amd/amd_isp4.c
> +++ b/drivers/platform/x86/amd/amd_isp4.c
> @@ -365,2 +365,3 @@ static int amd_isp_probe(struct platform_device *pdev)
>  
> +	dev_info(&pdev->dev, "SARU: %s started...", __func__);
>  	pinfo = device_get_match_data(&pdev->dev);
> @@ -388,2 +389,3 @@ static int amd_isp_probe(struct platform_device *pdev)
>  	platform_set_drvdata(pdev, isp4_platform);
> +	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
>  	return 0;

Sorry, please disregard my last two emails, as I was testing on the wrong
kernel. :(

I've confirmed that the MODULE_SOFTDEP("pre: pinctrl-amdisp") change indeed
fixes the newer firmware on the old isp driver 4.0 release. Without that change,
it is as you say: the ov05c sensor probe fails.

So now I can use FW 1cc8c1bf(ext):50582024(int).

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-08-05 11:37   ` Laurent Pinchart
@ 2025-08-12  1:36     ` Du, Bin
  2025-08-12 13:42       ` Laurent Pinchart
  2025-08-20 12:42       ` Sakari Ailus
  0 siblings, 2 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-12  1:36 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, hverkuil, bryan.odonoghue, sakari.ailus,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Many thanks Laurent Pinchart for the review.

On 8/5/2025 7:37 PM, Laurent Pinchart wrote:
> On Wed, Jun 18, 2025 at 05:19:59PM +0800, Bin Du wrote:
>> Add documentation for AMD isp 4 and describe the main components
>>
>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>> ---
>>   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:: <isonum.txt>
>> +
>> +====================================
>> +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:
>> +
>> +- <capture video device: capture device for retrieving images.
>> +
>> +
>> +  - ISP4 Image Signal Processing Subdevice Node
>> +-----------------------------------------------
>> +
>> +The isp4 is represented as a single V4L2 subdev, the sub-device does not
>> +provide interface to the user space.
> 
> Doesn't it ? The driver sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the
> subdev, and calls v4l2_device_register_subdev_nodes().
> 

We have exported subdev device to user space during the testing with 
libcamera sample pipeline.

> As far as I understand, the camera is exposed by the firmware with a
> webcam-like interface. We need to better understand your plans with this
> driver. If everything is handled by the firmware, why are the sensor and
> subdev exposed to userspace ? Why can't you expose a single video
> capture device, with a media device, and handle everything behind the
> scene ? I assume there may be more features coming later. Please
> document the plan, we can't provide feedback on the architecture
> otherwise.
> 

Currently, isp fw is controlling the sensor to update just the exposure 
and gain, since the 3A algorithms run on ISP HW rather than on x86. In a 
future version, we plan to introduce raw output support in the ISP 
driver, allowing users to choose between AMD’s 3A running on ISP 
hardware or a custom 3A running on x86. If the user opts for the 
x86-based 3A, the firmware will relinquish control of the sensor, and 
hands over full control to the x86 system.

>> The sub-device is connected to one video node
>> +(isp4_capture) with immutable active link. The isp entity is connected
>> +to sensor pad 0 and receives the frames using CSI-2 protocol. The sub-device is
>> +also responsible to configure CSI2-2 receiver.
>> +The sub-device processes bayer raw data from the connected sensor and output
>> +them to different YUV formats. The isp also has scaling capabilities.
>> +
>> +  - isp4_capture - Frames Capture Video Node
>> +--------------------------------------------
>> +
>> +Isp4_capture is a capture device to capture frames to memory.
>> +This entity is the DMA engine that write the frames to memory.
>> +The entity is connected to isp4 sub-device.
>> +
>> +Capturing Video Frames Example
>> +==============================
>> +
>> +.. code-block:: bash
>> +
>> +         # set the links
> 
> This seems very under-documented.
> 

Yes, documentation needs to be updated.

>> +
>> +         # start streaming:
>> +         v4l2-ctl "-d" "/dev/video0" "--set-fmt-video=width=1920,height=1080,pixelformat=NV12" "--stream-mmap" "--stream-count=10"
>> diff --git a/Documentation/admin-guide/media/amdisp4.dot b/Documentation/admin-guide/media/amdisp4.dot
>> new file mode 100644
>> index 000000000000..a4c2f0cceb30
>> --- /dev/null
>> +++ b/Documentation/admin-guide/media/amdisp4.dot
>> @@ -0,0 +1,8 @@
>> +digraph board {
>> +	rankdir=TB
>> +	n00000001 [label="{{<port0> 0} | amd isp4\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
>> +	n00000001:port1 -> n00000004 [style=bold]
>> +	n00000004 [label="Preview\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
>> +	n0000000a [label="{{} | ov05c10 22-0010\n/dev/v4l-subdev0 | {<port0> 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 <pratap.nirujogi@amd.com>
>>   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/*
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-11 22:17                                   ` Sultan Alsawaf
@ 2025-08-12  2:02                                     ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-12  2:02 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

Thanks Sultan.

On 8/12/2025 6:17 AM, Sultan Alsawaf wrote:
> On Mon, Aug 11, 2025 at 02:48:42PM -0700, Sultan Alsawaf wrote:
>> On Mon, Aug 11, 2025 at 04:35:10PM +0800, Du, Bin wrote:
>>> On 8/11/2025 1:49 PM, Sultan Alsawaf wrote:
>>>> On Fri, Aug 08, 2025 at 05:11:39PM +0800, Du, Bin wrote:
>>>>> On 8/4/2025 12:25 PM, Sultan Alsawaf wrote:
>>>>>> On Mon, Aug 04, 2025 at 11:32:11AM +0800, Du, Bin wrote:
>>>>>>> On 7/31/2025 6:04 PM, Du, Bin wrote:
>>>>>>>> Thanks Sultan for your test
>>>>>>>>
>>>>>>>> On 7/31/2025 8:30 AM, Sultan Alsawaf wrote:
>>>>>>>>> On Wed, Jul 30, 2025 at 05:53:58PM +0800, Du, Bin wrote:
>>>>>>>>>> On 7/30/2025 1:38 PM, Sultan Alsawaf wrote:
>>>>>>>>>>> On Tue, Jul 29, 2025 at 06:13:50PM +0800, Du, Bin wrote:
>>>>>>>>>>>> On 7/29/2025 3:45 PM, Sultan Alsawaf wrote:
>>>>>>>>>>>>> On Tue, Jul 29, 2025 at 12:42:16AM -0700, Sultan Alsawaf wrote:
>>>>>>>>>>>>>> On Tue, Jul 29, 2025 at 11:32:23AM +0800, Du, Bin wrote:
>>>>>>>>>>>>>>> Thanks Sultan, please see my comments
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On 7/27/2025 6:31 AM, Sultan Alsawaf wrote:
>>>>>>>>>>>>>>>> On Fri, Jul 25, 2025 at 06:22:03PM +0800, Du, Bin wrote:
>>>>>>>>>>>>>>>>>> I have the Ryzen AI MAX+ 395 SKU of the HP ZBook Ultra G1a 14.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> I cannot for the life of me get
>>>>>>>>>>>>>>>>>> the webcam working under Linux.
>>>>>>>>>>>>>>>>>> The webcam works
>>>>>>>>>>>>>>>>>> under Windows so it's not a hardware issue.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> With this patchset and all of
>>>>>>>>>>>>>>>>>> the patches you link here
>>>>>>>>>>>>>>>>>> applied to 6.15, I get
>>>>>>>>>>>>>>>>>> the following errors:
>>>>>>>>>>>>>>>>>>           [   11.970038]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware: Unknown
>>>>>>>>>>>>>>>>>> Synopsys component type:
>>>>>>>>>>>>>>>>>> 0xffffffff
>>>>>>>>>>>>>>>>>>           [   11.973162]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware: error
>>>>>>>>>>>>>>>>>> -19: i2c_dw_probe failed
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> With the old ispkernel code from
>>>>>>>>>>>>>>>>>> February [1] applied on 6.15,
>>>>>>>>>>>>>>>>>> the webcam
>>>>>>>>>>>>>>>>>> indicator LED lights up but
>>>>>>>>>>>>>>>>>> there's no image. I see these
>>>>>>>>>>>>>>>>>> messages at boot:
>>>>>>>>>>>>>>>>>>           [    9.449005]
>>>>>>>>>>>>>>>>>> amd_isp_capture
>>>>>>>>>>>>>>>>>> amd_isp_capture.1.auto: amdgpu:
>>>>>>>>>>>>>>>>>> AMD ISP v4l2 device registered
>>>>>>>>>>>>>>>>>>           [    9.489005]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>>>>> The OV05 sensor device is added
>>>>>>>>>>>>>>>>>> to the ISP I2C bus
>>>>>>>>>>>>>>>>>>           [    9.529012]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>>>>> timeout while trying to abort
>>>>>>>>>>>>>>>>>> current transfer
>>>>>>>>>>>>>>>>>>           [    9.554046]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>>>>> timeout in disabling adapter
>>>>>>>>>>>>>>>>>>           [    9.554174]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>>>>> timeout while trying to abort
>>>>>>>>>>>>>>>>>> current transfer
>>>>>>>>>>>>>>>>>>           [    9.580022]
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware
>>>>>>>>>>>>>>>>>> amd_isp_i2c_designware.2.auto:
>>>>>>>>>>>>>>>>>> timeout in disabling adapter
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> And then the kernel crashes due
>>>>>>>>>>>>>>>>>> to the same use-after-free
>>>>>>>>>>>>>>>>>> issues I pointed out
>>>>>>>>>>>>>>>>>> in my other email [2].
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Any idea what's going on?
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> [1]
>>>>>>>>>>>>>>>>>> https://github.com/amd/Linux_ISP_Kernel/commit/
>>>>>>>>>>>>>>>>>> c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>>>>>>>>>>>>> [2] https://lore.kernel.org/r/aIEiJL83pOYO8lUJ@sultan-box
>>>>>>>>>>>>>>>>> Hi Sultan,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> [1] is for kernel 6.8, believe it
>>>>>>>>>>>>>>>>> can't be applied to 6.15. We didn't
>>>>>>>>>>>>>>>>> verify
>>>>>>>>>>>>>>>>> on 6.15 but we are really glad to
>>>>>>>>>>>>>>>>> help, would you please provide some
>>>>>>>>>>>>>>>>> info,
>>>>>>>>>>>>>>>>> 1. Suppose you are using Ubuntu, right? What's the version?
>>>>>>>>>>>>>>>>> 2. 6.15, do you mean
>>>>>>>>>>>>>>>>> https://github.com/torvalds/linux/tree/
>>>>>>>>>>>>>>>>> v6.15 ?
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> After your confirmation, we'll see
>>>>>>>>>>>>>>>>> what we can do to enable your camera
>>>>>>>>>>>>>>>>> quickly and easily
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Regards,
>>>>>>>>>>>>>>>>> Bin
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Thank you, Bin!
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 1. I'm using Arch Linux with the ISP4-patched libcamera [1].
>>>>>>>>>>>>>>>> 2. Yes, here is my kernel source [2].
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> I have some more findings:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Currently, the first blocking issue is
>>>>>>>>>>>>>>>> that the I2C adapter fails to
>>>>>>>>>>>>>>>> initialize.
>>>>>>>>>>>>>>>> This is because the ISP tile isn't powered on.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> I noticed that in the old version of
>>>>>>>>>>>>>>>> amd_isp_i2c_designware [3], there were
>>>>>>>>>>>>>>>> calls to isp_power_set(), which is
>>>>>>>>>>>>>>>> available in the old ISP4 sources [4].
>>>>>>>>>>>>>>>> Without isp_power_set(), the I2C adapter
>>>>>>>>>>>>>>>> always fails to initialize for me.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> How is the ISP tile supposed to get
>>>>>>>>>>>>>>>> powered on in the current ISP4 code?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> You are correct, yes, i believe the I2C
>>>>>>>>>>>>>>> adapter failure is caused by ISP not
>>>>>>>>>>>>>>> being powered up. Currently in latest code,
>>>>>>>>>>>>>>> isp_power_set is no longer
>>>>>>>>>>>>>>> available, instead, we implemented genPD for ISP in amdgpu
>>>>>>>>>>>>>>> https://lore.kernel.org/all/20250618221923.3944751-1-
>>>>>>>>>>>>>>> pratap.nirujogi@amd.com/
>>>>>>>>>>>>>>> Both amd_isp_i2c and amd_isp_capture are in
>>>>>>>>>>>>>>> the power domain and use the
>>>>>>>>>>>>>>> standard runtime PM API to do the power control
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Thanks for that link, I found it along with
>>>>>>>>>>>>>> another patch on the list to make
>>>>>>>>>>>>>> the fwnode work ("drm/amd/amdgpu: Initialize
>>>>>>>>>>>>>> swnode for ISP MFD device").
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Also, I noticed that the driver init
>>>>>>>>>>>>>>>> ordering matters between all of the
>>>>>>>>>>>>>>>> drivers
>>>>>>>>>>>>>>>> needed for the ISP4 camera. In
>>>>>>>>>>>>>>>> particular, amd_isp_i2c_designware and
>>>>>>>>>>>>>>>> amd_isp4
>>>>>>>>>>>>>>>> must be initialized before amd_capture,
>>>>>>>>>>>>>>>> otherwise amd_capture will fail to find
>>>>>>>>>>>>>>>> the fwnode properties for the OV05C10
>>>>>>>>>>>>>>>> device attached to the I2C bus.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> But there is no driver init ordering
>>>>>>>>>>>>>>>> enforced, which also caused some issues
>>>>>>>>>>>>>>>> for
>>>>>>>>>>>>>>>> me until I figured it out. Maybe probe
>>>>>>>>>>>>>>>> deferral (-EPROBE_DEFER) should be used
>>>>>>>>>>>>>>>> to ensure each driver waits for its dependencies to init first?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> amd_isp_capture only has dependency on
>>>>>>>>>>>>>>> amd_isp4 which is the ACPI platform
>>>>>>>>>>>>>>> driver, it is init before amd_isp_catpure.
>>>>>>>>>>>>>>> Do you see in your side the amd_capture
>>>>>>>>>>>>>>> probe failure caused by failing to
>>>>>>>>>>>>>>> read fwnode properties? If that's the case
>>>>>>>>>>>>>>> please help to check if amd_isp4
>>>>>>>>>>>>>>> is loaded successfully
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I got much further now: there aren't any driver
>>>>>>>>>>>>>> initialization errors, but when
>>>>>>>>>>>>>> I open the camera, there's no image. The camera
>>>>>>>>>>>>>> LED turns on so it's active.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> And then shortly afterwards, amdgpu dies and the
>>>>>>>>>>>>>> entire system freezes.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I've attached my full dmesg, please let me know
>>>>>>>>>>>>>> what you think. Thanks!
>>>>>>>>>>>>>
>>>>>>>>>>>>> I almost forgot, here is my current kernel tree:
>>>>>>>>>>>>> https://github.com/kerneltoast/kernel_x86_laptop/tree/v6.16-
>>>>>>>>>>>>> sultan-isp4
>>>>>>>>>>>>>
>>>>>>>>>>>>> Sultan
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks Sultan, yes, seems much close to the final
>>>>>>>>>>>> success. Will have some
>>>>>>>>>>>> internal discussion.
>>>>>>>>>>>
>>>>>>>>>>> I got the webcam working. The same bug happened when I tried
>>>>>>>>>>> Ubuntu's linux-oem
>>>>>>>>>>> kernel, which made me think that the issue was firmware.
>>>>>>>>>>>
>>>>>>>>>>> And indeed, the culprit was a firmware update from February. I bisected
>>>>>>>>>>> linux-firmware and found the commit which broke the webcam for me:
>>>>>>>>>>>
>>>>>>>>>>>        commit 1cc8c1bfa11251ce8bfcc97d1f15e312f7fe4df0 (HEAD)
>>>>>>>>>>>        Author: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>>>>>>        Date:   Wed Feb 19 12:16:51 2025 -0500
>>>>>>>>>>>
>>>>>>>>>>>            amdgpu: Update ISP FW for isp v4.1.1
>>>>>>>>>>>
>>>>>>>>>>>            From internal git commit:
>>>>>>>>>>>            5058202443e08a673b6772ea6339efb50853be28
>>>>>>>>>>>
>>>>>>>>>>>            Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>>>>>>
>>>>>>>>>>>         amdgpu/isp_4_1_1.bin | Bin 4543184 -> 6083536 bytes
>>>>>>>>>>>         1 file changed, 0 insertions(+), 0 deletions(-)
>>>>>>>>>>>
>>>>>>>>>>> Downgrading firmware to before that commit fixes the webcam.
>>>>>>>>>>> Any idea why?
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Sultan
>>>>>>>>>>
>>>>>>>>>> So, can i say the working firmware binary is this one?
>>>>>>>>>>
>>>>>>>>>> Commit 8f070131
>>>>>>>>>> amdgpu: Update ISP FW for isp v4.1.1
>>>>>>>>>>
>>>>>>>>>>     From internal git commit:
>>>>>>>>>> 39b007366cc76ef8c65e3bc6220ccb213f4861fb
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
>>>>>>>>>
>>>>>>>>> Correct.
>>>>>>>>>
>>>>>>>>>> There are too many changes between them, so i can't tell exactly which
>>>>>>>>>> change caused this. So, from my side
>>>>>>>>>> 1. Will try these two firmware to see if we have the same issue.
>>>>>>>>>> 2. It has been quite a long time since last release, will see if need to
>>>>>>>>>> release a latest one.
>>>>>>>>>
>>>>>>>>> Thanks. It was a quick bisect for me, so I'm happy to help test if a
>>>>>>>>> bisect
>>>>>>>>> between those two internal git commits is needed.
>>>>>>>>>
>>>>>>>> Really appreciate your test.
>>>>>>>>> In case it makes a difference, I have the laptop with the 2.8K OLED
>>>>>>>>> display. I'm
>>>>>>>>> aware there is one other display variant on other SKUs, which is a
>>>>>>>>> WUXGA IPS.
>>>>>>>>>
>>>>>>>> Good to know, I believe it won't make any difference for ISP
>>>>>>>>
>>>>>>>>> Also, with that old firmware, my camera only works with the old isp4
>>>>>>>>> driver from
>>>>>>>>> that Linux_ISP_Kernel repo (which is the same isp4 driver used in
>>>>>>>>> Ubuntu's
>>>>>>>>> linux-oem kernel). Does the new isp4 driver you've submitted here
>>>>>>>>> require newer
>>>>>>>>> firmware than the old driver located in Linux_ISP_Kernel?
>>>>>>>>>
>>>>>>>>> Sultan
>>>>>>>>
>>>>>>>> We had a try, yes, both of the old FW can't work on the new ISP4 driver,
>>>>>>>> as you know, for the last months, we did lots of driver modifications
>>>>>>>> for upstream and cause it incompatible with old FW.
>>>>>>>> Now, under internal discussion to upstream a new FW to support the new
>>>>>>>> ISP driver
>>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Bin
>>>>>>>>
>>>>>>>> Hi Sultan,
>>>>>>>
>>>>>>> This is the conclusion of your test,
>>>>>>> Driver: https://github.com/amd/Linux_ISP_Kernel/commit/c6d42584fbd0aa42cc91ecf16dc5c4f3dfea0bb4
>>>>>>> [1] It works on FW      8f070131(ext):39b00736(int)
>>>>>>> [2] It can't work on FW 1cc8c1bf(ext):50582024(int)
>>>>>>
>>>>>> Correct.
>>>>>>
>>>>>>> Would you please help to check if CONFIG_VIDEO_OV05C is defined not in the
>>>>>>> .config file when building the kernel? Our assumption is to make [1] work,
>>>>>>> CONFIG_VIDEO_OV05C shouldn't be defined. to make [2] work,
>>>>>>> CONFIG_VIDEO_OV05C should be defined.
>>>>>>
>>>>>> Yes, it is enabled and I have only tested with it enabled:
>>>>>>
>>>>>>        $ rg CONFIG_VIDEO_OV05C linux-oem-6.14/.config
>>>>>>        CONFIG_VIDEO_OV05C=m
>>>>>>
>>>>>> That's the Ubuntu linux-oem-6.14 kernel. You can get the full source and .config
>>>>>> I tested by running the following commands:
>>>>>>
>>>>>>        git clone https://git.launchpad.net/ubuntu/+source/linux-oem-6.14 -b applied/6.14.0-1006.6
>>>>>>        cd linux-oem-6.14
>>>>>>        python debian/scripts/misc/annotations -e --arch amd64 > .config
>>>>>>        make olddefconfig
>>>>>>
>>>>>> Let me know if that works.
>>>>>>
>>>>>> Sultan
>>>>>
>>>>> Thanks Sultan for the details, yes, we can reproduce the same issue on old
>>>>> isp driver 4.0 release on FW 1cc8c1bf(ext):50582024(int), after debug, the
>>>>> cause is
>>>>>     - ov05c sensor device is added by amd i2c driver
>>>>>     - When ov05c sensor driver probes, it will try to get gpio description but
>>>>> it will fail because the amd-pinctl driver which creates the gpio resource
>>>>> hasn't been loaded yet.
>>>>>     - the ov05c sensor driver probe failure will finally make sensor not able
>>>>> to work when start streaming
>>>>>
>>>>> Add following patch is supposed to fix this issue to make it work on FW
>>>>> 1cc8c1bf(ext):50582024(int) when CONFIG_VIDEO_OV05C is defined.
>>>>>
>>>>> @@ -1121,6 +1129,7 @@ static struct i2c_driver ov05_i2c_driver = {
>>>>>
>>>>> module_i2c_driver(ov05_i2c_driver);
>>>>>
>>>>> +MODULE_SOFTDEP("pre: pinctrl-amdisp");
>>>>> MODULE_ALIAS("ov05");
>>>>> MODULE_DESCRIPTION("OmniVision OV05 sensor driver");
>>>>> MODULE_LICENSE("GPL and additional rights");
>>>>>
>>>>> Please help to see if it works if you get time.
>>>>
>>>> There is no difference I'm afraid. I applied the patch and tested with FW
>>>> 1cc8c1bf(ext):50582024(int) and the webcam is still broken on that FW:
>>>>
>>>>     [   19.523006] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
>>>>     [   19.537000] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
>>>>     [   19.537009] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
>>>>     [   19.537050] PHY register access test success!
>>>>     [   19.537901] Termination calibration observability: 0x0
>>>>     [   19.539926] Wait for phyReady: 0x0
>>>>     [   19.541932] Wait for phyReady: 0x1
>>>>     [   20.901654] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
>>>>     [   22.070676] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
>>>>     ...
>>>>     [   28.769372] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
>>>>     [   28.769388] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
>>>>     [   28.769868] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
>>>>     [   28.771799] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]
>>>>
>>>> Sultan
>>>
>>> That's really weird, I tested kernel built from
>>> https://github.com/amd/Linux_ISP_Kernel/tree/4.0 with CONFIG_VIDEO_OV05C=m
>>> and above sensor driver probe failure patch on FW c8c1bf(ext):50582024(int),
>>> camera APPs like cheese, qv4l2, Camera all work well.
>>>
>>> Your failure still looks like sensor related, Would you help to add log to
>>> sensor driver drivers/media/i2c/ov05c.c to see if its probe function gets
>>> called and succeeds? Here is the log in success case,
>>>
>>> amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
>>> PHY register access test success!
>>> Termination calibration observability: 0x0
>>> Wait for phyReady: 0x0
>>> Wait for phyReady: 0x1
>>> amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting camera sensor
>>> amd_isp_capture amd_isp_capture.1.auto: isp_intf_start_stream,cid:0,sid:0
>>
>> Debug log output:
>>
>> $ dmesg | rg SARU
>> [    4.565697] amd-isp4 OMNI5C10:00: SARU: amd_isp_probe started...
>> [    4.565753] amd-isp4 OMNI5C10:00: SARU: amd_isp_probe completed successfully
>> [    6.937077] amd_isp_i2c_designware amd_isp_i2c_designware: SARU: amd_isp_dw_i2c_plat_probe started...
>> [    6.937522] amdisp-pinctrl amdisp-pinctrl: SARU: amdisp_pinctrl_probe started...
>> [    6.941264] amdisp-pinctrl amdisp-pinctrl: SARU: amdisp_pinctrl_probe completed successfully
>> [    6.951967] amd_isp_i2c_designware amd_isp_i2c_designware: SARU: amd_isp_dw_i2c_plat_probe completed successfully
>>
>> Log output when opening cheese:
>>
>> [   46.957925] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:0)|start_streaming
>> [   46.979797] amd_isp_capture amd_isp_capture.1.auto: ISP FW boot suc!
>> [   46.979812] amd_isp_capture amd_isp_capture.1.auto: amdgpu: starting Phy
>> [   46.979860] PHY register access test success!
>> [   46.980565] Termination calibration observability: 0x0
>> [   46.982598] Wait for phyReady: 0x0
>> [   46.984634] Wait for phyReady: 0x1
>> [   48.340154] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
>> [   49.509505] amd_isp_capture amd_isp_capture.1.auto: -><- fail respid Unknown respid(0x30002)
>> [   51.823498] amd_isp_capture amd_isp_capture.1.auto: amdgpu: Preview(fw_run:1)|stop_streaming
>> [   51.823513] amd_isp_capture amd_isp_capture.1.auto: amdgpu: stopping Phy
>> [   51.823962] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[1]
>> [   51.825358] amd_isp_capture amd_isp_capture.1.auto: isp_rm_cmd_from_cmdq_by_stream: fail empty cmd q, stream[0]
>>
>> Patch applied to tree:
>>
>> --- a/drivers/i2c/busses/i2c-designware-amdisp.c
>> +++ b/drivers/i2c/busses/i2c-designware-amdisp.c
>> @@ -42,2 +42,3 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
>>   	pdev->dev.init_name = DRV_NAME;
>> +	dev_info(&pdev->dev, "SARU: %s started...", __func__);
>>   
>> @@ -95,2 +96,3 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
>>   
>> +	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
>>   	return 0;
>> --- a/drivers/media/i2c/ov05c.c
>> +++ b/drivers/media/i2c/ov05c.c
>> @@ -1031,2 +1031,3 @@ static int ov05_probe(struct i2c_client *client)
>>   
>> +	dev_info(&client->dev, "SARU: %s started...", __func__);
>>   	ov05c = devm_kzalloc(&client->dev, sizeof(*ov05c), GFP_KERNEL);
>> @@ -1081,2 +1082,3 @@ static int ov05_probe(struct i2c_client *client)
>>   
>> +	dev_info(&client->dev, "SARU: %s completed successfully", __func__);
>>   	return 0;
>> @@ -1123,2 +1125,3 @@ module_i2c_driver(ov05_i2c_driver);
>>   
>> +MODULE_SOFTDEP("pre: pinctrl-amdisp");
>>   MODULE_ALIAS("ov05");
>> --- a/drivers/pinctrl/pinctrl-amdisp.c
>> +++ b/drivers/pinctrl/pinctrl-amdisp.c
>> @@ -183,2 +183,3 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev)
>>   	pdev->dev.init_name = DRV_NAME;
>> +	dev_info(&pdev->dev, "SARU: %s started...", __func__);
>>   
>> @@ -215,2 +216,3 @@ static int amdisp_pinctrl_probe(struct platform_device *pdev)
>>   
>> +	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
>>   	return 0;
>> --- a/drivers/platform/x86/amd/amd_isp4.c
>> +++ b/drivers/platform/x86/amd/amd_isp4.c
>> @@ -365,2 +365,3 @@ static int amd_isp_probe(struct platform_device *pdev)
>>   
>> +	dev_info(&pdev->dev, "SARU: %s started...", __func__);
>>   	pinfo = device_get_match_data(&pdev->dev);
>> @@ -388,2 +389,3 @@ static int amd_isp_probe(struct platform_device *pdev)
>>   	platform_set_drvdata(pdev, isp4_platform);
>> +	dev_info(&pdev->dev, "SARU: %s completed successfully", __func__);
>>   	return 0;
> 
> Sorry, please disregard my last two emails, as I was testing on the wrong
> kernel. :(
> 
> I've confirmed that the MODULE_SOFTDEP("pre: pinctrl-amdisp") change indeed
> fixes the newer firmware on the old isp driver 4.0 release. Without that change,
> it is as you say: the ov05c sensor probe fails.
> 
> So now I can use FW 1cc8c1bf(ext):50582024(int).
> 
> Sultan

Never mind, really glad it is finally resolved and you can use the new FW.

Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-11 11:46       ` Sakari Ailus
  2025-08-11 12:31         ` Laurent Pinchart
@ 2025-08-12  2:44         ` Du, Bin
  1 sibling, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-12  2:44 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

Thanks Sakari Ailus for the comments

On 8/11/2025 7:46 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
>> Many thanks Askari Ailus for your careful review
>>
>> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
>>> Hi Bin,
>>>
>>> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
>>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>>>> called ccpu.
>>>> The communication between ISP FW and driver is using commands and
>>>> response messages sent through the ring buffer. Command buffers support
>>>> either global setting that is not specific to the steam and support stream
>>>> specific parameters. Response buffers contains ISP FW notification
>>>> information such as frame buffer done and command done. IRQ is used for
>>>> receiving response buffer from ISP firmware, which is handled in the main
>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
>>>> helper function prior to stream start.
>>>> Memory used for command buffer and response buffer needs to be allocated
>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>>
>>> Please rewrap this, some lines above are quite short.
>>>
>> Thanks, the line after the short line is supposed to be a new paragraph?
>> Should we put all the description in one paragraph?
> 
> One or more paragraphs work fine, but a new paragraph is separated from the
> previous one by another newline.
> 
> ...
> 

Got it, thanks.

>>>> +	void *cpu_ptr;
>>>> +	u64 gpu_addr;
>>>> +	u32 ret;
>>>> +
>>>> +	dev = ispif->dev;
>>>> +
>>>> +	if (!mem_size)
>>>> +		return NULL;
>>>> +
>>>> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
>>>> +	if (!mem_info)
>>>> +		return NULL;
>>>> +
>>>> +	adev = (struct amdgpu_device *)ispif->adev;
>>>
>>> Why the cast?
>>>
>>> adev isn't a great name here as it's usually used for struct acpi_devices.
>>>
>> In the next patch, will use new helper function for this and will no longer
>> use amdgpu_device
> 
> Use correct types when you can; either way this doesn't seem to be changed
> by the further patches in the set.
> 
> ...
> 

Yes, totally agree.

>>>> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
>>>> +			       struct isp4if_gpu_mem_info *mem_info)
>>>> +{
>>>> +	struct device *dev = ispif->dev;
>>>> +	struct amdgpu_bo *bo;
>>>> +
>>>> +	if (!mem_info) {
>>>> +		dev_err(dev, "invalid mem_info\n");
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
>>>
>>> Why do you need to cast here?
>>>
>> In the next patch, will use new helper function for this and will no longer
>> use amdgpu_bo
> 
> Not quite, on top of this patch number 6 adds more of the same.
> 
> ...
> 

Thanks, will double check all new patches to avoid similar problem.

>>>> +static struct isp4if_cmd_element *
>>>> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
>>>> +			 struct isp4if_cmd_element *cmd_ele)
>>>> +{
>>>> +	struct isp4if_cmd_element *copy_command = NULL;
>>>> +
>>>> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
>>>> +	if (!copy_command)
>>>> +		return NULL;
>>>> +
>>>> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
>>>
>>> kmemdup()?
>>>
>> Kmemdup is to allocate memory and copy, can't be used here.
> 
> Isn't that what you're doing above?
> 
>>

Yes, you are absolutely right. Sorry, missed the kmalloc before the 
memcpy, will fix in the next patch.

>>>> +
>>>> +	guard(mutex)(&ispif->cmdq_mutex);
>>>> +
>>>> +	list_add_tail(&copy_command->list, &ispif->cmdq);
>>>> +
>>>> +	return copy_command;
>>>> +}
> 

Regards,
Bin

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-11 12:31         ` Laurent Pinchart
@ 2025-08-12  3:36           ` Du, Bin
  2025-08-12  7:34             ` Laurent Pinchart
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-12  3:36 UTC (permalink / raw)
  To: Laurent Pinchart, Sakari Ailus
  Cc: mchehab, hverkuil, bryan.odonoghue, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, pratap.nirujogi, benjamin.chan,
	king.li, gjorgji.rosikopulos, Phil.Jawich, Dominic.Antony,
	Mario Limonciello, Richard.Gong, anson.tsao

Many thanks Laurent Pinchart for the comments.

On 8/11/2025 8:31 PM, Laurent Pinchart wrote:
> On Mon, Aug 11, 2025 at 11:46:27AM +0000, Sakari Ailus wrote:
>> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
>>> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
>>>> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
>>>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>>>>> called ccpu.
>>>>> The communication between ISP FW and driver is using commands and
>>>>> response messages sent through the ring buffer. Command buffers support
>>>>> either global setting that is not specific to the steam and support stream
>>>>> specific parameters. Response buffers contains ISP FW notification
>>>>> information such as frame buffer done and command done. IRQ is used for
>>>>> receiving response buffer from ISP firmware, which is handled in the main
>>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
>>>>> helper function prior to stream start.
>>>>> Memory used for command buffer and response buffer needs to be allocated
>>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>>>
>>>> Please rewrap this, some lines above are quite short.
>>>>
>>> Thanks, the line after the short line is supposed to be a new paragraph?
>>> Should we put all the description in one paragraph?
>>
>> One or more paragraphs work fine, but a new paragraph is separated from the
>> previous one by another newline.
>>
>> ...
> 
> Paragraphs are defined as a block of text that convey one idea. They
> should be visually separated by a space. As we can't have fractional
> line spacing in plain text, paragraphs need to be separated by a blank
> line. This is a typography rule that maximizes readability. There should
> be no line break between sentences in a single paragraph.
> 
> Whether you write commit messages, formal documentation or comments in
> code, typography is important to give the best experience to readers.
> After all, a block of text that wouldn't focus on the readers would have
> no reason to exist.
> 
> 
> Now compare the above with
> 
> 
> Paragraphs are defined as a block of text that convey one idea. They
> should be visually separated by a space.
> As we can't have fractional line spacing in plain text, paragraphs need
> to be separated by a blank line.
> This is a typography rule that maximizes readability. There should be no
> line break between sentences in a single paragraph. Whether you write
> commit messages, formal documentation or comments in code, typography is
> important to give the best experience to readers.
> After all, a block of text that wouldn't focus on the readers would have
> no reason to exist.
> 

Really appreciate the detailed guide, will follow it. May I summarize 
like this? 1 Separate paragraphs by a blank line. 2 Don't add line break 
between sentences in a single paragraph, an exception to this is commit 
message, because of the 75-character patch check limit, line break can 
be added, but it should at the 75-character limit boundary

>>>>> +	void *cpu_ptr;
>>>>> +	u64 gpu_addr;
>>>>> +	u32 ret;
>>>>> +
>>>>> +	dev = ispif->dev;
>>>>> +
>>>>> +	if (!mem_size)
>>>>> +		return NULL;
>>>>> +
>>>>> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
>>>>> +	if (!mem_info)
>>>>> +		return NULL;
>>>>> +
>>>>> +	adev = (struct amdgpu_device *)ispif->adev;
>>>>
>>>> Why the cast?
>>>>
>>>> adev isn't a great name here as it's usually used for struct acpi_devices.
>>>>
>>> In the next patch, will use new helper function for this and will no longer
>>> use amdgpu_device
>>
>> Use correct types when you can; either way this doesn't seem to be changed
>> by the further patches in the set.
>>
>> ...
>>
>>>>> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
>>>>> +			       struct isp4if_gpu_mem_info *mem_info)
>>>>> +{
>>>>> +	struct device *dev = ispif->dev;
>>>>> +	struct amdgpu_bo *bo;
>>>>> +
>>>>> +	if (!mem_info) {
>>>>> +		dev_err(dev, "invalid mem_info\n");
>>>>> +		return -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
>>>>
>>>> Why do you need to cast here?
>>>>
>>> In the next patch, will use new helper function for this and will no longer
>>> use amdgpu_bo
>>
>> Not quite, on top of this patch number 6 adds more of the same.
>>
>> ...
>>
>>>>> +static struct isp4if_cmd_element *
>>>>> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
>>>>> +			 struct isp4if_cmd_element *cmd_ele)
>>>>> +{
>>>>> +	struct isp4if_cmd_element *copy_command = NULL;
>>>>> +
>>>>> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
>>>>> +	if (!copy_command)
>>>>> +		return NULL;
>>>>> +
>>>>> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
>>>>
>>>> kmemdup()?
>>>>
>>> Kmemdup is to allocate memory and copy, can't be used here.
>>
>> Isn't that what you're doing above?
>>
>>>>> +
>>>>> +	guard(mutex)(&ispif->cmdq_mutex);
>>>>> +
>>>>> +	list_add_tail(&copy_command->list, &ispif->cmdq);
>>>>> +
>>>>> +	return copy_command;
>>>>> +}
> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-08-11  9:05           ` Du, Bin
@ 2025-08-12  5:51             ` Sultan Alsawaf
  2025-08-12  6:33               ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-12  5:51 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony

On Mon, Aug 11, 2025 at 05:05:39PM +0800, Du, Bin wrote:
> > > [ old quotes trimmed out ]
> > 
> > Following up on this: there were several more issues hiding in the driver that
> > needed to be fixed unfortunately. I ended up making a lot of changes to fix all
> > of the buffer lifetime issues, and I created individual commits for this work
> > because it was getting hard to keep track of all the changes.
> > 
> > I think I'll have this completed tomorrow and will provide a link to my tree
> > with my commits. Hopefully your internal branch hasn't diverged too much from
> > this patchset submission, otherwise there may be some conflicts to resolve.
> > 
> > Sultan
> 
> Really appreciate your time and effort. Yes, big code changes happen in our
> internal branch to address upstream comments, but i believe your commits
> will be extremely valuable. We can check and test after fixing possbile
> conflict.

I've pushed my work here:

  https://github.com/kerneltoast/kernel_x86_laptop.git v6.16-drm-tip-isp4-for-amd

Please see my changes since commit 48d18b6e58c6dadbc79374773736924d2f532da5 on
that branch, up to commit 5cdacf4ff108d83869414a00465e7a612bcd04b1.

There are 29 patches:

Sultan Alsawaf (29):
      media: amd: isp4: Use amdgpu helper functions for ISP buffers
      media: amd: isp4: Remove -mpreferred-stack-boundary=4 cflag
      media: amd: isp4: Remove -DCONFIG_COMPAT from ccflags-y
      media: amd: isp4: Remove the myriad of redundant ccflags includes
      media: amd: isp4: Pass warning flags through cc-option
      media: amd: isp4: Clean up amd_capture-objs formatting
      media: amd: isp4: Don't set CONFIG_AMD_ISP4 to y by default
      media: amd: isp4: Clean up AMD_ISP4 Kconfig dependencies
      media: amd: Fix Kconfig/Makefile directory structure
      media: amd: isp4: Remove superfluous NULL pointer checks
      media: amd: isp4: Remove superfluous void pointer casts
      media: amd: isp4: Remove superfluous memset in isp4vid_vb2_map_dmabuf()
      media: amd: isp4: Don't read refcount counter directly
      media: amd: isp4: Add missing refcount tracking to mmap memop
      media: amd: isp4: Don't put or unmap the dmabuf when detaching
      media: amd: isp4: Don't increment refcount when dmabuf export fails
      media: amd: isp4: Fix possible use-after-free in isp4vid_vb2_put()
      media: amd: isp4: Always export a new dmabuf from get_dmabuf memop
      media: amd: isp4: Fix implicit dmabuf lifetime tracking
      media: amd: isp4: Fix possible use-after-free when putting implicit dmabuf
      media: amd: isp4: Remove 'refcount > 0' warning in isp4vid_vb2_put()
      media: amd: isp4: Fix comment in isp4vid_vb2_dmabuf_ops_release()
      media: amd: isp4: Simplify isp4vid_get_dmabuf() arguments
      media: amd: isp4: Add comment to CONFIG_HAS_DMA #endif
      media: amd: isp4: Move up buf->vaddr check in isp4vid_get_dmabuf()
      media: amd: isp4: Remove unused userptr memops
      media: amd: isp4: Make isp4vid_vb2_memops static
      media: amd: isp4: Add missing cleanup on error in isp4vid_vb2_alloc()
      media: amd: isp4: Release queued buffers on error in start_streaming

 drivers/media/platform/amd/Kconfig               |  18 +-
 drivers/media/platform/amd/Makefile              |   6 +-
 drivers/media/platform/amd/isp4/Kconfig          |  14 ++
 drivers/media/platform/amd/isp4/Makefile         |  42 +---
 drivers/media/platform/amd/isp4/isp4.c           |   9 +-
 drivers/media/platform/amd/isp4/isp4.h           |  11 -
 drivers/media/platform/amd/isp4/isp4_debug.c     |   4 +-
 drivers/media/platform/amd/isp4/isp4_interface.c |  46 +---
 drivers/media/platform/amd/isp4/isp4_interface.h |   6 +-
 drivers/media/platform/amd/isp4/isp4_subdev.c    |   8 +-
 drivers/media/platform/amd/isp4/isp4_subdev.h    |   4 +-
 drivers/media/platform/amd/isp4/isp4_video.c     | 297 ++++++-----------------
 drivers/media/platform/amd/isp4/isp4_video.h     |   4 +-
 13 files changed, 122 insertions(+), 347 deletions(-)

At least 1 of them should be redundant for your internal branch (9f394a7af2cf
"media: amd: isp4: Use amdgpu helper functions for ISP buffers").

Cheers,
Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-08-12  5:51             ` Sultan Alsawaf
@ 2025-08-12  6:33               ` Du, Bin
  2025-08-13  9:42                 ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-12  6:33 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

Many thanks, Sultan.

On 8/12/2025 1:51 PM, Sultan Alsawaf wrote:
> On Mon, Aug 11, 2025 at 05:05:39PM +0800, Du, Bin wrote:
>>>> [ old quotes trimmed out ]
>>>
>>> Following up on this: there were several more issues hiding in the driver that
>>> needed to be fixed unfortunately. I ended up making a lot of changes to fix all
>>> of the buffer lifetime issues, and I created individual commits for this work
>>> because it was getting hard to keep track of all the changes.
>>>
>>> I think I'll have this completed tomorrow and will provide a link to my tree
>>> with my commits. Hopefully your internal branch hasn't diverged too much from
>>> this patchset submission, otherwise there may be some conflicts to resolve.
>>>
>>> Sultan
>>
>> Really appreciate your time and effort. Yes, big code changes happen in our
>> internal branch to address upstream comments, but i believe your commits
>> will be extremely valuable. We can check and test after fixing possbile
>> conflict.
> 
> I've pushed my work here:
> 
>    https://github.com/kerneltoast/kernel_x86_laptop.git v6.16-drm-tip-isp4-for-amd
> 
> Please see my changes since commit 48d18b6e58c6dadbc79374773736924d2f532da5 on
> that branch, up to commit 5cdacf4ff108d83869414a00465e7a612bcd04b1.
> 
> There are 29 patches:
> 
> Sultan Alsawaf (29):
>        media: amd: isp4: Use amdgpu helper functions for ISP buffers
>        media: amd: isp4: Remove -mpreferred-stack-boundary=4 cflag
>        media: amd: isp4: Remove -DCONFIG_COMPAT from ccflags-y
>        media: amd: isp4: Remove the myriad of redundant ccflags includes
>        media: amd: isp4: Pass warning flags through cc-option
>        media: amd: isp4: Clean up amd_capture-objs formatting
>        media: amd: isp4: Don't set CONFIG_AMD_ISP4 to y by default
>        media: amd: isp4: Clean up AMD_ISP4 Kconfig dependencies
>        media: amd: Fix Kconfig/Makefile directory structure
>        media: amd: isp4: Remove superfluous NULL pointer checks
>        media: amd: isp4: Remove superfluous void pointer casts
>        media: amd: isp4: Remove superfluous memset in isp4vid_vb2_map_dmabuf()
>        media: amd: isp4: Don't read refcount counter directly
>        media: amd: isp4: Add missing refcount tracking to mmap memop
>        media: amd: isp4: Don't put or unmap the dmabuf when detaching
>        media: amd: isp4: Don't increment refcount when dmabuf export fails
>        media: amd: isp4: Fix possible use-after-free in isp4vid_vb2_put()
>        media: amd: isp4: Always export a new dmabuf from get_dmabuf memop
>        media: amd: isp4: Fix implicit dmabuf lifetime tracking
>        media: amd: isp4: Fix possible use-after-free when putting implicit dmabuf
>        media: amd: isp4: Remove 'refcount > 0' warning in isp4vid_vb2_put()
>        media: amd: isp4: Fix comment in isp4vid_vb2_dmabuf_ops_release()
>        media: amd: isp4: Simplify isp4vid_get_dmabuf() arguments
>        media: amd: isp4: Add comment to CONFIG_HAS_DMA #endif
>        media: amd: isp4: Move up buf->vaddr check in isp4vid_get_dmabuf()
>        media: amd: isp4: Remove unused userptr memops
>        media: amd: isp4: Make isp4vid_vb2_memops static
>        media: amd: isp4: Add missing cleanup on error in isp4vid_vb2_alloc()
>        media: amd: isp4: Release queued buffers on error in start_streaming
> 
>   drivers/media/platform/amd/Kconfig               |  18 +-
>   drivers/media/platform/amd/Makefile              |   6 +-
>   drivers/media/platform/amd/isp4/Kconfig          |  14 ++
>   drivers/media/platform/amd/isp4/Makefile         |  42 +---
>   drivers/media/platform/amd/isp4/isp4.c           |   9 +-
>   drivers/media/platform/amd/isp4/isp4.h           |  11 -
>   drivers/media/platform/amd/isp4/isp4_debug.c     |   4 +-
>   drivers/media/platform/amd/isp4/isp4_interface.c |  46 +---
>   drivers/media/platform/amd/isp4/isp4_interface.h |   6 +-
>   drivers/media/platform/amd/isp4/isp4_subdev.c    |   8 +-
>   drivers/media/platform/amd/isp4/isp4_subdev.h    |   4 +-
>   drivers/media/platform/amd/isp4/isp4_video.c     | 297 ++++++-----------------
>   drivers/media/platform/amd/isp4/isp4_video.h     |   4 +-
>   13 files changed, 122 insertions(+), 347 deletions(-)
> 
> At least 1 of them should be redundant for your internal branch (9f394a7af2cf
> "media: amd: isp4: Use amdgpu helper functions for ISP buffers").
> 
> Cheers,
> Sultan

Wow, amazing, fantastic work. Will compare to our latest internal branch 
to see what might be missing and try to merge, then have some test. Will 
let you know the result, it might cost some time. Thanks again.

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-12  3:36           ` Du, Bin
@ 2025-08-12  7:34             ` Laurent Pinchart
  2025-08-12  8:08               ` Du, Bin
  2025-08-12  8:20               ` Sakari Ailus
  0 siblings, 2 replies; 96+ messages in thread
From: Laurent Pinchart @ 2025-08-12  7:34 UTC (permalink / raw)
  To: Du, Bin
  Cc: Sakari Ailus, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

On Tue, Aug 12, 2025 at 11:36:23AM +0800, Du, Bin wrote:
> Many thanks Laurent Pinchart for the comments.
> 
> On 8/11/2025 8:31 PM, Laurent Pinchart wrote:
> > On Mon, Aug 11, 2025 at 11:46:27AM +0000, Sakari Ailus wrote:
> >> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
> >>> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
> >>>> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
> >>>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
> >>>>> called ccpu.
> >>>>> The communication between ISP FW and driver is using commands and
> >>>>> response messages sent through the ring buffer. Command buffers support
> >>>>> either global setting that is not specific to the steam and support stream
> >>>>> specific parameters. Response buffers contains ISP FW notification
> >>>>> information such as frame buffer done and command done. IRQ is used for
> >>>>> receiving response buffer from ISP firmware, which is handled in the main
> >>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
> >>>>> helper function prior to stream start.
> >>>>> Memory used for command buffer and response buffer needs to be allocated
> >>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
> >>>>
> >>>> Please rewrap this, some lines above are quite short.
> >>>>
> >>> Thanks, the line after the short line is supposed to be a new paragraph?
> >>> Should we put all the description in one paragraph?
> >>
> >> One or more paragraphs work fine, but a new paragraph is separated from the
> >> previous one by another newline.
> >>
> >> ...
> > 
> > Paragraphs are defined as a block of text that convey one idea. They
> > should be visually separated by a space. As we can't have fractional
> > line spacing in plain text, paragraphs need to be separated by a blank
> > line. This is a typography rule that maximizes readability. There should
> > be no line break between sentences in a single paragraph.
> > 
> > Whether you write commit messages, formal documentation or comments in
> > code, typography is important to give the best experience to readers.
> > After all, a block of text that wouldn't focus on the readers would have
> > no reason to exist.
> > 
> > 
> > Now compare the above with
> > 
> > 
> > Paragraphs are defined as a block of text that convey one idea. They
> > should be visually separated by a space.
> > As we can't have fractional line spacing in plain text, paragraphs need
> > to be separated by a blank line.
> > This is a typography rule that maximizes readability. There should be no
> > line break between sentences in a single paragraph. Whether you write
> > commit messages, formal documentation or comments in code, typography is
> > important to give the best experience to readers.
> > After all, a block of text that wouldn't focus on the readers would have
> > no reason to exist.
> 
> Really appreciate the detailed guide, will follow it. May I summarize 
> like this? 1 Separate paragraphs by a blank line. 2 Don't add line break 
> between sentences in a single paragraph, an exception to this is commit 
> message, because of the 75-character patch check limit, line break can 
> be added, but it should at the 75-character limit boundary

When I wrote "line break", I meant breaking the line after a sentence,
before the 75 columns limits. Text blocks should always be wrapped (at
75 columns in commit messages, or 80 in kernel code). What you should
avoid is line breaks not related to the columns limit.

This is fine:

This paragraph has a long sentence that does not hold on a single line
of 72 characters and therefore needs to be wrapped. There is no line
break otherwise, for instance between the first and second sentence, or
within a sentence.

This is not right:

This paragraph has a long sentence that does not hold on a single line
of 72 characters and therefore needs to be wrapped.
There is a line break between the first and second sentence,
and also a line break in the second sentence, which are not fine.

> >>>>> +	void *cpu_ptr;
> >>>>> +	u64 gpu_addr;
> >>>>> +	u32 ret;
> >>>>> +
> >>>>> +	dev = ispif->dev;
> >>>>> +
> >>>>> +	if (!mem_size)
> >>>>> +		return NULL;
> >>>>> +
> >>>>> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
> >>>>> +	if (!mem_info)
> >>>>> +		return NULL;
> >>>>> +
> >>>>> +	adev = (struct amdgpu_device *)ispif->adev;
> >>>>
> >>>> Why the cast?
> >>>>
> >>>> adev isn't a great name here as it's usually used for struct acpi_devices.
> >>>>
> >>> In the next patch, will use new helper function for this and will no longer
> >>> use amdgpu_device
> >>
> >> Use correct types when you can; either way this doesn't seem to be changed
> >> by the further patches in the set.
> >>
> >> ...
> >>
> >>>>> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
> >>>>> +			       struct isp4if_gpu_mem_info *mem_info)
> >>>>> +{
> >>>>> +	struct device *dev = ispif->dev;
> >>>>> +	struct amdgpu_bo *bo;
> >>>>> +
> >>>>> +	if (!mem_info) {
> >>>>> +		dev_err(dev, "invalid mem_info\n");
> >>>>> +		return -EINVAL;
> >>>>> +	}
> >>>>> +
> >>>>> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
> >>>>
> >>>> Why do you need to cast here?
> >>>>
> >>> In the next patch, will use new helper function for this and will no longer
> >>> use amdgpu_bo
> >>
> >> Not quite, on top of this patch number 6 adds more of the same.
> >>
> >> ...
> >>
> >>>>> +static struct isp4if_cmd_element *
> >>>>> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
> >>>>> +			 struct isp4if_cmd_element *cmd_ele)
> >>>>> +{
> >>>>> +	struct isp4if_cmd_element *copy_command = NULL;
> >>>>> +
> >>>>> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
> >>>>> +	if (!copy_command)
> >>>>> +		return NULL;
> >>>>> +
> >>>>> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
> >>>>
> >>>> kmemdup()?
> >>>>
> >>> Kmemdup is to allocate memory and copy, can't be used here.
> >>
> >> Isn't that what you're doing above?
> >>
> >>>>> +
> >>>>> +	guard(mutex)(&ispif->cmdq_mutex);
> >>>>> +
> >>>>> +	list_add_tail(&copy_command->list, &ispif->cmdq);
> >>>>> +
> >>>>> +	return copy_command;
> >>>>> +}

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-12  7:34             ` Laurent Pinchart
@ 2025-08-12  8:08               ` Du, Bin
  2025-08-12  8:20               ` Sakari Ailus
  1 sibling, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-12  8:08 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sakari Ailus, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

Many thanks Laurent Pinchart

On 8/12/2025 3:34 PM, Laurent Pinchart wrote:
> On Tue, Aug 12, 2025 at 11:36:23AM +0800, Du, Bin wrote:
>> Many thanks Laurent Pinchart for the comments.
>>
>> On 8/11/2025 8:31 PM, Laurent Pinchart wrote:
>>> On Mon, Aug 11, 2025 at 11:46:27AM +0000, Sakari Ailus wrote:
>>>> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
>>>>> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
>>>>>> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
>>>>>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>>>>>>> called ccpu.
>>>>>>> The communication between ISP FW and driver is using commands and
>>>>>>> response messages sent through the ring buffer. Command buffers support
>>>>>>> either global setting that is not specific to the steam and support stream
>>>>>>> specific parameters. Response buffers contains ISP FW notification
>>>>>>> information such as frame buffer done and command done. IRQ is used for
>>>>>>> receiving response buffer from ISP firmware, which is handled in the main
>>>>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
>>>>>>> helper function prior to stream start.
>>>>>>> Memory used for command buffer and response buffer needs to be allocated
>>>>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>>>>>
>>>>>> Please rewrap this, some lines above are quite short.
>>>>>>
>>>>> Thanks, the line after the short line is supposed to be a new paragraph?
>>>>> Should we put all the description in one paragraph?
>>>>
>>>> One or more paragraphs work fine, but a new paragraph is separated from the
>>>> previous one by another newline.
>>>>
>>>> ...
>>>
>>> Paragraphs are defined as a block of text that convey one idea. They
>>> should be visually separated by a space. As we can't have fractional
>>> line spacing in plain text, paragraphs need to be separated by a blank
>>> line. This is a typography rule that maximizes readability. There should
>>> be no line break between sentences in a single paragraph.
>>>
>>> Whether you write commit messages, formal documentation or comments in
>>> code, typography is important to give the best experience to readers.
>>> After all, a block of text that wouldn't focus on the readers would have
>>> no reason to exist.
>>>
>>>
>>> Now compare the above with
>>>
>>>
>>> Paragraphs are defined as a block of text that convey one idea. They
>>> should be visually separated by a space.
>>> As we can't have fractional line spacing in plain text, paragraphs need
>>> to be separated by a blank line.
>>> This is a typography rule that maximizes readability. There should be no
>>> line break between sentences in a single paragraph. Whether you write
>>> commit messages, formal documentation or comments in code, typography is
>>> important to give the best experience to readers.
>>> After all, a block of text that wouldn't focus on the readers would have
>>> no reason to exist.
>>
>> Really appreciate the detailed guide, will follow it. May I summarize
>> like this? 1 Separate paragraphs by a blank line. 2 Don't add line break
>> between sentences in a single paragraph, an exception to this is commit
>> message, because of the 75-character patch check limit, line break can
>> be added, but it should at the 75-character limit boundary
> 
> When I wrote "line break", I meant breaking the line after a sentence,
> before the 75 columns limits. Text blocks should always be wrapped (at
> 75 columns in commit messages, or 80 in kernel code). What you should
> avoid is line breaks not related to the columns limit.
> 
> This is fine:
> 
> This paragraph has a long sentence that does not hold on a single line
> of 72 characters and therefore needs to be wrapped. There is no line
> break otherwise, for instance between the first and second sentence, or
> within a sentence.
> 
> This is not right:
> 
> This paragraph has a long sentence that does not hold on a single line
> of 72 characters and therefore needs to be wrapped.
> There is a line break between the first and second sentence,
> and also a line break in the second sentence, which are not fine.
> 

Really appreciate for your patient explanation and wonderful example, 
it's totally clear now.

>>>>>>> +	void *cpu_ptr;
>>>>>>> +	u64 gpu_addr;
>>>>>>> +	u32 ret;
>>>>>>> +
>>>>>>> +	dev = ispif->dev;
>>>>>>> +
>>>>>>> +	if (!mem_size)
>>>>>>> +		return NULL;
>>>>>>> +
>>>>>>> +	mem_info = kzalloc(sizeof(*mem_info), GFP_KERNEL);
>>>>>>> +	if (!mem_info)
>>>>>>> +		return NULL;
>>>>>>> +
>>>>>>> +	adev = (struct amdgpu_device *)ispif->adev;
>>>>>>
>>>>>> Why the cast?
>>>>>>
>>>>>> adev isn't a great name here as it's usually used for struct acpi_devices.
>>>>>>
>>>>> In the next patch, will use new helper function for this and will no longer
>>>>> use amdgpu_device
>>>>
>>>> Use correct types when you can; either way this doesn't seem to be changed
>>>> by the further patches in the set.
>>>>
>>>> ...
>>>>
>>>>>>> +static int isp4if_gpu_mem_free(struct isp4_interface *ispif,
>>>>>>> +			       struct isp4if_gpu_mem_info *mem_info)
>>>>>>> +{
>>>>>>> +	struct device *dev = ispif->dev;
>>>>>>> +	struct amdgpu_bo *bo;
>>>>>>> +
>>>>>>> +	if (!mem_info) {
>>>>>>> +		dev_err(dev, "invalid mem_info\n");
>>>>>>> +		return -EINVAL;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	bo = (struct amdgpu_bo *)mem_info->mem_handle;
>>>>>>
>>>>>> Why do you need to cast here?
>>>>>>
>>>>> In the next patch, will use new helper function for this and will no longer
>>>>> use amdgpu_bo
>>>>
>>>> Not quite, on top of this patch number 6 adds more of the same.
>>>>
>>>> ...
>>>>
>>>>>>> +static struct isp4if_cmd_element *
>>>>>>> +isp4if_append_cmd_2_cmdq(struct isp4_interface *ispif,
>>>>>>> +			 struct isp4if_cmd_element *cmd_ele)
>>>>>>> +{
>>>>>>> +	struct isp4if_cmd_element *copy_command = NULL;
>>>>>>> +
>>>>>>> +	copy_command = kmalloc(sizeof(*copy_command), GFP_KERNEL);
>>>>>>> +	if (!copy_command)
>>>>>>> +		return NULL;
>>>>>>> +
>>>>>>> +	memcpy(copy_command, cmd_ele, sizeof(*copy_command));
>>>>>>
>>>>>> kmemdup()?
>>>>>>
>>>>> Kmemdup is to allocate memory and copy, can't be used here.
>>>>
>>>> Isn't that what you're doing above?
>>>>
>>>>>>> +
>>>>>>> +	guard(mutex)(&ispif->cmdq_mutex);
>>>>>>> +
>>>>>>> +	list_add_tail(&copy_command->list, &ispif->cmdq);
>>>>>>> +
>>>>>>> +	return copy_command;
>>>>>>> +}
> 

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-12  7:34             ` Laurent Pinchart
  2025-08-12  8:08               ` Du, Bin
@ 2025-08-12  8:20               ` Sakari Ailus
  2025-08-12 10:04                 ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sakari Ailus @ 2025-08-12  8:20 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Du, Bin, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

Hi Laurent, Bin,

On Tue, Aug 12, 2025 at 10:34:32AM +0300, Laurent Pinchart wrote:
> On Tue, Aug 12, 2025 at 11:36:23AM +0800, Du, Bin wrote:
> > Many thanks Laurent Pinchart for the comments.
> > 
> > On 8/11/2025 8:31 PM, Laurent Pinchart wrote:
> > > On Mon, Aug 11, 2025 at 11:46:27AM +0000, Sakari Ailus wrote:
> > >> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
> > >>> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
> > >>>> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
> > >>>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
> > >>>>> called ccpu.
> > >>>>> The communication between ISP FW and driver is using commands and
> > >>>>> response messages sent through the ring buffer. Command buffers support
> > >>>>> either global setting that is not specific to the steam and support stream
> > >>>>> specific parameters. Response buffers contains ISP FW notification
> > >>>>> information such as frame buffer done and command done. IRQ is used for
> > >>>>> receiving response buffer from ISP firmware, which is handled in the main
> > >>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
> > >>>>> helper function prior to stream start.
> > >>>>> Memory used for command buffer and response buffer needs to be allocated
> > >>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
> > >>>>
> > >>>> Please rewrap this, some lines above are quite short.
> > >>>>
> > >>> Thanks, the line after the short line is supposed to be a new paragraph?
> > >>> Should we put all the description in one paragraph?
> > >>
> > >> One or more paragraphs work fine, but a new paragraph is separated from the
> > >> previous one by another newline.
> > >>
> > >> ...
> > > 
> > > Paragraphs are defined as a block of text that convey one idea. They
> > > should be visually separated by a space. As we can't have fractional
> > > line spacing in plain text, paragraphs need to be separated by a blank
> > > line. This is a typography rule that maximizes readability. There should
> > > be no line break between sentences in a single paragraph.
> > > 
> > > Whether you write commit messages, formal documentation or comments in
> > > code, typography is important to give the best experience to readers.
> > > After all, a block of text that wouldn't focus on the readers would have
> > > no reason to exist.
> > > 
> > > 
> > > Now compare the above with
> > > 
> > > 
> > > Paragraphs are defined as a block of text that convey one idea. They
> > > should be visually separated by a space.
> > > As we can't have fractional line spacing in plain text, paragraphs need
> > > to be separated by a blank line.
> > > This is a typography rule that maximizes readability. There should be no
> > > line break between sentences in a single paragraph. Whether you write
> > > commit messages, formal documentation or comments in code, typography is
> > > important to give the best experience to readers.
> > > After all, a block of text that wouldn't focus on the readers would have
> > > no reason to exist.
> > 
> > Really appreciate the detailed guide, will follow it. May I summarize 
> > like this? 1 Separate paragraphs by a blank line. 2 Don't add line break 
> > between sentences in a single paragraph, an exception to this is commit 
> > message, because of the 75-character patch check limit, line break can 
> > be added, but it should at the 75-character limit boundary
> 
> When I wrote "line break", I meant breaking the line after a sentence,
> before the 75 columns limits. Text blocks should always be wrapped (at
> 75 columns in commit messages, or 80 in kernel code). What you should
> avoid is line breaks not related to the columns limit.
> 
> This is fine:
> 
> This paragraph has a long sentence that does not hold on a single line
> of 72 characters and therefore needs to be wrapped. There is no line
> break otherwise, for instance between the first and second sentence, or
> within a sentence.
> 
> This is not right:
> 
> This paragraph has a long sentence that does not hold on a single line
> of 72 characters and therefore needs to be wrapped.
> There is a line break between the first and second sentence,
> and also a line break in the second sentence, which are not fine.

I wonder if this should make it to kernel documentation. I've come across
many new developers recently who would definitely benefit from this.

Also, most editors can rewrap paragraphs of text (e.g. Emacs M-q or Joe C-k
C-j).

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface
  2025-08-12  8:20               ` Sakari Ailus
@ 2025-08-12 10:04                 ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-12 10:04 UTC (permalink / raw)
  To: Sakari Ailus, Laurent Pinchart
  Cc: mchehab, hverkuil, bryan.odonoghue, prabhakar.mahadev-lad.rj,
	linux-media, linux-kernel, pratap.nirujogi, benjamin.chan,
	king.li, gjorgji.rosikopulos, Phil.Jawich, Dominic.Antony,
	Mario Limonciello, Richard.Gong, anson.tsao

Hi Sakari Ailus,

On 8/12/2025 4:20 PM, Sakari Ailus wrote:
> Hi Laurent, Bin,
> 
> On Tue, Aug 12, 2025 at 10:34:32AM +0300, Laurent Pinchart wrote:
>> On Tue, Aug 12, 2025 at 11:36:23AM +0800, Du, Bin wrote:
>>> Many thanks Laurent Pinchart for the comments.
>>>
>>> On 8/11/2025 8:31 PM, Laurent Pinchart wrote:
>>>> On Mon, Aug 11, 2025 at 11:46:27AM +0000, Sakari Ailus wrote:
>>>>> On Tue, Jul 29, 2025 at 05:12:03PM +0800, Du, Bin wrote:
>>>>>> On 7/28/2025 3:23 PM, Sakari Ailus wrote:
>>>>>>> On Wed, Jun 18, 2025 at 05:19:55PM +0800, Bin Du wrote:
>>>>>>>> ISP firmware controls ISP HW pipeline using dedicated embedded processor
>>>>>>>> called ccpu.
>>>>>>>> The communication between ISP FW and driver is using commands and
>>>>>>>> response messages sent through the ring buffer. Command buffers support
>>>>>>>> either global setting that is not specific to the steam and support stream
>>>>>>>> specific parameters. Response buffers contains ISP FW notification
>>>>>>>> information such as frame buffer done and command done. IRQ is used for
>>>>>>>> receiving response buffer from ISP firmware, which is handled in the main
>>>>>>>> isp4 media device. ISP ccpu is booted up through the firmware loading
>>>>>>>> helper function prior to stream start.
>>>>>>>> Memory used for command buffer and response buffer needs to be allocated
>>>>>>>> from amdgpu buffer manager because isp4 is a child device of amdgpu.
>>>>>>>
>>>>>>> Please rewrap this, some lines above are quite short.
>>>>>>>
>>>>>> Thanks, the line after the short line is supposed to be a new paragraph?
>>>>>> Should we put all the description in one paragraph?
>>>>>
>>>>> One or more paragraphs work fine, but a new paragraph is separated from the
>>>>> previous one by another newline.
>>>>>
>>>>> ...
>>>>
>>>> Paragraphs are defined as a block of text that convey one idea. They
>>>> should be visually separated by a space. As we can't have fractional
>>>> line spacing in plain text, paragraphs need to be separated by a blank
>>>> line. This is a typography rule that maximizes readability. There should
>>>> be no line break between sentences in a single paragraph.
>>>>
>>>> Whether you write commit messages, formal documentation or comments in
>>>> code, typography is important to give the best experience to readers.
>>>> After all, a block of text that wouldn't focus on the readers would have
>>>> no reason to exist.
>>>>
>>>>
>>>> Now compare the above with
>>>>
>>>>
>>>> Paragraphs are defined as a block of text that convey one idea. They
>>>> should be visually separated by a space.
>>>> As we can't have fractional line spacing in plain text, paragraphs need
>>>> to be separated by a blank line.
>>>> This is a typography rule that maximizes readability. There should be no
>>>> line break between sentences in a single paragraph. Whether you write
>>>> commit messages, formal documentation or comments in code, typography is
>>>> important to give the best experience to readers.
>>>> After all, a block of text that wouldn't focus on the readers would have
>>>> no reason to exist.
>>>
>>> Really appreciate the detailed guide, will follow it. May I summarize
>>> like this? 1 Separate paragraphs by a blank line. 2 Don't add line break
>>> between sentences in a single paragraph, an exception to this is commit
>>> message, because of the 75-character patch check limit, line break can
>>> be added, but it should at the 75-character limit boundary
>>
>> When I wrote "line break", I meant breaking the line after a sentence,
>> before the 75 columns limits. Text blocks should always be wrapped (at
>> 75 columns in commit messages, or 80 in kernel code). What you should
>> avoid is line breaks not related to the columns limit.
>>
>> This is fine:
>>
>> This paragraph has a long sentence that does not hold on a single line
>> of 72 characters and therefore needs to be wrapped. There is no line
>> break otherwise, for instance between the first and second sentence, or
>> within a sentence.
>>
>> This is not right:
>>
>> This paragraph has a long sentence that does not hold on a single line
>> of 72 characters and therefore needs to be wrapped.
>> There is a line break between the first and second sentence,
>> and also a line break in the second sentence, which are not fine.
> 
> I wonder if this should make it to kernel documentation. I've come across
> many new developers recently who would definitely benefit from this.
> 

Yes, totally agree, furthermore, if checkpatch script can be 
strengthened to add this kind of check, developers can even find and fix 
them before submit the patches

> Also, most editors can rewrap paragraphs of text (e.g. Emacs M-q or Joe C-k
> C-j).
> 

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-08-12  1:36     ` Du, Bin
@ 2025-08-12 13:42       ` Laurent Pinchart
  2025-08-22  2:28         ` Du, Bin
  2025-08-20 12:42       ` Sakari Ailus
  1 sibling, 1 reply; 96+ messages in thread
From: Laurent Pinchart @ 2025-08-12 13:42 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, bryan.odonoghue, sakari.ailus,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Tue, Aug 12, 2025 at 09:36:04AM +0800, Du, Bin wrote:
> On 8/5/2025 7:37 PM, Laurent Pinchart wrote:
> > On Wed, Jun 18, 2025 at 05:19:59PM +0800, Bin Du wrote:
> >> Add documentation for AMD isp 4 and describe the main components
> >>
> >> Signed-off-by: Bin Du <Bin.Du@amd.com>
> >> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> >> ---
> >>   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:: <isonum.txt>
> >> +
> >> +====================================
> >> +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:
> >> +
> >> +- <capture video device: capture device for retrieving images.
> >> +
> >> +
> >> +  - ISP4 Image Signal Processing Subdevice Node
> >> +-----------------------------------------------
> >> +
> >> +The isp4 is represented as a single V4L2 subdev, the sub-device does not
> >> +provide interface to the user space.
> > 
> > Doesn't it ? The driver sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the
> > subdev, and calls v4l2_device_register_subdev_nodes().
> 
> We have exported subdev device to user space during the testing with 
> libcamera sample pipeline.

But it's not needed anymore ? If not, you could stop exposing the subdev
to userspace for the time being.

> > As far as I understand, the camera is exposed by the firmware with a
> > webcam-like interface. We need to better understand your plans with this
> > driver. If everything is handled by the firmware, why are the sensor and
> > subdev exposed to userspace ? Why can't you expose a single video
> > capture device, with a media device, and handle everything behind the
> > scene ? I assume there may be more features coming later. Please
> > document the plan, we can't provide feedback on the architecture
> > otherwise.
> 
> Currently, isp fw is controlling the sensor to update just the exposure 
> and gain, since the 3A algorithms run on ISP HW rather than on x86.

This design decision makes my hair stand on end :-( Exposing the camera
sensor to both the firmware and the host concurrently is asking for
trouble. If you really want to abstract the camera behind a firmware and
only expose a webcam-like API (or not even that in this version, as the
driver exposes no control as far as I can see), then you should push the
whole sensor handling to the firmware too. In my opinion that would not
be a good solution compared to exposing the ISP to the host, but it
would be better than this hybrid model.

> In a 
> future version, we plan to introduce raw output support in the ISP 
> driver, allowing users to choose between AMD’s 3A running on ISP 
> hardware or a custom 3A running on x86. If the user opts for the 
> x86-based 3A, the firmware will relinquish control of the sensor, and 
> hands over full control to the x86 system.

Will the firmware at that point expose to Linux all the ISP statistics
needed to implement auto-exposure ? What if I want to also set digital
gain ? Or have manual white balance (requiring statistics), and manual
CCM ?

> >> The sub-device is connected to one video node
> >> +(isp4_capture) with immutable active link. The isp entity is connected
> >> +to sensor pad 0 and receives the frames using CSI-2 protocol. The sub-device is
> >> +also responsible to configure CSI2-2 receiver.
> >> +The sub-device processes bayer raw data from the connected sensor and output
> >> +them to different YUV formats. The isp also has scaling capabilities.
> >> +
> >> +  - isp4_capture - Frames Capture Video Node
> >> +--------------------------------------------
> >> +
> >> +Isp4_capture is a capture device to capture frames to memory.
> >> +This entity is the DMA engine that write the frames to memory.
> >> +The entity is connected to isp4 sub-device.
> >> +
> >> +Capturing Video Frames Example
> >> +==============================
> >> +
> >> +.. code-block:: bash
> >> +
> >> +         # set the links
> > 
> > This seems very under-documented.
> 
> Yes, documentation needs to be updated.
> 
> >> +
> >> +         # start streaming:
> >> +         v4l2-ctl "-d" "/dev/video0" "--set-fmt-video=width=1920,height=1080,pixelformat=NV12" "--stream-mmap" "--stream-count=10"
> >> diff --git a/Documentation/admin-guide/media/amdisp4.dot b/Documentation/admin-guide/media/amdisp4.dot
> >> new file mode 100644
> >> index 000000000000..a4c2f0cceb30
> >> --- /dev/null
> >> +++ b/Documentation/admin-guide/media/amdisp4.dot
> >> @@ -0,0 +1,8 @@
> >> +digraph board {
> >> +	rankdir=TB
> >> +	n00000001 [label="{{<port0> 0} | amd isp4\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
> >> +	n00000001:port1 -> n00000004 [style=bold]
> >> +	n00000004 [label="Preview\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
> >> +	n0000000a [label="{{} | ov05c10 22-0010\n/dev/v4l-subdev0 | {<port0> 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 <pratap.nirujogi@amd.com>
> >>   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/*

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-08-12  6:33               ` Du, Bin
@ 2025-08-13  9:42                 ` Du, Bin
  2025-08-14  6:37                   ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-13  9:42 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

Hi Sultan,

On 8/12/2025 2:33 PM, Du, Bin wrote:
> Many thanks, Sultan.
> 
> On 8/12/2025 1:51 PM, Sultan Alsawaf wrote:
>> On Mon, Aug 11, 2025 at 05:05:39PM +0800, Du, Bin wrote:
>>>>> [ old quotes trimmed out ]
>>>>
>>>> Following up on this: there were several more issues hiding in the 
>>>> driver that
>>>> needed to be fixed unfortunately. I ended up making a lot of changes 
>>>> to fix all
>>>> of the buffer lifetime issues, and I created individual commits for 
>>>> this work
>>>> because it was getting hard to keep track of all the changes.
>>>>
>>>> I think I'll have this completed tomorrow and will provide a link to 
>>>> my tree
>>>> with my commits. Hopefully your internal branch hasn't diverged too 
>>>> much from
>>>> this patchset submission, otherwise there may be some conflicts to 
>>>> resolve.
>>>>
>>>> Sultan
>>>
>>> Really appreciate your time and effort. Yes, big code changes happen 
>>> in our
>>> internal branch to address upstream comments, but i believe your commits
>>> will be extremely valuable. We can check and test after fixing possbile
>>> conflict.
>>
>> I've pushed my work here:
>>
>>    https://github.com/kerneltoast/kernel_x86_laptop.git v6.16-drm-tip- 
>> isp4-for-amd
>>
>> Please see my changes since commit 
>> 48d18b6e58c6dadbc79374773736924d2f532da5 on
>> that branch, up to commit 5cdacf4ff108d83869414a00465e7a612bcd04b1.
>>
>> There are 29 patches:
>>
>> Sultan Alsawaf (29):
>>        media: amd: isp4: Use amdgpu helper functions for ISP buffers
>>        media: amd: isp4: Remove -mpreferred-stack-boundary=4 cflag
>>        media: amd: isp4: Remove -DCONFIG_COMPAT from ccflags-y
>>        media: amd: isp4: Remove the myriad of redundant ccflags includes
>>        media: amd: isp4: Pass warning flags through cc-option
>>        media: amd: isp4: Clean up amd_capture-objs formatting
>>        media: amd: isp4: Don't set CONFIG_AMD_ISP4 to y by default
>>        media: amd: isp4: Clean up AMD_ISP4 Kconfig dependencies
>>        media: amd: Fix Kconfig/Makefile directory structure
>>        media: amd: isp4: Remove superfluous NULL pointer checks
>>        media: amd: isp4: Remove superfluous void pointer casts
>>        media: amd: isp4: Remove superfluous memset in 
>> isp4vid_vb2_map_dmabuf()
>>        media: amd: isp4: Don't read refcount counter directly
>>        media: amd: isp4: Add missing refcount tracking to mmap memop
>>        media: amd: isp4: Don't put or unmap the dmabuf when detaching
>>        media: amd: isp4: Don't increment refcount when dmabuf export 
>> fails
>>        media: amd: isp4: Fix possible use-after-free in isp4vid_vb2_put()
>>        media: amd: isp4: Always export a new dmabuf from get_dmabuf memop
>>        media: amd: isp4: Fix implicit dmabuf lifetime tracking
>>        media: amd: isp4: Fix possible use-after-free when putting 
>> implicit dmabuf
>>        media: amd: isp4: Remove 'refcount > 0' warning in 
>> isp4vid_vb2_put()
>>        media: amd: isp4: Fix comment in isp4vid_vb2_dmabuf_ops_release()
>>        media: amd: isp4: Simplify isp4vid_get_dmabuf() arguments
>>        media: amd: isp4: Add comment to CONFIG_HAS_DMA #endif
>>        media: amd: isp4: Move up buf->vaddr check in isp4vid_get_dmabuf()
>>        media: amd: isp4: Remove unused userptr memops
>>        media: amd: isp4: Make isp4vid_vb2_memops static
>>        media: amd: isp4: Add missing cleanup on error in 
>> isp4vid_vb2_alloc()
>>        media: amd: isp4: Release queued buffers on error in 
>> start_streaming
>>
>>   drivers/media/platform/amd/Kconfig               |  18 +-
>>   drivers/media/platform/amd/Makefile              |   6 +-
>>   drivers/media/platform/amd/isp4/Kconfig          |  14 ++
>>   drivers/media/platform/amd/isp4/Makefile         |  42 +---
>>   drivers/media/platform/amd/isp4/isp4.c           |   9 +-
>>   drivers/media/platform/amd/isp4/isp4.h           |  11 -
>>   drivers/media/platform/amd/isp4/isp4_debug.c     |   4 +-
>>   drivers/media/platform/amd/isp4/isp4_interface.c |  46 +---
>>   drivers/media/platform/amd/isp4/isp4_interface.h |   6 +-
>>   drivers/media/platform/amd/isp4/isp4_subdev.c    |   8 +-
>>   drivers/media/platform/amd/isp4/isp4_subdev.h    |   4 +-
>>   drivers/media/platform/amd/isp4/isp4_video.c     | 297 +++++ 
>> +-----------------
>>   drivers/media/platform/amd/isp4/isp4_video.h     |   4 +-
>>   13 files changed, 122 insertions(+), 347 deletions(-)
>>
>> At least 1 of them should be redundant for your internal branch 
>> (9f394a7af2cf
>> "media: amd: isp4: Use amdgpu helper functions for ISP buffers").
>>
>> Cheers,
>> Sultan
> 
> Wow, amazing, fantastic work. Will compare to our latest internal branch 
> to see what might be missing and try to merge, then have some test. Will 
> let you know the result, it might cost some time. Thanks again.
> 

We cherry-picked your buffer related changes and did some quick test, it 
works well. Will merge them into our internal branch and check other 
changes later. Really appreciate for your time, effort and good work.

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers handling added
  2025-08-13  9:42                 ` Du, Bin
@ 2025-08-14  6:37                   ` Sultan Alsawaf
  0 siblings, 0 replies; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-14  6:37 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

On Wed, Aug 13, 2025 at 05:42:16PM +0800, Du, Bin wrote:
> On 8/12/2025 2:33 PM, Du, Bin wrote:
> > Many thanks, Sultan.
> > 
> > On 8/12/2025 1:51 PM, Sultan Alsawaf wrote:
> > > On Mon, Aug 11, 2025 at 05:05:39PM +0800, Du, Bin wrote:
> > > > > > [ old quotes trimmed out ]
> > > > > 
> > > > > Following up on this: there were several more issues hiding
> > > > > in the driver that
> > > > > needed to be fixed unfortunately. I ended up making a lot of
> > > > > changes to fix all
> > > > > of the buffer lifetime issues, and I created individual
> > > > > commits for this work
> > > > > because it was getting hard to keep track of all the changes.
> > > > > 
> > > > > I think I'll have this completed tomorrow and will provide a
> > > > > link to my tree
> > > > > with my commits. Hopefully your internal branch hasn't
> > > > > diverged too much from
> > > > > this patchset submission, otherwise there may be some
> > > > > conflicts to resolve.
> > > > > 
> > > > > Sultan
> > > > 
> > > > Really appreciate your time and effort. Yes, big code changes
> > > > happen in our
> > > > internal branch to address upstream comments, but i believe your commits
> > > > will be extremely valuable. We can check and test after fixing possbile
> > > > conflict.
> > > 
> > > I've pushed my work here:
> > > 
> > >    https://github.com/kerneltoast/kernel_x86_laptop.git
> > > v6.16-drm-tip- isp4-for-amd
> > > 
> > > Please see my changes since commit
> > > 48d18b6e58c6dadbc79374773736924d2f532da5 on
> > > that branch, up to commit 5cdacf4ff108d83869414a00465e7a612bcd04b1.
> > > 
> > > There are 29 patches:
> > > 
> > > Sultan Alsawaf (29):
> > >        media: amd: isp4: Use amdgpu helper functions for ISP buffers
> > >        media: amd: isp4: Remove -mpreferred-stack-boundary=4 cflag
> > >        media: amd: isp4: Remove -DCONFIG_COMPAT from ccflags-y
> > >        media: amd: isp4: Remove the myriad of redundant ccflags includes
> > >        media: amd: isp4: Pass warning flags through cc-option
> > >        media: amd: isp4: Clean up amd_capture-objs formatting
> > >        media: amd: isp4: Don't set CONFIG_AMD_ISP4 to y by default
> > >        media: amd: isp4: Clean up AMD_ISP4 Kconfig dependencies
> > >        media: amd: Fix Kconfig/Makefile directory structure
> > >        media: amd: isp4: Remove superfluous NULL pointer checks
> > >        media: amd: isp4: Remove superfluous void pointer casts
> > >        media: amd: isp4: Remove superfluous memset in
> > > isp4vid_vb2_map_dmabuf()
> > >        media: amd: isp4: Don't read refcount counter directly
> > >        media: amd: isp4: Add missing refcount tracking to mmap memop
> > >        media: amd: isp4: Don't put or unmap the dmabuf when detaching
> > >        media: amd: isp4: Don't increment refcount when dmabuf export
> > > fails
> > >        media: amd: isp4: Fix possible use-after-free in isp4vid_vb2_put()
> > >        media: amd: isp4: Always export a new dmabuf from get_dmabuf memop
> > >        media: amd: isp4: Fix implicit dmabuf lifetime tracking
> > >        media: amd: isp4: Fix possible use-after-free when putting
> > > implicit dmabuf
> > >        media: amd: isp4: Remove 'refcount > 0' warning in
> > > isp4vid_vb2_put()
> > >        media: amd: isp4: Fix comment in isp4vid_vb2_dmabuf_ops_release()
> > >        media: amd: isp4: Simplify isp4vid_get_dmabuf() arguments
> > >        media: amd: isp4: Add comment to CONFIG_HAS_DMA #endif
> > >        media: amd: isp4: Move up buf->vaddr check in isp4vid_get_dmabuf()
> > >        media: amd: isp4: Remove unused userptr memops
> > >        media: amd: isp4: Make isp4vid_vb2_memops static
> > >        media: amd: isp4: Add missing cleanup on error in
> > > isp4vid_vb2_alloc()
> > >        media: amd: isp4: Release queued buffers on error in
> > > start_streaming
> > > 
> > >   drivers/media/platform/amd/Kconfig               |  18 +-
> > >   drivers/media/platform/amd/Makefile              |   6 +-
> > >   drivers/media/platform/amd/isp4/Kconfig          |  14 ++
> > >   drivers/media/platform/amd/isp4/Makefile         |  42 +---
> > >   drivers/media/platform/amd/isp4/isp4.c           |   9 +-
> > >   drivers/media/platform/amd/isp4/isp4.h           |  11 -
> > >   drivers/media/platform/amd/isp4/isp4_debug.c     |   4 +-
> > >   drivers/media/platform/amd/isp4/isp4_interface.c |  46 +---
> > >   drivers/media/platform/amd/isp4/isp4_interface.h |   6 +-
> > >   drivers/media/platform/amd/isp4/isp4_subdev.c    |   8 +-
> > >   drivers/media/platform/amd/isp4/isp4_subdev.h    |   4 +-
> > >   drivers/media/platform/amd/isp4/isp4_video.c     | 297 +++++
> > > +-----------------
> > >   drivers/media/platform/amd/isp4/isp4_video.h     |   4 +-
> > >   13 files changed, 122 insertions(+), 347 deletions(-)
> > > 
> > > At least 1 of them should be redundant for your internal branch
> > > (9f394a7af2cf
> > > "media: amd: isp4: Use amdgpu helper functions for ISP buffers").
> > > 
> > > Cheers,
> > > Sultan
> > 
> > Wow, amazing, fantastic work. Will compare to our latest internal branch
> > to see what might be missing and try to merge, then have some test. Will
> > let you know the result, it might cost some time. Thanks again.
> > 
> 
> We cherry-picked your buffer related changes and did some quick test, it
> works well. Will merge them into our internal branch and check other changes
> later. Really appreciate for your time, effort and good work.

Glad to hear it! :)

Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
                   ` (8 preceding siblings ...)
  2025-07-23 18:12 ` [PATCH v2 0/8] Add AMD ISP4 driver Sultan Alsawaf
@ 2025-08-14  6:53 ` Sultan Alsawaf
  2025-08-22  2:23   ` Du, Bin
  9 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-14  6:53 UTC (permalink / raw)
  To: Bin Du
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
> AMD ISP4 Key features:
> - Processes bayer raw data from the connected sensor and output them to different YUV formats
> - Downscale input image to different output image resolution
> - Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc

BTW, another problem I have which I would love some help with: may I get the FW
commands for setting basic 3A parameters?

It seems like the default AE mode does frame-averaging, which is really
unsuitable for video calls on the webcam. My face is really underexposed as a
result during the daytime because there's a lot of ambient light in the
background.

The webcam on this laptop also has a very wide field of view, which makes my
face appear small and shows too much of the background. This also exacerbates
the AE problem.

I'm thinking CMD_ID_SET_ZOOM would fix the FOV problem, and then either
CMD_ID_AE_SET_MODE to change the AE mode or CMD_ID_AE_SET_REGION to set the AE
ROI would fix the exposure problem. What do you think?

Thanks,
Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-08-12  1:36     ` Du, Bin
  2025-08-12 13:42       ` Laurent Pinchart
@ 2025-08-20 12:42       ` Sakari Ailus
  2025-08-22  2:20         ` Du, Bin
  1 sibling, 1 reply; 96+ messages in thread
From: Sakari Ailus @ 2025-08-20 12:42 UTC (permalink / raw)
  To: Du, Bin
  Cc: Laurent Pinchart, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Svetoslav.Stoilov

Hi Bin,

On Tue, Aug 12, 2025 at 09:36:04AM +0800, Du, Bin wrote:
> Many thanks Laurent Pinchart for the review.
> 
> On 8/5/2025 7:37 PM, Laurent Pinchart wrote:
> > On Wed, Jun 18, 2025 at 05:19:59PM +0800, Bin Du wrote:
> > > Add documentation for AMD isp 4 and describe the main components
> > > 
> > > Signed-off-by: Bin Du <Bin.Du@amd.com>
> > > Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
> > > ---
> > >   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:: <isonum.txt>
> > > +
> > > +====================================
> > > +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:
> > > +
> > > +- <capture video device: capture device for retrieving images.
> > > +
> > > +
> > > +  - ISP4 Image Signal Processing Subdevice Node
> > > +-----------------------------------------------
> > > +
> > > +The isp4 is represented as a single V4L2 subdev, the sub-device does not
> > > +provide interface to the user space.
> > 
> > Doesn't it ? The driver sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the
> > subdev, and calls v4l2_device_register_subdev_nodes().
> > 
> 
> We have exported subdev device to user space during the testing with
> libcamera sample pipeline.
> 
> > As far as I understand, the camera is exposed by the firmware with a
> > webcam-like interface. We need to better understand your plans with this
> > driver. If everything is handled by the firmware, why are the sensor and
> > subdev exposed to userspace ? Why can't you expose a single video
> > capture device, with a media device, and handle everything behind the
> > scene ? I assume there may be more features coming later. Please
> > document the plan, we can't provide feedback on the architecture
> > otherwise.
> > 
> 
> Currently, isp fw is controlling the sensor to update just the exposure and
> gain, since the 3A algorithms run on ISP HW rather than on x86. In a future
> version, we plan to introduce raw output support in the ISP driver, allowing
> users to choose between AMD’s 3A running on ISP hardware or a custom 3A
> running on x86. If the user opts for the x86-based 3A, the firmware will
> relinquish control of the sensor, and hands over full control to the x86
> system.

There are a few problems I see with this approach.

Camera sensors are separate devices from the ISP and they're expected to be
controlled by the respective camera sensor drivers and these drivers only.
The firmware contains the camera control algorithms as well as tuning; this
is something that's better located outside of it.

The complex camera system comprising of a camera sensor, an ISP and a
microcontroller within you have is right now semi-integrated to the SoC and
I think it needs to be either fully unintegrated (the ISPs we currently
support) or fully integrated (e.g. UVC webcams).

There are two options that I can see here, in descending order of
preference:

1. Control the ISP processing blocks from the AMD ISP driver, via a
   documented UAPI. This includes setting processing block parameters and
   being able to obtain statistics from the ISP. This is aligned with the
   other currently supported ISP drivers.
   
   This option could include support for the CSI-2 receiver only, with the
   processing taking place in SoftISP. Fully supported ISP would of course
   be preferred.
   
   Right now I don't have an opinion on whether or not this needs to
   include libcamera support, but the ISP driver wouldn't be of much use
   without that anyway.

2. Move sensor control to firmware and make the AMD ISP driver expose an
   interface that looks like a webcam, akin to the UVC driver. In this case
   there's also no use for the sensor driver you've posted earlier.
   Overall, the ISP/sensor combination will probably be limited to use as a
   webcam in this case.

-- 
Kind regards,

Sakari Ailus

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-08-20 12:42       ` Sakari Ailus
@ 2025-08-22  2:20         ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-22  2:20 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Laurent Pinchart, mchehab, hverkuil, bryan.odonoghue,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du, Mario Limonciello,
	Richard.Gong, anson.tsao

Many thanks Sakari Ailus for your deep insight

On 8/20/2025 8:42 PM, Sakari Ailus wrote:
> Hi Bin,
> 
> On Tue, Aug 12, 2025 at 09:36:04AM +0800, Du, Bin wrote:
>> Many thanks Laurent Pinchart for the review.
>>
>> On 8/5/2025 7:37 PM, Laurent Pinchart wrote:
>>> On Wed, Jun 18, 2025 at 05:19:59PM +0800, Bin Du wrote:
>>>> Add documentation for AMD isp 4 and describe the main components
>>>>
>>>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>>> ---
>>>>    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:: <isonum.txt>
>>>> +
>>>> +====================================
>>>> +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:
>>>> +
>>>> +- <capture video device: capture device for retrieving images.
>>>> +
>>>> +
>>>> +  - ISP4 Image Signal Processing Subdevice Node
>>>> +-----------------------------------------------
>>>> +
>>>> +The isp4 is represented as a single V4L2 subdev, the sub-device does not
>>>> +provide interface to the user space.
>>>
>>> Doesn't it ? The driver sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the
>>> subdev, and calls v4l2_device_register_subdev_nodes().
>>>
>>
>> We have exported subdev device to user space during the testing with
>> libcamera sample pipeline.
>>
>>> As far as I understand, the camera is exposed by the firmware with a
>>> webcam-like interface. We need to better understand your plans with this
>>> driver. If everything is handled by the firmware, why are the sensor and
>>> subdev exposed to userspace ? Why can't you expose a single video
>>> capture device, with a media device, and handle everything behind the
>>> scene ? I assume there may be more features coming later. Please
>>> document the plan, we can't provide feedback on the architecture
>>> otherwise.
>>>
>>
>> Currently, isp fw is controlling the sensor to update just the exposure and
>> gain, since the 3A algorithms run on ISP HW rather than on x86. In a future
>> version, we plan to introduce raw output support in the ISP driver, allowing
>> users to choose between AMD’s 3A running on ISP hardware or a custom 3A
>> running on x86. If the user opts for the x86-based 3A, the firmware will
>> relinquish control of the sensor, and hands over full control to the x86
>> system.
> 
> There are a few problems I see with this approach.
> 
> Camera sensors are separate devices from the ISP and they're expected to be
> controlled by the respective camera sensor drivers and these drivers only.
> The firmware contains the camera control algorithms as well as tuning; this
> is something that's better located outside of it.
> 
> The complex camera system comprising of a camera sensor, an ISP and a
> microcontroller within you have is right now semi-integrated to the SoC and
> I think it needs to be either fully unintegrated (the ISPs we currently
> support) or fully integrated (e.g. UVC webcams).
> 
> There are two options that I can see here, in descending order of
> preference:
> 
> 1. Control the ISP processing blocks from the AMD ISP driver, via a
>     documented UAPI. This includes setting processing block parameters and
>     being able to obtain statistics from the ISP. This is aligned with the
>     other currently supported ISP drivers.
>     
>     This option could include support for the CSI-2 receiver only, with the
>     processing taking place in SoftISP. Fully supported ISP would of course
>     be preferred.
>     
>     Right now I don't have an opinion on whether or not this needs to
>     include libcamera support, but the ISP driver wouldn't be of much use
>     without that anyway.
> 
> 2. Move sensor control to firmware and make the AMD ISP driver expose an
>     interface that looks like a webcam, akin to the UVC driver. In this case
>     there's also no use for the sensor driver you've posted earlier.
>     Overall, the ISP/sensor combination will probably be limited to use as a
>     webcam in this case.
> 

Based on our internal discussion and validation, will make option 2 as 
our current upstream target, after that, will plan option 1 with more 
considerations, a. Whether to provide the capability and interface so 
user can do switch between option 1 and 2. b. Whether and how to expose 
interface so host can leverage the ISP HW feature to accelerat some 
processing. Though sensor driver is not used in option 2, we still plan 
to upstream it because of option 1 as next step.

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-14  6:53 ` Sultan Alsawaf
@ 2025-08-22  2:23   ` Du, Bin
  2025-08-22  3:56     ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-22  2:23 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du, Mario Limonciello,
	Richard.Gong, anson.tsao

Thanks Sultan for the suggestion, sorry for the late response because we 
spent some time internally to discuss the feasibility.

On 8/14/2025 2:53 PM, Sultan Alsawaf wrote:
> On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
>> AMD ISP4 Key features:
>> - Processes bayer raw data from the connected sensor and output them to different YUV formats
>> - Downscale input image to different output image resolution
>> - Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc
> 
> BTW, another problem I have which I would love some help with: may I get the FW
> commands for setting basic 3A parameters?
> 
> It seems like the default AE mode does frame-averaging, which is really
> unsuitable for video calls on the webcam. My face is really underexposed as a
> result during the daytime because there's a lot of ambient light in the
> background.
> 
> The webcam on this laptop also has a very wide field of view, which makes my
> face appear small and shows too much of the background. This also exacerbates
> the AE problem.
> 
> I'm thinking CMD_ID_SET_ZOOM would fix the FOV problem, and then either
> CMD_ID_AE_SET_MODE to change the AE mode or CMD_ID_AE_SET_REGION to set the AE
> ROI would fix the exposure problem. What do you think?
> 
> Thanks,
> Sultan

Yes, it's really good suggestion. Because current V4l2 doesn't have 
standard ioctl for like region setting, to support it, besides adding FW 
command, new customized ioctl also needs be added and no existing APP 
can benefit from it. So our idea is not to add them to our current 
upstream driver, but we would be really glad to help you to enable them 
locally with dedicated thread, suppose it can help to improve the IQ 
with correct input setting like the correct ROI region, but we aren't 
sure because we didn't do that before on Linux and would really expect 
your test result and feedback.

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver
  2025-08-12 13:42       ` Laurent Pinchart
@ 2025-08-22  2:28         ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-08-22  2:28 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: mchehab, hverkuil, bryan.odonoghue, sakari.ailus,
	prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, bin.du, Mario Limonciello,
	Richard.Gong, anson.tsao

Many thanks Laurent, sorry for the late response because we had a lot of 
internal discussion and did possible solution prototype validation.

On 8/12/2025 9:42 PM, Laurent Pinchart wrote:
> On Tue, Aug 12, 2025 at 09:36:04AM +0800, Du, Bin wrote:
>> On 8/5/2025 7:37 PM, Laurent Pinchart wrote:
>>> On Wed, Jun 18, 2025 at 05:19:59PM +0800, Bin Du wrote:
>>>> Add documentation for AMD isp 4 and describe the main components
>>>>
>>>> Signed-off-by: Bin Du <Bin.Du@amd.com>
>>>> Signed-off-by: Svetoslav Stoilov <Svetoslav.Stoilov@amd.com>
>>>> ---
>>>>    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:: <isonum.txt>
>>>> +
>>>> +====================================
>>>> +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:
>>>> +
>>>> +- <capture video device: capture device for retrieving images.
>>>> +
>>>> +
>>>> +  - ISP4 Image Signal Processing Subdevice Node
>>>> +-----------------------------------------------
>>>> +
>>>> +The isp4 is represented as a single V4L2 subdev, the sub-device does not
>>>> +provide interface to the user space.
>>>
>>> Doesn't it ? The driver sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the
>>> subdev, and calls v4l2_device_register_subdev_nodes().
>>
>> We have exported subdev device to user space during the testing with
>> libcamera sample pipeline.
> 
> But it's not needed anymore ? If not, you could stop exposing the subdev
> to userspace for the time being.
> 

Yes, will not expose ISP subdev to userspace. Please see more details below.

>>> As far as I understand, the camera is exposed by the firmware with a
>>> webcam-like interface. We need to better understand your plans with this
>>> driver. If everything is handled by the firmware, why are the sensor and
>>> subdev exposed to userspace ? Why can't you expose a single video
>>> capture device, with a media device, and handle everything behind the
>>> scene ? I assume there may be more features coming later. Please
>>> document the plan, we can't provide feedback on the architecture
>>> otherwise.
>>
>> Currently, isp fw is controlling the sensor to update just the exposure
>> and gain, since the 3A algorithms run on ISP HW rather than on x86.
> 
> This design decision makes my hair stand on end :-( Exposing the camera
> sensor to both the firmware and the host concurrently is asking for
> trouble. If you really want to abstract the camera behind a firmware and
> only expose a webcam-like API (or not even that in this version, as the
> driver exposes no control as far as I can see), then you should push the
> whole sensor handling to the firmware too. In my opinion that would not
> be a good solution compared to exposing the ISP to the host, but it
> would be better than this hybrid model.
> 

Totally agree, yes, the hybrid model is really a bad idea, based on our 
internal validation, we plan to take one of your suggestions, that is to 
push the whole sensor handling to the firmware, so our ISP driver will 
work like UVC driver.

>> In a
>> future version, we plan to introduce raw output support in the ISP
>> driver, allowing users to choose between AMD’s 3A running on ISP
>> hardware or a custom 3A running on x86. If the user opts for the
>> x86-based 3A, the firmware will relinquish control of the sensor, and
>> hands over full control to the x86 system.
> 
> Will the firmware at that point expose to Linux all the ISP statistics
> needed to implement auto-exposure ? What if I want to also set digital
> gain ? Or have manual white balance (requiring statistics), and manual
> CCM ?
> 

No, because all 3A, ISP and camera control will be put inside firmware. 
Currently, we only support auto mode, so, no manual control will be exposed

>>>> The sub-device is connected to one video node
>>>> +(isp4_capture) with immutable active link. The isp entity is connected
>>>> +to sensor pad 0 and receives the frames using CSI-2 protocol. The sub-device is
>>>> +also responsible to configure CSI2-2 receiver.
>>>> +The sub-device processes bayer raw data from the connected sensor and output
>>>> +them to different YUV formats. The isp also has scaling capabilities.
>>>> +
>>>> +  - isp4_capture - Frames Capture Video Node
>>>> +--------------------------------------------
>>>> +
>>>> +Isp4_capture is a capture device to capture frames to memory.
>>>> +This entity is the DMA engine that write the frames to memory.
>>>> +The entity is connected to isp4 sub-device.
>>>> +
>>>> +Capturing Video Frames Example
>>>> +==============================
>>>> +
>>>> +.. code-block:: bash
>>>> +
>>>> +         # set the links
>>>
>>> This seems very under-documented.
>>
>> Yes, documentation needs to be updated.
>>
>>>> +
>>>> +         # start streaming:
>>>> +         v4l2-ctl "-d" "/dev/video0" "--set-fmt-video=width=1920,height=1080,pixelformat=NV12" "--stream-mmap" "--stream-count=10"
>>>> diff --git a/Documentation/admin-guide/media/amdisp4.dot b/Documentation/admin-guide/media/amdisp4.dot
>>>> new file mode 100644
>>>> index 000000000000..a4c2f0cceb30
>>>> --- /dev/null
>>>> +++ b/Documentation/admin-guide/media/amdisp4.dot
>>>> @@ -0,0 +1,8 @@
>>>> +digraph board {
>>>> +	rankdir=TB
>>>> +	n00000001 [label="{{<port0> 0} | amd isp4\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
>>>> +	n00000001:port1 -> n00000004 [style=bold]
>>>> +	n00000004 [label="Preview\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
>>>> +	n0000000a [label="{{} | ov05c10 22-0010\n/dev/v4l-subdev0 | {<port0> 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 <pratap.nirujogi@amd.com>
>>>>    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/*
> 

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-22  2:23   ` Du, Bin
@ 2025-08-22  3:56     ` Sultan Alsawaf
  2025-08-27 10:30       ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-22  3:56 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab, hverkuil, laurent.pinchart+renesas, bryan.odonoghue,
	sakari.ailus, prabhakar.mahadev-lad.rj, linux-media, linux-kernel,
	pratap.nirujogi, benjamin.chan, king.li, gjorgji.rosikopulos,
	Phil.Jawich, Dominic.Antony, Mario Limonciello, Richard.Gong,
	anson.tsao

On Fri, Aug 22, 2025 at 10:23:48AM +0800, Du, Bin wrote:
> On 8/14/2025 2:53 PM, Sultan Alsawaf wrote:
> > On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
> > > AMD ISP4 Key features:
> > > - Processes bayer raw data from the connected sensor and output them to different YUV formats
> > > - Downscale input image to different output image resolution
> > > - Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc
> > 
> > BTW, another problem I have which I would love some help with: may I get the FW
> > commands for setting basic 3A parameters?
> > 
> > It seems like the default AE mode does frame-averaging, which is really
> > unsuitable for video calls on the webcam. My face is really underexposed as a
> > result during the daytime because there's a lot of ambient light in the
> > background.
> > 
> > The webcam on this laptop also has a very wide field of view, which makes my
> > face appear small and shows too much of the background. This also exacerbates
> > the AE problem.
> > 
> > I'm thinking CMD_ID_SET_ZOOM would fix the FOV problem, and then either
> > CMD_ID_AE_SET_MODE to change the AE mode or CMD_ID_AE_SET_REGION to set the AE
> > ROI would fix the exposure problem. What do you think?
> > 
> > Thanks,
> > Sultan
>
> Thanks Sultan for the suggestion, sorry for the late response because we
> spent some time internally to discuss the feasibility.

Thanks for looking into this!

> Yes, it's really good suggestion. Because current V4l2 doesn't have standard
> ioctl for like region setting, to support it, besides adding FW command, new
> customized ioctl also needs be added and no existing APP can benefit from
> it. So our idea is not to add them to our current upstream driver, but we
> would be really glad to help you to enable them locally with dedicated
> thread, suppose it can help to improve the IQ with correct input setting
> like the correct ROI region, but we aren't sure because we didn't do that
> before on Linux and would really expect your test result and feedback.

I'm happy to help develop this and even help write the code. :)

I think a lot of useful functionality can be put upstream just through V4L2,
like V4L2_CID_EXPOSURE_METERING to control the AE mode.

For advanced functions that don't have a standard V4L2 control, maybe we can set
some defaults in the driver to improve the experience for front-facing cameras,
i.e. webcams.

Depending on the features exposed by FW, maybe setting a ROI for AE isn't
necessary. Is it possible for the FW to do face detection and set 3A according
to the face landmarks/ROI?

Thanks,
Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-22  3:56     ` Sultan Alsawaf
@ 2025-08-27 10:30       ` Du, Bin
  2025-08-28  5:50         ` Sultan Alsawaf
  0 siblings, 1 reply; 96+ messages in thread
From: Du, Bin @ 2025-08-27 10:30 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
	laurent.pinchart+renesas@ideasonboard.com,
	bryan.odonoghue@linaro.org, sakari.ailus@linux.intel.com,
	prabhakar.mahadev-lad.rj@bp.renesas.com,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	Nirujogi, Pratap, Chan, Benjamin (Koon Pan), Li, King,
	Rosikopulos, Gjorgji, Jawich, Phil, Antony, Dominic,
	Limonciello, Mario, Gong, Richard, Tsao, Anson

Thanks Sultan.

On 8/22/2025 11:56 AM, Sultan Alsawaf wrote:
> On Fri, Aug 22, 2025 at 10:23:48AM +0800, Du, Bin wrote:
>> On 8/14/2025 2:53 PM, Sultan Alsawaf wrote:
>>> On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
>>>> AMD ISP4 Key features:
>>>> - Processes bayer raw data from the connected sensor and output them to different YUV formats
>>>> - Downscale input image to different output image resolution
>>>> - Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc
>>>
>>> BTW, another problem I have which I would love some help with: may I get the FW
>>> commands for setting basic 3A parameters?
>>>
>>> It seems like the default AE mode does frame-averaging, which is really
>>> unsuitable for video calls on the webcam. My face is really underexposed as a
>>> result during the daytime because there's a lot of ambient light in the
>>> background.
>>>
>>> The webcam on this laptop also has a very wide field of view, which makes my
>>> face appear small and shows too much of the background. This also exacerbates
>>> the AE problem.
>>>
>>> I'm thinking CMD_ID_SET_ZOOM would fix the FOV problem, and then either
>>> CMD_ID_AE_SET_MODE to change the AE mode or CMD_ID_AE_SET_REGION to set the AE
>>> ROI would fix the exposure problem. What do you think?
>>>
>>> Thanks,
>>> Sultan
>>
>> Thanks Sultan for the suggestion, sorry for the late response because we
>> spent some time internally to discuss the feasibility.
> 
> Thanks for looking into this!
> 
>> Yes, it's really good suggestion. Because current V4l2 doesn't have standard
>> ioctl for like region setting, to support it, besides adding FW command, new
>> customized ioctl also needs be added and no existing APP can benefit from
>> it. So our idea is not to add them to our current upstream driver, but we
>> would be really glad to help you to enable them locally with dedicated
>> thread, suppose it can help to improve the IQ with correct input setting
>> like the correct ROI region, but we aren't sure because we didn't do that
>> before on Linux and would really expect your test result and feedback.
> 
> I'm happy to help develop this and even help write the code. :)
> 

Thank you very much for your consistent help, that's invaluable.

> I think a lot of useful functionality can be put upstream just through V4L2,
> like V4L2_CID_EXPOSURE_METERING to control the AE mode.
> 

Yes, that's feasible, the consideration is if we add support to control 
AE mode, as a complete solution, then we have to add support to set 
again and exposure time in manual mode by FW command , besides that, 
extra work is also needed from QA to develop new testcases, all these 
together will cost more time. So, our current plan is first to upstream 
a version with basic functions, after that, we can submit incremental 
patches to add more features. Does it make sense?

> For advanced functions that don't have a standard V4L2 control, maybe we can set
> some defaults in the driver to improve the experience for front-facing cameras,
> i.e. webcams.
>> Depending on the features exposed by FW, maybe setting a ROI for AE isn't
> necessary. Is it possible for the FW to do face detection and set 3A according
> to the face landmarks/ROI?
> 

Oh, so sad, our FW doesn't embed algorithm to do face detection. :(

> Thanks,
> Sultan

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-27 10:30       ` Du, Bin
@ 2025-08-28  5:50         ` Sultan Alsawaf
  2025-09-02  2:08           ` Du, Bin
  0 siblings, 1 reply; 96+ messages in thread
From: Sultan Alsawaf @ 2025-08-28  5:50 UTC (permalink / raw)
  To: Du, Bin
  Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
	laurent.pinchart+renesas@ideasonboard.com,
	bryan.odonoghue@linaro.org, sakari.ailus@linux.intel.com,
	prabhakar.mahadev-lad.rj@bp.renesas.com,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	Nirujogi, Pratap, Chan, Benjamin (Koon Pan), Li, King,
	Rosikopulos, Gjorgji, Jawich, Phil, Antony, Dominic,
	Limonciello, Mario, Gong, Richard, Tsao, Anson

On Wed, Aug 27, 2025 at 06:30:14PM +0800, Du, Bin wrote:
> On 8/22/2025 11:56 AM, Sultan Alsawaf wrote:
> > On Fri, Aug 22, 2025 at 10:23:48AM +0800, Du, Bin wrote:
> > > On 8/14/2025 2:53 PM, Sultan Alsawaf wrote:
> > > > On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
> > > > > AMD ISP4 Key features:
> > > > > - Processes bayer raw data from the connected sensor and output them to different YUV formats
> > > > > - Downscale input image to different output image resolution
> > > > > - Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc
> > > > 
> > > > BTW, another problem I have which I would love some help with: may I get the FW
> > > > commands for setting basic 3A parameters?
> > > > 
> > > > It seems like the default AE mode does frame-averaging, which is really
> > > > unsuitable for video calls on the webcam. My face is really underexposed as a
> > > > result during the daytime because there's a lot of ambient light in the
> > > > background.
> > > > 
> > > > The webcam on this laptop also has a very wide field of view, which makes my
> > > > face appear small and shows too much of the background. This also exacerbates
> > > > the AE problem.
> > > > 
> > > > I'm thinking CMD_ID_SET_ZOOM would fix the FOV problem, and then either
> > > > CMD_ID_AE_SET_MODE to change the AE mode or CMD_ID_AE_SET_REGION to set the AE
> > > > ROI would fix the exposure problem. What do you think?
> > > > 
> > > > Thanks,
> > > > Sultan
> > > 
> > > Thanks Sultan for the suggestion, sorry for the late response because we
> > > spent some time internally to discuss the feasibility.
> > 
> > Thanks for looking into this!
> > 
> > > Yes, it's really good suggestion. Because current V4l2 doesn't have standard
> > > ioctl for like region setting, to support it, besides adding FW command, new
> > > customized ioctl also needs be added and no existing APP can benefit from
> > > it. So our idea is not to add them to our current upstream driver, but we
> > > would be really glad to help you to enable them locally with dedicated
> > > thread, suppose it can help to improve the IQ with correct input setting
> > > like the correct ROI region, but we aren't sure because we didn't do that
> > > before on Linux and would really expect your test result and feedback.
> > 
> > I'm happy to help develop this and even help write the code. :)
> 
> Thank you very much for your consistent help, that's invaluable.

Of course! :)

> > For advanced functions that don't have a standard V4L2 control, maybe we can set
> > some defaults in the driver to improve the experience for front-facing cameras,
> > i.e. webcams.
> >
> > Depending on the features exposed by FW, maybe setting a ROI for AE isn't
> > necessary. Is it possible for the FW to do face detection and set 3A according
> > to the face landmarks/ROI?
> 
> Oh, so sad, our FW doesn't embed algorithm to do face detection. :(

Ah, that's unfortunate. :(

> > I think a lot of useful functionality can be put upstream just through V4L2,
> > like V4L2_CID_EXPOSURE_METERING to control the AE mode.
> 
> Yes, that's feasible, the consideration is if we add support to control AE
> mode, as a complete solution, then we have to add support to set again and
> exposure time in manual mode by FW command , besides that, extra work is
> also needed from QA to develop new testcases, all these together will cost
> more time. So, our current plan is first to upstream a version with basic
> functions, after that, we can submit incremental patches to add more
> features. Does it make sense?

Yes, I understand.

For now, what about just changing the default AE mode to center-weighted? I
think this would produce a big IQ improvement since the typical usecase for the
webcam is to show your face in the center of the frame. This change could even
be made in the firmware instead of the driver.

Or alternatively, HDR could be enabled by default.

What do you think?

Thanks,
Sultan

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v2 0/8] Add AMD ISP4 driver
  2025-08-28  5:50         ` Sultan Alsawaf
@ 2025-09-02  2:08           ` Du, Bin
  0 siblings, 0 replies; 96+ messages in thread
From: Du, Bin @ 2025-09-02  2:08 UTC (permalink / raw)
  To: Sultan Alsawaf
  Cc: mchehab@kernel.org, hverkuil@xs4all.nl,
	laurent.pinchart+renesas@ideasonboard.com,
	bryan.odonoghue@linaro.org, sakari.ailus@linux.intel.com,
	prabhakar.mahadev-lad.rj@bp.renesas.com,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	Nirujogi, Pratap, Chan, Benjamin (Koon Pan), Li, King,
	Rosikopulos, Gjorgji, Jawich, Phil, Antony, Dominic,
	Limonciello, Mario, Gong, Richard, Tsao, Anson

Thanks, Sultan.

On 8/28/2025 1:50 PM, Sultan Alsawaf wrote:
> On Wed, Aug 27, 2025 at 06:30:14PM +0800, Du, Bin wrote:
>> On 8/22/2025 11:56 AM, Sultan Alsawaf wrote:
>>> On Fri, Aug 22, 2025 at 10:23:48AM +0800, Du, Bin wrote:
>>>> On 8/14/2025 2:53 PM, Sultan Alsawaf wrote:
>>>>> On Wed, Jun 18, 2025 at 05:19:51PM +0800, Bin Du wrote:
>>>>>> AMD ISP4 Key features:
>>>>>> - Processes bayer raw data from the connected sensor and output them to different YUV formats
>>>>>> - Downscale input image to different output image resolution
>>>>>> - Pipeline to do image processing on the input image including demosaic, denoise, 3A, etc
>>>>>
>>>>> BTW, another problem I have which I would love some help with: may I get the FW
>>>>> commands for setting basic 3A parameters?
>>>>>
>>>>> It seems like the default AE mode does frame-averaging, which is really
>>>>> unsuitable for video calls on the webcam. My face is really underexposed as a
>>>>> result during the daytime because there's a lot of ambient light in the
>>>>> background.
>>>>>
>>>>> The webcam on this laptop also has a very wide field of view, which makes my
>>>>> face appear small and shows too much of the background. This also exacerbates
>>>>> the AE problem.
>>>>>
>>>>> I'm thinking CMD_ID_SET_ZOOM would fix the FOV problem, and then either
>>>>> CMD_ID_AE_SET_MODE to change the AE mode or CMD_ID_AE_SET_REGION to set the AE
>>>>> ROI would fix the exposure problem. What do you think?
>>>>>
>>>>> Thanks,
>>>>> Sultan
>>>>
>>>> Thanks Sultan for the suggestion, sorry for the late response because we
>>>> spent some time internally to discuss the feasibility.
>>>
>>> Thanks for looking into this!
>>>
>>>> Yes, it's really good suggestion. Because current V4l2 doesn't have standard
>>>> ioctl for like region setting, to support it, besides adding FW command, new
>>>> customized ioctl also needs be added and no existing APP can benefit from
>>>> it. So our idea is not to add them to our current upstream driver, but we
>>>> would be really glad to help you to enable them locally with dedicated
>>>> thread, suppose it can help to improve the IQ with correct input setting
>>>> like the correct ROI region, but we aren't sure because we didn't do that
>>>> before on Linux and would really expect your test result and feedback.
>>>
>>> I'm happy to help develop this and even help write the code. :)
>>
>> Thank you very much for your consistent help, that's invaluable.
> 
> Of course! :)
> 
>>> For advanced functions that don't have a standard V4L2 control, maybe we can set
>>> some defaults in the driver to improve the experience for front-facing cameras,
>>> i.e. webcams.
>>>
>>> Depending on the features exposed by FW, maybe setting a ROI for AE isn't
>>> necessary. Is it possible for the FW to do face detection and set 3A according
>>> to the face landmarks/ROI?
>>
>> Oh, so sad, our FW doesn't embed algorithm to do face detection. :(
> 
> Ah, that's unfortunate. :(
> 
>>> I think a lot of useful functionality can be put upstream just through V4L2,
>>> like V4L2_CID_EXPOSURE_METERING to control the AE mode.
>>
>> Yes, that's feasible, the consideration is if we add support to control AE
>> mode, as a complete solution, then we have to add support to set again and
>> exposure time in manual mode by FW command , besides that, extra work is
>> also needed from QA to develop new testcases, all these together will cost
>> more time. So, our current plan is first to upstream a version with basic
>> functions, after that, we can submit incremental patches to add more
>> features. Does it make sense?
> 
> Yes, I understand.
> 
> For now, what about just changing the default AE mode to center-weighted? I
> think this would produce a big IQ improvement since the typical usecase for the
> webcam is to show your face in the center of the frame. This change could even
> be made in the firmware instead of the driver.
> 

Many thanks, you can always come up with good suggestions and ideas, 
that's really helpful. Yes, the ideal place will be in the FW. Have 
given this suggestion to FW guys, they mentioned they will check if 
there is center-wighted AE mode if got time, so far, it is never used 
and tuned.

> Or alternatively, HDR could be enabled by default.
> 
> What do you think?
> 

Yes, HDR should be able to improve the IQ, as you know, starting from 
patch V3, sensor driver will embed in FW and ISP driver will work just 
like webcam. To add HDR, we need support from sensor vendor, on the 
other hand, complete tuning and verification are also needed.

> Thanks,
> Sultan

-- 
Regards,
Bin


^ permalink raw reply	[flat|nested] 96+ messages in thread

end of thread, other threads:[~2025-09-02  2:08 UTC | newest]

Thread overview: 96+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-18  9:19 [PATCH v2 0/8] Add AMD ISP4 driver Bin Du
2025-06-18  9:19 ` [PATCH v2 1/8] media: platform: amd: Introduce amd isp4 capture driver Bin Du
2025-06-18 15:58   ` Mario Limonciello
2025-06-19  7:46     ` Du, Bin
2025-06-19 13:00       ` Mario Limonciello
2025-06-20  3:08         ` Du, Bin
2025-07-28  5:54   ` Sakari Ailus
2025-07-28  9:00     ` Du, Bin
2025-06-18  9:19 ` [PATCH v2 2/8] media: platform: amd: low level support for isp4 firmware Bin Du
2025-06-18 16:00   ` Mario Limonciello
2025-06-19  7:53     ` Du, Bin
2025-07-28  5:57   ` Sakari Ailus
2025-07-28  9:24     ` Du, Bin
2025-06-18  9:19 ` [PATCH v2 3/8] media: platform: amd: Add helpers to configure isp4 mipi phy Bin Du
2025-07-28  6:33   ` Sakari Ailus
2025-08-05  9:53     ` Du, Bin
2025-08-05 10:53       ` Laurent Pinchart
2025-08-06  9:56         ` Du, Bin
2025-08-05 10:39     ` Laurent Pinchart
2025-08-06  9:45       ` Du, Bin
2025-07-28  7:28   ` Sakari Ailus
2025-07-31  9:31     ` Du, Bin
2025-06-18  9:19 ` [PATCH v2 4/8] media: platform: amd: Add isp4 fw and hw interface Bin Du
2025-06-18 16:17   ` Mario Limonciello
2025-06-19  9:58     ` Du, Bin
2025-06-19 15:11       ` Mario Limonciello
2025-06-20  3:32         ` Du, Bin
2025-07-28  7:23   ` Sakari Ailus
2025-07-29  9:12     ` Du, Bin
2025-08-11 11:46       ` Sakari Ailus
2025-08-11 12:31         ` Laurent Pinchart
2025-08-12  3:36           ` Du, Bin
2025-08-12  7:34             ` Laurent Pinchart
2025-08-12  8:08               ` Du, Bin
2025-08-12  8:20               ` Sakari Ailus
2025-08-12 10:04                 ` Du, Bin
2025-08-12  2:44         ` Du, Bin
2025-06-18  9:19 ` [PATCH v2 5/8] media: platform: amd: isp4 subdev and firmware loading handling added Bin Du
2025-06-18 16:35   ` Mario Limonciello
2025-06-20  9:31     ` Du, Bin
2025-07-06 20:55       ` Mario Limonciello
2025-07-07  6:22         ` Du, Bin
2025-07-25  1:35   ` Sultan Alsawaf
2025-07-25  9:03     ` Du, Bin
2025-06-18  9:19 ` [PATCH v2 6/8] media: platform: amd: isp4 video node and buffers " Bin Du
2025-07-23 17:55   ` Sultan Alsawaf
2025-07-24  5:14     ` Sultan Alsawaf
2025-07-25  9:05       ` Du, Bin
2025-07-25  9:22     ` Du, Bin
2025-07-26 21:41       ` Sultan Alsawaf
2025-07-26 21:50         ` Sultan Alsawaf
2025-07-29  6:12           ` Du, Bin
2025-07-29  6:08         ` Du, Bin
2025-07-28  7:04   ` Sultan Alsawaf
2025-07-29  7:43     ` Du, Bin
2025-07-31  0:34       ` Sultan Alsawaf
2025-07-31  9:45         ` Du, Bin
2025-08-11  6:02         ` Sultan Alsawaf
2025-08-11  9:05           ` Du, Bin
2025-08-12  5:51             ` Sultan Alsawaf
2025-08-12  6:33               ` Du, Bin
2025-08-13  9:42                 ` Du, Bin
2025-08-14  6:37                   ` Sultan Alsawaf
2025-06-18  9:19 ` [PATCH v2 7/8] media: platform: amd: isp4 debug fs logging and more descriptive errors Bin Du
2025-06-18  9:19 ` [PATCH v2 8/8] Documentation: add documentation of AMD isp 4 driver Bin Du
2025-08-05 11:37   ` Laurent Pinchart
2025-08-12  1:36     ` Du, Bin
2025-08-12 13:42       ` Laurent Pinchart
2025-08-22  2:28         ` Du, Bin
2025-08-20 12:42       ` Sakari Ailus
2025-08-22  2:20         ` Du, Bin
2025-07-23 18:12 ` [PATCH v2 0/8] Add AMD ISP4 driver Sultan Alsawaf
2025-07-25 10:22   ` Du, Bin
2025-07-26 22:31     ` Sultan Alsawaf
2025-07-29  3:32       ` Du, Bin
2025-07-29  7:42         ` Sultan Alsawaf
2025-07-29  7:45           ` Sultan Alsawaf
2025-07-29 10:13             ` Du, Bin
2025-07-30  5:38               ` Sultan Alsawaf
2025-07-30  9:53                 ` Du, Bin
2025-07-31  0:30                   ` Sultan Alsawaf
2025-07-31 10:04                     ` Du, Bin
2025-08-04  3:32                       ` Du, Bin
2025-08-04  4:25                         ` Sultan Alsawaf
2025-08-08  9:11                           ` Du, Bin
2025-08-11  5:49                             ` Sultan Alsawaf
2025-08-11  8:35                               ` Du, Bin
2025-08-11 21:48                                 ` Sultan Alsawaf
2025-08-11 22:17                                   ` Sultan Alsawaf
2025-08-12  2:02                                     ` Du, Bin
2025-08-14  6:53 ` Sultan Alsawaf
2025-08-22  2:23   ` Du, Bin
2025-08-22  3:56     ` Sultan Alsawaf
2025-08-27 10:30       ` Du, Bin
2025-08-28  5:50         ` Sultan Alsawaf
2025-09-02  2:08           ` Du, Bin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).