diff --git a/drivers/staging/media/ipu7/ipu7-fw-isys.c b/drivers/staging/media/ipu7/ipu7-fw-isys.c
new file mode 100644
index 000000000000..e4b9c364572b
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-fw-isys.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/cacheflush.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "abi/ipu7_fw_insys_config_abi.h"
+#include "abi/ipu7_fw_isys_abi.h"
+
+#include "ipu7.h"
+#include "ipu7-boot.h"
+#include "ipu7-bus.h"
+#include "ipu7-dma.h"
+#include "ipu7-fw-isys.h"
+#include "ipu7-isys.h"
+#include "ipu7-platform-regs.h"
+#include "ipu7-syscom.h"
+
+static const char * const send_msg_types[N_IPU_INSYS_SEND_TYPE] = {
+	"STREAM_OPEN",
+	"STREAM_START_AND_CAPTURE",
+	"STREAM_CAPTURE",
+	"STREAM_ABORT",
+	"STREAM_FLUSH",
+	"STREAM_CLOSE"
+};
+
+int ipu7_fw_isys_complex_cmd(struct ipu7_isys *isys,
+			     const unsigned int stream_handle,
+			     void *cpu_mapped_buf,
+			     dma_addr_t dma_mapped_buf,
+			     size_t size, u16 send_type)
+{
+	struct ipu7_syscom_context *ctx = isys->adev->syscom;
+	struct device *dev = &isys->adev->auxdev.dev;
+	struct ipu7_insys_send_queue_token *token;
+
+	if (send_type >= N_IPU_INSYS_SEND_TYPE)
+		return -EINVAL;
+
+	dev_dbg(dev, "send_token: %s\n", send_msg_types[send_type]);
+
+	/*
+	 * Time to flush cache in case we have some payload. Not all messages
+	 * have that
+	 */
+	if (cpu_mapped_buf)
+		clflush_cache_range(cpu_mapped_buf, size);
+
+	token = ipu7_syscom_get_token(ctx, stream_handle +
+				      IPU_INSYS_INPUT_MSG_QUEUE);
+	if (!token)
+		return -EBUSY;
+
+	token->addr = dma_mapped_buf;
+	token->buf_handle = (unsigned long)cpu_mapped_buf;
+	token->send_type = send_type;
+	token->stream_id = stream_handle;
+	token->flag = IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE;
+
+	ipu7_syscom_put_token(ctx, stream_handle + IPU_INSYS_INPUT_MSG_QUEUE);
+	/* now wakeup FW */
+	ipu_buttress_wakeup_is_uc(isys->adev->isp);
+
+	return 0;
+}
+
+int ipu7_fw_isys_simple_cmd(struct ipu7_isys *isys,
+			    const unsigned int stream_handle, u16 send_type)
+{
+	return ipu7_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
+					send_type);
+}
+
+int ipu7_fw_isys_init(struct ipu7_isys *isys)
+{
+	struct syscom_queue_config *queue_configs;
+	struct ipu7_bus_device *adev = isys->adev;
+	struct device *dev = &adev->auxdev.dev;
+	struct ipu7_insys_config *isys_config;
+	struct ipu7_syscom_context *syscom;
+	dma_addr_t isys_config_dma_addr;
+	unsigned int i, num_queues;
+	u32 freq;
+	u8 major;
+	int ret;
+
+	/* Allocate and init syscom context. */
+	syscom = devm_kzalloc(dev, sizeof(struct ipu7_syscom_context),
+			      GFP_KERNEL);
+	if (!syscom)
+		return -ENOMEM;
+
+	adev->syscom = syscom;
+	syscom->num_input_queues = IPU_INSYS_MAX_INPUT_QUEUES;
+	syscom->num_output_queues = IPU_INSYS_MAX_OUTPUT_QUEUES;
+	num_queues = syscom->num_input_queues + syscom->num_output_queues;
+	queue_configs = devm_kzalloc(dev, FW_QUEUE_CONFIG_SIZE(num_queues),
+				     GFP_KERNEL);
+	if (!queue_configs) {
+		ipu7_fw_isys_release(isys);
+		return -ENOMEM;
+	}
+	syscom->queue_configs = queue_configs;
+	queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].max_capacity =
+		IPU_ISYS_SIZE_RECV_QUEUE;
+	queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes =
+		sizeof(struct ipu7_insys_resp);
+	queue_configs[IPU_INSYS_OUTPUT_LOG_QUEUE].max_capacity =
+		IPU_ISYS_SIZE_LOG_QUEUE;
+	queue_configs[IPU_INSYS_OUTPUT_LOG_QUEUE].token_size_in_bytes =
+		sizeof(struct ipu7_insys_resp);
+	queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0;
+	queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0;
+
+	queue_configs[IPU_INSYS_INPUT_DEV_QUEUE].max_capacity =
+		IPU_ISYS_MAX_STREAMS;
+	queue_configs[IPU_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes =
+		sizeof(struct ipu7_insys_send_queue_token);
+
+	for (i = IPU_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
+		queue_configs[i].max_capacity = IPU_ISYS_SIZE_SEND_QUEUE;
+		queue_configs[i].token_size_in_bytes =
+			sizeof(struct ipu7_insys_send_queue_token);
+	}
+
+	/* Allocate ISYS subsys config. */
+	isys_config = ipu7_dma_alloc(adev, sizeof(struct ipu7_insys_config),
+				     &isys_config_dma_addr, GFP_KERNEL, 0);
+	if (!isys_config) {
+		dev_err(dev, "Failed to allocate isys subsys config.\n");
+		ipu7_fw_isys_release(isys);
+		return -ENOMEM;
+	}
+	isys->subsys_config = isys_config;
+	isys->subsys_config_dma_addr = isys_config_dma_addr;
+	memset(isys_config, 0, sizeof(struct ipu7_insys_config));
+	isys_config->logger_config.use_source_severity = 0;
+	isys_config->logger_config.use_channels_enable_bitmask = 1;
+	isys_config->logger_config.channels_enable_bitmask =
+		LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK;
+	isys_config->logger_config.hw_printf_buffer_base_addr = 0U;
+	isys_config->logger_config.hw_printf_buffer_size_bytes = 0U;
+	isys_config->wdt_config.wdt_timer1_us = 0;
+	isys_config->wdt_config.wdt_timer2_us = 0;
+	ret = ipu_buttress_get_isys_freq(adev->isp, &freq);
+	if (ret) {
+		dev_err(dev, "Failed to get ISYS frequency.\n");
+		ipu7_fw_isys_release(isys);
+		return ret;
+	}
+
+	ipu7_dma_sync_single(adev, isys_config_dma_addr,
+			     sizeof(struct ipu7_insys_config));
+
+	major = is_ipu8(adev->isp->hw_ver) ? 2U : 1U;
+	ret = ipu7_boot_init_boot_config(adev, queue_configs, num_queues,
+					 freq, isys_config_dma_addr, major);
+	if (ret)
+		ipu7_fw_isys_release(isys);
+
+	return ret;
+}
+
+void ipu7_fw_isys_release(struct ipu7_isys *isys)
+{
+	struct ipu7_bus_device *adev = isys->adev;
+
+	ipu7_boot_release_boot_config(adev);
+	if (isys->subsys_config) {
+		ipu7_dma_free(adev,
+			      sizeof(struct ipu7_insys_config),
+			      isys->subsys_config,
+			      isys->subsys_config_dma_addr, 0);
+		isys->subsys_config = NULL;
+		isys->subsys_config_dma_addr = 0;
+	}
+}
+
+int ipu7_fw_isys_open(struct ipu7_isys *isys)
+{
+	return ipu7_boot_start_fw(isys->adev);
+}
+
+int ipu7_fw_isys_close(struct ipu7_isys *isys)
+{
+	return ipu7_boot_stop_fw(isys->adev);
+}
+
+struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu7_isys *isys)
+{
+	return (struct ipu7_insys_resp *)
+		ipu7_syscom_get_token(isys->adev->syscom,
+				      IPU_INSYS_OUTPUT_MSG_QUEUE);
+}
+
+void ipu7_fw_isys_put_resp(struct ipu7_isys *isys)
+{
+	ipu7_syscom_put_token(isys->adev->syscom, IPU_INSYS_OUTPUT_MSG_QUEUE);
+}
+
+void ipu7_fw_isys_dump_stream_cfg(struct device *dev,
+				  struct ipu7_insys_stream_cfg *cfg)
+{
+	unsigned int i;
+
+	dev_dbg(dev, "---------------------------\n");
+	dev_dbg(dev, "IPU_FW_ISYS_STREAM_CFG_DATA\n");
+
+	dev_dbg(dev, ".port id %d\n", cfg->port_id);
+	dev_dbg(dev, ".vc %d\n", cfg->vc);
+	dev_dbg(dev, ".nof_input_pins = %d\n", cfg->nof_input_pins);
+	dev_dbg(dev, ".nof_output_pins = %d\n", cfg->nof_output_pins);
+	dev_dbg(dev, ".stream_msg_map = 0x%x\n", cfg->stream_msg_map);
+
+	for (i = 0; i < cfg->nof_input_pins; i++) {
+		dev_dbg(dev, ".input_pin[%d]:\n", i);
+		dev_dbg(dev, "\t.dt = 0x%0x\n",
+			cfg->input_pins[i].dt);
+		dev_dbg(dev, "\t.disable_mipi_unpacking = %d\n",
+			cfg->input_pins[i].disable_mipi_unpacking);
+		dev_dbg(dev, "\t.dt_rename_mode = %d\n",
+			cfg->input_pins[i].dt_rename_mode);
+		dev_dbg(dev, "\t.mapped_dt = 0x%0x\n",
+			cfg->input_pins[i].mapped_dt);
+		dev_dbg(dev, "\t.input_res = %d x %d\n",
+			cfg->input_pins[i].input_res.width,
+			cfg->input_pins[i].input_res.height);
+		dev_dbg(dev, "\t.sync_msg_map = 0x%x\n",
+			cfg->input_pins[i].sync_msg_map);
+	}
+
+	for (i = 0; i < cfg->nof_output_pins; i++) {
+		dev_dbg(dev, ".output_pin[%d]:\n", i);
+		dev_dbg(dev, "\t.input_pin_id = %d\n",
+			cfg->output_pins[i].input_pin_id);
+		dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride);
+		dev_dbg(dev, "\t.send_irq = %d\n",
+			cfg->output_pins[i].send_irq);
+		dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft);
+
+		dev_dbg(dev, "\t.link.buffer_lines = %d\n",
+			cfg->output_pins[i].link.buffer_lines);
+		dev_dbg(dev, "\t.link.foreign_key = %d\n",
+			cfg->output_pins[i].link.foreign_key);
+		dev_dbg(dev, "\t.link.granularity_pointer_update = %d\n",
+			cfg->output_pins[i].link.granularity_pointer_update);
+		dev_dbg(dev, "\t.link.msg_link_streaming_mode = %d\n",
+			cfg->output_pins[i].link.msg_link_streaming_mode);
+		dev_dbg(dev, "\t.link.pbk_id = %d\n",
+			cfg->output_pins[i].link.pbk_id);
+		dev_dbg(dev, "\t.link.pbk_slot_id = %d\n",
+			cfg->output_pins[i].link.pbk_slot_id);
+		dev_dbg(dev, "\t.link.dest = %d\n",
+			cfg->output_pins[i].link.dest);
+		dev_dbg(dev, "\t.link.use_sw_managed = %d\n",
+			cfg->output_pins[i].link.use_sw_managed);
+		dev_dbg(dev, "\t.link.is_snoop = %d\n",
+			cfg->output_pins[i].link.is_snoop);
+
+		dev_dbg(dev, "\t.crop.line_top = %d\n",
+			cfg->output_pins[i].crop.line_top);
+		dev_dbg(dev, "\t.crop.line_bottom = %d\n",
+			cfg->output_pins[i].crop.line_bottom);
+
+		dev_dbg(dev, "\t.dpcm_enable = %d\n",
+			cfg->output_pins[i].dpcm.enable);
+		dev_dbg(dev, "\t.dpcm.type = %d\n",
+			cfg->output_pins[i].dpcm.type);
+		dev_dbg(dev, "\t.dpcm.predictor = %d\n",
+			cfg->output_pins[i].dpcm.predictor);
+	}
+	dev_dbg(dev, "---------------------------\n");
+}
+
+void ipu7_fw_isys_dump_frame_buff_set(struct device *dev,
+				      struct ipu7_insys_buffset *buf,
+				      unsigned int outputs)
+{
+	unsigned int i;
+
+	dev_dbg(dev, "--------------------------\n");
+	dev_dbg(dev, "IPU_ISYS_BUFF_SET\n");
+	dev_dbg(dev, ".capture_msg_map = %d\n", buf->capture_msg_map);
+	dev_dbg(dev, ".frame_id = %d\n", buf->frame_id);
+	dev_dbg(dev, ".skip_frame = %d\n", buf->skip_frame);
+
+	for (i = 0; i < outputs; i++) {
+		dev_dbg(dev, ".output_pin[%d]:\n", i);
+		dev_dbg(dev, "\t.user_token = %llx\n",
+			buf->output_pins[i].user_token);
+		dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr);
+	}
+	dev_dbg(dev, "---------------------------\n");
+}
diff --git a/drivers/staging/media/ipu7/ipu7-fw-isys.h b/drivers/staging/media/ipu7/ipu7-fw-isys.h
new file mode 100644
index 000000000000..b556feda6b08
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-fw-isys.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_FW_ISYS_H
+#define IPU7_FW_ISYS_H
+
+#include <linux/types.h>
+
+#include "abi/ipu7_fw_isys_abi.h"
+
+struct device;
+struct ipu7_insys_buffset;
+struct ipu7_insys_stream_cfg;
+struct ipu7_isys;
+
+/* From here on type defines not coming from the ISYSAPI interface */
+
+int ipu7_fw_isys_init(struct ipu7_isys *isys);
+void ipu7_fw_isys_release(struct ipu7_isys *isys);
+int ipu7_fw_isys_open(struct ipu7_isys *isys);
+int ipu7_fw_isys_close(struct ipu7_isys *isys);
+
+void ipu7_fw_isys_dump_stream_cfg(struct device *dev,
+				  struct ipu7_insys_stream_cfg *cfg);
+void ipu7_fw_isys_dump_frame_buff_set(struct device *dev,
+				      struct ipu7_insys_buffset *buf,
+				      unsigned int outputs);
+int ipu7_fw_isys_simple_cmd(struct ipu7_isys *isys,
+			    const unsigned int stream_handle, u16 send_type);
+int ipu7_fw_isys_complex_cmd(struct ipu7_isys *isys,
+			     const unsigned int stream_handle,
+			     void *cpu_mapped_buf,
+			     dma_addr_t dma_mapped_buf,
+			     size_t size, u16 send_type);
+struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu7_isys *isys);
+void ipu7_fw_isys_put_resp(struct ipu7_isys *isys);
+#endif
diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c
new file mode 100644
index 000000000000..4407750c7f40
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c
@@ -0,0 +1,1034 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-device.h>
+
+#include "ipu7.h"
+#include "ipu7-bus.h"
+#include "ipu7-buttress.h"
+#include "ipu7-isys.h"
+#include "ipu7-isys-csi2.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-platform-regs.h"
+#include "ipu7-isys-csi-phy.h"
+
+#define PORT_A		0U
+#define PORT_B		1U
+#define PORT_C		2U
+#define PORT_D		3U
+
+#define N_DATA_IDS	8U
+static DECLARE_BITMAP(data_ids, N_DATA_IDS);
+
+struct ddlcal_counter_ref_s {
+	u16 min_mbps;
+	u16 max_mbps;
+
+	u16 ddlcal_counter_ref;
+};
+
+struct ddlcal_params {
+	u16 min_mbps;
+	u16 max_mbps;
+	u16 oa_lanex_hsrx_cdphy_sel_fast;
+	u16 ddlcal_max_phase;
+	u16 phase_bound;
+	u16 ddlcal_dll_fbk;
+	u16 ddlcal_ddl_coarse_bank;
+	u16 fjump_deskew;
+	u16 min_eye_opening_deskew;
+};
+
+struct i_thssettle_params {
+	u16 min_mbps;
+	u16 max_mbps;
+	u16 i_thssettle;
+};
+
+ /* lane2 for 4l3t, lane1 for 2l2t */
+struct oa_lane_clk_div_params {
+	u16 min_mbps;
+	u16 max_mbps;
+	u16 oa_lane_hsrx_hs_clk_div;
+};
+
+struct cdr_fbk_cap_prog_params {
+	u16 min_mbps;
+	u16 max_mbps;
+	u16 val;
+};
+
+static const struct ddlcal_counter_ref_s table0[] = {
+	{ 1500, 1999, 118 },
+	{ 2000, 2499, 157 },
+	{ 2500, 3499, 196 },
+	{ 3500, 4499, 274 },
+	{ 4500, 4500, 352 },
+	{ }
+};
+
+static const struct ddlcal_params table1[] = {
+	{ 1500, 1587, 0, 143, 167, 17, 3, 4, 29 },
+	{ 1588, 1687, 0, 135, 167, 15, 3, 4, 27 },
+	{ 1688, 1799, 0, 127, 135, 15, 2, 4, 26 },
+	{ 1800, 1928, 0, 119, 135, 13, 2, 3, 24 },
+	{ 1929, 2076, 0, 111, 135, 13, 2, 3, 23 },
+	{ 2077, 2249, 0, 103, 135, 11, 2, 3, 21 },
+	{ 2250, 2454, 0, 95, 103, 11, 1, 3, 19 },
+	{ 2455, 2699, 0, 87, 103, 9, 1, 3, 18 },
+	{ 2700, 2999, 0, 79, 103, 9, 1, 2, 16 },
+	{ 3000, 3229, 0, 71, 71, 7, 1, 2, 15 },
+	{ 3230, 3599, 1, 87, 103, 9, 1, 3, 18 },
+	{ 3600, 3999, 1, 79, 103, 9, 1, 2, 16 },
+	{ 4000, 4499, 1, 71, 103, 7, 1, 2, 15 },
+	{ 4500, 4500, 1, 63, 71, 7, 0, 2, 13 },
+	{ }
+};
+
+static const struct i_thssettle_params table2[] = {
+	{ 80, 124, 24 },
+	{ 125, 249, 20 },
+	{ 250, 499, 16 },
+	{ 500, 749, 14 },
+	{ 750, 1499, 13 },
+	{ 1500, 4500, 12 },
+	{ }
+};
+
+static const struct oa_lane_clk_div_params table6[] = {
+	{ 80, 159, 0x1 },
+	{ 160, 319, 0x2 },
+	{ 320, 639, 0x3 },
+	{ 640, 1279, 0x4 },
+	{ 1280, 2560, 0x5 },
+	{ 2561, 4500, 0x6 },
+	{ }
+};
+
+static const struct cdr_fbk_cap_prog_params table7[] = {
+	{ 80, 919, 0 },
+	{ 920, 1029, 1 },
+	{ 1030, 1169, 2 },
+	{ 1170, 1349, 3 },
+	{ 1350, 1589, 4 },
+	{ 1590, 1949, 5 },
+	{ 1950, 2499, 6 },
+	{ }
+};
+
+static void dwc_phy_write(struct ipu7_isys *isys, u32 id, u32 addr, u16 data)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id);
+
+	dev_dbg(&isys->adev->auxdev.dev, "phy write: reg 0x%zx = data 0x%04x",
+		base + addr - isys_base, data);
+	writew(data, base + addr);
+}
+
+static u16 dwc_phy_read(struct ipu7_isys *isys, u32 id, u32 addr)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id);
+	u16 data;
+
+	data = readw(base + addr);
+	dev_dbg(&isys->adev->auxdev.dev, "phy read: reg 0x%zx = data 0x%04x",
+		base + addr - isys_base, data);
+
+	return data;
+}
+
+static void dwc_csi_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id);
+	struct device *dev = &isys->adev->auxdev.dev;
+
+	dev_dbg(dev, "csi write: reg 0x%zx = data 0x%08x",
+		base + addr - isys_base, data);
+	writel(data, base + addr);
+	dev_dbg(dev, "csi read: reg 0x%zx = data 0x%08x",
+		base + addr - isys_base, readl(base + addr));
+}
+
+static void gpreg_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	u32 gpreg = isys->pdata->ipdata->csi2.gpreg;
+	void __iomem *base = isys_base + gpreg + 0x1000 * id;
+	struct device *dev = &isys->adev->auxdev.dev;
+
+	dev_dbg(dev, "gpreg write: reg 0x%zx = data 0x%08x",
+		base + addr - isys_base, data);
+	writel(data, base + addr);
+	dev_dbg(dev, "gpreg read: reg 0x%zx = data 0x%08x",
+		base + addr - isys_base, readl(base + addr));
+}
+
+static u32 dwc_csi_read(struct ipu7_isys *isys, u32 id, u32 addr)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id);
+	u32 data;
+
+	data = readl(base + addr);
+	dev_dbg(&isys->adev->auxdev.dev, "csi read: reg 0x%zx = data 0x%x",
+		base + addr - isys_base, data);
+
+	return data;
+}
+
+static void dwc_phy_write_mask(struct ipu7_isys *isys, u32 id, u32 addr,
+			       u16 val, u8 lo, u8 hi)
+{
+	u32 temp, mask;
+
+	WARN_ON(lo > hi);
+	WARN_ON(hi > 15);
+
+	mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
+	temp = dwc_phy_read(isys, id, addr);
+	temp &= ~mask;
+	temp |= (val << lo) & mask;
+	dwc_phy_write(isys, id, addr, temp);
+}
+
+static void dwc_csi_write_mask(struct ipu7_isys *isys, u32 id, u32 addr,
+			       u32 val, u8 hi, u8 lo)
+{
+	u32 temp, mask;
+
+	WARN_ON(lo > hi);
+
+	mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
+	temp = dwc_csi_read(isys, id, addr);
+	temp &= ~mask;
+	temp |= (val << lo) & mask;
+	dwc_csi_write(isys, id, addr, temp);
+}
+
+static void ipu7_isys_csi_ctrl_cfg(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_isys *isys = csi2->isys;
+	struct device *dev = &isys->adev->auxdev.dev;
+	u32 id, lanes, phy_mode;
+	u32 val;
+
+	id = csi2->port;
+	lanes = csi2->nlanes;
+	phy_mode = csi2->phy_mode;
+	dev_dbg(dev, "csi-%d controller init with %u lanes, phy mode %u",
+		id, lanes, phy_mode);
+
+	val = dwc_csi_read(isys, id, VERSION);
+	dev_dbg(dev, "csi-%d controller version = 0x%x", id, val);
+
+	/* num of active data lanes */
+	dwc_csi_write(isys, id, N_LANES, lanes - 1);
+	dwc_csi_write(isys, id, CDPHY_MODE, phy_mode);
+	dwc_csi_write(isys, id, VC_EXTENSION, 0);
+
+	/* only mask PHY_FATAL and PKT_FATAL interrupts */
+	dwc_csi_write(isys, id, INT_MSK_PHY_FATAL, 0xff);
+	dwc_csi_write(isys, id, INT_MSK_PKT_FATAL, 0x3);
+	dwc_csi_write(isys, id, INT_MSK_PHY, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_LINE, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_BNDRY_FRAME_FATAL, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_SEQ_FRAME_FATAL, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_CRC_FRAME_FATAL, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_PLD_CRC_FATAL, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_DATA_ID, 0x0);
+	dwc_csi_write(isys, id, INT_MSK_ECC_CORRECTED, 0x0);
+}
+
+static void ipu7_isys_csi_phy_reset(struct ipu7_isys *isys, u32 id)
+{
+	dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 0);
+	dwc_csi_write(isys, id, DPHY_RSTZ, 0);
+	dwc_csi_write(isys, id, CSI2_RESETN, 0);
+	gpreg_write(isys, id, PHY_RESET, 0);
+	gpreg_write(isys, id, PHY_SHUTDOWN, 0);
+}
+
+/* 8 Data ID monitors, each Data ID is composed by pair of VC and data type */
+static int __dids_config(struct ipu7_isys_csi2 *csi2, u32 id, u8 vc, u8 dt)
+{
+	struct ipu7_isys *isys = csi2->isys;
+	u32 reg, n;
+	u8 lo, hi;
+	int ret;
+
+	dev_dbg(&isys->adev->auxdev.dev, "config CSI-%u with vc:%u dt:0x%02x\n",
+		id, vc, dt);
+
+	dwc_csi_write(isys, id, VC_EXTENSION, 0x0);
+	n = find_first_zero_bit(data_ids, N_DATA_IDS);
+	if (n == N_DATA_IDS)
+		return -ENOSPC;
+
+	ret = test_and_set_bit(n, data_ids);
+	if (ret)
+		return -EBUSY;
+
+	reg = n < 4 ? DATA_IDS_VC_1 : DATA_IDS_VC_2;
+	lo = (n % 4) * 8;
+	hi = lo + 4;
+	dwc_csi_write_mask(isys, id, reg, vc & GENMASK(4, 0), hi, lo);
+
+	reg = n < 4 ? DATA_IDS_1 : DATA_IDS_2;
+	lo = (n % 4) * 8;
+	hi = lo + 5;
+	dwc_csi_write_mask(isys, id, reg, dt & GENMASK(5, 0), hi, lo);
+
+	return 0;
+}
+
+static int ipu7_isys_csi_ctrl_dids_config(struct ipu7_isys_csi2 *csi2, u32 id)
+{
+	struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
+	struct device *dev = &csi2->isys->adev->auxdev.dev;
+	struct v4l2_mbus_frame_desc desc;
+	struct v4l2_subdev *ext_sd;
+	struct media_pad *pad;
+	unsigned int i;
+	int ret;
+
+	pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
+	if (IS_ERR(pad)) {
+		dev_warn(dev, "can't get remote source pad of %s (%ld)\n",
+			 csi2->asd.sd.name, PTR_ERR(pad));
+		return PTR_ERR(pad);
+	}
+
+	ext_sd = media_entity_to_v4l2_subdev(pad->entity);
+	if (WARN(!ext_sd, "Failed to get subdev for entity %s\n",
+		 pad->entity->name))
+		return -ENODEV;
+
+	ret = v4l2_subdev_call(ext_sd, pad, get_frame_desc, pad->index, &desc);
+	if (ret)
+		return ret;
+
+	if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		dev_warn(dev, "Unsupported frame descriptor type\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < desc.num_entries; i++) {
+		desc_entry = &desc.entry[i];
+		if (desc_entry->bus.csi2.vc < IPU7_NR_OF_CSI2_VC) {
+			ret = __dids_config(csi2, id, desc_entry->bus.csi2.vc,
+					    desc_entry->bus.csi2.dt);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+#define CDPHY_TIMEOUT 5000000U
+static int ipu7_isys_phy_ready(struct ipu7_isys *isys, u32 id)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	u32 gpreg_offset = isys->pdata->ipdata->csi2.gpreg;
+	void __iomem *gpreg = isys_base + gpreg_offset + 0x1000 * id;
+	struct device *dev = &isys->adev->auxdev.dev;
+	unsigned int i;
+	u32 phy_ready;
+	u32 reg, rext;
+	int ret;
+
+	dev_dbg(dev, "waiting phy ready...\n");
+	ret = readl_poll_timeout(gpreg + PHY_READY, phy_ready,
+				 phy_ready & BIT(0) && phy_ready != ~0U,
+				 100, CDPHY_TIMEOUT);
+	dev_dbg(dev, "phy %u ready = 0x%08x\n", id, readl(gpreg + PHY_READY));
+	dev_dbg(dev, "csi %u PHY_RX = 0x%08x\n", id,
+		dwc_csi_read(isys, id, PHY_RX));
+	dev_dbg(dev, "csi %u PHY_STOPSTATE = 0x%08x\n", id,
+		dwc_csi_read(isys, id, PHY_STOPSTATE));
+	dev_dbg(dev, "csi %u PHY_CAL = 0x%08x\n", id,
+		dwc_csi_read(isys, id, PHY_CAL));
+	for (i = 0; i < 4U; i++) {
+		reg = CORE_DIG_DLANE_0_R_HS_RX_0 + (i * 0x400U);
+		dev_dbg(dev, "phy %u DLANE%u skewcal = 0x%04x\n",
+			id, i, dwc_phy_read(isys, id, reg));
+	}
+	dev_dbg(dev, "phy %u DDLCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5));
+	dev_dbg(dev, "phy %u TERMCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, PPI_R_TERMCAL_DEBUG_0));
+	dev_dbg(dev, "phy %u LPDCOCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_RB));
+	dev_dbg(dev, "phy %u HSDCOCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, PPI_R_HSDCOCAL_DEBUG_RB));
+	dev_dbg(dev, "phy %u LPDCOCAL_VT = 0x%04x\n", id,
+		dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_VT));
+
+	if (!ret) {
+		if (id) {
+			dev_dbg(dev, "ignore phy %u rext\n", id);
+			return 0;
+		}
+
+		rext = dwc_phy_read(isys, id,
+				    CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15) & 0xfU;
+		dev_dbg(dev, "phy %u rext value = %u\n", id, rext);
+		isys->phy_rext_cal = (rext ? rext : 5);
+
+		return 0;
+	}
+
+	dev_err(dev, "wait phy ready timeout!\n");
+
+	return ret;
+}
+
+static int lookup_table1(u64 mbps)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(table1); i++) {
+		if (mbps >= table1[i].min_mbps && mbps <= table1[i].max_mbps)
+			return i;
+	}
+
+	return -ENXIO;
+}
+
+static const u16 deskew_fine_mem[] = {
+	0x0404, 0x040c, 0x0414, 0x041c,
+	0x0423, 0x0429, 0x0430, 0x043a,
+	0x0445, 0x044a, 0x0450, 0x045a,
+	0x0465, 0x0469, 0x0472, 0x047a,
+	0x0485, 0x0489, 0x0490, 0x049a,
+	0x04a4, 0x04ac, 0x04b4, 0x04bc,
+	0x04c4, 0x04cc, 0x04d4, 0x04dc,
+	0x04e4, 0x04ec, 0x04f4, 0x04fc,
+	0x0504, 0x050c, 0x0514, 0x051c,
+	0x0523, 0x0529, 0x0530, 0x053a,
+	0x0545, 0x054a, 0x0550, 0x055a,
+	0x0565, 0x0569, 0x0572, 0x057a,
+	0x0585, 0x0589, 0x0590, 0x059a,
+	0x05a4, 0x05ac, 0x05b4, 0x05bc,
+	0x05c4, 0x05cc, 0x05d4, 0x05dc,
+	0x05e4, 0x05ec, 0x05f4, 0x05fc,
+	0x0604, 0x060c, 0x0614, 0x061c,
+	0x0623, 0x0629, 0x0632, 0x063a,
+	0x0645, 0x064a, 0x0650, 0x065a,
+	0x0665, 0x0669, 0x0672, 0x067a,
+	0x0685, 0x0689, 0x0690, 0x069a,
+	0x06a4, 0x06ac, 0x06b4, 0x06bc,
+	0x06c4, 0x06cc, 0x06d4, 0x06dc,
+	0x06e4, 0x06ec, 0x06f4, 0x06fc,
+	0x0704, 0x070c, 0x0714, 0x071c,
+	0x0723, 0x072a, 0x0730, 0x073a,
+	0x0745, 0x074a, 0x0750, 0x075a,
+	0x0765, 0x0769, 0x0772, 0x077a,
+	0x0785, 0x0789, 0x0790, 0x079a,
+	0x07a4, 0x07ac, 0x07b4, 0x07bc,
+	0x07c4, 0x07cc, 0x07d4, 0x07dc,
+	0x07e4, 0x07ec, 0x07f4, 0x07fc,
+};
+
+static void ipu7_isys_dphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
+				  bool aggregation, u64 mbps)
+{
+	u16 hsrxval0 = 0;
+	u16 hsrxval1 = 0;
+	u16 hsrxval2 = 0;
+	int index;
+	u16 reg;
+	u16 val;
+	u32 i;
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, 0, 0, 9);
+	if (mbps > 1500)
+		dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7,
+				   40, 0, 7);
+	else
+		dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7,
+				   104, 0, 7);
+
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 80, 0, 7);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_0, 191, 0, 9);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 34, 7, 12);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1, 38, 8, 15);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 4, 12, 15);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 2, 10, 11);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 8, 8);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 38, 0, 7);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 9, 9);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_4, 10, 0, 9);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_6, 20, 0, 9);
+	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 19, 0, 6);
+
+	for (i = 0; i < ARRAY_SIZE(table0); i++) {
+		if (mbps >= table0[i].min_mbps && mbps <= table0[i].max_mbps) {
+			dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_3,
+					   table0[i].ddlcal_counter_ref,
+					   0, 9);
+			break;
+		}
+	}
+
+	index = lookup_table1(mbps);
+	if (index >= 0) {
+		dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1,
+				   table1[index].phase_bound, 0, 7);
+		dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5,
+				   table1[index].ddlcal_dll_fbk, 4, 9);
+		dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5,
+				   table1[index].ddlcal_ddl_coarse_bank, 0, 3);
+
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8;
+		val = table1[index].oa_lanex_hsrx_cdphy_sel_fast;
+		for (i = 0; i < lanes + 1; i++)
+			dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
+					   12, 12);
+	}
+
+	reg = CORE_DIG_DLANE_0_RW_LP_0;
+	for (i = 0; i < lanes; i++)
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2,
+			   0, 0, 0);
+	if (!is_ipu7(isys->adev->isp->hw_ver) ||
+	    id == PORT_B || id == PORT_C) {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
+				   1, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
+				   0, 0, 0);
+	} else {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
+				   0, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
+				   1, 0, 0);
+	}
+
+	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
+				   0, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
+				   0, 0, 0);
+	}
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 0, 2);
+	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 3, 5);
+
+	reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12;
+	val = (mbps > 1500) ? 0 : 1;
+	for (i = 0; i < lanes + 1; i++) {
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), !val, 3, 3);
+	}
+
+	reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13;
+	val = (mbps > 1500) ? 0 : 1;
+	for (i = 0; i < lanes + 1; i++) {
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 3, 3);
+	}
+
+	if (!is_ipu7(isys->adev->isp->hw_ver) || id == PORT_B || id == PORT_C)
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9;
+	else
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9;
+
+	for (i = 0; i < ARRAY_SIZE(table6); i++) {
+		if (mbps >= table6[i].min_mbps && mbps <= table6[i].max_mbps) {
+			dwc_phy_write_mask(isys, id, reg,
+					   table6[i].oa_lane_hsrx_hs_clk_div,
+					   5, 7);
+			break;
+		}
+	}
+
+	if (aggregation) {
+		dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_0, 1,
+				   1, 1);
+
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15;
+		dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
+
+		val = (id == PORT_A) ? 3 : 0;
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15;
+		dwc_phy_write_mask(isys, id, reg, val, 3, 4);
+
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15;
+		dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
+	}
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_0, 28, 0, 7);
+	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_7, 6, 0, 7);
+
+	reg = CORE_DIG_DLANE_0_RW_HS_RX_0;
+	for (i = 0; i < ARRAY_SIZE(table2); i++) {
+		if (mbps >= table2[i].min_mbps && mbps <= table2[i].max_mbps) {
+			u8 j;
+
+			for (j = 0; j < lanes; j++)
+				dwc_phy_write_mask(isys, id, reg + (j * 0x400),
+						   table2[i].i_thssettle,
+						   8, 15);
+			break;
+		}
+	}
+
+	/* deskew */
+	for (i = 0; i < lanes; i++) {
+		reg = CORE_DIG_DLANE_0_RW_CFG_1;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+				   ((mbps > 1500) ? 0x1 : 0x2), 2, 3);
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_2;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+				   ((mbps > 2500) ? 0 : 1), 15, 15);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 13, 13);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 7, 9, 12);
+
+		reg = CORE_DIG_DLANE_0_RW_LP_0;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 12, 15);
+
+		reg = CORE_DIG_DLANE_0_RW_LP_2;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 0);
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_1;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 16, 0, 7);
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_3;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 2);
+		index = lookup_table1(mbps);
+		if (index >= 0) {
+			val = table1[index].fjump_deskew;
+			dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
+					   3, 8);
+		}
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_4;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 150, 0, 15);
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_5;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 7);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 8, 15);
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_6;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 7);
+		index = lookup_table1(mbps);
+		if (index >= 0) {
+			val = table1[index].min_eye_opening_deskew;
+			dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
+					   8, 15);
+		}
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_7;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 13, 13);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 15, 15);
+
+		reg = CORE_DIG_DLANE_0_RW_HS_RX_9;
+		index = lookup_table1(mbps);
+		if (index >= 0) {
+			val = table1[index].ddlcal_max_phase;
+			dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+					   val, 0, 7);
+		}
+	}
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_0, 1, 12, 15);
+	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_2, 0, 0, 0);
+
+	for (i = 0; i < ARRAY_SIZE(deskew_fine_mem); i++)
+		dwc_phy_write_mask(isys, id, CORE_DIG_COMMON_RW_DESKEW_FINE_MEM,
+				   deskew_fine_mem[i], 0, 15);
+
+	if (mbps > 1500) {
+		hsrxval0 = 4;
+		hsrxval2 = 3;
+	}
+
+	if (mbps > 2500)
+		hsrxval1 = 2;
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
+			   hsrxval0, 0, 2);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
+			   hsrxval0, 0, 2);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
+			   hsrxval0, 0, 2);
+	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
+				   hsrxval0, 0, 2);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
+				   hsrxval0, 0, 2);
+	}
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
+			   hsrxval1, 3, 4);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
+			   hsrxval1, 3, 4);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
+			   hsrxval1, 3, 4);
+	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
+				   hsrxval1, 3, 4);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
+				   hsrxval1, 3, 4);
+	}
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15,
+			   hsrxval2, 0, 2);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15,
+			   hsrxval2, 0, 2);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15,
+			   hsrxval2, 0, 2);
+	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15,
+				   hsrxval2, 0, 2);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15,
+				   hsrxval2, 0, 2);
+	}
+
+	/* force and override rext */
+	if (isys->phy_rext_cal && id) {
+		dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8,
+				   isys->phy_rext_cal, 0, 3);
+		dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
+				   1, 11, 11);
+	}
+}
+
+static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
+				  bool aggregation, u64 mbps)
+{
+	u8 trios = 2;
+	u16 coarse_target;
+	u16 deass_thresh;
+	u16 delay_thresh;
+	u16 reset_thresh;
+	u16 cap_prog = 6U;
+	u16 reg;
+	u16 val;
+	u32 i;
+	u32 r;
+
+	if (is_ipu7p5(isys->adev->isp->hw_ver))
+		val = 0x15;
+	else
+		val = 0x155;
+
+	if (is_ipu7(isys->adev->isp->hw_ver))
+		trios = 3;
+
+	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, val, 0, 9);
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, 104, 0, 7);
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 16, 0, 7);
+
+	reg = CORE_DIG_CLANE_0_RW_LP_0;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
+
+	val = (mbps > 900U) ? 1U : 0U;
+	for (i = 0; i < trios; i++) {
+		reg = CORE_DIG_CLANE_0_RW_HS_RX_0;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 0, 0);
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
+
+		reg = CORE_DIG_CLANE_0_RW_HS_RX_1;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
+
+		reg = CORE_DIG_CLANE_0_RW_HS_RX_5;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
+
+		reg = CORE_DIG_CLANE_0_RW_HS_RX_6;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 10, 0, 15);
+	}
+
+	/*
+	 * Below 900Msps, always use the same value.
+	 * The formula is suitable for data rate 80-3500Msps.
+	 * Timebase (us) = 1, DIV = 32, TDDL (UI) = 0.5
+	 */
+	if (mbps >= 80U)
+		coarse_target = DIV_ROUND_UP_ULL(mbps, 16) - 1;
+	else
+		coarse_target = 56;
+
+	for (i = 0; i < trios; i++) {
+		reg = CORE_DIG_CLANE_0_RW_HS_RX_2 + i * 0x400;
+		dwc_phy_write_mask(isys, id, reg, coarse_target, 0, 15);
+	}
+
+	dwc_phy_write_mask(isys, id,
+			   CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, 1, 0, 0);
+	dwc_phy_write_mask(isys, id,
+			   CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, 0, 0, 0);
+	dwc_phy_write_mask(isys, id,
+			   CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, 1, 0, 0);
+
+	if (!is_ipu7p5(isys->adev->isp->hw_ver) && lanes == 4) {
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
+				   1, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
+				   0, 0, 0);
+	}
+
+	for (i = 0; i < trios; i++) {
+		reg = CORE_DIG_RW_TRIO0_0 + i * 0x400;
+		dwc_phy_write_mask(isys, id, reg, 1, 6, 8);
+		dwc_phy_write_mask(isys, id, reg, 1, 3, 5);
+		dwc_phy_write_mask(isys, id, reg, 2, 0, 2);
+	}
+
+	deass_thresh = (u16)div_u64_rem(7 * 1000 * 6, mbps * 5U, &r) + 1;
+	if (r != 0)
+		deass_thresh++;
+
+	reg = CORE_DIG_RW_TRIO0_2;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+				   deass_thresh, 0, 7);
+
+	delay_thresh =
+		((224U - (9U * 7U)) * 1000U) / (5U * mbps) - 7U;
+
+	if (delay_thresh < 1)
+		delay_thresh = 1;
+
+	reg = CORE_DIG_RW_TRIO0_1;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+				   delay_thresh, 0, 15);
+
+	reset_thresh = (u16)div_u64_rem(2U * 5U * mbps, 7U * 1000U, &r);
+	if (!r)
+		reset_thresh--;
+
+	if (reset_thresh < 1)
+		reset_thresh = 1;
+
+	reg = CORE_DIG_RW_TRIO0_0;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+				   reset_thresh, 9, 11);
+
+	reg = CORE_DIG_CLANE_0_RW_LP_0;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 1, 12, 15);
+
+	reg = CORE_DIG_CLANE_0_RW_LP_2;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 0, 0, 0);
+
+	reg = CORE_DIG_CLANE_0_RW_HS_RX_0;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 12, 2, 6);
+
+	for (i = 0; i < ARRAY_SIZE(table7); i++) {
+		if (mbps >= table7[i].min_mbps && mbps <= table7[i].max_mbps) {
+			cap_prog = table7[i].val;
+			break;
+		}
+	}
+
+	for (i = 0; i < (lanes + 1); i++) {
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 + 0x400 * i;
+		dwc_phy_write_mask(isys, id, reg, 4U, 0, 2);
+		dwc_phy_write_mask(isys, id, reg, 0U, 3, 4);
+
+		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 + 0x400 * i;
+		dwc_phy_write_mask(isys, id, reg, cap_prog, 10, 12);
+	}
+}
+
+static int ipu7_isys_phy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
+				bool aggregation)
+{
+	struct device *dev = &isys->adev->auxdev.dev;
+	u32 phy_mode;
+	s64 link_freq;
+	u64 mbps;
+
+	if (aggregation)
+		link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[0]);
+	else
+		link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[id]);
+
+	if (link_freq < 0) {
+		dev_err(dev, "get link freq failed (%lld)\n", link_freq);
+		return link_freq;
+	}
+
+	mbps = div_u64(link_freq, 500000);
+	dev_dbg(dev, "config phy %u with lanes %u aggregation %d mbps %lld\n",
+		id, lanes, aggregation, mbps);
+
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_10, 48, 0, 7);
+	dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2,
+			   1, 12, 13);
+	dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0,
+			   63, 2, 7);
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_STARTUP_1_1,
+			   563, 0, 11);
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 5, 0, 7);
+	/* bypass the RCAL state (bit6) */
+	if (aggregation && id != PORT_A)
+		dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 0x45,
+				   0, 7);
+
+	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_6, 39, 0, 7);
+	dwc_phy_write_mask(isys, id, PPI_CALIBCTRL_RW_COMMON_BG_0, 500, 0, 8);
+	dwc_phy_write_mask(isys, id, PPI_RW_TERMCAL_CFG_0, 38, 0, 6);
+	dwc_phy_write_mask(isys, id, PPI_RW_OFFSETCAL_CFG_0, 7, 0, 4);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TIMEBASE, 153, 0, 9);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF, 800, 0, 10);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF_RANGE, 27, 0, 4);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 47, 0, 8);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 127, 9, 15);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 47, 7, 15);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 27, 2, 6);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 3, 0, 1);
+	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_COARSE_CFG, 1, 0, 1);
+	dwc_phy_write_mask(isys, id, PPI_RW_COMMON_CFG, 3, 0, 1);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
+			   0, 10, 10);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
+			   1, 10, 10);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
+			   0, 15, 15);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3,
+			   3, 8, 9);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
+			   0, 15, 15);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6,
+			   7, 12, 14);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
+			   0, 8, 10);
+	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5,
+			   0, 8, 8);
+
+	if (aggregation)
+		phy_mode = isys->csi2[0].phy_mode;
+	else
+		phy_mode = isys->csi2[id].phy_mode;
+
+	if (phy_mode == PHY_MODE_DPHY) {
+		ipu7_isys_dphy_config(isys, id, lanes, aggregation, mbps);
+	} else if (phy_mode == PHY_MODE_CPHY) {
+		ipu7_isys_cphy_config(isys, id, lanes, aggregation, mbps);
+	} else {
+		dev_err(dev, "unsupported phy mode %d!\n",
+			isys->csi2[id].phy_mode);
+	}
+
+	return 0;
+}
+
+int ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_isys *isys = csi2->isys;
+	u32 lanes = csi2->nlanes;
+	bool aggregation = false;
+	u32 id = csi2->port;
+	int ret;
+
+	/* lanes remapping for aggregation (port AB) mode */
+	if (!is_ipu7(isys->adev->isp->hw_ver) && lanes > 2 && id == PORT_A) {
+		aggregation = true;
+		lanes = 2;
+	}
+
+	ipu7_isys_csi_phy_reset(isys, id);
+	gpreg_write(isys, id, PHY_CLK_LANE_CONTROL, 0x1);
+	gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0x2);
+	gpreg_write(isys, id, PHY_LANE_CONTROL_EN, (1U << lanes) - 1U);
+	gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0xf);
+	gpreg_write(isys, id, PHY_MODE, csi2->phy_mode);
+
+	/* config PORT_B if aggregation mode */
+	if (aggregation) {
+		ipu7_isys_csi_phy_reset(isys, PORT_B);
+		gpreg_write(isys, PORT_B, PHY_CLK_LANE_CONTROL, 0x0);
+		gpreg_write(isys, PORT_B, PHY_LANE_CONTROL_EN, 0x3);
+		gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0x2);
+		gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0xf);
+		gpreg_write(isys, PORT_B, PHY_MODE, csi2->phy_mode);
+	}
+
+	ipu7_isys_csi_ctrl_cfg(csi2);
+	ipu7_isys_csi_ctrl_dids_config(csi2, id);
+
+	ret = ipu7_isys_phy_config(isys, id, lanes, aggregation);
+	if (ret < 0)
+		return ret;
+
+	gpreg_write(isys, id, PHY_RESET, 1);
+	gpreg_write(isys, id, PHY_SHUTDOWN, 1);
+	dwc_csi_write(isys, id, DPHY_RSTZ, 1);
+	dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 1);
+	dwc_csi_write(isys, id, CSI2_RESETN, 1);
+
+	ret = ipu7_isys_phy_ready(isys, id);
+	if (ret < 0)
+		return ret;
+
+	gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0);
+	gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0);
+
+	/* config PORT_B if aggregation mode */
+	if (aggregation) {
+		ret = ipu7_isys_phy_config(isys, PORT_B, 2, aggregation);
+		if (ret < 0)
+			return ret;
+
+		gpreg_write(isys, PORT_B, PHY_RESET, 1);
+		gpreg_write(isys, PORT_B, PHY_SHUTDOWN, 1);
+		dwc_csi_write(isys, PORT_B, DPHY_RSTZ, 1);
+		dwc_csi_write(isys, PORT_B, PHY_SHUTDOWNZ, 1);
+		dwc_csi_write(isys, PORT_B, CSI2_RESETN, 1);
+		ret = ipu7_isys_phy_ready(isys, PORT_B);
+		if (ret < 0)
+			return ret;
+
+		gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0);
+		gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0);
+	}
+
+	return 0;
+}
+
+void ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_isys *isys = csi2->isys;
+
+	ipu7_isys_csi_phy_reset(isys, csi2->port);
+	if (!is_ipu7(isys->adev->isp->hw_ver) &&
+	    csi2->nlanes > 2U && csi2->port == PORT_A)
+		ipu7_isys_csi_phy_reset(isys, PORT_B);
+}
diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi-phy.h b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.h
new file mode 100644
index 000000000000..dfdcb61540c4
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_CSI_PHY_H
+#define IPU7_ISYS_CSI_PHY_H
+
+struct ipu7_isys;
+
+#define PHY_MODE_DPHY		0U
+#define PHY_MODE_CPHY		1U
+
+int ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 *csi2);
+void ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 *csi2);
+#endif
diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi2-regs.h b/drivers/staging/media/ipu7/ipu7-isys-csi2-regs.h
new file mode 100644
index 000000000000..aad52c44a005
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-csi2-regs.h
@@ -0,0 +1,1197 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_CSI2_REG_H
+#define IPU7_ISYS_CSI2_REG_H
+
+/* IS main regs base */
+#define IS_MAIN_BASE				0x240000
+#define IS_MAIN_S2B_BASE			(IS_MAIN_BASE + 0x22000)
+#define IS_MAIN_B2O_BASE			(IS_MAIN_BASE + 0x26000)
+#define IS_MAIN_ISD_M0_BASE			(IS_MAIN_BASE + 0x2b000)
+#define IS_MAIN_ISD_M1_BASE			(IS_MAIN_BASE + 0x2b100)
+#define IS_MAIN_ISD_INT_BASE			(IS_MAIN_BASE + 0x2b200)
+#define IS_MAIN_GDA_BASE			(IS_MAIN_BASE + 0x32000)
+#define IS_MAIN_GPREGS_MAIN_BASE		(IS_MAIN_BASE + 0x32500)
+#define IS_MAIN_IRQ_CTRL_BASE			(IS_MAIN_BASE + 0x32700)
+#define IS_MAIN_PWM_CTRL_BASE			(IS_MAIN_BASE + 0x32b00)
+
+#define S2B_IRQ_COMMON_0_CTL_STATUS		(IS_MAIN_S2B_BASE + 0x1c)
+#define S2B_IRQ_COMMON_0_CTL_CLEAR		(IS_MAIN_S2B_BASE + 0x20)
+#define S2B_IRQ_COMMON_0_CTL_ENABLE		(IS_MAIN_S2B_BASE + 0x24)
+#define S2B_IID_IRQ_CTL_STATUS(iid)		(IS_MAIN_S2B_BASE + 0x94 + \
+						 0x100 * (iid))
+
+#define B2O_IRQ_COMMON_0_CTL_STATUS		(IS_MAIN_B2O_BASE + 0x30)
+#define B2O_IRQ_COMMON_0_CTL_CLEAR		(IS_MAIN_B2O_BASE + 0x34)
+#define B2O_IRQ_COMMON_0_CTL_ENABLE		(IS_MAIN_B2O_BASE + 0x38)
+#define B2O_IID_IRQ_CTL_STATUS(oid)		(IS_MAIN_B2O_BASE + 0x3dc + \
+						 0x200 * (oid))
+
+#define ISD_M0_IRQ_CTL_STATUS			(IS_MAIN_ISD_M0_BASE + 0x1c)
+#define ISD_M0_IRQ_CTL_CLEAR			(IS_MAIN_ISD_M0_BASE + 0x20)
+#define ISD_M0_IRQ_CTL_ENABLE			(IS_MAIN_ISD_M0_BASE + 0x24)
+
+#define ISD_M1_IRQ_CTL_STATUS			(IS_MAIN_ISD_M1_BASE + 0x1c)
+#define ISD_M1_IRQ_CTL_CLEAR			(IS_MAIN_ISD_M1_BASE + 0x20)
+#define ISD_M1_IRQ_CTL_ENABLE			(IS_MAIN_ISD_M1_BASE + 0x24)
+
+#define ISD_INT_IRQ_CTL_STATUS			(IS_MAIN_ISD_INT_BASE + 0x1c)
+#define ISD_INT_IRQ_CTL_CLEAR			(IS_MAIN_ISD_INT_BASE + 0x20)
+#define ISD_INT_IRQ_CTL_ENABLE			(IS_MAIN_ISD_INT_BASE + 0x24)
+
+#define GDA_IRQ_CTL_STATUS			(IS_MAIN_GDA_BASE + 0x1c)
+#define GDA_IRQ_CTL_CLEAR			(IS_MAIN_GDA_BASE + 0x20)
+#define GDA_IRQ_CTL_ENABLE			(IS_MAIN_GDA_BASE + 0x24)
+
+#define IS_MAIN_IRQ_CTL_EDGE			IS_MAIN_IRQ_CTRL_BASE
+#define IS_MAIN_IRQ_CTL_MASK			(IS_MAIN_IRQ_CTRL_BASE + 0x4)
+#define IS_MAIN_IRQ_CTL_STATUS			(IS_MAIN_IRQ_CTRL_BASE + 0x8)
+#define IS_MAIN_IRQ_CTL_CLEAR			(IS_MAIN_IRQ_CTRL_BASE + 0xc)
+#define IS_MAIN_IRQ_CTL_ENABLE			(IS_MAIN_IRQ_CTRL_BASE + 0x10)
+#define IS_MAIN_IRQ_CTL_LEVEL_NOT_PULSE		(IS_MAIN_IRQ_CTRL_BASE + 0x14)
+
+/* IS IO regs base */
+#define IS_PHY_NUM				4U
+#define IS_IO_BASE				0x280000
+
+/* dwc csi cdphy registers */
+#define IS_IO_CDPHY_BASE(i)			(IS_IO_BASE + 0x10000 * (i))
+#define PPI_STARTUP_RW_COMMON_DPHY_0			0x1800
+#define PPI_STARTUP_RW_COMMON_DPHY_1			0x1802
+#define PPI_STARTUP_RW_COMMON_DPHY_2			0x1804
+#define PPI_STARTUP_RW_COMMON_DPHY_3			0x1806
+#define PPI_STARTUP_RW_COMMON_DPHY_4			0x1808
+#define PPI_STARTUP_RW_COMMON_DPHY_5			0x180a
+#define PPI_STARTUP_RW_COMMON_DPHY_6			0x180c
+#define PPI_STARTUP_RW_COMMON_DPHY_7			0x180e
+#define PPI_STARTUP_RW_COMMON_DPHY_8			0x1810
+#define PPI_STARTUP_RW_COMMON_DPHY_9			0x1812
+#define PPI_STARTUP_RW_COMMON_DPHY_A			0x1814
+#define PPI_STARTUP_RW_COMMON_DPHY_10			0x1820
+#define PPI_STARTUP_RW_COMMON_STARTUP_1_1		0x1822
+#define PPI_STARTUP_RW_COMMON_STARTUP_1_2		0x1824
+#define PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_0		0x1840
+#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_1		0x1842
+#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_2		0x1844
+#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_3		0x1846
+#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_4		0x1848
+#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5		0x184a
+#define PPI_CALIBCTRL_RW_COMMON_BG_0			0x184c
+#define PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_7		0x184e
+#define PPI_CALIBCTRL_RW_ADC_CFG_0			0x1850
+#define PPI_CALIBCTRL_RW_ADC_CFG_1			0x1852
+#define PPI_CALIBCTRL_R_ADC_DEBUG			0x1854
+#define PPI_RW_LPDCOCAL_TOP_OVERRIDE			0x1c00
+#define PPI_RW_LPDCOCAL_TIMEBASE			0x1c02
+#define PPI_RW_LPDCOCAL_NREF				0x1c04
+#define PPI_RW_LPDCOCAL_NREF_RANGE			0x1c06
+#define PPI_RW_LPDCOCAL_NREF_TRIGGER_MAN		0x1c08
+#define PPI_RW_LPDCOCAL_TWAIT_CONFIG			0x1c0a
+#define PPI_RW_LPDCOCAL_VT_CONFIG			0x1c0c
+#define PPI_R_LPDCOCAL_DEBUG_RB				0x1c0e
+#define PPI_RW_LPDCOCAL_COARSE_CFG			0x1c10
+#define PPI_R_LPDCOCAL_DEBUG_COARSE_RB			0x1c12
+#define PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_0_RB		0x1c14
+#define PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_1_RB		0x1c16
+#define PPI_R_LPDCOCAL_DEBUG_COARSE_FWORD_RB		0x1c18
+#define PPI_R_LPDCOCAL_DEBUG_MEASURE_CURR_ERROR		0x1c1a
+#define PPI_R_LPDCOCAL_DEBUG_MEASURE_LAST_ERROR		0x1c1c
+#define PPI_R_LPDCOCAL_DEBUG_VT				0x1c1e
+#define PPI_RW_LB_TIMEBASE_CONFIG			0x1c20
+#define PPI_RW_LB_STARTCMU_CONFIG			0x1c22
+#define PPI_R_LBPULSE_COUNTER_RB			0x1c24
+#define PPI_R_LB_START_CMU_RB				0x1c26
+#define PPI_RW_LB_DPHY_BURST_START			0x1c28
+#define PPI_RW_LB_CPHY_BURST_START			0x1c2a
+#define PPI_RW_DDLCAL_CFG_0				0x1c40
+#define PPI_RW_DDLCAL_CFG_1				0x1c42
+#define PPI_RW_DDLCAL_CFG_2				0x1c44
+#define PPI_RW_DDLCAL_CFG_3				0x1c46
+#define PPI_RW_DDLCAL_CFG_4				0x1c48
+#define PPI_RW_DDLCAL_CFG_5				0x1c4a
+#define PPI_RW_DDLCAL_CFG_6				0x1c4c
+#define PPI_RW_DDLCAL_CFG_7				0x1c4e
+#define PPI_R_DDLCAL_DEBUG_0				0x1c50
+#define PPI_R_DDLCAL_DEBUG_1				0x1c52
+#define PPI_RW_PARITY_TEST				0x1c60
+#define PPI_RW_STARTUP_OVR_0				0x1c62
+#define PPI_RW_STARTUP_STATE_OVR_1			0x1c64
+#define PPI_RW_DTB_SELECTOR				0x1c66
+#define PPI_RW_DPHY_CLK_SPARE				0x1c6a
+#define PPI_RW_COMMON_CFG				0x1c6c
+#define PPI_RW_TERMCAL_CFG_0				0x1c80
+#define PPI_R_TERMCAL_DEBUG_0				0x1c82
+#define PPI_RW_TERMCAL_CTRL_0				0x1c84
+#define PPI_RW_OFFSETCAL_CFG_0				0x1ca0
+#define PPI_R_OFFSETCAL_DEBUG_LANE0			0x1ca2
+#define PPI_R_OFFSETCAL_DEBUG_LANE1			0x1ca4
+#define PPI_R_OFFSETCAL_DEBUG_LANE2			0x1ca6
+#define PPI_R_OFFSETCAL_DEBUG_LANE3			0x1ca8
+#define PPI_R_OFFSETCAL_DEBUG_LANE4			0x1caa
+#define PPI_RW_HSDCOCAL_CFG_O				0x1d00
+#define PPI_RW_HSDCOCAL_CFG_1				0x1d02
+#define PPI_RW_HSDCOCAL_CFG_2				0x1d04
+#define PPI_RW_HSDCOCAL_CFG_3				0x1d06
+#define PPI_RW_HSDCOCAL_CFG_4				0x1d08
+#define PPI_RW_HSDCOCAL_CFG_5				0x1d0a
+#define PPI_RW_HSDCOCAL_CFG_6				0x1d0c
+#define PPI_RW_HSDCOCAL_CFG_7				0x1d0e
+#define PPI_RW_HSDCOCAL_CFG_8				0x1d10
+#define PPI_R_HSDCOCAL_DEBUG_RB				0x1d12
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_0	0x2000
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_1	0x2002
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_2	0x2004
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_3	0x2006
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_4	0x2008
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_5	0x200a
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_6	0x200c
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_7	0x200e
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_8	0x2010
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_9	0x2012
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_10	0x2014
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_11	0x2016
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_12	0x2018
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_13	0x201a
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_14	0x201c
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_15	0x201e
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_0	0x2020
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_1	0x2022
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_2	0x2024
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_3	0x2026
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_4	0x2028
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_5	0x202a
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_6	0x202c
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_7	0x202e
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_8	0x2030
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_9	0x2032
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_10	0x2034
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_11	0x2036
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_12	0x2038
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_13	0x203a
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_14	0x203c
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_15	0x203e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_0		0x2040
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_1		0x2042
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2		0x2044
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_3		0x2046
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_4		0x2048
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_5		0x204a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_6		0x204c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7		0x204e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8		0x2050
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9		0x2052
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_10		0x2054
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_11		0x2056
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12		0x2058
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13		0x205a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_14		0x205c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15		0x205e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_0		0x2060
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_1		0x2062
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_2		0x2064
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_3		0x2066
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_4		0x2068
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_5		0x206a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_6		0x206c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_7		0x206e
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_8		0x2070
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_9		0x2072
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_10		0x2074
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_11		0x2076
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_12		0x2078
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_13		0x207a
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_14		0x207c
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_15		0x207e
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_0		0x2080
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_1		0x2082
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_2		0x2084
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_3		0x2086
+#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_4		0x2088
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_0	0x20a0
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_1	0x20a2
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_2	0x20a4
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_3	0x20a6
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_4	0x20a8
+#define CORE_DIG_RW_TRIO0_0				0x2100
+#define CORE_DIG_RW_TRIO0_1				0x2102
+#define CORE_DIG_RW_TRIO0_2				0x2104
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_0	0x2400
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_1	0x2402
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_2	0x2404
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_3	0x2406
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_4	0x2408
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_5	0x240a
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_6	0x240c
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_7	0x240e
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_8	0x2410
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_9	0x2412
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_10	0x2414
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_11	0x2416
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_12	0x2418
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_13	0x241a
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_14	0x241c
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_15	0x241e
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_0	0x2420
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_1	0x2422
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_2	0x2424
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_3	0x2426
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_4	0x2428
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_5	0x242a
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_6	0x242c
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_7	0x242e
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_8	0x2430
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_9	0x2432
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_10	0x2434
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_11	0x2436
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_12	0x2438
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_13	0x243a
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_14	0x243c
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_15	0x243e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_0		0x2440
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_1		0x2442
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2		0x2444
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_3		0x2446
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_4		0x2448
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_5		0x244a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_6		0x244c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_7		0x244e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_8		0x2450
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9		0x2452
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_10		0x2454
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_11		0x2456
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_12		0x2458
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_13		0x245a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_14		0x245c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15		0x245e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_0		0x2460
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_1		0x2462
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_2		0x2464
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_3		0x2466
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_4		0x2468
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_5		0x246a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_6		0x246c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_7		0x246e
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_8		0x2470
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_9		0x2472
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_10		0x2474
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_11		0x2476
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_12		0x2478
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_13		0x247a
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_14		0x247c
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_15		0x247e
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_0		0x2480
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_1		0x2482
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_2		0x2484
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_3		0x2486
+#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_4		0x2488
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_0	0x24a0
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_1	0x24a2
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_2	0x24a4
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_3	0x24a6
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_4	0x24a8
+#define CORE_DIG_RW_TRIO1_0				0x2500
+#define CORE_DIG_RW_TRIO1_1				0x2502
+#define CORE_DIG_RW_TRIO1_2				0x2504
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_0	0x2800
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_1	0x2802
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_2	0x2804
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_3	0x2806
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_4	0x2808
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_5	0x280a
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_6	0x280c
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_7	0x280e
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_8	0x2810
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_9	0x2812
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_10	0x2814
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_11	0x2816
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_12	0x2818
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_13	0x281a
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_14	0x281c
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_15	0x281e
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_0	0x2820
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_1	0x2822
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_2	0x2824
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_3	0x2826
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_4	0x2828
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_5	0x282a
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_6	0x282c
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_7	0x282e
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_8	0x2830
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_9	0x2832
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_10	0x2834
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_11	0x2836
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_12	0x2838
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_13	0x283a
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_14	0x283c
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_15	0x283e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_0		0x2840
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_1		0x2842
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2		0x2844
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_3		0x2846
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_4		0x2848
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_5		0x284a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_6		0x284c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_7		0x284e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_8		0x2850
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9		0x2852
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_10		0x2854
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_11		0x2856
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_12		0x2858
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_13		0x285a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_14		0x285c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15		0x285e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_0		0x2860
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_1		0x2862
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_2		0x2864
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_3		0x2866
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_4		0x2868
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_5		0x286a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_6		0x286c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_7		0x286e
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_8		0x2870
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_9		0x2872
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_10		0x2874
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_11		0x2876
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_12		0x2878
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_13		0x287a
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_14		0x287c
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_15		0x287e
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_0		0x2880
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_1		0x2882
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_2		0x2884
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_3		0x2886
+#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_4		0x2888
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_0	0x28a0
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_1	0x28a2
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_2	0x28a4
+#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_3	0x28a6
+#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_4	0x28a8
+#define CORE_DIG_RW_TRIO2_0				0x2900
+#define CORE_DIG_RW_TRIO2_1				0x2902
+#define CORE_DIG_RW_TRIO2_2				0x2904
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_0	0x2c00
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_1	0x2c02
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_2	0x2c04
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_3	0x2c06
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_4	0x2c08
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_5	0x2c0a
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_6	0x2c0c
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_7	0x2c0e
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_8	0x2c10
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_9	0x2c12
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_10	0x2c14
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_11	0x2c16
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_12	0x2c18
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_13	0x2c1a
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_14	0x2c1c
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_15	0x2c1e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_0		0x2c40
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_1		0x2c42
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2		0x2c44
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_3		0x2c46
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_4		0x2c48
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_5		0x2c4a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_6		0x2c4c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_7		0x2c4e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_8		0x2c50
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9		0x2c52
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_10		0x2c54
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_11		0x2c56
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_12		0x2c58
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_13		0x2c5a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_14		0x2c5c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15		0x2c5e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_0		0x2c60
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_1		0x2c62
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_2		0x2c64
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_3		0x2c66
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_4		0x2c68
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_5		0x2c6a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_6		0x2c6c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_7		0x2c6e
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_8		0x2c70
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_9		0x2c72
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_10		0x2c74
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_11		0x2c76
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_12		0x2c78
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_13		0x2c7a
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_14		0x2c7c
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_15		0x2c7e
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_0		0x2c80
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_1		0x2c82
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_2		0x2c84
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_3		0x2c86
+#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_4		0x2c88
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_0		0x3040
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_1		0x3042
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2		0x3044
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_3		0x3046
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_4		0x3048
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_5		0x304a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_6		0x304c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_7		0x304e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_8		0x3050
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9		0x3052
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_10		0x3054
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_11		0x3056
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_12		0x3058
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_13		0x305a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_14		0x305c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15		0x305e
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_0		0x3060
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_1		0x3062
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_2		0x3064
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_3		0x3066
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_4		0x3068
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_5		0x306a
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_6		0x306c
+#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_7		0x306e
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_8		0x3070
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_9		0x3072
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_10		0x3074
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_11		0x3076
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_12		0x3078
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_13		0x307a
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_14		0x307c
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_15		0x307e
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_0		0x3080
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_1		0x3082
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_2		0x3084
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_3		0x3086
+#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_4		0x3088
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_0		0x3400
+#define CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_1		0x3402
+#define CORE_DIG_IOCTRL_R_DPHY_PPI_CLK_OVR_0_2		0x3404
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_0		0x3800
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_1		0x3802
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_2		0x3804
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_3		0x3806
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_4		0x3808
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_5		0x380a
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_6		0x380c
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_7		0x380e
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_8		0x3810
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_9		0x3812
+#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_10		0x3814
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_11		0x3816
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_12		0x3818
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_13		0x381a
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_14		0x381c
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_15		0x381e
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_0		0x3820
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_1		0x3822
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_2		0x3824
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_3		0x3826
+#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_4		0x3828
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0		0x3840
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1		0x3842
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_2		0x3844
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3		0x3846
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_4		0x3848
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5		0x384a
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6		0x384c
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7		0x384e
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8		0x3850
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_9		0x3852
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_10		0x3854
+#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_11		0x3856
+#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_12		0x3858
+#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_13		0x385a
+#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_14		0x385c
+#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15		0x385e
+#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_3_0		0x3860
+#define CORE_DIG_RW_COMMON_0				0x3880
+#define CORE_DIG_RW_COMMON_1				0x3882
+#define CORE_DIG_RW_COMMON_2				0x3884
+#define CORE_DIG_RW_COMMON_3				0x3886
+#define CORE_DIG_RW_COMMON_4				0x3888
+#define CORE_DIG_RW_COMMON_5				0x388a
+#define CORE_DIG_RW_COMMON_6				0x388c
+#define CORE_DIG_RW_COMMON_7				0x388e
+#define CORE_DIG_RW_COMMON_8				0x3890
+#define CORE_DIG_RW_COMMON_9				0x3892
+#define CORE_DIG_RW_COMMON_10				0x3894
+#define CORE_DIG_RW_COMMON_11				0x3896
+#define CORE_DIG_RW_COMMON_12				0x3898
+#define CORE_DIG_RW_COMMON_13				0x389a
+#define CORE_DIG_RW_COMMON_14				0x389c
+#define CORE_DIG_RW_COMMON_15				0x389e
+#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0		0x39e0
+#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_1		0x39e2
+#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2		0x39e4
+#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_3		0x39e6
+#define CORE_DIG_COMMON_RW_DESKEW_FINE_MEM		0x3fe0
+#define CORE_DIG_COMMON_R_DESKEW_FINE_MEM		0x3fe2
+#define PPI_RW_DPHY_LANE0_LBERT_0			0x4000
+#define PPI_RW_DPHY_LANE0_LBERT_1			0x4002
+#define PPI_R_DPHY_LANE0_LBERT_0			0x4004
+#define PPI_R_DPHY_LANE0_LBERT_1			0x4006
+#define PPI_RW_DPHY_LANE0_SPARE				0x4008
+#define PPI_RW_DPHY_LANE1_LBERT_0			0x4400
+#define PPI_RW_DPHY_LANE1_LBERT_1			0x4402
+#define PPI_R_DPHY_LANE1_LBERT_0			0x4404
+#define PPI_R_DPHY_LANE1_LBERT_1			0x4406
+#define PPI_RW_DPHY_LANE1_SPARE				0x4408
+#define PPI_RW_DPHY_LANE2_LBERT_0			0x4800
+#define PPI_RW_DPHY_LANE2_LBERT_1			0x4802
+#define PPI_R_DPHY_LANE2_LBERT_0			0x4804
+#define PPI_R_DPHY_LANE2_LBERT_1			0x4806
+#define PPI_RW_DPHY_LANE2_SPARE				0x4808
+#define PPI_RW_DPHY_LANE3_LBERT_0			0x4c00
+#define PPI_RW_DPHY_LANE3_LBERT_1			0x4c02
+#define PPI_R_DPHY_LANE3_LBERT_0			0x4c04
+#define PPI_R_DPHY_LANE3_LBERT_1			0x4c06
+#define PPI_RW_DPHY_LANE3_SPARE				0x4c08
+#define CORE_DIG_DLANE_0_RW_CFG_0			0x6000
+#define CORE_DIG_DLANE_0_RW_CFG_1			0x6002
+#define CORE_DIG_DLANE_0_RW_CFG_2			0x6004
+#define CORE_DIG_DLANE_0_RW_LP_0			0x6080
+#define CORE_DIG_DLANE_0_RW_LP_1			0x6082
+#define CORE_DIG_DLANE_0_RW_LP_2			0x6084
+#define CORE_DIG_DLANE_0_R_LP_0				0x60a0
+#define CORE_DIG_DLANE_0_R_LP_1				0x60a2
+#define CORE_DIG_DLANE_0_R_HS_TX_0			0x60e0
+#define CORE_DIG_DLANE_0_RW_HS_RX_0			0x6100
+#define CORE_DIG_DLANE_0_RW_HS_RX_1			0x6102
+#define CORE_DIG_DLANE_0_RW_HS_RX_2			0x6104
+#define CORE_DIG_DLANE_0_RW_HS_RX_3			0x6106
+#define CORE_DIG_DLANE_0_RW_HS_RX_4			0x6108
+#define CORE_DIG_DLANE_0_RW_HS_RX_5			0x610a
+#define CORE_DIG_DLANE_0_RW_HS_RX_6			0x610c
+#define CORE_DIG_DLANE_0_RW_HS_RX_7			0x610e
+#define CORE_DIG_DLANE_0_RW_HS_RX_8			0x6110
+#define CORE_DIG_DLANE_0_RW_HS_RX_9			0x6112
+#define CORE_DIG_DLANE_0_R_HS_RX_0			0x6120
+#define CORE_DIG_DLANE_0_R_HS_RX_1			0x6122
+#define CORE_DIG_DLANE_0_R_HS_RX_2			0x6124
+#define CORE_DIG_DLANE_0_R_HS_RX_3			0x6126
+#define CORE_DIG_DLANE_0_R_HS_RX_4			0x6128
+#define CORE_DIG_DLANE_0_RW_HS_TX_0			0x6200
+#define CORE_DIG_DLANE_0_RW_HS_TX_1			0x6202
+#define CORE_DIG_DLANE_0_RW_HS_TX_2			0x6204
+#define CORE_DIG_DLANE_0_RW_HS_TX_3			0x6206
+#define CORE_DIG_DLANE_0_RW_HS_TX_4			0x6208
+#define CORE_DIG_DLANE_0_RW_HS_TX_5			0x620a
+#define CORE_DIG_DLANE_0_RW_HS_TX_6			0x620c
+#define CORE_DIG_DLANE_0_RW_HS_TX_7			0x620e
+#define CORE_DIG_DLANE_0_RW_HS_TX_8			0x6210
+#define CORE_DIG_DLANE_0_RW_HS_TX_9			0x6212
+#define CORE_DIG_DLANE_0_RW_HS_TX_10			0x6214
+#define CORE_DIG_DLANE_0_RW_HS_TX_11			0x6216
+#define CORE_DIG_DLANE_0_RW_HS_TX_12			0x6218
+#define CORE_DIG_DLANE_1_RW_CFG_0			0x6400
+#define CORE_DIG_DLANE_1_RW_CFG_1			0x6402
+#define CORE_DIG_DLANE_1_RW_CFG_2			0x6404
+#define CORE_DIG_DLANE_1_RW_LP_0			0x6480
+#define CORE_DIG_DLANE_1_RW_LP_1			0x6482
+#define CORE_DIG_DLANE_1_RW_LP_2			0x6484
+#define CORE_DIG_DLANE_1_R_LP_0				0x64a0
+#define CORE_DIG_DLANE_1_R_LP_1				0x64a2
+#define CORE_DIG_DLANE_1_R_HS_TX_0			0x64e0
+#define CORE_DIG_DLANE_1_RW_HS_RX_0			0x6500
+#define CORE_DIG_DLANE_1_RW_HS_RX_1			0x6502
+#define CORE_DIG_DLANE_1_RW_HS_RX_2			0x6504
+#define CORE_DIG_DLANE_1_RW_HS_RX_3			0x6506
+#define CORE_DIG_DLANE_1_RW_HS_RX_4			0x6508
+#define CORE_DIG_DLANE_1_RW_HS_RX_5			0x650a
+#define CORE_DIG_DLANE_1_RW_HS_RX_6			0x650c
+#define CORE_DIG_DLANE_1_RW_HS_RX_7			0x650e
+#define CORE_DIG_DLANE_1_RW_HS_RX_8			0x6510
+#define CORE_DIG_DLANE_1_RW_HS_RX_9			0x6512
+#define CORE_DIG_DLANE_1_R_HS_RX_0			0x6520
+#define CORE_DIG_DLANE_1_R_HS_RX_1			0x6522
+#define CORE_DIG_DLANE_1_R_HS_RX_2			0x6524
+#define CORE_DIG_DLANE_1_R_HS_RX_3			0x6526
+#define CORE_DIG_DLANE_1_R_HS_RX_4			0x6528
+#define CORE_DIG_DLANE_1_RW_HS_TX_0			0x6600
+#define CORE_DIG_DLANE_1_RW_HS_TX_1			0x6602
+#define CORE_DIG_DLANE_1_RW_HS_TX_2			0x6604
+#define CORE_DIG_DLANE_1_RW_HS_TX_3			0x6606
+#define CORE_DIG_DLANE_1_RW_HS_TX_4			0x6608
+#define CORE_DIG_DLANE_1_RW_HS_TX_5			0x660a
+#define CORE_DIG_DLANE_1_RW_HS_TX_6			0x660c
+#define CORE_DIG_DLANE_1_RW_HS_TX_7			0x660e
+#define CORE_DIG_DLANE_1_RW_HS_TX_8			0x6610
+#define CORE_DIG_DLANE_1_RW_HS_TX_9			0x6612
+#define CORE_DIG_DLANE_1_RW_HS_TX_10			0x6614
+#define CORE_DIG_DLANE_1_RW_HS_TX_11			0x6616
+#define CORE_DIG_DLANE_1_RW_HS_TX_12			0x6618
+#define CORE_DIG_DLANE_2_RW_CFG_0			0x6800
+#define CORE_DIG_DLANE_2_RW_CFG_1			0x6802
+#define CORE_DIG_DLANE_2_RW_CFG_2			0x6804
+#define CORE_DIG_DLANE_2_RW_LP_0			0x6880
+#define CORE_DIG_DLANE_2_RW_LP_1			0x6882
+#define CORE_DIG_DLANE_2_RW_LP_2			0x6884
+#define CORE_DIG_DLANE_2_R_LP_0				0x68a0
+#define CORE_DIG_DLANE_2_R_LP_1				0x68a2
+#define CORE_DIG_DLANE_2_R_HS_TX_0			0x68e0
+#define CORE_DIG_DLANE_2_RW_HS_RX_0			0x6900
+#define CORE_DIG_DLANE_2_RW_HS_RX_1			0x6902
+#define CORE_DIG_DLANE_2_RW_HS_RX_2			0x6904
+#define CORE_DIG_DLANE_2_RW_HS_RX_3			0x6906
+#define CORE_DIG_DLANE_2_RW_HS_RX_4			0x6908
+#define CORE_DIG_DLANE_2_RW_HS_RX_5			0x690a
+#define CORE_DIG_DLANE_2_RW_HS_RX_6			0x690c
+#define CORE_DIG_DLANE_2_RW_HS_RX_7			0x690e
+#define CORE_DIG_DLANE_2_RW_HS_RX_8			0x6910
+#define CORE_DIG_DLANE_2_RW_HS_RX_9			0x6912
+#define CORE_DIG_DLANE_2_R_HS_RX_0			0x6920
+#define CORE_DIG_DLANE_2_R_HS_RX_1			0x6922
+#define CORE_DIG_DLANE_2_R_HS_RX_2			0x6924
+#define CORE_DIG_DLANE_2_R_HS_RX_3			0x6926
+#define CORE_DIG_DLANE_2_R_HS_RX_4			0x6928
+#define CORE_DIG_DLANE_2_RW_HS_TX_0			0x6a00
+#define CORE_DIG_DLANE_2_RW_HS_TX_1			0x6a02
+#define CORE_DIG_DLANE_2_RW_HS_TX_2			0x6a04
+#define CORE_DIG_DLANE_2_RW_HS_TX_3			0x6a06
+#define CORE_DIG_DLANE_2_RW_HS_TX_4			0x6a08
+#define CORE_DIG_DLANE_2_RW_HS_TX_5			0x6a0a
+#define CORE_DIG_DLANE_2_RW_HS_TX_6			0x6a0c
+#define CORE_DIG_DLANE_2_RW_HS_TX_7			0x6a0e
+#define CORE_DIG_DLANE_2_RW_HS_TX_8			0x6a10
+#define CORE_DIG_DLANE_2_RW_HS_TX_9			0x6a12
+#define CORE_DIG_DLANE_2_RW_HS_TX_10			0x6a14
+#define CORE_DIG_DLANE_2_RW_HS_TX_11			0x6a16
+#define CORE_DIG_DLANE_2_RW_HS_TX_12			0x6a18
+#define CORE_DIG_DLANE_3_RW_CFG_0			0x6c00
+#define CORE_DIG_DLANE_3_RW_CFG_1			0x6c02
+#define CORE_DIG_DLANE_3_RW_CFG_2			0x6c04
+#define CORE_DIG_DLANE_3_RW_LP_0			0x6c80
+#define CORE_DIG_DLANE_3_RW_LP_1			0x6c82
+#define CORE_DIG_DLANE_3_RW_LP_2			0x6c84
+#define CORE_DIG_DLANE_3_R_LP_0				0x6ca0
+#define CORE_DIG_DLANE_3_R_LP_1				0x6ca2
+#define CORE_DIG_DLANE_3_R_HS_TX_0			0x6ce0
+#define CORE_DIG_DLANE_3_RW_HS_RX_0			0x6d00
+#define CORE_DIG_DLANE_3_RW_HS_RX_1			0x6d02
+#define CORE_DIG_DLANE_3_RW_HS_RX_2			0x6d04
+#define CORE_DIG_DLANE_3_RW_HS_RX_3			0x6d06
+#define CORE_DIG_DLANE_3_RW_HS_RX_4			0x6d08
+#define CORE_DIG_DLANE_3_RW_HS_RX_5			0x6d0a
+#define CORE_DIG_DLANE_3_RW_HS_RX_6			0x6d0c
+#define CORE_DIG_DLANE_3_RW_HS_RX_7			0x6d0e
+#define CORE_DIG_DLANE_3_RW_HS_RX_8			0x6d10
+#define CORE_DIG_DLANE_3_RW_HS_RX_9			0x6d12
+#define CORE_DIG_DLANE_3_R_HS_RX_0			0x6d20
+#define CORE_DIG_DLANE_3_R_HS_RX_1			0x6d22
+#define CORE_DIG_DLANE_3_R_HS_RX_2			0x6d24
+#define CORE_DIG_DLANE_3_R_HS_RX_3			0x6d26
+#define CORE_DIG_DLANE_3_R_HS_RX_4			0x6d28
+#define CORE_DIG_DLANE_3_RW_HS_TX_0			0x6e00
+#define CORE_DIG_DLANE_3_RW_HS_TX_1			0x6e02
+#define CORE_DIG_DLANE_3_RW_HS_TX_2			0x6e04
+#define CORE_DIG_DLANE_3_RW_HS_TX_3			0x6e06
+#define CORE_DIG_DLANE_3_RW_HS_TX_4			0x6e08
+#define CORE_DIG_DLANE_3_RW_HS_TX_5			0x6e0a
+#define CORE_DIG_DLANE_3_RW_HS_TX_6			0x6e0c
+#define CORE_DIG_DLANE_3_RW_HS_TX_7			0x6e0e
+#define CORE_DIG_DLANE_3_RW_HS_TX_8			0x6e10
+#define CORE_DIG_DLANE_3_RW_HS_TX_9			0x6e12
+#define CORE_DIG_DLANE_3_RW_HS_TX_10			0x6e14
+#define CORE_DIG_DLANE_3_RW_HS_TX_11			0x6e16
+#define CORE_DIG_DLANE_3_RW_HS_TX_12			0x6e18
+#define CORE_DIG_DLANE_CLK_RW_CFG_0			0x7000
+#define CORE_DIG_DLANE_CLK_RW_CFG_1			0x7002
+#define CORE_DIG_DLANE_CLK_RW_CFG_2			0x7004
+#define CORE_DIG_DLANE_CLK_RW_LP_0			0x7080
+#define CORE_DIG_DLANE_CLK_RW_LP_1			0x7082
+#define CORE_DIG_DLANE_CLK_RW_LP_2			0x7084
+#define CORE_DIG_DLANE_CLK_R_LP_0			0x70a0
+#define CORE_DIG_DLANE_CLK_R_LP_1			0x70a2
+#define CORE_DIG_DLANE_CLK_R_HS_TX_0			0x70e0
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_0			0x7100
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_1			0x7102
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_2			0x7104
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_3			0x7106
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_4			0x7108
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_5			0x710a
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_6			0x710c
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_7			0x710e
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_8			0x7110
+#define CORE_DIG_DLANE_CLK_RW_HS_RX_9			0x7112
+#define CORE_DIG_DLANE_CLK_R_HS_RX_0			0x7120
+#define CORE_DIG_DLANE_CLK_R_HS_RX_1			0x7122
+#define CORE_DIG_DLANE_CLK_R_HS_RX_2			0x7124
+#define CORE_DIG_DLANE_CLK_R_HS_RX_3			0x7126
+#define CORE_DIG_DLANE_CLK_R_HS_RX_4			0x7128
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_0			0x7200
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_1			0x7202
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_2			0x7204
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_3			0x7206
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_4			0x7208
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_5			0x720a
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_6			0x720c
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_7			0x720e
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_8			0x7210
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_9			0x7212
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_10			0x7214
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_11			0x7216
+#define CORE_DIG_DLANE_CLK_RW_HS_TX_12			0x7218
+#define PPI_RW_CPHY_TRIO0_LBERT_0			0x8000
+#define PPI_RW_CPHY_TRIO0_LBERT_1			0x8002
+#define PPI_R_CPHY_TRIO0_LBERT_0			0x8004
+#define PPI_R_CPHY_TRIO0_LBERT_1			0x8006
+#define PPI_RW_CPHY_TRIO0_SPARE				0x8008
+#define PPI_RW_CPHY_TRIO1_LBERT_0			0x8400
+#define PPI_RW_CPHY_TRIO1_LBERT_1			0x8402
+#define PPI_R_CPHY_TRIO1_LBERT_0			0x8404
+#define PPI_R_CPHY_TRIO1_LBERT_1			0x8406
+#define PPI_RW_CPHY_TRIO1_SPARE				0x8408
+#define PPI_RW_CPHY_TRIO2_LBERT_0			0x8800
+#define PPI_RW_CPHY_TRIO2_LBERT_1			0x8802
+#define PPI_R_CPHY_TRIO2_LBERT_0			0x8804
+#define PPI_R_CPHY_TRIO2_LBERT_1			0x8806
+#define PPI_RW_CPHY_TRIO2_SPARE				0x8808
+#define CORE_DIG_CLANE_0_RW_CFG_0			0xa000
+#define CORE_DIG_CLANE_0_RW_CFG_2			0xa004
+#define CORE_DIG_CLANE_0_RW_LP_0			0xa080
+#define CORE_DIG_CLANE_0_RW_LP_1			0xa082
+#define CORE_DIG_CLANE_0_RW_LP_2			0xa084
+#define CORE_DIG_CLANE_0_R_LP_0				0xa0a0
+#define CORE_DIG_CLANE_0_R_LP_1				0xa0a2
+#define CORE_DIG_CLANE_0_RW_HS_RX_0			0xa100
+#define CORE_DIG_CLANE_0_RW_HS_RX_1			0xa102
+#define CORE_DIG_CLANE_0_RW_HS_RX_2			0xa104
+#define CORE_DIG_CLANE_0_RW_HS_RX_3			0xa106
+#define CORE_DIG_CLANE_0_RW_HS_RX_4			0xa108
+#define CORE_DIG_CLANE_0_RW_HS_RX_5			0xa10a
+#define CORE_DIG_CLANE_0_RW_HS_RX_6			0xa10c
+#define CORE_DIG_CLANE_0_R_RX_0				0xa120
+#define CORE_DIG_CLANE_0_R_RX_1				0xa122
+#define CORE_DIG_CLANE_0_R_TX_0				0xa124
+#define CORE_DIG_CLANE_0_R_RX_2				0xa126
+#define CORE_DIG_CLANE_0_R_RX_3				0xa128
+#define CORE_DIG_CLANE_0_RW_HS_TX_0			0xa200
+#define CORE_DIG_CLANE_0_RW_HS_TX_1			0xa202
+#define CORE_DIG_CLANE_0_RW_HS_TX_2			0xa204
+#define CORE_DIG_CLANE_0_RW_HS_TX_3			0xa206
+#define CORE_DIG_CLANE_0_RW_HS_TX_4			0xa208
+#define CORE_DIG_CLANE_0_RW_HS_TX_5			0xa20a
+#define CORE_DIG_CLANE_0_RW_HS_TX_6			0xa20c
+#define CORE_DIG_CLANE_0_RW_HS_TX_7			0xa20e
+#define CORE_DIG_CLANE_0_RW_HS_TX_8			0xa210
+#define CORE_DIG_CLANE_0_RW_HS_TX_9			0xa212
+#define CORE_DIG_CLANE_0_RW_HS_TX_10			0xa214
+#define CORE_DIG_CLANE_0_RW_HS_TX_11			0xa216
+#define CORE_DIG_CLANE_0_RW_HS_TX_12			0xa218
+#define CORE_DIG_CLANE_0_RW_HS_TX_13			0xa21a
+#define CORE_DIG_CLANE_1_RW_CFG_0			0xa400
+#define CORE_DIG_CLANE_1_RW_CFG_2			0xa404
+#define CORE_DIG_CLANE_1_RW_LP_0			0xa480
+#define CORE_DIG_CLANE_1_RW_LP_1			0xa482
+#define CORE_DIG_CLANE_1_RW_LP_2			0xa484
+#define CORE_DIG_CLANE_1_R_LP_0				0xa4a0
+#define CORE_DIG_CLANE_1_R_LP_1				0xa4a2
+#define CORE_DIG_CLANE_1_RW_HS_RX_0			0xa500
+#define CORE_DIG_CLANE_1_RW_HS_RX_1			0xa502
+#define CORE_DIG_CLANE_1_RW_HS_RX_2			0xa504
+#define CORE_DIG_CLANE_1_RW_HS_RX_3			0xa506
+#define CORE_DIG_CLANE_1_RW_HS_RX_4			0xa508
+#define CORE_DIG_CLANE_1_RW_HS_RX_5			0xa50a
+#define CORE_DIG_CLANE_1_RW_HS_RX_6			0xa50c
+#define CORE_DIG_CLANE_1_R_RX_0				0xa520
+#define CORE_DIG_CLANE_1_R_RX_1				0xa522
+#define CORE_DIG_CLANE_1_R_TX_0				0xa524
+#define CORE_DIG_CLANE_1_R_RX_2				0xa526
+#define CORE_DIG_CLANE_1_R_RX_3				0xa528
+#define CORE_DIG_CLANE_1_RW_HS_TX_0			0xa600
+#define CORE_DIG_CLANE_1_RW_HS_TX_1			0xa602
+#define CORE_DIG_CLANE_1_RW_HS_TX_2			0xa604
+#define CORE_DIG_CLANE_1_RW_HS_TX_3			0xa606
+#define CORE_DIG_CLANE_1_RW_HS_TX_4			0xa608
+#define CORE_DIG_CLANE_1_RW_HS_TX_5			0xa60a
+#define CORE_DIG_CLANE_1_RW_HS_TX_6			0xa60c
+#define CORE_DIG_CLANE_1_RW_HS_TX_7			0xa60e
+#define CORE_DIG_CLANE_1_RW_HS_TX_8			0xa610
+#define CORE_DIG_CLANE_1_RW_HS_TX_9			0xa612
+#define CORE_DIG_CLANE_1_RW_HS_TX_10			0xa614
+#define CORE_DIG_CLANE_1_RW_HS_TX_11			0xa616
+#define CORE_DIG_CLANE_1_RW_HS_TX_12			0xa618
+#define CORE_DIG_CLANE_1_RW_HS_TX_13			0xa61a
+#define CORE_DIG_CLANE_2_RW_CFG_0			0xa800
+#define CORE_DIG_CLANE_2_RW_CFG_2			0xa804
+#define CORE_DIG_CLANE_2_RW_LP_0			0xa880
+#define CORE_DIG_CLANE_2_RW_LP_1			0xa882
+#define CORE_DIG_CLANE_2_RW_LP_2			0xa884
+#define CORE_DIG_CLANE_2_R_LP_0				0xa8a0
+#define CORE_DIG_CLANE_2_R_LP_1				0xa8a2
+#define CORE_DIG_CLANE_2_RW_HS_RX_0			0xa900
+#define CORE_DIG_CLANE_2_RW_HS_RX_1			0xa902
+#define CORE_DIG_CLANE_2_RW_HS_RX_2			0xa904
+#define CORE_DIG_CLANE_2_RW_HS_RX_3			0xa906
+#define CORE_DIG_CLANE_2_RW_HS_RX_4			0xa908
+#define CORE_DIG_CLANE_2_RW_HS_RX_5			0xa90a
+#define CORE_DIG_CLANE_2_RW_HS_RX_6			0xa90c
+#define CORE_DIG_CLANE_2_R_RX_0				0xa920
+#define CORE_DIG_CLANE_2_R_RX_1				0xa922
+#define CORE_DIG_CLANE_2_R_TX_0				0xa924
+#define CORE_DIG_CLANE_2_R_RX_2				0xa926
+#define CORE_DIG_CLANE_2_R_RX_3				0xa928
+#define CORE_DIG_CLANE_2_RW_HS_TX_0			0xaa00
+#define CORE_DIG_CLANE_2_RW_HS_TX_1			0xaa02
+#define CORE_DIG_CLANE_2_RW_HS_TX_2			0xaa04
+#define CORE_DIG_CLANE_2_RW_HS_TX_3			0xaa06
+#define CORE_DIG_CLANE_2_RW_HS_TX_4			0xaa08
+#define CORE_DIG_CLANE_2_RW_HS_TX_5			0xaa0a
+#define CORE_DIG_CLANE_2_RW_HS_TX_6			0xaa0c
+#define CORE_DIG_CLANE_2_RW_HS_TX_7			0xaa0e
+#define CORE_DIG_CLANE_2_RW_HS_TX_8			0xaa10
+#define CORE_DIG_CLANE_2_RW_HS_TX_9			0xaa12
+#define CORE_DIG_CLANE_2_RW_HS_TX_10			0xaa14
+#define CORE_DIG_CLANE_2_RW_HS_TX_11			0xaa16
+#define CORE_DIG_CLANE_2_RW_HS_TX_12			0xaa18
+#define CORE_DIG_CLANE_2_RW_HS_TX_13			0xaa1a
+
+/* dwc csi host controller registers */
+#define IS_IO_CSI2_HOST_BASE(i)			(IS_IO_BASE + 0x40000 + \
+						 0x2000 * (i))
+#define VERSION					0x0
+#define N_LANES					0x4
+#define CSI2_RESETN				0x8
+#define INT_ST_MAIN				0xc
+#define DATA_IDS_1				0x10
+#define DATA_IDS_2				0x14
+#define CDPHY_MODE				0x1c
+#define DATA_IDS_VC_1				0x30
+#define DATA_IDS_VC_2				0x34
+#define PHY_SHUTDOWNZ				0x40
+#define DPHY_RSTZ				0x44
+#define PHY_RX					0x48
+#define PHY_STOPSTATE				0x4c
+#define PHY_TEST_CTRL0				0x50
+#define PHY_TEST_CTRL1				0x54
+#define PPI_PG_PATTERN_VRES			0x60
+#define PPI_PG_PATTERN_HRES			0x64
+#define PPI_PG_CONFIG				0x68
+#define PPI_PG_ENABLE				0x6c
+#define PPI_PG_STATUS				0x70
+#define VC_EXTENSION				0xc8
+#define PHY_CAL					0xcc
+#define INT_ST_PHY_FATAL			0xe0
+#define INT_MSK_PHY_FATAL			0xe4
+#define INT_FORCE_PHY_FATAL			0xe8
+#define INT_ST_PKT_FATAL			0xf0
+#define INT_MSK_PKT_FATAL			0xf4
+#define INT_FORCE_PKT_FATAL			0xf8
+#define INT_ST_PHY				0x110
+#define INT_MSK_PHY				0x114
+#define INT_FORCE_PHY				0x118
+#define INT_ST_LINE				0x130
+#define INT_MSK_LINE				0x134
+#define INT_FORCE_LINE				0x138
+#define INT_ST_BNDRY_FRAME_FATAL		0x280
+#define INT_MSK_BNDRY_FRAME_FATAL		0x284
+#define INT_FORCE_BNDRY_FRAME_FATAL		0x288
+#define INT_ST_SEQ_FRAME_FATAL			0x290
+#define INT_MSK_SEQ_FRAME_FATAL			0x294
+#define INT_FORCE_SEQ_FRAME_FATAL		0x298
+#define INT_ST_CRC_FRAME_FATAL			0x2a0
+#define INT_MSK_CRC_FRAME_FATAL			0x2a4
+#define INT_FORCE_CRC_FRAME_FATAL		0x2a8
+#define INT_ST_PLD_CRC_FATAL			0x2b0
+#define INT_MSK_PLD_CRC_FATAL			0x2b4
+#define INT_FORCE_PLD_CRC_FATAL			0x2b8
+#define INT_ST_DATA_ID				0x2c0
+#define INT_MSK_DATA_ID				0x2c4
+#define INT_FORCE_DATA_ID			0x2c8
+#define INT_ST_ECC_CORRECTED			0x2d0
+#define INT_MSK_ECC_CORRECTED			0x2d4
+#define INT_FORCE_ECC_CORRECTED			0x2d8
+#define SCRAMBLING				0x300
+#define SCRAMBLING_SEED1			0x304
+#define SCRAMBLING_SEED2			0x308
+#define SCRAMBLING_SEED3			0x30c
+#define SCRAMBLING_SEED4			0x310
+#define SCRAMBLING				0x300
+
+#define IS_IO_CSI2_ADPL_PORT_BASE(i)		(IS_IO_BASE + 0x40800 + \
+						 0x2000 * (i))
+#define CSI2_ADPL_INPUT_MODE			0x0
+#define CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN	0x4
+#define CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_ADDR	0x8
+#define CSI2_ADPL_CSI_RX_ERR_IRQ_STATUS		0xc
+#define CSI2_ADPL_IRQ_CTL_COMMON_STATUS		0xa4
+#define CSI2_ADPL_IRQ_CTL_COMMON_CLEAR		0xa8
+#define CSI2_ADPL_IRQ_CTL_COMMON_ENABLE		0xac
+#define CSI2_ADPL_IRQ_CTL_FS_STATUS		0xbc
+#define CSI2_ADPL_IRQ_CTL_FS_CLEAR		0xc0
+#define CSI2_ADPL_IRQ_CTL_FS_ENABLE		0xc4
+#define CSI2_ADPL_IRQ_CTL_FE_STATUS		0xc8
+#define CSI2_ADPL_IRQ_CTL_FE_CLEAR		0xcc
+#define CSI2_ADPL_IRQ_CTL_FE_ENABLE		0xd0
+
+/* software control the legacy csi irq */
+#define IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(i)	(IS_IO_BASE + 0x40c00 + \
+						 0x2000 * (i))
+#define IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(i)	(IS_IO_BASE + 0x40d00 + \
+						 0x2000 * (i))
+#define IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE		(IS_IO_BASE + 0x49000)
+#define IS_IO_CSI2_IRQ_CTRL_BASE		(IS_IO_BASE + 0x4e100)
+
+#define IRQ_CTL_EDGE				0x0
+#define IRQ_CTL_MASK				0x4
+#define IRQ_CTL_STATUS				0x8
+#define IRQ_CTL_CLEAR				0xc
+#define IRQ_CTL_ENABLE				0x10
+/* FE irq for PTL */
+#define IRQ1_CTL_MASK				0x14
+#define IRQ1_CTL_STATUS				0x18
+#define IRQ1_CTL_CLEAR				0x1c
+#define IRQ1_CTL_ENABLE				0x20
+
+/* software to set the clock gate to use the port or mgc */
+#define IS_IO_GPREGS_BASE			(IS_IO_BASE + 0x49200)
+#define SRST_PORT_ARB				0x0
+#define SRST_MGC				0x4
+#define SRST_WIDTH_CONV				0x8
+#define SRST_CSI_IRQ				0xc
+#define SRST_CSI_LEGACY_IRQ			0x10
+#define CLK_EN_TXCLKESC				0x14
+#define CLK_DIV_FACTOR_IS_CLK			0x18
+#define CLK_DIV_FACTOR_APB_CLK			0x1c
+#define CSI_PORT_CLK_GATE			0x20
+#define CSI_PORTAB_AGGREGATION			0x24
+#define MGC_CLK_GATE				0x2c
+#define CG_CTRL_BITS				0x3c
+#define SPARE_RW				0xf8
+#define SPARE_RO				0xfc
+
+#define IS_IO_CSI2_MPF_PORT_BASE(i)		(IS_IO_BASE + 0x53000 + \
+						 0x1000 * (i))
+#define MPF_16_IRQ_CNTRL_STATUS			0x238
+#define MPF_16_IRQ_CNTRL_CLEAR			0x23c
+#define MPF_16_IRQ_CNTRL_ENABLE			0x240
+
+/* software config the phy */
+#define IS_IO_CSI2_GPREGS_BASE		(IS_IO_BASE + 0x53400)
+#define IPU8_IS_IO_CSI2_GPREGS_BASE	(IS_IO_BASE + 0x40e00)
+#define CSI_ADAPT_LAYER_SRST		0x0
+#define MPF_SRST_RST			0x4
+#define CSI_ERR_IRQ_CTRL_SRST		0x8
+#define CSI_SYNC_RC_SRST		0xc
+#define CSI_CG_CTRL_BITS		0x10
+#define SOC_CSI2HOST_SELECT		0x14
+#define PHY_RESET			0x18
+#define PHY_SHUTDOWN			0x1c
+#define PHY_MODE			0x20
+#define PHY_READY			0x24
+#define PHY_CLK_LANE_FORCE_CONTROL	0x28
+#define PHY_CLK_LANE_CONTROL		0x2c
+#define PHY_CLK_LANE_STATUS		0x30
+#define PHY_LANE_RX_ESC_REQ		0x34
+#define PHY_LANE_RX_ESC_DATA		0x38
+#define PHY_LANE_TURNDISABLE		0x3c
+#define PHY_LANE_DIRECTION		0x40
+#define PHY_LANE_FORCE_CONTROL		0x44
+#define PHY_LANE_CONTROL_EN		0x48
+#define PHY_LANE_CONTROL_DATAWIDTH	0x4c
+#define PHY_LANE_STATUS			0x50
+#define PHY_LANE_ERR			0x54
+#define PHY_LANE_RXALP			0x58
+#define PHY_LANE_RXALP_NIBBLE		0x5c
+#define PHY_PARITY_ERROR		0x60
+#define PHY_DEBUG_REGS_CLK_GATE_EN	0x64
+#define SPARE_RW			0xf8
+#define SPARE_RO			0xfc
+
+/* software not touch */
+#define PORT_ARB_BASE				(IS_IO_BASE + 0x4e000)
+#define PORT_ARB_IRQ_CTL_STATUS			0x4
+#define PORT_ARB_IRQ_CTL_CLEAR			0x8
+#define PORT_ARB_IRQ_CTL_ENABLE			0xc
+
+#define MGC_PPC					4U
+#define MGC_DTYPE_RAW(i)			(((i) - 8) / 2)
+#define IS_IO_MGC_BASE				(IS_IO_BASE + 0x48000)
+#define MGC_KICK				0x0
+#define MGC_ASYNC_STOP				0x4
+#define MGC_PORT_OFFSET				0x100
+#define MGC_CSI_PORT_MAP(i)			(0x8 + (i) * 0x4)
+#define MGC_MG_PORT(i)				(IS_IO_MGC_BASE + \
+						 (i) * MGC_PORT_OFFSET)
+/* per mgc instance */
+#define MGC_MG_CSI_ADAPT_LAYER_TYPE		0x28
+#define MGC_MG_MODE				0x2c
+#define MGC_MG_INIT_COUNTER			0x30
+#define MGC_MG_MIPI_VC				0x34
+#define MGC_MG_MIPI_DTYPES			0x38
+#define MGC_MG_MULTI_DTYPES_MODE		0x3c
+#define MGC_MG_NOF_FRAMES			0x40
+#define MGC_MG_FRAME_DIM			0x44
+#define MGC_MG_HBLANK				0x48
+#define MGC_MG_VBLANK				0x4c
+#define MGC_MG_TPG_MODE				0x50
+#define MGC_MG_TPG_R0				0x54
+#define MGC_MG_TPG_G0				0x58
+#define MGC_MG_TPG_B0				0x5c
+#define MGC_MG_TPG_R1				0x60
+#define MGC_MG_TPG_G1				0x64
+#define MGC_MG_TPG_B1				0x68
+#define MGC_MG_TPG_FACTORS			0x6c
+#define MGC_MG_TPG_MASKS			0x70
+#define MGC_MG_TPG_XY_MASK			0x74
+#define MGC_MG_TPG_TILE_DIM			0x78
+#define MGC_MG_PRBS_LFSR_INIT_0			0x7c
+#define MGC_MG_PRBS_LFSR_INIT_1			0x80
+#define MGC_MG_SYNC_STOP_POINT			0x84
+#define MGC_MG_SYNC_STOP_POINT_LOC		0x88
+#define MGC_MG_ERR_INJECT			0x8c
+#define MGC_MG_ERR_LOCATION			0x90
+#define MGC_MG_DTO_SPEED_CTRL_EN		0x94
+#define MGC_MG_DTO_SPEED_CTRL_INCR_VAL		0x98
+#define MGC_MG_HOR_LOC_STTS			0x9c
+#define MGC_MG_VER_LOC_STTS			0xa0
+#define MGC_MG_FRAME_NUM_STTS			0xa4
+#define MGC_MG_BUSY_STTS			0xa8
+#define MGC_MG_STOPPED_STTS			0xac
+/* tile width and height in pixels for Chess board and Color palette */
+#define MGC_TPG_TILE_WIDTH			64U
+#define MGC_TPG_TILE_HEIGHT			64U
+
+#define IPU_CSI_PORT_A_ADDR_OFFSET		0x0
+#define IPU_CSI_PORT_B_ADDR_OFFSET		0x0
+#define IPU_CSI_PORT_C_ADDR_OFFSET		0x0
+#define IPU_CSI_PORT_D_ADDR_OFFSET		0x0
+
+/*
+ * 0 - CSI RX Port 0 interrupt;
+ * 1 - MPF Port 0 interrupt;
+ * 2 - CSI RX Port 1 interrupt;
+ * 3 - MPF Port 1 interrupt;
+ * 4 - CSI RX Port 2 interrupt;
+ * 5 - MPF Port 2 interrupt;
+ * 6 - CSI RX Port 3 interrupt;
+ * 7 - MPF Port 3 interrupt;
+ * 8 - Port ARB FIFO 0 overflow;
+ * 9 - Port ARB FIFO 1 overflow;
+ * 10 - Port ARB FIFO 2 overflow;
+ * 11 - Port ARB FIFO 3 overflow;
+ * 12 - isys_cfgnoc_err_probe_intl;
+ * 13-15 - reserved
+ */
+#define IPU7_CSI_IS_IO_IRQ_MASK		0xffff
+
+/* Adapter layer irq */
+#define IPU7_CSI_ADPL_IRQ_MASK		0xffff
+
+/* sw irq from legacy irq control
+ * legacy irq status
+ * IPU7
+ * 0 - CSI Port 0 error interrupt
+ * 1 - CSI Port 0 sync interrupt
+ * 2 - CSI Port 1 error interrupt
+ * 3 - CSI Port 1 sync interrupt
+ * 4 - CSI Port 2 error interrupt
+ * 5 - CSI Port 2 sync interrupt
+ * 6 - CSI Port 3 error interrupt
+ * 7 - CSI Port 3 sync interrupt
+ * IPU7P5
+ * 0 - CSI Port 0 error interrupt
+ * 1 - CSI Port 0 fs interrupt
+ * 2 - CSI Port 0 fe interrupt
+ * 3 - CSI Port 1 error interrupt
+ * 4 - CSI Port 1 fs interrupt
+ * 5 - CSI Port 1 fe interrupt
+ * 6 - CSI Port 2 error interrupt
+ * 7 - CSI Port 2 fs interrupt
+ * 8 - CSI Port 2 fe interrupt
+ */
+#define IPU7_CSI_RX_LEGACY_IRQ_MASK		0x1ff
+
+/* legacy error status per port
+ * 0 - Error handler FIFO full;
+ * 1 - Reserved Short Packet encoding detected;
+ * 2 - Reserved Long Packet encoding detected;
+ * 3 - Received packet is too short (fewer data words than specified in header);
+ * 4 - Received packet is too long (more data words than specified in header);
+ * 5 - Short packet discarded due to errors;
+ * 6 - Long packet discarded due to errors;
+ * 7 - CSI Combo Rx interrupt;
+ * 8 - IDI CDC FIFO overflow; remaining bits are reserved and tied to 0;
+ */
+#define IPU7_CSI_RX_ERROR_IRQ_MASK		0xfff
+
+/*
+ * 0 - VC0 frame start received
+ * 1 - VC0 frame end received
+ * 2 - VC1 frame start received
+ * 3 - VC1 frame end received
+ * 4 - VC2 frame start received
+ * 5 - VC2 frame end received
+ * 6 - VC3 frame start received
+ * 7 - VC3 frame end received
+ * 8 - VC4 frame start received
+ * 9 - VC4 frame end received
+ * 10 - VC5 frame start received
+ * 11 - VC5 frame end received
+ * 12 - VC6 frame start received
+ * 13 - VC6 frame end received
+ * 14 - VC7 frame start received
+ * 15 - VC7 frame end received
+ * 16 - VC8 frame start received
+ * 17 - VC8 frame end received
+ * 18 - VC9 frame start received
+ * 19 - VC9 frame end received
+ * 20 - VC10 frame start received
+ * 21 - VC10 frame end received
+ * 22 - VC11 frame start received
+ * 23 - VC11 frame end received
+ * 24 - VC12 frame start received
+ * 25 - VC12 frame end received
+ * 26 - VC13 frame start received
+ * 27 - VC13 frame end received
+ * 28 - VC14 frame start received
+ * 29 - VC14 frame end received
+ * 30 - VC15 frame start received
+ * 31 - VC15 frame end received
+ */
+
+#define IPU7_CSI_RX_SYNC_IRQ_MASK		0x0
+#define IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK		0x0
+
+#define CSI_RX_NUM_ERRORS_IN_IRQ		12U
+#define CSI_RX_NUM_SYNC_IN_IRQ			32U
+
+enum CSI_FE_MODE_TYPE {
+	CSI_FE_DPHY_MODE = 0,
+	CSI_FE_CPHY_MODE = 1,
+};
+
+enum CSI_FE_INPUT_MODE {
+	CSI_SENSOR_INPUT = 0,
+	CSI_MIPIGEN_INPUT = 1,
+};
+
+enum MGC_CSI_ADPL_TYPE {
+	MGC_MAPPED_2_LANES = 0,
+	MGC_MAPPED_4_LANES = 1,
+};
+
+enum CSI2HOST_SELECTION {
+	CSI2HOST_SEL_SOC = 0,
+	CSI2HOST_SEL_CSI2HOST = 1,
+};
+
+#define IPU7_ISYS_LEGACY_IRQ_CSI2(port)		(0x3 << (port))
+#define IPU7P5_ISYS_LEGACY_IRQ_CSI2(port)	(0x7 << (port))
+
+/* ---------------------------------------------------------------- */
+#define CSI_REG_BASE				0x220000
+#define CSI_REG_BASE_PORT(id)			((id) * 0x1000)
+
+/* CSI Port General Purpose Registers */
+#define CSI_REG_PORT_GPREG_SRST			0x0
+#define CSI_REG_PORT_GPREG_CSI2_SLV_REG_SRST	0x4
+#define CSI_REG_PORT_GPREG_CSI2_PORT_CONTROL	0x8
+
+#define CSI_RX_NUM_IRQ				32U
+
+#define IPU7_CSI_RX_SYNC_FS_VC			0x55555555
+#define IPU7_CSI_RX_SYNC_FE_VC			0xaaaaaaaa
+#define IPU7P5_CSI_RX_SYNC_FS_VC		0xffff
+#define IPU7P5_CSI_RX_SYNC_FE_VC		0xffff
+
+#endif /* IPU7_ISYS_CSI2_REG_H */
diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi2.c b/drivers/staging/media/ipu7/ipu7-isys-csi2.c
new file mode 100644
index 000000000000..9c16ae9a0e5b
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-csi2.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/atomic.h>
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#include "ipu7.h"
+#include "ipu7-bus.h"
+#include "ipu7-isys.h"
+#include "ipu7-isys-csi2.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-isys-csi-phy.h"
+
+static const u32 csi2_supported_codes[] = {
+	MEDIA_BUS_FMT_Y10_1X10,
+	MEDIA_BUS_FMT_RGB565_1X16,
+	MEDIA_BUS_FMT_RGB888_1X24,
+	MEDIA_BUS_FMT_UYVY8_1X16,
+	MEDIA_BUS_FMT_YUYV8_1X16,
+	MEDIA_BUS_FMT_YUYV10_1X20,
+	MEDIA_BUS_FMT_SBGGR10_1X10,
+	MEDIA_BUS_FMT_SGBRG10_1X10,
+	MEDIA_BUS_FMT_SGRBG10_1X10,
+	MEDIA_BUS_FMT_SRGGB10_1X10,
+	MEDIA_BUS_FMT_SBGGR12_1X12,
+	MEDIA_BUS_FMT_SGBRG12_1X12,
+	MEDIA_BUS_FMT_SGRBG12_1X12,
+	MEDIA_BUS_FMT_SRGGB12_1X12,
+	MEDIA_BUS_FMT_SBGGR8_1X8,
+	MEDIA_BUS_FMT_SGBRG8_1X8,
+	MEDIA_BUS_FMT_SGRBG8_1X8,
+	MEDIA_BUS_FMT_SRGGB8_1X8,
+	0,
+};
+
+s64 ipu7_isys_csi2_get_link_freq(struct ipu7_isys_csi2 *csi2)
+{
+	struct media_pad *src_pad;
+
+	src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
+	if (IS_ERR(src_pad)) {
+		dev_err(&csi2->isys->adev->auxdev.dev,
+			"can't get source pad of %s (%ld)\n",
+			csi2->asd.sd.name, PTR_ERR(src_pad));
+		return PTR_ERR(src_pad);
+	}
+
+	return v4l2_get_link_freq(src_pad, 0, 0);
+}
+
+static int csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd);
+	struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd);
+	struct device *dev = &csi2->isys->adev->auxdev.dev;
+
+	dev_dbg(dev, "csi2 subscribe event(type %u id %u)\n",
+		sub->type, sub->id);
+
+	switch (sub->type) {
+	case V4L2_EVENT_FRAME_SYNC:
+		return v4l2_event_subscribe(fh, sub, 10, NULL);
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct v4l2_subdev_core_ops csi2_sd_core_ops = {
+	.subscribe_event = csi2_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static void csi2_irq_enable(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_device *isp = csi2->isys->adev->isp;
+	unsigned int offset, mask;
+
+	/* enable CSI2 legacy error irq */
+	offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+	writel(mask, csi2->base + offset + IRQ_CTL_CLEAR);
+	writel(mask, csi2->base + offset + IRQ_CTL_MASK);
+	writel(mask, csi2->base + offset + IRQ_CTL_ENABLE);
+
+	/* enable CSI2 legacy sync irq */
+	offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_SYNC_IRQ_MASK;
+	writel(mask, csi2->base + offset + IRQ_CTL_CLEAR);
+	writel(mask, csi2->base + offset + IRQ_CTL_MASK);
+	writel(mask, csi2->base + offset + IRQ_CTL_ENABLE);
+
+	mask = IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK;
+	if (!is_ipu7(isp->hw_ver)) {
+		writel(mask, csi2->base + offset + IRQ1_CTL_CLEAR);
+		writel(mask, csi2->base + offset + IRQ1_CTL_MASK);
+		writel(mask, csi2->base + offset + IRQ1_CTL_ENABLE);
+	}
+}
+
+static void csi2_irq_disable(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_device *isp = csi2->isys->adev->isp;
+	unsigned int offset, mask;
+
+	/* disable CSI2 legacy error irq */
+	offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+	writel(mask, csi2->base + offset + IRQ_CTL_CLEAR);
+	writel(0, csi2->base + offset + IRQ_CTL_MASK);
+	writel(0, csi2->base + offset + IRQ_CTL_ENABLE);
+
+	/* disable CSI2 legacy sync irq */
+	offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_SYNC_IRQ_MASK;
+	writel(mask, csi2->base + offset + IRQ_CTL_CLEAR);
+	writel(0, csi2->base + offset + IRQ_CTL_MASK);
+	writel(0, csi2->base + offset + IRQ_CTL_ENABLE);
+
+	if (!is_ipu7(isp->hw_ver)) {
+		writel(mask, csi2->base + offset + IRQ1_CTL_CLEAR);
+		writel(0, csi2->base + offset + IRQ1_CTL_MASK);
+		writel(0, csi2->base + offset + IRQ1_CTL_ENABLE);
+	}
+}
+
+static void ipu7_isys_csi2_disable_stream(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_isys *isys = csi2->isys;
+	void __iomem *isys_base = isys->pdata->base;
+
+	ipu7_isys_csi_phy_powerdown(csi2);
+
+	writel(0x4, isys_base + IS_IO_GPREGS_BASE + CLK_DIV_FACTOR_APB_CLK);
+	csi2_irq_disable(csi2);
+}
+
+static int ipu7_isys_csi2_enable_stream(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_isys *isys = csi2->isys;
+	struct device *dev = &isys->adev->auxdev.dev;
+	void __iomem *isys_base = isys->pdata->base;
+	unsigned int port, nlanes, offset;
+	int ret;
+
+	port = csi2->port;
+	nlanes = csi2->nlanes;
+
+	offset = IS_IO_GPREGS_BASE;
+	writel(0x2, isys_base + offset + CLK_DIV_FACTOR_APB_CLK);
+	dev_dbg(dev, "port %u CLK_GATE = 0x%04x DIV_FACTOR_APB_CLK=0x%04x\n",
+		port, readl(isys_base + offset + CSI_PORT_CLK_GATE),
+		readl(isys_base + offset + CLK_DIV_FACTOR_APB_CLK));
+	if (port == 0U && nlanes == 4U && !is_ipu7(isys->adev->isp->hw_ver)) {
+		dev_dbg(dev, "CSI port %u in aggregation mode\n", port);
+		writel(0x1, isys_base + offset + CSI_PORTAB_AGGREGATION);
+	}
+
+	/* input is coming from CSI receiver (sensor) */
+	offset = IS_IO_CSI2_ADPL_PORT_BASE(port);
+	writel(CSI_SENSOR_INPUT, isys_base + offset + CSI2_ADPL_INPUT_MODE);
+	writel(1, isys_base + offset + CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN);
+
+	ret = ipu7_isys_csi_phy_powerup(csi2);
+	if (ret) {
+		dev_err(dev, "CSI-%d PHY power up failed %d\n", port, ret);
+		return ret;
+	}
+
+	csi2_irq_enable(csi2);
+
+	return 0;
+}
+
+static int ipu7_isys_csi2_set_sel(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd);
+	struct device *dev = &asd->isys->adev->auxdev.dev;
+	struct v4l2_mbus_framefmt *sink_ffmt;
+	struct v4l2_mbus_framefmt *src_ffmt;
+	struct v4l2_rect *crop;
+
+	if (sel->pad == IPU7_CSI2_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
+		return -EINVAL;
+
+	sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state,
+								 sel->pad,
+								 sel->stream);
+	if (!sink_ffmt)
+		return -EINVAL;
+
+	src_ffmt = v4l2_subdev_state_get_format(state, sel->pad, sel->stream);
+	if (!src_ffmt)
+		return -EINVAL;
+
+	crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
+	if (!crop)
+		return -EINVAL;
+
+	/* Only vertical cropping is supported */
+	sel->r.left = 0;
+	sel->r.width = sink_ffmt->width;
+	/* Non-bayer formats can't be single line cropped */
+	if (!ipu7_isys_is_bayer_format(sink_ffmt->code))
+		sel->r.top &= ~1U;
+	sel->r.height = clamp(sel->r.height & ~1U, IPU_ISYS_MIN_HEIGHT,
+			      sink_ffmt->height - sel->r.top);
+	*crop = sel->r;
+
+	/* update source pad format */
+	src_ffmt->width = sel->r.width;
+	src_ffmt->height = sel->r.height;
+	if (ipu7_isys_is_bayer_format(sink_ffmt->code))
+		src_ffmt->code = ipu7_isys_convert_bayer_order(sink_ffmt->code,
+							       sel->r.left,
+							       sel->r.top);
+	dev_dbg(dev, "set crop for %s sel: %d,%d,%d,%d code: 0x%x\n",
+		sd->name, sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+		src_ffmt->code);
+
+	return 0;
+}
+
+static int ipu7_isys_csi2_get_sel(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_mbus_framefmt *sink_ffmt;
+	struct v4l2_rect *crop;
+	int ret = 0;
+
+	if (sd->entity.pads[sel->pad].flags & MEDIA_PAD_FL_SINK)
+		return -EINVAL;
+
+	sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state,
+								 sel->pad,
+								 sel->stream);
+	if (!sink_ffmt)
+		return -EINVAL;
+
+	crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
+	if (!crop)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = sink_ffmt->width;
+		sel->r.height = sink_ffmt->height;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		sel->r = *crop;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * Maximum stream ID is 63 for now, as we use u64 bitmask to represent a set
+ * of streams.
+ */
+#define CSI2_SUBDEV_MAX_STREAM_ID 63
+
+static int ipu7_isys_csi2_enable_streams(struct v4l2_subdev *sd,
+					 struct v4l2_subdev_state *state,
+					 u32 pad, u64 streams_mask)
+{
+	struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd);
+	struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd);
+	struct v4l2_subdev *r_sd;
+	struct media_pad *rp;
+	u32 sink_pad, sink_stream;
+	int ret, i;
+
+	if (!csi2->stream_count) {
+		dev_dbg(&csi2->isys->adev->auxdev.dev,
+			"stream on CSI2-%u with %u lanes\n", csi2->port,
+			csi2->nlanes);
+		ret = ipu7_isys_csi2_enable_stream(csi2);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i <= CSI2_SUBDEV_MAX_STREAM_ID; i++) {
+		if (streams_mask & BIT_ULL(i))
+			break;
+	}
+
+	ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, i,
+						    &sink_pad, &sink_stream);
+	if (ret)
+		return ret;
+
+	rp = media_pad_remote_pad_first(&sd->entity.pads[IPU7_CSI2_PAD_SINK]);
+	r_sd = media_entity_to_v4l2_subdev(rp->entity);
+
+	ret = v4l2_subdev_enable_streams(r_sd, rp->index,
+					 BIT_ULL(sink_stream));
+	if (!ret) {
+		csi2->stream_count++;
+		return 0;
+	}
+
+	if (!csi2->stream_count)
+		ipu7_isys_csi2_disable_stream(csi2);
+
+	return ret;
+}
+
+static int ipu7_isys_csi2_disable_streams(struct v4l2_subdev *sd,
+					  struct v4l2_subdev_state *state,
+					  u32 pad, u64 streams_mask)
+{
+	struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd);
+	struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd);
+	struct v4l2_subdev *r_sd;
+	struct media_pad *rp;
+	u32 sink_pad, sink_stream;
+	int ret, i;
+
+	for (i = 0; i <= CSI2_SUBDEV_MAX_STREAM_ID; i++) {
+		if (streams_mask & BIT_ULL(i))
+			break;
+	}
+
+	ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, i,
+						    &sink_pad, &sink_stream);
+	if (ret)
+		return ret;
+
+	rp = media_pad_remote_pad_first(&sd->entity.pads[IPU7_CSI2_PAD_SINK]);
+	r_sd = media_entity_to_v4l2_subdev(rp->entity);
+
+	v4l2_subdev_disable_streams(r_sd, rp->index, BIT_ULL(sink_stream));
+
+	if (--csi2->stream_count)
+		return 0;
+
+	dev_dbg(&csi2->isys->adev->auxdev.dev,
+		"stream off CSI2-%u with %u lanes\n", csi2->port, csi2->nlanes);
+
+	ipu7_isys_csi2_disable_stream(csi2);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
+	.get_fmt = v4l2_subdev_get_fmt,
+	.set_fmt = ipu7_isys_subdev_set_fmt,
+	.get_selection = ipu7_isys_csi2_get_sel,
+	.set_selection = ipu7_isys_csi2_set_sel,
+	.enum_mbus_code = ipu7_isys_subdev_enum_mbus_code,
+	.enable_streams = ipu7_isys_csi2_enable_streams,
+	.disable_streams = ipu7_isys_csi2_disable_streams,
+	.set_routing = ipu7_isys_subdev_set_routing,
+};
+
+static const struct v4l2_subdev_ops csi2_sd_ops = {
+	.core = &csi2_sd_core_ops,
+	.pad = &csi2_sd_pad_ops,
+};
+
+static const struct media_entity_operations csi2_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+	.has_pad_interdep = v4l2_subdev_has_pad_interdep,
+};
+
+void ipu7_isys_csi2_cleanup(struct ipu7_isys_csi2 *csi2)
+{
+	if (!csi2->isys)
+		return;
+
+	v4l2_device_unregister_subdev(&csi2->asd.sd);
+	v4l2_subdev_cleanup(&csi2->asd.sd);
+	ipu7_isys_subdev_cleanup(&csi2->asd);
+	csi2->isys = NULL;
+}
+
+int ipu7_isys_csi2_init(struct ipu7_isys_csi2 *csi2,
+			struct ipu7_isys *isys,
+			void __iomem *base, unsigned int index)
+{
+	struct device *dev = &isys->adev->auxdev.dev;
+	int ret;
+
+	csi2->isys = isys;
+	csi2->base = base;
+	csi2->port = index;
+
+	if (!is_ipu7(isys->adev->isp->hw_ver))
+		csi2->legacy_irq_mask = 0x7U << (index * 3U);
+	else
+		csi2->legacy_irq_mask = 0x3U << (index * 2U);
+
+	dev_dbg(dev, "csi-%d legacy irq mask = 0x%x\n", index,
+		csi2->legacy_irq_mask);
+
+	csi2->asd.sd.entity.ops = &csi2_entity_ops;
+	csi2->asd.isys = isys;
+
+	ret = ipu7_isys_subdev_init(&csi2->asd, &csi2_sd_ops, 0,
+				    IPU7_NR_OF_CSI2_SINK_PADS,
+				    IPU7_NR_OF_CSI2_SRC_PADS);
+	if (ret)
+		return ret;
+
+	csi2->asd.source = (int)index;
+	csi2->asd.supported_codes = csi2_supported_codes;
+	snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name),
+		 IPU_ISYS_ENTITY_PREFIX " CSI2 %u", index);
+	v4l2_set_subdevdata(&csi2->asd.sd, &csi2->asd);
+
+	ret = v4l2_subdev_init_finalize(&csi2->asd.sd);
+	if (ret) {
+		dev_err(dev, "failed to init v4l2 subdev (%d)\n", ret);
+		goto isys_subdev_cleanup;
+	}
+
+	ret = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2->asd.sd);
+	if (ret) {
+		dev_err(dev, "failed to register v4l2 subdev (%d)\n", ret);
+		goto v4l2_subdev_cleanup;
+	}
+
+	return 0;
+
+v4l2_subdev_cleanup:
+	v4l2_subdev_cleanup(&csi2->asd.sd);
+isys_subdev_cleanup:
+	ipu7_isys_subdev_cleanup(&csi2->asd);
+
+	return ret;
+}
+
+void ipu7_isys_csi2_sof_event_by_stream(struct ipu7_isys_stream *stream)
+{
+	struct ipu7_isys_csi2 *csi2 = ipu7_isys_subdev_to_csi2(stream->asd);
+	struct device *dev = &stream->isys->adev->auxdev.dev;
+	struct video_device *vdev = csi2->asd.sd.devnode;
+	struct v4l2_event ev = {
+		.type = V4L2_EVENT_FRAME_SYNC,
+	};
+
+	ev.id = stream->vc;
+	ev.u.frame_sync.frame_sequence = atomic_fetch_inc(&stream->sequence);
+	v4l2_event_queue(vdev, &ev);
+
+	dev_dbg(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n",
+		csi2->port, ev.u.frame_sync.frame_sequence, stream->vc);
+}
+
+void ipu7_isys_csi2_eof_event_by_stream(struct ipu7_isys_stream *stream)
+{
+	struct ipu7_isys_csi2 *csi2 = ipu7_isys_subdev_to_csi2(stream->asd);
+	struct device *dev = &stream->isys->adev->auxdev.dev;
+	u32 frame_sequence = atomic_read(&stream->sequence);
+
+	dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n",
+		csi2->port, frame_sequence);
+}
+
+int ipu7_isys_csi2_get_remote_desc(u32 source_stream,
+				   struct ipu7_isys_csi2 *csi2,
+				   struct media_entity *source_entity,
+				   struct v4l2_mbus_frame_desc_entry *entry,
+				   int *nr_queues)
+{
+	struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
+	struct device *dev = &csi2->isys->adev->auxdev.dev;
+	struct v4l2_mbus_frame_desc desc;
+	struct v4l2_subdev *source;
+	struct media_pad *pad;
+	unsigned int i;
+	int ret;
+
+	source = media_entity_to_v4l2_subdev(source_entity);
+	if (!source)
+		return -EPIPE;
+
+	pad = media_pad_remote_pad_first(&csi2->asd.pad[IPU7_CSI2_PAD_SINK]);
+	if (!pad)
+		return -EPIPE;
+
+	ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc);
+	if (ret)
+		return ret;
+
+	if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		dev_err(dev, "Unsupported frame descriptor type\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < desc.num_entries; i++) {
+		if (source_stream == desc.entry[i].stream) {
+			desc_entry = &desc.entry[i];
+			break;
+		}
+	}
+
+	if (!desc_entry) {
+		dev_err(dev, "Failed to find stream %u from remote subdev\n",
+			source_stream);
+		return -EINVAL;
+	}
+
+	if (desc_entry->bus.csi2.vc >= IPU7_NR_OF_CSI2_VC) {
+		dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc);
+		return -EINVAL;
+	}
+
+	*entry = *desc_entry;
+
+	for (i = 0; i < desc.num_entries; i++) {
+		if (desc_entry->bus.csi2.vc == desc.entry[i].bus.csi2.vc)
+			(*nr_queues)++;
+	}
+
+	return 0;
+}
diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi2.h b/drivers/staging/media/ipu7/ipu7-isys-csi2.h
new file mode 100644
index 000000000000..6c23b80f92a2
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-csi2.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_CSI2_H
+#define IPU7_ISYS_CSI2_H
+
+#include <linux/container_of.h>
+#include <linux/types.h>
+
+#include "ipu7-isys-subdev.h"
+#include "ipu7-isys-video.h"
+
+struct ipu7_isys;
+struct ipu7_isys_csi2_pdata;
+struct ipu7_isys_stream;
+
+#define IPU7_NR_OF_CSI2_VC		16U
+#define INVALID_VC_ID			-1
+#define IPU7_NR_OF_CSI2_SINK_PADS	1U
+#define IPU7_CSI2_PAD_SINK		0U
+#define IPU7_NR_OF_CSI2_SRC_PADS	8U
+#define IPU7_CSI2_PAD_SRC		1U
+#define IPU7_NR_OF_CSI2_PADS		(IPU7_NR_OF_CSI2_SINK_PADS + \
+					 IPU7_NR_OF_CSI2_SRC_PADS)
+
+/*
+ * struct ipu7_isys_csi2
+ *
+ * @nlanes: number of lanes in the receiver
+ */
+struct ipu7_isys_csi2 {
+	struct ipu7_isys_subdev asd;
+	struct ipu7_isys_csi2_pdata *pdata;
+	struct ipu7_isys *isys;
+	struct ipu7_isys_video av[IPU7_NR_OF_CSI2_SRC_PADS];
+
+	void __iomem *base;
+	u32 receiver_errors;
+	u32 legacy_irq_mask;
+	unsigned int nlanes;
+	unsigned int port;
+	unsigned int phy_mode;
+	unsigned int stream_count;
+};
+
+#define ipu7_isys_subdev_to_csi2(__sd)			\
+	container_of(__sd, struct ipu7_isys_csi2, asd)
+
+#define to_ipu7_isys_csi2(__asd) container_of(__asd, struct ipu7_isys_csi2, asd)
+
+s64 ipu7_isys_csi2_get_link_freq(struct ipu7_isys_csi2 *csi2);
+int ipu7_isys_csi2_init(struct ipu7_isys_csi2 *csi2, struct ipu7_isys *isys,
+			void __iomem *base, unsigned int index);
+void ipu7_isys_csi2_cleanup(struct ipu7_isys_csi2 *csi2);
+void ipu7_isys_csi2_sof_event_by_stream(struct ipu7_isys_stream *stream);
+void ipu7_isys_csi2_eof_event_by_stream(struct ipu7_isys_stream *stream);
+int ipu7_isys_csi2_get_remote_desc(u32 source_stream,
+				   struct ipu7_isys_csi2 *csi2,
+				   struct media_entity *source_entity,
+				   struct v4l2_mbus_frame_desc_entry *entry,
+				   int *nr_queues);
+#endif /* IPU7_ISYS_CSI2_H */
diff --git a/drivers/staging/media/ipu7/ipu7-isys-queue.c b/drivers/staging/media/ipu7/ipu7-isys-queue.c
new file mode 100644
index 000000000000..7046c29141f8
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-queue.c
@@ -0,0 +1,829 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/lockdep.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "abi/ipu7_fw_isys_abi.h"
+
+#include "ipu7-bus.h"
+#include "ipu7-dma.h"
+#include "ipu7-fw-isys.h"
+#include "ipu7-isys.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-isys-video.h"
+#include "ipu7-platform-regs.h"
+
+#define IPU_MAX_FRAME_COUNTER	(U8_MAX + 1)
+
+static int ipu7_isys_buf_init(struct vb2_buffer *vb)
+{
+	struct ipu7_isys *isys = vb2_get_drv_priv(vb->vb2_queue);
+	struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
+	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+	struct ipu7_isys_video_buffer *ivb =
+		vb2_buffer_to_ipu7_isys_video_buffer(vvb);
+	int ret;
+
+	ret = ipu7_dma_map_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0);
+	if (ret)
+		return ret;
+
+	ivb->dma_addr = sg_dma_address(sg->sgl);
+
+	return 0;
+}
+
+static void ipu7_isys_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct ipu7_isys *isys = vb2_get_drv_priv(vb->vb2_queue);
+	struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
+	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+	struct ipu7_isys_video_buffer *ivb =
+		vb2_buffer_to_ipu7_isys_video_buffer(vvb);
+
+	ivb->dma_addr = 0;
+	ipu7_dma_unmap_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0);
+}
+
+static int ipu7_isys_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+				 unsigned int *num_planes, unsigned int sizes[],
+				 struct device *alloc_devs[])
+{
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(q);
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	u32 size = av->pix_fmt.sizeimage;
+
+	/* num_planes == 0: we're being called through VIDIOC_REQBUFS */
+	if (!*num_planes) {
+		sizes[0] = size;
+	} else if (sizes[0] < size) {
+		dev_dbg(dev, "%s: queue setup: size %u < %u\n",
+			av->vdev.name, sizes[0], size);
+		return -EINVAL;
+	}
+
+	*num_planes = 1;
+
+	return 0;
+}
+
+static int ipu7_isys_buf_prepare(struct vb2_buffer *vb)
+{
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	u32 bytesperline = av->pix_fmt.bytesperline;
+	u32 height = av->pix_fmt.height;
+
+	dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n",
+		av->vdev.name, av->pix_fmt.sizeimage, vb2_plane_size(vb, 0));
+
+	if (av->pix_fmt.sizeimage > vb2_plane_size(vb, 0))
+		return -EINVAL;
+
+	dev_dbg(dev, "buffer: %s: bytesperline %u, height %u\n",
+		av->vdev.name, bytesperline, height);
+	vb2_set_plane_payload(vb, 0, bytesperline * height);
+
+	return 0;
+}
+
+/*
+ * Queue a buffer list back to incoming or active queues. The buffers
+ * are removed from the buffer list.
+ */
+void ipu7_isys_buffer_list_queue(struct ipu7_isys_buffer_list *bl,
+				 unsigned long op_flags,
+				 enum vb2_buffer_state state)
+{
+	struct ipu7_isys_buffer *ib, *ib_safe;
+	unsigned long flags;
+	bool first = true;
+
+	if (!bl)
+		return;
+
+	WARN_ON_ONCE(!bl->nbufs);
+	WARN_ON_ONCE(op_flags & IPU_ISYS_BUFFER_LIST_FL_ACTIVE &&
+		     op_flags & IPU_ISYS_BUFFER_LIST_FL_INCOMING);
+
+	list_for_each_entry_safe(ib, ib_safe, &bl->head, head) {
+		struct ipu7_isys_video *av;
+
+		struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+		struct ipu7_isys_queue *aq =
+			vb2_queue_to_isys_queue(vb->vb2_queue);
+
+		av = ipu7_isys_queue_to_video(aq);
+		spin_lock_irqsave(&aq->lock, flags);
+		list_del(&ib->head);
+		if (op_flags & IPU_ISYS_BUFFER_LIST_FL_ACTIVE)
+			list_add(&ib->head, &aq->active);
+		else if (op_flags & IPU_ISYS_BUFFER_LIST_FL_INCOMING)
+			list_add_tail(&ib->head, &aq->incoming);
+		spin_unlock_irqrestore(&aq->lock, flags);
+
+		if (op_flags & IPU_ISYS_BUFFER_LIST_FL_SET_STATE)
+			vb2_buffer_done(vb, state);
+
+		if (first) {
+			dev_dbg(&av->isys->adev->auxdev.dev,
+				"queue buf list %p flags %lx, s %d, %d bufs\n",
+				bl, op_flags, state, bl->nbufs);
+			first = false;
+		}
+
+		bl->nbufs--;
+	}
+
+	WARN_ON(bl->nbufs);
+}
+
+/*
+ * flush_firmware_streamon_fail() - Flush in cases where requests may
+ * have been queued to firmware and the *firmware streamon fails for a
+ * reason or another.
+ */
+static void flush_firmware_streamon_fail(struct ipu7_isys_stream *stream)
+{
+	struct ipu7_isys_queue *aq;
+	unsigned long flags;
+
+	lockdep_assert_held(&stream->mutex);
+
+	list_for_each_entry(aq, &stream->queues, node) {
+		struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+		struct device *dev = &av->isys->adev->auxdev.dev;
+		struct ipu7_isys_buffer *ib, *ib_safe;
+
+		spin_lock_irqsave(&aq->lock, flags);
+		list_for_each_entry_safe(ib, ib_safe, &aq->active, head) {
+			struct vb2_buffer *vb =
+				ipu7_isys_buffer_to_vb2_buffer(ib);
+
+			list_del(&ib->head);
+			if (av->streaming) {
+				dev_dbg(dev,
+					"%s: queue buffer %u back to incoming\n",
+					av->vdev.name, vb->index);
+				/* Queue already streaming, return to driver. */
+				list_add(&ib->head, &aq->incoming);
+				continue;
+			}
+			/* Queue not yet streaming, return to user. */
+			dev_dbg(dev, "%s: return %u back to videobuf2\n",
+				av->vdev.name, vb->index);
+			vb2_buffer_done(ipu7_isys_buffer_to_vb2_buffer(ib),
+					VB2_BUF_STATE_QUEUED);
+		}
+		spin_unlock_irqrestore(&aq->lock, flags);
+	}
+}
+
+/*
+ * Attempt obtaining a buffer list from the incoming queues, a list of buffers
+ * that contains one entry from each video buffer queue. If a buffer can't be
+ * obtained from every queue, the buffers are returned back to the queue.
+ */
+static int buffer_list_get(struct ipu7_isys_stream *stream,
+			   struct ipu7_isys_buffer_list *bl)
+{
+	unsigned long buf_flag = IPU_ISYS_BUFFER_LIST_FL_INCOMING;
+	struct device *dev = &stream->isys->adev->auxdev.dev;
+	struct ipu7_isys_queue *aq;
+	unsigned long flags;
+
+	bl->nbufs = 0;
+	INIT_LIST_HEAD(&bl->head);
+
+	list_for_each_entry(aq, &stream->queues, node) {
+		struct ipu7_isys_buffer *ib;
+
+		spin_lock_irqsave(&aq->lock, flags);
+		if (list_empty(&aq->incoming)) {
+			spin_unlock_irqrestore(&aq->lock, flags);
+			if (!list_empty(&bl->head))
+				ipu7_isys_buffer_list_queue(bl, buf_flag, 0);
+			return -ENODATA;
+		}
+
+		ib = list_last_entry(&aq->incoming,
+				     struct ipu7_isys_buffer, head);
+
+		dev_dbg(dev, "buffer: %s: buffer %u\n",
+			ipu7_isys_queue_to_video(aq)->vdev.name,
+			ipu7_isys_buffer_to_vb2_buffer(ib)->index);
+		list_del(&ib->head);
+		list_add(&ib->head, &bl->head);
+		spin_unlock_irqrestore(&aq->lock, flags);
+
+		bl->nbufs++;
+	}
+
+	dev_dbg(dev, "get buffer list %p, %u buffers\n", bl, bl->nbufs);
+
+	return 0;
+}
+
+static void ipu7_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
+					      struct ipu7_insys_buffset *set)
+{
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+	struct ipu7_isys_video_buffer *ivb =
+		vb2_buffer_to_ipu7_isys_video_buffer(vvb);
+
+	set->output_pins[aq->fw_output].addr = ivb->dma_addr;
+	set->output_pins[aq->fw_output].user_token = (uintptr_t)set;
+}
+
+/*
+ * Convert a buffer list to a isys fw ABI framebuffer set. The
+ * buffer list is not modified.
+ */
+#define IPU_ISYS_FRAME_NUM_THRESHOLD	(30)
+void ipu7_isys_buffer_to_fw_frame_buff(struct ipu7_insys_buffset *set,
+				       struct ipu7_isys_stream *stream,
+				       struct ipu7_isys_buffer_list *bl)
+{
+	struct ipu7_isys_buffer *ib;
+	u32 buf_id;
+
+	WARN_ON(!bl->nbufs);
+
+	set->skip_frame = 0;
+	set->capture_msg_map = IPU_INSYS_FRAME_ENABLE_MSG_SEND_RESP |
+			       IPU_INSYS_FRAME_ENABLE_MSG_SEND_IRQ;
+
+	buf_id = atomic_fetch_inc(&stream->buf_id);
+	set->frame_id = buf_id % IPU_MAX_FRAME_COUNTER;
+
+	list_for_each_entry(ib, &bl->head, head) {
+		struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+
+		ipu7_isys_buf_to_fw_frame_buf_pin(vb, set);
+	}
+}
+
+/* Start streaming for real. The buffer list must be available. */
+static int ipu7_isys_stream_start(struct ipu7_isys_video *av,
+				  struct ipu7_isys_buffer_list *bl, bool error)
+{
+	struct ipu7_isys_stream *stream = av->stream;
+	struct device *dev = &stream->isys->adev->auxdev.dev;
+	struct ipu7_isys_buffer_list __bl;
+	int ret;
+
+	mutex_lock(&stream->isys->stream_mutex);
+
+	ret = ipu7_isys_video_set_streaming(av, 1, bl);
+	mutex_unlock(&stream->isys->stream_mutex);
+	if (ret)
+		goto out_requeue;
+
+	stream->streaming = 1;
+
+	bl = &__bl;
+
+	do {
+		struct ipu7_insys_buffset *buf = NULL;
+		struct isys_fw_msgs *msg;
+		enum ipu7_insys_send_type send_type =
+			IPU_INSYS_SEND_TYPE_STREAM_CAPTURE;
+
+		ret = buffer_list_get(stream, bl);
+		if (ret < 0)
+			break;
+
+		msg = ipu7_get_fw_msg_buf(stream);
+		if (!msg)
+			return -ENOMEM;
+
+		buf = &msg->fw_msg.frame;
+
+		ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl);
+
+		ipu7_fw_isys_dump_frame_buff_set(dev, buf,
+						 stream->nr_output_pins);
+
+		ipu7_isys_buffer_list_queue(bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE,
+					    0);
+
+		ret = ipu7_fw_isys_complex_cmd(stream->isys,
+					       stream->stream_handle, buf,
+					       msg->dma_addr, sizeof(*buf),
+					       send_type);
+	} while (!WARN_ON(ret));
+
+	return 0;
+
+out_requeue:
+	if (bl && bl->nbufs)
+		ipu7_isys_buffer_list_queue(bl,
+					    IPU_ISYS_BUFFER_LIST_FL_INCOMING |
+					    (error ?
+					     IPU_ISYS_BUFFER_LIST_FL_SET_STATE :
+					     0), error ? VB2_BUF_STATE_ERROR :
+					    VB2_BUF_STATE_QUEUED);
+	flush_firmware_streamon_fail(stream);
+
+	return ret;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+	struct ipu7_isys_video_buffer *ivb =
+		vb2_buffer_to_ipu7_isys_video_buffer(vvb);
+	struct media_pipeline *media_pipe =
+		media_entity_pipeline(&av->vdev.entity);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu7_isys_stream *stream = av->stream;
+	struct ipu7_isys_buffer *ib = &ivb->ib;
+	struct ipu7_insys_buffset *buf = NULL;
+	struct ipu7_isys_buffer_list bl;
+	struct isys_fw_msgs *msg;
+	unsigned long flags;
+	dma_addr_t dma;
+	int ret;
+
+	dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);
+
+	dma = ivb->dma_addr;
+	dev_dbg(dev, "iova: iova %pad\n", &dma);
+
+	spin_lock_irqsave(&aq->lock, flags);
+	list_add(&ib->head, &aq->incoming);
+	spin_unlock_irqrestore(&aq->lock, flags);
+
+	if (!media_pipe || !vb->vb2_queue->start_streaming_called) {
+		dev_dbg(dev, "media pipeline is not ready for %s\n",
+			av->vdev.name);
+		return;
+	}
+
+	mutex_lock(&stream->mutex);
+
+	if (stream->nr_streaming != stream->nr_queues) {
+		dev_dbg(dev, "not streaming yet, adding to incoming\n");
+		goto out;
+	}
+
+	/*
+	 * We just put one buffer to the incoming list of this queue
+	 * (above). Let's see whether all queues in the pipeline would
+	 * have a buffer.
+	 */
+	ret = buffer_list_get(stream, &bl);
+	if (ret < 0) {
+		dev_dbg(dev, "No buffers available\n");
+		goto out;
+	}
+
+	msg = ipu7_get_fw_msg_buf(stream);
+	if (!msg) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	buf = &msg->fw_msg.frame;
+
+	ipu7_isys_buffer_to_fw_frame_buff(buf, stream, &bl);
+
+	ipu7_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
+
+	if (!stream->streaming) {
+		ret = ipu7_isys_stream_start(av, &bl, true);
+		if (ret)
+			dev_err(dev, "stream start failed.\n");
+		goto out;
+	}
+
+	/*
+	 * We must queue the buffers in the buffer list to the
+	 * appropriate video buffer queues BEFORE passing them to the
+	 * firmware since we could get a buffer event back before we
+	 * have queued them ourselves to the active queue.
+	 */
+	ipu7_isys_buffer_list_queue(&bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
+
+	ret = ipu7_fw_isys_complex_cmd(stream->isys, stream->stream_handle,
+				       buf, msg->dma_addr, sizeof(*buf),
+				       IPU_INSYS_SEND_TYPE_STREAM_CAPTURE);
+	if (ret < 0)
+		dev_err(dev, "send stream capture failed\n");
+
+out:
+	mutex_unlock(&stream->mutex);
+}
+
+static int ipu7_isys_link_fmt_validate(struct ipu7_isys_queue *aq)
+{
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct media_pad *remote_pad =
+		media_pad_remote_pad_first(av->vdev.entity.pads);
+	struct v4l2_mbus_framefmt format;
+	struct v4l2_subdev *sd;
+	u32 r_stream, code;
+	int ret;
+
+	if (!remote_pad)
+		return -ENOTCONN;
+
+	sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+	r_stream = ipu7_isys_get_src_stream_by_src_pad(sd, remote_pad->index);
+
+	ret = ipu7_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream,
+					   &format);
+	if (ret) {
+		dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n",
+			sd->entity.name, remote_pad->index, r_stream);
+		return ret;
+	}
+
+	if (format.width != av->pix_fmt.width ||
+	    format.height != av->pix_fmt.height) {
+		dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n",
+			av->pix_fmt.width, av->pix_fmt.height, format.width,
+			format.height);
+		return -EINVAL;
+	}
+
+	code = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat)->code;
+	if (format.code != code) {
+		dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n",
+			code, format.code);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void return_buffers(struct ipu7_isys_queue *aq,
+			   enum vb2_buffer_state state)
+{
+	struct ipu7_isys_buffer *ib;
+	struct vb2_buffer *vb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&aq->lock, flags);
+	/*
+	 * Something went wrong (FW crash / HW hang / not all buffers
+	 * returned from isys) if there are still buffers queued in active
+	 * queue. We have to clean up places a bit.
+	 */
+	while (!list_empty(&aq->active)) {
+		ib = list_last_entry(&aq->active, struct ipu7_isys_buffer,
+				     head);
+		vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+
+		list_del(&ib->head);
+		spin_unlock_irqrestore(&aq->lock, flags);
+
+		vb2_buffer_done(vb, state);
+
+		spin_lock_irqsave(&aq->lock, flags);
+	}
+
+	while (!list_empty(&aq->incoming)) {
+		ib = list_last_entry(&aq->incoming, struct ipu7_isys_buffer,
+				     head);
+		vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+		list_del(&ib->head);
+		spin_unlock_irqrestore(&aq->lock, flags);
+
+		vb2_buffer_done(vb, state);
+
+		spin_lock_irqsave(&aq->lock, flags);
+	}
+
+	spin_unlock_irqrestore(&aq->lock, flags);
+}
+
+static void ipu7_isys_stream_cleanup(struct ipu7_isys_video *av)
+{
+	video_device_pipeline_stop(&av->vdev);
+	ipu7_isys_put_stream(av->stream);
+	av->stream = NULL;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(q);
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	const struct ipu7_isys_pixelformat *pfmt =
+		ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
+	struct ipu7_isys_buffer_list __bl, *bl = NULL;
+	struct ipu7_isys_stream *stream;
+	struct media_entity *source_entity = NULL;
+	int nr_queues, ret;
+
+	dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",
+		av->vdev.name, av->pix_fmt.width, av->pix_fmt.height,
+		pfmt->css_pixelformat);
+
+	ret = ipu7_isys_setup_video(av, &source_entity, &nr_queues);
+	if (ret < 0) {
+		dev_dbg(dev, "failed to setup video\n");
+		goto out_return_buffers;
+	}
+
+	ret = ipu7_isys_link_fmt_validate(aq);
+	if (ret) {
+		dev_dbg(dev,
+			"%s: link format validation failed (%d)\n",
+			av->vdev.name, ret);
+		goto out_pipeline_stop;
+	}
+
+	stream = av->stream;
+	mutex_lock(&stream->mutex);
+	if (!stream->nr_streaming) {
+		ret = ipu7_isys_video_prepare_stream(av, source_entity,
+						     nr_queues);
+		if (ret) {
+			mutex_unlock(&stream->mutex);
+			goto out_pipeline_stop;
+		}
+	}
+
+	stream->nr_streaming++;
+	dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,
+		stream->nr_queues);
+
+	list_add(&aq->node, &stream->queues);
+
+	if (stream->nr_streaming != stream->nr_queues)
+		goto out;
+
+	bl = &__bl;
+	ret = buffer_list_get(stream, bl);
+	if (ret < 0) {
+		dev_warn(dev, "no buffer available, DRIVER BUG?\n");
+		goto out;
+	}
+
+	ret = ipu7_isys_fw_open(av->isys);
+	if (ret)
+		goto out_stream_start;
+
+	ipu7_isys_setup_hw(av->isys);
+
+	ret = ipu7_isys_stream_start(av, bl, false);
+	if (ret)
+		goto out_isys_fw_close;
+
+out:
+	mutex_unlock(&stream->mutex);
+
+	return 0;
+
+out_isys_fw_close:
+	ipu7_isys_fw_close(av->isys);
+
+out_stream_start:
+	list_del(&aq->node);
+	stream->nr_streaming--;
+	mutex_unlock(&stream->mutex);
+
+out_pipeline_stop:
+	ipu7_isys_stream_cleanup(av);
+
+out_return_buffers:
+	return_buffers(aq, VB2_BUF_STATE_QUEUED);
+
+	return ret;
+}
+
+static void stop_streaming(struct vb2_queue *q)
+{
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(q);
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct ipu7_isys_stream *stream = av->stream;
+
+	mutex_lock(&stream->mutex);
+	mutex_lock(&av->isys->stream_mutex);
+	if (stream->nr_streaming == stream->nr_queues && stream->streaming)
+		ipu7_isys_video_set_streaming(av, 0, NULL);
+	mutex_unlock(&av->isys->stream_mutex);
+
+	stream->nr_streaming--;
+	list_del(&aq->node);
+	stream->streaming = 0;
+
+	mutex_unlock(&stream->mutex);
+
+	ipu7_isys_stream_cleanup(av);
+
+	return_buffers(aq, VB2_BUF_STATE_ERROR);
+
+	ipu7_isys_fw_close(av->isys);
+}
+
+static unsigned int
+get_sof_sequence_by_timestamp(struct ipu7_isys_stream *stream, u64 time)
+{
+	struct ipu7_isys *isys = stream->isys;
+	struct device *dev = &isys->adev->auxdev.dev;
+	unsigned int i;
+
+	/*
+	 * The timestamp is invalid as no TSC in some FPGA platform,
+	 * so get the sequence from pipeline directly in this case.
+	 */
+	if (time == 0)
+		return atomic_read(&stream->sequence) - 1;
+
+	for (i = 0; i < IPU_ISYS_MAX_PARALLEL_SOF; i++)
+		if (time == stream->seq[i].timestamp) {
+			dev_dbg(dev, "SOF: using seq nr %u for ts %llu\n",
+				stream->seq[i].sequence, time);
+			return stream->seq[i].sequence;
+		}
+
+	dev_dbg(dev, "SOF: looking for %llu\n", time);
+	for (i = 0; i < IPU_ISYS_MAX_PARALLEL_SOF; i++)
+		dev_dbg(dev, "SOF: sequence %u, timestamp value %llu\n",
+			stream->seq[i].sequence, stream->seq[i].timestamp);
+	dev_dbg(dev, "SOF sequence number not found\n");
+
+	return atomic_read(&stream->sequence) - 1;
+}
+
+static u64 get_sof_ns_delta(struct ipu7_isys_video *av, u64 time)
+{
+	struct ipu7_bus_device *adev = av->isys->adev;
+	struct ipu7_device *isp = adev->isp;
+	u64 delta, tsc_now;
+
+	ipu_buttress_tsc_read(isp, &tsc_now);
+	if (!tsc_now)
+		return 0;
+
+	delta = tsc_now - time;
+
+	return ipu_buttress_tsc_ticks_to_ns(delta, isp);
+}
+
+static void ipu7_isys_buf_calc_sequence_time(struct ipu7_isys_buffer *ib,
+					     u64 time)
+{
+	struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu7_isys_stream *stream = av->stream;
+	u64 ns;
+	u32 sequence;
+
+	ns = ktime_get_ns() - get_sof_ns_delta(av, time);
+	sequence = get_sof_sequence_by_timestamp(stream, time);
+
+	vbuf->vb2_buf.timestamp = ns;
+	vbuf->sequence = sequence;
+
+	dev_dbg(dev, "buf: %s: buffer done, CPU-timestamp:%lld, sequence:%d\n",
+		av->vdev.name, ktime_get_ns(), sequence);
+	dev_dbg(dev, "index:%d, vbuf timestamp:%lld\n", vb->index,
+		vbuf->vb2_buf.timestamp);
+}
+
+static void ipu7_isys_queue_buf_done(struct ipu7_isys_buffer *ib)
+{
+	struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+
+	if (atomic_read(&ib->str2mmio_flag)) {
+		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+		/*
+		 * Operation on buffer is ended with error and will be reported
+		 * to the userspace when it is de-queued
+		 */
+		atomic_set(&ib->str2mmio_flag, 0);
+	} else {
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+}
+
+void ipu7_isys_queue_buf_ready(struct ipu7_isys_stream *stream,
+			       struct ipu7_insys_resp *info)
+{
+	struct ipu7_isys_queue *aq = stream->output_pins[info->pin_id].aq;
+	u64 time = ((u64)info->timestamp[1] << 32 | info->timestamp[0]);
+	struct ipu7_isys *isys = stream->isys;
+	struct device *dev = &isys->adev->auxdev.dev;
+	struct ipu7_isys_buffer *ib;
+	struct vb2_buffer *vb;
+	unsigned long flags;
+	bool first = true;
+	struct vb2_v4l2_buffer *buf;
+
+	dev_dbg(dev, "buffer: %s: received buffer %8.8x %d\n",
+		ipu7_isys_queue_to_video(aq)->vdev.name, info->pin.addr,
+		info->frame_id);
+
+	spin_lock_irqsave(&aq->lock, flags);
+	if (list_empty(&aq->active)) {
+		spin_unlock_irqrestore(&aq->lock, flags);
+		dev_err(dev, "active queue empty\n");
+		return;
+	}
+
+	list_for_each_entry_reverse(ib, &aq->active, head) {
+		struct ipu7_isys_video_buffer *ivb;
+		struct vb2_v4l2_buffer *vvb;
+		dma_addr_t addr;
+
+		vb = ipu7_isys_buffer_to_vb2_buffer(ib);
+		vvb = to_vb2_v4l2_buffer(vb);
+		ivb = vb2_buffer_to_ipu7_isys_video_buffer(vvb);
+		addr = ivb->dma_addr;
+
+		if (info->pin.addr != addr) {
+			if (first)
+				dev_err(dev, "Unexpected buffer address %pad\n",
+					&addr);
+
+			first = false;
+			continue;
+		}
+
+		dev_dbg(dev, "buffer: found buffer %pad\n", &addr);
+
+		buf = to_vb2_v4l2_buffer(vb);
+		buf->field = V4L2_FIELD_NONE;
+
+		list_del(&ib->head);
+		spin_unlock_irqrestore(&aq->lock, flags);
+
+		ipu7_isys_buf_calc_sequence_time(ib, time);
+
+		ipu7_isys_queue_buf_done(ib);
+
+		return;
+	}
+
+	dev_err(dev, "Failed to find a matching video buffer\n");
+
+	spin_unlock_irqrestore(&aq->lock, flags);
+}
+
+static const struct vb2_ops ipu7_isys_queue_ops = {
+	.queue_setup = ipu7_isys_queue_setup,
+	.buf_init = ipu7_isys_buf_init,
+	.buf_prepare = ipu7_isys_buf_prepare,
+	.buf_cleanup = ipu7_isys_buf_cleanup,
+	.start_streaming = start_streaming,
+	.stop_streaming = stop_streaming,
+	.buf_queue = buf_queue,
+};
+
+int ipu7_isys_queue_init(struct ipu7_isys_queue *aq)
+{
+	struct ipu7_isys *isys = ipu7_isys_queue_to_video(aq)->isys;
+	struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq);
+	struct ipu7_bus_device *adev = isys->adev;
+	int ret;
+
+	if (!aq->vbq.io_modes)
+		aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF;
+
+	aq->vbq.drv_priv = isys;
+	aq->vbq.ops = &ipu7_isys_queue_ops;
+	aq->vbq.lock = &av->mutex;
+	aq->vbq.mem_ops = &vb2_dma_sg_memops;
+	aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	aq->vbq.min_queued_buffers = 1;
+	aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
+	ret = vb2_queue_init(&aq->vbq);
+	if (ret)
+		return ret;
+
+	aq->dev = &adev->auxdev.dev;
+	aq->vbq.dev = &adev->isp->pdev->dev;
+	spin_lock_init(&aq->lock);
+	INIT_LIST_HEAD(&aq->active);
+	INIT_LIST_HEAD(&aq->incoming);
+
+	return 0;
+}
diff --git a/drivers/staging/media/ipu7/ipu7-isys-queue.h b/drivers/staging/media/ipu7/ipu7-isys-queue.h
new file mode 100644
index 000000000000..0cb08a38f756
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-queue.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_QUEUE_H
+#define IPU7_ISYS_QUEUE_H
+
+#include <linux/atomic.h>
+#include <linux/container_of.h>
+#include <linux/list.h>
+#include <linux/spinlock_types.h>
+
+#include <media/videobuf2-v4l2.h>
+
+struct device;
+struct ipu7_isys_stream;
+struct ipu7_insys_resp;
+struct ipu7_insys_buffset;
+
+struct ipu7_isys_queue {
+	struct vb2_queue vbq;
+	struct list_head node;
+	struct device *dev;
+	spinlock_t lock;
+	struct list_head active;
+	struct list_head incoming;
+	unsigned int fw_output;
+};
+
+struct ipu7_isys_buffer {
+	struct list_head head;
+	atomic_t str2mmio_flag;
+};
+
+struct ipu7_isys_video_buffer {
+	struct vb2_v4l2_buffer vb_v4l2;
+	struct ipu7_isys_buffer ib;
+	dma_addr_t dma_addr;
+};
+
+#define IPU_ISYS_BUFFER_LIST_FL_INCOMING	BIT(0)
+#define IPU_ISYS_BUFFER_LIST_FL_ACTIVE	BIT(1)
+#define IPU_ISYS_BUFFER_LIST_FL_SET_STATE	BIT(2)
+
+struct ipu7_isys_buffer_list {
+	struct list_head head;
+	unsigned int nbufs;
+};
+
+#define vb2_queue_to_isys_queue(__vb2)				\
+	container_of(__vb2, struct ipu7_isys_queue, vbq)
+
+#define ipu7_isys_to_isys_video_buffer(__ib)			\
+	container_of(__ib, struct ipu7_isys_video_buffer, ib)
+
+#define vb2_buffer_to_ipu7_isys_video_buffer(__vvb)			\
+	container_of(__vvb, struct ipu7_isys_video_buffer, vb_v4l2)
+
+#define ipu7_isys_buffer_to_vb2_buffer(__ib)				\
+	(&ipu7_isys_to_isys_video_buffer(__ib)->vb_v4l2.vb2_buf)
+
+void ipu7_isys_buffer_list_queue(struct ipu7_isys_buffer_list *bl,
+				 unsigned long op_flags,
+				 enum vb2_buffer_state state);
+void ipu7_isys_buffer_to_fw_frame_buff(struct ipu7_insys_buffset *set,
+				       struct ipu7_isys_stream *stream,
+				       struct ipu7_isys_buffer_list *bl);
+void ipu7_isys_queue_buf_ready(struct ipu7_isys_stream *stream,
+			       struct ipu7_insys_resp *info);
+int ipu7_isys_queue_init(struct ipu7_isys_queue *aq);
+#endif /* IPU7_ISYS_QUEUE_H */
diff --git a/drivers/staging/media/ipu7/ipu7-isys-subdev.c b/drivers/staging/media/ipu7/ipu7-isys-subdev.c
new file mode 100644
index 000000000000..2ef8b20574da
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-subdev.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/minmax.h>
+#include <linux/types.h>
+
+#include <media/media-entity.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include <uapi/linux/media-bus-format.h>
+
+#include "ipu7-bus.h"
+#include "ipu7-isys.h"
+#include "ipu7-isys-subdev.h"
+
+unsigned int ipu7_isys_mbus_code_to_mipi(u32 code)
+{
+	switch (code) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		return MIPI_CSI2_DT_RGB565;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		return MIPI_CSI2_DT_RGB888;
+	case MEDIA_BUS_FMT_YUYV10_1X20:
+		return MIPI_CSI2_DT_YUV422_10B;
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+	case MEDIA_BUS_FMT_YUYV8_1X16:
+		return MIPI_CSI2_DT_YUV422_8B;
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+		return MIPI_CSI2_DT_RAW12;
+	case MEDIA_BUS_FMT_Y10_1X10:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		return MIPI_CSI2_DT_RAW10;
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+		return MIPI_CSI2_DT_RAW8;
+	default:
+		WARN_ON(1);
+		return 0xffff;
+	}
+}
+
+bool ipu7_isys_is_bayer_format(u32 code)
+{
+	switch (ipu7_isys_mbus_code_to_mipi(code)) {
+	case MIPI_CSI2_DT_RAW8:
+	case MIPI_CSI2_DT_RAW10:
+	case MIPI_CSI2_DT_RAW12:
+	case MIPI_CSI2_DT_RAW14:
+	case MIPI_CSI2_DT_RAW16:
+	case MIPI_CSI2_DT_RAW20:
+	case MIPI_CSI2_DT_RAW24:
+	case MIPI_CSI2_DT_RAW28:
+		return true;
+	default:
+		return false;
+	}
+}
+
+u32 ipu7_isys_convert_bayer_order(u32 code, int x, int y)
+{
+	static const u32 code_map[] = {
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+	};
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(code_map); i++)
+		if (code_map[i] == code)
+			break;
+
+	if (WARN_ON(i == ARRAY_SIZE(code_map)))
+		return code;
+
+	return code_map[i ^ ((((u32)y & 1U) << 1U) | ((u32)x & 1U))];
+}
+
+int ipu7_isys_subdev_set_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *state,
+			     struct v4l2_subdev_format *format)
+{
+	struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd);
+	u32 code = asd->supported_codes[0];
+	struct v4l2_mbus_framefmt *fmt;
+	u32 other_pad, other_stream;
+	struct v4l2_rect *crop;
+	unsigned int i;
+	int ret;
+
+	/* No transcoding, source and sink formats must match. */
+	if ((sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SOURCE) &&
+	    sd->entity.num_pads > 1)
+		return v4l2_subdev_get_fmt(sd, state, format);
+
+	format->format.width = clamp(format->format.width, IPU_ISYS_MIN_WIDTH,
+				     IPU_ISYS_MAX_WIDTH);
+	format->format.height = clamp(format->format.height,
+				      IPU_ISYS_MIN_HEIGHT,
+				      IPU_ISYS_MAX_HEIGHT);
+
+	for (i = 0; asd->supported_codes[i]; i++) {
+		if (asd->supported_codes[i] == format->format.code) {
+			code = asd->supported_codes[i];
+			break;
+		}
+	}
+	format->format.code = code;
+	format->format.field = V4L2_FIELD_NONE;
+
+	/* Store the format and propagate it to the source pad. */
+	fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
+	if (!fmt)
+		return -EINVAL;
+
+	*fmt = format->format;
+
+	if (!(sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SINK))
+		return 0;
+
+	/* propagate format to following source pad */
+	fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+							   format->stream);
+	if (!fmt)
+		return -EINVAL;
+
+	*fmt = format->format;
+
+	ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
+						    format->pad,
+						    format->stream,
+						    &other_pad,
+						    &other_stream);
+	if (ret)
+		return -EINVAL;
+
+	crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
+	/* reset crop */
+	crop->left = 0;
+	crop->top = 0;
+	crop->width = fmt->width;
+	crop->height = fmt->height;
+
+	return 0;
+}
+
+int ipu7_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *state,
+				    struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd);
+	const u32 *supported_codes = asd->supported_codes;
+	u32 index;
+
+	for (index = 0; supported_codes[index]; index++) {
+		if (index == code->index) {
+			code->code = supported_codes[index];
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int subdev_set_routing(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_state *state,
+			      struct v4l2_subdev_krouting *routing)
+{
+	static const struct v4l2_mbus_framefmt fmt = {
+		.width = 4096,
+		.height = 3072,
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.field = V4L2_FIELD_NONE,
+	};
+	int ret;
+
+	ret = v4l2_subdev_routing_validate(sd, routing,
+					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+	if (ret)
+		return ret;
+
+	return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &fmt);
+}
+
+int ipu7_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
+				 struct v4l2_mbus_framefmt *format)
+{
+	struct v4l2_subdev_state *state;
+	struct v4l2_mbus_framefmt *fmt;
+
+	if (!sd || !format)
+		return -EINVAL;
+
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+	fmt = v4l2_subdev_state_get_format(state, pad, stream);
+	if (fmt)
+		*format = *fmt;
+	v4l2_subdev_unlock_state(state);
+
+	return fmt ? 0 : -EINVAL;
+}
+
+u32 ipu7_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
+{
+	struct v4l2_subdev_state *state;
+	struct v4l2_subdev_route *routes;
+	u32 source_stream = 0;
+	unsigned int i;
+
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+	if (!state)
+		return 0;
+
+	routes = state->routing.routes;
+	for (i = 0; i < state->routing.num_routes; i++) {
+		if (routes[i].source_pad == pad) {
+			source_stream = routes[i].source_stream;
+			break;
+		}
+	}
+
+	v4l2_subdev_unlock_state(state);
+
+	return source_stream;
+}
+
+static int ipu7_isys_subdev_init_state(struct v4l2_subdev *sd,
+				       struct v4l2_subdev_state *state)
+{
+	struct v4l2_subdev_route route = {
+		.sink_pad = 0,
+		.sink_stream = 0,
+		.source_pad = 1,
+		.source_stream = 0,
+		.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+	};
+	struct v4l2_subdev_krouting routing = {
+		.num_routes = 1,
+		.routes = &route,
+	};
+
+	return subdev_set_routing(sd, state, &routing);
+}
+
+int ipu7_isys_subdev_set_routing(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 enum v4l2_subdev_format_whence which,
+				 struct v4l2_subdev_krouting *routing)
+{
+	return subdev_set_routing(sd, state, routing);
+}
+
+static const struct v4l2_subdev_internal_ops ipu7_isys_subdev_internal_ops = {
+	.init_state = ipu7_isys_subdev_init_state,
+};
+
+int ipu7_isys_subdev_init(struct ipu7_isys_subdev *asd,
+			  const struct v4l2_subdev_ops *ops,
+			  unsigned int nr_ctrls,
+			  unsigned int num_sink_pads,
+			  unsigned int num_source_pads)
+{
+	unsigned int num_pads = num_sink_pads + num_source_pads;
+	unsigned int i;
+	int ret;
+
+	v4l2_subdev_init(&asd->sd, ops);
+
+	asd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+			 V4L2_SUBDEV_FL_HAS_EVENTS |
+			 V4L2_SUBDEV_FL_STREAMS;
+	asd->sd.owner = THIS_MODULE;
+	asd->sd.dev = &asd->isys->adev->auxdev.dev;
+	asd->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	asd->sd.internal_ops = &ipu7_isys_subdev_internal_ops;
+
+	asd->pad = devm_kcalloc(&asd->isys->adev->auxdev.dev, num_pads,
+				sizeof(*asd->pad), GFP_KERNEL);
+	if (!asd->pad)
+		return -ENOMEM;
+
+	for (i = 0; i < num_sink_pads; i++)
+		asd->pad[i].flags = MEDIA_PAD_FL_SINK |
+			MEDIA_PAD_FL_MUST_CONNECT;
+
+	for (i = num_sink_pads; i < num_pads; i++)
+		asd->pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&asd->sd.entity, num_pads, asd->pad);
+	if (ret) {
+		pr_err("isys subdev init failed %d.\n", ret);
+		return ret;
+	}
+
+	if (asd->ctrl_init) {
+		ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, nr_ctrls);
+		if (ret)
+			goto out_media_entity_cleanup;
+
+		asd->ctrl_init(&asd->sd);
+		if (asd->ctrl_handler.error) {
+			ret = asd->ctrl_handler.error;
+			goto out_v4l2_ctrl_handler_free;
+		}
+
+		asd->sd.ctrl_handler = &asd->ctrl_handler;
+	}
+
+	asd->source = -1;
+
+	return 0;
+
+out_v4l2_ctrl_handler_free:
+	v4l2_ctrl_handler_free(&asd->ctrl_handler);
+
+out_media_entity_cleanup:
+	media_entity_cleanup(&asd->sd.entity);
+
+	return ret;
+}
+
+void ipu7_isys_subdev_cleanup(struct ipu7_isys_subdev *asd)
+{
+	media_entity_cleanup(&asd->sd.entity);
+	v4l2_ctrl_handler_free(&asd->ctrl_handler);
+}
diff --git a/drivers/staging/media/ipu7/ipu7-isys-subdev.h b/drivers/staging/media/ipu7/ipu7-isys-subdev.h
new file mode 100644
index 000000000000..1057ec39ae39
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-subdev.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_SUBDEV_H
+#define IPU7_ISYS_SUBDEV_H
+
+#include <linux/container_of.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+struct ipu7_isys;
+
+struct ipu7_isys_subdev {
+	struct v4l2_subdev sd;
+	struct ipu7_isys *isys;
+	u32 const *supported_codes;
+	struct media_pad *pad;
+	struct v4l2_ctrl_handler ctrl_handler;
+	void (*ctrl_init)(struct v4l2_subdev *sd);
+	int source;	/* SSI stream source; -1 if unset */
+};
+
+#define to_ipu7_isys_subdev(__sd)			\
+	container_of(__sd, struct ipu7_isys_subdev, sd)
+unsigned int ipu7_isys_mbus_code_to_mipi(u32 code);
+bool ipu7_isys_is_bayer_format(u32 code);
+u32 ipu7_isys_convert_bayer_order(u32 code, int x, int y);
+
+int ipu7_isys_subdev_set_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *state,
+			     struct v4l2_subdev_format *format);
+int ipu7_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_state *state,
+				    struct v4l2_subdev_mbus_code_enum
+				    *code);
+u32 ipu7_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad);
+int ipu7_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
+				 struct v4l2_mbus_framefmt *format);
+int ipu7_isys_subdev_set_routing(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 enum v4l2_subdev_format_whence which,
+				 struct v4l2_subdev_krouting *routing);
+int ipu7_isys_subdev_init(struct ipu7_isys_subdev *asd,
+			  const struct v4l2_subdev_ops *ops,
+			  unsigned int nr_ctrls,
+			  unsigned int num_sink_pads,
+			  unsigned int num_source_pads);
+void ipu7_isys_subdev_cleanup(struct ipu7_isys_subdev *asd);
+#endif /* IPU7_ISYS_SUBDEV_H */
diff --git a/drivers/staging/media/ipu7/ipu7-isys-video.c b/drivers/staging/media/ipu7/ipu7-isys-video.c
new file mode 100644
index 000000000000..63b90c42d59b
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-video.c
@@ -0,0 +1,1112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/align.h>
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/compat.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "abi/ipu7_fw_isys_abi.h"
+
+#include "ipu7.h"
+#include "ipu7-bus.h"
+#include "ipu7-buttress-regs.h"
+#include "ipu7-fw-isys.h"
+#include "ipu7-isys.h"
+#include "ipu7-isys-video.h"
+#include "ipu7-platform-regs.h"
+
+const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = {
+	{V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW16},
+	{V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8,
+	 IPU_INSYS_FRAME_FORMAT_RAW8},
+	{V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8,
+	 IPU_INSYS_FRAME_FORMAT_RAW8},
+	{V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8,
+	 IPU_INSYS_FRAME_FORMAT_RAW8},
+	{V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8,
+	 IPU_INSYS_FRAME_FORMAT_RAW8},
+	{V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW12},
+	{V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW12},
+	{V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW12},
+	{V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
+	 IPU_INSYS_FRAME_FORMAT_RAW12},
+	{V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW10},
+	{V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW10},
+	{V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW10},
+	{V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
+	 IPU_INSYS_FRAME_FORMAT_RAW10},
+	{V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16,
+	 IPU_INSYS_FRAME_FORMAT_UYVY},
+	{V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16,
+	 IPU_INSYS_FRAME_FORMAT_YUYV},
+	{V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16,
+	 IPU_INSYS_FRAME_FORMAT_RGB565},
+	{V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
+	 IPU_INSYS_FRAME_FORMAT_RGBA888},
+};
+
+static int video_open(struct file *file)
+{
+	return v4l2_fh_open(file);
+}
+
+const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
+		const struct ipu7_isys_pixelformat *pfmt = &ipu7_isys_pfmts[i];
+
+		if (pfmt->pixelformat == pixelformat)
+			return pfmt;
+	}
+
+	return &ipu7_isys_pfmts[0];
+}
+
+static int ipu7_isys_vidioc_querycap(struct file *file, void *fh,
+				     struct v4l2_capability *cap)
+{
+	struct ipu7_isys_video *av = video_drvdata(file);
+
+	strscpy(cap->driver, IPU_ISYS_NAME, sizeof(cap->driver));
+	strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card));
+
+	return 0;
+}
+
+static int ipu7_isys_vidioc_enum_fmt(struct file *file, void *fh,
+				     struct v4l2_fmtdesc *f)
+{
+	unsigned int i, num_found;
+
+	for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
+		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			continue;
+
+		if (f->mbus_code && f->mbus_code != ipu7_isys_pfmts[i].code)
+			continue;
+
+		if (num_found < f->index) {
+			num_found++;
+			continue;
+		}
+
+		f->flags = 0;
+		f->pixelformat = ipu7_isys_pfmts[i].pixelformat;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int ipu7_isys_vidioc_enum_framesizes(struct file *file, void *fh,
+					    struct v4l2_frmsizeenum *fsize)
+{
+	unsigned int i;
+
+	if (fsize->index > 0)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) {
+		if (fsize->pixel_format != ipu7_isys_pfmts[i].pixelformat)
+			continue;
+
+		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+		fsize->stepwise.min_width = IPU_ISYS_MIN_WIDTH;
+		fsize->stepwise.max_width = IPU_ISYS_MAX_WIDTH;
+		fsize->stepwise.min_height = IPU_ISYS_MIN_HEIGHT;
+		fsize->stepwise.max_height = IPU_ISYS_MAX_HEIGHT;
+		fsize->stepwise.step_width = 2;
+		fsize->stepwise.step_height = 2;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int ipu7_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+					  struct v4l2_format *f)
+{
+	struct ipu7_isys_video *av = video_drvdata(file);
+
+	f->fmt.pix = av->pix_fmt;
+
+	return 0;
+}
+
+static void ipu7_isys_try_fmt_cap(struct ipu7_isys_video *av, u32 type,
+				  u32 *format, u32 *width, u32 *height,
+				  u32 *bytesperline, u32 *sizeimage)
+{
+	const struct ipu7_isys_pixelformat *pfmt =
+		ipu7_isys_get_isys_format(*format);
+
+	*format = pfmt->pixelformat;
+	*width = clamp(*width, IPU_ISYS_MIN_WIDTH, IPU_ISYS_MAX_WIDTH);
+	*height = clamp(*height, IPU_ISYS_MIN_HEIGHT, IPU_ISYS_MAX_HEIGHT);
+
+	if (pfmt->bpp != pfmt->bpp_packed)
+		*bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
+	else
+		*bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
+
+	*bytesperline = ALIGN(*bytesperline, 64U);
+
+	/*
+	 * (height + 1) * bytesperline due to a hardware issue: the DMA unit
+	 * is a power of two, and a line should be transferred as few units
+	 * as possible. The result is that up to line length more data than
+	 * the image size may be transferred to memory after the image.
+	 * Another limitation is the GDA allocation unit size. For low
+	 * resolution it gives a bigger number. Use larger one to avoid
+	 * memory corruption.
+	 */
+	*sizeimage = *bytesperline * *height +
+		max(*bytesperline,
+		    av->isys->pdata->ipdata->isys_dma_overshoot);
+}
+
+static void __ipu_isys_vidioc_try_fmt_vid_cap(struct ipu7_isys_video *av,
+					      struct v4l2_format *f)
+{
+	ipu7_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
+			      &f->fmt.pix.width, &f->fmt.pix.height,
+			      &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
+	f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
+	f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int ipu7_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+					    struct v4l2_format *f)
+{
+	struct ipu7_isys_video *av = video_drvdata(file);
+
+	if (vb2_is_busy(&av->aq.vbq))
+		return -EBUSY;
+
+	__ipu_isys_vidioc_try_fmt_vid_cap(av, f);
+
+	return 0;
+}
+
+static int ipu7_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+					  struct v4l2_format *f)
+{
+	struct ipu7_isys_video *av = video_drvdata(file);
+
+	ipu7_isys_vidioc_try_fmt_vid_cap(file, fh, f);
+	av->pix_fmt = f->fmt.pix;
+
+	return 0;
+}
+
+static int ipu7_isys_vidioc_reqbufs(struct file *file, void *priv,
+				    struct v4l2_requestbuffers *p)
+{
+	struct ipu7_isys_video *av = video_drvdata(file);
+	int ret;
+
+	av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
+	av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
+
+	ret = vb2_queue_change_type(&av->aq.vbq, p->type);
+	if (ret)
+		return ret;
+
+	return vb2_ioctl_reqbufs(file, priv, p);
+}
+
+static int ipu7_isys_vidioc_create_bufs(struct file *file, void *priv,
+					struct v4l2_create_buffers *p)
+{
+	struct ipu7_isys_video *av = video_drvdata(file);
+	int ret;
+
+	av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
+	av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
+
+	ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
+	if (ret)
+		return ret;
+
+	return vb2_ioctl_create_bufs(file, priv, p);
+}
+
+static int link_validate(struct media_link *link)
+{
+	struct ipu7_isys_video *av =
+		container_of(link->sink, struct ipu7_isys_video, pad);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct v4l2_subdev_state *s_state;
+	struct v4l2_mbus_framefmt *s_fmt;
+	struct v4l2_subdev *s_sd;
+	struct media_pad *s_pad;
+	u32 s_stream, code;
+	int ret = -EPIPE;
+
+	if (!link->source->entity)
+		return ret;
+
+	s_sd = media_entity_to_v4l2_subdev(link->source->entity);
+	s_state = v4l2_subdev_get_unlocked_active_state(s_sd);
+	if (!s_state)
+		return ret;
+
+	dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n",
+		link->source->entity->name, link->source->index,
+		link->sink->entity->name);
+
+	s_pad = media_pad_remote_pad_first(&av->pad);
+	s_stream = ipu7_isys_get_src_stream_by_src_pad(s_sd, s_pad->index);
+
+	v4l2_subdev_lock_state(s_state);
+
+	s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream);
+	if (!s_fmt) {
+		dev_err(dev, "failed to get source pad format\n");
+		goto unlock;
+	}
+
+	code = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat)->code;
+
+	if (s_fmt->width != av->pix_fmt.width ||
+	    s_fmt->height != av->pix_fmt.height || s_fmt->code != code) {
+		dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
+			s_fmt->width, s_fmt->height, s_fmt->code,
+			av->pix_fmt.width, av->pix_fmt.height, code);
+		goto unlock;
+	}
+
+	v4l2_subdev_unlock_state(s_state);
+
+	return 0;
+unlock:
+	v4l2_subdev_unlock_state(s_state);
+
+	return ret;
+}
+
+static void get_stream_opened(struct ipu7_isys_video *av)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&av->isys->streams_lock, flags);
+	av->isys->stream_opened++;
+	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
+}
+
+static void put_stream_opened(struct ipu7_isys_video *av)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&av->isys->streams_lock, flags);
+	av->isys->stream_opened--;
+	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
+}
+
+static int ipu7_isys_fw_pin_cfg(struct ipu7_isys_video *av,
+				struct ipu7_insys_stream_cfg *cfg)
+{
+	struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
+	struct ipu7_isys_stream *stream = av->stream;
+	const struct ipu7_isys_pixelformat *pfmt =
+		ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
+	struct ipu7_insys_output_pin *output_pin;
+	struct ipu7_insys_input_pin *input_pin;
+	int input_pins = cfg->nof_input_pins++;
+	struct ipu7_isys_queue *aq = &av->aq;
+	struct ipu7_isys *isys = av->isys;
+	struct device *dev = &isys->adev->auxdev.dev;
+	struct v4l2_mbus_framefmt fmt;
+	int output_pins;
+	u32 src_stream;
+	int ret;
+
+	src_stream = ipu7_isys_get_src_stream_by_src_pad(sd, src_pad->index);
+	ret = ipu7_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
+					   &fmt);
+	if (ret < 0) {
+		dev_err(dev, "can't get stream format (%d)\n", ret);
+		return ret;
+	}
+
+	input_pin = &cfg->input_pins[input_pins];
+	input_pin->input_res.width = fmt.width;
+	input_pin->input_res.height = fmt.height;
+	input_pin->dt = av->dt;
+	input_pin->disable_mipi_unpacking = 0;
+	pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
+	if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE)
+		input_pin->disable_mipi_unpacking = 1;
+	input_pin->mapped_dt = N_IPU_INSYS_MIPI_DATA_TYPE;
+	input_pin->dt_rename_mode = IPU_INSYS_MIPI_DT_NO_RENAME;
+	/* if enable polling isys interrupt, the follow values maybe set */
+	input_pin->sync_msg_map = IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF |
+		IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED |
+		IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF |
+		IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED;
+
+	output_pins = cfg->nof_output_pins++;
+	aq->fw_output = output_pins;
+	stream->output_pins[output_pins].pin_ready = ipu7_isys_queue_buf_ready;
+	stream->output_pins[output_pins].aq = aq;
+
+	output_pin = &cfg->output_pins[output_pins];
+	/* output pin msg link */
+	output_pin->link.buffer_lines = 0;
+	output_pin->link.foreign_key = IPU_MSG_LINK_FOREIGN_KEY_NONE;
+	output_pin->link.granularity_pointer_update = 0;
+	output_pin->link.msg_link_streaming_mode =
+		IA_GOFO_MSG_LINK_STREAMING_MODE_SOFF;
+
+	output_pin->link.pbk_id = IPU_MSG_LINK_PBK_ID_DONT_CARE;
+	output_pin->link.pbk_slot_id = IPU_MSG_LINK_PBK_SLOT_ID_DONT_CARE;
+	output_pin->link.dest = IPU_INSYS_OUTPUT_LINK_DEST_MEM;
+	output_pin->link.use_sw_managed = 1;
+	/* TODO: set the snoop bit for metadata capture */
+	output_pin->link.is_snoop = 0;
+
+	/* output pin crop */
+	output_pin->crop.line_top = 0;
+	output_pin->crop.line_bottom = 0;
+
+	/* output de-compression */
+	output_pin->dpcm.enable = 0;
+
+	/* frame format type */
+	pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
+	output_pin->ft = (u16)pfmt->css_pixelformat;
+
+	/* stride in bytes */
+	output_pin->stride = av->pix_fmt.bytesperline;
+	output_pin->send_irq = 1;
+	output_pin->early_ack_en = 0;
+
+	/* input pin id */
+	output_pin->input_pin_id = input_pins;
+
+	return 0;
+}
+
+/* Create stream and start it using the CSS FW ABI. */
+static int start_stream_firmware(struct ipu7_isys_video *av,
+				 struct ipu7_isys_buffer_list *bl)
+{
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu7_isys_stream *stream = av->stream;
+	struct ipu7_insys_stream_cfg *stream_cfg;
+	struct ipu7_insys_buffset *buf = NULL;
+	struct isys_fw_msgs *msg = NULL;
+	struct ipu7_isys_queue *aq;
+	int ret, retout, tout;
+	u16 send_type;
+
+	if (WARN_ON(!bl))
+		return -EIO;
+
+	msg = ipu7_get_fw_msg_buf(stream);
+	if (!msg)
+		return -ENOMEM;
+
+	stream_cfg = &msg->fw_msg.stream;
+	stream_cfg->port_id = stream->stream_source;
+	stream_cfg->vc = stream->vc;
+	stream_cfg->stream_msg_map = IPU_INSYS_STREAM_ENABLE_MSG_SEND_RESP |
+				     IPU_INSYS_STREAM_ENABLE_MSG_SEND_IRQ;
+
+	list_for_each_entry(aq, &stream->queues, node) {
+		struct ipu7_isys_video *__av = ipu7_isys_queue_to_video(aq);
+
+		ret = ipu7_isys_fw_pin_cfg(__av, stream_cfg);
+		if (ret < 0) {
+			ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+			return ret;
+		}
+	}
+
+	ipu7_fw_isys_dump_stream_cfg(dev, stream_cfg);
+
+	stream->nr_output_pins = stream_cfg->nof_output_pins;
+
+	reinit_completion(&stream->stream_open_completion);
+
+	ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle,
+				       stream_cfg, msg->dma_addr,
+				       sizeof(*stream_cfg),
+				       IPU_INSYS_SEND_TYPE_STREAM_OPEN);
+	if (ret < 0) {
+		dev_err(dev, "can't open stream (%d)\n", ret);
+		ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+		return ret;
+	}
+
+	get_stream_opened(av);
+
+	tout = wait_for_completion_timeout(&stream->stream_open_completion,
+					   FW_CALL_TIMEOUT_JIFFIES);
+
+	ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+
+	if (!tout) {
+		dev_err(dev, "stream open time out\n");
+		ret = -ETIMEDOUT;
+		goto out_put_stream_opened;
+	}
+	if (stream->error) {
+		dev_err(dev, "stream open error: %d\n", stream->error);
+		ret = -EIO;
+		goto out_put_stream_opened;
+	}
+	dev_dbg(dev, "start stream: open complete\n");
+
+	msg = ipu7_get_fw_msg_buf(stream);
+	if (!msg) {
+		ret = -ENOMEM;
+		goto out_put_stream_opened;
+	}
+	buf = &msg->fw_msg.frame;
+
+	ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl);
+	ipu7_isys_buffer_list_queue(bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
+
+	reinit_completion(&stream->stream_start_completion);
+
+	send_type = IPU_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
+	ipu7_fw_isys_dump_frame_buff_set(dev, buf,
+					 stream_cfg->nof_output_pins);
+	ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle, buf,
+				       msg->dma_addr, sizeof(*buf),
+				       send_type);
+	if (ret < 0) {
+		dev_err(dev, "can't start streaming (%d)\n", ret);
+		goto out_stream_close;
+	}
+
+	tout = wait_for_completion_timeout(&stream->stream_start_completion,
+					   FW_CALL_TIMEOUT_JIFFIES);
+	if (!tout) {
+		dev_err(dev, "stream start time out\n");
+		ret = -ETIMEDOUT;
+		goto out_stream_close;
+	}
+	if (stream->error) {
+		dev_err(dev, "stream start error: %d\n", stream->error);
+		ret = -EIO;
+		goto out_stream_close;
+	}
+	dev_dbg(dev, "start stream: complete\n");
+
+	return 0;
+
+out_stream_close:
+	reinit_completion(&stream->stream_close_completion);
+
+	retout = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
+					 IPU_INSYS_SEND_TYPE_STREAM_CLOSE);
+	if (retout < 0) {
+		dev_dbg(dev, "can't close stream (%d)\n", retout);
+		goto out_put_stream_opened;
+	}
+
+	tout = wait_for_completion_timeout(&stream->stream_close_completion,
+					   FW_CALL_TIMEOUT_JIFFIES);
+	if (!tout)
+		dev_err(dev, "stream close time out with error %d\n",
+			stream->error);
+	else
+		dev_dbg(dev, "stream close complete\n");
+
+out_put_stream_opened:
+	put_stream_opened(av);
+
+	return ret;
+}
+
+static void stop_streaming_firmware(struct ipu7_isys_video *av)
+{
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu7_isys_stream *stream = av->stream;
+	int ret, tout;
+
+	reinit_completion(&stream->stream_stop_completion);
+
+	ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
+				      IPU_INSYS_SEND_TYPE_STREAM_FLUSH);
+	if (ret < 0) {
+		dev_err(dev, "can't stop stream (%d)\n", ret);
+		return;
+	}
+
+	tout = wait_for_completion_timeout(&stream->stream_stop_completion,
+					   FW_CALL_TIMEOUT_JIFFIES);
+	if (!tout)
+		dev_warn(dev, "stream stop time out\n");
+	else if (stream->error)
+		dev_warn(dev, "stream stop error: %d\n", stream->error);
+	else
+		dev_dbg(dev, "stop stream: complete\n");
+}
+
+static void close_streaming_firmware(struct ipu7_isys_video *av)
+{
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu7_isys_stream *stream =  av->stream;
+	int ret, tout;
+
+	reinit_completion(&stream->stream_close_completion);
+
+	ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle,
+				      IPU_INSYS_SEND_TYPE_STREAM_CLOSE);
+	if (ret < 0) {
+		dev_err(dev, "can't close stream (%d)\n", ret);
+		return;
+	}
+
+	tout = wait_for_completion_timeout(&stream->stream_close_completion,
+					   FW_CALL_TIMEOUT_JIFFIES);
+	if (!tout)
+		dev_warn(dev, "stream close time out\n");
+	else if (stream->error)
+		dev_warn(dev, "stream close error: %d\n", stream->error);
+	else
+		dev_dbg(dev, "close stream: complete\n");
+
+	put_stream_opened(av);
+}
+
+int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av,
+				   struct media_entity *source_entity,
+				   int nr_queues)
+{
+	struct ipu7_isys_stream *stream = av->stream;
+	struct ipu7_isys_csi2 *csi2;
+
+	if (WARN_ON(stream->nr_streaming))
+		return -EINVAL;
+
+	stream->nr_queues = nr_queues;
+	atomic_set(&stream->sequence, 0);
+	atomic_set(&stream->buf_id, 0);
+
+	stream->seq_index = 0;
+	memset(stream->seq, 0, sizeof(stream->seq));
+
+	if (WARN_ON(!list_empty(&stream->queues)))
+		return -EINVAL;
+
+	stream->stream_source = stream->asd->source;
+
+	csi2 = ipu7_isys_subdev_to_csi2(stream->asd);
+	csi2->receiver_errors = 0;
+	stream->source_entity = source_entity;
+
+	dev_dbg(&av->isys->adev->auxdev.dev,
+		"prepare stream: external entity %s\n",
+		stream->source_entity->name);
+
+	return 0;
+}
+
+void ipu7_isys_put_stream(struct ipu7_isys_stream *stream)
+{
+	unsigned long flags;
+	struct device *dev;
+	unsigned int i;
+
+	if (!stream) {
+		pr_err("ipu7-isys: no available stream\n");
+		return;
+	}
+
+	dev = &stream->isys->adev->auxdev.dev;
+
+	spin_lock_irqsave(&stream->isys->streams_lock, flags);
+	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
+		if (&stream->isys->streams[i] == stream) {
+			if (stream->isys->streams_ref_count[i] > 0)
+				stream->isys->streams_ref_count[i]--;
+			else
+				dev_warn(dev, "invalid stream %d\n", i);
+
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
+}
+
+static struct ipu7_isys_stream *
+ipu7_isys_get_stream(struct ipu7_isys_video *av, struct ipu7_isys_subdev *asd)
+{
+	struct ipu7_isys_stream *stream = NULL;
+	struct ipu7_isys *isys = av->isys;
+	unsigned long flags;
+	unsigned int i;
+	u8 vc = av->vc;
+
+	if (!isys)
+		return NULL;
+
+	spin_lock_irqsave(&isys->streams_lock, flags);
+	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
+		if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
+		    isys->streams[i].asd == asd) {
+			isys->streams_ref_count[i]++;
+			stream = &isys->streams[i];
+			break;
+		}
+	}
+
+	if (!stream) {
+		for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
+			if (!isys->streams_ref_count[i]) {
+				isys->streams_ref_count[i]++;
+				stream = &isys->streams[i];
+				stream->vc = vc;
+				stream->asd = asd;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&isys->streams_lock, flags);
+
+	return stream;
+}
+
+struct ipu7_isys_stream *
+ipu7_isys_query_stream_by_handle(struct ipu7_isys *isys, u8 stream_handle)
+{
+	unsigned long flags;
+	struct ipu7_isys_stream *stream = NULL;
+
+	if (!isys)
+		return NULL;
+
+	if (stream_handle >= IPU_ISYS_MAX_STREAMS) {
+		dev_err(&isys->adev->auxdev.dev,
+			"stream_handle %d is invalid\n", stream_handle);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&isys->streams_lock, flags);
+	if (isys->streams_ref_count[stream_handle] > 0) {
+		isys->streams_ref_count[stream_handle]++;
+		stream = &isys->streams[stream_handle];
+	}
+	spin_unlock_irqrestore(&isys->streams_lock, flags);
+
+	return stream;
+}
+
+struct ipu7_isys_stream *
+ipu7_isys_query_stream_by_source(struct ipu7_isys *isys, int source, u8 vc)
+{
+	struct ipu7_isys_stream *stream = NULL;
+	unsigned long flags;
+	unsigned int i;
+
+	if (!isys)
+		return NULL;
+
+	if (source < 0) {
+		dev_err(&isys->adev->auxdev.dev,
+			"query stream with invalid port number\n");
+		return NULL;
+	}
+
+	spin_lock_irqsave(&isys->streams_lock, flags);
+	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
+		if (!isys->streams_ref_count[i])
+			continue;
+
+		if (isys->streams[i].stream_source == source &&
+		    isys->streams[i].vc == vc) {
+			stream = &isys->streams[i];
+			isys->streams_ref_count[i]++;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&isys->streams_lock, flags);
+
+	return stream;
+}
+
+static u32 get_remote_pad_stream(struct media_pad *r_pad)
+{
+	struct v4l2_subdev_state *state;
+	struct v4l2_subdev *sd;
+	u32 stream_id = 0;
+	unsigned int i;
+
+	sd = media_entity_to_v4l2_subdev(r_pad->entity);
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+	if (!state)
+		return 0;
+
+	for (i = 0; i < state->stream_configs.num_configs; i++) {
+		struct v4l2_subdev_stream_config *cfg =
+			&state->stream_configs.configs[i];
+		if (cfg->pad == r_pad->index) {
+			stream_id = cfg->stream;
+			break;
+		}
+	}
+
+	v4l2_subdev_unlock_state(state);
+
+	return stream_id;
+}
+
+int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state,
+				  struct ipu7_isys_buffer_list *bl)
+{
+	struct ipu7_isys_stream *stream = av->stream;
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct media_pad *r_pad;
+	struct v4l2_subdev *sd;
+	u32 r_stream;
+	int ret = 0;
+
+	dev_dbg(dev, "set stream: %d\n", state);
+
+	if (WARN(!stream->source_entity, "No source entity for stream\n"))
+		return -ENODEV;
+
+	sd = &stream->asd->sd;
+	r_pad = media_pad_remote_pad_first(&av->pad);
+	r_stream = get_remote_pad_stream(r_pad);
+	if (!state) {
+		stop_streaming_firmware(av);
+
+		/* stop sub-device which connects with video */
+		dev_dbg(dev, "disable streams %s pad:%d mask:0x%llx\n",
+			sd->name, r_pad->index, BIT_ULL(r_stream));
+		ret = v4l2_subdev_disable_streams(sd, r_pad->index,
+						  BIT_ULL(r_stream));
+		if (ret) {
+			dev_err(dev, "disable streams %s failed with %d\n",
+				sd->name, ret);
+			return ret;
+		}
+
+		close_streaming_firmware(av);
+	} else {
+		ret = start_stream_firmware(av, bl);
+		if (ret) {
+			dev_err(dev, "start stream of firmware failed\n");
+			return ret;
+		}
+
+		/* start sub-device which connects with video */
+		dev_dbg(dev, "enable streams %s pad: %d mask:0x%llx\n",
+			sd->name, r_pad->index, BIT_ULL(r_stream));
+		ret = v4l2_subdev_enable_streams(sd, r_pad->index,
+						 BIT_ULL(r_stream));
+		if (ret) {
+			dev_err(dev, "enable streams %s failed with %d\n",
+				sd->name, ret);
+			goto out_media_entity_stop_streaming_firmware;
+		}
+	}
+
+	av->streaming = state;
+
+	return 0;
+
+out_media_entity_stop_streaming_firmware:
+	stop_streaming_firmware(av);
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops ipu7_v4l2_ioctl_ops = {
+	.vidioc_querycap = ipu7_isys_vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap = ipu7_isys_vidioc_enum_fmt,
+	.vidioc_enum_framesizes = ipu7_isys_vidioc_enum_framesizes,
+	.vidioc_g_fmt_vid_cap = ipu7_isys_vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap = ipu7_isys_vidioc_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap = ipu7_isys_vidioc_try_fmt_vid_cap,
+	.vidioc_reqbufs = ipu7_isys_vidioc_reqbufs,
+	.vidioc_create_bufs = ipu7_isys_vidioc_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+static const struct media_entity_operations entity_ops = {
+	.link_validate = link_validate,
+};
+
+static const struct v4l2_file_operations isys_fops = {
+	.owner = THIS_MODULE,
+	.poll = vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = vb2_fop_mmap,
+	.open = video_open,
+	.release = vb2_fop_release,
+};
+
+int ipu7_isys_fw_open(struct ipu7_isys *isys)
+{
+	struct ipu7_bus_device *adev = isys->adev;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&isys->mutex);
+
+	if (isys->ref_count++)
+		goto unlock;
+
+	/*
+	 * Buffers could have been left to wrong queue at last closure.
+	 * Move them now back to empty buffer queue.
+	 */
+	ipu7_cleanup_fw_msg_bufs(isys);
+
+	ret = ipu7_fw_isys_open(isys);
+	if (ret < 0)
+		goto out;
+
+unlock:
+	mutex_unlock(&isys->mutex);
+
+	return 0;
+out:
+	isys->ref_count--;
+	mutex_unlock(&isys->mutex);
+	pm_runtime_put(&adev->auxdev.dev);
+
+	return ret;
+}
+
+void ipu7_isys_fw_close(struct ipu7_isys *isys)
+{
+	mutex_lock(&isys->mutex);
+
+	isys->ref_count--;
+
+	if (!isys->ref_count)
+		ipu7_fw_isys_close(isys);
+
+	mutex_unlock(&isys->mutex);
+}
+
+int ipu7_isys_setup_video(struct ipu7_isys_video *av,
+			  struct media_entity **source_entity, int *nr_queues)
+{
+	const struct ipu7_isys_pixelformat *pfmt =
+		ipu7_isys_get_isys_format(av->pix_fmt.pixelformat);
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct media_pad *source_pad, *remote_pad;
+	struct v4l2_mbus_frame_desc_entry entry;
+	struct v4l2_subdev_route *route = NULL;
+	struct v4l2_subdev_route *r;
+	struct v4l2_subdev_state *state;
+	struct ipu7_isys_subdev *asd;
+	struct v4l2_subdev *remote_sd;
+	struct media_pipeline *pipeline;
+	int ret = -EINVAL;
+
+	*nr_queues = 0;
+
+	remote_pad = media_pad_remote_pad_unique(&av->pad);
+	if (IS_ERR(remote_pad)) {
+		dev_dbg(dev, "failed to get remote pad\n");
+		return PTR_ERR(remote_pad);
+	}
+
+	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+	asd = to_ipu7_isys_subdev(remote_sd);
+
+	source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
+	if (!source_pad) {
+		dev_dbg(dev, "No external source entity\n");
+		return -ENODEV;
+	}
+
+	*source_entity = source_pad->entity;
+
+	state = v4l2_subdev_lock_and_get_active_state(remote_sd);
+	for_each_active_route(&state->routing, r) {
+		if (r->source_pad == remote_pad->index)
+			route = r;
+	}
+
+	if (!route) {
+		v4l2_subdev_unlock_state(state);
+		dev_dbg(dev, "Failed to find route\n");
+		return -ENODEV;
+	}
+
+	v4l2_subdev_unlock_state(state);
+
+	ret = ipu7_isys_csi2_get_remote_desc(route->sink_stream,
+					     to_ipu7_isys_csi2(asd),
+					     *source_entity, &entry,
+					     nr_queues);
+	if (ret == -ENOIOCTLCMD) {
+		av->vc = 0;
+		av->dt = ipu7_isys_mbus_code_to_mipi(pfmt->code);
+		if (av->dt == 0xffff)
+			return -EINVAL;
+		*nr_queues = 1;
+	} else if (*nr_queues && !ret) {
+		dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
+			entry.stream, entry.length, entry.bus.csi2.vc,
+			entry.bus.csi2.dt);
+
+		av->vc = entry.bus.csi2.vc;
+		av->dt = entry.bus.csi2.dt;
+	} else {
+		dev_err(dev, "failed to get remote frame desc\n");
+		return ret;
+	}
+
+	pipeline = media_entity_pipeline(&av->vdev.entity);
+	if (!pipeline)
+		ret = video_device_pipeline_alloc_start(&av->vdev);
+	else
+		ret = video_device_pipeline_start(&av->vdev, pipeline);
+	if (ret < 0) {
+		dev_dbg(dev, "media pipeline start failed\n");
+		return ret;
+	}
+
+	av->stream = ipu7_isys_get_stream(av, asd);
+	if (!av->stream) {
+		video_device_pipeline_stop(&av->vdev);
+		dev_err(dev, "no available stream for firmware\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Do everything that's needed to initialise things related to video
+ * buffer queue, video node, and the related media entity. The caller
+ * is expected to assign isys field and set the name of the video
+ * device.
+ */
+int ipu7_isys_video_init(struct ipu7_isys_video *av)
+{
+	struct v4l2_format format = {
+		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		.fmt.pix = {
+			.width = 1920,
+			.height = 1080,
+		},
+	};
+	int ret;
+
+	mutex_init(&av->mutex);
+	av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
+		V4L2_CAP_VIDEO_CAPTURE;
+	av->vdev.vfl_dir = VFL_DIR_RX;
+
+	ret = ipu7_isys_queue_init(&av->aq);
+	if (ret)
+		goto out_mutex_destroy;
+
+	av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
+	if (ret)
+		goto out_vb2_queue_cleanup;
+
+	av->vdev.entity.ops = &entity_ops;
+	av->vdev.release = video_device_release_empty;
+	av->vdev.fops = &isys_fops;
+	av->vdev.v4l2_dev = &av->isys->v4l2_dev;
+	av->vdev.dev_parent = &av->isys->adev->isp->pdev->dev;
+	av->vdev.ioctl_ops = &ipu7_v4l2_ioctl_ops;
+	av->vdev.queue = &av->aq.vbq;
+	av->vdev.lock = &av->mutex;
+
+	__ipu_isys_vidioc_try_fmt_vid_cap(av, &format);
+	av->pix_fmt = format.fmt.pix;
+
+	set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);
+	video_set_drvdata(&av->vdev, av);
+
+	ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);
+	if (ret)
+		goto out_media_entity_cleanup;
+
+	return ret;
+
+out_media_entity_cleanup:
+	vb2_video_unregister_device(&av->vdev);
+	media_entity_cleanup(&av->vdev.entity);
+
+out_vb2_queue_cleanup:
+	vb2_queue_release(&av->aq.vbq);
+
+out_mutex_destroy:
+	mutex_destroy(&av->mutex);
+
+	return ret;
+}
+
+void ipu7_isys_video_cleanup(struct ipu7_isys_video *av)
+{
+	vb2_video_unregister_device(&av->vdev);
+	media_entity_cleanup(&av->vdev.entity);
+	mutex_destroy(&av->mutex);
+}
diff --git a/drivers/staging/media/ipu7/ipu7-isys-video.h b/drivers/staging/media/ipu7/ipu7-isys-video.h
new file mode 100644
index 000000000000..1ac1787fabef
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys-video.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_VIDEO_H
+#define IPU7_ISYS_VIDEO_H
+
+#include <linux/atomic.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+
+#include "ipu7-isys-queue.h"
+
+#define IPU_INSYS_OUTPUT_PINS		11U
+#define IPU_ISYS_MAX_PARALLEL_SOF	2U
+
+struct file;
+struct ipu7_isys;
+struct ipu7_isys_csi2;
+struct ipu7_insys_stream_cfg;
+struct ipu7_isys_subdev;
+
+struct ipu7_isys_pixelformat {
+	u32 pixelformat;
+	u32 bpp;
+	u32 bpp_packed;
+	u32 code;
+	u32 css_pixelformat;
+};
+
+struct sequence_info {
+	unsigned int sequence;
+	u64 timestamp;
+};
+
+struct output_pin_data {
+	void (*pin_ready)(struct ipu7_isys_stream *stream,
+			  struct ipu7_insys_resp *info);
+	struct ipu7_isys_queue *aq;
+};
+
+/*
+ * Align with firmware stream. Each stream represents a CSI virtual channel.
+ * May map to multiple video devices
+ */
+struct ipu7_isys_stream {
+	struct mutex mutex;
+	struct media_entity *source_entity;
+	atomic_t sequence;
+	atomic_t buf_id;
+	unsigned int seq_index;
+	struct sequence_info seq[IPU_ISYS_MAX_PARALLEL_SOF];
+	int stream_source;
+	int stream_handle;
+	unsigned int nr_output_pins;
+	struct ipu7_isys_subdev *asd;
+
+	int nr_queues;  /* Number of capture queues */
+	int nr_streaming;
+	int streaming;
+	struct list_head queues;
+	struct completion stream_open_completion;
+	struct completion stream_close_completion;
+	struct completion stream_start_completion;
+	struct completion stream_stop_completion;
+	struct ipu7_isys *isys;
+
+	struct output_pin_data output_pins[IPU_INSYS_OUTPUT_PINS];
+	int error;
+	u8 vc;
+};
+
+struct ipu7_isys_video {
+	struct ipu7_isys_queue aq;
+	/* Serialise access to other fields in the struct. */
+	struct mutex mutex;
+	struct media_pad pad;
+	struct video_device vdev;
+	struct v4l2_pix_format pix_fmt;
+	struct ipu7_isys *isys;
+	struct ipu7_isys_csi2 *csi2;
+	struct ipu7_isys_stream *stream;
+	unsigned int streaming;
+	u8 vc;
+	u8 dt;
+};
+
+#define ipu7_isys_queue_to_video(__aq)			\
+	container_of(__aq, struct ipu7_isys_video, aq)
+
+extern const struct ipu7_isys_pixelformat ipu7_isys_pfmts[];
+
+const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat);
+int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av,
+				   struct media_entity *source_entity,
+				   int nr_queues);
+int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state,
+				  struct ipu7_isys_buffer_list *bl);
+int ipu7_isys_fw_open(struct ipu7_isys *isys);
+void ipu7_isys_fw_close(struct ipu7_isys *isys);
+int ipu7_isys_setup_video(struct ipu7_isys_video *av,
+			  struct media_entity **source_entity, int *nr_queues);
+int ipu7_isys_video_init(struct ipu7_isys_video *av);
+void ipu7_isys_video_cleanup(struct ipu7_isys_video *av);
+void ipu7_isys_put_stream(struct ipu7_isys_stream *stream);
+struct ipu7_isys_stream *
+ipu7_isys_query_stream_by_handle(struct ipu7_isys *isys,
+				 u8 stream_handle);
+struct ipu7_isys_stream *
+ipu7_isys_query_stream_by_source(struct ipu7_isys *isys, int source, u8 vc);
+#endif /* IPU7_ISYS_VIDEO_H */
diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c
new file mode 100644
index 000000000000..cb2f49f3e0fa
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys.c
@@ -0,0 +1,1166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <media/ipu-bridge.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#include "abi/ipu7_fw_isys_abi.h"
+
+#include "ipu7-bus.h"
+#include "ipu7-buttress-regs.h"
+#include "ipu7-cpd.h"
+#include "ipu7-dma.h"
+#include "ipu7-fw-isys.h"
+#include "ipu7-mmu.h"
+#include "ipu7-isys.h"
+#include "ipu7-isys-csi2.h"
+#include "ipu7-isys-csi-phy.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-isys-video.h"
+#include "ipu7-platform-regs.h"
+
+#define ISYS_PM_QOS_VALUE	300
+
+static int
+isys_complete_ext_device_registration(struct ipu7_isys *isys,
+				      struct v4l2_subdev *sd,
+				      struct ipu7_isys_csi2_config *csi2)
+{
+	struct device *dev = &isys->adev->auxdev.dev;
+	unsigned int i;
+	int ret;
+
+	v4l2_set_subdev_hostdata(sd, csi2);
+
+	for (i = 0; i < sd->entity.num_pads; i++) {
+		if (sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
+			break;
+	}
+
+	if (i == sd->entity.num_pads) {
+		dev_warn(dev, "no source pad in external entity\n");
+		ret = -ENOENT;
+		goto skip_unregister_subdev;
+	}
+
+	ret = media_create_pad_link(&sd->entity, i,
+				    &isys->csi2[csi2->port].asd.sd.entity,
+				    0, MEDIA_LNK_FL_ENABLED |
+				    MEDIA_LNK_FL_IMMUTABLE);
+	if (ret) {
+		dev_warn(dev, "can't create link\n");
+		goto skip_unregister_subdev;
+	}
+
+	isys->csi2[csi2->port].nlanes = csi2->nlanes;
+	if (csi2->bus_type == V4L2_MBUS_CSI2_DPHY)
+		isys->csi2[csi2->port].phy_mode = PHY_MODE_DPHY;
+	else
+		isys->csi2[csi2->port].phy_mode = PHY_MODE_CPHY;
+
+	return 0;
+
+skip_unregister_subdev:
+	v4l2_device_unregister_subdev(sd);
+	return ret;
+}
+
+static void isys_stream_init(struct ipu7_isys *isys)
+{
+	unsigned int i;
+
+	for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) {
+		mutex_init(&isys->streams[i].mutex);
+		init_completion(&isys->streams[i].stream_open_completion);
+		init_completion(&isys->streams[i].stream_close_completion);
+		init_completion(&isys->streams[i].stream_start_completion);
+		init_completion(&isys->streams[i].stream_stop_completion);
+		INIT_LIST_HEAD(&isys->streams[i].queues);
+		isys->streams[i].isys = isys;
+		isys->streams[i].stream_handle = i;
+		isys->streams[i].vc = INVALID_VC_ID;
+	}
+}
+
+static int isys_fw_log_init(struct ipu7_isys *isys)
+{
+	struct device *dev = &isys->adev->auxdev.dev;
+	struct isys_fw_log *fw_log;
+	void *log_buf;
+
+	if (isys->fw_log)
+		return 0;
+
+	fw_log = devm_kzalloc(dev, sizeof(*fw_log), GFP_KERNEL);
+	if (!fw_log)
+		return -ENOMEM;
+
+	mutex_init(&fw_log->mutex);
+
+	log_buf = devm_kzalloc(dev, FW_LOG_BUF_SIZE, GFP_KERNEL);
+	if (!log_buf)
+		return -ENOMEM;
+
+	fw_log->head = log_buf;
+	fw_log->addr = log_buf;
+	fw_log->count = 0;
+	fw_log->size = 0;
+
+	isys->fw_log = fw_log;
+
+	return 0;
+}
+
+/* The .bound() notifier callback when a match is found */
+static int isys_notifier_bound(struct v4l2_async_notifier *notifier,
+			       struct v4l2_subdev *sd,
+			       struct v4l2_async_connection *asc)
+{
+	struct ipu7_isys *isys = container_of(notifier,
+					      struct ipu7_isys, notifier);
+	struct sensor_async_sd *s_asd =
+		container_of(asc, struct sensor_async_sd, asc);
+	struct device *dev = &isys->adev->auxdev.dev;
+	int ret;
+
+	ret = ipu_bridge_instantiate_vcm(sd->dev);
+	if (ret) {
+		dev_err(dev, "instantiate vcm failed\n");
+		return ret;
+	}
+
+	dev_info(dev, "bind %s nlanes is %d port is %d\n",
+		 sd->name, s_asd->csi2.nlanes, s_asd->csi2.port);
+	isys_complete_ext_device_registration(isys, sd, &s_asd->csi2);
+
+	return v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
+}
+
+static int isys_notifier_complete(struct v4l2_async_notifier *notifier)
+{
+	struct ipu7_isys *isys = container_of(notifier,
+					      struct ipu7_isys, notifier);
+
+	dev_info(&isys->adev->auxdev.dev,
+		 "All sensor registration completed.\n");
+
+	return v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
+}
+
+static const struct v4l2_async_notifier_operations isys_async_ops = {
+	.bound = isys_notifier_bound,
+	.complete = isys_notifier_complete,
+};
+
+static int isys_notifier_init(struct ipu7_isys *isys)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2 =
+		&isys->pdata->ipdata->csi2;
+	struct ipu7_device *isp = isys->adev->isp;
+	struct device *dev = &isp->pdev->dev;
+	unsigned int i;
+	int ret;
+
+	v4l2_async_nf_init(&isys->notifier, &isys->v4l2_dev);
+
+	for (i = 0; i < csi2->nports; i++) {
+		struct v4l2_fwnode_endpoint vep = {
+			.bus_type = V4L2_MBUS_UNKNOWN
+		};
+		struct sensor_async_sd *s_asd;
+		struct fwnode_handle *ep;
+
+		ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), i, 0,
+						     FWNODE_GRAPH_ENDPOINT_NEXT);
+		if (!ep)
+			continue;
+
+		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+		if (ret)
+			goto err_parse;
+
+		if (vep.bus_type != V4L2_MBUS_CSI2_DPHY &&
+		    vep.bus_type != V4L2_MBUS_CSI2_CPHY) {
+			ret = -EINVAL;
+			dev_err(dev, "unsupported bus type %d!\n",
+				vep.bus_type);
+			goto err_parse;
+		}
+
+		s_asd = v4l2_async_nf_add_fwnode_remote(&isys->notifier, ep,
+							struct
+							sensor_async_sd);
+		if (IS_ERR(s_asd)) {
+			ret = PTR_ERR(s_asd);
+			goto err_parse;
+		}
+
+		s_asd->csi2.port = vep.base.port;
+		s_asd->csi2.nlanes = vep.bus.mipi_csi2.num_data_lanes;
+		s_asd->csi2.bus_type = vep.bus_type;
+
+		fwnode_handle_put(ep);
+
+		continue;
+
+err_parse:
+		fwnode_handle_put(ep);
+		return ret;
+	}
+
+	if (list_empty(&isys->notifier.waiting_list)) {
+		/* isys probe could continue with async subdevs missing */
+		dev_warn(dev, "no subdev found in graph\n");
+		return 0;
+	}
+
+	isys->notifier.ops = &isys_async_ops;
+	ret = v4l2_async_nf_register(&isys->notifier);
+	if (ret) {
+		dev_err(dev, "failed to register async notifier(%d)\n", ret);
+		v4l2_async_nf_cleanup(&isys->notifier);
+	}
+
+	return ret;
+}
+
+static void isys_notifier_cleanup(struct ipu7_isys *isys)
+{
+	v4l2_async_nf_unregister(&isys->notifier);
+	v4l2_async_nf_cleanup(&isys->notifier);
+}
+
+static void isys_unregister_video_devices(struct ipu7_isys *isys)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2_pdata =
+		&isys->pdata->ipdata->csi2;
+	unsigned int i, j;
+
+	for (i = 0; i < csi2_pdata->nports; i++)
+		for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++)
+			ipu7_isys_video_cleanup(&isys->csi2[i].av[j]);
+}
+
+static int isys_register_video_devices(struct ipu7_isys *isys)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2_pdata =
+		&isys->pdata->ipdata->csi2;
+	unsigned int i, j;
+	int ret;
+
+	for (i = 0; i < csi2_pdata->nports; i++) {
+		for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) {
+			struct ipu7_isys_video *av = &isys->csi2[i].av[j];
+
+			snprintf(av->vdev.name, sizeof(av->vdev.name),
+				 IPU_ISYS_ENTITY_PREFIX " ISYS Capture %u",
+				 i * IPU7_NR_OF_CSI2_SRC_PADS + j);
+			av->isys = isys;
+			av->aq.vbq.buf_struct_size =
+				sizeof(struct ipu7_isys_video_buffer);
+
+			ret = ipu7_isys_video_init(av);
+			if (ret)
+				goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	i = i + 1U;
+	while (i--) {
+		while (j--)
+			ipu7_isys_video_cleanup(&isys->csi2[i].av[j]);
+		j = IPU7_NR_OF_CSI2_SRC_PADS;
+	}
+
+	return ret;
+}
+
+static void isys_csi2_unregister_subdevices(struct ipu7_isys *isys)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2 =
+		&isys->pdata->ipdata->csi2;
+	unsigned int i;
+
+	for (i = 0; i < csi2->nports; i++)
+		ipu7_isys_csi2_cleanup(&isys->csi2[i]);
+}
+
+static int isys_csi2_register_subdevices(struct ipu7_isys *isys)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2_pdata =
+		&isys->pdata->ipdata->csi2;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < csi2_pdata->nports; i++) {
+		ret = ipu7_isys_csi2_init(&isys->csi2[i], isys,
+					  isys->pdata->base +
+					  csi2_pdata->offsets[i], i);
+		if (ret)
+			goto fail;
+	}
+
+	isys->isr_csi2_mask = IPU7_CSI_RX_LEGACY_IRQ_MASK;
+
+	return 0;
+
+fail:
+	while (i--)
+		ipu7_isys_csi2_cleanup(&isys->csi2[i]);
+
+	return ret;
+}
+
+static int isys_csi2_create_media_links(struct ipu7_isys *isys)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2_pdata =
+		&isys->pdata->ipdata->csi2;
+	struct device *dev = &isys->adev->auxdev.dev;
+	struct media_entity *sd;
+	unsigned int i, j;
+	int ret;
+
+	for (i = 0; i < csi2_pdata->nports; i++) {
+		sd = &isys->csi2[i].asd.sd.entity;
+
+		for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) {
+			struct ipu7_isys_video *av = &isys->csi2[i].av[j];
+
+			ret = media_create_pad_link(sd, IPU7_CSI2_PAD_SRC + j,
+						    &av->vdev.entity, 0, 0);
+			if (ret) {
+				dev_err(dev, "CSI2 can't create link\n");
+				return ret;
+			}
+
+			av->csi2 = &isys->csi2[i];
+		}
+	}
+
+	return 0;
+}
+
+static int isys_register_devices(struct ipu7_isys *isys)
+{
+	struct device *dev = &isys->adev->auxdev.dev;
+	struct pci_dev *pdev = isys->adev->isp->pdev;
+	int ret;
+
+	media_device_pci_init(&isys->media_dev,
+			      pdev, IPU_MEDIA_DEV_MODEL_NAME);
+
+	strscpy(isys->v4l2_dev.name, isys->media_dev.model,
+		sizeof(isys->v4l2_dev.name));
+
+	ret = media_device_register(&isys->media_dev);
+	if (ret < 0)
+		goto out_media_device_unregister;
+
+	isys->v4l2_dev.mdev = &isys->media_dev;
+	isys->v4l2_dev.ctrl_handler = NULL;
+
+	ret = v4l2_device_register(dev, &isys->v4l2_dev);
+	if (ret < 0)
+		goto out_media_device_unregister;
+
+	ret = isys_register_video_devices(isys);
+	if (ret)
+		goto out_v4l2_device_unregister;
+
+	ret = isys_csi2_register_subdevices(isys);
+	if (ret)
+		goto out_video_unregister_device;
+
+	ret = isys_csi2_create_media_links(isys);
+	if (ret)
+		goto out_csi2_unregister_subdevices;
+
+	ret = isys_notifier_init(isys);
+	if (ret)
+		goto out_csi2_unregister_subdevices;
+
+	return 0;
+
+out_csi2_unregister_subdevices:
+	isys_csi2_unregister_subdevices(isys);
+
+out_video_unregister_device:
+	isys_unregister_video_devices(isys);
+
+out_v4l2_device_unregister:
+	v4l2_device_unregister(&isys->v4l2_dev);
+
+out_media_device_unregister:
+	media_device_unregister(&isys->media_dev);
+	media_device_cleanup(&isys->media_dev);
+
+	dev_err(dev, "failed to register isys devices\n");
+
+	return ret;
+}
+
+static void isys_unregister_devices(struct ipu7_isys *isys)
+{
+	isys_unregister_video_devices(isys);
+	isys_csi2_unregister_subdevices(isys);
+	v4l2_device_unregister(&isys->v4l2_dev);
+	media_device_unregister(&isys->media_dev);
+	media_device_cleanup(&isys->media_dev);
+}
+
+static void enable_csi2_legacy_irq(struct ipu7_isys *isys, bool enable)
+{
+	u32 offset = IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE;
+	void __iomem *base = isys->pdata->base;
+	u32 mask = isys->isr_csi2_mask;
+
+	if (!enable) {
+		writel(mask, base + offset + IRQ_CTL_CLEAR);
+		writel(0, base + offset + IRQ_CTL_ENABLE);
+		return;
+	}
+
+	writel(mask, base + offset + IRQ_CTL_EDGE);
+	writel(mask, base + offset + IRQ_CTL_CLEAR);
+	writel(mask, base + offset + IRQ_CTL_MASK);
+	writel(mask, base + offset + IRQ_CTL_ENABLE);
+}
+
+static void enable_to_sw_irq(struct ipu7_isys *isys, bool enable)
+{
+	void __iomem *base = isys->pdata->base;
+	u32 mask = IS_UC_TO_SW_IRQ_MASK;
+	u32 offset = IS_UC_CTRL_BASE;
+
+	if (!enable) {
+		writel(0, base + offset + TO_SW_IRQ_CNTL_ENABLE);
+		return;
+	}
+
+	writel(mask, base + offset + TO_SW_IRQ_CNTL_CLEAR);
+	writel(mask, base + offset + TO_SW_IRQ_CNTL_MASK_N);
+	writel(mask, base + offset + TO_SW_IRQ_CNTL_ENABLE);
+}
+
+void ipu7_isys_setup_hw(struct ipu7_isys *isys)
+{
+	u32 offset;
+	void __iomem *base = isys->pdata->base;
+
+	/* soft reset */
+	offset = IS_IO_GPREGS_BASE;
+
+	writel(0x0, base + offset + CLK_EN_TXCLKESC);
+	/* Update if ISYS freq updated (0: 400/1, 1:400/2, 63:400/64) */
+	writel(0x0, base + offset + CLK_DIV_FACTOR_IS_CLK);
+	/* correct the initial printf configuration */
+	writel(0x200, base + IS_UC_CTRL_BASE + PRINTF_AXI_CNTL);
+
+	enable_to_sw_irq(isys, 1);
+	enable_csi2_legacy_irq(isys, 1);
+}
+
+static void isys_cleanup_hw(struct ipu7_isys *isys)
+{
+	enable_csi2_legacy_irq(isys, 0);
+	enable_to_sw_irq(isys, 0);
+}
+
+static int isys_runtime_pm_resume(struct device *dev)
+{
+	struct ipu7_bus_device *adev = to_ipu7_bus_device(dev);
+	struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev);
+	struct ipu7_device *isp = adev->isp;
+	unsigned long flags;
+	int ret;
+
+	if (!isys)
+		return 0;
+
+	ret = ipu7_mmu_hw_init(adev->mmu);
+	if (ret)
+		return ret;
+
+	cpu_latency_qos_update_request(&isys->pm_qos, ISYS_PM_QOS_VALUE);
+
+	ret = ipu_buttress_start_tsc_sync(isp);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&isys->power_lock, flags);
+	isys->power = 1;
+	spin_unlock_irqrestore(&isys->power_lock, flags);
+
+	return 0;
+}
+
+static int isys_runtime_pm_suspend(struct device *dev)
+{
+	struct ipu7_bus_device *adev = to_ipu7_bus_device(dev);
+	struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev);
+	unsigned long flags;
+
+	if (!isys)
+		return 0;
+
+	isys_cleanup_hw(isys);
+
+	spin_lock_irqsave(&isys->power_lock, flags);
+	isys->power = 0;
+	spin_unlock_irqrestore(&isys->power_lock, flags);
+
+	cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
+
+	ipu7_mmu_hw_cleanup(adev->mmu);
+
+	return 0;
+}
+
+static int isys_suspend(struct device *dev)
+{
+	struct ipu7_isys *isys = dev_get_drvdata(dev);
+
+	/* If stream is open, refuse to suspend */
+	if (isys->stream_opened)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int isys_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops isys_pm_ops = {
+	.runtime_suspend = isys_runtime_pm_suspend,
+	.runtime_resume = isys_runtime_pm_resume,
+	.suspend = isys_suspend,
+	.resume = isys_resume,
+};
+
+static void isys_remove(struct auxiliary_device *auxdev)
+{
+	struct ipu7_isys *isys = dev_get_drvdata(&auxdev->dev);
+	struct isys_fw_msgs *fwmsg, *safe;
+	struct ipu7_bus_device *adev = auxdev_to_adev(auxdev);
+
+	for (int i = 0; i < IPU_ISYS_MAX_STREAMS; i++)
+		mutex_destroy(&isys->streams[i].mutex);
+
+	list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist, head)
+		ipu7_dma_free(adev, sizeof(struct isys_fw_msgs),
+			      fwmsg, fwmsg->dma_addr, 0);
+
+	list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist_fw, head)
+		ipu7_dma_free(adev, sizeof(struct isys_fw_msgs),
+			      fwmsg, fwmsg->dma_addr, 0);
+
+	isys_notifier_cleanup(isys);
+	isys_unregister_devices(isys);
+
+	cpu_latency_qos_remove_request(&isys->pm_qos);
+
+	mutex_destroy(&isys->stream_mutex);
+	mutex_destroy(&isys->mutex);
+}
+
+static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount)
+{
+	struct ipu7_bus_device *adev = isys->adev;
+	struct isys_fw_msgs *addr;
+	dma_addr_t dma_addr;
+	unsigned long flags;
+	unsigned int i;
+
+	for (i = 0; i < amount; i++) {
+		addr = ipu7_dma_alloc(adev, sizeof(struct isys_fw_msgs),
+				      &dma_addr, GFP_KERNEL, 0);
+		if (!addr)
+			break;
+		addr->dma_addr = dma_addr;
+
+		spin_lock_irqsave(&isys->listlock, flags);
+		list_add(&addr->head, &isys->framebuflist);
+		spin_unlock_irqrestore(&isys->listlock, flags);
+	}
+
+	if (i == amount)
+		return 0;
+
+	spin_lock_irqsave(&isys->listlock, flags);
+	while (!list_empty(&isys->framebuflist)) {
+		addr = list_first_entry(&isys->framebuflist,
+					struct isys_fw_msgs, head);
+		list_del(&addr->head);
+		spin_unlock_irqrestore(&isys->listlock, flags);
+		ipu7_dma_free(adev, sizeof(struct isys_fw_msgs),
+			      addr, addr->dma_addr, 0);
+		spin_lock_irqsave(&isys->listlock, flags);
+	}
+	spin_unlock_irqrestore(&isys->listlock, flags);
+
+	return -ENOMEM;
+}
+
+struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream)
+{
+	struct device *dev = &stream->isys->adev->auxdev.dev;
+	struct ipu7_isys *isys = stream->isys;
+	struct isys_fw_msgs *msg;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&isys->listlock, flags);
+	if (list_empty(&isys->framebuflist)) {
+		spin_unlock_irqrestore(&isys->listlock, flags);
+		dev_dbg(dev, "Frame buffer list empty\n");
+
+		ret = alloc_fw_msg_bufs(isys, 5);
+		if (ret < 0)
+			return NULL;
+
+		spin_lock_irqsave(&isys->listlock, flags);
+		if (list_empty(&isys->framebuflist)) {
+			spin_unlock_irqrestore(&isys->listlock, flags);
+			dev_err(dev, "Frame list empty\n");
+			return NULL;
+		}
+	}
+	msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head);
+	list_move(&msg->head, &isys->framebuflist_fw);
+	spin_unlock_irqrestore(&isys->listlock, flags);
+	memset(&msg->fw_msg, 0, sizeof(msg->fw_msg));
+
+	return msg;
+}
+
+void ipu7_cleanup_fw_msg_bufs(struct ipu7_isys *isys)
+{
+	struct isys_fw_msgs *fwmsg, *fwmsg0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&isys->listlock, flags);
+	list_for_each_entry_safe(fwmsg, fwmsg0, &isys->framebuflist_fw, head)
+		list_move(&fwmsg->head, &isys->framebuflist);
+	spin_unlock_irqrestore(&isys->listlock, flags);
+}
+
+void ipu7_put_fw_msg_buf(struct ipu7_isys *isys, uintptr_t data)
+{
+	struct isys_fw_msgs *msg;
+	void *ptr = (void *)data;
+	unsigned long flags;
+
+	if (WARN_ON_ONCE(!ptr))
+		return;
+
+	spin_lock_irqsave(&isys->listlock, flags);
+	msg = container_of(ptr, struct isys_fw_msgs, fw_msg.dummy);
+	list_move(&msg->head, &isys->framebuflist);
+	spin_unlock_irqrestore(&isys->listlock, flags);
+}
+
+static int isys_probe(struct auxiliary_device *auxdev,
+		      const struct auxiliary_device_id *auxdev_id)
+{
+	const struct ipu7_isys_internal_csi2_pdata *csi2_pdata;
+	struct ipu7_bus_device *adev = auxdev_to_adev(auxdev);
+	struct ipu7_device *isp = adev->isp;
+	struct ipu7_isys *isys;
+	int ret = 0;
+
+	if (!isp->ipu7_bus_ready_to_probe)
+		return -EPROBE_DEFER;
+
+	isys = devm_kzalloc(&auxdev->dev, sizeof(*isys), GFP_KERNEL);
+	if (!isys)
+		return -ENOMEM;
+
+	ret = pm_runtime_resume_and_get(&auxdev->dev);
+	if (ret < 0)
+		return ret;
+
+	adev->auxdrv_data =
+		(const struct ipu7_auxdrv_data *)auxdev_id->driver_data;
+	adev->auxdrv = to_auxiliary_drv(auxdev->dev.driver);
+	isys->adev = adev;
+	isys->pdata = adev->pdata;
+
+	INIT_LIST_HEAD(&isys->requests);
+	csi2_pdata = &isys->pdata->ipdata->csi2;
+
+	isys->csi2 = devm_kcalloc(&auxdev->dev, csi2_pdata->nports,
+				  sizeof(*isys->csi2), GFP_KERNEL);
+	if (!isys->csi2) {
+		ret = -ENOMEM;
+		goto out_runtime_put;
+	}
+
+	ret = ipu7_mmu_hw_init(adev->mmu);
+	if (ret)
+		goto out_runtime_put;
+
+	spin_lock_init(&isys->streams_lock);
+	spin_lock_init(&isys->power_lock);
+	isys->power = 0;
+
+	mutex_init(&isys->mutex);
+	mutex_init(&isys->stream_mutex);
+
+	spin_lock_init(&isys->listlock);
+	INIT_LIST_HEAD(&isys->framebuflist);
+	INIT_LIST_HEAD(&isys->framebuflist_fw);
+
+	dev_set_drvdata(&auxdev->dev, isys);
+
+	isys->icache_prefetch = 0;
+	isys->phy_rext_cal = 0;
+
+	isys_stream_init(isys);
+
+	cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
+	ret = alloc_fw_msg_bufs(isys, 20);
+	if (ret < 0)
+		goto out_cleanup_isys;
+
+	ret = ipu7_fw_isys_init(isys);
+	if (ret)
+		goto out_cleanup_isys;
+
+	ret = isys_register_devices(isys);
+	if (ret)
+		goto out_cleanup_fw;
+
+	ret = isys_fw_log_init(isys);
+	if (ret)
+		goto out_cleanup;
+
+	ipu7_mmu_hw_cleanup(adev->mmu);
+	pm_runtime_put(&auxdev->dev);
+
+	return 0;
+
+out_cleanup:
+	isys_unregister_devices(isys);
+out_cleanup_fw:
+	ipu7_fw_isys_release(isys);
+out_cleanup_isys:
+	cpu_latency_qos_remove_request(&isys->pm_qos);
+
+	for (unsigned int i = 0; i < IPU_ISYS_MAX_STREAMS; i++)
+		mutex_destroy(&isys->streams[i].mutex);
+
+	mutex_destroy(&isys->mutex);
+	mutex_destroy(&isys->stream_mutex);
+
+	ipu7_mmu_hw_cleanup(adev->mmu);
+
+out_runtime_put:
+	pm_runtime_put(&auxdev->dev);
+
+	return ret;
+}
+
+struct ipu7_csi2_error {
+	const char *error_string;
+	bool is_info_only;
+};
+
+/*
+ * Strings corresponding to CSI-2 receiver errors are here.
+ * Corresponding macros are defined in the header file.
+ */
+static const struct ipu7_csi2_error dphy_rx_errors[] = {
+	{ "Error handler FIFO full", false },
+	{ "Reserved Short Packet encoding detected", true },
+	{ "Reserved Long Packet encoding detected", true },
+	{ "Received packet is too short", false},
+	{ "Received packet is too long", false},
+	{ "Short packet discarded due to errors", false },
+	{ "Long packet discarded due to errors", false },
+	{ "CSI Combo Rx interrupt", false },
+	{ "IDI CDC FIFO overflow(remaining bits are reserved as 0)", false },
+	{ "Received NULL packet", true },
+	{ "Received blanking packet", true },
+	{ "Tie to 0", true },
+	{ }
+};
+
+static void ipu7_isys_register_errors(struct ipu7_isys_csi2 *csi2)
+{
+	u32 offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+	u32 status = readl(csi2->base + offset + IRQ_CTL_STATUS);
+	u32 mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+
+	if (!status)
+		return;
+
+	dev_dbg(&csi2->isys->adev->auxdev.dev, "csi2-%u error status 0x%08x\n",
+		csi2->port, status);
+
+	writel(status & mask, csi2->base + offset + IRQ_CTL_CLEAR);
+	csi2->receiver_errors |= status & mask;
+}
+
+static void ipu7_isys_csi2_error(struct ipu7_isys_csi2 *csi2)
+{
+	struct ipu7_csi2_error const *errors;
+	unsigned int i;
+	u32 status;
+
+	/* Register errors once more in case of error interrupts are disabled */
+	ipu7_isys_register_errors(csi2);
+	status = csi2->receiver_errors;
+	csi2->receiver_errors = 0;
+	errors = dphy_rx_errors;
+
+	for (i = 0; i < CSI_RX_NUM_ERRORS_IN_IRQ; i++) {
+		if (status & BIT(i))
+			dev_err_ratelimited(&csi2->isys->adev->auxdev.dev,
+					    "csi2-%i error: %s\n",
+					    csi2->port,
+					    errors[i].error_string);
+	}
+}
+
+struct resp_to_msg {
+	enum ipu7_insys_resp_type type;
+	const char *msg;
+};
+
+static const struct resp_to_msg is_fw_msg[] = {
+	{IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE,
+	 "IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE"},
+	{IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
+	 "IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK"},
+	{IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK,
+	 "IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK"},
+	{IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK,
+	 "IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK"},
+	{IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK,
+	 "IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK"},
+	{IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK,
+	 "IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK"},
+	{IPU_INSYS_RESP_TYPE_PIN_DATA_READY,
+	 "IPU_INSYS_RESP_TYPE_PIN_DATA_READY"},
+	{IPU_INSYS_RESP_TYPE_FRAME_SOF, "IPU_INSYS_RESP_TYPE_FRAME_SOF"},
+	{IPU_INSYS_RESP_TYPE_FRAME_EOF, "IPU_INSYS_RESP_TYPE_FRAME_EOF"},
+	{IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
+	 "IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE"},
+	{IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE,
+	 "IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE"},
+	{N_IPU_INSYS_RESP_TYPE, "N_IPU_INSYS_RESP_TYPE"},
+};
+
+int isys_isr_one(struct ipu7_bus_device *adev)
+{
+	struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev);
+	struct ipu7_isys_stream *stream = NULL;
+	struct device *dev = &adev->auxdev.dev;
+	struct ipu7_isys_csi2 *csi2 = NULL;
+	struct ia_gofo_msg_err err_info;
+	struct ipu7_insys_resp *resp;
+	u64 ts;
+
+	if (!isys->adev->syscom)
+		return 1;
+
+	resp = ipu7_fw_isys_get_resp(isys);
+	if (!resp)
+		return 1;
+	if (resp->type >= N_IPU_INSYS_RESP_TYPE) {
+		dev_err(dev, "Unknown response type %u stream %u\n",
+			resp->type, resp->stream_id);
+		ipu7_fw_isys_put_resp(isys);
+		return 1;
+	}
+
+	err_info = resp->error_info;
+	ts = ((u64)resp->timestamp[1] << 32) | resp->timestamp[0];
+	if (err_info.err_group == INSYS_MSG_ERR_GROUP_CAPTURE &&
+	    err_info.err_code == INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP) {
+		/* receive a sp w/o command, firmware drop it */
+		dev_dbg(dev, "FRAME DROP: %02u %s stream %u\n",
+			resp->type, is_fw_msg[resp->type].msg,
+			resp->stream_id);
+		dev_dbg(dev, "\tpin %u buf_id %llx frame %u\n",
+			resp->pin_id, resp->buf_id, resp->frame_id);
+		dev_dbg(dev, "\terror group %u code %u details [%u %u]\n",
+			err_info.err_group, err_info.err_code,
+			err_info.err_detail[0], err_info.err_detail[1]);
+	} else if (!IA_GOFO_MSG_ERR_IS_OK(err_info)) {
+		dev_err(dev, "%02u %s stream %u pin %u buf_id %llx frame %u\n",
+			resp->type, is_fw_msg[resp->type].msg, resp->stream_id,
+			resp->pin_id, resp->buf_id, resp->frame_id);
+		dev_err(dev, "\terror group %u code %u details [%u %u]\n",
+			err_info.err_group, err_info.err_code,
+			err_info.err_detail[0], err_info.err_detail[1]);
+	} else {
+		dev_dbg(dev, "%02u %s stream %u pin %u buf_id %llx frame %u\n",
+			resp->type, is_fw_msg[resp->type].msg, resp->stream_id,
+			resp->pin_id, resp->buf_id, resp->frame_id);
+		dev_dbg(dev, "\tts %llu\n", ts);
+	}
+
+	if (resp->stream_id >= IPU_ISYS_MAX_STREAMS) {
+		dev_err(dev, "bad stream handle %u\n",
+			resp->stream_id);
+		goto leave;
+	}
+
+	stream = ipu7_isys_query_stream_by_handle(isys, resp->stream_id);
+	if (!stream) {
+		dev_err(dev, "stream of stream_handle %u is unused\n",
+			resp->stream_id);
+		goto leave;
+	}
+
+	stream->error = err_info.err_code;
+
+	if (stream->asd)
+		csi2 = ipu7_isys_subdev_to_csi2(stream->asd);
+
+	switch (resp->type) {
+	case IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE:
+		complete(&stream->stream_open_completion);
+		break;
+	case IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK:
+		complete(&stream->stream_close_completion);
+		break;
+	case IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
+		complete(&stream->stream_start_completion);
+		break;
+	case IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK:
+		complete(&stream->stream_stop_completion);
+		break;
+	case IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK:
+		complete(&stream->stream_stop_completion);
+		break;
+	case IPU_INSYS_RESP_TYPE_PIN_DATA_READY:
+		/*
+		 * firmware only release the capture msg until software
+		 * get pin_data_ready event
+		 */
+		ipu7_put_fw_msg_buf(ipu7_bus_get_drvdata(adev), resp->buf_id);
+		if (resp->pin_id < IPU_INSYS_OUTPUT_PINS &&
+		    stream->output_pins[resp->pin_id].pin_ready)
+			stream->output_pins[resp->pin_id].pin_ready(stream,
+								    resp);
+		else
+			dev_err(dev, "No handler for pin %u ready\n",
+				resp->pin_id);
+		if (csi2)
+			ipu7_isys_csi2_error(csi2);
+
+		break;
+	case IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK:
+		break;
+	case IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
+	case IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE:
+		break;
+	case IPU_INSYS_RESP_TYPE_FRAME_SOF:
+		if (csi2)
+			ipu7_isys_csi2_sof_event_by_stream(stream);
+
+		stream->seq[stream->seq_index].sequence =
+			atomic_read(&stream->sequence) - 1U;
+		stream->seq[stream->seq_index].timestamp = ts;
+		dev_dbg(dev,
+			"SOF: stream %u frame %u (index %u), ts 0x%16.16llx\n",
+			resp->stream_id, resp->frame_id,
+			stream->seq[stream->seq_index].sequence, ts);
+		stream->seq_index = (stream->seq_index + 1U)
+			% IPU_ISYS_MAX_PARALLEL_SOF;
+		break;
+	case IPU_INSYS_RESP_TYPE_FRAME_EOF:
+		if (csi2)
+			ipu7_isys_csi2_eof_event_by_stream(stream);
+
+		dev_dbg(dev, "eof: stream %d(index %u) ts 0x%16.16llx\n",
+			resp->stream_id,
+			stream->seq[stream->seq_index].sequence, ts);
+		break;
+	default:
+		dev_err(dev, "Unknown response type %u stream %u\n",
+			resp->type, resp->stream_id);
+		break;
+	}
+
+	ipu7_isys_put_stream(stream);
+leave:
+	ipu7_fw_isys_put_resp(isys);
+
+	return 0;
+}
+
+static void ipu7_isys_csi2_isr(struct ipu7_isys_csi2 *csi2)
+{
+	struct device *dev = &csi2->isys->adev->auxdev.dev;
+	struct ipu7_device *isp = csi2->isys->adev->isp;
+	struct ipu7_isys_stream *s;
+	u32 sync, offset;
+	u32 fe = 0;
+	u8 vc;
+
+	ipu7_isys_register_errors(csi2);
+
+	offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+	sync = readl(csi2->base + offset + IRQ_CTL_STATUS);
+	writel(sync, csi2->base + offset + IRQ_CTL_CLEAR);
+	dev_dbg(dev, "csi2-%u sync status 0x%08x\n", csi2->port, sync);
+
+	if (!is_ipu7(isp->hw_ver)) {
+		fe = readl(csi2->base + offset + IRQ1_CTL_STATUS);
+		writel(fe, csi2->base + offset + IRQ1_CTL_CLEAR);
+		dev_dbg(dev, "csi2-%u FE status 0x%08x\n", csi2->port, fe);
+	}
+
+	for (vc = 0; vc < IPU7_NR_OF_CSI2_VC && (sync || fe); vc++) {
+		s = ipu7_isys_query_stream_by_source(csi2->isys,
+						     csi2->asd.source, vc);
+		if (!s)
+			continue;
+
+		if (!is_ipu7(isp->hw_ver)) {
+			if (sync & IPU7P5_CSI_RX_SYNC_FS_VC & (1U << vc))
+				ipu7_isys_csi2_sof_event_by_stream(s);
+
+			if (fe & IPU7P5_CSI_RX_SYNC_FE_VC & (1U << vc))
+				ipu7_isys_csi2_eof_event_by_stream(s);
+		} else {
+			if (sync & IPU7_CSI_RX_SYNC_FS_VC & (1U << (vc * 2)))
+				ipu7_isys_csi2_sof_event_by_stream(s);
+
+			if (sync & IPU7_CSI_RX_SYNC_FE_VC & (2U << (vc * 2)))
+				ipu7_isys_csi2_eof_event_by_stream(s);
+		}
+	}
+}
+
+static irqreturn_t isys_isr(struct ipu7_bus_device *adev)
+{
+	struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev);
+	u32 status_csi, status_sw, csi_offset, sw_offset;
+	struct device *dev = &isys->adev->auxdev.dev;
+	void __iomem *base = isys->pdata->base;
+
+	spin_lock(&isys->power_lock);
+	if (!isys->power) {
+		spin_unlock(&isys->power_lock);
+		return IRQ_NONE;
+	}
+
+	csi_offset = IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE;
+	sw_offset = IS_BASE;
+
+	status_csi = readl(base + csi_offset + IRQ_CTL_STATUS);
+	status_sw = readl(base + sw_offset + TO_SW_IRQ_CNTL_STATUS);
+	if (!status_csi && !status_sw) {
+		spin_unlock(&isys->power_lock);
+		return IRQ_NONE;
+	}
+
+	if (status_csi)
+		dev_dbg(dev, "status csi 0x%08x\n", status_csi);
+	if (status_sw)
+		dev_dbg(dev, "status to_sw 0x%08x\n", status_sw);
+
+	do {
+		writel(status_sw, base + sw_offset + TO_SW_IRQ_CNTL_CLEAR);
+		writel(status_csi, base + csi_offset + IRQ_CTL_CLEAR);
+
+		if (isys->isr_csi2_mask & status_csi) {
+			unsigned int i;
+
+			for (i = 0; i < isys->pdata->ipdata->csi2.nports; i++) {
+				/* irq from not enabled port */
+				if (!isys->csi2[i].base)
+					continue;
+				if (status_csi & isys->csi2[i].legacy_irq_mask)
+					ipu7_isys_csi2_isr(&isys->csi2[i]);
+			}
+		}
+
+		if (!isys_isr_one(adev))
+			status_sw = TO_SW_IRQ_FW;
+		else
+			status_sw = 0;
+
+		status_csi = readl(base + csi_offset + IRQ_CTL_STATUS);
+		status_sw |= readl(base + sw_offset + TO_SW_IRQ_CNTL_STATUS);
+	} while ((status_csi & isys->isr_csi2_mask) ||
+		 (status_sw & TO_SW_IRQ_FW));
+
+	writel(TO_SW_IRQ_MASK, base + sw_offset + TO_SW_IRQ_CNTL_MASK_N);
+
+	spin_unlock(&isys->power_lock);
+
+	return IRQ_HANDLED;
+}
+
+static const struct ipu7_auxdrv_data ipu7_isys_auxdrv_data = {
+	.isr = isys_isr,
+	.isr_threaded = NULL,
+	.wake_isr_thread = false,
+};
+
+static const struct auxiliary_device_id ipu7_isys_id_table[] = {
+	{
+		.name = "intel_ipu7.isys",
+		.driver_data = (kernel_ulong_t)&ipu7_isys_auxdrv_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(auxiliary, ipu7_isys_id_table);
+
+static struct auxiliary_driver isys_driver = {
+	.name = IPU_ISYS_NAME,
+	.probe = isys_probe,
+	.remove = isys_remove,
+	.id_table = ipu7_isys_id_table,
+	.driver = {
+		.pm = &isys_pm_ops,
+	},
+};
+
+module_auxiliary_driver(isys_driver);
+
+MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
+MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
+MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel ipu7 input system driver");
+MODULE_IMPORT_NS("INTEL_IPU7");
+MODULE_IMPORT_NS("INTEL_IPU_BRIDGE");
diff --git a/drivers/staging/media/ipu7/ipu7-isys.h b/drivers/staging/media/ipu7/ipu7-isys.h
new file mode 100644
index 000000000000..ef1ab1b42f6c
--- /dev/null
+++ b/drivers/staging/media/ipu7/ipu7-isys.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2025 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_H
+#define IPU7_ISYS_H
+
+#include <linux/irqreturn.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/pm_qos.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+
+#include "abi/ipu7_fw_msg_abi.h"
+#include "abi/ipu7_fw_isys_abi.h"
+
+#include "ipu7.h"
+#include "ipu7-isys-csi2.h"
+#include "ipu7-isys-video.h"
+
+#define IPU_ISYS_ENTITY_PREFIX		"Intel IPU7"
+
+/* FW support max 16 streams */
+#define IPU_ISYS_MAX_STREAMS		16U
+
+/*
+ * Current message queue configuration. These must be big enough
+ * so that they never gets full. Queues are located in system memory
+ */
+#define IPU_ISYS_SIZE_RECV_QUEUE	40U
+#define IPU_ISYS_SIZE_LOG_QUEUE		256U
+#define IPU_ISYS_SIZE_SEND_QUEUE	40U
+#define IPU_ISYS_NUM_RECV_QUEUE		1U
+
+#define IPU_ISYS_MIN_WIDTH		2U
+#define IPU_ISYS_MIN_HEIGHT		2U
+#define IPU_ISYS_MAX_WIDTH		8160U
+#define IPU_ISYS_MAX_HEIGHT		8190U
+
+#define FW_CALL_TIMEOUT_JIFFIES		\
+	msecs_to_jiffies(IPU_LIB_CALL_TIMEOUT_MS)
+
+struct isys_fw_log {
+	struct mutex mutex; /* protect whole struct */
+	void *head;
+	void *addr;
+	u32 count; /* running counter of log */
+	u32 size; /* actual size of log content, in bits */
+};
+
+/*
+ * struct ipu7_isys
+ *
+ * @media_dev: Media device
+ * @v4l2_dev: V4L2 device
+ * @adev: ISYS bus device
+ * @power: Is ISYS powered on or not?
+ * @isr_bits: Which bits does the ISR handle?
+ * @power_lock: Serialise access to power (power state in general)
+ * @csi2_rx_ctrl_cached: cached shared value between all CSI2 receivers
+ * @streams_lock: serialise access to streams
+ * @streams: streams per firmware stream ID
+ * @syscom: fw communication layer context
+ * @ref_count: total number of callers fw open
+ * @mutex: serialise access isys video open/release related operations
+ * @stream_mutex: serialise stream start and stop, queueing requests
+ * @pdata: platform data pointer
+ * @csi2: CSI-2 receivers
+ */
+struct ipu7_isys {
+	struct media_device media_dev;
+	struct v4l2_device v4l2_dev;
+	struct ipu7_bus_device *adev;
+
+	int power;
+	spinlock_t power_lock;	/* Serialise access to power */
+	u32 isr_csi2_mask;
+	u32 csi2_rx_ctrl_cached;
+	spinlock_t streams_lock;
+	struct ipu7_isys_stream streams[IPU_ISYS_MAX_STREAMS];
+	int streams_ref_count[IPU_ISYS_MAX_STREAMS];
+	u32 phy_rext_cal;
+	bool icache_prefetch;
+	bool csi2_cse_ipc_not_supported;
+	unsigned int ref_count;
+	unsigned int stream_opened;
+
+	struct mutex mutex;	/* Serialise isys video open/release related */
+	struct mutex stream_mutex;	/* Stream start, stop, queueing reqs */
+
+	struct ipu7_isys_pdata *pdata;
+
+	struct ipu7_isys_csi2 *csi2;
+	struct isys_fw_log *fw_log;
+
+	struct list_head requests;
+	struct pm_qos_request pm_qos;
+	spinlock_t listlock;	/* Protect framebuflist */
+	struct list_head framebuflist;
+	struct list_head framebuflist_fw;
+	struct v4l2_async_notifier notifier;
+
+	struct ipu7_insys_config *subsys_config;
+	dma_addr_t subsys_config_dma_addr;
+};
+
+struct isys_fw_msgs {
+	union {
+		u64 dummy;
+		struct ipu7_insys_buffset frame;
+		struct ipu7_insys_stream_cfg stream;
+	} fw_msg;
+	struct list_head head;
+	dma_addr_t dma_addr;
+};
+
+struct ipu7_isys_csi2_config {
+	unsigned int nlanes;
+	unsigned int port;
+	enum v4l2_mbus_type bus_type;
+};
+
+struct sensor_async_sd {
+	struct v4l2_async_connection asc;
+	struct ipu7_isys_csi2_config csi2;
+};
+
+struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream);
+void ipu7_put_fw_msg_buf(struct ipu7_isys *isys, uintptr_t data);
+void ipu7_cleanup_fw_msg_bufs(struct ipu7_isys *isys);
+int isys_isr_one(struct ipu7_bus_device *adev);
+void ipu7_isys_setup_hw(struct ipu7_isys *isys);
+#endif /* IPU7_ISYS_H */
