Linux Media Controller development
 help / color / mirror / Atom feed
* [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware
@ 2026-08-21 11:42 Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation Antti Laakso
                   ` (43 more replies)
  0 siblings, 44 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Hello,

The 7th Gen Intel Imaging Processing Unit is a PCI device including
input system and processing system. This set adds support for ISYS
in IPU7 and IPU7.5.

Changes since v1:
- Fixed review and checkpatch issues.
- Fixed a bug in ipu6 fw communication.
- Added missing bits for ipu7 CSI2 initialization.
- Changed IPU runtime detection.
- Added IPU7.5 support.

Antti Laakso (44):
  media: ipu6: Add helpers for IPU runtime variation
  media: ipu6: Rename pointer to firmware context
  media: ipu6: Rename buttress_ipc pointer
  media: ipu6: Remove duplicate warnings in cpd validation
  media: ipu6: Remove unused ipu6 firmware struct
  media: ipu6: Cleanup ipu6_mmu_init()
  media: ipu6: Simplify firmware com arguments
  media: ipu6: Add helper to identify ipu7
  media: ipu6: Prepare buttress for ipu7 support
  media: ipu6: Use single struct for registers
  media: ipu6: Rename IPU subsys ID
  media: ipu6: Add ipu7 buttress support
  media: ipu6: Prepare mmu driver for hw variation
  media: ipu6: Add ipu7 mmu support
  media: ipu6: Add ipu7 cpd handling
  media: ipu6: Add check for pkg_dir before freeing
  media: ipu6: Rename isys fw msg union
  media: ipu6: Move isys isr handlers to fw file
  media: ipu6: Move hw specific buffer handling down
  media: ipu6: Isolate hw specific buffer handling
  media: ipu6: Add isys firmware ops
  media: ipu6: Add ipu7 fw start/stop functionality
  media: ipu6: Add ipu7 fw com methods
  media: ipu6: Add ipu7 fw isys ops
  media: ipu6: Add ipu7 csi2 register definitions
  media: ipu6: Add ipu7 isr handler
  media: ipu6: Add ipu7 csi phy driver
  media: ipu6: Split ipu6 csi2 stream enable/disable
  media: ipu6: Add support for ipu7 csi2 receiver
  media: ipu6: Parse bus type for ipu7
  media: ipu6: Enable ipu7 isys interrupts
  media: ipu6: Skip watermark configuration for ipu7
  media: ipu6: The SPC init is valid only for ipu6
  media: ipu6: The VC arbitration mechanism is ipu6 only
  media: ipu6: Move buttress mem alloc out from probe
  media: ipu6: Read correct SKU ID for ipu7
  media: ipu6: Add support for fixed iova region
  media: ipu6: Make fw mapping function reusable
  media: ipu6: Move isys fw mapping to pci_probe
  media: ipu6: Map ipu7 firmware
  media: ipu6: Set model name for ipu7
  media: ipu6: Add ipu7.5 buttress support
  media: ipu6: Add ipu7.5 mmu initialization data
  media: ipu6: Enable ipu7 and ipu7.5

 drivers/media/pci/intel/ipu6/Makefile         |   10 +-
 drivers/media/pci/intel/ipu6/ipu6-bus.h       |    6 +-
 drivers/media/pci/intel/ipu6/ipu6-buttress.c  |  568 +++++---
 drivers/media/pci/intel/ipu6/ipu6-buttress.h  |   50 +-
 drivers/media/pci/intel/ipu6/ipu6-cpd.c       |  195 ++-
 drivers/media/pci/intel/ipu6/ipu6-cpd.h       |   43 +
 drivers/media/pci/intel/ipu6/ipu6-dma.c       |   24 +-
 drivers/media/pci/intel/ipu6/ipu6-dma.h       |    2 +
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c   |  589 +++++++-
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.h   |   48 +-
 drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c |  207 ++-
 drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h |    5 +
 .../media/pci/intel/ipu6/ipu6-isys-queue.c    |   87 +-
 .../media/pci/intel/ipu6/ipu6-isys-queue.h    |    6 +-
 .../media/pci/intel/ipu6/ipu6-isys-video.c    |  160 +--
 .../media/pci/intel/ipu6/ipu6-isys-video.h    |    1 +
 drivers/media/pci/intel/ipu6/ipu6-isys.c      |  397 ++----
 drivers/media/pci/intel/ipu6/ipu6-isys.h      |   55 +-
 drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c    |  296 ++++
 drivers/media/pci/intel/ipu6/ipu6-mmu.c       |  133 +-
 drivers/media/pci/intel/ipu6/ipu6-mmu.h       |  158 ++-
 .../intel/ipu6/ipu6-platform-buttress-regs.h  |  111 +-
 drivers/media/pci/intel/ipu6/ipu6.c           |  536 +++++---
 drivers/media/pci/intel/ipu6/ipu6.h           |  200 +--
 drivers/media/pci/intel/ipu6/ipu7-boot.c      |  405 ++++++
 drivers/media/pci/intel/ipu6/ipu7-boot.h      |   46 +
 drivers/media/pci/intel/ipu6/ipu7-fw-com.c    |   74 +
 drivers/media/pci/intel/ipu6/ipu7-fw-com.h    |   53 +
 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c   |  787 +++++++++++
 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h   |  296 ++++
 .../media/pci/intel/ipu6/ipu7-isys-csi-phy.c  | 1072 +++++++++++++++
 .../media/pci/intel/ipu6/ipu7-isys-csi-phy.h  |   16 +
 .../pci/intel/ipu6/ipu7-isys-csi2-regs.h      | 1189 +++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c    |  858 ++++++++++++
 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h    |  254 ++++
 .../media/pci/intel/ipu6/ipu7-platform-regs.h |   32 +
 include/media/ipu6-pci-table.h                |    4 +
 37 files changed, 7596 insertions(+), 1377 deletions(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-boot.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-boot.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-com.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-com.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-platform-regs.h

-- 
2.55.0


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

* [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context Antti Laakso
                   ` (42 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

And replace inline functions with defines.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys.c |  4 +--
 drivers/media/pci/intel/ipu6/ipu6.c      | 29 ++++++++--------
 drivers/media/pci/intel/ipu6/ipu6.h      | 42 +++++-------------------
 3 files changed, 25 insertions(+), 50 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 24db2763de54..799e7b30e6a2 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1104,9 +1104,9 @@ static int isys_probe(struct auxiliary_device *auxdev,
 
 	isys_iwake_watermark_init(isys);
 
-	if (is_ipu6se(adev->isp->hw_ver))
+	if (IS_IPU6SE(adev->isp))
 		isys->phy_set_power = ipu6_isys_jsl_phy_set_power;
-	else if (is_ipu6ep_mtl(adev->isp->hw_ver))
+	else if (IS_IPU6EP_MTL(adev->isp))
 		isys->phy_set_power = ipu6_isys_dwc_phy_set_power;
 	else
 		isys->phy_set_power = ipu6_isys_mcd_phy_set_power;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 5449a2006bcc..6d3235352a1c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -290,8 +290,6 @@ EXPORT_SYMBOL_NS_GPL(ipu6_configure_spc, "INTEL_IPU6");
 
 static void ipu6_internal_pdata_init(struct ipu6_device *isp)
 {
-	u8 hw_ver = isp->hw_ver;
-
 	isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
 	isys_ipdata.sram_gran_shift = IPU6_SRAM_GRANULARITY_SHIFT;
 	isys_ipdata.sram_gran_size = IPU6_SRAM_GRANULARITY_SIZE;
@@ -314,19 +312,19 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
 		IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
 	isys_ipdata.csi2.ctrl0_irq_lnp =
 		IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE;
-	isys_ipdata.enhanced_iwake = is_ipu6ep_mtl(hw_ver) || is_ipu6ep(hw_ver);
+	isys_ipdata.enhanced_iwake = IS_IPU6EP_MTL(isp) || IS_IPU6EP(isp);
 	psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
 	isys_ipdata.csi2.fw_access_port_ofs = CSI_REG_HUB_FW_ACCESS_PORT_OFS;
 
-	if (is_ipu6ep(hw_ver)) {
+	if (IS_IPU6EP(isp)) {
 		isys_ipdata.ltr = IPU6EP_LTR_VALUE;
 		isys_ipdata.memopen_threshold = IPU6EP_MIN_MEMOPEN_TH;
 	}
 
-	if (is_ipu6_tgl(hw_ver))
+	if (IS_IPU6_TGL(isp))
 		isys_ipdata.csi2.nports = IPU6_TGL_ISYS_CSI2_NPORTS;
 
-	if (is_ipu6ep_mtl(hw_ver)) {
+	if (IS_IPU6EP_MTL(isp)) {
 		isys_ipdata.csi2.nports = IPU6EP_MTL_ISYS_CSI2_NPORTS;
 
 		isys_ipdata.csi2.ctrl0_irq_edge =
@@ -347,7 +345,7 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
 		isys_ipdata.memopen_threshold = IPU6EP_MTL_MIN_MEMOPEN_TH;
 	}
 
-	if (is_ipu6se(hw_ver)) {
+	if (IS_IPU6SE(isp)) {
 		isys_ipdata.csi2.nports = IPU6SE_ISYS_CSI2_NPORTS;
 		isys_ipdata.csi2.irq_mask = IPU6SE_CSI_RX_ERROR_IRQ_MASK;
 		isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
@@ -454,12 +452,13 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
 	return psys_adev;
 }
 
-static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver)
+static int ipu6_pci_config_setup(struct pci_dev *dev)
 {
+	struct ipu6_device *isp = pci_get_drvdata(dev);
 	int ret;
 
 	/* No PCI msi capability for IPU6EP */
-	if (is_ipu6ep(hw_ver) || is_ipu6ep_mtl(hw_ver)) {
+	if (IS_IPU6EP(isp) || IS_IPU6EP_MTL(isp)) {
 		/* likely do nothing as msi not enabled by default */
 		pci_disable_msi(dev);
 		return 0;
@@ -525,26 +524,26 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
 	switch (id->device) {
 	case PCI_DEVICE_ID_INTEL_IPU6:
-		isp->hw_ver = IPU6_VER_6;
+		isp->hw_ver = IPU_VERSION_6;
 		isp->cpd_fw_name = IPU6_FIRMWARE_NAME;
 		break;
 	case PCI_DEVICE_ID_INTEL_IPU6SE:
-		isp->hw_ver = IPU6_VER_6SE;
+		isp->hw_ver = IPU_VERSION_6SE;
 		isp->cpd_fw_name = IPU6SE_FIRMWARE_NAME;
 		isp->cpd_metadata_cmpnt_size =
 			sizeof(struct ipu6se_cpd_metadata_cmpnt);
 		break;
 	case PCI_DEVICE_ID_INTEL_IPU6EP_ADLP:
 	case PCI_DEVICE_ID_INTEL_IPU6EP_RPLP:
-		isp->hw_ver = IPU6_VER_6EP;
+		isp->hw_ver = IPU_VERSION_6EP;
 		isp->cpd_fw_name = IPU6EP_FIRMWARE_NAME;
 		break;
 	case PCI_DEVICE_ID_INTEL_IPU6EP_ADLN:
-		isp->hw_ver = IPU6_VER_6EP;
+		isp->hw_ver = IPU_VERSION_6EP;
 		isp->cpd_fw_name = IPU6EPADLN_FIRMWARE_NAME;
 		break;
 	case PCI_DEVICE_ID_INTEL_IPU6EP_MTL:
-		isp->hw_ver = IPU6_VER_6EP_MTL;
+		isp->hw_ver = IPU_VERSION_6EP_MTL;
 		isp->cpd_fw_name = IPU6EPMTL_FIRMWARE_NAME;
 		break;
 	default:
@@ -564,7 +563,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	dma_set_max_seg_size(dev, UINT_MAX);
 
-	ret = ipu6_pci_config_setup(pdev, isp->hw_ver);
+	ret = ipu6_pci_config_setup(pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 92e3c3414c91..07ca59048f44 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -23,39 +23,15 @@ struct ipu6_bus_device;
 #define IPU6EPMTL_FIRMWARE_NAME		"intel/ipu/ipu6epmtl_fw.bin"
 #define IPU6EPADLN_FIRMWARE_NAME	"intel/ipu/ipu6epadln_fw.bin"
 
-enum ipu6_version {
-	IPU6_VER_INVALID = 0,
-	IPU6_VER_6 = 1,
-	IPU6_VER_6SE = 3,
-	IPU6_VER_6EP = 5,
-	IPU6_VER_6EP_MTL = 6,
-};
-
-/*
- * IPU6 - TGL
- * IPU6SE - JSL
- * IPU6EP - ADL/RPL
- * IPU6EP_MTL - MTL
- */
-static inline bool is_ipu6se(u8 hw_ver)
-{
-	return hw_ver == IPU6_VER_6SE;
-}
-
-static inline bool is_ipu6ep(u8 hw_ver)
-{
-	return hw_ver == IPU6_VER_6EP;
-}
-
-static inline bool is_ipu6ep_mtl(u8 hw_ver)
-{
-	return hw_ver == IPU6_VER_6EP_MTL;
-}
-
-static inline bool is_ipu6_tgl(u8 hw_ver)
-{
-	return hw_ver == IPU6_VER_6;
-}
+#define IPU_VERSION_6		BIT(0) /* TGL */
+#define IPU_VERSION_6SE		BIT(1) /* JSL */
+#define IPU_VERSION_6EP		BIT(2) /* ADL/RPL */
+#define IPU_VERSION_6EP_MTL	BIT(3) /* MTL */
+
+#define IS_IPU6_TGL(isp)	((isp)->hw_ver & IPU_VERSION_6)
+#define IS_IPU6SE(isp)		((isp)->hw_ver & IPU_VERSION_6SE)
+#define IS_IPU6EP(isp)		((isp)->hw_ver & IPU_VERSION_6EP)
+#define IS_IPU6EP_MTL(isp)	((isp)->hw_ver & IPU_VERSION_6EP_MTL)
 
 /*
  * ISYS DMA can overshoot. For higher resolutions over allocation is one line
-- 
2.55.0


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

* [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer Antti Laakso
                   ` (41 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The name fwcom is used to refer firmware communication context
and firmware communication configuration. Try to avoid confusion
and rename context variable.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c   | 56 ++++++++++---------
 .../media/pci/intel/ipu6/ipu6-isys-video.c    |  4 +-
 drivers/media/pci/intel/ipu6/ipu6-isys.c      |  6 +-
 drivers/media/pci/intel/ipu6/ipu6-isys.h      |  5 +-
 4 files changed, 36 insertions(+), 35 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 62ed92ff1d30..a65e9f1aa104 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -32,7 +32,7 @@ static int handle_proxy_response(struct ipu6_isys *isys, unsigned int req_id)
 	struct ipu6_fw_isys_proxy_resp_info_abi *resp;
 	int ret;
 
-	resp = ipu6_recv_get_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
+	resp = ipu6_recv_get_token(isys->fwctx, IPU6_BASE_PROXY_RECV_QUEUES);
 	if (!resp)
 		return 1;
 
@@ -42,7 +42,7 @@ static int handle_proxy_response(struct ipu6_isys *isys, unsigned int req_id)
 
 	ret = req_id == resp->request_id ? 0 : -EIO;
 
-	ipu6_recv_put_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
+	ipu6_recv_put_token(isys->fwctx, IPU6_BASE_PROXY_RECV_QUEUES);
 
 	return ret;
 }
@@ -52,7 +52,7 @@ int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
 				  unsigned int index,
 				  unsigned int offset, u32 value)
 {
-	struct ipu6_fw_com_context *ctx = isys->fwcom;
+	struct ipu6_fw_com_context *ctx = isys->fwctx;
 	struct device *dev = &isys->adev->auxdev.dev;
 	struct ipu6_fw_proxy_send_queue_token *token;
 	unsigned int timeout = 1000;
@@ -96,7 +96,7 @@ int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
 			     dma_addr_t dma_mapped_buf,
 			     size_t size, u16 send_type)
 {
-	struct ipu6_fw_com_context *ctx = isys->fwcom;
+	struct ipu6_fw_com_context *ctx = isys->fwctx;
 	struct device *dev = &isys->adev->auxdev.dev;
 	struct ipu6_fw_send_queue_token *token;
 
@@ -138,7 +138,7 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
 	struct device *dev = &isys->adev->auxdev.dev;
 	int retry = IPU6_ISYS_CLOSE_RETRY;
 	unsigned long flags;
-	void *fwcom;
+	void *fwctx;
 	int ret;
 
 	/*
@@ -148,9 +148,9 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
 	 * spinlock to wait the interrupt handler to be finished
 	 */
 	spin_lock_irqsave(&isys->power_lock, flags);
-	ret = ipu6_fw_com_close(isys->fwcom);
-	fwcom = isys->fwcom;
-	isys->fwcom = NULL;
+	ret = ipu6_fw_com_close(isys->fwctx);
+	fwctx = isys->fwctx;
+	isys->fwctx = NULL;
 	spin_unlock_irqrestore(&isys->power_lock, flags);
 	if (ret)
 		dev_err(dev, "Device close failure: %d\n", ret);
@@ -158,14 +158,14 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
 	/* release probably fails if the close failed. Let's try still */
 	do {
 		usleep_range(400, 500);
-		ret = ipu6_fw_com_release(fwcom, 0);
+		ret = ipu6_fw_com_release(fwctx, 0);
 		retry--;
 	} while (ret && retry);
 
 	if (ret) {
 		dev_err(dev, "Device release time out %d\n", ret);
 		spin_lock_irqsave(&isys->power_lock, flags);
-		isys->fwcom = fwcom;
+		isys->fwctx = fwctx;
 		spin_unlock_irqrestore(&isys->power_lock, flags);
 	}
 
@@ -176,11 +176,11 @@ void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
 {
 	int ret;
 
-	ret = ipu6_fw_com_release(isys->fwcom, 1);
+	ret = ipu6_fw_com_release(isys->fwctx, 1);
 	if (ret < 0)
 		dev_warn(&isys->adev->auxdev.dev,
 			 "Device busy, fw_com release failed.");
-	isys->fwcom = NULL;
+	isys->fwctx = NULL;
 }
 
 static void start_sp(struct ipu6_bus_device *adev)
@@ -212,7 +212,7 @@ static int query_sp(struct ipu6_bus_device *adev)
 }
 
 static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
-				    struct ipu6_fw_com_cfg *fwcom,
+				    struct ipu6_fw_com_cfg *fwcom_cfg,
 				    unsigned int num_streams)
 {
 	unsigned int max_send_queues, max_sram_blocks, max_devq_size;
@@ -258,14 +258,16 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
 	if (!output_queue_cfg)
 		return -ENOMEM;
 
-	fwcom->input = input_queue_cfg;
-	fwcom->output = output_queue_cfg;
+	fwcom_cfg->input = input_queue_cfg;
+	fwcom_cfg->output = output_queue_cfg;
 
-	fwcom->num_input_queues = isys_fw_cfg->num_send_queues[type_proxy] +
+	fwcom_cfg->num_input_queues =
+		isys_fw_cfg->num_send_queues[type_proxy] +
 		isys_fw_cfg->num_send_queues[type_dev] +
 		isys_fw_cfg->num_send_queues[type_msg];
 
-	fwcom->num_output_queues = isys_fw_cfg->num_recv_queues[type_proxy] +
+	fwcom_cfg->num_output_queues =
+		isys_fw_cfg->num_recv_queues[type_proxy] +
 		isys_fw_cfg->num_recv_queues[type_dev] +
 		isys_fw_cfg->num_recv_queues[type_msg];
 
@@ -280,7 +282,7 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
 			isys_fw_cfg->buffer_partition.num_gda_pages[i] = 0;
 	}
 
-	/* FW assumes proxy interface at fwcom queue 0 */
+	/* FW assumes proxy interface at fwcom_cfg queue 0 */
 	for (i = 0; i < isys_fw_cfg->num_send_queues[type_proxy]; i++) {
 		input_queue_cfg[i].token_size =
 			sizeof(struct ipu6_fw_proxy_send_queue_token);
@@ -314,9 +316,9 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
 			IPU6_ISYS_SIZE_RECV_QUEUE;
 	}
 
-	fwcom->dmem_addr = isys->pdata->ipdata->hw_variant.dmem_offset;
-	fwcom->specific_addr = isys_fw_cfg;
-	fwcom->specific_size = sizeof(*isys_fw_cfg);
+	fwcom_cfg->dmem_addr = isys->pdata->ipdata->hw_variant.dmem_offset;
+	fwcom_cfg->specific_addr = isys_fw_cfg;
+	fwcom_cfg->specific_size = sizeof(*isys_fw_cfg);
 
 	return 0;
 }
@@ -325,23 +327,23 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 {
 	struct device *dev = &isys->adev->auxdev.dev;
 	int retry = IPU6_ISYS_OPEN_RETRY;
-	struct ipu6_fw_com_cfg fwcom = {
+	struct ipu6_fw_com_cfg fwcom_cfg = {
 		.cell_start = start_sp,
 		.cell_ready = query_sp,
 		.buttress_boot_offset = SYSCOM_BUTTRESS_FW_PARAMS_ISYS_OFFSET,
 	};
 	int ret;
 
-	ipu6_isys_fwcom_cfg_init(isys, &fwcom, num_streams);
+	ipu6_isys_fwcom_cfg_init(isys, &fwcom_cfg, num_streams);
 
-	isys->fwcom = ipu6_fw_com_prepare(&fwcom, isys->adev,
+	isys->fwctx = ipu6_fw_com_prepare(&fwcom_cfg, isys->adev,
 					  isys->pdata->base);
-	if (!isys->fwcom) {
+	if (!isys->fwctx) {
 		dev_err(dev, "isys fw com prepare failed\n");
 		return -EIO;
 	}
 
-	ret = ipu6_fw_com_open(isys->fwcom);
+	ret = ipu6_fw_com_open(isys->fwctx);
 	if (ret) {
 		dev_err(dev, "isys fw com open failed %d\n", ret);
 		return ret;
@@ -349,7 +351,7 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 
 	do {
 		usleep_range(400, 500);
-		if (ipu6_fw_com_ready(isys->fwcom))
+		if (ipu6_fw_com_ready(isys->fwctx))
 			break;
 		retry--;
 	} while (retry > 0);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 3ac48d2076da..89eb265737d7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -1114,7 +1114,7 @@ int ipu6_isys_fw_open(struct ipu6_isys *isys)
 	 */
 	ipu6_cleanup_fw_msg_bufs(isys);
 
-	if (isys->fwcom) {
+	if (isys->fwctx) {
 		/*
 		 * Something went wrong in previous shutdown. As we are now
 		 * restarting isys we can safely delete old context.
@@ -1147,7 +1147,7 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys)
 	isys->ref_count--;
 	if (!isys->ref_count) {
 		ipu6_fw_isys_close(isys);
-		if (isys->fwcom) {
+		if (isys->fwctx) {
 			isys->need_reset = true;
 			dev_warn(&isys->adev->auxdev.dev,
 				 "failed to close fw isys\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 799e7b30e6a2..180a53f3d7ab 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1212,10 +1212,10 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
 	u32 index;
 	u64 ts;
 
-	if (!isys->fwcom)
+	if (!isys->fwctx)
 		return 1;
 
-	resp = ipu6_fw_isys_get_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
+	resp = ipu6_fw_isys_get_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 	if (!resp)
 		return 1;
 
@@ -1324,7 +1324,7 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
 
 	ipu6_isys_put_stream(stream);
 leave:
-	ipu6_fw_isys_put_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
+	ipu6_fw_isys_put_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 	return 0;
 }
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 7fb8cb820912..0b139ab24431 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -114,8 +114,7 @@ struct sensor_async_sd {
  * @csi2_rx_ctrl_cached: cached shared value between all CSI2 receivers
  * @streams_lock: serialise access to streams
  * @streams: streams per firmware stream ID
- * @fwcom: fw communication layer private pointer
- *         or optional external library private pointer
+ * @fwctx: fw communication layer context pointer
  * @phy_termcal_val: the termination calibration value, only used for DWC PHY
  * @need_reset: Isys requires d0i0->i3 transition
  * @ref_count: total number of callers fw open
@@ -136,7 +135,7 @@ struct ipu6_isys {
 	spinlock_t streams_lock;
 	struct ipu6_isys_stream streams[IPU6_ISYS_MAX_STREAMS];
 	int streams_ref_count[IPU6_ISYS_MAX_STREAMS];
-	void *fwcom;
+	void *fwctx;
 	u32 phy_termcal_val;
 	bool need_reset;
 	bool icache_prefetch;
-- 
2.55.0


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

* [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation Antti Laakso
                   ` (40 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu6_buttress_ipc structure is called as cse sometimes,
rename it to ipc for consistency.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.c | 33 ++++++++++----------
 drivers/media/pci/intel/ipu6/ipu6-buttress.h |  2 +-
 drivers/media/pci/intel/ipu6/ipu6.c          |  4 +--
 3 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index e0ecb4c8b081..cbe356589a9d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -221,7 +221,7 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
 	unsigned long tx_timeout_jiffies, rx_timeout_jiffies;
 	unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY;
 	struct ipu6_buttress *b = &isp->buttress;
-	struct ipu6_buttress_ipc *ipc = &b->cse;
+	struct ipu6_buttress_ipc *ipc = &b->ipc;
 	u32 val;
 	int ret;
 	int tout;
@@ -378,14 +378,15 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 		if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) {
 			dev_dbg(&isp->pdev->dev,
 				"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
-			ipu6_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data);
-			complete(&b->cse.recv_complete);
+
+			ipu6_buttress_ipc_recv(isp, &b->ipc, &b->ipc.recv_data);
+			complete(&b->ipc.recv_complete);
 		}
 
 		if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
 			dev_dbg(&isp->pdev->dev,
 				"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
-			complete(&b->cse.send_complete);
+			complete(&b->ipc.send_complete);
 		}
 
 		if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
@@ -830,17 +831,17 @@ int ipu6_buttress_init(struct ipu6_device *isp)
 	mutex_init(&b->auth_mutex);
 	mutex_init(&b->cons_mutex);
 	mutex_init(&b->ipc_mutex);
-	init_completion(&b->cse.send_complete);
-	init_completion(&b->cse.recv_complete);
-
-	b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
-	b->cse.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
-	b->cse.csr_in = BUTTRESS_REG_CSE2IUCSR;
-	b->cse.csr_out = BUTTRESS_REG_IU2CSECSR;
-	b->cse.db0_in = BUTTRESS_REG_CSE2IUDB0;
-	b->cse.db0_out = BUTTRESS_REG_IU2CSEDB0;
-	b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0;
-	b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0;
+	init_completion(&b->ipc.send_complete);
+	init_completion(&b->ipc.recv_complete);
+
+	b->ipc.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
+	b->ipc.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
+	b->ipc.csr_in = BUTTRESS_REG_CSE2IUCSR;
+	b->ipc.csr_out = BUTTRESS_REG_IU2CSECSR;
+	b->ipc.db0_in = BUTTRESS_REG_CSE2IUDB0;
+	b->ipc.db0_out = BUTTRESS_REG_IU2CSEDB0;
+	b->ipc.data0_in = BUTTRESS_REG_CSE2IUDATA0;
+	b->ipc.data0_out = BUTTRESS_REG_IU2CSEDATA0;
 
 	INIT_LIST_HEAD(&b->constraints);
 
@@ -877,7 +878,7 @@ int ipu6_buttress_init(struct ipu6_device *isp)
 
 	/* Retry couple of times in case of CSE initialization is delayed */
 	do {
-		ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+		ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
 		if (ret) {
 			dev_warn(&isp->pdev->dev,
 				 "IPC reset protocol failed, retrying\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 51e5ad48db82..b1c1a10e3e6d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -44,7 +44,7 @@ struct ipu6_buttress_ipc {
 
 struct ipu6_buttress {
 	struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
-	struct ipu6_buttress_ipc cse;
+	struct ipu6_buttress_ipc ipc;
 	struct list_head constraints;
 	u32 wdt_cached_value;
 	bool force_suspend;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 6d3235352a1c..efb58bc4d127 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -765,7 +765,7 @@ static int ipu6_resume(struct device *dev)
 
 	ipu6_buttress_restore(isp);
 
-	ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+	ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
 	if (ret)
 		dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
 
@@ -797,7 +797,7 @@ static int ipu6_runtime_resume(struct device *dev)
 		struct ipu6_buttress *b = &isp->buttress;
 
 		isp->need_ipc_reset = false;
-		ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+		ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
 		if (ret)
 			dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
 	}
-- 
2.55.0


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

* [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (2 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct Antti Laakso
                   ` (39 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Some of the error paths printed same or similar errors twice,
once is enough.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-cpd.c | 29 ++++++-------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index b7013f6524ec..966a16a300f8 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -266,7 +266,6 @@ static int ipu6_cpd_validate_moduledata(struct ipu6_device *isp,
 					u32 moduledata_size)
 {
 	const struct ipu6_cpd_module_data_hdr *mod_hdr = moduledata;
-	int ret;
 
 	/* Ensure moduledata hdr is within moduledata */
 	if (moduledata_size < sizeof(*mod_hdr) ||
@@ -276,15 +275,9 @@ static int ipu6_cpd_validate_moduledata(struct ipu6_device *isp,
 	}
 
 	dev_dbg(&isp->pdev->dev, "FW version: %x\n", mod_hdr->fw_pkg_date);
-	ret = ipu6_cpd_validate_cpd(isp, moduledata + mod_hdr->hdr_len,
-				    moduledata_size - mod_hdr->hdr_len,
-				    moduledata_size);
-	if (ret) {
-		dev_err(&isp->pdev->dev, "Invalid CPD in moduledata\n");
-		return ret;
-	}
-
-	return 0;
+	return ipu6_cpd_validate_cpd(isp, moduledata + mod_hdr->hdr_len,
+				     moduledata_size - mod_hdr->hdr_len,
+				     moduledata_size);
 }
 
 static int ipu6_cpd_validate_metadata(struct ipu6_device *isp,
@@ -325,10 +318,8 @@ int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
 
 	ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
 				    cpd_file_size);
-	if (ret) {
-		dev_err(&isp->pdev->dev, "Invalid CPD in file\n");
+	if (ret)
 		return ret;
-	}
 
 	/* Check for CPD file marker */
 	if (hdr->hdr_mark != CPD_HDR_MARK) {
@@ -346,17 +337,11 @@ int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
 	/* Validate metadata */
 	ent = ipu6_cpd_get_metadata(cpd_file);
 	ret = ipu6_cpd_validate_metadata(isp, cpd_file + ent->offset, ent->len);
-	if (ret) {
-		dev_err(&isp->pdev->dev, "Invalid CPD metadata\n");
+	if (ret)
 		return ret;
-	}
 
 	/* Validate moduledata */
 	ent = ipu6_cpd_get_moduledata(cpd_file);
-	ret = ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
-					   ent->len);
-	if (ret)
-		dev_err(&isp->pdev->dev, "Invalid CPD moduledata\n");
-
-	return ret;
+	return ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
+					    ent->len);
 }
-- 
2.55.0


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

* [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (3 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init() Antti Laakso
                   ` (38 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The struct ipu6_fw_proxy_write_queue_token is not used anywhere,
remove it.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index b60f02076d8a..393245a633f4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -511,21 +511,6 @@ struct ipu6_fw_isys_proxy_resp_info_abi {
 	struct ipu6_fw_isys_proxy_error_info_abi error_info;
 };
 
-/**
- * struct ipu6_fw_proxy_write_queue_token - ISYS proxy write queue token
- * @request_id: update id for the specific proxy write request
- * @region_index: Region id for the proxy write request
- * @offset: Offset of the write request according to the base address
- *	    of the region
- * @value: Value that is requested to be written with the proxy write request
- */
-struct ipu6_fw_proxy_write_queue_token {
-	u32 request_id;
-	u32 region_index;
-	u32 offset;
-	u32 value;
-};
-
 /**
  * struct ipu6_fw_resp_queue_token - ISYS response queue token
  * @resp_info: response info
-- 
2.55.0


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

* [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init()
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (4 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments Antti Laakso
                   ` (37 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The struct ipu6_mmu_pdata is used only in ipu6_mmu_init(),
and not really needed, remove it.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-mmu.c | 13 ++++++-------
 drivers/media/pci/intel/ipu6/ipu6.h     |  6 ------
 2 files changed, 6 insertions(+), 13 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 0e6dca36b6ba..6b1a49ebbcc2 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -750,27 +750,26 @@ struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
 			       const struct ipu6_hw_variants *hw)
 {
 	struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
-	struct ipu6_mmu_pdata *pdata;
+	struct ipu6_mmu_hw *mmu_hw;
 	struct ipu6_mmu *mmu;
 	unsigned int i;
 
 	if (hw->nr_mmus > IPU6_MMU_MAX_DEVICES)
 		return ERR_PTR(-EINVAL);
 
-	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
+	mmu_hw = devm_kcalloc(dev, sizeof(*mmu_hw), hw->nr_mmus, GFP_KERNEL);
+	if (!mmu_hw)
 		return ERR_PTR(-ENOMEM);
 
 	for (i = 0; i < hw->nr_mmus; i++) {
-		struct ipu6_mmu_hw *pdata_mmu = &pdata->mmu_hw[i];
 		const struct ipu6_mmu_hw *src_mmu = &hw->mmu_hw[i];
 
 		if (src_mmu->nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
 		    src_mmu->nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
 			return ERR_PTR(-EINVAL);
 
-		*pdata_mmu = *src_mmu;
-		pdata_mmu->base = base + src_mmu->offset;
+		mmu_hw[i] = *src_mmu;
+		mmu_hw[i].base = base + src_mmu->offset;
 	}
 
 	mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL);
@@ -778,7 +777,7 @@ struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
 		return ERR_PTR(-ENOMEM);
 
 	mmu->mmid = mmid;
-	mmu->mmu_hw = pdata->mmu_hw;
+	mmu->mmu_hw = mmu_hw;
 	mmu->nr_mmus = hw->nr_mmus;
 	mmu->tlb_invalidate = tlb_invalidate;
 	mmu->ready = false;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 07ca59048f44..874b377a2e9a 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -239,12 +239,6 @@ struct ipu6_mmu_hw {
 	bool insert_read_before_invalidate;
 };
 
-struct ipu6_mmu_pdata {
-	u32 nr_mmus;
-	struct ipu6_mmu_hw mmu_hw[IPU6_MMU_MAX_DEVICES];
-	int mmid;
-};
-
 struct ipu6_isys_csi2_pdata {
 	void __iomem *base;
 };
-- 
2.55.0


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

* [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (5 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init() Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7 Antti Laakso
                   ` (36 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

We need only pointer to ipu6_isys struct, and queue number
can be removed as it is always the same.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 8 ++++----
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 4 ++--
 drivers/media/pci/intel/ipu6/ipu6-isys.c    | 4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index a65e9f1aa104..fc2f24c05de7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -366,14 +366,14 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 }
 
 struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(void *context, unsigned int queue)
+ipu6_fw_isys_get_resp(struct ipu6_isys *isys)
 {
-	return ipu6_recv_get_token(context, queue);
+	return ipu6_recv_get_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 }
 
-void ipu6_fw_isys_put_resp(void *context, unsigned int queue)
+void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
 {
-	ipu6_recv_put_token(context, queue);
+	ipu6_recv_put_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 }
 
 void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index 393245a633f4..15d4ae355f28 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -576,6 +576,6 @@ int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
 				  unsigned int offset, u32 value);
 void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
 struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(void *context, unsigned int queue);
-void ipu6_fw_isys_put_resp(void *context, unsigned int queue);
+ipu6_fw_isys_get_resp(struct ipu6_isys *isys);
+void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
 #endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 180a53f3d7ab..8af891081bd3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1215,7 +1215,7 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
 	if (!isys->fwctx)
 		return 1;
 
-	resp = ipu6_fw_isys_get_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
+	resp = ipu6_fw_isys_get_resp(isys);
 	if (!resp)
 		return 1;
 
@@ -1324,7 +1324,7 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
 
 	ipu6_isys_put_stream(stream);
 leave:
-	ipu6_fw_isys_put_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
+	ipu6_fw_isys_put_resp(isys);
 	return 0;
 }
 
-- 
2.55.0


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

* [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (6 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support Antti Laakso
                   ` (35 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 comes in two flavors as of now, ipu7 and ipu7p5.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 874b377a2e9a..ebae876058ca 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -27,11 +27,17 @@ struct ipu6_bus_device;
 #define IPU_VERSION_6SE		BIT(1) /* JSL */
 #define IPU_VERSION_6EP		BIT(2) /* ADL/RPL */
 #define IPU_VERSION_6EP_MTL	BIT(3) /* MTL */
+#define IPU_VERSION_7		BIT(4) /* LNL */
+#define IPU_VERSION_7P5		BIT(5) /* PTL */
 
 #define IS_IPU6_TGL(isp)	((isp)->hw_ver & IPU_VERSION_6)
 #define IS_IPU6SE(isp)		((isp)->hw_ver & IPU_VERSION_6SE)
 #define IS_IPU6EP(isp)		((isp)->hw_ver & IPU_VERSION_6EP)
 #define IS_IPU6EP_MTL(isp)	((isp)->hw_ver & IPU_VERSION_6EP_MTL)
+#define IS_IPU7(isp)		((isp)->hw_ver & \
+				 (IPU_VERSION_7 | IPU_VERSION_7P5))
+#define IS_IPU7_MTL(isp)	((isp)->hw_ver & IPU_VERSION_7)
+#define IS_IPU7P5(isp)		((isp)->hw_ver & IPU_VERSION_7P5)
 
 /*
  * ISYS DMA can overshoot. For higher resolutions over allocation is one line
-- 
2.55.0


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

* [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (7 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 10/44] media: ipu6: Use single struct for registers Antti Laakso
                   ` (34 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Introduce a struct to hold buttress registers and bitmasks that vary
across hardware versions beyond ipu6 to simplify support for future
hardware versions.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.c  | 96 ++++++++++---------
 drivers/media/pci/intel/ipu6/ipu6-buttress.h  | 25 +++++
 .../intel/ipu6/ipu6-platform-buttress-regs.h  |  2 +-
 drivers/media/pci/intel/ipu6/ipu6.c           | 26 +++++
 4 files changed, 101 insertions(+), 48 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index cbe356589a9d..3c5f4e407b7c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -55,11 +55,6 @@
 
 #define BUTTRESS_MAX_CONSECUTIVE_IRQS	100
 
-static const u32 ipu6_adev_irq_mask[2] = {
-	BUTTRESS_ISR_IS_IRQ,
-	BUTTRESS_ISR_PS_IRQ
-};
-
 int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 			    struct ipu6_buttress_ipc *ipc)
 {
@@ -337,7 +332,8 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 	struct ipu6_device *isp = isp_ptr;
 	struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
 	struct ipu6_buttress *b = &isp->buttress;
-	u32 reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
+	const struct ipu6_buttress_registers *regs = b->regs;
+	const u32 adev_irq_mask[] = { regs->irq_is, regs->irq_ps };
 	irqreturn_t ret = IRQ_NONE;
 	u32 disable_irqs = 0;
 	u32 irq_status;
@@ -348,7 +344,7 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 	if (!active)
 		return IRQ_NONE;
 
-	irq_status = readl(isp->base + reg_irq_sts);
+	irq_status = readl(isp->base + regs->irq_status);
 	if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) {
 		if (active > 0)
 			pm_runtime_put_noidle(&isp->pdev->dev);
@@ -356,26 +352,26 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 	}
 
 	do {
-		writel(irq_status, isp->base + BUTTRESS_REG_ISR_CLEAR);
+		writel(irq_status, isp->base + regs->irq_clear);
 
-		for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask); i++) {
+		for (i = 0; i < ARRAY_SIZE(adev_irq_mask); i++) {
 			irqreturn_t r = ipu6_buttress_call_isr(adev[i]);
 
-			if (!(irq_status & ipu6_adev_irq_mask[i]))
+			if (!(irq_status & adev_irq_mask[i]))
 				continue;
 
 			if (r == IRQ_WAKE_THREAD) {
 				ret = IRQ_WAKE_THREAD;
-				disable_irqs |= ipu6_adev_irq_mask[i];
+				disable_irqs |= adev_irq_mask[i];
 			} else if (ret == IRQ_NONE && r == IRQ_HANDLED) {
 				ret = IRQ_HANDLED;
 			}
 		}
 
-		if ((irq_status & BUTTRESS_EVENT) && ret == IRQ_NONE)
+		if ((irq_status & regs->irq_events) && ret == IRQ_NONE)
 			ret = IRQ_HANDLED;
 
-		if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) {
+		if (irq_status & regs->irq_cse_ipc) {
 			dev_dbg(&isp->pdev->dev,
 				"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
 
@@ -383,13 +379,13 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 			complete(&b->ipc.recv_complete);
 		}
 
-		if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
+		if (irq_status & regs->irq_exec_done) {
 			dev_dbg(&isp->pdev->dev,
 				"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
 			complete(&b->ipc.send_complete);
 		}
 
-		if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
+		if (irq_status & regs->irq_sai &&
 		    ipu6_buttress_get_secure_mode(isp))
 			dev_err(&isp->pdev->dev,
 				"BUTTRESS_ISR_SAI_VIOLATION\n");
@@ -408,12 +404,12 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 			break;
 		}
 
-		irq_status = readl(isp->base + reg_irq_sts);
+		irq_status = readl(isp->base + regs->irq_status);
 	} while (irq_status);
 
 	if (disable_irqs)
-		writel(BUTTRESS_IRQS & ~disable_irqs,
-		       isp->base + BUTTRESS_REG_ISR_ENABLE);
+		writel(regs->irq_all & ~disable_irqs,
+		       isp->base + regs->irq_enable);
 
 	if (active > 0)
 		pm_runtime_put(&isp->pdev->dev);
@@ -424,12 +420,13 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
 {
 	struct ipu6_device *isp = isp_ptr;
+	const struct ipu6_buttress_registers *regs = isp->buttress.regs;
 	struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
 	const struct ipu6_auxdrv_data *drv_data = NULL;
 	irqreturn_t ret = IRQ_NONE;
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask) && adev[i]; i++) {
+	for (i = 0; i < ARRAY_SIZE(adev) && adev[i]; i++) {
 		drv_data = adev[i]->auxdrv_data;
 		if (!drv_data)
 			continue;
@@ -439,7 +436,7 @@ irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
 			ret = IRQ_HANDLED;
 	}
 
-	writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
+	writel(regs->irq_all, isp->base + regs->irq_enable);
 
 	return ret;
 }
@@ -472,7 +469,7 @@ int ipu6_buttress_power(struct device *dev,
 
 	writel(val, isp->base + ctrl->freq_ctl);
 
-	ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE,
+	ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
 				 val, (val & ctrl->pwr_sts_mask) == pwr_sts,
 				 100, BUTTRESS_POWER_TIMEOUT_US);
 	if (ret)
@@ -488,7 +485,7 @@ bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp)
 {
 	u32 val;
 
-	val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL);
+	val = readl(isp->base + isp->buttress.regs->security_ctl);
 
 	return val & BUTTRESS_SECURITY_CTL_FW_SECURE_MODE;
 }
@@ -500,7 +497,7 @@ bool ipu6_buttress_auth_done(struct ipu6_device *isp)
 	if (!isp->secure_mode)
 		return true;
 
-	val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL);
+	val = readl(isp->base + isp->buttress.regs->security_ctl);
 	val = FIELD_GET(BUTTRESS_SECURITY_CTL_FW_SETUP_MASK, val);
 
 	return val == BUTTRESS_SECURITY_CTL_AUTH_DONE;
@@ -518,10 +515,10 @@ int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
 	}
 
 	writel(BUTTRESS_FW_RESET_CTL_START, isp->base +
-	       BUTTRESS_REG_FW_RESET_CTL);
+	       isp->buttress.regs->fw_reset_ctl);
 
-	ret = readl_poll_timeout(isp->base + BUTTRESS_REG_FW_RESET_CTL, val,
-				 val & BUTTRESS_FW_RESET_CTL_DONE, 500,
+	ret = readl_poll_timeout(isp->base + isp->buttress.regs->fw_reset_ctl,
+				 val, val & BUTTRESS_FW_RESET_CTL_DONE, 500,
 				 BUTTRESS_CSE_FWRESET_TIMEOUT_US);
 	if (ret) {
 		dev_err(&isp->pdev->dev,
@@ -530,7 +527,8 @@ int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
 	}
 
 	dev_dbg(&isp->pdev->dev, "FW reset for authentication done\n");
-	writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL);
+	writel(0, isp->base + isp->buttress.regs->fw_reset_ctl);
+
 	/* leave some time for HW restore */
 	usleep_range(800, 1000);
 
@@ -660,7 +658,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
 	mask = BUTTRESS_SECURITY_CTL_FW_SETUP_MASK;
 	done = BUTTRESS_SECURITY_CTL_FW_SETUP_DONE;
 	fail = BUTTRESS_SECURITY_CTL_AUTH_FAILED;
-	ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data,
+	ret = readl_poll_timeout(isp->base + b->regs->security_ctl, data,
 				 ((data & mask) == done ||
 				  (data & mask) == fail), 500,
 				 BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US);
@@ -700,7 +698,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
 	}
 
 	done = BUTTRESS_SECURITY_CTL_AUTH_DONE;
-	ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data,
+	ret = readl_poll_timeout(isp->base + b->regs->security_ctl, data,
 				 ((data & mask) == done ||
 				  (data & mask) == fail), 500,
 				 BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US);
@@ -725,15 +723,16 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
 
 static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
 {
+	const struct ipu6_buttress_registers *regs = isp->buttress.regs;
 	u32 val, mask, done;
 	int ret;
 
 	mask = BUTTRESS_PWR_STATE_HH_STATUS_MASK;
 
 	writel(BUTTRESS_FABRIC_CMD_START_TSC_SYNC,
-	       isp->base + BUTTRESS_REG_FABRIC_CMD);
+	       isp->base + regs->fabric_cmd);
 
-	val = readl(isp->base + BUTTRESS_REG_PWR_STATE);
+	val = readl(isp->base + regs->pwr_status);
 	val = FIELD_GET(mask, val);
 	if (val == BUTTRESS_PWR_STATE_HH_STATE_ERR) {
 		dev_err(&isp->pdev->dev, "Start tsc sync failed\n");
@@ -741,8 +740,8 @@ static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
 	}
 
 	done = BUTTRESS_PWR_STATE_HH_STATE_DONE;
-	ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE, val,
-				 FIELD_GET(mask, val) == done, 500,
+	ret = readl_poll_timeout(isp->base + regs->pwr_status,
+				 val, FIELD_GET(mask, val) == done, 500,
 				 BUTTRESS_TSC_SYNC_TIMEOUT_US);
 	if (ret)
 		dev_err(&isp->pdev->dev, "Start tsc sync timeout\n");
@@ -762,11 +761,13 @@ int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
 		if (ret != -ETIMEDOUT)
 			return ret;
 
-		val = readl(isp->base + BUTTRESS_REG_TSW_CTL);
+		u32 tsw_ctl = isp->buttress.regs->tsw_ctl;
+
+		val = readl(isp->base + tsw_ctl);
 		val = val | BUTTRESS_TSW_CTL_SOFT_RESET;
-		writel(val, isp->base + BUTTRESS_REG_TSW_CTL);
+		writel(val, isp->base + tsw_ctl);
 		val = val & ~BUTTRESS_TSW_CTL_SOFT_RESET;
-		writel(val, isp->base + BUTTRESS_REG_TSW_CTL);
+		writel(val, isp->base + tsw_ctl);
 	}
 
 	dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n");
@@ -777,13 +778,14 @@ EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, "INTEL_IPU6");
 
 void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val)
 {
+	void __iomem *tsc = isp->base + isp->buttress.regs->tsc_lo;
 	u32 tsc_hi_1, tsc_hi_2, tsc_lo;
 	unsigned long flags;
 
 	local_irq_save(flags);
-	tsc_hi_1 = readl(isp->base + BUTTRESS_REG_TSC_HI);
-	tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO);
-	tsc_hi_2 = readl(isp->base + BUTTRESS_REG_TSC_HI);
+	tsc_hi_1 = readl(tsc + BUTTRESS_TSC_HI_OFFSET);
+	tsc_lo = readl(tsc);
+	tsc_hi_2 = readl(tsc + BUTTRESS_TSC_HI_OFFSET);
 	if (tsc_hi_1 == tsc_hi_2) {
 		*val = (u64)tsc_hi_1 << 32 | tsc_lo;
 	} else {
@@ -816,9 +818,9 @@ void ipu6_buttress_restore(struct ipu6_device *isp)
 {
 	struct ipu6_buttress *b = &isp->buttress;
 
-	writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
-	writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
-	writel(b->wdt_cached_value, isp->base + BUTTRESS_REG_WDT);
+	writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+	writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+	writel(b->wdt_cached_value, isp->base + b->regs->wdt);
 }
 
 int ipu6_buttress_init(struct ipu6_device *isp)
@@ -851,12 +853,12 @@ int ipu6_buttress_init(struct ipu6_device *isp)
 		readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
 		readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
 
-	b->wdt_cached_value = readl(isp->base + BUTTRESS_REG_WDT);
-	writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
-	writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
+	b->wdt_cached_value = readl(isp->base + b->regs->wdt);
+	writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+	writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
 
 	/* get ref_clk frequency by reading the indication in btrs control */
-	val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
+	val = readl(isp->base + b->regs->btrs_ctrl);
 	val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
 
 	switch (val) {
@@ -902,7 +904,7 @@ void ipu6_buttress_exit(struct ipu6_device *isp)
 {
 	struct ipu6_buttress *b = &isp->buttress;
 
-	writel(0, isp->base + BUTTRESS_REG_ISR_ENABLE);
+	writel(0, isp->base + b->regs->irq_enable);
 
 	mutex_destroy(&b->power_mutex);
 	mutex_destroy(&b->auth_mutex);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index b1c1a10e3e6d..68586a32fda3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -42,9 +42,34 @@ struct ipu6_buttress_ipc {
 	u32 data0_in;
 };
 
+struct ipu6_buttress_registers {
+	/* Registers */
+	u32 irq_status;
+	u32 irq_clear;
+	u32 irq_enable;
+	u32 pwr_status;
+	u32 security_ctl;
+	u32 fw_reset_ctl;
+	u32 fabric_cmd;
+	u32 tsw_ctl;
+	u32 tsc_lo;
+	u32 wdt;
+	u32 btrs_ctrl;
+
+	/* Bitmasks */
+	u32 irq_is;
+	u32 irq_ps;
+	u32 irq_all;
+	u32 irq_events;
+	u32 irq_cse_ipc;
+	u32 irq_exec_done;
+	u32 irq_sai;
+};
+
 struct ipu6_buttress {
 	struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
 	struct ipu6_buttress_ipc ipc;
+	const struct ipu6_buttress_registers *regs;
 	struct list_head constraints;
 	u32 wdt_cached_value;
 	bool force_suspend;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index efd65e494c16..5006cce74b23 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -212,7 +212,7 @@ enum {
 #define BUTTRESS_TSW_CTL_SOFT_RESET	BIT(8)
 
 #define BUTTRESS_REG_TSC_LO	0x164
-#define BUTTRESS_REG_TSC_HI	0x168
+#define BUTTRESS_TSC_HI_OFFSET	4
 
 #define BUTTRESS_IRQS		(BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
 				 BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE |    \
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index efb58bc4d127..55e660fda421 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -228,6 +228,30 @@ static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
 	.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
 };
 
+static const struct ipu6_buttress_registers ipu6_buttress_regs = {
+	/* Registers */
+	.irq_status	= BUTTRESS_REG_ISR_STATUS,
+	.irq_clear	= BUTTRESS_REG_ISR_CLEAR,
+	.irq_enable	= BUTTRESS_REG_ISR_ENABLE,
+	.pwr_status	= BUTTRESS_REG_PWR_STATE,
+	.security_ctl	= BUTTRESS_REG_SECURITY_CTL,
+	.fw_reset_ctl	= BUTTRESS_REG_FW_RESET_CTL,
+	.fabric_cmd	= BUTTRESS_REG_FABRIC_CMD,
+	.tsw_ctl	= BUTTRESS_REG_TSW_CTL,
+	.tsc_lo		= BUTTRESS_REG_TSC_LO,
+	.wdt		= BUTTRESS_REG_WDT,
+	.btrs_ctrl	= BUTTRESS_REG_BTRS_CTRL,
+
+	/* Bitmasks */
+	.irq_is		= BUTTRESS_ISR_IS_IRQ,
+	.irq_ps		= BUTTRESS_ISR_PS_IRQ,
+	.irq_all	= BUTTRESS_IRQS,
+	.irq_events	= BUTTRESS_EVENT,
+	.irq_cse_ipc	= BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING,
+	.irq_exec_done	= BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE,
+	.irq_sai	= BUTTRESS_ISR_SAI_VIOLATION,
+};
+
 static void
 ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
 			   const struct ipu6_hw_variants *hw_variant,
@@ -522,6 +546,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	pci_set_master(pdev);
 
 	isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
+	isp->buttress.regs = &ipu6_buttress_regs;
+
 	switch (id->device) {
 	case PCI_DEVICE_ID_INTEL_IPU6:
 		isp->hw_ver = IPU_VERSION_6;
-- 
2.55.0


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

* [PATCH v2 10/44] media: ipu6: Use single struct for registers
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (8 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID Antti Laakso
                   ` (33 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Move register values from ipu6_buttress_ipc struct to
ipu6_buttress_registers as these are different in future
hardware versions as well.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.c | 86 +++++++++-----------
 drivers/media/pci/intel/ipu6/ipu6-buttress.h | 17 ++--
 drivers/media/pci/intel/ipu6/ipu6.c          | 13 +--
 3 files changed, 54 insertions(+), 62 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 3c5f4e407b7c..e77a569bb97e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -55,11 +55,11 @@
 
 #define BUTTRESS_MAX_CONSECUTIVE_IRQS	100
 
-int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
-			    struct ipu6_buttress_ipc *ipc)
+int ipu6_buttress_ipc_reset(struct ipu6_device *isp)
 {
 	unsigned int retries = BUTTRESS_IPC_RESET_RETRY;
 	struct ipu6_buttress *b = &isp->buttress;
+	const struct ipu6_buttress_registers *regs = b->regs;
 	u32 val = 0, csr_in_clr;
 
 	if (!isp->secure_mode) {
@@ -70,11 +70,11 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 	mutex_lock(&b->ipc_mutex);
 
 	/* Clear-by-1 CSR (all bits), corresponding internal states. */
-	val = readl(isp->base + ipc->csr_in);
-	writel(val, isp->base + ipc->csr_in);
+	val = readl(isp->base + regs->csr_in);
+	writel(val, isp->base + regs->csr_in);
 
 	/* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */
-	writel(ENTRY, isp->base + ipc->csr_out);
+	writel(ENTRY, isp->base + regs->csr_out);
 	/*
 	 * Clear-by-1 all CSR bits EXCEPT following
 	 * bits:
@@ -89,7 +89,7 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 
 	do {
 		usleep_range(400, 500);
-		val = readl(isp->base + ipc->csr_in);
+		val = readl(isp->base + regs->csr_in);
 		switch (val) {
 		case ENTRY | EXIT:
 		case ENTRY | EXIT | QUERY:
@@ -100,8 +100,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 			 * 2) Set peer CSR bit
 			 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
 			 */
-			writel(ENTRY | EXIT, isp->base + ipc->csr_in);
-			writel(QUERY, isp->base + ipc->csr_out);
+			writel(ENTRY | EXIT, isp->base + regs->csr_in);
+			writel(QUERY, isp->base + regs->csr_out);
 			break;
 		case ENTRY:
 		case ENTRY | QUERY:
@@ -112,8 +112,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 			 * 2) Set peer CSR bit
 			 * IPC_PEER_COMP_ACTIONS_RST_PHASE1.
 			 */
-			writel(ENTRY | QUERY, isp->base + ipc->csr_in);
-			writel(ENTRY, isp->base + ipc->csr_out);
+			writel(ENTRY | QUERY, isp->base + regs->csr_in);
+			writel(ENTRY, isp->base + regs->csr_out);
 			break;
 		case EXIT:
 		case EXIT | QUERY:
@@ -130,17 +130,17 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 			 * 3) Set peer CSR bit
 			 * IPC_PEER_COMP_ACTIONS_RST_PHASE2.
 			 */
-			writel(EXIT, isp->base + ipc->csr_in);
-			writel(0, isp->base + ipc->db0_in);
-			writel(csr_in_clr, isp->base + ipc->csr_in);
-			writel(EXIT, isp->base + ipc->csr_out);
+			writel(EXIT, isp->base + regs->csr_in);
+			writel(0, isp->base + regs->db0_in);
+			writel(csr_in_clr, isp->base + regs->csr_in);
+			writel(EXIT, isp->base + regs->csr_out);
 
 			/*
 			 * Read csr_in again to make sure if RST_PHASE2 is done.
 			 * If csr_in is QUERY, it should be handled again.
 			 */
 			usleep_range(200, 300);
-			val = readl(isp->base + ipc->csr_in);
+			val = readl(isp->base + regs->csr_in);
 			if (val & QUERY) {
 				dev_dbg(&isp->pdev->dev,
 					"RST_PHASE2 retry csr_in = %x\n", val);
@@ -155,8 +155,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 			 * 2) Set peer CSR bit
 			 * IPC_PEER_COMP_ACTIONS_RST_PHASE1
 			 */
-			writel(QUERY, isp->base + ipc->csr_in);
-			writel(ENTRY, isp->base + ipc->csr_out);
+			writel(QUERY, isp->base + regs->csr_in);
+			writel(ENTRY, isp->base + regs->csr_out);
 			break;
 		default:
 			dev_dbg_ratelimited(&isp->pdev->dev,
@@ -171,42 +171,42 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
 	return -ETIMEDOUT;
 }
 
-static void ipu6_buttress_ipc_validity_close(struct ipu6_device *isp,
-					     struct ipu6_buttress_ipc *ipc)
+static void ipu6_buttress_ipc_validity_close(struct ipu6_device *isp)
 {
 	writel(BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ,
-	       isp->base + ipc->csr_out);
+	       isp->base + isp->buttress.regs->csr_out);
 }
 
 static int
-ipu6_buttress_ipc_validity_open(struct ipu6_device *isp,
-				struct ipu6_buttress_ipc *ipc)
+ipu6_buttress_ipc_validity_open(struct ipu6_device *isp)
 {
 	unsigned int mask = BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID;
+	const struct ipu6_buttress_registers *regs = isp->buttress.regs;
 	void __iomem *addr;
 	int ret;
 	u32 val;
 
 	writel(BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ,
-	       isp->base + ipc->csr_out);
+	       isp->base + regs->csr_out);
 
-	addr = isp->base + ipc->csr_in;
+	addr = isp->base + regs->csr_in;
 	ret = readl_poll_timeout(addr, val, val & mask, 200,
 				 BUTTRESS_IPC_VALIDITY_TIMEOUT_US);
 	if (ret) {
 		dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val);
-		ipu6_buttress_ipc_validity_close(isp, ipc);
+		ipu6_buttress_ipc_validity_close(isp);
 	}
 
 	return ret;
 }
 
-static void ipu6_buttress_ipc_recv(struct ipu6_device *isp,
-				   struct ipu6_buttress_ipc *ipc, u32 *ipc_msg)
+static void ipu6_buttress_ipc_recv(struct ipu6_device *isp, u32 *ipc_msg)
 {
+	const struct ipu6_buttress_registers *regs = isp->buttress.regs;
+
 	if (ipc_msg)
-		*ipc_msg = readl(isp->base + ipc->data0_in);
-	writel(0, isp->base + ipc->db0_in);
+		*ipc_msg = readl(isp->base + regs->data0_in);
+	writel(0, isp->base + regs->db0_in);
 }
 
 static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
@@ -217,13 +217,14 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
 	unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY;
 	struct ipu6_buttress *b = &isp->buttress;
 	struct ipu6_buttress_ipc *ipc = &b->ipc;
+	const struct ipu6_buttress_registers *regs = b->regs;
 	u32 val;
 	int ret;
 	int tout;
 
 	mutex_lock(&b->ipc_mutex);
 
-	ret = ipu6_buttress_ipc_validity_open(isp, ipc);
+	ret = ipu6_buttress_ipc_validity_open(isp);
 	if (ret) {
 		dev_err(&isp->pdev->dev, "IPC validity open failed\n");
 		goto out;
@@ -239,9 +240,9 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
 
 		dev_dbg(&isp->pdev->dev, "bulk IPC command: 0x%x\n",
 			msgs[i].cmd);
-		writel(msgs[i].cmd, isp->base + ipc->data0_out);
+		writel(msgs[i].cmd, isp->base + regs->data0_out);
 		val = BUTTRESS_IU2CSEDB0_BUSY | msgs[i].cmd_size;
-		writel(val, isp->base + ipc->db0_out);
+		writel(val, isp->base + regs->db0_out);
 
 		tout = wait_for_completion_timeout(&ipc->send_complete,
 						   tx_timeout_jiffies);
@@ -253,7 +254,7 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
 			}
 
 			/* Try again if CSE is not responding on first try */
-			writel(0, isp->base + ipc->db0_out);
+			writel(0, isp->base + regs->db0_out);
 			i--;
 			continue;
 		}
@@ -271,8 +272,8 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
 			goto out;
 		}
 
-		if (ipc->nack_mask &&
-		    (ipc->recv_data & ipc->nack_mask) == ipc->nack) {
+		if ((ipc->recv_data & BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK) ==
+		     BUTTRESS_CSE2IUDATA0_IPC_NACK) {
 			dev_err(&isp->pdev->dev,
 				"IPC NACK for cmd 0x%x\n", msgs[i].cmd);
 			ret = -EIO;
@@ -291,7 +292,7 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
 	dev_dbg(&isp->pdev->dev, "bulk IPC commands done\n");
 
 out:
-	ipu6_buttress_ipc_validity_close(isp, ipc);
+	ipu6_buttress_ipc_validity_close(isp);
 	mutex_unlock(&b->ipc_mutex);
 	return ret;
 }
@@ -375,7 +376,7 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 			dev_dbg(&isp->pdev->dev,
 				"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
 
-			ipu6_buttress_ipc_recv(isp, &b->ipc, &b->ipc.recv_data);
+			ipu6_buttress_ipc_recv(isp, &b->ipc.recv_data);
 			complete(&b->ipc.recv_complete);
 		}
 
@@ -836,15 +837,6 @@ int ipu6_buttress_init(struct ipu6_device *isp)
 	init_completion(&b->ipc.send_complete);
 	init_completion(&b->ipc.recv_complete);
 
-	b->ipc.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
-	b->ipc.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
-	b->ipc.csr_in = BUTTRESS_REG_CSE2IUCSR;
-	b->ipc.csr_out = BUTTRESS_REG_IU2CSECSR;
-	b->ipc.db0_in = BUTTRESS_REG_CSE2IUDB0;
-	b->ipc.db0_out = BUTTRESS_REG_IU2CSEDB0;
-	b->ipc.data0_in = BUTTRESS_REG_CSE2IUDATA0;
-	b->ipc.data0_out = BUTTRESS_REG_IU2CSEDATA0;
-
 	INIT_LIST_HEAD(&b->constraints);
 
 	isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
@@ -880,7 +872,7 @@ int ipu6_buttress_init(struct ipu6_device *isp)
 
 	/* Retry couple of times in case of CSE initialization is delayed */
 	do {
-		ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
+		ret = ipu6_buttress_ipc_reset(isp);
 		if (ret) {
 			dev_warn(&isp->pdev->dev,
 				 "IPC reset protocol failed, retrying\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 68586a32fda3..a3c23adede7b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -31,15 +31,7 @@ struct ipu6_buttress_ctrl {
 struct ipu6_buttress_ipc {
 	struct completion send_complete;
 	struct completion recv_complete;
-	u32 nack;
-	u32 nack_mask;
 	u32 recv_data;
-	u32 csr_out;
-	u32 csr_in;
-	u32 db0_in;
-	u32 db0_out;
-	u32 data0_out;
-	u32 data0_in;
 };
 
 struct ipu6_buttress_registers {
@@ -55,6 +47,12 @@ struct ipu6_buttress_registers {
 	u32 tsc_lo;
 	u32 wdt;
 	u32 btrs_ctrl;
+	u32 csr_in;
+	u32 csr_out;
+	u32 db0_in;
+	u32 db0_out;
+	u32 data0_in;
+	u32 data0_out;
 
 	/* Bitmasks */
 	u32 irq_is;
@@ -83,8 +81,7 @@ struct ipu6_ipc_buttress_bulk_msg {
 	u8 cmd_size;
 };
 
-int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
-			    struct ipu6_buttress_ipc *ipc);
+int ipu6_buttress_ipc_reset(struct ipu6_device *isp);
 int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
 			       const struct firmware *fw,
 			       struct sg_table *sgt);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 55e660fda421..7ac9c92744c0 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -241,6 +241,12 @@ static const struct ipu6_buttress_registers ipu6_buttress_regs = {
 	.tsc_lo		= BUTTRESS_REG_TSC_LO,
 	.wdt		= BUTTRESS_REG_WDT,
 	.btrs_ctrl	= BUTTRESS_REG_BTRS_CTRL,
+	.csr_in		= BUTTRESS_REG_CSE2IUCSR,
+	.csr_out	= BUTTRESS_REG_IU2CSECSR,
+	.db0_in		= BUTTRESS_REG_CSE2IUDB0,
+	.db0_out	= BUTTRESS_REG_IU2CSEDB0,
+	.data0_in	= BUTTRESS_REG_CSE2IUDATA0,
+	.data0_out	= BUTTRESS_REG_IU2CSEDATA0,
 
 	/* Bitmasks */
 	.irq_is		= BUTTRESS_ISR_IS_IRQ,
@@ -779,7 +785,6 @@ static int ipu6_resume(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct ipu6_device *isp = pci_get_drvdata(pdev);
-	struct ipu6_buttress *b = &isp->buttress;
 	int ret;
 
 	/* Configure the arbitration mechanisms for VC requests */
@@ -791,7 +796,7 @@ static int ipu6_resume(struct device *dev)
 
 	ipu6_buttress_restore(isp);
 
-	ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
+	ret = ipu6_buttress_ipc_reset(isp);
 	if (ret)
 		dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
 
@@ -820,10 +825,8 @@ static int ipu6_runtime_resume(struct device *dev)
 	ipu6_buttress_restore(isp);
 
 	if (isp->need_ipc_reset) {
-		struct ipu6_buttress *b = &isp->buttress;
-
 		isp->need_ipc_reset = false;
-		ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
+		ret = ipu6_buttress_ipc_reset(isp);
 		if (ret)
 			dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
 	}
-- 
2.55.0


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

* [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (9 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 10/44] media: ipu6: Use single struct for registers Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support Antti Laakso
                   ` (32 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

We will need subsys ID later elsewhere, so move it to
common header too.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-mmu.h | 3 ---
 drivers/media/pci/intel/ipu6/ipu6.c     | 5 ++---
 drivers/media/pci/intel/ipu6/ipu6.h     | 3 +++
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index 8e40b4a66d7d..35cac80d2d4e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -4,9 +4,6 @@
 #ifndef IPU6_MMU_H
 #define IPU6_MMU_H
 
-#define ISYS_MMID 1
-#define PSYS_MMID 0
-
 #include <linux/list.h>
 #include <linux/spinlock_types.h>
 #include <linux/types.h>
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 7ac9c92744c0..c24e18520de6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -424,8 +424,7 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
 				"ipu6_bus_initialize_device isys failed\n");
 	}
 
-	isys_adev->mmu = ipu6_mmu_init(dev, base, ISYS_MMID,
-				       &ipdata->hw_variant);
+	isys_adev->mmu = ipu6_mmu_init(dev, base, IPU_ISYS, &ipdata->hw_variant);
 	if (IS_ERR(isys_adev->mmu)) {
 		put_device(&isys_adev->auxdev.dev);
 		return dev_err_cast_probe(dev, isys_adev->mmu,
@@ -465,7 +464,7 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
 				"ipu6_bus_initialize_device psys failed\n");
 	}
 
-	psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, PSYS_MMID,
+	psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, IPU_PSYS,
 				       &ipdata->hw_variant);
 	if (IS_ERR(psys_adev->mmu)) {
 		put_device(&psys_adev->auxdev.dev);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index ebae876058ca..dc98a787612f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -70,6 +70,9 @@ struct ipu6_device {
 	bool bus_ready_to_probe;
 };
 
+#define IPU_PSYS	0
+#define IPU_ISYS	1
+
 #define IPU6_ISYS_NAME "isys"
 #define IPU6_PSYS_NAME "psys"
 
-- 
2.55.0


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

* [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (10 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation Antti Laakso
                   ` (31 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 differs from ipu6 e.g. in power management, authentication,
interrupt handling and clock setup. Add support for ipu7 buttress.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.c  | 292 +++++++++++++++---
 drivers/media/pci/intel/ipu6/ipu6-buttress.h  |   3 +
 .../intel/ipu6/ipu6-platform-buttress-regs.h  | 102 ++++++
 drivers/media/pci/intel/ipu6/ipu6.c           | 104 +++++--
 drivers/media/pci/intel/ipu6/ipu6.h           |   2 +
 include/media/ipu6-pci-table.h                |   2 +
 6 files changed, 444 insertions(+), 61 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index e77a569bb97e..13fd7a083b25 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -345,6 +345,13 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
 	if (!active)
 		return IRQ_NONE;
 
+	if (IS_IPU7(isp)) {
+		u32 pb_irq;
+
+		pb_irq = readl(isp->pb_base + IPU7_PB_INTERRUPT_STATUS);
+		writel(pb_irq, isp->pb_base + IPU7_PB_INTERRUPT_STATUS);
+	}
+
 	irq_status = readl(isp->base + regs->irq_status);
 	if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) {
 		if (active > 0)
@@ -442,28 +449,141 @@ irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
 	return ret;
 }
 
-int ipu6_buttress_power(struct device *dev,
-			const struct ipu6_buttress_ctrl *ctrl, bool on)
+static int ipu7_isys_d2d_power(struct ipu6_device *isp, bool on)
+{
+	u32 target = on ? IPU7_BUTTRESS_D2D_PWR_ACK : 0U;
+	u32 val;
+	int ret;
+
+	val = readl(isp->base + IPU7_BUTTRESS_REG_D2D_CTL);
+	if ((val & IPU7_BUTTRESS_D2D_PWR_ACK) == target)
+		return 0;
+
+	if (on)
+		val |= IPU7_BUTTRESS_D2D_PWR_EN;
+	else
+		val &= ~IPU7_BUTTRESS_D2D_PWR_EN;
+	writel(val, isp->base + IPU7_BUTTRESS_REG_D2D_CTL);
+
+	ret = readl_poll_timeout(isp->base + IPU7_BUTTRESS_REG_D2D_CTL, val,
+				 (val & IPU7_BUTTRESS_D2D_PWR_ACK) == target,
+				 100, BUTTRESS_POWER_TIMEOUT_US);
+	if (ret)
+		dev_err(&isp->pdev->dev, "D2D power %s timeout: 0x%x\n",
+			on ? "up" : "down", val);
+
+	return ret;
+}
+
+static void ipu7_nde_control(struct ipu6_device *isp, bool on)
+{
+	u32 val;
+
+	val = FIELD_PREP(IPU7_NDE_VAL_MASK,
+			 on ? IPU7_NDE_VAL_ACTIVE : IPU7_NDE_VAL_DEFAULT) |
+	      FIELD_PREP(IPU7_NDE_SCALE_MASK,
+			 on ? IPU7_NDE_SCALE_ACTIVE : IPU7_NDE_SCALE_DEFAULT) |
+	      FIELD_PREP(IPU7_NDE_VALID_MASK,
+			 on ? IPU7_NDE_VALID_ACTIVE : IPU7_NDE_VALID_DEFAULT) |
+	      FIELD_PREP(IPU7_NDE_RESVEC_MASK, IPU7_NDE_RESVEC);
+	writel(val, isp->base + IPU7_BUTTRESS_REG_NDE_CONTROL);
+}
+
+static int __ipu7_power_on(struct device *dev,
+			   const struct ipu6_buttress_ctrl *ctrl)
+{
+	struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
+	bool is_isys = ctrl->subsys_id == IPU_ISYS;
+	u32 pwr_sts, val, ovrd_clk, slp, own_clk_ack;
+	int ret;
+
+	val = ctrl->ratio | (IPU7_FREQ_CTL_CDYN << IPU7_FREQ_CTL_CDYN_SHIFT);
+	pwr_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift;
+
+	if (is_isys) {
+		ret = ipu7_isys_d2d_power(isp, true);
+		if (ret)
+			return ret;
+
+		ipu7_nde_control(isp, true);
+	}
+
+	/* Request clock ownership. */
+	ovrd_clk = is_isys ? IPU7_BUTTRESS_OVERRIDE_IS_CLK :
+			     IPU7_BUTTRESS_OVERRIDE_PS_CLK;
+
+	slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+	writel(slp | ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+
+	own_clk_ack = is_isys ? IPU7_BUTTRESS_OWN_ACK_IS_CLK :
+				IPU7_BUTTRESS_OWN_ACK_PS_CLK;
+	ret = readl_poll_timeout(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_STS,
+				 slp, (slp & own_clk_ack),
+				 100, BUTTRESS_POWER_TIMEOUT_US);
+	if (ret)
+		dev_warn(&isp->pdev->dev, "clock ownership timeout: 0x%x\n",
+			 slp);
+
+	writel(val, isp->base + ctrl->freq_ctl);
+
+	ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
+				 val, (val & ctrl->pwr_sts_mask) == pwr_sts,
+				 100, BUTTRESS_POWER_TIMEOUT_US);
+	if (ret) {
+		dev_err(&isp->pdev->dev,
+			"Change power status timeout with 0x%x\n", val);
+		return ret;
+	}
+
+	slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+	writel(slp & ~ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+
+	return 0;
+}
+
+static int __ipu7_power_off(struct device *dev,
+			    const struct ipu6_buttress_ctrl *ctrl)
 {
 	struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
 	u32 pwr_sts, val;
 	int ret;
 
-	if (!ctrl)
-		return 0;
+	writel(0x8U, isp->base + ctrl->freq_ctl);
 
-	mutex_lock(&isp->buttress.power_mutex);
+	pwr_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift;
+	ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
+				 val, (val & ctrl->pwr_sts_mask) == pwr_sts,
+				 100, BUTTRESS_POWER_TIMEOUT_US);
+	if (ret) {
+		dev_err(&isp->pdev->dev,
+			"Change power status timeout with 0x%x\n", val);
+		return ret;
+	}
+
+	if (ctrl->subsys_id == IPU_ISYS) {
+		ipu7_isys_d2d_power(isp, false);
+		ipu7_nde_control(isp, false);
+	}
+
+	return 0;
+}
+
+static int __ipu6_power(struct device *dev,
+			const struct ipu6_buttress_ctrl *ctrl, bool on)
+{
+	struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
+	u32 pwr_sts, val;
+	int ret;
 
 	if (!on) {
 		val = 0;
 		pwr_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift;
 	} else {
 		val = BUTTRESS_FREQ_CTL_START |
-			FIELD_PREP(BUTTRESS_FREQ_CTL_RATIO_MASK,
-				   ctrl->ratio) |
-			FIELD_PREP(BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK,
-				   ctrl->qos_floor) |
-			BUTTRESS_FREQ_CTL_ICCMAX_LEVEL;
+		      FIELD_PREP(BUTTRESS_FREQ_CTL_RATIO_MASK, ctrl->ratio) |
+		      FIELD_PREP(BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK,
+				 ctrl->qos_floor) |
+		      BUTTRESS_FREQ_CTL_ICCMAX_LEVEL;
 
 		pwr_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift;
 	}
@@ -477,6 +597,26 @@ int ipu6_buttress_power(struct device *dev,
 		dev_err(&isp->pdev->dev,
 			"Change power status timeout with 0x%x\n", val);
 
+	return ret;
+}
+
+int ipu6_buttress_power(struct device *dev,
+			const struct ipu6_buttress_ctrl *ctrl, bool on)
+{
+	struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
+	int ret;
+
+	if (!ctrl)
+		return 0;
+
+	mutex_lock(&isp->buttress.power_mutex);
+
+	if (IS_IPU7(isp))
+		ret = on ? __ipu7_power_on(dev, ctrl) :
+			   __ipu7_power_off(dev, ctrl);
+	else
+		ret = __ipu6_power(dev, ctrl, on);
+
 	mutex_unlock(&isp->buttress.power_mutex);
 
 	return ret;
@@ -634,11 +774,18 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
 	 * Write address of FIT table to FW_SOURCE register
 	 * Let's use fw address. I.e. not using FIT table yet
 	 */
-	data = lower_32_bits(isp->psys->pkg_dir_dma_addr);
-	writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_LO);
+	if (IS_IPU7(isp)) {
+		writel(isp->cpd_fw->size,
+		       isp->base + IPU7_BUTTRESS_REG_FW_SOURCE_SIZE);
+		writel(sg_dma_address(isp->psys->fw_sgt.sgl),
+		       isp->base + IPU7_BUTTRESS_REG_FW_SOURCE_BASE);
+	} else {
+		data = lower_32_bits(isp->psys->pkg_dir_dma_addr);
+		writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_LO);
 
-	data = upper_32_bits(isp->psys->pkg_dir_dma_addr);
-	writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_HI);
+		data = upper_32_bits(isp->psys->pkg_dir_dma_addr);
+		writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_HI);
+	}
 
 	/*
 	 * Write boot_load into IU2CSEDATA0
@@ -674,8 +821,11 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
 		goto out_unlock;
 	}
 
-	ret = readl_poll_timeout(psys_pdata->base + BOOTLOADER_STATUS_OFFSET,
-				 data, data == BOOTLOADER_MAGIC_KEY, 500,
+	void __iomem *base = IS_IPU7(isp) ?
+			     isp->base + IPU7_BUTTRESS_REG_FW_BOOT_PARAMS7 :
+			     psys_pdata->base + BOOTLOADER_STATUS_OFFSET;
+
+	ret = readl_poll_timeout(base, data, data == BOOTLOADER_MAGIC_KEY, 500,
 				 BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US);
 	if (ret) {
 		dev_err(&isp->pdev->dev, "Unexpected magic number 0x%x\n",
@@ -815,12 +965,61 @@ u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp)
 }
 EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_ticks_to_ns, "INTEL_IPU6");
 
-void ipu6_buttress_restore(struct ipu6_device *isp)
+/* trigger uc control to wakeup fw */
+void ipu7_buttress_wakeup_isys(const struct ipu6_device *isp)
+{
+	u32 val;
+
+	val = readl(isp->base + IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS);
+	val |= IPU7_UCX_CTL_WAKEUP;
+	writel(val, isp->base + IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS);
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_buttress_wakeup_isys, "INTEL_IPU6");
+
+u32 ipu7_buttress_get_isys_freq(struct ipu6_device *isp)
+{
+	u32 val;
+
+	val = readl(isp->base + IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ);
+	val &= IPU7_BUTTRESS_IS_FREQ_CTL_RATIO_MASK;
+
+	return val * 50 / 3;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_buttress_get_isys_freq, "INTEL_IPU6");
+
+static void ipu7_buttress_setup(struct ipu6_device *isp)
 {
 	struct ipu6_buttress *b = &isp->buttress;
+	u32 val;
+
+	/* program PB BAR */
+	writel(0, isp->pb_base + IPU7_GLOBAL_INTERRUPT_MASK);
+	val = readl(isp->pb_base + IPU7_BAR2_MISC_CONFIG);
+	val |= 0x100U;
+
+	writel(val, isp->pb_base + IPU7_BAR2_MISC_CONFIG);
+
+	writel(BIT(22), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
+	writel(BIT(1), isp->pb_base + IPU7_TLBID_HASH_ENABLE_127_96);
 
 	writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+	writel(b->regs->irq_all, isp->base + IPU7_BUTTRESS_REG_IRQ_MASK);
 	writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+
+	/* LNL SW workaround for PS PD hang when PS sub-domain during PD */
+	writel(IPU7_BUTTRESS_CG_CTRL_PS_FSM_CG, isp->base + IPU7_BUTTRESS_REG_CG_CTRL_BITS);
+}
+
+void ipu6_buttress_restore(struct ipu6_device *isp)
+{
+	struct ipu6_buttress *b = &isp->buttress;
+
+	if (IS_IPU7(isp)) {
+		ipu7_buttress_setup(isp);
+	} else {
+		writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+		writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+	}
 	writel(b->wdt_cached_value, isp->base + b->regs->wdt);
 }
 
@@ -838,37 +1037,44 @@ int ipu6_buttress_init(struct ipu6_device *isp)
 	init_completion(&b->ipc.recv_complete);
 
 	INIT_LIST_HEAD(&b->constraints);
-
 	isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
-	dev_dbg(&isp->pdev->dev, "IPU6 in %s mode touch 0x%x mask 0x%x\n",
-		isp->secure_mode ? "secure" : "non-secure",
-		readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
-		readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
 
-	b->wdt_cached_value = readl(isp->base + b->regs->wdt);
-	writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
-	writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+	dev_dbg(&isp->pdev->dev, "IPU in %s mode\n",
+		isp->secure_mode ? "secure" : "non-secure");
 
-	/* get ref_clk frequency by reading the indication in btrs control */
-	val = readl(isp->base + b->regs->btrs_ctrl);
-	val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
-
-	switch (val) {
-	case 0x0:
-		b->ref_clk = 240;
-		break;
-	case 0x1:
-		b->ref_clk = 192;
-		break;
-	case 0x2:
+	if (IS_IPU7(isp)) {
+		ipu7_buttress_setup(isp);
 		b->ref_clk = 384;
-		break;
-	default:
-		dev_warn(&isp->pdev->dev,
-			 "Unsupported ref clock, use 19.2Mhz by default.\n");
-		b->ref_clk = 192;
-		break;
+	} else {
+		dev_dbg(&isp->pdev->dev, "IPU6 touch 0x%x mask 0x%x\n",
+			readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
+			readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
+
+		writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+		writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+
+		/* get ref_clk frequency by reading the indication in btrs control */
+		val = readl(isp->base + b->regs->btrs_ctrl);
+		val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
+
+		switch (val) {
+		case 0x0:
+			b->ref_clk = 240;
+			break;
+		case 0x1:
+			b->ref_clk = 192;
+			break;
+		case 0x2:
+			b->ref_clk = 384;
+			break;
+		default:
+			dev_warn(&isp->pdev->dev,
+				 "Unsupported ref clock, use 19.2Mhz by default.\n");
+			b->ref_clk = 192;
+			break;
+		}
 	}
+	b->wdt_cached_value = readl(isp->base + b->regs->wdt);
 
 	/* Retry couple of times in case of CSE initialization is delayed */
 	do {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index a3c23adede7b..af72de2b8729 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -26,6 +26,7 @@ struct ipu6_buttress_ctrl {
 	u32 freq_ctl, pwr_sts_shift, pwr_sts_mask, pwr_sts_on, pwr_sts_off;
 	unsigned int ratio;
 	unsigned int qos_floor;
+	int subsys_id;
 };
 
 struct ipu6_buttress_ipc {
@@ -104,4 +105,6 @@ void ipu6_buttress_exit(struct ipu6_device *isp);
 void ipu6_buttress_csi_port_config(struct ipu6_device *isp,
 				   u32 legacy, u32 combo);
 void ipu6_buttress_restore(struct ipu6_device *isp);
+void ipu7_buttress_wakeup_isys(const struct ipu6_device *isp);
+u32 ipu7_buttress_get_isys_freq(struct ipu6_device *isp);
 #endif /* IPU6_BUTTRESS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index 5006cce74b23..c4da72c6bd8f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -221,4 +221,106 @@ enum {
 #define BUTTRESS_EVENT		 (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
 				  BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE |    \
 				  BUTTRESS_ISR_SAI_VIOLATION)
+
+/* IPU7 */
+
+/* IPU7 buttress register offsets */
+#define IPU7_BUTTRESS_REG_SKU			0x3030
+#define IPU7_BUTTRESS_REG_IRQ_STATUS		0x2000
+#define IPU7_BUTTRESS_REG_IRQ_ENABLE		0x2008
+#define IPU7_BUTTRESS_REG_IRQ_CLEAR		0x200c
+#define IPU7_BUTTRESS_REG_IRQ_MASK		0x2010
+#define IPU7_BUTTRESS_REG_TSC_CMD		0x2014
+#define IPU7_BUTTRESS_REG_TSC_CTL		0x2018
+#define IPU7_BUTTRESS_REG_TSC_LO		0x201c
+#define IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ	0x2104
+#define IPU7_BUTTRESS_REG_PS_WORKPOINT_REQ	0x2100
+#define IPU7_BUTTRESS_REG_IDLE_WDT		0x218c
+#define IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS	0x2200
+#define IPU7_BUTTRESS_REG_ISYS_UCX_START_ADDR	0x2204
+#define IPU7_BUTTRESS_REG_PSYS_UCX_CTRL_STATUS	0x2208
+#define IPU7_BUTTRESS_REG_PSYS_UCX_START_ADDR	0x220c
+#define IPU7_BUTTRESS_REG_SECURITY_CTL		0x2318
+#define IPU7_BUTTRESS_REG_FW_RESET_CTL		0x2334
+#define IPU7_BUTTRESS_REG_FW_SOURCE_SIZE	0x2338
+#define IPU7_BUTTRESS_REG_FW_SOURCE_BASE	0x233c
+#define IPU7_BUTTRESS_REG_CSE2IUDB0		0x2500
+#define IPU7_BUTTRESS_REG_CSE2IUDATA0		0x2504
+#define IPU7_BUTTRESS_REG_CSE2IUCSR		0x2508
+#define IPU7_BUTTRESS_REG_IU2CSEDB0		0x250c
+#define IPU7_BUTTRESS_REG_IU2CSEDATA0		0x2510
+#define IPU7_BUTTRESS_REG_IU2CSECSR		0x2514
+#define IPU7_BUTTRESS_REG_CG_CTRL_BITS		0x3014
+#define IPU7_BUTTRESS_REG_FW_BOOT_PARAMS0	0x4000
+#define IPU7_BUTTRESS_REG_FW_BOOT_PARAMS7	0x401c
+#define IPU7_BUTTRESS_REG_PWR_STATUS		0x2114
+
+#define IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE		BIT(0)
+#define IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING	BIT(1)
+#define IPU7_BUTTRESS_IRQ_CSE_CSR_SET			BIT(2)
+#define IPU7_BUTTRESS_IRQ_SAI_VIOLATION			BIT(4)
+#define IPU7_BUTTRESS_IRQ_IS_IRQ			BIT(30)
+#define IPU7_BUTTRESS_IRQ_PS_IRQ			BIT(31)
+
+#define IPU7_BUTTRESS_IRQS	(IPU7_BUTTRESS_IRQ_IS_IRQ |		\
+				 IPU7_BUTTRESS_IRQ_PS_IRQ |		\
+				 IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING | \
+				 IPU7_BUTTRESS_IRQ_CSE_CSR_SET |	\
+				 IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE)
+
+/* LNL SW workaround for PS PD hang */
+#define IPU7_BUTTRESS_CG_CTRL_PS_FSM_CG		BIT(3)
+
+/* P-unit Bridge (PB) BAR registers */
+#define IPU7_PB_INTERRUPT_STATUS		0x0
+
+/* Frequency control encoding */
+#define IPU7_FREQ_CTL_CDYN			0x80
+#define IPU7_FREQ_CTL_CDYN_SHIFT		8
+#define IPU7_BUTTRESS_IS_FREQ_CTL_RATIO_MASK	GENMASK(7, 0)
+#define IPU7_IS_FREQ_CTL_DEFAULT_RATIO		0x1b
+#define IPU7_PS_FREQ_CTL_DEFAULT_RATIO		0x14
+
+/* D2D power control */
+#define IPU7_BUTTRESS_REG_D2D_CTL		0x21d4
+#define IPU7_BUTTRESS_D2D_PWR_EN		BIT(0)
+#define IPU7_BUTTRESS_D2D_PWR_ACK		BIT(4)
+
+#define IPU7_BUTTRESS_PWR_STATE_IS_PWR_SHIFT	0
+#define IPU7_BUTTRESS_PWR_STATE_IS_PWR_MASK	(0x3U << 0)
+#define IPU7_BUTTRESS_PWR_STATE_PS_PWR_SHIFT	4
+#define IPU7_BUTTRESS_PWR_STATE_PS_PWR_MASK	(0x3U << 4)
+
+/* NDE */
+#define IPU7_BUTTRESS_REG_NDE_CONTROL		0x21a4
+#define IPU7_NDE_VAL_MASK			GENMASK(9, 0)
+#define IPU7_NDE_SCALE_MASK			GENMASK(12, 10)
+#define IPU7_NDE_VALID_MASK			BIT(13)
+#define IPU7_NDE_RESVEC_MASK			GENMASK(19, 16)
+#define IPU7_NDE_VAL_ACTIVE			48
+#define IPU7_NDE_SCALE_ACTIVE			2
+#define IPU7_NDE_VALID_ACTIVE			1
+#define IPU7_NDE_VAL_DEFAULT			1023
+#define IPU7_NDE_SCALE_DEFAULT			2
+#define IPU7_NDE_VALID_DEFAULT			0
+#define IPU7_NDE_RESVEC				0xe
+
+/* IS UCX control */
+#define IPU7_UCX_CTL_RESET			BIT(0)
+#define IPU7_UCX_CTL_RUN			BIT(1)
+#define IPU7_UCX_CTL_WAKEUP			BIT(2)
+
+#define IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG	0x21b0
+#define IPU7_BUTTRESS_REG_SLEEP_LEVEL_STS	0x21b4
+#define IPU7_BUTTRESS_OVERRIDE_IS_CLK		BIT(1)
+#define IPU7_BUTTRESS_OWN_ACK_IS_CLK		BIT(9)
+#define IPU7_BUTTRESS_OVERRIDE_PS_CLK		BIT(2)
+#define IPU7_BUTTRESS_OWN_ACK_PS_CLK		BIT(10)
+
+/* PB registers */
+#define IPU7_GLOBAL_INTERRUPT_MASK		0x8
+#define IPU7_TLBID_HASH_ENABLE_63_32		0x34
+#define IPU7_TLBID_HASH_ENABLE_127_96		0x3c
+#define IPU7_BAR2_MISC_CONFIG			0x64
+
 #endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index c24e18520de6..4af0b068e759 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -34,6 +34,7 @@
 #include "ipu6-platform-regs.h"
 
 #define IPU6_PCI_BAR		0
+#define IPU7_PCI_PBBAR		4
 
 struct ipu6_cell_program {
 	u32 magic_number;
@@ -209,6 +210,7 @@ static struct ipu6_psys_internal_pdata psys_ipdata = {
 };
 
 static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
+	.subsys_id = IPU_ISYS,
 	.ratio = IPU6_IS_FREQ_CTL_DEFAULT_RATIO,
 	.qos_floor = IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
 	.freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
@@ -219,6 +221,7 @@ static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
 };
 
 static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
+	.subsys_id = IPU_PSYS,
 	.ratio = IPU6_PS_FREQ_CTL_DEFAULT_RATIO,
 	.qos_floor = IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
 	.freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
@@ -228,6 +231,28 @@ static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
 	.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
 };
 
+static const struct ipu6_buttress_ctrl ipu7_isys_buttress_ctrl = {
+	.subsys_id = IPU_ISYS,
+	.ratio = IPU7_IS_FREQ_CTL_DEFAULT_RATIO,
+	.qos_floor = 0,
+	.freq_ctl = IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ,
+	.pwr_sts_shift = IPU7_BUTTRESS_PWR_STATE_IS_PWR_SHIFT,
+	.pwr_sts_mask = IPU7_BUTTRESS_PWR_STATE_IS_PWR_MASK,
+	.pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
+	.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
+};
+
+static const struct ipu6_buttress_ctrl ipu7_psys_buttress_ctrl = {
+	.subsys_id = IPU_PSYS,
+	.ratio = IPU7_PS_FREQ_CTL_DEFAULT_RATIO,
+	.qos_floor = 0,
+	.freq_ctl = IPU7_BUTTRESS_REG_PS_WORKPOINT_REQ,
+	.pwr_sts_shift = IPU7_BUTTRESS_PWR_STATE_PS_PWR_SHIFT,
+	.pwr_sts_mask = IPU7_BUTTRESS_PWR_STATE_PS_PWR_MASK,
+	.pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
+	.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
+};
+
 static const struct ipu6_buttress_registers ipu6_buttress_regs = {
 	/* Registers */
 	.irq_status	= BUTTRESS_REG_ISR_STATUS,
@@ -258,6 +283,35 @@ static const struct ipu6_buttress_registers ipu6_buttress_regs = {
 	.irq_sai	= BUTTRESS_ISR_SAI_VIOLATION,
 };
 
+static const struct ipu6_buttress_registers ipu7_buttress_regs = {
+	/* Registers */
+	.irq_status	= IPU7_BUTTRESS_REG_IRQ_STATUS,
+	.irq_clear	= IPU7_BUTTRESS_REG_IRQ_CLEAR,
+	.irq_enable	= IPU7_BUTTRESS_REG_IRQ_ENABLE,
+	.pwr_status	= IPU7_BUTTRESS_REG_PWR_STATUS,
+	.security_ctl	= IPU7_BUTTRESS_REG_SECURITY_CTL,
+	.fw_reset_ctl	= IPU7_BUTTRESS_REG_FW_RESET_CTL,
+	.fabric_cmd	= IPU7_BUTTRESS_REG_TSC_CMD,
+	.tsw_ctl	= IPU7_BUTTRESS_REG_TSC_CTL,
+	.tsc_lo		= IPU7_BUTTRESS_REG_TSC_LO,
+	.wdt		= IPU7_BUTTRESS_REG_IDLE_WDT,
+	.csr_in		= IPU7_BUTTRESS_REG_CSE2IUCSR,
+	.csr_out	= IPU7_BUTTRESS_REG_IU2CSECSR,
+	.db0_in		= IPU7_BUTTRESS_REG_CSE2IUDB0,
+	.db0_out	= IPU7_BUTTRESS_REG_IU2CSEDB0,
+	.data0_in	= IPU7_BUTTRESS_REG_CSE2IUDATA0,
+	.data0_out	= IPU7_BUTTRESS_REG_IU2CSEDATA0,
+
+	/* Bitmasks */
+	.irq_is		= IPU7_BUTTRESS_IRQ_IS_IRQ,
+	.irq_ps		= IPU7_BUTTRESS_IRQ_PS_IRQ,
+	.irq_all	= IPU7_BUTTRESS_IRQS,
+	.irq_events	= IPU7_BUTTRESS_IRQS,
+	.irq_cse_ipc	= IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING,
+	.irq_exec_done	= IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE,
+	.irq_sai	= IPU7_BUTTRESS_IRQ_SAI_VIOLATION,
+};
+
 static void
 ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
 			   const struct ipu6_hw_variants *hw_variant,
@@ -532,24 +586,6 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (!isp)
 		return -ENOMEM;
 
-	isp->pdev = pdev;
-	INIT_LIST_HEAD(&isp->devices);
-
-	ret = pcim_enable_device(pdev);
-	if (ret)
-		return dev_err_probe(dev, ret, "Enable PCI device failed\n");
-
-	phys = pci_resource_start(pdev, IPU6_PCI_BAR);
-	dev_dbg(dev, "IPU6 PCI bar[%u] = %pa\n", IPU6_PCI_BAR, &phys);
-
-	isp->base = pcim_iomap_region(pdev, IPU6_PCI_BAR, IPU6_NAME);
-	if (IS_ERR(isp->base))
-		return dev_err_probe(dev, PTR_ERR(isp->base),
-				     "Failed to I/O mem remapping\n");
-
-	pci_set_drvdata(pdev, isp);
-	pci_set_master(pdev);
-
 	isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
 	isp->buttress.regs = &ipu6_buttress_regs;
 
@@ -577,12 +613,44 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		isp->hw_ver = IPU_VERSION_6EP_MTL;
 		isp->cpd_fw_name = IPU6EPMTL_FIRMWARE_NAME;
 		break;
+	case PCI_DEVICE_ID_INTEL_IPU7:
+		isp->hw_ver = IPU_VERSION_7;
+		isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
+		isp->buttress.regs = &ipu7_buttress_regs;
+		break;
 	default:
 		return dev_err_probe(dev, -ENODEV,
 				     "Unsupported IPU6 device %x\n",
 				     id->device);
 	}
 
+	isp->pdev = pdev;
+	INIT_LIST_HEAD(&isp->devices);
+
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Enable PCI device failed\n");
+
+	phys = pci_resource_start(pdev, IPU6_PCI_BAR);
+	dev_dbg(dev, "IPU6 PCI bar[%u] = %pa\n", IPU6_PCI_BAR, &phys);
+
+	isp->base = pcim_iomap_region(pdev, IPU6_PCI_BAR, IPU6_NAME);
+	if (IS_ERR(isp->base))
+		return dev_err_probe(dev, PTR_ERR(isp->base),
+				     "Failed to I/O mem remapping\n");
+
+	if (IS_IPU7(isp)) {
+		isp->pb_base = pcim_iomap_region(pdev, IPU7_PCI_PBBAR,
+						 IPU6_NAME);
+		if (IS_ERR(isp->pb_base))
+			return dev_err_probe(dev, PTR_ERR(isp->pb_base),
+					     "I/O remapping PB BAR %u failed\n",
+					     IPU7_PCI_PBBAR);
+	}
+
+	pci_set_drvdata(pdev, isp);
+	pci_set_master(pdev);
+
 	ipu6_internal_pdata_init(isp);
 
 	isys_base = isp->base + isys_ipdata.hw_variant.offset;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index dc98a787612f..a14b067f169f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -22,6 +22,7 @@ struct ipu6_bus_device;
 #define IPU6_FIRMWARE_NAME		"intel/ipu/ipu6_fw.bin"
 #define IPU6EPMTL_FIRMWARE_NAME		"intel/ipu/ipu6epmtl_fw.bin"
 #define IPU6EPADLN_FIRMWARE_NAME	"intel/ipu/ipu6epadln_fw.bin"
+#define IPU7_FIRMWARE_NAME		"intel/ipu/ipu7_fw.bin"
 
 #define IPU_VERSION_6		BIT(0) /* TGL */
 #define IPU_VERSION_6SE		BIT(1) /* JSL */
@@ -64,6 +65,7 @@ struct ipu6_device {
 	u32 cpd_metadata_cmpnt_size;
 
 	void __iomem *base;
+	void __iomem *pb_base;
 	bool need_ipc_reset;
 	bool secure_mode;
 	u8 hw_ver;
diff --git a/include/media/ipu6-pci-table.h b/include/media/ipu6-pci-table.h
index 0899d9d2f978..cd5b941fb96c 100644
--- a/include/media/ipu6-pci-table.h
+++ b/include/media/ipu6-pci-table.h
@@ -14,6 +14,8 @@
 #define PCI_DEVICE_ID_INTEL_IPU6EP_ADLN		0x462e
 #define PCI_DEVICE_ID_INTEL_IPU6EP_RPLP		0xa75d
 #define PCI_DEVICE_ID_INTEL_IPU6EP_MTL		0x7d19
+#define PCI_DEVICE_ID_INTEL_IPU7		0x645d
+#define PCI_DEVICE_ID_INTEL_IPU7P5		0xb05d
 
 static const struct pci_device_id ipu6_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6) },
-- 
2.55.0


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

* [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (11 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support Antti Laakso
                   ` (30 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

We are about to add support for ipu7 mmu. Split ipu6 mmu
hardware specific and common code to separate files.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/Makefile      |   1 +
 drivers/media/pci/intel/ipu6/ipu6-dma.c    |   4 +-
 drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c | 296 +++++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu6-mmu.c    | 120 +--------
 drivers/media/pci/intel/ipu6/ipu6-mmu.h    | 149 ++++++++++-
 drivers/media/pci/intel/ipu6/ipu6.c        | 125 +--------
 drivers/media/pci/intel/ipu6/ipu6.h        | 132 +--------
 7 files changed, 456 insertions(+), 371 deletions(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c

diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index a821b0a1567f..2106ab84acde 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -4,6 +4,7 @@ intel-ipu6-y			:= ipu6.o \
 				ipu6-bus.o \
 				ipu6-dma.o \
 				ipu6-mmu.o \
+				ipu6-mmu-hw.o \
 				ipu6-buttress.o \
 				ipu6-cpd.o \
 				ipu6-fw-com.o
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c
index fdcdb15b073c..6e8295d9c3a3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c
@@ -286,7 +286,7 @@ void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
 
 	__free_buffer(pages, size, attrs);
 
-	mmu->tlb_invalidate(mmu);
+	mmu->ops->tlb_invalidate(mmu);
 
 	__free_iova(&mmu->dmap->iovad, iova);
 
@@ -366,7 +366,7 @@ void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
 	ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
 		       PFN_PHYS(iova_size(iova)));
 
-	mmu->tlb_invalidate(mmu);
+	mmu->ops->tlb_invalidate(mmu);
 	__free_iova(&mmu->dmap->iovad, iova);
 }
 EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c b/drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c
new file mode 100644
index 000000000000..2b395fbd5969
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+#include <asm/barrier.h>
+
+#include <linux/bits.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "ipu6.h"
+#include "ipu6-dma.h"
+#include "ipu6-mmu.h"
+#include "ipu6-platform-regs.h"
+
+#define ISP_PAGE_SHIFT		12
+#define ISP_PAGE_SIZE		BIT(ISP_PAGE_SHIFT)
+#define ISP_PAGE_MASK		(~(ISP_PAGE_SIZE - 1))
+
+#define ISP_L1PT_SHIFT		22
+#define ISP_L1PT_MASK		(~((1U << ISP_L1PT_SHIFT) - 1))
+
+#define ISP_L2PT_SHIFT		12
+#define ISP_L2PT_MASK		(~(ISP_L1PT_MASK | (~(ISP_PAGE_MASK))))
+
+#define ISP_L1PT_PTES           1024
+#define ISP_L2PT_PTES           1024
+
+#define ISP_PADDR_SHIFT		12
+
+#define REG_TLB_INVALIDATE	0x0000
+
+#define REG_L1_PHYS		0x0004	/* 27-bit pfn */
+#define REG_INFO		0x0008
+
+#define TBL_PHYS_ADDR(a)	((phys_addr_t)(a) << ISP_PADDR_SHIFT)
+
+static struct ipu6_mmu_hw ipu6_isys_mmu_hwdata[] = {
+	{
+		.offset = IPU6_ISYS_IOMMU0_OFFSET,
+		.info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
+		.nr_l1streams = 16,
+		.l1_block_sz = {
+			3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
+			1, 1, 1, 1, 1, 1
+		},
+		.nr_l2streams = 16,
+		.l2_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2
+		},
+		.insert_read_before_invalidate = false,
+		.l1_stream_id_reg_offset =
+		IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+		.l2_stream_id_reg_offset =
+		IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+	},
+	{
+		.offset = IPU6_ISYS_IOMMU1_OFFSET,
+		.info_bits = 0,
+		.nr_l1streams = 16,
+		.l1_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 1, 1, 4
+		},
+		.nr_l2streams = 16,
+		.l2_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2
+		},
+		.insert_read_before_invalidate = false,
+		.l1_stream_id_reg_offset =
+		IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+		.l2_stream_id_reg_offset =
+		IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+	},
+	{
+		.offset = IPU6_ISYS_IOMMUI_OFFSET,
+		.info_bits = 0,
+		.nr_l1streams = 0,
+		.nr_l2streams = 0,
+		.insert_read_before_invalidate = false,
+	},
+};
+
+static struct ipu6_mmu_hw ipu6_psys_mmu_hwdata[] = {
+	{
+		.offset = IPU6_PSYS_IOMMU0_OFFSET,
+		.info_bits =
+		IPU6_INFO_REQUEST_DESTINATION_IOSF,
+		.nr_l1streams = 16,
+		.l1_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2
+		},
+		.nr_l2streams = 16,
+		.l2_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2
+		},
+		.insert_read_before_invalidate = false,
+		.l1_stream_id_reg_offset =
+		IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+		.l2_stream_id_reg_offset =
+		IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+	},
+	{
+		.offset = IPU6_PSYS_IOMMU1_OFFSET,
+		.info_bits = 0,
+		.nr_l1streams = 32,
+		.l1_block_sz = {
+			1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 10,
+			5, 4, 14, 6, 4, 14, 6, 4, 8,
+			4, 2, 1, 1, 1, 1, 14
+		},
+		.nr_l2streams = 32,
+		.l2_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2
+		},
+		.insert_read_before_invalidate = false,
+		.l1_stream_id_reg_offset =
+		IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+		.l2_stream_id_reg_offset =
+		IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
+	},
+	{
+		.offset = IPU6_PSYS_IOMMU1R_OFFSET,
+		.info_bits = 0,
+		.nr_l1streams = 16,
+		.l1_block_sz = {
+			1, 4, 4, 4, 4, 16, 8, 4, 32,
+			16, 16, 2, 2, 2, 1, 12
+		},
+		.nr_l2streams = 16,
+		.l2_block_sz = {
+			2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+			2, 2, 2, 2, 2, 2
+		},
+		.insert_read_before_invalidate = false,
+		.l1_stream_id_reg_offset =
+		IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+		.l2_stream_id_reg_offset =
+		IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+	},
+	{
+		.offset = IPU6_PSYS_IOMMUI_OFFSET,
+		.info_bits = 0,
+		.nr_l1streams = 0,
+		.nr_l2streams = 0,
+		.insert_read_before_invalidate = false,
+	},
+};
+
+struct ipu6_mmu_hwdata {
+	struct ipu6_mmu_hw *hwdata;
+	unsigned int nr_mmus;
+};
+
+static const struct ipu6_mmu_hwdata ipu6_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
+	[IPU_PSYS] = {
+		.hwdata = ipu6_psys_mmu_hwdata,
+		.nr_mmus = ARRAY_SIZE(ipu6_psys_mmu_hwdata),
+	},
+	[IPU_ISYS] = {
+		.hwdata = ipu6_isys_mmu_hwdata,
+		.nr_mmus = ARRAY_SIZE(ipu6_isys_mmu_hwdata),
+	},
+};
+
+static void __ipu6_tlb_invalidate(struct ipu6_mmu *mmu)
+{
+	struct ipu6_mmu_hw *mmu_hw = mmu->ipu6_mmu_hw;
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&mmu->ready_lock, flags);
+	if (!mmu->ready) {
+		spin_unlock_irqrestore(&mmu->ready_lock, flags);
+		return;
+	}
+
+	for (i = 0; i < mmu->nr_mmus; i++) {
+		/*
+		 * To avoid the HW bug induced dead lock in some of the IPU6
+		 * MMUs on successive invalidate calls, we need to first do a
+		 * read to the page table base before writing the invalidate
+		 * register. MMUs which need to implement this WA, will have
+		 * the insert_read_before_invalidate flags set as true.
+		 * Disregard the return value of the read.
+		 */
+		if (mmu_hw[i].insert_read_before_invalidate)
+			readl(mmu_hw[i].base + REG_L1_PHYS);
+
+		writel(0xffffffff, mmu_hw[i].base + REG_TLB_INVALIDATE);
+		/*
+		 * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
+		 * When the actual MMIO write reaches the IPU6 TLB Invalidate
+		 * register, wmb() will force the TLB invalidate out if the CPU
+		 * attempts to update the IOMMU page table (or sooner).
+		 */
+		wmb();
+	}
+	spin_unlock_irqrestore(&mmu->ready_lock, flags);
+}
+
+static int __ipu6_mmu_hw_init(struct ipu6_mmu *mmu)
+{
+	struct ipu6_mmu_info *mmu_info = mmu->dmap->mmu_info;
+	struct ipu6_mmu_hw *mmu_hw = mmu->ipu6_mmu_hw;
+
+	/* Initialise the each MMU HW block */
+	for (unsigned int i = 0; i < mmu->nr_mmus; i++) {
+		unsigned int j;
+		u16 block_addr;
+
+		/* Write page table address per MMU */
+		writel((phys_addr_t)mmu_info->l1_pt_dma,
+		       mmu_hw[i].base + REG_L1_PHYS);
+
+		/* Set info bits per MMU */
+		writel(mmu_hw[i].info_bits, mmu_hw[i].base + REG_INFO);
+
+		/* Configure MMU TLB stream configuration for L1 */
+		for (j = 0, block_addr = 0; j < mmu_hw[i].nr_l1streams;
+		     block_addr += mmu_hw[i].l1_block_sz[j], j++) {
+			if (block_addr > IPU6_MAX_LI_BLOCK_ADDR) {
+				dev_err(mmu->dev, "invalid L1 configuration\n");
+				return -EINVAL;
+			}
+
+			/* Write block start address for each streams */
+			writel(block_addr, mmu_hw[i].base +
+			       mmu_hw[i].l1_stream_id_reg_offset + 4 * j);
+		}
+
+		/* Configure MMU TLB stream configuration for L2 */
+		for (j = 0, block_addr = 0; j < mmu_hw[i].nr_l2streams;
+		     block_addr += mmu_hw[i].l2_block_sz[j], j++) {
+			if (block_addr > IPU6_MAX_L2_BLOCK_ADDR) {
+				dev_err(mmu->dev, "invalid L2 configuration\n");
+				return -EINVAL;
+			}
+
+			writel(block_addr, mmu_hw[i].base +
+			       mmu_hw[i].l2_stream_id_reg_offset + 4 * j);
+		}
+	}
+
+	return 0;
+}
+
+static int __ipu6_mmu_init_hw_data(struct ipu6_mmu *mmu, struct device *dev,
+				   void __iomem *base)
+{
+	const struct ipu6_mmu_hwdata *lookup;
+	struct ipu6_mmu_hw *mmu_hw, *src;
+	unsigned int i, nr_mmus;
+
+	if (mmu->mmid >= IPU_SUBSYS_NUM)
+		return -EINVAL;
+
+	lookup = &ipu6_mmu_hwdata_lookup[mmu->mmid];
+	src = lookup->hwdata;
+	nr_mmus = lookup->nr_mmus;
+
+	mmu_hw = devm_kcalloc(dev, nr_mmus, sizeof(*mmu_hw), GFP_KERNEL);
+	if (!mmu_hw)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_mmus; i++) {
+		if (src[i].nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
+		    src[i].nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
+			return -EINVAL;
+
+		mmu_hw[i] = src[i];
+		mmu_hw[i].base = base + src[i].offset;
+	}
+
+	mmu->nr_mmus = nr_mmus;
+	mmu->ipu6_mmu_hw = mmu_hw;
+
+	return 0;
+}
+
+const struct ipu6_mmu_hw_ops ipu6_mmu_ops = {
+	.init_hw_data = __ipu6_mmu_init_hw_data,
+	.hw_init = __ipu6_mmu_hw_init,
+	.tlb_invalidate = __ipu6_tlb_invalidate,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 6b1a49ebbcc2..98ac59d00b78 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -5,7 +5,6 @@
 #include <asm/barrier.h>
 
 #include <linux/align.h>
-#include <linux/atomic.h>
 #include <linux/bitops.h>
 #include <linux/bits.h>
 #include <linux/bug.h>
@@ -13,10 +12,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/gfp.h>
-#include <linux/io.h>
 #include <linux/iova.h>
 #include <linux/math.h>
-#include <linux/minmax.h>
 #include <linux/mm.h>
 #include <linux/pfn.h>
 #include <linux/slab.h>
@@ -51,42 +48,6 @@
 
 #define TBL_PHYS_ADDR(a)	((phys_addr_t)(a) << ISP_PADDR_SHIFT)
 
-static void tlb_invalidate(struct ipu6_mmu *mmu)
-{
-	unsigned long flags;
-	unsigned int i;
-
-	spin_lock_irqsave(&mmu->ready_lock, flags);
-	if (!mmu->ready) {
-		spin_unlock_irqrestore(&mmu->ready_lock, flags);
-		return;
-	}
-
-	for (i = 0; i < mmu->nr_mmus; i++) {
-		/*
-		 * To avoid the HW bug induced dead lock in some of the IPU6
-		 * MMUs on successive invalidate calls, we need to first do a
-		 * read to the page table base before writing the invalidate
-		 * register. MMUs which need to implement this WA, will have
-		 * the insert_read_before_invalidate flags set as true.
-		 * Disregard the return value of the read.
-		 */
-		if (mmu->mmu_hw[i].insert_read_before_invalidate)
-			readl(mmu->mmu_hw[i].base + REG_L1_PHYS);
-
-		writel(0xffffffff, mmu->mmu_hw[i].base +
-		       REG_TLB_INVALIDATE);
-		/*
-		 * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
-		 * When the actual MMIO write reaches the IPU6 TLB Invalidate
-		 * register, wmb() will force the TLB invalidate out if the CPU
-		 * attempts to update the IOMMU page table (or sooner).
-		 */
-		wmb();
-	}
-	spin_unlock_irqrestore(&mmu->ready_lock, flags);
-}
-
 #ifdef DEBUG
 static void page_table_dump(struct ipu6_mmu_info *mmu_info)
 {
@@ -472,55 +433,14 @@ static int allocate_trash_buffer(struct ipu6_mmu *mmu)
 
 int ipu6_mmu_hw_init(struct ipu6_mmu *mmu)
 {
-	struct ipu6_mmu_info *mmu_info;
 	unsigned long flags;
-	unsigned int i;
-
-	mmu_info = mmu->dmap->mmu_info;
-
-	/* Initialise the each MMU HW block */
-	for (i = 0; i < mmu->nr_mmus; i++) {
-		struct ipu6_mmu_hw *mmu_hw = &mmu->mmu_hw[i];
-		unsigned int j;
-		u16 block_addr;
-
-		/* Write page table address per MMU */
-		writel((phys_addr_t)mmu_info->l1_pt_dma,
-		       mmu->mmu_hw[i].base + REG_L1_PHYS);
-
-		/* Set info bits per MMU */
-		writel(mmu->mmu_hw[i].info_bits,
-		       mmu->mmu_hw[i].base + REG_INFO);
-
-		/* Configure MMU TLB stream configuration for L1 */
-		for (j = 0, block_addr = 0; j < mmu_hw->nr_l1streams;
-		     block_addr += mmu->mmu_hw[i].l1_block_sz[j], j++) {
-			if (block_addr > IPU6_MAX_LI_BLOCK_ADDR) {
-				dev_err(mmu->dev, "invalid L1 configuration\n");
-				return -EINVAL;
-			}
-
-			/* Write block start address for each streams */
-			writel(block_addr, mmu_hw->base +
-			       mmu_hw->l1_stream_id_reg_offset + 4 * j);
-		}
-
-		/* Configure MMU TLB stream configuration for L2 */
-		for (j = 0, block_addr = 0; j < mmu_hw->nr_l2streams;
-		     block_addr += mmu->mmu_hw[i].l2_block_sz[j], j++) {
-			if (block_addr > IPU6_MAX_L2_BLOCK_ADDR) {
-				dev_err(mmu->dev, "invalid L2 configuration\n");
-				return -EINVAL;
-			}
+	int ret;
 
-			writel(block_addr, mmu_hw->base +
-			       mmu_hw->l2_stream_id_reg_offset + 4 * j);
-		}
-	}
+	ret = mmu->ops->hw_init(mmu);
+	if (ret)
+		return ret;
 
 	if (!mmu->trash_page) {
-		int ret;
-
 		mmu->trash_page = alloc_page(GFP_KERNEL);
 		if (!mmu->trash_page) {
 			dev_err(mmu->dev, "insufficient memory for trash buffer\n");
@@ -746,44 +666,26 @@ static void ipu6_mmu_destroy(struct ipu6_mmu *mmu)
 }
 
 struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
-			       void __iomem *base, int mmid,
-			       const struct ipu6_hw_variants *hw)
+			       void __iomem *base, int mmid)
 {
 	struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
-	struct ipu6_mmu_hw *mmu_hw;
 	struct ipu6_mmu *mmu;
-	unsigned int i;
-
-	if (hw->nr_mmus > IPU6_MMU_MAX_DEVICES)
-		return ERR_PTR(-EINVAL);
-
-	mmu_hw = devm_kcalloc(dev, sizeof(*mmu_hw), hw->nr_mmus, GFP_KERNEL);
-	if (!mmu_hw)
-		return ERR_PTR(-ENOMEM);
-
-	for (i = 0; i < hw->nr_mmus; i++) {
-		const struct ipu6_mmu_hw *src_mmu = &hw->mmu_hw[i];
-
-		if (src_mmu->nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
-		    src_mmu->nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
-			return ERR_PTR(-EINVAL);
-
-		mmu_hw[i] = *src_mmu;
-		mmu_hw[i].base = base + src_mmu->offset;
-	}
+	int ret;
 
 	mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL);
 	if (!mmu)
 		return ERR_PTR(-ENOMEM);
 
+	mmu->ops = &ipu6_mmu_ops;
 	mmu->mmid = mmid;
-	mmu->mmu_hw = mmu_hw;
-	mmu->nr_mmus = hw->nr_mmus;
-	mmu->tlb_invalidate = tlb_invalidate;
 	mmu->ready = false;
 	INIT_LIST_HEAD(&mmu->vma_list);
 	spin_lock_init(&mmu->ready_lock);
 
+	ret = mmu->ops->init_hw_data(mmu, dev, base);
+	if (ret)
+		return ERR_PTR(ret);
+
 	mmu->dmap = alloc_dma_mapping(isp);
 	if (!mmu->dmap) {
 		dev_err(dev, "can't alloc dma mapping\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index 35cac80d2d4e..a741f1c0e284 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2013--2024 Intel Corporation */
+/* Copyright (C) 2013--2026 Intel Corporation */
 
 #ifndef IPU6_MMU_H
 #define IPU6_MMU_H
@@ -10,7 +10,6 @@
 
 struct device;
 struct page;
-struct ipu6_hw_variants;
 
 struct ipu6_mmu_info {
 	struct device *dev;
@@ -32,10 +31,147 @@ struct ipu6_mmu_info {
 	struct ipu6_dma_mapping *dmap;
 };
 
+/*
+ * MMU Invalidation HW bug workaround by ZLW mechanism
+ *
+ * Old IPU6 MMUV2 has a bug in the invalidation mechanism which might result in
+ * wrong translation or replication of the translation. This will cause data
+ * corruption. So we cannot directly use the MMU V2 invalidation registers
+ * to invalidate the MMU. Instead, whenever an invalidate is called, we need to
+ * clear the TLB by evicting all the valid translations by filling it with trash
+ * buffer (which is guaranteed not to be used by any other processes). ZLW is
+ * used to fill the L1 and L2 caches with the trash buffer translations. ZLW
+ * or Zero length write, is pre-fetch mechanism to pre-fetch the pages in
+ * advance to the L1 and L2 caches without triggering any memory operations.
+ *
+ * In MMU V2, L1 -> 16 streams and 64 blocks, maximum 16 blocks per stream
+ * One L1 block has 16 entries, hence points to 16 * 4K pages
+ * L2 -> 16 streams and 32 blocks. 2 blocks per streams
+ * One L2 block maps to 1024 L1 entries, hence points to 4MB address range
+ * 2 blocks per L2 stream means, 1 stream points to 8MB range
+ *
+ * As we need to clear the caches and 8MB being the biggest cache size, we need
+ * to have trash buffer which points to 8MB address range. As these trash
+ * buffers are not used for any memory transactions, we need only the least
+ * amount of physical memory. So we reserve 8MB IOVA address range but only
+ * one page is reserved from physical memory. Each of this 8MB IOVA address
+ * range is then mapped to the same physical memory page.
+ */
+/* One L2 entry maps 1024 L1 entries and one L1 entry per page */
+#define IPU6_MMUV2_L2_RANGE		(1024 * PAGE_SIZE)
+/* Max L2 blocks per stream */
+#define IPU6_MMUV2_MAX_L2_BLOCKS	2
+/* Max L1 blocks per stream */
+#define IPU6_MMUV2_MAX_L1_BLOCKS	16
+#define IPU6_MMUV2_TRASH_RANGE	(IPU6_MMUV2_L2_RANGE * IPU6_MMUV2_MAX_L2_BLOCKS)
+/* Entries per L1 block */
+#define MMUV2_ENTRIES_PER_L1_BLOCK	16
+#define MMUV2_TRASH_L1_BLOCK_OFFSET	(MMUV2_ENTRIES_PER_L1_BLOCK * PAGE_SIZE)
+#define MMUV2_TRASH_L2_BLOCK_OFFSET	IPU6_MMUV2_L2_RANGE
+
+/*
+ * In some of the IPU6 MMUs, there is provision to configure L1 and L2 page
+ * table caches. Both these L1 and L2 caches are divided into multiple sections
+ * called streams. There is maximum 16 streams for both caches. Each of these
+ * sections are subdivided into multiple blocks. When nr_l1streams = 0 and
+ * nr_l2streams = 0, means the MMU is of type MMU_V1 and do not support
+ * L1/L2 page table caches.
+ *
+ * L1 stream per block sizes are configurable and varies per usecase.
+ * L2 has constant block sizes - 2 blocks per stream.
+ *
+ * MMU1 support pre-fetching of the pages to have less cache lookup misses. To
+ * enable the pre-fetching, MMU1 AT (Address Translator) device registers
+ * need to be configured.
+ *
+ * There are four types of memory accesses which requires ZLW configuration.
+ * ZLW(Zero Length Write) is a mechanism to enable VT-d pre-fetching on IOMMU.
+ *
+ * 1. Sequential Access or 1D mode
+ *	Set ZLW_EN -> 1
+ *	set ZLW_PAGE_CROSS_1D -> 1
+ *	Set ZLW_N to "N" pages so that ZLW will be inserte N pages ahead where
+ *		  N is pre-defined and hardcoded in the platform data
+ *	Set ZLW_2D -> 0
+ *
+ * 2. ZLW 2D mode
+ *	Set ZLW_EN -> 1
+ *	set ZLW_PAGE_CROSS_1D -> 1,
+ *	Set ZLW_N -> 0
+ *	Set ZLW_2D -> 1
+ *
+ * 3. ZLW Enable (no 1D or 2D mode)
+ *	Set ZLW_EN -> 1
+ *	set ZLW_PAGE_CROSS_1D -> 0,
+ *	Set ZLW_N -> 0
+ *	Set ZLW_2D -> 0
+ *
+ * 4. ZLW disable
+ *	Set ZLW_EN -> 0
+ *	set ZLW_PAGE_CROSS_1D -> 0,
+ *	Set ZLW_N -> 0
+ *	Set ZLW_2D -> 0
+ *
+ * To configure the ZLW for the above memory access, four registers are
+ * available. Hence to track these four settings, we have the following entries
+ * in the struct ipu6_mmu_hw. Each of these entries are per stream and
+ * available only for the L1 streams.
+ *
+ * a. l1_zlw_en -> To track zlw enabled per stream (ZLW_EN)
+ * b. l1_zlw_1d_mode -> Track 1D mode per stream. ZLW inserted at page boundary
+ * c. l1_ins_zlw_ahead_pages -> to track how advance the ZLW need to be inserted
+ *			Insert ZLW request N pages ahead address.
+ * d. l1_zlw_2d_mode -> To track 2D mode per stream (ZLW_2D)
+ *
+ *
+ * Currently L1/L2 streams, blocks, AT ZLW configurations etc. are pre-defined
+ * as per the usecase specific calculations. Any change to this pre-defined
+ * table has to happen in sync with IPU6 FW.
+ */
+
+struct ipu6_mmu_hw {
+	union {
+		unsigned long offset;
+		void __iomem *base;
+	};
+	u32 info_bits;
+	u8 nr_l1streams;
+	/*
+	 * L1 has variable blocks per stream - total of 64 blocks and maximum of
+	 * 16 blocks per stream. Configurable by using the block start address
+	 * per stream. Block start address is calculated from the block size
+	 */
+	u8 l1_block_sz[IPU6_MMU_MAX_TLB_L1_STREAMS];
+	/* Is ZLW is enabled in each stream */
+	bool l1_zlw_en[IPU6_MMU_MAX_TLB_L1_STREAMS];
+	bool l1_zlw_1d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
+	u8 l1_ins_zlw_ahead_pages[IPU6_MMU_MAX_TLB_L1_STREAMS];
+	bool l1_zlw_2d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
+
+	u32 l1_stream_id_reg_offset;
+	u32 l2_stream_id_reg_offset;
+
+	u8 nr_l2streams;
+	/*
+	 * L2 has fixed 2 blocks per stream. Block address is calculated
+	 * from the block size
+	 */
+	u8 l2_block_sz[IPU6_MMU_MAX_TLB_L2_STREAMS];
+	/* flag to track if WA is needed for successive invalidate HW bug */
+	bool insert_read_before_invalidate;
+};
+
+struct ipu6_mmu_hw_ops {
+	int (*init_hw_data)(struct ipu6_mmu *mmu, struct device *dev,
+			    void __iomem *base);
+	int (*hw_init)(struct ipu6_mmu *mmu);
+	void (*tlb_invalidate)(struct ipu6_mmu *mmu);
+};
+
 struct ipu6_mmu {
 	struct list_head node;
 
-	struct ipu6_mmu_hw *mmu_hw;
+	struct ipu6_mmu_hw *ipu6_mmu_hw;
 	unsigned int nr_mmus;
 	unsigned int mmid;
 
@@ -52,12 +188,13 @@ struct ipu6_mmu {
 	bool ready;
 	spinlock_t ready_lock;	/* Serialize access to bool ready */
 
-	void (*tlb_invalidate)(struct ipu6_mmu *mmu);
+	const struct ipu6_mmu_hw_ops *ops;
 };
 
+extern const struct ipu6_mmu_hw_ops ipu6_mmu_ops;
+
 struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
-			       void __iomem *base, int mmid,
-			       const struct ipu6_hw_variants *hw);
+			       void __iomem *base, int mmid);
 void ipu6_mmu_cleanup(struct ipu6_mmu *mmu);
 int ipu6_mmu_hw_init(struct ipu6_mmu *mmu);
 void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 4af0b068e759..51174cafb1b4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -74,54 +74,6 @@ struct ipu6_cell_program {
 static struct ipu6_isys_internal_pdata isys_ipdata = {
 	.hw_variant = {
 		.offset = IPU6_UNIFIED_OFFSET,
-		.nr_mmus = 3,
-		.mmu_hw = {
-			{
-				.offset = IPU6_ISYS_IOMMU0_OFFSET,
-				.info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
-				.nr_l1streams = 16,
-				.l1_block_sz = {
-					3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
-					1, 1, 1, 1, 1, 1
-				},
-				.nr_l2streams = 16,
-				.l2_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2
-				},
-				.insert_read_before_invalidate = false,
-				.l1_stream_id_reg_offset =
-				IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
-				.l2_stream_id_reg_offset =
-				IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
-			},
-			{
-				.offset = IPU6_ISYS_IOMMU1_OFFSET,
-				.info_bits = 0,
-				.nr_l1streams = 16,
-				.l1_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 1, 1, 4
-				},
-				.nr_l2streams = 16,
-				.l2_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2
-				},
-				.insert_read_before_invalidate = false,
-				.l1_stream_id_reg_offset =
-				IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
-				.l2_stream_id_reg_offset =
-				IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
-			},
-			{
-				.offset = IPU6_ISYS_IOMMUI_OFFSET,
-				.info_bits = 0,
-				.nr_l1streams = 0,
-				.nr_l2streams = 0,
-				.insert_read_before_invalidate = false,
-			},
-		},
 		.cdc_fifos = 3,
 		.cdc_fifo_threshold = {6, 8, 2},
 		.dmem_offset = IPU6_ISYS_DMEM_OFFSET,
@@ -133,78 +85,6 @@ static struct ipu6_isys_internal_pdata isys_ipdata = {
 static struct ipu6_psys_internal_pdata psys_ipdata = {
 	.hw_variant = {
 		.offset = IPU6_UNIFIED_OFFSET,
-		.nr_mmus = 4,
-		.mmu_hw = {
-			{
-				.offset = IPU6_PSYS_IOMMU0_OFFSET,
-				.info_bits =
-				IPU6_INFO_REQUEST_DESTINATION_IOSF,
-				.nr_l1streams = 16,
-				.l1_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2
-				},
-				.nr_l2streams = 16,
-				.l2_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2
-				},
-				.insert_read_before_invalidate = false,
-				.l1_stream_id_reg_offset =
-				IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
-				.l2_stream_id_reg_offset =
-				IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
-			},
-			{
-				.offset = IPU6_PSYS_IOMMU1_OFFSET,
-				.info_bits = 0,
-				.nr_l1streams = 32,
-				.l1_block_sz = {
-					1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 10,
-					5, 4, 14, 6, 4, 14, 6, 4, 8,
-					4, 2, 1, 1, 1, 1, 14
-				},
-				.nr_l2streams = 32,
-				.l2_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2
-				},
-				.insert_read_before_invalidate = false,
-				.l1_stream_id_reg_offset =
-				IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
-				.l2_stream_id_reg_offset =
-				IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
-			},
-			{
-				.offset = IPU6_PSYS_IOMMU1R_OFFSET,
-				.info_bits = 0,
-				.nr_l1streams = 16,
-				.l1_block_sz = {
-					1, 4, 4, 4, 4, 16, 8, 4, 32,
-					16, 16, 2, 2, 2, 1, 12
-				},
-				.nr_l2streams = 16,
-				.l2_block_sz = {
-					2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-					2, 2, 2, 2, 2, 2
-				},
-				.insert_read_before_invalidate = false,
-				.l1_stream_id_reg_offset =
-				IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
-				.l2_stream_id_reg_offset =
-				IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
-			},
-			{
-				.offset = IPU6_PSYS_IOMMUI_OFFSET,
-				.info_bits = 0,
-				.nr_l1streams = 0,
-				.nr_l2streams = 0,
-				.insert_read_before_invalidate = false,
-			},
-		},
 		.dmem_offset = IPU6_PSYS_DMEM_OFFSET,
 	},
 };
@@ -478,7 +358,7 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
 				"ipu6_bus_initialize_device isys failed\n");
 	}
 
-	isys_adev->mmu = ipu6_mmu_init(dev, base, IPU_ISYS, &ipdata->hw_variant);
+	isys_adev->mmu = ipu6_mmu_init(dev, base, IPU_ISYS);
 	if (IS_ERR(isys_adev->mmu)) {
 		put_device(&isys_adev->auxdev.dev);
 		return dev_err_cast_probe(dev, isys_adev->mmu,
@@ -518,8 +398,7 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
 				"ipu6_bus_initialize_device psys failed\n");
 	}
 
-	psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, IPU_PSYS,
-				       &ipdata->hw_variant);
+	psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, IPU_PSYS);
 	if (IS_ERR(psys_adev->mmu)) {
 		put_device(&psys_adev->auxdev.dev);
 		return dev_err_cast_probe(&pdev->dev, psys_adev->mmu,
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index a14b067f169f..debd571b6f6d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -74,6 +74,7 @@ struct ipu6_device {
 
 #define IPU_PSYS	0
 #define IPU_ISYS	1
+#define IPU_SUBSYS_NUM	2
 
 #define IPU6_ISYS_NAME "isys"
 #define IPU6_PSYS_NAME "psys"
@@ -121,135 +122,6 @@ struct ipu6_device {
 #define IPU6_BTRS_ARB_STALL_MODE_VC1	\
 			IPU6_BTRS_ARB_MODE_TYPE_REARB
 
-/*
- * MMU Invalidation HW bug workaround by ZLW mechanism
- *
- * Old IPU6 MMUV2 has a bug in the invalidation mechanism which might result in
- * wrong translation or replication of the translation. This will cause data
- * corruption. So we cannot directly use the MMU V2 invalidation registers
- * to invalidate the MMU. Instead, whenever an invalidate is called, we need to
- * clear the TLB by evicting all the valid translations by filling it with trash
- * buffer (which is guaranteed not to be used by any other processes). ZLW is
- * used to fill the L1 and L2 caches with the trash buffer translations. ZLW
- * or Zero length write, is pre-fetch mechanism to pre-fetch the pages in
- * advance to the L1 and L2 caches without triggering any memory operations.
- *
- * In MMU V2, L1 -> 16 streams and 64 blocks, maximum 16 blocks per stream
- * One L1 block has 16 entries, hence points to 16 * 4K pages
- * L2 -> 16 streams and 32 blocks. 2 blocks per streams
- * One L2 block maps to 1024 L1 entries, hence points to 4MB address range
- * 2 blocks per L2 stream means, 1 stream points to 8MB range
- *
- * As we need to clear the caches and 8MB being the biggest cache size, we need
- * to have trash buffer which points to 8MB address range. As these trash
- * buffers are not used for any memory transactions, we need only the least
- * amount of physical memory. So we reserve 8MB IOVA address range but only
- * one page is reserved from physical memory. Each of this 8MB IOVA address
- * range is then mapped to the same physical memory page.
- */
-/* One L2 entry maps 1024 L1 entries and one L1 entry per page */
-#define IPU6_MMUV2_L2_RANGE		(1024 * PAGE_SIZE)
-/* Max L2 blocks per stream */
-#define IPU6_MMUV2_MAX_L2_BLOCKS	2
-/* Max L1 blocks per stream */
-#define IPU6_MMUV2_MAX_L1_BLOCKS	16
-#define IPU6_MMUV2_TRASH_RANGE	(IPU6_MMUV2_L2_RANGE * IPU6_MMUV2_MAX_L2_BLOCKS)
-/* Entries per L1 block */
-#define MMUV2_ENTRIES_PER_L1_BLOCK	16
-#define MMUV2_TRASH_L1_BLOCK_OFFSET	(MMUV2_ENTRIES_PER_L1_BLOCK * PAGE_SIZE)
-#define MMUV2_TRASH_L2_BLOCK_OFFSET	IPU6_MMUV2_L2_RANGE
-
-/*
- * In some of the IPU6 MMUs, there is provision to configure L1 and L2 page
- * table caches. Both these L1 and L2 caches are divided into multiple sections
- * called streams. There is maximum 16 streams for both caches. Each of these
- * sections are subdivided into multiple blocks. When nr_l1streams = 0 and
- * nr_l2streams = 0, means the MMU is of type MMU_V1 and do not support
- * L1/L2 page table caches.
- *
- * L1 stream per block sizes are configurable and varies per usecase.
- * L2 has constant block sizes - 2 blocks per stream.
- *
- * MMU1 support pre-fetching of the pages to have less cache lookup misses. To
- * enable the pre-fetching, MMU1 AT (Address Translator) device registers
- * need to be configured.
- *
- * There are four types of memory accesses which requires ZLW configuration.
- * ZLW(Zero Length Write) is a mechanism to enable VT-d pre-fetching on IOMMU.
- *
- * 1. Sequential Access or 1D mode
- *	Set ZLW_EN -> 1
- *	set ZLW_PAGE_CROSS_1D -> 1
- *	Set ZLW_N to "N" pages so that ZLW will be inserte N pages ahead where
- *		  N is pre-defined and hardcoded in the platform data
- *	Set ZLW_2D -> 0
- *
- * 2. ZLW 2D mode
- *	Set ZLW_EN -> 1
- *	set ZLW_PAGE_CROSS_1D -> 1,
- *	Set ZLW_N -> 0
- *	Set ZLW_2D -> 1
- *
- * 3. ZLW Enable (no 1D or 2D mode)
- *	Set ZLW_EN -> 1
- *	set ZLW_PAGE_CROSS_1D -> 0,
- *	Set ZLW_N -> 0
- *	Set ZLW_2D -> 0
- *
- * 4. ZLW disable
- *	Set ZLW_EN -> 0
- *	set ZLW_PAGE_CROSS_1D -> 0,
- *	Set ZLW_N -> 0
- *	Set ZLW_2D -> 0
- *
- * To configure the ZLW for the above memory access, four registers are
- * available. Hence to track these four settings, we have the following entries
- * in the struct ipu6_mmu_hw. Each of these entries are per stream and
- * available only for the L1 streams.
- *
- * a. l1_zlw_en -> To track zlw enabled per stream (ZLW_EN)
- * b. l1_zlw_1d_mode -> Track 1D mode per stream. ZLW inserted at page boundary
- * c. l1_ins_zlw_ahead_pages -> to track how advance the ZLW need to be inserted
- *			Insert ZLW request N pages ahead address.
- * d. l1_zlw_2d_mode -> To track 2D mode per stream (ZLW_2D)
- *
- *
- * Currently L1/L2 streams, blocks, AT ZLW configurations etc. are pre-defined
- * as per the usecase specific calculations. Any change to this pre-defined
- * table has to happen in sync with IPU6 FW.
- */
-struct ipu6_mmu_hw {
-	union {
-		unsigned long offset;
-		void __iomem *base;
-	};
-	u32 info_bits;
-	u8 nr_l1streams;
-	/*
-	 * L1 has variable blocks per stream - total of 64 blocks and maximum of
-	 * 16 blocks per stream. Configurable by using the block start address
-	 * per stream. Block start address is calculated from the block size
-	 */
-	u8 l1_block_sz[IPU6_MMU_MAX_TLB_L1_STREAMS];
-	/* Is ZLW is enabled in each stream */
-	bool l1_zlw_en[IPU6_MMU_MAX_TLB_L1_STREAMS];
-	bool l1_zlw_1d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
-	u8 l1_ins_zlw_ahead_pages[IPU6_MMU_MAX_TLB_L1_STREAMS];
-	bool l1_zlw_2d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
-
-	u32 l1_stream_id_reg_offset;
-	u32 l2_stream_id_reg_offset;
-
-	u8 nr_l2streams;
-	/*
-	 * L2 has fixed 2 blocks per stream. Block address is calculated
-	 * from the block size
-	 */
-	u8 l2_block_sz[IPU6_MMU_MAX_TLB_L2_STREAMS];
-	/* flag to track if WA is needed for successive invalidate HW bug */
-	bool insert_read_before_invalidate;
-};
-
 struct ipu6_isys_csi2_pdata {
 	void __iomem *base;
 };
@@ -274,8 +146,6 @@ struct ipu6_isys_internal_tpg_pdata {
 
 struct ipu6_hw_variants {
 	unsigned long offset;
-	u32 nr_mmus;
-	struct ipu6_mmu_hw mmu_hw[IPU6_MMU_MAX_DEVICES];
 	u8 cdc_fifos;
 	u8 cdc_fifo_threshold[IPU6_MAX_VC_IOSF_PORTS];
 	u32 dmem_offset;
-- 
2.55.0


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

* [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (12 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling Antti Laakso
                   ` (29 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 mmu have similar page tables as ipu6, but e.g. register interface
is different. Add own driver handling ipu7 mmu specifics.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/Makefile      |   1 +
 drivers/media/pci/intel/ipu6/ipu6-mmu.c    |  14 +-
 drivers/media/pci/intel/ipu6/ipu6-mmu.h    |   8 +-
 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c | 599 +++++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h | 155 ++++++
 5 files changed, 773 insertions(+), 4 deletions(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h

diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 2106ab84acde..c0daf0995b22 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -5,6 +5,7 @@ intel-ipu6-y			:= ipu6.o \
 				ipu6-dma.o \
 				ipu6-mmu.o \
 				ipu6-mmu-hw.o \
+				ipu7-mmu-hw.o \
 				ipu6-buttress.o \
 				ipu6-cpd.o \
 				ipu6-fw-com.o
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 98ac59d00b78..243d438786ba 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -473,7 +473,12 @@ static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp)
 	if (!mmu_info)
 		return NULL;
 
-	mmu_info->aperture_start = 0;
+	if (IS_IPU7(isp))
+		mmu_info->aperture_start = isp->secure_mode ?
+			IPU7_FW_CODE_REGION_END : IPU7_FW_CODE_REGION_START;
+	else
+		mmu_info->aperture_start = 0;
+
 	mmu_info->aperture_end =
 		(dma_addr_t)DMA_BIT_MASK(isp->secure_mode ?
 					 IPU6_MMU_ADDR_BITS :
@@ -532,6 +537,7 @@ EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_cleanup, "INTEL_IPU6");
 static struct ipu6_dma_mapping *alloc_dma_mapping(struct ipu6_device *isp)
 {
 	struct ipu6_dma_mapping *dmap;
+	unsigned long base_pfn;
 
 	dmap = kzalloc_obj(*dmap);
 	if (!dmap)
@@ -543,7 +549,9 @@ static struct ipu6_dma_mapping *alloc_dma_mapping(struct ipu6_device *isp)
 		return NULL;
 	}
 
-	init_iova_domain(&dmap->iovad, SZ_4K, 1);
+	base_pfn = max_t(unsigned long, 1,
+			 PFN_DOWN(dmap->mmu_info->aperture_start));
+	init_iova_domain(&dmap->iovad, SZ_4K, base_pfn);
 	dmap->mmu_info->dmap = dmap;
 
 	dev_dbg(&isp->pdev->dev, "alloc mapping\n");
@@ -676,7 +684,7 @@ struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
 	if (!mmu)
 		return ERR_PTR(-ENOMEM);
 
-	mmu->ops = &ipu6_mmu_ops;
+	mmu->ops = IS_IPU7(isp) ? &ipu7_mmu_ops : &ipu6_mmu_ops;
 	mmu->mmid = mmid;
 	mmu->ready = false;
 	INIT_LIST_HEAD(&mmu->vma_list);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index a741f1c0e284..44880478d242 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -8,6 +8,8 @@
 #include <linux/spinlock_types.h>
 #include <linux/types.h>
 
+#include "ipu7-mmu-hw.h"
+
 struct device;
 struct page;
 
@@ -171,7 +173,10 @@ struct ipu6_mmu_hw_ops {
 struct ipu6_mmu {
 	struct list_head node;
 
-	struct ipu6_mmu_hw *ipu6_mmu_hw;
+	union {
+		struct ipu6_mmu_hw *ipu6_mmu_hw;
+		struct ipu7_mmu_hw *ipu7_mmu_hw;
+	};
 	unsigned int nr_mmus;
 	unsigned int mmid;
 
@@ -192,6 +197,7 @@ struct ipu6_mmu {
 };
 
 extern const struct ipu6_mmu_hw_ops ipu6_mmu_ops;
+extern const struct ipu6_mmu_hw_ops ipu7_mmu_ops;
 
 struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
 			       void __iomem *base, int mmid);
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
new file mode 100644
index 000000000000..3cd9a818733c
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
@@ -0,0 +1,599 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include <linux/types.h>
+#include <linux/iopoll.h>
+
+#include "ipu6.h"
+#include "ipu6-dma.h"
+#include "ipu6-mmu.h"
+
+static struct ipu7_mmu_hw ipu7_isys_mmu_hwdata[] = {
+	{
+		.offset = IPU7_IS_MMU_FW_RD_OFFSET,
+		.zlx_offset = IPU7_IS_ZLX_UC_RD_OFFSET,
+		.uao_offset = IPU7_IS_UAO_UC_RD_OFFSET,
+		.info_bits = 0x20006701,
+		.refill = 0x00002726,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_IS_MMU_FW_RD_L1_BLOCKNR_REG,
+		.l2_block = IPU7_IS_MMU_FW_RD_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_IS_MMU_FW_RD_STREAM_NUM,
+		.nr_l2streams = IPU7_IS_MMU_FW_RD_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x8, 0xa },
+		.l2_block_sz = { 0x0, 0x2, 0x4 },
+		.zlx_nr = IPU7_IS_ZLX_UC_RD_NUM,
+		.zlx_axi_pool = { 0x00000f30 },
+		.zlx_en = { 0, 0, 0, 0 },
+		.zlx_conf = { 0x0, 0x0, 0x0, 0x0 },
+		.uao_p_num = IPU7_IS_UAO_UC_RD_PLANENUM,
+		.uao_p2tlb = { 0x61, 0x64, 0x65 },
+	},
+	{
+		.offset = IPU7_IS_MMU_FW_WR_OFFSET,
+		.zlx_offset = IPU7_IS_ZLX_UC_WR_OFFSET,
+		.uao_offset = IPU7_IS_UAO_UC_WR_OFFSET,
+		.info_bits = 0x20006801,
+		.refill = 0x00002524,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_IS_MMU_FW_WR_L1_BLOCKNR_REG,
+		.l2_block = IPU7_IS_MMU_FW_WR_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_IS_MMU_FW_WR_STREAM_NUM,
+		.nr_l2streams = IPU7_IS_MMU_FW_WR_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x8, 0xa },
+		.l2_block_sz = { 0x0, 0x2, 0x4	},
+		.zlx_nr = IPU7_IS_ZLX_UC_WR_NUM,
+		.zlx_axi_pool = { 0x00000f20 },
+		.zlx_en = { 0, 1, 1, 0 },
+		.zlx_conf = { 0x0, 0x00010101, 0x00010101 },
+		.uao_p_num = IPU7_IS_UAO_UC_WR_PLANENUM,
+		.uao_p2tlb = { 0x61, 0x62, 0x63 },
+	},
+	{
+		.offset = IPU7_IS_MMU_M0_OFFSET,
+		.zlx_offset = IPU7_IS_ZLX_M0_OFFSET,
+		.uao_offset = IPU7_IS_UAO_M0_WR_OFFSET,
+		.info_bits = 0x20006601,
+		.refill = 0x00002120,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_IS_MMU_M0_L1_BLOCKNR_REG,
+		.l2_block = IPU7_IS_MMU_M0_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_IS_MMU_M0_STREAM_NUM,
+		.nr_l2streams = IPU7_IS_MMU_M0_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x3, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10 },
+		.l2_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe },
+		.zlx_nr = IPU7_IS_ZLX_M0_NUM,
+		.zlx_axi_pool = { 0x00000f10 },
+		.zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1 },
+		.zlx_conf = {
+			0x00010103,
+			0x00010103,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+		},
+		.uao_p_num = IPU7_IS_UAO_M0_WR_PLANENUM,
+		.uao_p2tlb = {
+			0x00000049,
+			0x0000004a,
+			0x0000004b,
+			0x0000004c,
+			0x0000004d,
+			0x0000004e,
+			0x0000004f,
+			0x00000050,
+		},
+	},
+	{
+		.offset = IPU7_IS_MMU_M1_OFFSET,
+		.zlx_offset = IPU7_IS_ZLX_M1_OFFSET,
+		.uao_offset = IPU7_IS_UAO_M1_WR_OFFSET,
+		.info_bits = 0x20006901,
+		.refill = 0x00002322,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_IS_MMU_M1_L1_BLOCKNR_REG,
+		.l2_block = IPU7_IS_MMU_M1_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_IS_MMU_M1_STREAM_NUM,
+		.nr_l2streams = IPU7_IS_MMU_M1_STREAM_NUM,
+		.l1_block_sz = {
+			0x0, 0x3, 0x6, 0x9, 0xc,
+			0xe, 0x10, 0x12, 0x14, 0x16,
+			0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22,
+		},
+		.l2_block_sz = {
+			0x0, 0x2, 0x4, 0x6, 0x8,
+			0xa, 0xc, 0xe, 0x10, 0x12,
+			0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+		},
+		.zlx_nr = IPU7_IS_ZLX_M1_NUM,
+		.zlx_axi_pool = { 0x00000f20 },
+		.zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1,
+			    1, 1, 1, 1, 1, 1, 1, 1,
+		},
+		.zlx_conf = {
+			0x00010103,
+			0x00010103,
+			0x00010103,
+			0x00010103,
+			0x00010103,
+			0x00010103,
+			0x00010103,
+			0x00010103,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+		},
+		.uao_p_num = IPU7_IS_UAO_M1_WR_PLANENUM,
+		.uao_p2tlb = {
+			0x00000051,
+			0x00000052,
+			0x00000053,
+			0x00000054,
+			0x00000055,
+			0x00000056,
+			0x00000057,
+			0x00000058,
+			0x00000059,
+			0x0000005a,
+			0x0000005b,
+			0x0000005c,
+			0x0000005d,
+			0x0000005e,
+			0x0000005f,
+			0x00000060,
+		},
+	},
+};
+
+static struct ipu7_mmu_hw ipu7_psys_mmu_hwdata[] = {
+	{
+		.name = "PS_FW_RD",
+		.offset = IPU7_PS_MMU_FW_RD_OFFSET,
+		.zlx_offset = IPU7_PS_ZLX_FW_RD_OFFSET,
+		.uao_offset = IPU7_PS_UAO_FW_RD_OFFSET,
+		.info_bits = 0x20004801,
+		.refill = 0x00002726,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_PS_MMU_FW_RD_L1_BLOCKNR_REG,
+		.l2_block = IPU7_PS_MMU_FW_RD_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_PS_MMU_FW_RD_STREAM_NUM,
+		.nr_l2streams = IPU7_PS_MMU_FW_RD_STREAM_NUM,
+		.l1_block_sz = {
+			0, 0x8, 0xa, 0xc, 0xd,
+			0xf, 0x11, 0x12, 0x13, 0x14,
+			0x16, 0x18, 0x19, 0x1a, 0x1a,
+			0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+		},
+		.l2_block_sz = {
+			0x0, 0x2, 0x4, 0x6, 0x8,
+			0xa, 0xc, 0xe, 0x10, 0x12,
+			0x14, 0x16, 0x18, 0x1a, 0x1c,
+			0x1e, 0x20, 0x22, 0x24, 0x26,
+		},
+		.zlx_nr = IPU7_PS_ZLX_FW_RD_NUM,
+		.zlx_axi_pool = { 0x00000f30 },
+		.zlx_en = {
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+		},
+		.zlx_conf = { 0x0 },
+		.uao_p_num = IPU7_PS_UAO_FW_RD_PLANENUM,
+		.uao_p2tlb = {
+			0x00000036,
+			0x0000003d,
+			0x0000003e,
+			0x00000039,
+			0x0000003f,
+			0x00000040,
+			0x00000041,
+			0x0000003a,
+			0x0000003b,
+			0x00000042,
+			0x00000043,
+			0x00000044,
+			0x0000003c,
+		},
+	},
+	{
+		.offset = IPU7_PS_MMU_FW_WR_OFFSET,
+		.zlx_offset = IPU7_PS_ZLX_FW_WR_OFFSET,
+		.uao_offset = IPU7_PS_UAO_FW_WR_OFFSET,
+		.info_bits = 0x20004601,
+		.refill = 0x00002322,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_PS_MMU_FW_WR_L1_BLOCKNR_REG,
+		.l2_block = IPU7_PS_MMU_FW_WR_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_PS_MMU_FW_WR_STREAM_NUM,
+		.nr_l2streams = IPU7_PS_MMU_FW_WR_STREAM_NUM,
+		.l1_block_sz = {
+			0, 0x8, 0xa, 0xc, 0xd,
+			0xe, 0xf, 0x10, 0x10, 0x10,
+		},
+		.l2_block_sz = {
+			0x0, 0x2, 0x4, 0x6, 0x8,
+			0xa, 0xc, 0xe, 0x10, 0x12,
+		},
+		.zlx_nr = IPU7_PS_ZLX_FW_WR_NUM,
+		.zlx_axi_pool = { 0x00000f20 },
+		.zlx_en = { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
+		.zlx_conf = { 0x0, 0x00010101, 0x00010101 },
+		.uao_p_num = IPU7_PS_UAO_FW_WR_PLANENUM,
+		.uao_p2tlb = { 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c },
+	},
+	{
+		.offset = IPU7_PS_MMU_SRT_RD_OFFSET,
+		.zlx_offset = IPU7_PS_ZLX_DATA_RD_OFFSET,
+		.uao_offset = IPU7_PS_UAO_SRT_RD_OFFSET,
+		.info_bits = 0x20004701,
+		.refill = 0x00002120,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_PS_MMU_SRT_RD_L1_BLOCKNR_REG,
+		.l2_block = IPU7_PS_MMU_SRT_RD_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_PS_MMU_SRT_RD_STREAM_NUM,
+		.nr_l2streams = IPU7_PS_MMU_SRT_RD_STREAM_NUM,
+		.l1_block_sz = {
+			0x0, 0x4, 0x6, 0x8, 0xb,
+			0xd, 0xf, 0x11, 0x13, 0x15,
+			0x17, 0x23, 0x2b, 0x37, 0x3f,
+			0x41, 0x43, 0x44, 0x45, 0x46,
+			0x47, 0x48, 0x49, 0x4a, 0x4b,
+			0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+			0x51, 0x52, 0x53, 0x55, 0x57,
+			0x59, 0x5b, 0x5d, 0x5f, 0x61,
+		},
+		.l2_block_sz = {
+			0x0, 0x2, 0x4, 0x6, 0x8,
+			0xa, 0xc, 0xe, 0x10, 0x12,
+			0x14, 0x16, 0x18, 0x1a, 0x1c,
+			0x1e, 0x20, 0x22, 0x24, 0x26,
+			0x28, 0x2a, 0x2c, 0x2e, 0x30,
+			0x32, 0x34, 0x36, 0x38, 0x3a,
+			0x3c, 0x3e, 0x40, 0x42, 0x44,
+			0x46, 0x48, 0x4a, 0x4c, 0x4e,
+		},
+		.zlx_nr = IPU7_PS_ZLX_DATA_RD_NUM,
+		.zlx_axi_pool = { 0x00000f30 },
+		.zlx_en = {
+			1, 1, 1, 1, 1, 1, 1, 1,
+			1, 1, 1, 1, 1, 1, 1, 1,
+			0, 0, 0, 0, 0, 0, 0, 0,
+			0, 0, 0, 0, 0, 0, 0, 0,
+		},
+		.zlx_conf = {
+			0x00030303,
+			0x00010101,
+			0x00010101,
+			0x00030202,
+			0x00010101,
+			0x00010101,
+			0x00010101,
+			0x00030800,
+			0x00030500,
+			0x00020101,
+			0x00042000,
+			0x00031000,
+			0x00042000,
+			0x00031000,
+			0x00020400,
+			0x00010101,
+		},
+		.uao_p_num = IPU7_PS_UAO_SRT_RD_PLANENUM,
+		.uao_p2tlb = {
+			0x00000022,
+			0x00000023,
+			0x00000024,
+			0x00000025,
+			0x00000026,
+			0x00000027,
+			0x00000028,
+			0x00000029,
+			0x0000002a,
+			0x0000002b,
+			0x0000002c,
+			0x0000002d,
+			0x0000002e,
+			0x0000002f,
+			0x00000030,
+			0x00000031,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0000001e,
+			0x0000001f,
+			0x00000020,
+			0x00000021,
+			0x00000032,
+			0x00000033,
+			0x00000034,
+			0x00000035,
+		},
+	},
+	{
+		.offset = IPU7_PS_MMU_SRT_WR_OFFSET,
+		.zlx_offset = IPU7_PS_ZLX_DATA_WR_OFFSET,
+		.uao_offset = IPU7_PS_UAO_SRT_WR_OFFSET,
+		.info_bits = 0x20004501,
+		.refill = 0x00002120,
+		.collapse_en_bitmap = 0x0,
+		.l1_block = IPU7_PS_MMU_SRT_WR_L1_BLOCKNR_REG,
+		.l2_block = IPU7_PS_MMU_SRT_WR_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7_PS_MMU_SRT_WR_STREAM_NUM,
+		.nr_l2streams = IPU7_PS_MMU_SRT_WR_STREAM_NUM,
+		.l1_block_sz = {
+			0x0, 0x2, 0x6, 0xa, 0xc,
+			0xe, 0x10, 0x12, 0x14, 0x16,
+			0x18, 0x1a, 0x1c, 0x1e, 0x20,
+			0x22, 0x24, 0x26, 0x32, 0x3a,
+			0x3c, 0x3e, 0x4a, 0x52, 0x58,
+			0x64, 0x6c, 0x72, 0x7e, 0x86,
+			0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+			0x91, 0x92, 0x94, 0x96, 0x98,
+		},
+		.l2_block_sz = {
+			0x0, 0x2, 0x4, 0x6, 0x8,
+			0xa, 0xc, 0xe, 0x10, 0x12,
+			0x14, 0x16, 0x18, 0x1a, 0x1c,
+			0x1e, 0x20, 0x22, 0x24, 0x26,
+			0x28, 0x2a, 0x2c, 0x2e, 0x30,
+			0x32, 0x34, 0x36, 0x38, 0x3a,
+			0x3c, 0x3e, 0x40, 0x42, 0x44,
+			0x46, 0x48, 0x4a, 0x4c, 0x4e,
+		},
+		.zlx_nr = IPU7_PS_ZLX_DATA_WR_NUM,
+		.zlx_axi_pool = { 0x00000f50 },
+		.zlx_en = {
+			1, 1, 1, 1, 1, 1, 1, 1,
+			0, 0, 1, 1, 1, 1, 1, 1,
+			1, 1, 1, 1, 1, 1, 1, 1,
+			1, 1, 1, 1, 1, 1, 0, 0,
+		},
+		.zlx_conf = {
+			0x00010102,
+			0x00030103,
+			0x00030103,
+			0x00010101,
+			0x00010101,
+			0x00030101,
+			0x00010101,
+			0x38010101,
+			0x0,
+			0x0,
+			0x38010101,
+			0x38010101,
+			0x38010101,
+			0x38010101,
+			0x38010101,
+			0x38010101,
+			0x00010101,
+			0x00042000,
+			0x00031000,
+			0x00010101,
+			0x00010101,
+			0x00042000,
+			0x00031000,
+			0x00031000,
+			0x00042000,
+			0x00031000,
+			0x00031000,
+			0x00042000,
+			0x00031000,
+			0x00031000,
+			0x0,
+			0x0,
+		},
+		.uao_p_num = IPU7_PS_UAO_SRT_WR_PLANENUM,
+		.uao_p2tlb = {
+			0x00000000,
+			0x00000001,
+			0x00000002,
+			0x00000003,
+			0x00000004,
+			0x00000005,
+			0x00000006,
+			0x00000007,
+			0x00000008,
+			0x00000009,
+			0x0000000a,
+			0x0000000b,
+			0x0000000c,
+			0x0000000d,
+			0x0000000e,
+			0x0000000f,
+			0x00000010,
+			0x00000011,
+			0x00000012,
+			0x00000013,
+			0x00000014,
+			0x00000015,
+			0x00000016,
+			0x00000017,
+			0x00000018,
+			0x00000019,
+			0x0000001a,
+			0x0000001b,
+			0x0000001c,
+			0x0000001d,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0000001e,
+			0x0000001f,
+			0x00000020,
+			0x00000021,
+		},
+	},
+};
+
+static const struct ipu7_mmu_hwdata ipu7_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
+	[IPU_PSYS] = {
+		.hwdata = ipu7_psys_mmu_hwdata,
+		.nr_mmus = ARRAY_SIZE(ipu7_psys_mmu_hwdata),
+	},
+	[IPU_ISYS] = {
+		.hwdata = ipu7_isys_mmu_hwdata,
+		.nr_mmus = ARRAY_SIZE(ipu7_isys_mmu_hwdata),
+	},
+};
+
+static void __ipu7_tlb_invalidate(struct ipu6_mmu *mmu)
+{
+	struct ipu7_mmu_hw *mmu_hw = mmu->ipu7_mmu_hw;
+	unsigned long flags;
+	unsigned int i;
+	int ret;
+	u32 val;
+
+	spin_lock_irqsave(&mmu->ready_lock, flags);
+	if (!mmu->ready) {
+		spin_unlock_irqrestore(&mmu->ready_lock, flags);
+		return;
+	}
+
+	for (i = 0; i < mmu->nr_mmus; i++) {
+		writel(0xffffffffU, mmu_hw[i].base +
+		       IPU7_MMU_REG_INVALIDATE_0);
+
+		/* Need check with HW, use l1streams or l2streams */
+		if (mmu_hw[i].nr_l2streams > 32)
+			writel(0xffffffffU, mmu_hw[i].base +
+			       IPU7_MMU_REG_INVALIDATE_1);
+
+		/*
+		 * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
+		 * When the actual MMIO write reaches the IPU TLB Invalidate
+		 * register, wmb() will force the TLB invalidate out if the CPU
+		 * attempts to update the IOMMU page table (or sooner).
+		 */
+		wmb();
+
+		/* wait invalidation done */
+		ret = readl_poll_timeout_atomic(mmu_hw[i].base +
+						IPU7_MMU_REG_INVALIDATION_STATUS,
+						val, !(val & 0x1U), 500,
+						IPU7_MMU_TLB_INVALIDATE_TIMEOUT);
+		if (ret)
+			dev_err(mmu->dev, "MMU[%u] TLB invalidate failed\n", i);
+	}
+
+	spin_unlock_irqrestore(&mmu->ready_lock, flags);
+}
+
+static int __ipu7_mmu_hw_init(struct ipu6_mmu *mmu)
+{
+	struct ipu6_mmu_info *mmu_info;
+	struct ipu7_mmu_hw *mmu_hw = mmu->ipu7_mmu_hw;
+	unsigned int i, j;
+
+	mmu_info = mmu->dmap->mmu_info;
+	for (i = 0; i < mmu->nr_mmus; i++) {
+		/* Write page table address per MMU */
+		writel((phys_addr_t)mmu_info->l1_pt_dma,
+		       mmu_hw[i].base + IPU7_MMU_REG_PAGE_TABLE_BASE_ADDR);
+
+		/* Set info bits and axi_refill per MMU */
+		writel(mmu_hw[i].info_bits,
+		       mmu_hw[i].base + IPU7_MMU_REG_USER_INFO_BITS);
+		writel(mmu_hw[i].refill, mmu_hw[i].base + IPU7_MMU_REG_AXI_REFILL_IF_ID);
+		writel(mmu_hw[i].collapse_en_bitmap,
+		       mmu_hw[i].base + IPU7_MMU_REG_COLLAPSE_ENABLE_BITMAP);
+
+		if (mmu_hw[i].at_sp_arb_cfg)
+			writel(mmu_hw[i].at_sp_arb_cfg,
+			       mmu_hw[i].base + IPU7_MMU_REG_AT_SP_ARB_CFG);
+
+		/* Default irq configuration */
+		writel(0x3ff, mmu_hw[i].base + IPU7_MMU_REG_IRQ_MASK);
+		writel(0x3ff, mmu_hw[i].base + IPU7_MMU_REG_IRQ_ENABLE);
+
+		/* Configure MMU TLB stream configuration for L1/L2 */
+		for (j = 0; j < mmu_hw[i].nr_l1streams; j++) {
+			writel(mmu_hw[i].l1_block_sz[j], mmu_hw[i].base +
+			       mmu_hw[i].l1_block + 4U * j);
+		}
+
+		for (j = 0; j < mmu_hw[i].nr_l2streams; j++) {
+			writel(mmu_hw[i].l2_block_sz[j], mmu_hw[i].base +
+			       mmu_hw[i].l2_block + 4U * j);
+		}
+
+		for (j = 0; j < mmu_hw[i].uao_p_num; j++) {
+			if (!mmu_hw[i].uao_p2tlb[j])
+				continue;
+			writel(mmu_hw[i].uao_p2tlb[j], mmu_hw[i].uao_base + 4U * j);
+		}
+	}
+
+	for (i = 0; i < mmu->nr_mmus; i++) {
+		for (j = 0; j < IPU7_ZLX_POOL_NUM; j++) {
+			if (!mmu_hw[i].zlx_axi_pool[j])
+				continue;
+			writel(mmu_hw[i].zlx_axi_pool[j],
+			       mmu_hw[i].zlx_base + IPU7_ZLX_REG_AXI_POOL + j * 0x4U);
+		}
+
+		for (j = 0; j < mmu_hw[i].zlx_nr; j++) {
+			if (!mmu_hw[i].zlx_conf[j])
+				continue;
+
+			writel(mmu_hw[i].zlx_conf[j],
+			       mmu_hw[i].zlx_base + IPU7_ZLX_REG_CONF + j * 0x8U);
+		}
+
+		for (j = 0; j < mmu_hw[i].zlx_nr; j++) {
+			if (!mmu_hw[i].zlx_en[j])
+				continue;
+
+			writel(mmu_hw[i].zlx_en[j],
+			       mmu_hw[i].zlx_base + IPU7_ZLX_REG_EN + j * 0x8U);
+		}
+	}
+
+	return 0;
+}
+
+static int __ipu7_mmu_init_hw_data(struct ipu6_mmu *mmu, struct device *dev,
+				   void __iomem *base)
+{
+	const struct ipu7_mmu_hwdata *lookup = ipu7_mmu_hwdata_lookup;
+	struct ipu7_mmu_hw *mmu_hw, *src;
+	unsigned int i, nr_mmus;
+
+	if (mmu->mmid >= IPU_SUBSYS_NUM)
+		return -EINVAL;
+
+	src = lookup[mmu->mmid].hwdata;
+	nr_mmus = lookup[mmu->mmid].nr_mmus;
+
+	mmu_hw = devm_kcalloc(dev, nr_mmus, sizeof(*mmu_hw), GFP_KERNEL);
+	if (!mmu_hw)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_mmus; i++) {
+		if (src[i].nr_l1streams > IPU7_MMU_MAX_TLB_L1_STREAMS ||
+		    src[i].nr_l2streams > IPU7_MMU_MAX_TLB_L2_STREAMS)
+			return -EINVAL;
+
+		mmu_hw[i] = src[i];
+		mmu_hw[i].base = base + src[i].offset;
+		mmu_hw[i].zlx_base = base + src[i].zlx_offset;
+		mmu_hw[i].uao_base = base + src[i].uao_offset;
+	}
+
+	mmu->nr_mmus = nr_mmus;
+	mmu->ipu7_mmu_hw = mmu_hw;
+
+	return 0;
+}
+
+const struct ipu6_mmu_hw_ops ipu7_mmu_ops = {
+	.init_hw_data = __ipu7_mmu_init_hw_data,
+	.hw_init = __ipu7_mmu_hw_init,
+	.tlb_invalidate = __ipu7_tlb_invalidate,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
new file mode 100644
index 000000000000..68663057138a
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_MMU_HW_H
+#define IPU7_MMU_HW_H
+
+#define IPU7_MMU_REG_IRQ_MASK			0x2c
+#define IPU7_MMU_REG_IRQ_ENABLE			0x30
+#define IPU7_MMU_REG_PAGE_TABLE_BASE_ADDR	0x08
+#define IPU7_MMU_REG_USER_INFO_BITS		0x0c
+#define IPU7_MMU_REG_AXI_REFILL_IF_ID		0x10
+#define IPU7_MMU_REG_COLLAPSE_ENABLE_BITMAP	0x18
+#define IPU7_MMU_REG_AT_SP_ARB_CFG		0x20
+
+#define IPU7_ZLX_REG_AXI_POOL			0x0
+#define IPU7_ZLX_REG_EN				0x20
+#define IPU7_ZLX_REG_CONF			0x24
+#define IPU7_ZLX_POOL_NUM			8U
+
+#define IPU7_MMU_MAX_TLB_L1_STREAMS		40U
+#define IPU7_MMU_MAX_TLB_L2_STREAMS		40U
+#define IPU7_UAO_PLANE_MAX_NUM			64U
+#define IPU7_ZLX_MAX_NUM			32U
+
+#define IPU7_MMU_REG_INVALIDATE_0		0x00
+#define IPU7_MMU_REG_INVALIDATE_1		0x04
+#define IPU7_MMU_REG_INVALIDATION_STATUS	0x24
+#define IPU7_MMU_TLB_INVALIDATE_TIMEOUT		2000
+
+#define IPU7_FW_CODE_REGION_SIZE	0x1000000 /* 16MB */
+#define IPU7_FW_CODE_REGION_START	0x4000000 /* 64MB */
+#define IPU7_FW_CODE_REGION_END		(IPU7_FW_CODE_REGION_START +	\
+					 IPU7_FW_CODE_REGION_SIZE) /* 80MB */
+
+#define IPU7_IS_MMU_FW_RD_OFFSET		0x274000
+#define IPU7_IS_MMU_FW_RD_STREAM_NUM		3
+#define IPU7_IS_MMU_FW_RD_L1_BLOCKNR_REG	0x54
+#define IPU7_IS_MMU_FW_RD_L2_BLOCKNR_REG	0x60
+
+#define IPU7_IS_MMU_FW_WR_OFFSET		0x275000
+#define IPU7_IS_MMU_FW_WR_STREAM_NUM		3
+#define IPU7_IS_MMU_FW_WR_L1_BLOCKNR_REG	0x54
+#define IPU7_IS_MMU_FW_WR_L2_BLOCKNR_REG	0x60
+
+#define IPU7_IS_MMU_M0_OFFSET			0x276000
+#define IPU7_IS_MMU_M0_STREAM_NUM		8
+#define IPU7_IS_MMU_M0_L1_BLOCKNR_REG		0x54
+#define IPU7_IS_MMU_M0_L2_BLOCKNR_REG		0x74
+
+#define IPU7_IS_MMU_M1_OFFSET			0x277000
+#define IPU7_IS_MMU_M1_STREAM_NUM		16
+#define IPU7_IS_MMU_M1_L1_BLOCKNR_REG		0x54
+#define IPU7_IS_MMU_M1_L2_BLOCKNR_REG		0x94
+
+#define IPU7_PS_MMU_FW_RD_OFFSET		0x148000
+#define IPU7_PS_MMU_FW_RD_STREAM_NUM		20
+#define IPU7_PS_MMU_FW_RD_L1_BLOCKNR_REG	0x54
+#define IPU7_PS_MMU_FW_RD_L2_BLOCKNR_REG	0xa4
+
+#define IPU7_PS_MMU_FW_WR_OFFSET		0x149000
+#define IPU7_PS_MMU_FW_WR_STREAM_NUM		10
+#define IPU7_PS_MMU_FW_WR_L1_BLOCKNR_REG	0x54
+#define IPU7_PS_MMU_FW_WR_L2_BLOCKNR_REG	0x7c
+
+#define IPU7_PS_MMU_SRT_RD_OFFSET		0x14a000
+#define IPU7_PS_MMU_SRT_RD_STREAM_NUM		40
+#define IPU7_PS_MMU_SRT_RD_L1_BLOCKNR_REG	0x54
+#define IPU7_PS_MMU_SRT_RD_L2_BLOCKNR_REG	0xf4
+
+#define IPU7_PS_MMU_SRT_WR_OFFSET		0x14b000
+#define IPU7_PS_MMU_SRT_WR_STREAM_NUM		40
+#define IPU7_PS_MMU_SRT_WR_L1_BLOCKNR_REG	0x54
+#define IPU7_PS_MMU_SRT_WR_L2_BLOCKNR_REG	0xf4
+
+#define IPU7_IS_UAO_UC_RD_OFFSET		0x27c000
+#define IPU7_IS_UAO_UC_RD_PLANENUM		4
+
+#define IPU7_IS_UAO_UC_WR_OFFSET		0x27d000
+#define IPU7_IS_UAO_UC_WR_PLANENUM		4
+
+#define IPU7_IS_UAO_M0_WR_OFFSET		0x27e000
+#define IPU7_IS_UAO_M0_WR_PLANENUM		8
+
+#define IPU7_IS_UAO_M1_WR_OFFSET		0x27f000
+#define IPU7_IS_UAO_M1_WR_PLANENUM		16
+
+#define IPU7_PS_UAO_FW_RD_OFFSET		0x156000
+#define IPU7_PS_UAO_FW_RD_PLANENUM		20
+
+#define IPU7_PS_UAO_FW_WR_OFFSET		0x157000
+#define IPU7_PS_UAO_FW_WR_PLANENUM		16
+
+#define IPU7_PS_UAO_SRT_RD_OFFSET		0x154000
+#define IPU7_PS_UAO_SRT_RD_PLANENUM		40
+
+#define IPU7_PS_UAO_SRT_WR_OFFSET		0x155000
+#define IPU7_PS_UAO_SRT_WR_PLANENUM		40
+
+#define IPU7_IS_ZLX_UC_RD_OFFSET		0x278000
+#define IPU7_IS_ZLX_UC_WR_OFFSET		0x279000
+#define IPU7_IS_ZLX_M0_OFFSET			0x27a000
+#define IPU7_IS_ZLX_M1_OFFSET			0x27b000
+#define IPU7_IS_ZLX_UC_RD_NUM			4
+#define IPU7_IS_ZLX_UC_WR_NUM			4
+#define IPU7_IS_ZLX_M0_NUM			8
+#define IPU7_IS_ZLX_M1_NUM			16
+
+#define IPU7_PS_ZLX_DATA_RD_OFFSET		0x14e000
+#define IPU7_PS_ZLX_DATA_WR_OFFSET		0x14f000
+#define IPU7_PS_ZLX_FW_RD_OFFSET		0x150000
+#define IPU7_PS_ZLX_FW_WR_OFFSET		0x151000
+#define IPU7_PS_ZLX_DATA_RD_NUM			32
+#define IPU7_PS_ZLX_DATA_WR_NUM			32
+#define IPU7_PS_ZLX_FW_RD_NUM			16
+#define IPU7_PS_ZLX_FW_WR_NUM			10
+
+struct ipu7_mmu_hw {
+	char name[32];
+
+	void __iomem *base;
+	void __iomem *zlx_base;
+	void __iomem *uao_base;
+
+	u32 offset;
+	u32 zlx_offset;
+	u32 uao_offset;
+
+	u32 info_bits;
+	u32 refill;
+	u32 collapse_en_bitmap;
+	u32 at_sp_arb_cfg;
+
+	u32 l1_block;
+	u32 l2_block;
+
+	u8 nr_l1streams;
+	u8 nr_l2streams;
+	u32 l1_block_sz[IPU7_MMU_MAX_TLB_L1_STREAMS];
+	u32 l2_block_sz[IPU7_MMU_MAX_TLB_L2_STREAMS];
+
+	u8 zlx_nr;
+	u32 zlx_axi_pool[IPU7_ZLX_POOL_NUM];
+	u32 zlx_en[IPU7_ZLX_MAX_NUM];
+	u32 zlx_conf[IPU7_ZLX_MAX_NUM];
+
+	u32 uao_p_num;
+	u32 uao_p2tlb[IPU7_UAO_PLANE_MAX_NUM];
+};
+
+struct ipu7_mmu_hwdata {
+	struct ipu7_mmu_hw *hwdata;
+	unsigned int nr_mmus;
+};
+
+#endif
-- 
2.55.0


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

* [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (13 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing Antti Laakso
                   ` (28 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The firmware format differs slightly between ipu6 and ipu7.
Add support for ipu7 firmware validation and handling.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-cpd.c | 169 +++++++++++++++++++++---
 drivers/media/pci/intel/ipu6/ipu6-cpd.h |  43 ++++++
 2 files changed, 197 insertions(+), 15 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index 966a16a300f8..8e59406a725c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -16,6 +16,7 @@
 #include "ipu6-bus.h"
 #include "ipu6-cpd.h"
 #include "ipu6-dma.h"
+#include "ipu7-mmu-hw.h"
 
 /* 15 entries + header*/
 #define MAX_PKG_DIR_ENT_CNT		16
@@ -62,6 +63,20 @@ static inline const struct ipu6_cpd_ent *ipu6_cpd_get_entry(const void *cpd,
 #define ipu6_cpd_get_metadata(cpd) ipu6_cpd_get_entry(cpd, METADATA_IDX)
 #define ipu6_cpd_get_moduledata(cpd) ipu6_cpd_get_entry(cpd, MODULEDATA_IDX)
 
+#define IPU7_CPD_BINARY_START_IDX	1U
+#define IPU7_CPD_METADATA_START_IDX	2U
+#define IPU7_CPD_BINARY_NUM		2U /* ISYS + PSYS */
+#define IPU7_CPD_METADATA_ATTR		0xa
+#define IPU7_CPD_METADATA_IPL		0x1c
+/*
+ * Entries include:
+ * 1 manifest entry.
+ * 1 metadata entry for each sub system(ISYS and PSYS).
+ * 1 binary entry for each sub system(ISYS and PSYS).
+ */
+#define IPU7_CPD_ENTRY_NUM	(IPU7_CPD_BINARY_NUM * 2U + 1U)
+#define IPU7_MAX_MANIFEST_SIZE	(SZ_4K * sizeof(u32))
+
 static const struct ipu6_cpd_metadata_cmpnt_hdr *
 ipu6_cpd_metadata_get_cmpnt(struct ipu6_device *isp, const void *metadata,
 			    unsigned int metadata_size, u8 idx)
@@ -309,39 +324,163 @@ static int ipu6_cpd_validate_metadata(struct ipu6_device *isp,
 	return 0;
 }
 
-int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
-			       unsigned long cpd_file_size)
+static struct ipu7_cpd_metadata *ipu7_cpd_get_metadata(const void *cpd, int idx)
 {
-	const struct ipu6_cpd_hdr *hdr = cpd_file;
-	const struct ipu6_cpd_ent *ent;
-	int ret;
+	const struct ipu6_cpd_ent *cpd_ent =
+		ipu6_cpd_get_entry(cpd, IPU7_CPD_METADATA_START_IDX + idx * 2);
 
-	ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
-				    cpd_file_size);
-	if (ret)
-		return ret;
+	return (struct ipu7_cpd_metadata *)((u8 *)cpd + cpd_ent->offset);
+}
 
-	/* Check for CPD file marker */
-	if (hdr->hdr_mark != CPD_HDR_MARK) {
-		dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+static int ipu7_cpd_validate_metadata(struct ipu6_device *isp,
+				      const void *cpd, int idx)
+{
+	const struct ipu6_cpd_ent *cpd_ent =
+		ipu6_cpd_get_entry(cpd, IPU7_CPD_METADATA_START_IDX + idx * 2);
+	const struct ipu6_cpd_ent *bin_ent =
+		ipu6_cpd_get_entry(cpd, IPU7_CPD_BINARY_START_IDX + idx * 2);
+	const struct ipu7_cpd_metadata *metadata =
+		ipu7_cpd_get_metadata(cpd, idx);
+	struct device *dev = &isp->pdev->dev;
+	u32 offset;
+
+	/* Sanity check for metadata size */
+	if (cpd_ent->len != sizeof(struct ipu7_cpd_metadata)) {
+		dev_err(dev, "Invalid metadata size\n");
+		return -EINVAL;
+	}
+
+	/* Validate type and length of metadata sections */
+	if (metadata->attr.hdr.type != IPU7_CPD_METADATA_ATTR) {
+		dev_err(dev, "Invalid metadata attr type (%d)\n",
+			metadata->attr.hdr.type);
 		return -EINVAL;
 	}
+	if (metadata->attr.hdr.len != sizeof(struct ipu7_cpd_metadata_attr)) {
+		dev_err(dev, "Invalid metadata attr size (%d)\n",
+			metadata->attr.hdr.len);
+		return -EINVAL;
+	}
+	if (metadata->ipl.hdr.type != IPU7_CPD_METADATA_IPL) {
+		dev_err(dev, "Invalid metadata ipl type (%d)\n",
+			metadata->ipl.hdr.type);
+		return -EINVAL;
+	}
+	if (metadata->ipl.hdr.len != sizeof(struct ipu7_cpd_metadata_ipl)) {
+		dev_err(dev, "Invalid metadata ipl size (%d)\n",
+			metadata->ipl.hdr.len);
+		return -EINVAL;
+	}
+
+	offset = metadata->ipl.param[0];
+	if (offset > IPU7_FW_CODE_REGION_SIZE ||
+	    bin_ent->len > IPU7_FW_CODE_REGION_SIZE - offset) {
+		dev_err(dev, "Incorrect binary size %u and offset %u\n",
+			bin_ent->len, offset);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __ipu7_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+				    unsigned long cpd_file_size)
+{
+	const struct ipu6_cpd_ent *ent;
+	const struct ipu7_cpd_hdr *hdr = cpd_file;
+	unsigned int i;
 
-	/* Sanity check for manifest size */
 	ent = ipu6_cpd_get_manifest(cpd_file);
-	if (ent->len > MAX_MANIFEST_SIZE) {
+	if (ent->len > IPU7_MAX_MANIFEST_SIZE) {
 		dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
 		return -EINVAL;
 	}
+	/* Sanity check for CPD entry header */
+	if (hdr->ent_cnt != IPU7_CPD_ENTRY_NUM) {
+		dev_err(&isp->pdev->dev, "Invalid CPD entry number %d\n",
+			hdr->ent_cnt);
+		return -EINVAL;
+	}
 
 	/* Validate metadata */
+	for (i = 0; i < IPU7_CPD_BINARY_NUM; i++) {
+		int ret = ipu7_cpd_validate_metadata(isp, cpd_file, i);
+
+		if (ret) {
+			dev_err(&isp->pdev->dev, "Invalid metadata(%d)\n", i);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int __ipu6_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+				    unsigned long cpd_file_size)
+{
+	const struct ipu6_cpd_ent *ent;
+	int ret;
+
+	ent = ipu6_cpd_get_manifest(cpd_file);
+	if (ent->len > MAX_MANIFEST_SIZE) {
+		dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
+		return -EINVAL;
+	}
+
 	ent = ipu6_cpd_get_metadata(cpd_file);
 	ret = ipu6_cpd_validate_metadata(isp, cpd_file + ent->offset, ent->len);
 	if (ret)
 		return ret;
 
-	/* Validate moduledata */
 	ent = ipu6_cpd_get_moduledata(cpd_file);
 	return ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
 					    ent->len);
 }
+
+int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+			       unsigned long cpd_file_size)
+{
+	const struct ipu6_cpd_hdr *hdr = cpd_file;
+	int ret;
+
+	ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
+				    cpd_file_size);
+	if (ret)
+		return ret;
+
+	/* Check for CPD file marker */
+	if (hdr->hdr_mark != CPD_HDR_MARK) {
+		dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+		return -EINVAL;
+	}
+
+	if (IS_IPU7(isp))
+		return __ipu7_validate_cpd_file(isp, cpd_file, cpd_file_size);
+
+	return __ipu6_validate_cpd_file(isp, cpd_file, cpd_file_size);
+}
+
+int ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+			 u32 *entry)
+{
+	unsigned int i;
+
+	for (i = 0; i < IPU7_CPD_BINARY_NUM; i++) {
+		const struct ipu7_cpd_metadata *metadata;
+		u8 idx = IPU7_CPD_BINARY_START_IDX + i * 2U;
+		const struct ipu6_cpd_ent *ent =
+			ipu6_cpd_get_entry(cpd, idx);
+
+		if (strncmp(ent->name, name, sizeof(ent->name)))
+			continue;
+
+		metadata = ipu7_cpd_get_metadata(cpd, i);
+		memcpy(dst + metadata->ipl.param[0], cpd + ent->offset,
+		       ent->len);
+		*entry = metadata->ipl.param[2];
+
+		return 0;
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_cpd_copy_binary, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.h b/drivers/media/pci/intel/ipu6/ipu6-cpd.h
index e0e4fdeca902..b614ed0004bb 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.h
@@ -98,8 +98,51 @@ struct ipu6_cpd_client_pkg_hdr {
 	u32 prog_bin_size;
 } __packed;
 
+/* IPU7 */
+
+struct ipu7_cpd_hdr {
+	u32 hdr_mark;
+	u32 ent_cnt;
+	u8 hdr_ver;
+	u8 ent_ver;
+	u8 hdr_len;
+	u8 rsvd;
+	u8 partition_name[4];
+	u32 crc32;
+} __packed;
+
+struct ipu7_cpd_metadata_hdr {
+	u32 type;
+	u32 len;
+} __packed;
+
+struct ipu7_cpd_metadata_attr {
+	struct ipu7_cpd_metadata_hdr hdr;
+	u8 compression_type;
+	u8 encryption_type;
+	u8 rsvd[2];
+	u32 uncompressed_size;
+	u32 compressed_size;
+	u32 module_id;
+	u8 hash[48];
+} __packed;
+
+struct ipu7_cpd_metadata_ipl {
+	struct ipu7_cpd_metadata_hdr hdr;
+	u32 param[4];
+	u8 rsvd[8];
+} __packed;
+
+struct ipu7_cpd_metadata {
+	struct ipu7_cpd_metadata_attr attr;
+	struct ipu7_cpd_metadata_ipl ipl;
+} __packed;
+
 int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src);
 void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev);
 int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
 			       unsigned long cpd_file_size);
+int ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+			 u32 *entry);
+
 #endif /* IPU6_CPD_H */
-- 
2.55.0


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

* [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (14 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 17/44] media: ipu6: Rename isys fw msg union Antti Laakso
                   ` (27 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

We are adding support for mapping ipu7 firmware which doesn't have
pkg_dir.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-cpd.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index 8e59406a725c..564461e0bb62 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -235,8 +235,9 @@ EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, "INTEL_IPU6");
 
 void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev)
 {
-	ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
-		      adev->pkg_dir_dma_addr, 0);
+	if (adev->pkg_dir)
+		ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
+			      adev->pkg_dir_dma_addr, 0);
 }
 EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, "INTEL_IPU6");
 
-- 
2.55.0


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

* [PATCH v2 17/44] media: ipu6: Rename isys fw msg union
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (15 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file Antti Laakso
                   ` (26 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Later we need to abstract ipu7 firmware abi structs same way
we have it now for ipu6. Renaming union per ipu helps to make
the split more clear.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys-queue.c | 4 ++--
 drivers/media/pci/intel/ipu6/ipu6-isys-video.c | 4 ++--
 drivers/media/pci/intel/ipu6/ipu6-isys.c       | 4 ++--
 drivers/media/pci/intel/ipu6/ipu6-isys.h       | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index fabaed63df0c..529973860e9e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -316,7 +316,7 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
 		if (!msg)
 			return -ENOMEM;
 
-		buf = &msg->fw_msg.frame;
+		buf = &msg->ipu6.frame;
 		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
 		ipu6_fw_isys_dump_frame_buff_set(dev, buf,
 						 stream->nr_output_pins);
@@ -396,7 +396,7 @@ static void buf_queue(struct vb2_buffer *vb)
 		goto out;
 	}
 
-	buf = &msg->fw_msg.frame;
+	buf = &msg->ipu6.frame;
 	ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
 	ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 89eb265737d7..c925386a1e98 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -533,7 +533,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 	if (!msg)
 		return -ENOMEM;
 
-	stream_cfg = &msg->fw_msg.stream;
+	stream_cfg = &msg->ipu6.stream;
 	stream_cfg->src = stream->stream_source;
 	stream_cfg->vc = stream->vc;
 	stream_cfg->isl_use = 0;
@@ -590,7 +590,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 			ret = -ENOMEM;
 			goto out_put_stream_opened;
 		}
-		buf = &msg->fw_msg.frame;
+		buf = &msg->ipu6.frame;
 		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
 		ipu6_isys_buffer_list_queue(bl,
 					    IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 8af891081bd3..8f2d361b89f6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1003,7 +1003,7 @@ struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream)
 	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));
+	memset(&msg->ipu6, 0, sizeof(msg->ipu6));
 
 	return msg;
 }
@@ -1029,7 +1029,7 @@ void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data)
 		return;
 
 	spin_lock_irqsave(&isys->listlock, flags);
-	msg = container_of(ptr, struct isys_fw_msgs, fw_msg.dummy);
+	msg = container_of(ptr, struct isys_fw_msgs, ipu6.dummy);
 	list_move(&msg->head, &isys->framebuflist);
 	spin_unlock_irqrestore(&isys->listlock, flags);
 }
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 0b139ab24431..abcd5e1cbc2c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -169,7 +169,7 @@ struct isys_fw_msgs {
 		u64 dummy;
 		struct ipu6_fw_isys_frame_buff_set_abi frame;
 		struct ipu6_fw_isys_stream_cfg_data_abi stream;
-	} fw_msg;
+	} ipu6;
 	struct list_head head;
 	dma_addr_t dma_addr;
 };
-- 
2.55.0


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

* [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (16 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 17/44] media: ipu6: Rename isys fw msg union Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down Antti Laakso
                   ` (25 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 will have its own isr handlers. Move ipu6 isr
code to hardware specific file.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 259 +++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.h |   3 +
 drivers/media/pci/intel/ipu6/ipu6-isys.c    | 263 +-------------------
 3 files changed, 263 insertions(+), 262 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index fc2f24c05de7..7f7125202ffd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -487,3 +487,262 @@ ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
 
 	dev_dbg(dev, "-----------------------------------------------------\n");
 }
+
+struct fwmsg {
+	int type;
+	char *msg;
+	bool valid_ts;
+};
+
+static const struct fwmsg fw_msg[] = {
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK, "STREAM_START_ACK", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
+	 "STREAM_START_AND_CAPTURE_ACK", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK, "STREAM_STOP_ACK", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY", 1},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK", 0},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
+	 "STREAM_START_AND_CAPTURE_DONE", 1},
+	{IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE", 1},
+	{IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF", 1},
+	{IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF", 1},
+	{IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY, "STATS_READY", 1},
+	{-1, "UNKNOWN MESSAGE", 0}
+};
+
+static u32 resp_type_to_index(int type)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(fw_msg); i++)
+		if (fw_msg[i].type == type)
+			return i;
+
+	return  ARRAY_SIZE(fw_msg) - 1;
+}
+
+int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
+{
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	struct ipu6_fw_isys_resp_info_abi *resp;
+	struct ipu6_isys_stream *stream;
+	struct ipu6_isys_csi2 *csi2 = NULL;
+	u32 index;
+	u64 ts;
+
+	if (!isys->fwctx)
+		return 1;
+
+	resp = ipu6_fw_isys_get_resp(isys);
+	if (!resp)
+		return 1;
+
+	ts = (u64)resp->timestamp[1] << 32 | resp->timestamp[0];
+
+	index = resp_type_to_index(resp->type);
+	dev_dbg(&adev->auxdev.dev,
+		"FW resp %02d %s, stream %u, ts 0x%16.16llx, pin %d\n",
+		resp->type, fw_msg[index].msg, resp->stream_handle,
+		fw_msg[index].valid_ts ? ts : 0, resp->pin_id);
+
+	if (resp->error_info.error == IPU6_FW_ISYS_ERROR_STREAM_IN_SUSPENSION)
+		/* Suspension is kind of special case: not enough buffers */
+		dev_dbg(&adev->auxdev.dev,
+			"FW error resp SUSPENSION, details %d\n",
+			resp->error_info.error_details);
+	else if (resp->error_info.error)
+		dev_dbg(&adev->auxdev.dev,
+			"FW error resp error %d, details %d\n",
+			resp->error_info.error, resp->error_info.error_details);
+
+	if (resp->stream_handle >= IPU6_ISYS_MAX_STREAMS) {
+		dev_err(&adev->auxdev.dev, "bad stream handle %u\n",
+			resp->stream_handle);
+		goto leave;
+	}
+
+	stream = ipu6_isys_query_stream_by_handle(isys, resp->stream_handle);
+	if (!stream) {
+		dev_err(&adev->auxdev.dev, "stream of stream_handle %u is unused\n",
+			resp->stream_handle);
+		goto leave;
+	}
+	stream->error = resp->error_info.error;
+
+	csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
+
+	switch (resp->type) {
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE:
+		complete(&stream->stream_open_completion);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK:
+		complete(&stream->stream_close_completion);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK:
+		complete(&stream->stream_start_completion);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
+		complete(&stream->stream_start_completion);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK:
+		complete(&stream->stream_stop_completion);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK:
+		complete(&stream->stream_stop_completion);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
+		/*
+		 * firmware only release the capture msg until software
+		 * get pin_data_ready event
+		 */
+		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
+		if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
+		    stream->output_pins_queue[resp->pin_id])
+			ipu6_isys_queue_buf_ready(stream, resp);
+		else
+			dev_warn(&adev->auxdev.dev,
+				 "%d:No queue for pin id %d\n",
+				 resp->stream_handle, resp->pin_id);
+		if (csi2)
+			ipu6_isys_csi2_error(csi2);
+
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK:
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
+	case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE:
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF:
+
+		ipu6_isys_csi2_sof_event_by_stream(stream);
+		stream->seq[stream->seq_index].sequence =
+			atomic_read(&stream->sequence) - 1;
+		stream->seq[stream->seq_index].timestamp = ts;
+		dev_dbg(&adev->auxdev.dev,
+			"sof: handle %d: (index %u), timestamp 0x%16.16llx\n",
+			resp->stream_handle,
+			stream->seq[stream->seq_index].sequence, ts);
+		stream->seq_index = (stream->seq_index + 1)
+			% IPU6_ISYS_MAX_PARALLEL_SOF;
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF:
+		ipu6_isys_csi2_eof_event_by_stream(stream);
+		dev_dbg(&adev->auxdev.dev,
+			"eof: handle %d: (index %u), timestamp 0x%16.16llx\n",
+			resp->stream_handle,
+			stream->seq[stream->seq_index].sequence, ts);
+		break;
+	case IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY:
+		break;
+	default:
+		dev_err(&adev->auxdev.dev, "%d:unknown response type %u\n",
+			resp->stream_handle, resp->type);
+		break;
+	}
+
+	ipu6_isys_put_stream(stream);
+leave:
+	ipu6_fw_isys_put_resp(isys);
+	return 0;
+}
+
+static void ipu6_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys_stream *stream;
+	unsigned int i;
+	u32 status;
+	int source;
+
+	ipu6_isys_register_errors(csi2);
+
+	status = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+		       CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
+
+	writel(status, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+	       CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
+
+	source = csi2->asd.source;
+	for (i = 0; i < NR_OF_CSI2_VC; i++) {
+		if (status & IPU_CSI_RX_IRQ_FS_VC(i)) {
+			stream = ipu6_isys_query_stream_by_source(csi2->isys,
+								  source, i);
+			if (stream) {
+				ipu6_isys_csi2_sof_event_by_stream(stream);
+				ipu6_isys_put_stream(stream);
+			}
+		}
+
+		if (status & IPU_CSI_RX_IRQ_FE_VC(i)) {
+			stream = ipu6_isys_query_stream_by_source(csi2->isys,
+								  source, i);
+			if (stream) {
+				ipu6_isys_csi2_eof_event_by_stream(stream);
+				ipu6_isys_put_stream(stream);
+			}
+		}
+	}
+}
+
+irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev)
+{
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	void __iomem *base = isys->pdata->base;
+	u32 status_sw, status_csi;
+	u32 ctrl0_status, ctrl0_clear;
+
+	spin_lock(&isys->power_lock);
+	if (!isys->power) {
+		spin_unlock(&isys->power_lock);
+		return IRQ_NONE;
+	}
+
+	ctrl0_status = isys->pdata->ipdata->csi2.ctrl0_irq_status;
+	ctrl0_clear = isys->pdata->ipdata->csi2.ctrl0_irq_clear;
+
+	status_csi = readl(isys->pdata->base + ctrl0_status);
+	status_sw = readl(isys->pdata->base +
+			  IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
+
+	writel(ISYS_UNISPART_IRQS & ~IPU6_ISYS_UNISPART_IRQ_SW,
+	       base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
+
+	do {
+		writel(status_csi, isys->pdata->base + ctrl0_clear);
+
+		writel(status_sw, isys->pdata->base +
+		       IPU6_REG_ISYS_UNISPART_IRQ_CLEAR);
+
+		if (isys->isr_csi2_bits & 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 & IPU6_ISYS_UNISPART_IRQ_CSI2(i))
+					ipu6_isys_csi2_isr(&isys->csi2[i]);
+			}
+		}
+
+		writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_REG);
+
+		if (!ipu6_isys_isr_one(adev))
+			status_sw = IPU6_ISYS_UNISPART_IRQ_SW;
+		else
+			status_sw = 0;
+
+		status_csi = readl(isys->pdata->base + ctrl0_status);
+		status_sw |= readl(isys->pdata->base +
+				   IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
+	} while ((status_csi & isys->isr_csi2_bits) ||
+		 (status_sw & IPU6_ISYS_UNISPART_IRQ_SW));
+
+	writel(ISYS_UNISPART_IRQS, base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
+
+	spin_unlock(&isys->power_lock);
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index 15d4ae355f28..f65461a4c907 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -578,4 +578,7 @@ void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
 struct ipu6_fw_isys_resp_info_abi *
 ipu6_fw_isys_get_resp(struct ipu6_isys *isys);
 void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
+int ipu6_isys_isr_one(struct ipu6_bus_device *adev);
+irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev);
+
 #endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 8f2d361b89f6..a58a35112ebd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -100,8 +100,6 @@ enum ltr_did_type {
 
 #define ISYS_PM_QOS_VALUE	300
 
-static int isys_isr_one(struct ipu6_bus_device *adev);
-
 static int
 isys_complete_ext_device_registration(struct ipu6_isys *isys,
 				      struct v4l2_subdev *sd,
@@ -304,104 +302,6 @@ static void isys_setup_hw(struct ipu6_isys *isys)
 		writel(thd[i], base + IPU6_REG_ISYS_CDC_THRESHOLD(i));
 }
 
-static void ipu6_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
-{
-	struct ipu6_isys_stream *stream;
-	unsigned int i;
-	u32 status;
-	int source;
-
-	ipu6_isys_register_errors(csi2);
-
-	status = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
-		       CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
-
-	writel(status, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
-	       CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
-
-	source = csi2->asd.source;
-	for (i = 0; i < NR_OF_CSI2_VC; i++) {
-		if (status & IPU_CSI_RX_IRQ_FS_VC(i)) {
-			stream = ipu6_isys_query_stream_by_source(csi2->isys,
-								  source, i);
-			if (stream) {
-				ipu6_isys_csi2_sof_event_by_stream(stream);
-				ipu6_isys_put_stream(stream);
-			}
-		}
-
-		if (status & IPU_CSI_RX_IRQ_FE_VC(i)) {
-			stream = ipu6_isys_query_stream_by_source(csi2->isys,
-								  source, i);
-			if (stream) {
-				ipu6_isys_csi2_eof_event_by_stream(stream);
-				ipu6_isys_put_stream(stream);
-			}
-		}
-	}
-}
-
-static irqreturn_t isys_isr(struct ipu6_bus_device *adev)
-{
-	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
-	void __iomem *base = isys->pdata->base;
-	u32 status_sw, status_csi;
-	u32 ctrl0_status, ctrl0_clear;
-
-	spin_lock(&isys->power_lock);
-	if (!isys->power) {
-		spin_unlock(&isys->power_lock);
-		return IRQ_NONE;
-	}
-
-	ctrl0_status = isys->pdata->ipdata->csi2.ctrl0_irq_status;
-	ctrl0_clear = isys->pdata->ipdata->csi2.ctrl0_irq_clear;
-
-	status_csi = readl(isys->pdata->base + ctrl0_status);
-	status_sw = readl(isys->pdata->base +
-			  IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
-
-	writel(ISYS_UNISPART_IRQS & ~IPU6_ISYS_UNISPART_IRQ_SW,
-	       base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
-
-	do {
-		writel(status_csi, isys->pdata->base + ctrl0_clear);
-
-		writel(status_sw, isys->pdata->base +
-		       IPU6_REG_ISYS_UNISPART_IRQ_CLEAR);
-
-		if (isys->isr_csi2_bits & 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 & IPU6_ISYS_UNISPART_IRQ_CSI2(i))
-					ipu6_isys_csi2_isr(&isys->csi2[i]);
-			}
-		}
-
-		writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_REG);
-
-		if (!isys_isr_one(adev))
-			status_sw = IPU6_ISYS_UNISPART_IRQ_SW;
-		else
-			status_sw = 0;
-
-		status_csi = readl(isys->pdata->base + ctrl0_status);
-		status_sw |= readl(isys->pdata->base +
-				   IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
-	} while ((status_csi & isys->isr_csi2_bits) ||
-		 (status_sw & IPU6_ISYS_UNISPART_IRQ_SW));
-
-	writel(ISYS_UNISPART_IRQS, base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
-
-	spin_unlock(&isys->power_lock);
-
-	return IRQ_HANDLED;
-}
-
 static void get_lut_ltrdid(struct ipu6_isys *isys, struct ltr_did *pltr_did)
 {
 	struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
@@ -1167,169 +1067,8 @@ static void isys_remove(struct auxiliary_device *auxdev)
 	mutex_destroy(&isys->mutex);
 }
 
-struct fwmsg {
-	int type;
-	char *msg;
-	bool valid_ts;
-};
-
-static const struct fwmsg fw_msg[] = {
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK, "STREAM_START_ACK", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
-	 "STREAM_START_AND_CAPTURE_ACK", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK, "STREAM_STOP_ACK", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY", 1},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK", 0},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
-	 "STREAM_START_AND_CAPTURE_DONE", 1},
-	{IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE", 1},
-	{IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF", 1},
-	{IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF", 1},
-	{IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY, "STATS_READY", 1},
-	{-1, "UNKNOWN MESSAGE", 0}
-};
-
-static u32 resp_type_to_index(int type)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(fw_msg); i++)
-		if (fw_msg[i].type == type)
-			return i;
-
-	return  ARRAY_SIZE(fw_msg) - 1;
-}
-
-static int isys_isr_one(struct ipu6_bus_device *adev)
-{
-	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
-	struct ipu6_fw_isys_resp_info_abi *resp;
-	struct ipu6_isys_stream *stream;
-	struct ipu6_isys_csi2 *csi2 = NULL;
-	u32 index;
-	u64 ts;
-
-	if (!isys->fwctx)
-		return 1;
-
-	resp = ipu6_fw_isys_get_resp(isys);
-	if (!resp)
-		return 1;
-
-	ts = (u64)resp->timestamp[1] << 32 | resp->timestamp[0];
-
-	index = resp_type_to_index(resp->type);
-	dev_dbg(&adev->auxdev.dev,
-		"FW resp %02d %s, stream %u, ts 0x%16.16llx, pin %d\n",
-		resp->type, fw_msg[index].msg, resp->stream_handle,
-		fw_msg[index].valid_ts ? ts : 0, resp->pin_id);
-
-	if (resp->error_info.error == IPU6_FW_ISYS_ERROR_STREAM_IN_SUSPENSION)
-		/* Suspension is kind of special case: not enough buffers */
-		dev_dbg(&adev->auxdev.dev,
-			"FW error resp SUSPENSION, details %d\n",
-			resp->error_info.error_details);
-	else if (resp->error_info.error)
-		dev_dbg(&adev->auxdev.dev,
-			"FW error resp error %d, details %d\n",
-			resp->error_info.error, resp->error_info.error_details);
-
-	if (resp->stream_handle >= IPU6_ISYS_MAX_STREAMS) {
-		dev_err(&adev->auxdev.dev, "bad stream handle %u\n",
-			resp->stream_handle);
-		goto leave;
-	}
-
-	stream = ipu6_isys_query_stream_by_handle(isys, resp->stream_handle);
-	if (!stream) {
-		dev_err(&adev->auxdev.dev, "stream of stream_handle %u is unused\n",
-			resp->stream_handle);
-		goto leave;
-	}
-	stream->error = resp->error_info.error;
-
-	csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
-
-	switch (resp->type) {
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE:
-		complete(&stream->stream_open_completion);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK:
-		complete(&stream->stream_close_completion);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK:
-		complete(&stream->stream_start_completion);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
-		complete(&stream->stream_start_completion);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK:
-		complete(&stream->stream_stop_completion);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK:
-		complete(&stream->stream_stop_completion);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
-		/*
-		 * firmware only release the capture msg until software
-		 * get pin_data_ready event
-		 */
-		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
-		if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
-		    stream->output_pins_queue[resp->pin_id])
-			ipu6_isys_queue_buf_ready(stream, resp);
-		else
-			dev_warn(&adev->auxdev.dev,
-				 "%d:No queue for pin id %d\n",
-				 resp->stream_handle, resp->pin_id);
-		if (csi2)
-			ipu6_isys_csi2_error(csi2);
-
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK:
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
-	case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE:
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF:
-
-		ipu6_isys_csi2_sof_event_by_stream(stream);
-		stream->seq[stream->seq_index].sequence =
-			atomic_read(&stream->sequence) - 1;
-		stream->seq[stream->seq_index].timestamp = ts;
-		dev_dbg(&adev->auxdev.dev,
-			"sof: handle %d: (index %u), timestamp 0x%16.16llx\n",
-			resp->stream_handle,
-			stream->seq[stream->seq_index].sequence, ts);
-		stream->seq_index = (stream->seq_index + 1)
-			% IPU6_ISYS_MAX_PARALLEL_SOF;
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF:
-		ipu6_isys_csi2_eof_event_by_stream(stream);
-		dev_dbg(&adev->auxdev.dev,
-			"eof: handle %d: (index %u), timestamp 0x%16.16llx\n",
-			resp->stream_handle,
-			stream->seq[stream->seq_index].sequence, ts);
-		break;
-	case IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY:
-		break;
-	default:
-		dev_err(&adev->auxdev.dev, "%d:unknown response type %u\n",
-			resp->stream_handle, resp->type);
-		break;
-	}
-
-	ipu6_isys_put_stream(stream);
-leave:
-	ipu6_fw_isys_put_resp(isys);
-	return 0;
-}
-
 static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
-	.isr = isys_isr,
+	.isr = ipu6_isys_isr,
 	.isr_threaded = NULL,
 	.wake_isr_thread = false,
 };
-- 
2.55.0


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

* [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (17 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling Antti Laakso
                   ` (24 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Move handling of hardware specific buffers out of common code, like
ipu6-isys-video.c. Now the ipu6_put_fw_msg_buf() works with fw_msg_bufs,
like its counterpart ipu6_get_fw_msg_buf().

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c    | 11 ++++++++++-
 drivers/media/pci/intel/ipu6/ipu6-isys-video.c |  6 +++---
 drivers/media/pci/intel/ipu6/ipu6-isys.c       |  7 ++-----
 drivers/media/pci/intel/ipu6/ipu6-isys.h       |  2 +-
 4 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 7f7125202ffd..8906727ca84b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -530,6 +530,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
 	struct ipu6_fw_isys_resp_info_abi *resp;
 	struct ipu6_isys_stream *stream;
 	struct ipu6_isys_csi2 *csi2 = NULL;
+	struct isys_fw_msgs *isys_fw_msg = NULL;
 	u32 index;
 	u64 ts;
 
@@ -598,7 +599,15 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
 		 * firmware only release the capture msg until software
 		 * get pin_data_ready event
 		 */
-		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
+		if (!resp->buf_id)
+			dev_warn(&adev->auxdev.dev, "%d: Invalid buf ID\n",
+				 resp->stream_handle);
+		else
+			isys_fw_msg =
+				container_of((void *)(uintptr_t)resp->buf_id,
+					     struct isys_fw_msgs, ipu6.dummy);
+
+		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
 		if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
 		    stream->output_pins_queue[resp->pin_id])
 			ipu6_isys_queue_buf_ready(stream, resp);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index c925386a1e98..fabea6a75d7d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -544,7 +544,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 
 		ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
 		if (ret < 0) {
-			ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+			ipu6_put_fw_msg_buf(av->isys, msg);
 			return ret;
 		}
 	}
@@ -561,7 +561,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 				       IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
 	if (ret < 0) {
 		dev_err(dev, "can't open stream (%d)\n", ret);
-		ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+		ipu6_put_fw_msg_buf(av->isys, msg);
 		return ret;
 	}
 
@@ -570,7 +570,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 	tout = wait_for_completion_timeout(&stream->stream_open_completion,
 					   IPU6_FW_CALL_TIMEOUT_JIFFIES);
 
-	ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+	ipu6_put_fw_msg_buf(av->isys, msg);
 
 	if (!tout) {
 		dev_err(dev, "stream open time out\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index a58a35112ebd..bb3c0d6bc6c9 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -919,17 +919,14 @@ void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys)
 	spin_unlock_irqrestore(&isys->listlock, flags);
 }
 
-void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data)
+void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg)
 {
-	struct isys_fw_msgs *msg;
 	unsigned long flags;
-	void *ptr = (void *)data;
 
-	if (!ptr)
+	if (!msg)
 		return;
 
 	spin_lock_irqsave(&isys->listlock, flags);
-	msg = container_of(ptr, struct isys_fw_msgs, ipu6.dummy);
 	list_move(&msg->head, &isys->framebuflist);
 	spin_unlock_irqrestore(&isys->listlock, flags);
 }
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index abcd5e1cbc2c..f39566513a87 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -175,7 +175,7 @@ struct isys_fw_msgs {
 };
 
 struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream);
-void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data);
+void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg);
 void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
 
 extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops;
-- 
2.55.0


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

* [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (18 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 21/44] media: ipu6: Add isys firmware ops Antti Laakso
                   ` (23 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Move ipu6 specific buffer and stream handling down to
hardware specific file, to make it possible to add ipu7
specific functionality.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c   | 241 ++++++++++++++++--
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.h   |  42 ++-
 .../media/pci/intel/ipu6/ipu6-isys-queue.c    |  77 +-----
 .../media/pci/intel/ipu6/ipu6-isys-queue.h    |   4 -
 .../media/pci/intel/ipu6/ipu6-isys-video.c    | 128 +---------
 5 files changed, 270 insertions(+), 222 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 8906727ca84b..9256ea3b68c1 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -90,11 +90,11 @@ int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
 	return ret;
 }
 
-int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
-			     const unsigned int stream_handle,
-			     void *cpu_mapped_buf,
-			     dma_addr_t dma_mapped_buf,
-			     size_t size, u16 send_type)
+static int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
+				    const unsigned int stream_handle,
+				    void *cpu_mapped_buf,
+				    dma_addr_t dma_mapped_buf,
+				    size_t size, u16 send_type)
 {
 	struct ipu6_fw_com_context *ctx = isys->fwctx;
 	struct device *dev = &isys->adev->auxdev.dev;
@@ -126,13 +126,6 @@ int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
 	return 0;
 }
 
-int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
-			    const unsigned int stream_handle, u16 send_type)
-{
-	return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
-					send_type);
-}
-
 int ipu6_fw_isys_close(struct ipu6_isys *isys)
 {
 	struct device *dev = &isys->adev->auxdev.dev;
@@ -376,9 +369,9 @@ void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
 	ipu6_recv_put_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 }
 
-void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
-				  struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
+void ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *msg)
 {
+	struct ipu6_fw_isys_stream_cfg_data_abi *cfg = &msg->ipu6.stream;
 	unsigned int i;
 
 	dev_dbg(dev, "-----------------------------------------------------\n");
@@ -454,12 +447,14 @@ void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
 }
 
 void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
-				 struct ipu6_fw_isys_frame_buff_set_abi *buf,
+ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *msg,
 				 unsigned int outputs)
 {
+	struct ipu6_fw_isys_frame_buff_set_abi *buf;
 	unsigned int i;
 
+	buf = &msg->ipu6.frame;
+
 	dev_dbg(dev, "-----------------------------------------------------\n");
 	dev_dbg(dev, "IPU6_FW_ISYS_FRAME_BUFF_SET\n");
 
@@ -596,16 +591,17 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
 		break;
 	case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
 		/*
-		 * firmware only release the capture msg until software
+		 * firmware only release the capture message until software
 		 * get pin_data_ready event
 		 */
-		if (!resp->buf_id)
+		if (!resp->buf_id) {
 			dev_warn(&adev->auxdev.dev, "%d: Invalid buf ID\n",
 				 resp->stream_handle);
-		else
-			isys_fw_msg =
-				container_of((void *)(uintptr_t)resp->buf_id,
-					     struct isys_fw_msgs, ipu6.dummy);
+			goto leave_put_stream;
+		}
+
+		isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id,
+					   struct isys_fw_msgs, ipu6.dummy);
 
 		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
 		if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
@@ -652,6 +648,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
 		break;
 	}
 
+leave_put_stream:
 	ipu6_isys_put_stream(stream);
 leave:
 	ipu6_fw_isys_put_resp(isys);
@@ -755,3 +752,203 @@ irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev)
 
 	return IRQ_HANDLED;
 }
+
+static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
+				struct ipu6_fw_isys_stream_cfg_data_abi *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 v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
+	struct ipu6_fw_isys_input_pin_info_abi *input_pin;
+	struct ipu6_fw_isys_output_pin_info_abi *output_pin;
+	struct ipu6_isys_stream *stream = av->stream;
+	struct ipu6_isys_queue *aq = &av->aq;
+	struct v4l2_mbus_framefmt fmt;
+	const struct ipu6_isys_pixelformat *pfmt =
+		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
+	struct v4l2_rect v4l2_crop;
+	struct ipu6_isys *isys = av->isys;
+	int input_pins = cfg->nof_input_pins++;
+	int output_pins;
+	u32 src_stream;
+
+	src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
+	fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
+	v4l2_crop = *v4l2_subdev_state_get_crop(state, src_pad->index, src_stream);
+
+	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->bits_per_pix = pfmt->bpp_packed;
+	input_pin->mapped_dt = 0x40; /* invalid mipi data type */
+	input_pin->mipi_decompression = 0;
+	input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
+	input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
+		IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
+		IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
+	input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
+
+	output_pins = cfg->nof_output_pins++;
+	aq->fw_output = output_pins;
+	stream->output_pins_queue[output_pins] = aq;
+
+	output_pin = &cfg->output_pins[output_pins];
+	output_pin->input_pin_id = input_pins;
+	output_pin->output_res.width = ipu6_isys_get_frame_width(av);
+	output_pin->output_res.height = ipu6_isys_get_frame_height(av);
+
+	output_pin->stride = ipu6_isys_get_bytes_per_line(av);
+	if (pfmt->bpp != pfmt->bpp_packed)
+		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
+	else
+		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
+	output_pin->ft = pfmt->css_pixelformat;
+	output_pin->send_irq = 1;
+	memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
+	output_pin->s2m_pixel_soc_pixel_remapping =
+		S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
+	output_pin->csi_be_soc_pixel_remapping =
+		CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
+
+	output_pin->snoopable = true;
+	output_pin->error_handling_enable = false;
+	output_pin->sensor_type = isys->sensor_type++;
+	if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
+		isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
+
+	return 0;
+}
+
+int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+				    struct isys_fw_msgs *msg)
+{
+	struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu6_isys_stream *stream = av->stream;
+	struct ipu6_isys_queue *aq;
+
+	stream_cfg = &msg->ipu6.stream;
+	stream_cfg->src = stream->stream_source;
+	stream_cfg->vc = stream->vc;
+	stream_cfg->isl_use = 0;
+	stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
+
+	list_for_each_entry(aq, &stream->queues, node) {
+		struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
+		int ret;
+
+		ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
+		if (ret < 0)
+			return ret;
+	}
+
+	ipu6_fw_isys_dump_stream_cfg(dev, msg);
+
+	stream->nr_output_pins = stream_cfg->nof_output_pins;
+
+	return 0;
+}
+
+int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
+			     const unsigned int stream_handle,
+			     struct isys_fw_msgs *msg)
+{
+	return ipu6_fw_isys_complex_cmd(isys, stream_handle,
+				       &msg->ipu6.stream, msg->dma_addr,
+				       sizeof(msg->ipu6.stream),
+				       IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
+}
+
+int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
+			      const unsigned int stream_handle)
+{
+	return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
+					IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
+}
+
+int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
+			      const unsigned int stream_handle)
+{
+	return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
+					IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
+}
+
+int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
+			      const unsigned int stream_handle,
+			      struct isys_fw_msgs *msg, bool capture)
+{
+	u16 cmd_type;
+
+	if (capture)
+		cmd_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
+	else
+		cmd_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
+
+	return ipu6_fw_isys_complex_cmd(isys, stream_handle,
+					&msg->ipu6.stream, msg->dma_addr,
+					sizeof(msg->ipu6.stream), cmd_type);
+}
+
+int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
+				const unsigned int stream_handle,
+				struct isys_fw_msgs *msg)
+{
+	return ipu6_fw_isys_complex_cmd(isys, stream_handle,
+					&msg->ipu6.stream, msg->dma_addr,
+					sizeof(msg->ipu6.stream),
+					IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
+}
+
+static void
+ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
+				  struct ipu6_fw_isys_frame_buff_set_abi *set)
+{
+	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+	struct ipu6_isys_video_buffer *ivb =
+		vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+
+	set->output_pins[aq->fw_output].addr = ivb->dma_addr;
+	set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
+}
+
+/*
+ * Convert a buffer list to a isys fw ABI framebuffer set. The
+ * buffer list is not modified.
+ */
+#define IPU6_ISYS_FRAME_NUM_THRESHOLD  (30)
+void
+ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+			     struct ipu6_isys_stream *stream,
+			     struct ipu6_isys_buffer_list *bl)
+{
+	struct ipu6_fw_isys_frame_buff_set_abi *set = &msg->ipu6.frame;
+	struct ipu6_isys_buffer *ib;
+
+	WARN_ON(!bl->nbufs);
+
+	set->send_irq_sof = 1;
+	set->send_resp_sof = 1;
+	set->send_irq_eof = 0;
+	set->send_resp_eof = 0;
+
+	if (stream->streaming)
+		set->send_irq_capture_ack = 0;
+	else
+		set->send_irq_capture_ack = 1;
+	set->send_irq_capture_done = 0;
+
+	set->send_resp_capture_ack = 1;
+	set->send_resp_capture_done = 1;
+	if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {
+		set->send_resp_capture_ack = 0;
+		set->send_resp_capture_done = 0;
+	}
+
+	list_for_each_entry(ib, &bl->head, head) {
+		struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
+
+		ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
+	}
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index f65461a4c907..b589ae7fbd4e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -8,6 +8,10 @@
 
 struct device;
 struct ipu6_isys;
+struct ipu6_isys_video;
+struct isys_fw_msgs;
+struct ipu6_isys_stream;
+struct ipu6_isys_buffer_list;
 
 /* Max number of Input/Output Pins */
 #define IPU6_MAX_IPINS 4
@@ -555,21 +559,8 @@ struct ipu6_fw_proxy_send_queue_token {
 	u32 value;
 };
 
-void
-ipu6_fw_isys_dump_stream_cfg(struct device *dev,
-			     struct ipu6_fw_isys_stream_cfg_data_abi *cfg);
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
-				 struct ipu6_fw_isys_frame_buff_set_abi *buf,
-				 unsigned int outputs);
 int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams);
 int ipu6_fw_isys_close(struct ipu6_isys *isys);
-int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
-			    const unsigned int stream_handle, u16 send_type);
-int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
-			     const unsigned int stream_handle,
-			     void *cpu_mapped_buf, dma_addr_t dma_mapped_buf,
-			     size_t size, u16 send_type);
 int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
 				  unsigned int req_id,
 				  unsigned int index,
@@ -581,4 +572,29 @@ void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
 int ipu6_isys_isr_one(struct ipu6_bus_device *adev);
 irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev);
 
+int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
+			     const unsigned int stream_handle,
+			     struct isys_fw_msgs *msg);
+int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
+			      const unsigned int stream_handle);
+int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
+			      const unsigned int stream_handle);
+int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
+			      const unsigned int stream_handle,
+			      struct isys_fw_msgs *msg, bool capture);
+int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
+				const unsigned int stream_handle,
+				struct isys_fw_msgs *msg);
+int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+				    struct isys_fw_msgs *msg);
+void
+ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+			     struct ipu6_isys_stream *stream,
+			     struct ipu6_isys_buffer_list *bl);
+void
+ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *set);
+void
+ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *set,
+				 unsigned int outputs);
+
 #endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 529973860e9e..9f6f283600c8 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -233,58 +233,6 @@ static int buffer_list_get(struct ipu6_isys_stream *stream,
 	return 0;
 }
 
-static void
-ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
-				  struct ipu6_fw_isys_frame_buff_set_abi *set)
-{
-	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
-	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
-	struct ipu6_isys_video_buffer *ivb =
-		vb2_buffer_to_ipu6_isys_video_buffer(vvb);
-
-	set->output_pins[aq->fw_output].addr = ivb->dma_addr;
-	set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
-}
-
-/*
- * Convert a buffer list to a isys fw ABI framebuffer set. The
- * buffer list is not modified.
- */
-#define IPU6_ISYS_FRAME_NUM_THRESHOLD  (30)
-void
-ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
-			      struct ipu6_isys_stream *stream,
-			      struct ipu6_isys_buffer_list *bl)
-{
-	struct ipu6_isys_buffer *ib;
-
-	WARN_ON(!bl->nbufs);
-
-	set->send_irq_sof = 1;
-	set->send_resp_sof = 1;
-	set->send_irq_eof = 0;
-	set->send_resp_eof = 0;
-
-	if (stream->streaming)
-		set->send_irq_capture_ack = 0;
-	else
-		set->send_irq_capture_ack = 1;
-	set->send_irq_capture_done = 0;
-
-	set->send_resp_capture_ack = 1;
-	set->send_resp_capture_done = 1;
-	if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {
-		set->send_resp_capture_ack = 0;
-		set->send_resp_capture_done = 0;
-	}
-
-	list_for_each_entry(ib, &bl->head, head) {
-		struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
-
-		ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
-	}
-}
-
 /* Start streaming for real. The buffer list must be available. */
 static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
 				  struct ipu6_isys_buffer_list *bl)
@@ -304,9 +252,7 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
 	bl = &__bl;
 
 	do {
-		struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
 		struct isys_fw_msgs *msg;
-		u16 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE;
 
 		ret = buffer_list_get(stream, bl);
 		if (ret < 0)
@@ -316,16 +262,14 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
 		if (!msg)
 			return -ENOMEM;
 
-		buf = &msg->ipu6.frame;
-		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
-		ipu6_fw_isys_dump_frame_buff_set(dev, buf,
+		ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
+		ipu6_fw_isys_dump_frame_buff_set(dev, msg,
 						 stream->nr_output_pins);
 		ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,
 					    0);
-		ret = ipu6_fw_isys_complex_cmd(stream->isys,
-					       stream->stream_handle, buf,
-					       msg->dma_addr, sizeof(*buf),
-					       send_type);
+
+		ret = ipu6_fw_isys_stream_capture(stream->isys,
+						  stream->stream_handle, msg);
 	} while (!WARN_ON(ret));
 
 	return 0;
@@ -349,7 +293,6 @@ static void buf_queue(struct vb2_buffer *vb)
 		vb2_buffer_to_ipu6_isys_video_buffer(vvb);
 	struct ipu6_isys_buffer *ib = &ivb->ib;
 	struct device *dev = &av->isys->adev->auxdev.dev;
-	struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
 	struct ipu6_isys_stream *stream = av->stream;
 	struct ipu6_isys_buffer_list bl;
 	struct isys_fw_msgs *msg;
@@ -396,9 +339,8 @@ static void buf_queue(struct vb2_buffer *vb)
 		goto out;
 	}
 
-	buf = &msg->ipu6.frame;
-	ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
-	ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
+	ipu6_fw_isys_prepare_buf_set(msg, stream, &bl);
+	ipu6_fw_isys_dump_frame_buff_set(dev, msg, stream->nr_output_pins);
 
 	/*
 	 * We must queue the buffers in the buffer list to the
@@ -408,9 +350,8 @@ static void buf_queue(struct vb2_buffer *vb)
 	 */
 	ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
 
-	ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,
-				       buf, msg->dma_addr, sizeof(*buf),
-				       IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
+	ret = ipu6_fw_isys_stream_capture(stream->isys, stream->stream_handle,
+					  msg);
 	if (ret < 0)
 		dev_err(dev, "send stream capture failed\n");
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
index dec1fed44dd2..51de14183ccf 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
@@ -60,10 +60,6 @@ struct ipu6_isys_buffer_list {
 void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
 				 unsigned long op_flags,
 				 enum vb2_buffer_state state);
-void
-ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
-			      struct ipu6_isys_stream *stream,
-			      struct ipu6_isys_buffer_list *bl);
 void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
 			       struct ipu6_fw_isys_resp_info_abi *info);
 int ipu6_isys_queue_init(struct ipu6_isys_queue *aq);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index fabea6a75d7d..a6e50263f8da 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -450,115 +450,28 @@ static void put_stream_opened(struct ipu6_isys_video *av)
 	spin_unlock_irqrestore(&av->isys->streams_lock, flags);
 }
 
-static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
-				struct ipu6_fw_isys_stream_cfg_data_abi *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 v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
-	struct ipu6_fw_isys_input_pin_info_abi *input_pin;
-	struct ipu6_fw_isys_output_pin_info_abi *output_pin;
-	struct ipu6_isys_stream *stream = av->stream;
-	struct ipu6_isys_queue *aq = &av->aq;
-	struct v4l2_mbus_framefmt fmt;
-	const struct ipu6_isys_pixelformat *pfmt =
-		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
-	struct v4l2_rect v4l2_crop;
-	struct ipu6_isys *isys = av->isys;
-	int input_pins = cfg->nof_input_pins++;
-	int output_pins;
-	u32 src_stream;
-
-	src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
-	fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
-	v4l2_crop = *v4l2_subdev_state_get_crop(state, src_pad->index, src_stream);
-
-	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->bits_per_pix = pfmt->bpp_packed;
-	input_pin->mapped_dt = 0x40; /* invalid mipi data type */
-	input_pin->mipi_decompression = 0;
-	input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
-	input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
-		IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
-		IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
-	input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
-
-	output_pins = cfg->nof_output_pins++;
-	aq->fw_output = output_pins;
-	stream->output_pins_queue[output_pins] = aq;
-
-	output_pin = &cfg->output_pins[output_pins];
-	output_pin->input_pin_id = input_pins;
-	output_pin->output_res.width = ipu6_isys_get_frame_width(av);
-	output_pin->output_res.height = ipu6_isys_get_frame_height(av);
-
-	output_pin->stride = ipu6_isys_get_bytes_per_line(av);
-	if (pfmt->bpp != pfmt->bpp_packed)
-		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
-	else
-		output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
-	output_pin->ft = pfmt->css_pixelformat;
-	output_pin->send_irq = 1;
-	memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
-	output_pin->s2m_pixel_soc_pixel_remapping =
-		S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
-	output_pin->csi_be_soc_pixel_remapping =
-		CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
-
-	output_pin->snoopable = true;
-	output_pin->error_handling_enable = false;
-	output_pin->sensor_type = isys->sensor_type++;
-	if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
-		isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
-
-	return 0;
-}
-
 static int start_stream_firmware(struct ipu6_isys_video *av,
 				 struct ipu6_isys_buffer_list *bl)
 {
-	struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
-	struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
 	struct ipu6_isys_stream *stream = av->stream;
 	struct device *dev = &av->isys->adev->auxdev.dev;
 	struct isys_fw_msgs *msg = NULL;
-	struct ipu6_isys_queue *aq;
 	int ret, retout, tout;
-	u16 send_type;
+	bool capture = bl ? true : false;
 
 	msg = ipu6_get_fw_msg_buf(stream);
 	if (!msg)
 		return -ENOMEM;
 
-	stream_cfg = &msg->ipu6.stream;
-	stream_cfg->src = stream->stream_source;
-	stream_cfg->vc = stream->vc;
-	stream_cfg->isl_use = 0;
-	stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
-
-	list_for_each_entry(aq, &stream->queues, node) {
-		struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
-
-		ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
-		if (ret < 0) {
-			ipu6_put_fw_msg_buf(av->isys, msg);
-			return ret;
-		}
+	ret = ipu6_fw_isys_prepare_stream_cfg(av, msg);
+	if (ret < 0) {
+		ipu6_put_fw_msg_buf(av->isys, msg);
+		return ret;
 	}
 
-	ipu6_fw_isys_dump_stream_cfg(dev, stream_cfg);
-
-	stream->nr_output_pins = stream_cfg->nof_output_pins;
-
 	reinit_completion(&stream->stream_open_completion);
 
-	ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
-				       stream_cfg, msg->dma_addr,
-				       sizeof(*stream_cfg),
-				       IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
+	ret = ipu6_fw_isys_stream_open(av->isys, stream->stream_handle, msg);
 	if (ret < 0) {
 		dev_err(dev, "can't open stream (%d)\n", ret);
 		ipu6_put_fw_msg_buf(av->isys, msg);
@@ -590,26 +503,16 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 			ret = -ENOMEM;
 			goto out_put_stream_opened;
 		}
-		buf = &msg->ipu6.frame;
-		ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
+
+		ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
 		ipu6_isys_buffer_list_queue(bl,
 					    IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
 	}
 
 	reinit_completion(&stream->stream_start_completion);
 
-	if (bl) {
-		send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
-		ipu6_fw_isys_dump_frame_buff_set(dev, buf,
-						 stream_cfg->nof_output_pins);
-		ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
-					       buf, msg->dma_addr,
-					       sizeof(*buf), send_type);
-	} else {
-		send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
-		ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
-					      send_type);
-	}
+	ret = ipu6_fw_isys_stream_start(av->isys, stream->stream_handle, msg,
+					capture);
 
 	if (ret < 0) {
 		dev_err(dev, "can't start streaming (%d)\n", ret);
@@ -635,9 +538,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 out_stream_close:
 	reinit_completion(&stream->stream_close_completion);
 
-	retout = ipu6_fw_isys_simple_cmd(av->isys,
-					 stream->stream_handle,
-					 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
+	retout = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
 	if (retout < 0) {
 		dev_dbg(dev, "can't close stream (%d)\n", retout);
 		goto out_put_stream_opened;
@@ -666,9 +567,7 @@ static void stop_streaming_firmware(struct ipu6_isys_video *av)
 
 	reinit_completion(&stream->stream_stop_completion);
 
-	ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
-				      IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
-
+	ret = ipu6_fw_isys_stream_flush(av->isys, stream->stream_handle);
 	if (ret < 0) {
 		dev_err(dev, "can't stop stream (%d)\n", ret);
 		return;
@@ -692,8 +591,7 @@ static void close_streaming_firmware(struct ipu6_isys_video *av)
 
 	reinit_completion(&stream->stream_close_completion);
 
-	ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
-				      IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
+	ret = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
 	if (ret < 0) {
 		dev_err(dev, "can't close stream (%d)\n", ret);
 		return;
-- 
2.55.0


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

* [PATCH v2 21/44] media: ipu6: Add isys firmware ops
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (19 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality Antti Laakso
                   ` (22 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Add struct for ipu6 firmware ops. This is a preparation to
add support for ipu7 firmware communication.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-bus.h       |  3 +
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c   | 71 +++++++++++--------
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.h   | 38 +---------
 .../media/pci/intel/ipu6/ipu6-isys-queue.c    | 24 ++++---
 .../media/pci/intel/ipu6/ipu6-isys-video.c    | 35 +++++----
 drivers/media/pci/intel/ipu6/ipu6-isys.c      |  1 +
 drivers/media/pci/intel/ipu6/ipu6-isys.h      | 32 +++++++++
 7 files changed, 116 insertions(+), 88 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index a08c5468d536..62aa2b090699 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -37,6 +37,7 @@ struct ipu6_auxdrv_data {
 	irqreturn_t (*isr)(struct ipu6_bus_device *adev);
 	irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);
 	bool wake_isr_thread;
+	const struct ipu6_fw_isys_ops *fw_ops;
 };
 
 #define to_ipu6_bus_device(_dev) \
@@ -45,6 +46,8 @@ struct ipu6_auxdrv_data {
 	container_of(_auxdev, struct ipu6_bus_device, auxdev)
 #define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
 
+extern const struct ipu6_fw_isys_ops ipu6_fw_isys_ops;
+
 struct ipu6_bus_device *
 ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
 			   void *pdata, const struct ipu6_buttress_ctrl *ctrl,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 9256ea3b68c1..4ee5137f310e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -126,7 +126,7 @@ static int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
 	return 0;
 }
 
-int ipu6_fw_isys_close(struct ipu6_isys *isys)
+static int ipu6_fw_isys_close(struct ipu6_isys *isys)
 {
 	struct device *dev = &isys->adev->auxdev.dev;
 	int retry = IPU6_ISYS_CLOSE_RETRY;
@@ -165,7 +165,7 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
 	return ret;
 }
 
-void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
+static void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
 {
 	int ret;
 
@@ -316,7 +316,7 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
 	return 0;
 }
 
-int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
+static int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 {
 	struct device *dev = &isys->adev->auxdev.dev;
 	int retry = IPU6_ISYS_OPEN_RETRY;
@@ -358,18 +358,19 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 	return ret;
 }
 
-struct ipu6_fw_isys_resp_info_abi *
+static struct ipu6_fw_isys_resp_info_abi *
 ipu6_fw_isys_get_resp(struct ipu6_isys *isys)
 {
 	return ipu6_recv_get_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 }
 
-void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
+static void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
 {
 	ipu6_recv_put_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
 }
 
-void ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *msg)
+static void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
+					 struct isys_fw_msgs *msg)
 {
 	struct ipu6_fw_isys_stream_cfg_data_abi *cfg = &msg->ipu6.stream;
 	unsigned int i;
@@ -446,9 +447,9 @@ void ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *msg)
 	dev_dbg(dev, "-----------------------------------------------------\n");
 }
 
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *msg,
-				 unsigned int outputs)
+static void
+ipu6_fw_isys_dump_frame_buf_set(struct device *dev, struct isys_fw_msgs *msg,
+				unsigned int outputs)
 {
 	struct ipu6_fw_isys_frame_buff_set_abi *buf;
 	unsigned int i;
@@ -820,8 +821,8 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
 	return 0;
 }
 
-int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
-				    struct isys_fw_msgs *msg)
+static int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+					   struct isys_fw_msgs *msg)
 {
 	struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
 	struct device *dev = &av->isys->adev->auxdev.dev;
@@ -850,9 +851,9 @@ int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
 	return 0;
 }
 
-int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
-			     const unsigned int stream_handle,
-			     struct isys_fw_msgs *msg)
+static int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
+				    const unsigned int stream_handle,
+				    struct isys_fw_msgs *msg)
 {
 	return ipu6_fw_isys_complex_cmd(isys, stream_handle,
 				       &msg->ipu6.stream, msg->dma_addr,
@@ -860,23 +861,23 @@ int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
 				       IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
 }
 
-int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
-			      const unsigned int stream_handle)
+static int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
+				     const unsigned int stream_handle)
 {
 	return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
 					IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
 }
 
-int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
-			      const unsigned int stream_handle)
+static int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
+				     const unsigned int stream_handle)
 {
 	return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
 					IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
 }
 
-int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
-			      const unsigned int stream_handle,
-			      struct isys_fw_msgs *msg, bool capture)
+static int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
+				     const unsigned int stream_handle,
+				     struct isys_fw_msgs *msg, bool capture)
 {
 	u16 cmd_type;
 
@@ -890,9 +891,9 @@ int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
 					sizeof(msg->ipu6.stream), cmd_type);
 }
 
-int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
-				const unsigned int stream_handle,
-				struct isys_fw_msgs *msg)
+static int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
+				       const unsigned int stream_handle,
+				       struct isys_fw_msgs *msg)
 {
 	return ipu6_fw_isys_complex_cmd(isys, stream_handle,
 					&msg->ipu6.stream, msg->dma_addr,
@@ -918,10 +919,9 @@ ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
  * buffer list is not modified.
  */
 #define IPU6_ISYS_FRAME_NUM_THRESHOLD  (30)
-void
-ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
-			     struct ipu6_isys_stream *stream,
-			     struct ipu6_isys_buffer_list *bl)
+static void ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+					 struct ipu6_isys_stream *stream,
+					 struct ipu6_isys_buffer_list *bl)
 {
 	struct ipu6_fw_isys_frame_buff_set_abi *set = &msg->ipu6.frame;
 	struct ipu6_isys_buffer *ib;
@@ -952,3 +952,18 @@ ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
 		ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
 	}
 }
+
+const struct ipu6_fw_isys_ops ipu6_fw_isys_ops = {
+	.init = ipu6_fw_isys_init,
+	.close = ipu6_fw_isys_close,
+	.cleanup = ipu6_fw_isys_cleanup,
+	.prepare_stream_cfg = ipu6_fw_isys_prepare_stream_cfg,
+	.prepare_buf_set = ipu6_fw_isys_prepare_buf_set,
+	.stream_open = ipu6_fw_isys_stream_open,
+	.stream_start = ipu6_fw_isys_stream_start,
+	.stream_capture = ipu6_fw_isys_stream_capture,
+	.stream_flush = ipu6_fw_isys_stream_flush,
+	.stream_close = ipu6_fw_isys_stream_close,
+	.dump_stream_cfg = ipu6_fw_isys_dump_stream_cfg,
+	.dump_frame_buf_set = ipu6_fw_isys_dump_frame_buf_set,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index b589ae7fbd4e..2a679d995961 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -559,42 +559,10 @@ struct ipu6_fw_proxy_send_queue_token {
 	u32 value;
 };
 
-int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams);
-int ipu6_fw_isys_close(struct ipu6_isys *isys);
-int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
-				  unsigned int req_id,
-				  unsigned int index,
-				  unsigned int offset, u32 value);
-void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
-struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(struct ipu6_isys *isys);
-void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
+int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys, unsigned int req_id,
+				  unsigned int index, unsigned int offset,
+				  u32 value);
 int ipu6_isys_isr_one(struct ipu6_bus_device *adev);
 irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev);
 
-int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
-			     const unsigned int stream_handle,
-			     struct isys_fw_msgs *msg);
-int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
-			      const unsigned int stream_handle);
-int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
-			      const unsigned int stream_handle);
-int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
-			      const unsigned int stream_handle,
-			      struct isys_fw_msgs *msg, bool capture);
-int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
-				const unsigned int stream_handle,
-				struct isys_fw_msgs *msg);
-int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
-				    struct isys_fw_msgs *msg);
-void
-ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
-			     struct ipu6_isys_stream *stream,
-			     struct ipu6_isys_buffer_list *bl);
-void
-ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *set);
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *set,
-				 unsigned int outputs);
-
 #endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 9f6f283600c8..4cb1741445c6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -237,8 +237,10 @@ static int buffer_list_get(struct ipu6_isys_stream *stream,
 static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
 				  struct ipu6_isys_buffer_list *bl)
 {
+	struct ipu6_bus_device *adev = av->isys->adev;
+	const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
 	struct ipu6_isys_stream *stream = av->stream;
-	struct device *dev = &stream->isys->adev->auxdev.dev;
+	struct device *dev = &adev->auxdev.dev;
 	struct ipu6_isys_buffer_list __bl;
 	int ret;
 
@@ -262,14 +264,13 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
 		if (!msg)
 			return -ENOMEM;
 
-		ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
-		ipu6_fw_isys_dump_frame_buff_set(dev, msg,
-						 stream->nr_output_pins);
+		fw_ops->prepare_buf_set(msg, stream, bl);
+		fw_ops->dump_frame_buf_set(dev, msg, stream->nr_output_pins);
 		ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,
 					    0);
 
-		ret = ipu6_fw_isys_stream_capture(stream->isys,
-						  stream->stream_handle, msg);
+		ret = fw_ops->stream_capture(stream->isys,
+					     stream->stream_handle, msg);
 	} while (!WARN_ON(ret));
 
 	return 0;
@@ -288,11 +289,13 @@ static void buf_queue(struct vb2_buffer *vb)
 {
 	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
 	struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
+	struct ipu6_bus_device *adev = av->isys->adev;
+	const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
 	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
 	struct ipu6_isys_video_buffer *ivb =
 		vb2_buffer_to_ipu6_isys_video_buffer(vvb);
 	struct ipu6_isys_buffer *ib = &ivb->ib;
-	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct device *dev = &adev->auxdev.dev;
 	struct ipu6_isys_stream *stream = av->stream;
 	struct ipu6_isys_buffer_list bl;
 	struct isys_fw_msgs *msg;
@@ -339,8 +342,8 @@ static void buf_queue(struct vb2_buffer *vb)
 		goto out;
 	}
 
-	ipu6_fw_isys_prepare_buf_set(msg, stream, &bl);
-	ipu6_fw_isys_dump_frame_buff_set(dev, msg, stream->nr_output_pins);
+	fw_ops->prepare_buf_set(msg, stream, &bl);
+	fw_ops->dump_frame_buf_set(dev, msg, stream->nr_output_pins);
 
 	/*
 	 * We must queue the buffers in the buffer list to the
@@ -350,8 +353,7 @@ static void buf_queue(struct vb2_buffer *vb)
 	 */
 	ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
 
-	ret = ipu6_fw_isys_stream_capture(stream->isys, stream->stream_handle,
-					  msg);
+	ret = fw_ops->stream_capture(stream->isys, stream->stream_handle, msg);
 	if (ret < 0)
 		dev_err(dev, "send stream capture failed\n");
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index a6e50263f8da..803450b0156e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -453,8 +453,10 @@ static void put_stream_opened(struct ipu6_isys_video *av)
 static int start_stream_firmware(struct ipu6_isys_video *av,
 				 struct ipu6_isys_buffer_list *bl)
 {
+	struct ipu6_bus_device *adev = av->isys->adev;
+	const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
 	struct ipu6_isys_stream *stream = av->stream;
-	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct device *dev = &adev->auxdev.dev;
 	struct isys_fw_msgs *msg = NULL;
 	int ret, retout, tout;
 	bool capture = bl ? true : false;
@@ -463,7 +465,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 	if (!msg)
 		return -ENOMEM;
 
-	ret = ipu6_fw_isys_prepare_stream_cfg(av, msg);
+	ret = fw_ops->prepare_stream_cfg(av, msg);
 	if (ret < 0) {
 		ipu6_put_fw_msg_buf(av->isys, msg);
 		return ret;
@@ -471,7 +473,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 
 	reinit_completion(&stream->stream_open_completion);
 
-	ret = ipu6_fw_isys_stream_open(av->isys, stream->stream_handle, msg);
+	ret = fw_ops->stream_open(av->isys, stream->stream_handle, msg);
 	if (ret < 0) {
 		dev_err(dev, "can't open stream (%d)\n", ret);
 		ipu6_put_fw_msg_buf(av->isys, msg);
@@ -504,15 +506,15 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 			goto out_put_stream_opened;
 		}
 
-		ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
+		fw_ops->prepare_buf_set(msg, stream, bl);
 		ipu6_isys_buffer_list_queue(bl,
 					    IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
 	}
 
 	reinit_completion(&stream->stream_start_completion);
 
-	ret = ipu6_fw_isys_stream_start(av->isys, stream->stream_handle, msg,
-					capture);
+	ret = fw_ops->stream_start(av->isys, stream->stream_handle, msg,
+				   capture);
 
 	if (ret < 0) {
 		dev_err(dev, "can't start streaming (%d)\n", ret);
@@ -538,7 +540,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 out_stream_close:
 	reinit_completion(&stream->stream_close_completion);
 
-	retout = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
+	retout = fw_ops->stream_close(av->isys, stream->stream_handle);
 	if (retout < 0) {
 		dev_dbg(dev, "can't close stream (%d)\n", retout);
 		goto out_put_stream_opened;
@@ -561,13 +563,15 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
 
 static void stop_streaming_firmware(struct ipu6_isys_video *av)
 {
-	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu6_bus_device *adev = av->isys->adev;
+	const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
+	struct device *dev = &adev->auxdev.dev;
 	struct ipu6_isys_stream *stream = av->stream;
 	int ret, tout;
 
 	reinit_completion(&stream->stream_stop_completion);
 
-	ret = ipu6_fw_isys_stream_flush(av->isys, stream->stream_handle);
+	ret = fw_ops->stream_flush(av->isys, stream->stream_handle);
 	if (ret < 0) {
 		dev_err(dev, "can't stop stream (%d)\n", ret);
 		return;
@@ -585,13 +589,15 @@ static void stop_streaming_firmware(struct ipu6_isys_video *av)
 
 static void close_streaming_firmware(struct ipu6_isys_video *av)
 {
+	struct ipu6_bus_device *adev = av->isys->adev;
+	const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
 	struct ipu6_isys_stream *stream = av->stream;
-	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct device *dev = &adev->auxdev.dev;
 	int ret, tout;
 
 	reinit_completion(&stream->stream_close_completion);
 
-	ret = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
+	ret = fw_ops->stream_close(av->isys, stream->stream_handle);
 	if (ret < 0) {
 		dev_err(dev, "can't close stream (%d)\n", ret);
 		return;
@@ -990,6 +996,7 @@ static const struct v4l2_file_operations isys_fops = {
 int ipu6_isys_fw_open(struct ipu6_isys *isys)
 {
 	struct ipu6_bus_device *adev = isys->adev;
+	const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
 	const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
 	int ret;
 
@@ -1018,10 +1025,10 @@ int ipu6_isys_fw_open(struct ipu6_isys *isys)
 		 * restarting isys we can safely delete old context.
 		 */
 		dev_warn(&adev->auxdev.dev, "clearing old context\n");
-		ipu6_fw_isys_cleanup(isys);
+		fw_ops->cleanup(isys);
 	}
 
-	ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);
+	ret = fw_ops->init(isys, ipdata->num_parallel_streams);
 	if (ret < 0)
 		goto out;
 
@@ -1044,7 +1051,7 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys)
 
 	isys->ref_count--;
 	if (!isys->ref_count) {
-		ipu6_fw_isys_close(isys);
+		isys->adev->auxdrv_data->fw_ops->close(isys);
 		if (isys->fwctx) {
 			isys->need_reset = true;
 			dev_warn(&isys->adev->auxdev.dev,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index bb3c0d6bc6c9..159e769931b7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1068,6 +1068,7 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
 	.isr = ipu6_isys_isr,
 	.isr_threaded = NULL,
 	.wake_isr_thread = false,
+	.fw_ops = &ipu6_fw_isys_ops,
 };
 
 static const struct auxiliary_device_id ipu6_isys_id_table[] = {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index f39566513a87..fa9bc2730d64 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -174,6 +174,38 @@ struct isys_fw_msgs {
 	dma_addr_t dma_addr;
 };
 
+struct ipu6_fw_isys_ops {
+	int (*init)(struct ipu6_isys *isys, unsigned int num_streams);
+	int (*close)(struct ipu6_isys *isys);
+	int (*send_cmd)(struct ipu6_isys *isys,
+			const unsigned int stream_handle,
+			void *cpu_mapped_buf,
+			dma_addr_t dma_mapped_buf,
+			size_t size, u16 send_type);
+	void (*cleanup)(struct ipu6_isys *isys);
+	int (*prepare_stream_cfg)(struct ipu6_isys_video *av,
+				  struct isys_fw_msgs *msg);
+	void (*prepare_buf_set)(struct isys_fw_msgs *msg,
+				struct ipu6_isys_stream *stream,
+				struct ipu6_isys_buffer_list *bl);
+	int (*stream_open)(struct ipu6_isys *isys,
+			   const unsigned int stream_handle,
+			   struct isys_fw_msgs *msg);
+	int (*stream_start)(struct ipu6_isys *isys,
+			    const unsigned int stream_handle,
+			    struct isys_fw_msgs *msg, bool capture);
+	int (*stream_capture)(struct ipu6_isys *isys,
+			      const unsigned int stream_handle,
+			      struct isys_fw_msgs *msg);
+	int (*stream_flush)(struct ipu6_isys *isys,
+			    const unsigned int stream_handle);
+	int (*stream_close)(struct ipu6_isys *isys,
+			    const unsigned int stream_handle);
+	void (*dump_stream_cfg)(struct device *dev, struct isys_fw_msgs *msg);
+	void (*dump_frame_buf_set)(struct device *dev, struct isys_fw_msgs *msg,
+				   unsigned int outputs);
+};
+
 struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream);
 void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg);
 void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
-- 
2.55.0


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

* [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (20 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 21/44] media: ipu6: Add isys firmware ops Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods Antti Laakso
                   ` (21 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 firmware start/stop sequence differs from ipu6. Add
ipu7-specific functions to handle this.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu7-boot.c      | 405 ++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu7-boot.h      |  46 ++
 .../media/pci/intel/ipu6/ipu7-platform-regs.h |  12 +
 3 files changed, 463 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-boot.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-boot.h
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-platform-regs.h

diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.c b/drivers/media/pci/intel/ipu6/ipu7-boot.c
new file mode 100644
index 000000000000..5bd5281ec107
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-boot.c
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 - 2026 Intel Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+
+#include "ipu6.h"
+#include "ipu6-bus.h"
+#include "ipu6-buttress.h"
+#include "ipu6-dma.h"
+#include "ipu6-isys.h"
+#include "ipu6-platform-buttress-regs.h"
+#include "ipu7-boot.h"
+#include "ipu7-platform-regs.h"
+
+#define IPU7_FW_START_STOP_TIMEOUT		2000
+#define IPU7_BOOT_CELL_RESET_TIMEOUT		(2 * USEC_PER_SEC)
+#define IPU7_BOOT_STATE_CRITICAL(s)		(((s) & 0xffff0000U) == 0xdead0000U)
+#define IPU7_BOOT_STATE_READY(s)		((s) == 0x57a7e100U)
+#define IPU7_BOOT_STATE_INACTIVE(s)		((s) == 0x57a7e300U)
+#define IPU7_BUTTRESS_REG_FW_BOOT_PARAMS0				0x4000
+#define IPU7_BUTTRESS_FW_BOOT_PARAMS_ENTRY(i) \
+	(IPU7_BUTTRESS_REG_FW_BOOT_PARAMS0 + ((i) * 4U))
+
+struct boot_regs {
+	u32 base;
+	u32 dmem_address;
+	u32 status_ctrl_reg;
+	u32 fw_start_address_reg;
+	u32 fw_code_base_reg;
+};
+
+enum ipu7_boot_reg_id {
+	IPU7_FW_BOOT_CONFIG_ID = 0,
+	IPU7_FW_BOOT_STATE_ID = 1,
+	IPU7_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID = 2,
+	IPU7_FW_BOOT_UNTRUSTED_ADDR_MIN_ID = 3,
+	IPU7_FW_BOOT_MESSAGING_VERSION_ID = 4,
+	IPU7_FW_BOOT_ID_MAX,
+};
+
+enum ipu7_boot_state {
+	IPU7_FW_BOOT_STATE_UNINIT = 0x57a7e000U,
+	IPU7_FW_BOOT_STATE_READY = 0x57a7e100U,
+	IPU7_FW_BOOT_STATE_SHUTDOWN_CMD = 0x57a7f001U,
+	IPU7_FW_BOOT_STATE_INACTIVE = 0x57a7e300U,
+};
+
+static const struct boot_regs boot_regs[IPU_SUBSYS_NUM] = {
+	[IPU_ISYS] = {
+		.dmem_address = IPU7_ISYS_DMEM_OFFSET,
+		.status_ctrl_reg = IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS,
+		.fw_start_address_reg = IPU7_BUTTRESS_REG_ISYS_UCX_START_ADDR,
+		.fw_code_base_reg = IPU7_IS_UC_CTRL_BASE
+	},
+	[IPU_PSYS] = {
+		.dmem_address = IPU7_PSYS_DMEM_OFFSET,
+		.status_ctrl_reg = IPU7_BUTTRESS_REG_PSYS_UCX_CTRL_STATUS,
+		.fw_start_address_reg = IPU7_BUTTRESS_REG_PSYS_UCX_START_ADDR,
+		.fw_code_base_reg = IPU7_PS_UC_CTRL_BASE
+	}
+};
+
+static u32 get_fw_boot_reg_addr(const struct ipu6_bus_device *adev,
+				enum ipu7_boot_reg_id reg)
+{
+	u32 base = (adev->ctrl->subsys_id == IPU_ISYS) ?
+				0U : (u32)IPU7_FW_BOOT_ID_MAX;
+
+	return IPU7_BUTTRESS_FW_BOOT_PARAMS_ENTRY(base + (u32)reg);
+}
+
+static void write_fw_boot_param(const struct ipu6_bus_device *adev,
+				enum ipu7_boot_reg_id reg,
+				u32 val)
+{
+	void __iomem *base = adev->isp->base;
+
+	dev_dbg(&adev->auxdev.dev,
+		"write boot param reg: %d addr: %x val: 0x%x\n",
+		reg, get_fw_boot_reg_addr(adev, reg), val);
+	writel(val, base + get_fw_boot_reg_addr(adev, reg));
+}
+
+static u32 read_fw_boot_param(const struct ipu6_bus_device *adev,
+			      enum ipu7_boot_reg_id reg)
+{
+	void __iomem *base = adev->isp->base;
+
+	return readl(base + get_fw_boot_reg_addr(adev, reg));
+}
+
+static int ipu7_boot_cell_reset(const struct ipu6_bus_device *adev)
+{
+	const struct device *dev = &adev->auxdev.dev;
+	const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+	u32 ucx_ctrl_status = regs->status_ctrl_reg;
+	u32 timeout = IPU7_BOOT_CELL_RESET_TIMEOUT;
+	void __iomem *base = adev->isp->base;
+	u32 val, val2;
+	int ret;
+
+	val = readl(base + ucx_ctrl_status);
+	val |= IPU7_UCX_CTL_RESET;
+	val &= ~IPU7_UCX_CTL_RUN;
+
+	writel(val, base + ucx_ctrl_status);
+
+	ret = readl_poll_timeout(base + ucx_ctrl_status, val2,
+				 (val2 & 0x3U) == (val & 0x3U), 100, timeout);
+	if (ret) {
+		dev_err(dev, "cell enter reset timeout. status: 0x%x\n", val2);
+		return -ETIMEDOUT;
+	}
+
+	val = readl(base + ucx_ctrl_status);
+	val &= ~(IPU7_UCX_CTL_RESET | IPU7_UCX_CTL_RUN);
+	writel(val, base + ucx_ctrl_status);
+
+	ret = readl_poll_timeout(base + ucx_ctrl_status, val2,
+				 (val2 & 0x3U) == (val & 0x3U), 100, timeout);
+	if (ret) {
+		dev_err(dev, "cell exit reset timeout. status: 0x%x\n", val2);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void ipu7_boot_cell_start(const struct ipu6_bus_device *adev)
+{
+	const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+	void __iomem *base = adev->isp->base;
+	u32 val;
+
+	val = readl(base + regs->status_ctrl_reg);
+	WARN_ON(val & (IPU7_UCX_CTL_RESET | IPU7_UCX_CTL_RUN));
+
+	val &= ~IPU7_UCX_CTL_RESET;
+	val |= IPU7_UCX_CTL_RUN;
+	writel(val, base + regs->status_ctrl_reg);
+}
+
+static void ipu7_boot_cell_stop(const struct ipu6_bus_device *adev)
+{
+	const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+	void __iomem *base = adev->isp->base;
+	u32 val;
+
+	val = readl(base + regs->status_ctrl_reg);
+	val &= ~IPU7_UCX_CTL_RUN;
+	writel(val, base + regs->status_ctrl_reg);
+
+	/* Wait for uC transactions complete */
+	usleep_range(10, 20);
+
+	val = readl(base + regs->status_ctrl_reg);
+	val |= IPU7_UCX_CTL_RESET;
+	writel(val, base + regs->status_ctrl_reg);
+}
+
+static int ipu7_boot_cell_init(const struct ipu6_bus_device *adev)
+{
+	const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	struct ipu7_fw_com_context *fwctx = isys->fwctx;
+	void __iomem *base = adev->isp->base;
+
+	writel(fwctx->fw_entry, base + regs->fw_start_address_reg);
+
+	return ipu7_boot_cell_reset(adev);
+}
+
+static void init_cfg_versions(struct ipu7_boot_abi_cfg *boot_cfg, u32 length, u8 major)
+{
+	boot_cfg->length = length;
+	boot_cfg->config_version.major = 1U;
+	boot_cfg->config_version.minor = 0U;
+	boot_cfg->config_version.subminor = 0U;
+	boot_cfg->config_version.patch = 0U;
+
+	boot_cfg->client_version_support.num_versions = 1U;
+	boot_cfg->client_version_support.versions[0].major = major;
+	boot_cfg->client_version_support.versions[0].minor = 0U;
+	boot_cfg->client_version_support.versions[0].subminor = 0U;
+	boot_cfg->client_version_support.versions[0].patch = 0U;
+}
+
+int ipu7_init_boot_config(struct ipu6_bus_device *adev,
+			  struct ipu7_fw_com_queue_config *qconfigs,
+			  int num_queues, u32 uc_freq,
+			  dma_addr_t subsys_config, u8 major)
+{
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	struct ipu7_fw_com_context *fwctx = isys->fwctx;
+	struct ipu7_boot_abi_cfg *boot_config;
+	struct ipu7_fw_com_queue_params_config *cfgs;
+	struct device *dev = &adev->auxdev.dev;
+	u32 total_queue_size_aligned = 0;
+	dma_addr_t queue_mem_dma_ptr;
+	void *queue_mem_ptr;
+	unsigned int i;
+
+	/* Allocate boot config. */
+	fwctx->boot_config_size =
+		sizeof(*cfgs) * num_queues + sizeof(*boot_config);
+	fwctx->boot_config = ipu6_dma_alloc(adev, fwctx->boot_config_size,
+					    &fwctx->boot_config_dma_addr,
+					    GFP_KERNEL, 0);
+	if (!fwctx->boot_config) {
+		dev_err(dev, "Failed to allocate boot config.\n");
+		return -ENOMEM;
+	}
+
+	boot_config = fwctx->boot_config;
+	memset(boot_config, 0, sizeof(*boot_config));
+	init_cfg_versions(boot_config, fwctx->boot_config_size, major);
+	boot_config->subsys_config = subsys_config;
+
+	boot_config->uc_tile_frequency = uc_freq;
+	boot_config->uc_tile_frequency_units = 0;
+	boot_config->fw_com_config.max_output_queues =
+		fwctx->num_output_queues;
+	boot_config->fw_com_config.max_input_queues =
+		fwctx->num_input_queues;
+
+	ipu6_dma_sync_single(adev, fwctx->boot_config_dma_addr,
+			     fwctx->boot_config_size);
+
+	for (i = 0; i < num_queues; i++) {
+		u32 queue_size = qconfigs[i].max_capacity *
+			qconfigs[i].token_size_in_bytes;
+
+		queue_size = ALIGN(queue_size, 64U);
+		total_queue_size_aligned += queue_size;
+		qconfigs[i].queue_size = queue_size;
+	}
+
+	/* Allocate queue memory */
+	fwctx->queue_mem = ipu6_dma_alloc(adev, total_queue_size_aligned,
+					  &fwctx->queue_mem_dma_addr,
+					  GFP_KERNEL, 0);
+	if (!fwctx->queue_mem) {
+		dev_err(dev, "Failed to allocate queue memory.\n");
+		return -ENOMEM;
+	}
+	fwctx->queue_mem_size = total_queue_size_aligned;
+
+	cfgs = ipu7_fw_com_get_queue_config(&boot_config->fw_com_config);
+	queue_mem_ptr = fwctx->queue_mem;
+	queue_mem_dma_ptr = fwctx->queue_mem_dma_addr;
+	for (i = 0; i < num_queues; i++) {
+		cfgs[i].token_array_mem = queue_mem_dma_ptr;
+		cfgs[i].max_capacity = qconfigs[i].max_capacity;
+		cfgs[i].token_size_in_bytes = qconfigs[i].token_size_in_bytes;
+		qconfigs[i].token_array_mem = queue_mem_ptr;
+		queue_mem_dma_ptr += qconfigs[i].queue_size;
+		queue_mem_ptr += qconfigs[i].queue_size;
+	}
+
+	ipu6_dma_sync_single(adev, fwctx->queue_mem_dma_addr,
+			     total_queue_size_aligned);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_init_boot_config, "INTEL_IPU6");
+
+void ipu7_release_boot_config(struct ipu6_bus_device *adev)
+{
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	struct ipu7_fw_com_context *fwctx;
+
+	if (!isys || !isys->fwctx)
+		return;
+
+	fwctx = isys->fwctx;
+
+	if (fwctx->queue_mem) {
+		ipu6_dma_free(adev, fwctx->queue_mem_size,
+			      fwctx->queue_mem,
+			      fwctx->queue_mem_dma_addr, 0);
+		fwctx->queue_mem = NULL;
+		fwctx->queue_mem_dma_addr = 0;
+	}
+
+	if (fwctx->boot_config) {
+		ipu6_dma_free(adev, fwctx->boot_config_size,
+			      fwctx->boot_config,
+			      fwctx->boot_config_dma_addr, 0);
+		fwctx->boot_config = NULL;
+		fwctx->boot_config_dma_addr = 0;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_release_boot_config, "INTEL_IPU6");
+
+int ipu7_boot_start_fw(const struct ipu6_bus_device *adev)
+{
+	const struct device *dev = &adev->auxdev.dev;
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	struct ipu7_fw_com_context *fwctx = isys->fwctx;
+	u32 timeout = IPU7_FW_START_STOP_TIMEOUT;
+	void __iomem *base = adev->isp->base;
+	u32 boot_state, last_boot_state;
+	u32 indices_addr, msg_ver, id;
+	int ret;
+
+	ret = ipu7_boot_cell_init(adev);
+	if (ret)
+		return ret;
+
+	/* store "uninit" state to boot state reg */
+	write_fw_boot_param(adev, IPU7_FW_BOOT_STATE_ID,
+			    IPU7_FW_BOOT_STATE_UNINIT);
+	/* Set registers to zero, recommended for diagnostics. */
+	write_fw_boot_param(adev,
+			    IPU7_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID, 0);
+	write_fw_boot_param(adev, IPU7_FW_BOOT_MESSAGING_VERSION_ID, 0);
+	/* store firmware configuration address */
+	write_fw_boot_param(adev, IPU7_FW_BOOT_CONFIG_ID,
+			    fwctx->boot_config_dma_addr);
+
+	ipu7_boot_cell_start(adev);
+
+	last_boot_state = IPU7_FW_BOOT_STATE_UNINIT;
+	while (timeout--) {
+		boot_state = read_fw_boot_param(adev,
+						IPU7_FW_BOOT_STATE_ID);
+		if (boot_state != last_boot_state) {
+			dev_dbg(dev, "boot state changed from 0x%x to 0x%x\n",
+				last_boot_state, boot_state);
+			last_boot_state = boot_state;
+		}
+		if (IPU7_BOOT_STATE_CRITICAL(boot_state) ||
+		    IPU7_BOOT_STATE_READY(boot_state))
+			break;
+		usleep_range(1000, 1200);
+	}
+
+	if (IPU7_BOOT_STATE_CRITICAL(boot_state)) {
+		dev_err(dev, "critical boot state error 0x%x\n", boot_state);
+		return -EINVAL;
+	} else if (!IPU7_BOOT_STATE_READY(boot_state)) {
+		dev_err(dev, "fw boot timeout. state: 0x%x\n", boot_state);
+		return -ETIMEDOUT;
+	}
+	dev_dbg(dev, "fw boot done.\n");
+
+	id = IPU7_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID;
+	indices_addr = read_fw_boot_param(adev, id);
+	fwctx->queue_indices = base + indices_addr;
+	dev_dbg(dev, "fw queue indices offset is 0x%x\n", indices_addr);
+
+	msg_ver = read_fw_boot_param(adev,
+				     IPU7_FW_BOOT_MESSAGING_VERSION_ID);
+	dev_dbg(dev, "ipu message version is 0x%08x\n", msg_ver);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_boot_start_fw, "INTEL_IPU6");
+
+int ipu7_boot_stop_fw(const struct ipu6_bus_device *adev)
+{
+	const struct device *dev = &adev->auxdev.dev;
+	u32 timeout = IPU7_FW_START_STOP_TIMEOUT;
+	u32 boot_state;
+
+	boot_state = read_fw_boot_param(adev, IPU7_FW_BOOT_STATE_ID);
+	if (IPU7_BOOT_STATE_CRITICAL(boot_state) ||
+	    !IPU7_BOOT_STATE_READY(boot_state)) {
+		dev_err(dev, "fw not ready for shutdown, state 0x%x\n",
+			boot_state);
+		return -EBUSY;
+	}
+
+	/* Issue shutdown to start shutdown process */
+	dev_dbg(dev, "stopping fw...\n");
+	write_fw_boot_param(adev, IPU7_FW_BOOT_STATE_ID,
+			    IPU7_FW_BOOT_STATE_SHUTDOWN_CMD);
+	while (timeout--) {
+		boot_state = read_fw_boot_param(adev,
+						IPU7_FW_BOOT_STATE_ID);
+		if (IPU7_BOOT_STATE_CRITICAL(boot_state) ||
+		    IPU7_BOOT_STATE_INACTIVE(boot_state))
+			break;
+		usleep_range(1000, 1200);
+	}
+
+	if (IPU7_BOOT_STATE_CRITICAL(boot_state)) {
+		dev_err(dev, "critical boot state error 0x%x\n", boot_state);
+		return -EINVAL;
+	} else if (!IPU7_BOOT_STATE_INACTIVE(boot_state)) {
+		dev_err(dev, "stop fw timeout. state: 0x%x\n", boot_state);
+		return -ETIMEDOUT;
+	}
+
+	ipu7_boot_cell_stop(adev);
+	dev_dbg(dev, "stop fw done.\n");
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_boot_stop_fw, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.h b/drivers/media/pci/intel/ipu6/ipu7-boot.h
new file mode 100644
index 000000000000..242ad70a385d
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-boot.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_BOOT_H
+#define IPU7_BOOT_H
+
+#include "ipu7-fw-com.h"
+
+#define IPU7_BOOT_MSG_VER_MAX_ENTRIES	3U
+
+struct ipu7_boot_abi_version {
+	u8 patch;
+	u8 subminor;
+	u8 minor;
+	u8 major;
+};
+
+struct ipu7_boot_abi_msg_versions {
+	u8 num_versions;
+	u8 reserved[3];
+	struct ipu7_boot_abi_version versions[IPU7_BOOT_MSG_VER_MAX_ENTRIES];
+};
+
+struct ipu7_boot_abi_cfg {
+	u32 length;
+	struct ipu7_boot_abi_version config_version;
+	struct ipu7_boot_abi_msg_versions client_version_support;
+	u32 pkg_dir;
+	u32 subsys_config;
+	u32 uc_tile_frequency;
+	u16 checksum;
+	u8 uc_tile_frequency_units;
+	u8 padding[1];
+	u32 reserved[58];
+	struct ipu7_fw_com_config fw_com_config;
+} __packed;
+
+int ipu7_init_boot_config(struct ipu6_bus_device *adev,
+			  struct ipu7_fw_com_queue_config *qconfigs,
+			  int num_queues, u32 uc_freq,
+			  dma_addr_t subsys_config, u8 major);
+void ipu7_release_boot_config(struct ipu6_bus_device *adev);
+int ipu7_boot_start_fw(const struct ipu6_bus_device *adev);
+int ipu7_boot_stop_fw(const struct ipu6_bus_device *adev);
+
+#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
new file mode 100644
index 000000000000..3ca9d65e58b9
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_PLATFORM_REGS_H
+#define IPU7_PLATFORM_REGS_H
+
+#define IPU7_IS_UC_CTRL_BASE                   0x230000
+#define IPU7_ISYS_DMEM_OFFSET                  0x200000
+#define IPU7_PS_UC_CTRL_BASE                   0x130000
+#define IPU7_PSYS_DMEM_OFFSET                  0x100000
+
+#endif
-- 
2.55.0


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

* [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (21 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops Antti Laakso
                   ` (20 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The get/put token methods read/write to ipu7 firmware message queues.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/Makefile      |  4 +-
 drivers/media/pci/intel/ipu6/ipu7-fw-com.c | 74 ++++++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 51 +++++++++++++++
 3 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-com.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-com.h

diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index c0daf0995b22..406e2e19df17 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -8,7 +8,9 @@ intel-ipu6-y			:= ipu6.o \
 				ipu7-mmu-hw.o \
 				ipu6-buttress.o \
 				ipu6-cpd.o \
-				ipu6-fw-com.o
+				ipu6-fw-com.o \
+				ipu7-fw-com.o \
+				ipu7-boot.o
 
 obj-$(CONFIG_VIDEO_INTEL_IPU6)	+= intel-ipu6.o
 
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.c b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
new file mode 100644
index 000000000000..7dd1e683aa92
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include <linux/io.h>
+
+#include "ipu7-fw-com.h"
+
+static void __iomem *ipu7_fw_com_get_indices(struct ipu7_fw_com_context *ctx,
+					     u32 q)
+{
+	return ctx->queue_indices + (q * sizeof(struct ipu7_fw_com_queue_indices));
+}
+
+void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q)
+{
+	struct ipu7_fw_com_queue_config *queue_params = &ctx->queue_configs[q];
+	void __iomem *queue_indices = ipu7_fw_com_get_indices(ctx, q);
+	u32 write_index = readl(queue_indices +
+				offsetof(struct ipu7_fw_com_queue_indices,
+					 write_index));
+	u32 read_index = readl(queue_indices +
+			       offsetof(struct ipu7_fw_com_queue_indices,
+					read_index));
+	void *token = NULL;
+
+	if (q < ctx->num_output_queues) {
+		/* Output queue */
+		bool empty = (write_index == read_index);
+
+		if (!empty)
+			token = queue_params->token_array_mem +
+				read_index *
+				queue_params->token_size_in_bytes;
+	} else {
+		/* Input queue */
+		bool full = (read_index == ((write_index + 1U) %
+					    (u32)queue_params->max_capacity));
+
+		if (!full)
+			token = queue_params->token_array_mem +
+				write_index * queue_params->token_size_in_bytes;
+	}
+	return token;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_fw_com_get_token, "INTEL_IPU6");
+
+void ipu7_fw_com_put_token(struct ipu7_fw_com_context *ctx, int q)
+{
+	struct ipu7_fw_com_queue_config *queue_params = &ctx->queue_configs[q];
+	void __iomem *queue_indices = ipu7_fw_com_get_indices(ctx, q);
+	u32 offset, index;
+
+	if (q < ctx->num_output_queues)
+		/* Output queue */
+		offset = offsetof(struct ipu7_fw_com_queue_indices, read_index);
+
+	else
+		/* Input queue */
+		offset = offsetof(struct ipu7_fw_com_queue_indices, write_index);
+
+	index = readl(queue_indices + offset);
+	writel((index + 1U) % queue_params->max_capacity,
+	       queue_indices + offset);
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_fw_com_put_token, "INTEL_IPU6");
+
+struct ipu7_fw_com_queue_params_config *
+ipu7_fw_com_get_queue_config(struct ipu7_fw_com_config *config)
+{
+	return (struct ipu7_fw_com_queue_params_config *)(&config[1]);
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_fw_com_get_queue_config, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
new file mode 100644
index 000000000000..10c09e759bed
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_FW_COM_H
+#define IPU7_FW_COM_H
+
+#include <linux/types.h>
+
+struct ipu7_fw_com_queue_config {
+	void *token_array_mem;
+	u32 queue_size;
+	u16 token_size_in_bytes;
+	u16 max_capacity;
+};
+
+struct ipu7_fw_com_context {
+	u16 num_input_queues;
+	u16 num_output_queues;
+	struct ipu7_fw_com_queue_config *queue_configs;
+	void __iomem *queue_indices;
+	dma_addr_t queue_mem_dma_addr;
+	void *queue_mem;
+	u32 queue_mem_size;
+	struct ipu7_boot_abi_cfg *boot_config;
+	dma_addr_t boot_config_dma_addr;
+	u32 boot_config_size;
+	u32 fw_entry;
+};
+
+struct ipu7_fw_com_queue_params_config {
+	u32 token_array_mem;
+	u16 token_size_in_bytes;
+	u16 max_capacity;
+};
+
+struct ipu7_fw_com_config {
+	u16 max_output_queues;
+	u16 max_input_queues;
+};
+
+struct ipu7_fw_com_queue_indices {
+	u32 read_index;
+	u32 write_index;
+};
+
+void ipu7_fw_com_put_token(struct ipu7_fw_com_context *ctx, int q);
+void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q);
+struct ipu7_fw_com_queue_params_config *
+ipu7_fw_com_get_queue_config(struct ipu7_fw_com_config *config);
+
+#endif /* IPU7_FW_COM_H */
-- 
2.55.0


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

* [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (22 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions Antti Laakso
                   ` (19 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 isys firmware functions handle messaging
with ipu7 hardware.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/Makefile         |   1 +
 drivers/media/pci/intel/ipu6/ipu6-bus.h       |   2 +
 drivers/media/pci/intel/ipu6/ipu6-fw-isys.c   |   3 +-
 .../media/pci/intel/ipu6/ipu6-isys-queue.c    |   2 +-
 .../media/pci/intel/ipu6/ipu6-isys-queue.h    |   2 +
 .../media/pci/intel/ipu6/ipu6-isys-video.c    |   1 +
 .../media/pci/intel/ipu6/ipu6-isys-video.h    |   1 +
 drivers/media/pci/intel/ipu6/ipu6-isys.c      |  15 +-
 drivers/media/pci/intel/ipu6/ipu6-isys.h      |  13 +-
 drivers/media/pci/intel/ipu6/ipu7-fw-com.h    |   2 +
 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c   | 465 ++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h   | 258 ++++++++++
 12 files changed, 757 insertions(+), 8 deletions(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h

diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 406e2e19df17..66986d5709ae 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_VIDEO_INTEL_IPU6)	+= intel-ipu6.o
 intel-ipu6-isys-y		:= ipu6-isys.o \
 				ipu6-isys-csi2.o \
 				ipu6-fw-isys.o \
+				ipu7-fw-isys.o \
 				ipu6-isys-video.o \
 				ipu6-isys-queue.o \
 				ipu6-isys-subdev.o \
diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index 62aa2b090699..aef8e4a66c4a 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -31,6 +31,7 @@ struct ipu6_bus_device {
 	u64 *pkg_dir;
 	dma_addr_t pkg_dir_dma_addr;
 	unsigned int pkg_dir_size;
+	u32 fw_entry;
 };
 
 struct ipu6_auxdrv_data {
@@ -47,6 +48,7 @@ struct ipu6_auxdrv_data {
 #define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
 
 extern const struct ipu6_fw_isys_ops ipu6_fw_isys_ops;
+extern const struct ipu6_fw_isys_ops ipu7_fw_isys_ops;
 
 struct ipu6_bus_device *
 ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 4ee5137f310e..3cad7d8f9ca9 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -15,6 +15,7 @@
 #include "ipu6-isys.h"
 #include "ipu6-platform-isys-csi2-reg.h"
 #include "ipu6-platform-regs.h"
+#include "ipu7-fw-isys.h"
 
 static const char send_msg_types[N_IPU6_FW_ISYS_SEND_TYPE][32] = {
 	"STREAM_OPEN",
@@ -602,7 +603,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
 		}
 
 		isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id,
-					   struct isys_fw_msgs, ipu6.dummy);
+					   struct isys_fw_msgs, dummy);
 
 		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
 		if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 4cb1741445c6..38db162d64ca 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -684,7 +684,7 @@ static void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib)
 	}
 }
 
-static void
+void
 ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id, u32 pin_addr,
 		      u64 time, bool error_check)
 {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
index 51de14183ccf..5df47be0c181 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
@@ -63,4 +63,6 @@ void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
 void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
 			       struct ipu6_fw_isys_resp_info_abi *info);
 int ipu6_isys_queue_init(struct ipu6_isys_queue *aq);
+void ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id,
+			   u32 pin_addr, u64 time, bool error_check);
 #endif /* IPU6_ISYS_QUEUE_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 803450b0156e..560524e6e624 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -627,6 +627,7 @@ int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
 
 	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));
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
index 2ff53315d7b9..a7157646d563 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
@@ -44,6 +44,7 @@ struct sequence_info {
 struct ipu6_isys_stream {
 	struct mutex mutex;
 	atomic_t sequence;
+	atomic_t buf_id;
 	unsigned int seq_index;
 	struct sequence_info seq[IPU6_ISYS_MAX_PARALLEL_SOF];
 	int stream_source;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 159e769931b7..086c0f01ccda 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -931,6 +931,9 @@ void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg)
 	spin_unlock_irqrestore(&isys->listlock, flags);
 }
 
+static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data;
+static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data;
+
 static int isys_probe(struct auxiliary_device *auxdev,
 		      const struct auxiliary_device_id *auxdev_id)
 {
@@ -949,8 +952,8 @@ static int isys_probe(struct auxiliary_device *auxdev,
 	if (!isys)
 		return -ENOMEM;
 
-	adev->auxdrv_data =
-		(const struct ipu6_auxdrv_data *)auxdev_id->driver_data;
+	adev->auxdrv_data = IS_IPU7(isp) ? &ipu7_isys_auxdrv_data :
+					   &ipu6_isys_auxdrv_data;
 	adev->auxdrv = to_auxiliary_drv(auxdev->dev.driver);
 	isys->adev = adev;
 	isys->pdata = adev->pdata;
@@ -1071,10 +1074,16 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
 	.fw_ops = &ipu6_fw_isys_ops,
 };
 
+static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data = {
+	.isr = ipu6_isys_isr,
+	.isr_threaded = NULL,
+	.wake_isr_thread = false,
+	.fw_ops = &ipu7_fw_isys_ops,
+};
+
 static const struct auxiliary_device_id ipu6_isys_id_table[] = {
 	{
 		.name = "intel_ipu6.isys",
-		.driver_data = (kernel_ulong_t)&ipu6_isys_auxdrv_data,
 	},
 	{ }
 };
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index fa9bc2730d64..697c090cc3b1 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -17,6 +17,7 @@
 
 #include "ipu6.h"
 #include "ipu6-fw-isys.h"
+#include "ipu7-fw-isys.h"
 #include "ipu6-isys-csi2.h"
 #include "ipu6-isys-video.h"
 
@@ -167,9 +168,15 @@ struct ipu6_isys {
 struct isys_fw_msgs {
 	union {
 		u64 dummy;
-		struct ipu6_fw_isys_frame_buff_set_abi frame;
-		struct ipu6_fw_isys_stream_cfg_data_abi stream;
-	} ipu6;
+		union {
+			struct ipu6_fw_isys_frame_buff_set_abi frame;
+			struct ipu6_fw_isys_stream_cfg_data_abi stream;
+		} ipu6;
+		union {
+			struct ipu7_fw_isys_frame_buff_set frame;
+			struct ipu7_fw_isys_stream_cfg stream;
+		} ipu7;
+	};
 	struct list_head head;
 	dma_addr_t dma_addr;
 };
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
index 10c09e759bed..097eaab99547 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -25,6 +25,8 @@ struct ipu7_fw_com_context {
 	dma_addr_t boot_config_dma_addr;
 	u32 boot_config_size;
 	u32 fw_entry;
+	struct ipu7_insys_config *fw_config;
+	dma_addr_t fw_config_dma_addr;
 };
 
 struct ipu7_fw_com_queue_params_config {
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
new file mode 100644
index 000000000000..d35684a2cb58
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include "ipu6-bus.h"
+#include "ipu6-dma.h"
+#include "ipu6-isys.h"
+#include "ipu7-boot.h"
+#include "ipu7-fw-com.h"
+#include "ipu7-fw-isys.h"
+
+static void ipu7_fw_isys_cleanup(struct ipu6_isys *isys)
+{
+	struct ipu6_bus_device *adev = isys->adev;
+	struct ipu7_fw_com_context *fwctx = isys->fwctx;
+
+	if (!fwctx)
+		return;
+
+	ipu7_release_boot_config(adev);
+
+	if (fwctx->fw_config) {
+		ipu6_dma_free(adev, sizeof(*fwctx->fw_config), fwctx->fw_config,
+			      fwctx->fw_config_dma_addr, 0);
+		fwctx->fw_config = NULL;
+		fwctx->fw_config_dma_addr = 0;
+	}
+
+	isys->fwctx = NULL;
+}
+
+static int ipu7_fw_isys_open(struct ipu6_isys *isys)
+{
+	return ipu7_boot_start_fw(isys->adev);
+}
+
+static int ipu7_fw_isys_close(struct ipu6_isys *isys)
+{
+	int ret;
+
+	ret = ipu7_boot_stop_fw(isys->adev);
+	if (ret)
+		return ret;
+
+	ipu7_fw_isys_cleanup(isys);
+
+	return ret;
+}
+
+static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
+{
+	struct ipu7_fw_com_queue_config *queue_configs;
+	struct ipu6_bus_device *adev = isys->adev;
+	struct device *dev = &adev->auxdev.dev;
+	struct ipu7_insys_config *fw_config;
+	struct ipu7_fw_com_context *fwctx;
+	dma_addr_t fw_config_dma_addr;
+	unsigned int i, num_queues;
+	u32 freq;
+	int ret;
+
+	/* Allocate and init firmware context. */
+	fwctx = devm_kzalloc(dev, sizeof(struct ipu7_fw_com_context),
+			     GFP_KERNEL);
+	if (!fwctx)
+		return -ENOMEM;
+
+	fwctx->num_input_queues = IPU7_INSYS_MAX_INPUT_QUEUES;
+	fwctx->num_output_queues = IPU7_INSYS_MAX_OUTPUT_QUEUES;
+	num_queues = fwctx->num_input_queues + fwctx->num_output_queues;
+
+	queue_configs = devm_kcalloc(dev, num_queues, sizeof(*queue_configs),
+				     GFP_KERNEL);
+	if (!queue_configs) {
+		ipu7_fw_isys_cleanup(isys);
+		return -ENOMEM;
+	}
+	fwctx->fw_entry = adev->fw_entry;
+	fwctx->queue_configs = queue_configs;
+	queue_configs[IPU7_INSYS_OUTPUT_MSG_QUEUE].max_capacity =
+		IPU7_ISYS_SIZE_RECV_QUEUE;
+	queue_configs[IPU7_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes =
+		sizeof(struct ipu7_insys_resp);
+	queue_configs[IPU7_INSYS_OUTPUT_LOG_QUEUE].max_capacity =
+		IPU7_ISYS_SIZE_LOG_QUEUE;
+	queue_configs[IPU7_INSYS_OUTPUT_LOG_QUEUE].token_size_in_bytes =
+		sizeof(struct ipu7_insys_resp);
+	queue_configs[IPU7_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0;
+	queue_configs[IPU7_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0;
+
+	queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].max_capacity =
+		IPU7_ISYS_MAX_STREAMS;
+	queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes =
+		sizeof(struct ipu7_insys_send_queue_token);
+
+	for (i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
+		queue_configs[i].max_capacity = IPU7_ISYS_SIZE_SEND_QUEUE;
+		queue_configs[i].token_size_in_bytes =
+			sizeof(struct ipu7_insys_send_queue_token);
+	}
+
+	/* Allocate ISYS subsys config. */
+	fw_config = ipu6_dma_alloc(adev, sizeof(*fw_config),
+				   &fw_config_dma_addr, GFP_KERNEL, 0);
+	if (!fw_config) {
+		dev_err(dev, "Failed to allocate isys subsys config.\n");
+		ipu7_fw_isys_cleanup(isys);
+		return -ENOMEM;
+	}
+	fwctx->fw_config = fw_config;
+	fwctx->fw_config_dma_addr = fw_config_dma_addr;
+	memset(fw_config, 0, sizeof(*fw_config));
+	fw_config->logger_config.use_source_severity = 0;
+	fw_config->logger_config.use_channels_enable_bitmask = 1;
+	fw_config->logger_config.channels_enable_bitmask =
+				IPU7_LOGGER_CFG_CHANNEL_ENABLE_SYSCOM;
+	fw_config->logger_config.hw_printf_buffer_base_addr = 0U;
+	fw_config->logger_config.hw_printf_buffer_size_bytes = 0U;
+	fw_config->wdt_config.wdt_timer1_us = 0;
+	fw_config->wdt_config.wdt_timer2_us = 0;
+	freq = ipu7_buttress_get_isys_freq(adev->isp);
+
+	ipu6_dma_sync_single(adev, fw_config_dma_addr,
+			     sizeof(struct ipu7_insys_config));
+
+	isys->fwctx = fwctx;
+
+	ret = ipu7_init_boot_config(adev, queue_configs, num_queues,
+				    freq, fw_config_dma_addr, 1U);
+	if (ret) {
+		ipu7_fw_isys_cleanup(isys);
+		return ret;
+	}
+
+	ret = ipu7_fw_isys_open(isys);
+	if (ret)
+		ipu7_fw_isys_cleanup(isys);
+
+	return ret;
+}
+
+static struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu6_isys *isys)
+{
+	return ipu7_fw_com_get_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE);
+}
+
+static void ipu7_fw_isys_put_resp(struct ipu6_isys *isys)
+{
+	ipu7_fw_com_put_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE);
+}
+
+static int ipu7_isys_fw_pin_cfg(struct ipu6_isys_video *av,
+				struct ipu7_fw_isys_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 v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
+	struct ipu7_fw_isys_input_pin *input_pin;
+	struct ipu7_fw_isys_output_pin *output_pin;
+	struct ipu6_isys_stream *stream = av->stream;
+	struct ipu6_isys_queue *aq = &av->aq;
+	struct v4l2_mbus_framefmt fmt;
+	const struct ipu6_isys_pixelformat *pfmt =
+		ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
+	int input_pins = cfg->nof_input_pins++;
+	int output_pins;
+	u32 src_stream;
+
+	src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
+	fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
+
+	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;
+	if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE)
+		input_pin->disable_mipi_unpacking = 1;
+	input_pin->mapped_dt = IPU7_N_INSYS_MIPI_DATA_TYPE;
+	input_pin->dt_rename_mode = IPU7_INSYS_MIPI_DT_NO_RENAME;
+	input_pin->sync_msg_map =
+		IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF |
+		IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED |
+		IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF |
+		IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED;
+
+	output_pins = cfg->nof_output_pins++;
+	aq->fw_output = output_pins;
+	stream->output_pins_queue[output_pins] = aq;
+
+	output_pin = &cfg->output_pins[output_pins];
+	memset(output_pin, 0, sizeof(*output_pin));
+	output_pin->link.buffer_lines = 0;
+	output_pin->link.foreign_key = IPU7_MSG_LINK_FOREIGN_KEY_NONE;
+	output_pin->link.pbk_id = IPU7_MSG_LINK_PBK_ID_DONT_CARE;
+	output_pin->link.pbk_slot_id = IPU7_MSG_LINK_PBK_SLOT_ID_DONT_CARE;
+	output_pin->link.dest = 0; /* IPU_INSYS_OUTPUT_LINK_DEST_MEM */
+	output_pin->link.use_sw_managed = 1;
+	output_pin->crop.line_top = 0;
+	output_pin->crop.line_bottom = 0;
+	output_pin->dpcm.enable = 0;
+	output_pin->ft = pfmt->css_pixelformat;
+	output_pin->stride = ipu6_isys_get_bytes_per_line(av);
+	output_pin->send_irq = 1;
+	output_pin->input_pin_id = input_pins;
+
+	return 0;
+}
+
+static int
+ipu7_fw_isys_send_cmd(struct ipu6_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_fw_com_context *ctx = isys->fwctx;
+	/*struct device *dev = &isys->adev->auxdev.dev;*/
+	struct ipu7_insys_send_queue_token *token;
+
+	if (send_type >= N_IPU7_INSYS_SEND_TYPE)
+		return -EINVAL;
+
+	if (cpu_mapped_buf)
+		clflush_cache_range(cpu_mapped_buf, size);
+
+	token = ipu7_fw_com_get_token(ctx, stream_handle +
+				      IPU7_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 = IPU7_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE;
+
+	ipu7_fw_com_put_token(ctx, stream_handle + IPU7_INSYS_INPUT_MSG_QUEUE);
+	/* now wakeup FW */
+	ipu7_buttress_wakeup_isys(isys->adev->isp);
+
+	return 0;
+}
+
+static void ipu7_fw_isys_dump_stream_cfg(struct device *dev,
+					 struct isys_fw_msgs *msg)
+{
+	struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream;
+	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");
+}
+
+static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev,
+					    struct isys_fw_msgs *msg,
+					    unsigned int outputs)
+{
+	struct ipu7_fw_isys_frame_buff_set *buf = &msg->ipu7.frame;
+	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");
+}
+
+static int ipu7_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+					   struct isys_fw_msgs *msg)
+{
+	struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream;
+	struct device *dev = &av->isys->adev->auxdev.dev;
+	struct ipu6_isys_stream *stream = av->stream;
+	struct ipu6_isys_queue *aq;
+
+	memset(cfg, 0, sizeof(*cfg));
+	cfg->port_id = stream->stream_source;
+	cfg->vc = stream->vc;
+	cfg->stream_msg_map = IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP |
+			      IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ;
+
+	list_for_each_entry(aq, &stream->queues, node) {
+		struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
+		int ret = ipu7_isys_fw_pin_cfg(__av, cfg);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	stream->nr_output_pins = cfg->nof_output_pins;
+
+	ipu7_fw_isys_dump_stream_cfg(dev, msg);
+
+	return 0;
+}
+
+static void
+ipu7_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
+				  struct ipu7_fw_isys_frame_buff_set *set)
+{
+	struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+	struct ipu6_isys_video_buffer *ivb =
+		vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+
+	set->output_pins[aq->fw_output].addr = ivb->dma_addr;
+	set->output_pins[aq->fw_output].user_token = (u64)(uintptr_t)set;
+}
+
+static void
+ipu7_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+			     struct ipu6_isys_stream *stream,
+			     struct ipu6_isys_buffer_list *bl)
+{
+	struct ipu7_fw_isys_frame_buff_set *set = &msg->ipu7.frame;
+	struct ipu6_isys_buffer *ib;
+
+	WARN_ON(!bl->nbufs);
+
+	memset(set, 0, sizeof(*set));
+	set->capture_msg_map = IPU7_INSYS_FRAME_ENABLE_MSG_SEND_RESP |
+			       IPU7_INSYS_FRAME_ENABLE_MSG_SEND_IRQ;
+	set->frame_id = atomic_fetch_inc(&stream->buf_id) % 256;
+
+	list_for_each_entry(ib, &bl->head, head) {
+		struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
+
+		ipu7_isys_buf_to_fw_frame_buf_pin(vb, set);
+	}
+
+	dev_dbg(&stream->isys->adev->auxdev.dev,
+		"ipu7 frame_buf: cap_map=0x%x fid=%u opin[0].addr=0x%x token=0x%llx\n",
+		set->capture_msg_map, set->frame_id,
+		set->output_pins[0].addr, set->output_pins[0].user_token);
+}
+
+static int ipu7_fw_isys_stream_open(struct ipu6_isys *isys,
+				    const unsigned int stream_handle,
+				    struct isys_fw_msgs *msg)
+{
+	return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.stream,
+				     msg->dma_addr, sizeof(msg->ipu7.stream),
+				     IPU7_INSYS_SEND_TYPE_STREAM_OPEN);
+}
+
+static int ipu7_fw_isys_stream_close(struct ipu6_isys *isys,
+				     const unsigned int stream_handle)
+{
+	return ipu7_fw_isys_send_cmd(isys, stream_handle, NULL, 0, 0,
+				     IPU7_INSYS_SEND_TYPE_STREAM_CLOSE);
+}
+
+static int ipu7_fw_isys_stream_flush(struct ipu6_isys *isys,
+				     const unsigned int stream_handle)
+{
+	return ipu7_fw_isys_send_cmd(isys, stream_handle, NULL, 0, 0,
+				     IPU7_INSYS_SEND_TYPE_STREAM_FLUSH);
+}
+
+static int ipu7_fw_isys_stream_start(struct ipu6_isys *isys,
+				     const unsigned int stream_handle,
+				     struct isys_fw_msgs *msg, bool capture)
+{
+	return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.frame,
+				     msg->dma_addr, sizeof(msg->ipu7.frame),
+				     IPU7_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE);
+}
+
+static int ipu7_fw_isys_stream_capture(struct ipu6_isys *isys,
+				       const unsigned int stream_handle,
+				       struct isys_fw_msgs *msg)
+{
+	return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.frame,
+				     msg->dma_addr, sizeof(msg->ipu7.frame),
+				     IPU7_INSYS_SEND_TYPE_STREAM_CAPTURE);
+}
+
+const struct ipu6_fw_isys_ops ipu7_fw_isys_ops = {
+	.init = ipu7_fw_isys_init,
+	.close = ipu7_fw_isys_close,
+	.send_cmd = ipu7_fw_isys_send_cmd,
+	.cleanup = ipu7_fw_isys_cleanup,
+	.prepare_stream_cfg = ipu7_fw_isys_prepare_stream_cfg,
+	.prepare_buf_set = ipu7_fw_isys_prepare_buf_set,
+	.stream_open = ipu7_fw_isys_stream_open,
+	.stream_start = ipu7_fw_isys_stream_start,
+	.stream_capture = ipu7_fw_isys_stream_capture,
+	.stream_flush = ipu7_fw_isys_stream_flush,
+	.stream_close = ipu7_fw_isys_stream_close,
+	.dump_stream_cfg = ipu7_fw_isys_dump_stream_cfg,
+	.dump_frame_buf_set = ipu7_fw_isys_dump_frame_buf_set,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
new file mode 100644
index 000000000000..122531065362
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_FW_ISYS_H
+#define IPU7_FW_ISYS_H
+
+#define IPU7_FWLOG_MAX_LOGGER_SOURCES		(64U)
+#define IPU7_INSYS_MAX_OUTPUT_QUEUES		3U
+#define IPU7_INSYS_STREAM_ID_MAX		16U
+#define IPU7_INSYS_MAX_INPUT_QUEUES		(IPU7_INSYS_STREAM_ID_MAX + 1U)
+#define IPU7_INSYS_OUTPUT_MSG_QUEUE		0U
+#define IPU7_INSYS_OUTPUT_LOG_QUEUE		1U
+#define IPU7_INSYS_OUTPUT_RESERVED_QUEUE	2U
+#define IPU7_INSYS_INPUT_DEV_QUEUE		3U
+
+#define IPU7_INSYS_INPUT_FIRST_QUEUE		3U
+#define IPU7_INSYS_INPUT_MSG_QUEUE		4U
+#define IPU7_INSYS_INPUT_MSG_MAX_QUEUE		16U
+
+#define IPU7_MSG_ERR_MAX_DETAILS		4U
+#define IPU7_ISYS_SIZE_RECV_QUEUE		40U
+#define IPU7_ISYS_SIZE_LOG_QUEUE		256U
+#define IPU7_ISYS_SIZE_SEND_QUEUE		40U
+#define IPU7_ISYS_NUM_RECV_QUEUE		1U
+#define IPU7_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE	0U
+
+#define IPU7_LOGGER_CFG_CHANNEL_ENABLE_SYSCOM	BIT(1)
+
+#define IPU7_ISYS_MAX_STREAMS	16U
+#define IPU7_MAX_OPINS		4
+#define IPU7_MAX_IPINS		4
+
+#define IPU7_N_INSYS_MIPI_DATA_TYPE	0x40
+
+#define IPU7_MSG_LINK_FOREIGN_KEY_NONE		(65535U)
+#define IPU7_MSG_LINK_PBK_ID_DONT_CARE		(255U)
+#define IPU7_MSG_LINK_PBK_SLOT_ID_DONT_CARE	(255U)
+
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF		BIT(0)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF		BIT(1)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF			BIT(2)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF			BIT(3)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED	BIT(4)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED	BIT(5)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED	BIT(6)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED	BIT(7)
+
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE	BIT(0)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE		BIT(1)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK	BIT(2)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK		BIT(3)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK	BIT(4)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK		BIT(5)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK	BIT(6)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK		BIT(7)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK	BIT(8)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK		BIT(9)
+
+#define IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP ( \
+	IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE | \
+	IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK | \
+	IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK | \
+	IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK | \
+	IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK)
+#define IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ ( \
+	IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE | \
+	IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK | \
+	IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK | \
+	IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK | \
+	IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK)
+
+#define IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK		BIT(0)
+#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK		BIT(1)
+#define IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE		BIT(2)
+#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE		BIT(3)
+#define IPU7_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY		BIT(4)
+#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY		BIT(5)
+
+#define IPU7_INSYS_FRAME_ENABLE_MSG_SEND_RESP ( \
+	IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK | \
+	IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE | \
+	IPU7_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY)
+#define IPU7_INSYS_FRAME_ENABLE_MSG_SEND_IRQ ( \
+	IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK | \
+	IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE | \
+	IPU7_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY)
+
+enum ipu7_insys_send_type {
+	IPU7_INSYS_SEND_TYPE_STREAM_OPEN = 0,
+	IPU7_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE = 1,
+	IPU7_INSYS_SEND_TYPE_STREAM_CAPTURE = 2,
+	IPU7_INSYS_SEND_TYPE_STREAM_ABORT = 3,
+	IPU7_INSYS_SEND_TYPE_STREAM_FLUSH = 4,
+	IPU7_INSYS_SEND_TYPE_STREAM_CLOSE = 5,
+	N_IPU7_INSYS_SEND_TYPE
+};
+
+enum ipu7_insys_resp_type {
+	IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE = 0,
+	IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK = 1,
+	IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK = 2,
+	IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK = 3,
+	IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK = 4,
+	IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK = 5,
+	IPU7_INSYS_RESP_TYPE_PIN_DATA_READY = 6,
+	IPU7_INSYS_RESP_TYPE_FRAME_SOF = 7,
+	IPU7_INSYS_RESP_TYPE_FRAME_EOF = 8,
+	IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE = 9,
+	IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE = 10,
+	IPU7_INSYS_RESP_TYPE_PWM_IRQ = 11,
+	N_IPU7_INSYS_RESP_TYPE
+};
+
+enum ipu7_insys_mipi_dt_rename_mode {
+	IPU7_INSYS_MIPI_DT_NO_RENAME = 0,
+	IPU7_INSYS_MIPI_DT_RENAMED_MODE = 1,
+	N_IPU7_INSYS_MIPI_DT_MODE
+};
+
+struct ipu7_fw_isys_logger_config {
+	u8 use_source_severity;
+	u8 source_severity[IPU7_FWLOG_MAX_LOGGER_SOURCES];
+	u8 use_channels_enable_bitmask;
+	u8 channels_enable_bitmask;
+	u8 padding[1];
+	u32 hw_printf_buffer_base_addr;
+	u32 hw_printf_buffer_size_bytes;
+};
+
+struct ipu7_wdt_abi {
+	u32 wdt_timer1_us;
+	u32 wdt_timer2_us;
+};
+
+struct ipu7_insys_config {
+	u32 timeout_val_ms;
+	struct ipu7_fw_isys_logger_config logger_config;
+	struct ipu7_wdt_abi wdt_config;
+};
+
+struct ipu7_insys_capture_output_pin_payload {
+	u64 user_token;
+	u32 addr;
+	u8 pad[4];
+};
+
+struct ipu7_fw_isys_msg_err {
+	u32 err_group;
+	u32 err_code;
+	u32 err_detail[IPU7_MSG_ERR_MAX_DETAILS];
+};
+
+struct ipu7_insys_resp {
+	u64 buf_id;
+	struct ipu7_insys_capture_output_pin_payload pin;
+	struct ipu7_fw_isys_msg_err error_info;
+	u32 timestamp[2];
+	u8 type;
+	u8 msg_link_streaming_mode;
+	u8 stream_id;
+	u8 pin_id;
+	u8 frame_id;
+	u8 skip_frame;
+	u8 pad[2];
+};
+
+struct ipu7_insys_resp_queue_token {
+	struct ipu7_insys_resp resp_info;
+};
+
+struct ipu7_insys_send_queue_token {
+	u64 buf_handle;
+	u32 addr;
+	u16 stream_id;
+	u8 send_type;
+	u8 flag;
+};
+
+struct ipu7_fw_isys_output_link {
+	u32 buffer_lines;
+	u16 foreign_key;
+	u16 granularity_pointer_update;
+	u8 msg_link_streaming_mode;
+	u8 pbk_id;
+	u8 pbk_slot_id;
+	u8 dest;
+	u8 use_sw_managed;
+	u8 is_snoop;
+	u8 pad[2];
+} __packed;
+
+struct ipu7_fw_isys_output_cropping {
+	u16 line_top;
+	u16 line_bottom;
+} __packed;
+
+struct ipu7_fw_isys_output_dpcm {
+	u8 enable;
+	u8 type;
+	u8 predictor;
+	u8 pad;
+} __packed;
+
+struct ipu7_fw_isys_output_pin {
+	struct ipu7_fw_isys_output_link link;
+	struct ipu7_fw_isys_output_cropping crop;
+	struct ipu7_fw_isys_output_dpcm dpcm;
+	u32 stride;
+	u16 ft;
+	u8 send_irq;
+	u8 input_pin_id;
+	u8 early_ack_en;
+	u8 pad[3];
+} __packed;
+
+struct ipu7_fw_isys_resolution {
+	u32 width;
+	u32 height;
+} __packed;
+
+struct ipu7_fw_isys_input_pin {
+	struct ipu7_fw_isys_resolution input_res;
+	u16 sync_msg_map;
+	u8 dt;
+	u8 disable_mipi_unpacking;
+	u8 dt_rename_mode;
+	u8 mapped_dt;
+	u8 pad[2];
+} __packed;
+
+struct ipu7_fw_isys_stream_cfg {
+	struct ipu7_fw_isys_input_pin input_pins[IPU7_MAX_IPINS];
+	struct ipu7_fw_isys_output_pin output_pins[IPU7_MAX_OPINS];
+	u16 stream_msg_map;
+	u8 port_id;
+	u8 vc;
+	u8 nof_input_pins;
+	u8 nof_output_pins;
+	u8 pad[2];
+} __packed;
+
+struct ipu7_fw_isys_capture_output_pin {
+	u64 user_token;
+	u32 addr;
+	u8 pad[4];
+} __packed;
+
+struct ipu7_fw_isys_frame_buff_set {
+	struct ipu7_fw_isys_capture_output_pin output_pins[IPU7_MAX_OPINS];
+	u8 capture_msg_map;
+	u8 frame_id;
+	u8 skip_frame;
+	u8 pad[5];
+} __packed;
+
+struct ipu6_fw_isys_ops *ipu7_fw_isys_get_ops(void);
+
+#endif
-- 
2.55.0


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

* [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (23 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler Antti Laakso
                   ` (18 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

This is needed later when adding support for the ipu7 csi2
receiver.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 .../pci/intel/ipu6/ipu7-isys-csi2-regs.h      | 1189 +++++++++++++++++
 1 file changed, 1189 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h

diff --git a/drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h b/drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h
new file mode 100644
index 000000000000..3859401d4802
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h
@@ -0,0 +1,1189 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 - 2026 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_CSI2_REG_H
+#define IPU7_ISYS_CSI2_REG_H
+
+/* IS main regs base */
+#define IPU7_IS_MAIN_BASE			0x240000
+#define IPU7_IS_MAIN_S2B_BASE			(IPU7_IS_MAIN_BASE + 0x22000)
+#define IPU7_IS_MAIN_B2O_BASE			(IPU7_IS_MAIN_BASE + 0x26000)
+#define IPU7_IS_MAIN_ISD_M0_BASE		(IPU7_IS_MAIN_BASE + 0x2b000)
+#define IPU7_IS_MAIN_ISD_M1_BASE		(IPU7_IS_MAIN_BASE + 0x2b100)
+#define IPU7_IS_MAIN_ISD_INT_BASE		(IPU7_IS_MAIN_BASE + 0x2b200)
+#define IPU7_IS_MAIN_GDA_BASE			(IPU7_IS_MAIN_BASE + 0x32000)
+#define IPU7_IS_MAIN_GPREGS_MAIN_BASE		(IPU7_IS_MAIN_BASE + 0x32500)
+#define IPU7_IS_MAIN_IRQ_CTRL_BASE		(IPU7_IS_MAIN_BASE + 0x32700)
+#define IPU7_IS_MAIN_PWM_CTRL_BASE		(IPU7_IS_MAIN_BASE + 0x32b00)
+
+#define IPU7_S2B_IRQ_COMMON_0_CTL_STATUS	(IPU7_IS_MAIN_S2B_BASE + 0x1c)
+#define IPU7_S2B_IRQ_COMMON_0_CTL_CLEAR		(IPU7_IS_MAIN_S2B_BASE + 0x20)
+#define IPU7_S2B_IRQ_COMMON_0_CTL_ENABLE	(IPU7_IS_MAIN_S2B_BASE + 0x24)
+#define IPU7_S2B_IID_IRQ_CTL_STATUS(iid)	(IPU7_IS_MAIN_S2B_BASE + 0x94 + \
+						 0x100 * (iid))
+
+#define IPU7_B2O_IRQ_COMMON_0_CTL_STATUS	(IPU7_IS_MAIN_B2O_BASE + 0x30)
+#define IPU7_B2O_IRQ_COMMON_0_CTL_CLEAR		(IPU7_IS_MAIN_B2O_BASE + 0x34)
+#define IPU7_B2O_IRQ_COMMON_0_CTL_ENABLE	(IPU7_IS_MAIN_B2O_BASE + 0x38)
+#define IPU7_B2O_IID_IRQ_CTL_STATUS(oid)	(IPU7_IS_MAIN_B2O_BASE + 0x3dc + \
+						 0x200 * (oid))
+
+#define IPU7_ISD_M0_IRQ_CTL_STATUS		(IPU7_IS_MAIN_ISD_M0_BASE + 0x1c)
+#define IPU7_ISD_M0_IRQ_CTL_CLEAR		(IPU7_IS_MAIN_ISD_M0_BASE + 0x20)
+#define IPU7_ISD_M0_IRQ_CTL_ENABLE		(IPU7_IS_MAIN_ISD_M0_BASE + 0x24)
+
+#define IPU7_ISD_M1_IRQ_CTL_STATUS		(IPU7_IS_MAIN_ISD_M1_BASE + 0x1c)
+#define IPU7_ISD_M1_IRQ_CTL_CLEAR		(IPU7_IS_MAIN_ISD_M1_BASE + 0x20)
+#define IPU7_ISD_M1_IRQ_CTL_ENABLE		(IPU7_IS_MAIN_ISD_M1_BASE + 0x24)
+
+#define IPU7_ISD_INT_IRQ_CTL_STATUS		(IPU7_IS_MAIN_ISD_INT_BASE + 0x1c)
+#define IPU7_ISD_INT_IRQ_CTL_CLEAR		(IPU7_IS_MAIN_ISD_INT_BASE + 0x20)
+#define IPU7_ISD_INT_IRQ_CTL_ENABLE		(IPU7_IS_MAIN_ISD_INT_BASE + 0x24)
+
+#define IPU7_GDA_IRQ_CTL_STATUS			(IPU7_IS_MAIN_GDA_BASE + 0x1c)
+#define IPU7_GDA_IRQ_CTL_CLEAR			(IPU7_IS_MAIN_GDA_BASE + 0x20)
+#define IPU7_GDA_IRQ_CTL_ENABLE			(IPU7_IS_MAIN_GDA_BASE + 0x24)
+
+#define IPU7_IS_MAIN_IRQ_CTL_EDGE		IPU7_IS_MAIN_IRQ_CTRL_BASE
+#define IPU7_IS_MAIN_IRQ_CTL_MASK		(IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x4)
+#define IPU7_IS_MAIN_IRQ_CTL_STATUS		(IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x8)
+#define IPU7_IS_MAIN_IRQ_CTL_CLEAR		(IPU7_IS_MAIN_IRQ_CTRL_BASE + 0xc)
+#define IPU7_IS_MAIN_IRQ_CTL_ENABLE		(IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x10)
+#define IPU7_IS_MAIN_IRQ_CTL_LEVEL_NOT_PULSE	(IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x14)
+
+/* IS IO regs base */
+#define IPU7_IS_PHY_NUM				4U
+#define IPU7_IS_IO_BASE				0x280000
+
+/* dwc csi cdphy registers */
+#define IPU7_IS_IO_CDPHY_BASE(i)			(IPU7_IS_IO_BASE + 0x10000 * (i))
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_0		0x1800
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_1		0x1802
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_2		0x1804
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_3		0x1806
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_4		0x1808
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_5		0x180a
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_6		0x180c
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_7		0x180e
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_8		0x1810
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_9		0x1812
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_A		0x1814
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_10		0x1820
+#define IPU7_PPI_STARTUP_RW_COMMON_STARTUP_1_1		0x1822
+#define IPU7_PPI_STARTUP_RW_COMMON_STARTUP_1_2		0x1824
+#define IPU7_PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_0	0x1840
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_1	0x1842
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_2	0x1844
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_3	0x1846
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_4	0x1848
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5	0x184a
+#define IPU7_PPI_CALIBCTRL_RW_COMMON_BG_0		0x184c
+#define IPU7_PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_7	0x184e
+#define IPU7_PPI_CALIBCTRL_RW_ADC_CFG_0			0x1850
+#define IPU7_PPI_CALIBCTRL_RW_ADC_CFG_1			0x1852
+#define IPU7_PPI_CALIBCTRL_R_ADC_DEBUG			0x1854
+#define IPU7_PPI_RW_LPDCOCAL_TOP_OVERRIDE		0x1c00
+#define IPU7_PPI_RW_LPDCOCAL_TIMEBASE			0x1c02
+#define IPU7_PPI_RW_LPDCOCAL_NREF			0x1c04
+#define IPU7_PPI_RW_LPDCOCAL_NREF_RANGE			0x1c06
+#define IPU7_PPI_RW_LPDCOCAL_NREF_TRIGGER_MAN		0x1c08
+#define IPU7_PPI_RW_LPDCOCAL_TWAIT_CONFIG		0x1c0a
+#define IPU7_PPI_RW_LPDCOCAL_VT_CONFIG			0x1c0c
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_RB			0x1c0e
+#define IPU7_PPI_RW_LPDCOCAL_COARSE_CFG			0x1c10
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_RB		0x1c12
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_0_RB	0x1c14
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_1_RB	0x1c16
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_FWORD_RB	0x1c18
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_MEASURE_CURR_ERROR	0x1c1a
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_MEASURE_LAST_ERROR	0x1c1c
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_VT			0x1c1e
+#define IPU7_PPI_RW_LB_TIMEBASE_CONFIG			0x1c20
+#define IPU7_PPI_RW_LB_STARTCMU_CONFIG			0x1c22
+#define IPU7_PPI_R_LBPULSE_COUNTER_RB			0x1c24
+#define IPU7_PPI_R_LB_START_CMU_RB			0x1c26
+#define IPU7_PPI_RW_LB_DPHY_BURST_START			0x1c28
+#define IPU7_PPI_RW_LB_CPHY_BURST_START			0x1c2a
+#define IPU7_PPI_RW_DDLCAL_CFG_0			0x1c40
+#define IPU7_PPI_RW_DDLCAL_CFG_1			0x1c42
+#define IPU7_PPI_RW_DDLCAL_CFG_2			0x1c44
+#define IPU7_PPI_RW_DDLCAL_CFG_3			0x1c46
+#define IPU7_PPI_RW_DDLCAL_CFG_4			0x1c48
+#define IPU7_PPI_RW_DDLCAL_CFG_5			0x1c4a
+#define IPU7_PPI_RW_DDLCAL_CFG_6			0x1c4c
+#define IPU7_PPI_RW_DDLCAL_CFG_7			0x1c4e
+#define IPU7_PPI_R_DDLCAL_DEBUG_0			0x1c50
+#define IPU7_PPI_R_DDLCAL_DEBUG_1			0x1c52
+#define IPU7_PPI_RW_PARITY_TEST				0x1c60
+#define IPU7_PPI_RW_STARTUP_OVR_0			0x1c62
+#define IPU7_PPI_RW_STARTUP_STATE_OVR_1			0x1c64
+#define IPU7_PPI_RW_DTB_SELECTOR			0x1c66
+#define IPU7_PPI_RW_DPHY_CLK_SPARE			0x1c6a
+#define IPU7_PPI_RW_COMMON_CFG				0x1c6c
+#define IPU7_PPI_RW_TERMCAL_CFG_0			0x1c80
+#define IPU7_PPI_R_TERMCAL_DEBUG_0			0x1c82
+#define IPU7_PPI_RW_TERMCAL_CTRL_0			0x1c84
+#define IPU7_PPI_RW_OFFSETCAL_CFG_0			0x1ca0
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE0		0x1ca2
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE1		0x1ca4
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE2		0x1ca6
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE3		0x1ca8
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE4		0x1caa
+#define IPU7_PPI_RW_HSDCOCAL_CFG_O			0x1d00
+#define IPU7_PPI_RW_HSDCOCAL_CFG_1			0x1d02
+#define IPU7_PPI_RW_HSDCOCAL_CFG_2			0x1d04
+#define IPU7_PPI_RW_HSDCOCAL_CFG_3			0x1d06
+#define IPU7_PPI_RW_HSDCOCAL_CFG_4			0x1d08
+#define IPU7_PPI_RW_HSDCOCAL_CFG_5			0x1d0a
+#define IPU7_PPI_RW_HSDCOCAL_CFG_6			0x1d0c
+#define IPU7_PPI_RW_HSDCOCAL_CFG_7			0x1d0e
+#define IPU7_PPI_RW_HSDCOCAL_CFG_8			0x1d10
+#define IPU7_PPI_R_HSDCOCAL_DEBUG_RB			0x1d12
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_0	0x2000
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_1	0x2002
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_2	0x2004
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_3	0x2006
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_4	0x2008
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_5	0x200a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_6	0x200c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_7	0x200e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_8	0x2010
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_9	0x2012
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_10	0x2014
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_11	0x2016
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_12	0x2018
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_13	0x201a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_14	0x201c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_15	0x201e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_0	0x2020
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_1	0x2022
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_2	0x2024
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_3	0x2026
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_4	0x2028
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_5	0x202a
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_6	0x202c
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_7	0x202e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_8	0x2030
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_9	0x2032
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_10	0x2034
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_11	0x2036
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_12	0x2038
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_13	0x203a
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_14	0x203c
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_15	0x203e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_0	0x2040
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_1	0x2042
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2	0x2044
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_3	0x2046
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_4	0x2048
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_5	0x204a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_6	0x204c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7	0x204e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8	0x2050
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9	0x2052
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_10	0x2054
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_11	0x2056
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12	0x2058
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13	0x205a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_14	0x205c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15	0x205e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_0	0x2060
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_1	0x2062
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_2	0x2064
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_3	0x2066
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_4	0x2068
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_5	0x206a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_6	0x206c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_7	0x206e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_8	0x2070
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_9	0x2072
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_10	0x2074
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_11	0x2076
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_12	0x2078
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_13	0x207a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_14	0x207c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_15	0x207e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_0	0x2080
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_1	0x2082
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_2	0x2084
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_3	0x2086
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_4	0x2088
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_0	0x20a0
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_1	0x20a2
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_2	0x20a4
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_3	0x20a6
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_4	0x20a8
+#define IPU7_CORE_DIG_RW_TRIO0_0			0x2100
+#define IPU7_CORE_DIG_RW_TRIO0_1			0x2102
+#define IPU7_CORE_DIG_RW_TRIO0_2			0x2104
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_0	0x2400
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_1	0x2402
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_2	0x2404
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_3	0x2406
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_4	0x2408
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_5	0x240a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_6	0x240c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_7	0x240e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_8	0x2410
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_9	0x2412
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_10	0x2414
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_11	0x2416
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_12	0x2418
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_13	0x241a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_14	0x241c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_15	0x241e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_0	0x2420
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_1	0x2422
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_2	0x2424
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_3	0x2426
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_4	0x2428
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_5	0x242a
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_6	0x242c
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_7	0x242e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_8	0x2430
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_9	0x2432
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_10	0x2434
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_11	0x2436
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_12	0x2438
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_13	0x243a
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_14	0x243c
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_15	0x243e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_0	0x2440
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_1	0x2442
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2	0x2444
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_3	0x2446
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_4	0x2448
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_5	0x244a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_6	0x244c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_7	0x244e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_8	0x2450
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9	0x2452
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_10	0x2454
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_11	0x2456
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_12	0x2458
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_13	0x245a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_14	0x245c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15	0x245e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_0	0x2460
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_1	0x2462
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_2	0x2464
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_3	0x2466
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_4	0x2468
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_5	0x246a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_6	0x246c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_7	0x246e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_8	0x2470
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_9	0x2472
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_10	0x2474
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_11	0x2476
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_12	0x2478
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_13	0x247a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_14	0x247c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_15	0x247e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_0	0x2480
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_1	0x2482
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_2	0x2484
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_3	0x2486
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_4	0x2488
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_0	0x24a0
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_1	0x24a2
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_2	0x24a4
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_3	0x24a6
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_4	0x24a8
+#define IPU7_CORE_DIG_RW_TRIO1_0			0x2500
+#define IPU7_CORE_DIG_RW_TRIO1_1			0x2502
+#define IPU7_CORE_DIG_RW_TRIO1_2			0x2504
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_0	0x2800
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_1	0x2802
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_2	0x2804
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_3	0x2806
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_4	0x2808
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_5	0x280a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_6	0x280c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_7	0x280e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_8	0x2810
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_9	0x2812
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_10	0x2814
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_11	0x2816
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_12	0x2818
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_13	0x281a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_14	0x281c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_15	0x281e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_0	0x2820
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_1	0x2822
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_2	0x2824
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_3	0x2826
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_4	0x2828
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_5	0x282a
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_6	0x282c
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_7	0x282e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_8	0x2830
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_9	0x2832
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_10	0x2834
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_11	0x2836
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_12	0x2838
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_13	0x283a
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_14	0x283c
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_15	0x283e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_0	0x2840
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_1	0x2842
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2	0x2844
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_3	0x2846
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_4	0x2848
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_5	0x284a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_6	0x284c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_7	0x284e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_8	0x2850
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9	0x2852
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_10	0x2854
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_11	0x2856
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_12	0x2858
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_13	0x285a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_14	0x285c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15	0x285e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_0	0x2860
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_1	0x2862
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_2	0x2864
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_3	0x2866
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_4	0x2868
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_5	0x286a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_6	0x286c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_7	0x286e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_8	0x2870
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_9	0x2872
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_10	0x2874
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_11	0x2876
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_12	0x2878
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_13	0x287a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_14	0x287c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_15	0x287e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_0	0x2880
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_1	0x2882
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_2	0x2884
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_3	0x2886
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_4	0x2888
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_0	0x28a0
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_1	0x28a2
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_2	0x28a4
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_3	0x28a6
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_4	0x28a8
+#define IPU7_CORE_DIG_RW_TRIO2_0			0x2900
+#define IPU7_CORE_DIG_RW_TRIO2_1			0x2902
+#define IPU7_CORE_DIG_RW_TRIO2_2			0x2904
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_0	0x2c00
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_1	0x2c02
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_2	0x2c04
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_3	0x2c06
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_4	0x2c08
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_5	0x2c0a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_6	0x2c0c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_7	0x2c0e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_8	0x2c10
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_9	0x2c12
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_10	0x2c14
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_11	0x2c16
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_12	0x2c18
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_13	0x2c1a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_14	0x2c1c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_15	0x2c1e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_0	0x2c40
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_1	0x2c42
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2	0x2c44
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_3	0x2c46
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_4	0x2c48
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_5	0x2c4a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_6	0x2c4c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_7	0x2c4e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_8	0x2c50
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9	0x2c52
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_10	0x2c54
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_11	0x2c56
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_12	0x2c58
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_13	0x2c5a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_14	0x2c5c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15	0x2c5e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_0	0x2c60
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_1	0x2c62
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_2	0x2c64
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_3	0x2c66
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_4	0x2c68
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_5	0x2c6a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_6	0x2c6c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_7	0x2c6e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_8	0x2c70
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_9	0x2c72
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_10	0x2c74
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_11	0x2c76
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_12	0x2c78
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_13	0x2c7a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_14	0x2c7c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_15	0x2c7e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_0	0x2c80
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_1	0x2c82
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_2	0x2c84
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_3	0x2c86
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_4	0x2c88
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_0	0x3040
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_1	0x3042
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2	0x3044
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_3	0x3046
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_4	0x3048
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_5	0x304a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_6	0x304c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_7	0x304e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_8	0x3050
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9	0x3052
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_10	0x3054
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_11	0x3056
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_12	0x3058
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_13	0x305a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_14	0x305c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15	0x305e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_0	0x3060
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_1	0x3062
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_2	0x3064
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_3	0x3066
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_4	0x3068
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_5	0x306a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_6	0x306c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_7	0x306e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_8	0x3070
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_9	0x3072
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_10	0x3074
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_11	0x3076
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_12	0x3078
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_13	0x307a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_14	0x307c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_15	0x307e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_0	0x3080
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_1	0x3082
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_2	0x3084
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_3	0x3086
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_4	0x3088
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_0	0x3400
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_1	0x3402
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_CLK_OVR_0_2	0x3404
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_0	0x3800
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_1	0x3802
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_2	0x3804
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_3	0x3806
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_4	0x3808
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_5	0x380a
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_6	0x380c
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_7	0x380e
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_8	0x3810
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_9	0x3812
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_10	0x3814
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_11	0x3816
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_12	0x3818
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_13	0x381a
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_14	0x381c
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_15	0x381e
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_0	0x3820
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_1	0x3822
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_2	0x3824
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_3	0x3826
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_4	0x3828
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0		0x3840
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1		0x3842
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_2		0x3844
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3		0x3846
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_4		0x3848
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5		0x384a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6		0x384c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7		0x384e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8		0x3850
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_9		0x3852
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_10	0x3854
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_11	0x3856
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_12		0x3858
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_13		0x385a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_14		0x385c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15		0x385e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_3_0		0x3860
+#define IPU7_CORE_DIG_RW_COMMON_0			0x3880
+#define IPU7_CORE_DIG_RW_COMMON_1			0x3882
+#define IPU7_CORE_DIG_RW_COMMON_2			0x3884
+#define IPU7_CORE_DIG_RW_COMMON_3			0x3886
+#define IPU7_CORE_DIG_RW_COMMON_4			0x3888
+#define IPU7_CORE_DIG_RW_COMMON_5			0x388a
+#define IPU7_CORE_DIG_RW_COMMON_6			0x388c
+#define IPU7_CORE_DIG_RW_COMMON_7			0x388e
+#define IPU7_CORE_DIG_RW_COMMON_8			0x3890
+#define IPU7_CORE_DIG_RW_COMMON_9			0x3892
+#define IPU7_CORE_DIG_RW_COMMON_10			0x3894
+#define IPU7_CORE_DIG_RW_COMMON_11			0x3896
+#define IPU7_CORE_DIG_RW_COMMON_12			0x3898
+#define IPU7_CORE_DIG_RW_COMMON_13			0x389a
+#define IPU7_CORE_DIG_RW_COMMON_14			0x389c
+#define IPU7_CORE_DIG_RW_COMMON_15			0x389e
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0	0x39e0
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_1	0x39e2
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2	0x39e4
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_3	0x39e6
+#define IPU7_CORE_DIG_COMMON_RW_DESKEW_FINE_MEM		0x3fe0
+#define IPU7_CORE_DIG_COMMON_R_DESKEW_FINE_MEM		0x3fe2
+#define IPU7_PPI_RW_DPHY_LANE0_LBERT_0			0x4000
+#define IPU7_PPI_RW_DPHY_LANE0_LBERT_1			0x4002
+#define IPU7_PPI_R_DPHY_LANE0_LBERT_0			0x4004
+#define IPU7_PPI_R_DPHY_LANE0_LBERT_1			0x4006
+#define IPU7_PPI_RW_DPHY_LANE0_SPARE			0x4008
+#define IPU7_PPI_RW_DPHY_LANE1_LBERT_0			0x4400
+#define IPU7_PPI_RW_DPHY_LANE1_LBERT_1			0x4402
+#define IPU7_PPI_R_DPHY_LANE1_LBERT_0			0x4404
+#define IPU7_PPI_R_DPHY_LANE1_LBERT_1			0x4406
+#define IPU7_PPI_RW_DPHY_LANE1_SPARE			0x4408
+#define IPU7_PPI_RW_DPHY_LANE2_LBERT_0			0x4800
+#define IPU7_PPI_RW_DPHY_LANE2_LBERT_1			0x4802
+#define IPU7_PPI_R_DPHY_LANE2_LBERT_0			0x4804
+#define IPU7_PPI_R_DPHY_LANE2_LBERT_1			0x4806
+#define IPU7_PPI_RW_DPHY_LANE2_SPARE			0x4808
+#define IPU7_PPI_RW_DPHY_LANE3_LBERT_0			0x4c00
+#define IPU7_PPI_RW_DPHY_LANE3_LBERT_1			0x4c02
+#define IPU7_PPI_R_DPHY_LANE3_LBERT_0			0x4c04
+#define IPU7_PPI_R_DPHY_LANE3_LBERT_1			0x4c06
+#define IPU7_PPI_RW_DPHY_LANE3_SPARE			0x4c08
+#define IPU7_CORE_DIG_DLANE_0_RW_CFG_0			0x6000
+#define IPU7_CORE_DIG_DLANE_0_RW_CFG_1			0x6002
+#define IPU7_CORE_DIG_DLANE_0_RW_CFG_2			0x6004
+#define IPU7_CORE_DIG_DLANE_0_RW_LP_0			0x6080
+#define IPU7_CORE_DIG_DLANE_0_RW_LP_1			0x6082
+#define IPU7_CORE_DIG_DLANE_0_RW_LP_2			0x6084
+#define IPU7_CORE_DIG_DLANE_0_R_LP_0			0x60a0
+#define IPU7_CORE_DIG_DLANE_0_R_LP_1			0x60a2
+#define IPU7_CORE_DIG_DLANE_0_R_HS_TX_0			0x60e0
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_0		0x6100
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_1		0x6102
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_2		0x6104
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_3		0x6106
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_4		0x6108
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_5		0x610a
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_6		0x610c
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_7		0x610e
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_8		0x6110
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_9		0x6112
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_0			0x6120
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_1			0x6122
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_2			0x6124
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_3			0x6126
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_4			0x6128
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_0		0x6200
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_1		0x6202
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_2		0x6204
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_3		0x6206
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_4		0x6208
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_5		0x620a
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_6		0x620c
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_7		0x620e
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_8		0x6210
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_9		0x6212
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_10		0x6214
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_11		0x6216
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_12		0x6218
+#define IPU7_CORE_DIG_DLANE_1_RW_CFG_0			0x6400
+#define IPU7_CORE_DIG_DLANE_1_RW_CFG_1			0x6402
+#define IPU7_CORE_DIG_DLANE_1_RW_CFG_2			0x6404
+#define IPU7_CORE_DIG_DLANE_1_RW_LP_0			0x6480
+#define IPU7_CORE_DIG_DLANE_1_RW_LP_1			0x6482
+#define IPU7_CORE_DIG_DLANE_1_RW_LP_2			0x6484
+#define IPU7_CORE_DIG_DLANE_1_R_LP_0			0x64a0
+#define IPU7_CORE_DIG_DLANE_1_R_LP_1			0x64a2
+#define IPU7_CORE_DIG_DLANE_1_R_HS_TX_0			0x64e0
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_0		0x6500
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_1		0x6502
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_2		0x6504
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_3		0x6506
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_4		0x6508
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_5		0x650a
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_6		0x650c
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_7		0x650e
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_8		0x6510
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_9		0x6512
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_0			0x6520
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_1			0x6522
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_2			0x6524
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_3			0x6526
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_4			0x6528
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_0		0x6600
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_1		0x6602
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_2		0x6604
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_3		0x6606
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_4		0x6608
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_5		0x660a
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_6		0x660c
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_7		0x660e
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_8		0x6610
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_9		0x6612
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_10		0x6614
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_11		0x6616
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_12		0x6618
+#define IPU7_CORE_DIG_DLANE_2_RW_CFG_0			0x6800
+#define IPU7_CORE_DIG_DLANE_2_RW_CFG_1			0x6802
+#define IPU7_CORE_DIG_DLANE_2_RW_CFG_2			0x6804
+#define IPU7_CORE_DIG_DLANE_2_RW_LP_0			0x6880
+#define IPU7_CORE_DIG_DLANE_2_RW_LP_1			0x6882
+#define IPU7_CORE_DIG_DLANE_2_RW_LP_2			0x6884
+#define IPU7_CORE_DIG_DLANE_2_R_LP_0			0x68a0
+#define IPU7_CORE_DIG_DLANE_2_R_LP_1			0x68a2
+#define IPU7_CORE_DIG_DLANE_2_R_HS_TX_0			0x68e0
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_0		0x6900
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_1		0x6902
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_2		0x6904
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_3		0x6906
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_4		0x6908
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_5		0x690a
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_6		0x690c
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_7		0x690e
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_8		0x6910
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_9		0x6912
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_0			0x6920
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_1			0x6922
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_2			0x6924
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_3			0x6926
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_4			0x6928
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_0		0x6a00
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_1		0x6a02
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_2		0x6a04
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_3		0x6a06
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_4		0x6a08
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_5		0x6a0a
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_6		0x6a0c
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_7		0x6a0e
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_8		0x6a10
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_9		0x6a12
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_10		0x6a14
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_11		0x6a16
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_12		0x6a18
+#define IPU7_CORE_DIG_DLANE_3_RW_CFG_0			0x6c00
+#define IPU7_CORE_DIG_DLANE_3_RW_CFG_1			0x6c02
+#define IPU7_CORE_DIG_DLANE_3_RW_CFG_2			0x6c04
+#define IPU7_CORE_DIG_DLANE_3_RW_LP_0			0x6c80
+#define IPU7_CORE_DIG_DLANE_3_RW_LP_1			0x6c82
+#define IPU7_CORE_DIG_DLANE_3_RW_LP_2			0x6c84
+#define IPU7_CORE_DIG_DLANE_3_R_LP_0			0x6ca0
+#define IPU7_CORE_DIG_DLANE_3_R_LP_1			0x6ca2
+#define IPU7_CORE_DIG_DLANE_3_R_HS_TX_0			0x6ce0
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_0		0x6d00
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_1		0x6d02
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_2		0x6d04
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_3		0x6d06
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_4		0x6d08
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_5		0x6d0a
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_6		0x6d0c
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_7		0x6d0e
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_8		0x6d10
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_9		0x6d12
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_0			0x6d20
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_1			0x6d22
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_2			0x6d24
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_3			0x6d26
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_4			0x6d28
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_0		0x6e00
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_1		0x6e02
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_2		0x6e04
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_3		0x6e06
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_4		0x6e08
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_5		0x6e0a
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_6		0x6e0c
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_7		0x6e0e
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_8		0x6e10
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_9		0x6e12
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_10		0x6e14
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_11		0x6e16
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_12		0x6e18
+#define IPU7_CORE_DIG_DLANE_CLK_RW_CFG_0		0x7000
+#define IPU7_CORE_DIG_DLANE_CLK_RW_CFG_1		0x7002
+#define IPU7_CORE_DIG_DLANE_CLK_RW_CFG_2		0x7004
+#define IPU7_CORE_DIG_DLANE_CLK_RW_LP_0			0x7080
+#define IPU7_CORE_DIG_DLANE_CLK_RW_LP_1			0x7082
+#define IPU7_CORE_DIG_DLANE_CLK_RW_LP_2			0x7084
+#define IPU7_CORE_DIG_DLANE_CLK_R_LP_0			0x70a0
+#define IPU7_CORE_DIG_DLANE_CLK_R_LP_1			0x70a2
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_TX_0		0x70e0
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_0		0x7100
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_1		0x7102
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_2		0x7104
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_3		0x7106
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_4		0x7108
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_5		0x710a
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_6		0x710c
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_7		0x710e
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_8		0x7110
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_9		0x7112
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_0		0x7120
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_1		0x7122
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_2		0x7124
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_3		0x7126
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_4		0x7128
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_0		0x7200
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_1		0x7202
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_2		0x7204
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_3		0x7206
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_4		0x7208
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_5		0x720a
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_6		0x720c
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_7		0x720e
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_8		0x7210
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_9		0x7212
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_10		0x7214
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_11		0x7216
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_12		0x7218
+#define IPU7_PPI_RW_CPHY_TRIO0_LBERT_0			0x8000
+#define IPU7_PPI_RW_CPHY_TRIO0_LBERT_1			0x8002
+#define IPU7_PPI_R_CPHY_TRIO0_LBERT_0			0x8004
+#define IPU7_PPI_R_CPHY_TRIO0_LBERT_1			0x8006
+#define IPU7_PPI_RW_CPHY_TRIO0_SPARE			0x8008
+#define IPU7_PPI_RW_CPHY_TRIO1_LBERT_0			0x8400
+#define IPU7_PPI_RW_CPHY_TRIO1_LBERT_1			0x8402
+#define IPU7_PPI_R_CPHY_TRIO1_LBERT_0			0x8404
+#define IPU7_PPI_R_CPHY_TRIO1_LBERT_1			0x8406
+#define IPU7_PPI_RW_CPHY_TRIO1_SPARE			0x8408
+#define IPU7_PPI_RW_CPHY_TRIO2_LBERT_0			0x8800
+#define IPU7_PPI_RW_CPHY_TRIO2_LBERT_1			0x8802
+#define IPU7_PPI_R_CPHY_TRIO2_LBERT_0			0x8804
+#define IPU7_PPI_R_CPHY_TRIO2_LBERT_1			0x8806
+#define IPU7_PPI_RW_CPHY_TRIO2_SPARE			0x8808
+#define IPU7_CORE_DIG_CLANE_0_RW_CFG_0			0xa000
+#define IPU7_CORE_DIG_CLANE_0_RW_CFG_2			0xa004
+#define IPU7_CORE_DIG_CLANE_0_RW_LP_0			0xa080
+#define IPU7_CORE_DIG_CLANE_0_RW_LP_1			0xa082
+#define IPU7_CORE_DIG_CLANE_0_RW_LP_2			0xa084
+#define IPU7_CORE_DIG_CLANE_0_R_LP_0			0xa0a0
+#define IPU7_CORE_DIG_CLANE_0_R_LP_1			0xa0a2
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_0		0xa100
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_1		0xa102
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_2		0xa104
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_3		0xa106
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_4		0xa108
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_5		0xa10a
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_6		0xa10c
+#define IPU7_CORE_DIG_CLANE_0_R_RX_0			0xa120
+#define IPU7_CORE_DIG_CLANE_0_R_RX_1			0xa122
+#define IPU7_CORE_DIG_CLANE_0_R_TX_0			0xa124
+#define IPU7_CORE_DIG_CLANE_0_R_RX_2			0xa126
+#define IPU7_CORE_DIG_CLANE_0_R_RX_3			0xa128
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_0		0xa200
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_1		0xa202
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_2		0xa204
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_3		0xa206
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_4		0xa208
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_5		0xa20a
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_6		0xa20c
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_7		0xa20e
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_8		0xa210
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_9		0xa212
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_10		0xa214
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_11		0xa216
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_12		0xa218
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_13		0xa21a
+#define IPU7_CORE_DIG_CLANE_1_RW_CFG_0			0xa400
+#define IPU7_CORE_DIG_CLANE_1_RW_CFG_2			0xa404
+#define IPU7_CORE_DIG_CLANE_1_RW_LP_0			0xa480
+#define IPU7_CORE_DIG_CLANE_1_RW_LP_1			0xa482
+#define IPU7_CORE_DIG_CLANE_1_RW_LP_2			0xa484
+#define IPU7_CORE_DIG_CLANE_1_R_LP_0			0xa4a0
+#define IPU7_CORE_DIG_CLANE_1_R_LP_1			0xa4a2
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_0		0xa500
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_1		0xa502
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_2		0xa504
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_3		0xa506
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_4		0xa508
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_5		0xa50a
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_6		0xa50c
+#define IPU7_CORE_DIG_CLANE_1_R_RX_0			0xa520
+#define IPU7_CORE_DIG_CLANE_1_R_RX_1			0xa522
+#define IPU7_CORE_DIG_CLANE_1_R_TX_0			0xa524
+#define IPU7_CORE_DIG_CLANE_1_R_RX_2			0xa526
+#define IPU7_CORE_DIG_CLANE_1_R_RX_3			0xa528
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_0		0xa600
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_1		0xa602
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_2		0xa604
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_3		0xa606
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_4		0xa608
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_5		0xa60a
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_6		0xa60c
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_7		0xa60e
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_8		0xa610
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_9		0xa612
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_10		0xa614
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_11		0xa616
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_12		0xa618
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_13		0xa61a
+#define IPU7_CORE_DIG_CLANE_2_RW_CFG_0			0xa800
+#define IPU7_CORE_DIG_CLANE_2_RW_CFG_2			0xa804
+#define IPU7_CORE_DIG_CLANE_2_RW_LP_0			0xa880
+#define IPU7_CORE_DIG_CLANE_2_RW_LP_1			0xa882
+#define IPU7_CORE_DIG_CLANE_2_RW_LP_2			0xa884
+#define IPU7_CORE_DIG_CLANE_2_R_LP_0			0xa8a0
+#define IPU7_CORE_DIG_CLANE_2_R_LP_1			0xa8a2
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_0		0xa900
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_1		0xa902
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_2		0xa904
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_3		0xa906
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_4		0xa908
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_5		0xa90a
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_6		0xa90c
+#define IPU7_CORE_DIG_CLANE_2_R_RX_0			0xa920
+#define IPU7_CORE_DIG_CLANE_2_R_RX_1			0xa922
+#define IPU7_CORE_DIG_CLANE_2_R_TX_0			0xa924
+#define IPU7_CORE_DIG_CLANE_2_R_RX_2			0xa926
+#define IPU7_CORE_DIG_CLANE_2_R_RX_3			0xa928
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_0		0xaa00
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_1		0xaa02
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_2		0xaa04
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_3		0xaa06
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_4		0xaa08
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_5		0xaa0a
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_6		0xaa0c
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_7		0xaa0e
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_8		0xaa10
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_9		0xaa12
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_10		0xaa14
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_11		0xaa16
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_12		0xaa18
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_13		0xaa1a
+
+/* dwc csi host controller registers */
+#define IPU7_IS_IO_CSI2_HOST_BASE(i)		(IPU7_IS_IO_BASE + 0x40000 + \
+						 0x2000 * (i))
+#define IPU7_VERSION				0x0
+#define IPU7_N_LANES				0x4
+#define IPU7_CSI2_RESETN			0x8
+#define IPU7_INT_ST_MAIN			0xc
+#define IPU7_DATA_IDS_1				0x10
+#define IPU7_DATA_IDS_2				0x14
+#define IPU7_CDPHY_MODE				0x1c
+#define IPU7_DATA_IDS_VC_1			0x30
+#define IPU7_DATA_IDS_VC_2			0x34
+#define IPU7_PHY_SHUTDOWNZ			0x40
+#define IPU7_DPHY_RSTZ				0x44
+#define IPU7_PHY_RX				0x48
+#define IPU7_PHY_STOPSTATE			0x4c
+#define IPU7_PHY_TEST_CTRL0			0x50
+#define IPU7_PHY_TEST_CTRL1			0x54
+#define IPU7_PPI_PG_PATTERN_VRES		0x60
+#define IPU7_PPI_PG_PATTERN_HRES		0x64
+#define IPU7_PPI_PG_CONFIG			0x68
+#define IPU7_PPI_PG_ENABLE			0x6c
+#define IPU7_PPI_PG_STATUS			0x70
+#define IPU7_VC_EXTENSION			0xc8
+#define IPU7_PHY_CAL				0xcc
+#define IPU7_INT_ST_PHY_FATAL			0xe0
+#define IPU7_INT_MSK_PHY_FATAL			0xe4
+#define IPU7_INT_FORCE_PHY_FATAL		0xe8
+#define IPU7_INT_ST_PKT_FATAL			0xf0
+#define IPU7_INT_MSK_PKT_FATAL			0xf4
+#define IPU7_INT_FORCE_PKT_FATAL		0xf8
+#define IPU7_INT_ST_PHY				0x110
+#define IPU7_INT_MSK_PHY			0x114
+#define IPU7_INT_FORCE_PHY			0x118
+#define IPU7_INT_ST_LINE			0x130
+#define IPU7_INT_MSK_LINE			0x134
+#define IPU7_INT_FORCE_LINE			0x138
+#define IPU7_INT_ST_BNDRY_FRAME_FATAL		0x280
+#define IPU7_INT_MSK_BNDRY_FRAME_FATAL		0x284
+#define IPU7_INT_FORCE_BNDRY_FRAME_FATAL	0x288
+#define IPU7_INT_ST_SEQ_FRAME_FATAL		0x290
+#define IPU7_INT_MSK_SEQ_FRAME_FATAL		0x294
+#define IPU7_INT_FORCE_SEQ_FRAME_FATAL		0x298
+#define IPU7_INT_ST_CRC_FRAME_FATAL		0x2a0
+#define IPU7_INT_MSK_CRC_FRAME_FATAL		0x2a4
+#define IPU7_INT_FORCE_CRC_FRAME_FATAL		0x2a8
+#define IPU7_INT_ST_PLD_CRC_FATAL		0x2b0
+#define IPU7_INT_MSK_PLD_CRC_FATAL		0x2b4
+#define IPU7_INT_FORCE_PLD_CRC_FATAL		0x2b8
+#define IPU7_INT_ST_DATA_ID			0x2c0
+#define IPU7_INT_MSK_DATA_ID			0x2c4
+#define IPU7_INT_FORCE_DATA_ID			0x2c8
+#define IPU7_INT_ST_ECC_CORRECTED		0x2d0
+#define IPU7_INT_MSK_ECC_CORRECTED		0x2d4
+#define IPU7_INT_FORCE_ECC_CORRECTED		0x2d8
+#define IPU7_SCRAMBLING				0x300
+#define IPU7_SCRAMBLING_SEED1			0x304
+#define IPU7_SCRAMBLING_SEED2			0x308
+#define IPU7_SCRAMBLING_SEED3			0x30c
+#define IPU7_SCRAMBLING_SEED4			0x310
+#define IPU7_SCRAMBLING				0x300
+
+#define IPU7_IS_IO_CSI2_ADPL_PORT_BASE(i)		(IPU7_IS_IO_BASE + 0x40800 + \
+							 0x2000 * (i))
+#define IPU7_CSI2_ADPL_INPUT_MODE			0x0
+#define IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN		0x4
+#define IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_ADDR	0x8
+#define IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_STATUS		0xc
+#define IPU7_CSI2_ADPL_IRQ_CTL_COMMON_STATUS		0xa4
+#define IPU7_CSI2_ADPL_IRQ_CTL_COMMON_CLEAR		0xa8
+#define IPU7_CSI2_ADPL_IRQ_CTL_COMMON_ENABLE		0xac
+#define IPU7_CSI2_ADPL_IRQ_CTL_FS_STATUS		0xbc
+#define IPU7_CSI2_ADPL_IRQ_CTL_FS_CLEAR			0xc0
+#define IPU7_CSI2_ADPL_IRQ_CTL_FS_ENABLE		0xc4
+#define IPU7_CSI2_ADPL_IRQ_CTL_FE_STATUS		0xc8
+#define IPU7_CSI2_ADPL_IRQ_CTL_FE_CLEAR			0xcc
+#define IPU7_CSI2_ADPL_IRQ_CTL_FE_ENABLE		0xd0
+
+/* software control the legacy csi irq */
+#define IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(i)	(IPU7_IS_IO_BASE + \
+							 0x40c00 + 0x2000 * (i))
+#define IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(i)	(IPU7_IS_IO_BASE + \
+							 0x40d00 + 0x2000 * (i))
+#define IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE		(IPU7_IS_IO_BASE + \
+							 0x49000)
+#define IPU7_IS_IO_CSI2_IRQ_CTRL_BASE			(IPU7_IS_IO_BASE + 0x4e100)
+
+#define IPU7_IRQ_CTL_EDGE				0x0
+#define IPU7_IRQ_CTL_MASK				0x4
+#define IPU7_IRQ_CTL_STATUS				0x8
+#define IPU7_IRQ_CTL_CLEAR				0xc
+#define IPU7_IRQ_CTL_ENABLE				0x10
+/* FE irq for PTL */
+#define IPU7_IRQ1_CTL_MASK				0x14
+#define IPU7_IRQ1_CTL_STATUS				0x18
+#define IPU7_IRQ1_CTL_CLEAR				0x1c
+#define IPU7_IRQ1_CTL_ENABLE				0x20
+
+/* software to set the clock gate to use the port or mgc */
+#define IPU7_IS_IO_GPREGS_BASE			(IPU7_IS_IO_BASE + 0x49200)
+#define IPU7_SRST_PORT_ARB			0x0
+#define IPU7_SRST_MGC				0x4
+#define IPU7_SRST_WIDTH_CONV			0x8
+#define IPU7_SRST_CSI_IRQ			0xc
+#define IPU7_SRST_CSI_LEGACY_IRQ		0x10
+#define IPU7_CLK_EN_TXCLKESC			0x14
+#define IPU7_CLK_DIV_FACTOR_IS_CLK		0x18
+#define IPU7_CLK_DIV_FACTOR_APB_CLK		0x1c
+#define IPU7_CSI_PORT_CLK_GATE			0x20
+#define IPU7_CSI_PORTAB_AGGREGATION		0x24
+#define IPU7_MGC_CLK_GATE			0x2c
+#define IPU7_CG_CTRL_BITS			0x3c
+#define IPU7_SPARE_RW				0xf8
+#define IPU7_SPARE_RO				0xfc
+
+#define IPU7_IS_IO_CSI2_MPF_PORT_BASE(i)	(IPU7_IS_IO_BASE + 0x53000 + \
+						 0x1000 * (i))
+#define IPU7_MPF_16_IRQ_CNTRL_STATUS		0x238
+#define IPU7_MPF_16_IRQ_CNTRL_CLEAR		0x23c
+#define IPU7_MPF_16_IRQ_CNTRL_ENABLE		0x240
+
+/* software config the phy */
+#define IPU7_IS_IO_CSI2_GPREGS_BASE		(IPU7_IS_IO_BASE + 0x53400)
+#define IPU8_IS_IO_CSI2_GPREGS_BASE		(IPU7_IS_IO_BASE + 0x40e00)
+#define IPU7_CSI_ADAPT_LAYER_SRST		0x0
+#define IPU7_MPF_SRST_RST			0x4
+#define IPU7_CSI_ERR_IRQ_CTRL_SRST		0x8
+#define IPU7_CSI_SYNC_RC_SRST			0xc
+#define IPU7_CSI_CG_CTRL_BITS			0x10
+#define IPU7_SOC_CSI2HOST_SELECT		0x14
+#define IPU7_PHY_RESET				0x18
+#define IPU7_PHY_SHUTDOWN			0x1c
+#define IPU7_PHY_MODE				0x20
+#define IPU7_PHY_READY				0x24
+#define IPU7_PHY_CLK_LANE_FORCE_CONTROL		0x28
+#define IPU7_PHY_CLK_LANE_CONTROL		0x2c
+#define IPU7_PHY_CLK_LANE_STATUS		0x30
+#define IPU7_PHY_LANE_RX_ESC_REQ		0x34
+#define IPU7_PHY_LANE_RX_ESC_DATA		0x38
+#define IPU7_PHY_LANE_TURNDISABLE		0x3c
+#define IPU7_PHY_LANE_DIRECTION			0x40
+#define IPU7_PHY_LANE_FORCE_CONTROL		0x44
+#define IPU7_PHY_LANE_CONTROL_EN		0x48
+#define IPU7_PHY_LANE_CONTROL_DATAWIDTH		0x4c
+#define IPU7_PHY_LANE_STATUS			0x50
+#define IPU7_PHY_LANE_ERR			0x54
+#define IPU7_PHY_LANE_RXALP			0x58
+#define IPU7_PHY_LANE_RXALP_NIBBLE		0x5c
+#define IPU7_PHY_PARITY_ERROR			0x60
+#define IPU7_PHY_DEBUG_REGS_CLK_GATE_EN		0x64
+#define IPU7_SPARE_RW				0xf8
+#define IPU7_SPARE_RO				0xfc
+
+/* software not touch */
+#define IPU7_PORT_ARB_BASE			(IPU7_IS_IO_BASE + 0x4e000)
+#define IPU7_PORT_ARB_IRQ_CTL_STATUS		0x4
+#define IPU7_PORT_ARB_IRQ_CTL_CLEAR		0x8
+#define IPU7_PORT_ARB_IRQ_CTL_ENABLE		0xc
+
+#define IPU7_MGC_PPC				4U
+#define IPU7_MGC_DTYPE_RAW(i)			(((i) - 8) / 2)
+#define IPU7_IS_IO_MGC_BASE			(IPU7_IS_IO_BASE + 0x48000)
+#define IPU7_MGC_KICK				0x0
+#define IPU7_MGC_ASYNC_STOP			0x4
+#define IPU7_MGC_PORT_OFFSET			0x100
+#define IPU7_MGC_CSI_PORT_MAP(i)		(0x8 + (i) * 0x4)
+#define IPU7_MGC_MG_PORT(i)			(IPU7_IS_IO_MGC_BASE + \
+						 (i) * IPU7_MGC_PORT_OFFSET)
+/* per mgc instance */
+#define IPU7_MGC_MG_CSI_ADAPT_LAYER_TYPE	0x28
+#define IPU7_MGC_MG_MODE			0x2c
+#define IPU7_MGC_MG_INIT_COUNTER		0x30
+#define IPU7_MGC_MG_MIPI_VC			0x34
+#define IPU7_MGC_MG_MIPI_DTYPES			0x38
+#define IPU7_MGC_MG_MULTI_DTYPES_MODE		0x3c
+#define IPU7_MGC_MG_NOF_FRAMES			0x40
+#define IPU7_MGC_MG_FRAME_DIM			0x44
+#define IPU7_MGC_MG_HBLANK			0x48
+#define IPU7_MGC_MG_VBLANK			0x4c
+#define IPU7_MGC_MG_TPG_MODE			0x50
+#define IPU7_MGC_MG_TPG_R0			0x54
+#define IPU7_MGC_MG_TPG_G0			0x58
+#define IPU7_MGC_MG_TPG_B0			0x5c
+#define IPU7_MGC_MG_TPG_R1			0x60
+#define IPU7_MGC_MG_TPG_G1			0x64
+#define IPU7_MGC_MG_TPG_B1			0x68
+#define IPU7_MGC_MG_TPG_FACTORS			0x6c
+#define IPU7_MGC_MG_TPG_MASKS			0x70
+#define IPU7_MGC_MG_TPG_XY_MASK			0x74
+#define IPU7_MGC_MG_TPG_TILE_DIM		0x78
+#define IPU7_MGC_MG_PRBS_LFSR_INIT_0		0x7c
+#define IPU7_MGC_MG_PRBS_LFSR_INIT_1		0x80
+#define IPU7_MGC_MG_SYNC_STOP_POINT		0x84
+#define IPU7_MGC_MG_SYNC_STOP_POINT_LOC		0x88
+#define IPU7_MGC_MG_ERR_INJECT			0x8c
+#define IPU7_MGC_MG_ERR_LOCATION		0x90
+#define IPU7_MGC_MG_DTO_SPEED_CTRL_EN		0x94
+#define IPU7_MGC_MG_DTO_SPEED_CTRL_INCR_VAL	0x98
+#define IPU7_MGC_MG_HOR_LOC_STTS		0x9c
+#define IPU7_MGC_MG_VER_LOC_STTS		0xa0
+#define IPU7_MGC_MG_FRAME_NUM_STTS		0xa4
+#define IPU7_MGC_MG_BUSY_STTS			0xa8
+#define IPU7_MGC_MG_STOPPED_STTS		0xac
+/* tile width and height in pixels for Chess board and Color palette */
+#define IPU7_MGC_TPG_TILE_WIDTH			64U
+#define IPU7_MGC_TPG_TILE_HEIGHT		64U
+
+#define IPU7_CSI_PORT_A_ADDR_OFFSET		0x0
+#define IPU7_CSI_PORT_B_ADDR_OFFSET		0x0
+#define IPU7_CSI_PORT_C_ADDR_OFFSET		0x0
+#define IPU7_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 IPU7_CSI_RX_NUM_ERRORS_IN_IRQ		12U
+#define IPU7_CSI_RX_NUM_SYNC_IN_IRQ		32U
+
+enum IPU7_MGC_CSI_ADPL_TYPE {
+	IPU7_MGC_MAPPED_2_LANES = 0,
+	IPU7_MGC_MAPPED_4_LANES = 1,
+};
+
+enum IPU7_CSI2HOST_SELECTION {
+	IPU7_CSI2HOST_SEL_SOC = 0,
+	IPU7_CSI2HOST_SEL_CSI2HOST = 1,
+};
+
+#define IPU7_CSI_LEGACY_IRQ_MASK(port)		(0x3 << ((port) *  2))
+#define IPU7P5_CSI_LEGACY_IRQ_MASK(port)	(0x7 << ((port) *  3))
+
+#define IPU7_ISYS_LEGACY_IRQ_CSI2(port)		(0x3 << (port))
+#define IPU7P5_ISYS_LEGACY_IRQ_CSI2(port)	(0x7 << (port))
+
+/* ---------------------------------------------------------------- */
+#define IPU7_CSI_REG_BASE				0x220000
+#define IPU7_CSI_REG_BASE_PORT(id)			((id) * 0x1000)
+
+/* CSI Port General Purpose Registers */
+#define IPU7_CSI_REG_PORT_GPREG_SRST			0x0
+#define IPU7_CSI_REG_PORT_GPREG_CSI2_SLV_REG_SRST	0x4
+#define IPU7_CSI_REG_PORT_GPREG_CSI2_PORT_CONTROL	0x8
+
+#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 */
-- 
2.55.0


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

* [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (24 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver Antti Laakso
                   ` (17 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Add ipu7 interrupt handler for software and CSI events.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h |   1 +
 drivers/media/pci/intel/ipu6/ipu6-isys.c      |   2 +-
 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c   | 330 +++++++++++++++++-
 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h   |  38 ++
 .../media/pci/intel/ipu6/ipu7-platform-regs.h |  20 ++
 5 files changed, 386 insertions(+), 5 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
index ce8eed91065c..ef367c7dc0fa 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
@@ -43,6 +43,7 @@ struct ipu6_isys_csi2 {
 	u32 receiver_errors;
 	unsigned int nlanes;
 	unsigned int port;
+	u32 legacy_irq_mask;
 };
 
 struct ipu6_isys_csi2_timing {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 086c0f01ccda..bcdaf96e9350 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1075,7 +1075,7 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
 };
 
 static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data = {
-	.isr = ipu6_isys_isr,
+	.isr = ipu7_isys_isr,
 	.isr_threaded = NULL,
 	.wake_isr_thread = false,
 	.fw_ops = &ipu7_fw_isys_ops,
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
index d35684a2cb58..b2f37aaf0a10 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -3,12 +3,17 @@
  * Copyright (C) 2026 Intel Corporation
  */
 
+#include <linux/cleanup.h>
+
 #include "ipu6-bus.h"
 #include "ipu6-dma.h"
 #include "ipu6-isys.h"
+#include "ipu6-platform-regs.h"
 #include "ipu7-boot.h"
 #include "ipu7-fw-com.h"
 #include "ipu7-fw-isys.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-platform-regs.h"
 
 static void ipu7_fw_isys_cleanup(struct ipu6_isys *isys)
 {
@@ -56,7 +61,7 @@ static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 	struct ipu7_insys_config *fw_config;
 	struct ipu7_fw_com_context *fwctx;
 	dma_addr_t fw_config_dma_addr;
-	unsigned int i, num_queues;
+	unsigned int num_queues;
 	u32 freq;
 	int ret;
 
@@ -94,7 +99,7 @@ static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
 	queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes =
 		sizeof(struct ipu7_insys_send_queue_token);
 
-	for (i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
+	for (unsigned int i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
 		queue_configs[i].max_capacity = IPU7_ISYS_SIZE_SEND_QUEUE;
 		queue_configs[i].token_size_in_bytes =
 			sizeof(struct ipu7_insys_send_queue_token);
@@ -321,7 +326,6 @@ static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev,
 					    unsigned int outputs)
 {
 	struct ipu7_fw_isys_frame_buff_set *buf = &msg->ipu7.frame;
-	unsigned int i;
 
 	dev_dbg(dev, "--------------------------\n");
 	dev_dbg(dev, "IPU_ISYS_BUFF_SET\n");
@@ -329,7 +333,7 @@ static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev,
 	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++) {
+	for (unsigned int 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);
@@ -463,3 +467,321 @@ const struct ipu6_fw_isys_ops ipu7_fw_isys_ops = {
 	.dump_stream_cfg = ipu7_fw_isys_dump_stream_cfg,
 	.dump_frame_buf_set = ipu7_fw_isys_dump_frame_buf_set,
 };
+
+static const struct ipu7_csi2_error {
+	const char *error_string;
+	bool is_info_only;
+} 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 ipu6_isys_csi2 *csi2)
+{
+	u32 offset = IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+	u32 status = readl(csi2->base + offset + IPU7_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 + IPU7_IRQ_CTL_CLEAR);
+	csi2->receiver_errors |= status & mask;
+}
+
+static void ipu7_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
+{
+	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;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(dphy_rx_errors); i++) {
+		if (status & BIT(i))
+			dev_err_ratelimited(&csi2->isys->adev->auxdev.dev,
+					    "csi2-%i error: %s\n",
+					    csi2->port,
+					    dphy_rx_errors[i].error_string);
+	}
+}
+
+static const struct resp_to_msg {
+	enum ipu7_insys_resp_type type;
+	const char *msg;
+} is_fw_msg[] = {
+	{ IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
+	 "STREAM_START_AND_CAPTURE_ACK" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK, "STREAM_ABORT_ACK" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK" },
+	{ IPU7_INSYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY" },
+	{ IPU7_INSYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF" },
+	{ IPU7_INSYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
+	 "STREAM_START_AND_CAPTURE_DONE" },
+	{ IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE" },
+	{ N_IPU7_INSYS_RESP_TYPE, "N_IPU7_INSYS_RESP_TYPE" },
+};
+
+static int ipu7_isys_isr_one(struct ipu6_bus_device *adev)
+{
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	struct ipu6_isys_stream *stream = NULL;
+	struct device *dev = &adev->auxdev.dev;
+	struct ipu6_isys_csi2 *csi2 = NULL;
+	struct ipu7_fw_isys_msg_err err_info;
+	struct isys_fw_msgs *isys_fw_msg;
+	struct ipu7_insys_resp *resp;
+	u64 ts;
+
+	if (!isys->fwctx)
+		return 1;
+
+	resp = ipu7_fw_isys_get_resp(isys);
+	if (!resp)
+		return 1;
+
+	if (resp->type >= N_IPU7_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 (err_info.err_code) {
+		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 >= IPU7_ISYS_MAX_STREAMS) {
+		dev_err(dev, "bad stream handle %u\n",
+			resp->stream_id);
+		goto leave;
+	}
+
+	stream = ipu6_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 = ipu6_isys_subdev_to_csi2(stream->asd);
+
+	switch (resp->type) {
+	case IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE:
+		complete(&stream->stream_open_completion);
+		break;
+	case IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK:
+		complete(&stream->stream_close_completion);
+		break;
+	case IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
+		complete(&stream->stream_start_completion);
+		break;
+	case IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK:
+		complete(&stream->stream_stop_completion);
+		break;
+	case IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK:
+		complete(&stream->stream_stop_completion);
+		break;
+	case IPU7_INSYS_RESP_TYPE_PIN_DATA_READY:
+		/*
+		 * firmware only release the capture msg until software
+		 * get pin_data_ready event
+		 */
+		isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id,
+					   struct isys_fw_msgs, dummy);
+
+		ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
+		if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS)
+			ipu6_stream_buf_ready(stream, resp->pin_id,
+					      resp->pin.addr, ts, 0);
+		else
+			dev_err(dev, "No handler for pin %u ready\n",
+				resp->pin_id);
+		if (csi2)
+			ipu7_isys_csi2_error(csi2);
+
+		break;
+	case IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK:
+		break;
+	case IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
+	case IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE:
+		break;
+	case IPU7_INSYS_RESP_TYPE_FRAME_SOF:
+		if (csi2)
+			ipu6_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)
+			% IPU6_ISYS_MAX_PARALLEL_SOF;
+		break;
+	case IPU7_INSYS_RESP_TYPE_FRAME_EOF:
+		if (csi2)
+			ipu6_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;
+	}
+
+	ipu6_isys_put_stream(stream);
+leave:
+	ipu7_fw_isys_put_resp(isys);
+
+	return 0;
+}
+
+#define IPU7_NR_OF_CSI2_VC		16U
+static void ipu7_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
+{
+	struct device *dev = &csi2->isys->adev->auxdev.dev;
+	struct ipu6_device *isp = csi2->isys->adev->isp;
+	struct ipu6_isys_stream *s;
+	u32 sync, offset;
+	u32 fe = 0;
+	u8 vc;
+
+	ipu7_isys_register_errors(csi2);
+
+	offset = IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+	sync = readl(csi2->base + offset + IPU7_IRQ_CTL_STATUS);
+	writel(sync, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+	dev_dbg(dev, "csi2-%u sync status 0x%08x\n", csi2->port, sync);
+
+	if (!IS_IPU7_MTL(isp)) {
+		fe = readl(csi2->base + offset + IPU7_IRQ1_CTL_STATUS);
+		writel(fe, csi2->base + offset + IPU7_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 = ipu6_isys_query_stream_by_source(csi2->isys,
+						     csi2->asd.source, vc);
+		if (!s)
+			continue;
+
+		if (!IS_IPU7_MTL(isp)) {
+			if (sync & IPU7P5_CSI_RX_SYNC_FS_VC & (1U << vc))
+				ipu6_isys_csi2_sof_event_by_stream(s);
+
+			if (fe & IPU7P5_CSI_RX_SYNC_FE_VC & (1U << vc))
+				ipu6_isys_csi2_eof_event_by_stream(s);
+		} else {
+			if (sync & IPU7_CSI_RX_SYNC_FS_VC & (1U << (vc * 2)))
+				ipu6_isys_csi2_sof_event_by_stream(s);
+
+			if (sync & IPU7_CSI_RX_SYNC_FE_VC & (2U << (vc * 2)))
+				ipu6_isys_csi2_eof_event_by_stream(s);
+		}
+	}
+}
+
+static void ipu7_dispatch_csi2_isr(struct ipu6_isys *isys, u32 status)
+{
+	for (unsigned int i = 0; i < isys->pdata->ipdata->csi2.nports; i++) {
+		if (!isys->csi2[i].base)
+			continue;
+		if (status & isys->csi2[i].legacy_irq_mask)
+			ipu7_isys_csi2_isr(&isys->csi2[i]);
+	}
+}
+
+irqreturn_t ipu7_isys_isr(struct ipu6_bus_device *adev)
+{
+	struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+	void __iomem *base = isys->pdata->base;
+	u32 status_sw, status_csi;
+	u32 csi_offset, sw_offset;
+
+	guard(spinlock)(&isys->power_lock);
+
+	if (!isys->power)
+		return IRQ_NONE;
+
+	csi_offset = IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE;
+	sw_offset = IPU7_IS_UC_CTRL_BASE;
+
+	status_csi = readl(base + csi_offset + IPU7_IRQ_CTL_STATUS);
+	status_sw = readl(base + sw_offset + IPU7_TO_SW_IRQ_CNTL_STATUS);
+
+	if (!status_csi && !status_sw)
+		return IRQ_NONE;
+
+	do {
+		writel(status_sw, base + sw_offset + IPU7_TO_SW_IRQ_CNTL_CLEAR);
+		writel(status_csi, base + csi_offset + IPU7_IRQ_CTL_CLEAR);
+
+		if (isys->isr_csi2_bits & status_csi)
+			ipu7_dispatch_csi2_isr(isys, status_csi);
+
+		if (!ipu7_isys_isr_one(adev))
+			status_sw = IPU7_TO_SW_IRQ_FW;
+		else
+			status_sw = 0;
+
+		status_csi = readl(base + csi_offset + IPU7_IRQ_CTL_STATUS);
+		status_sw |= readl(base + sw_offset +
+				   IPU7_TO_SW_IRQ_CNTL_STATUS);
+	} while ((status_csi & isys->isr_csi2_bits) ||
+		 (status_sw & IPU7_TO_SW_IRQ_FW));
+
+	writel(IPU7_IS_UC_TO_SW_IRQ_MASK,
+	       base + sw_offset + IPU7_TO_SW_IRQ_CNTL_MASK_N);
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
index 122531065362..d5289f6add8c 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
@@ -117,6 +117,43 @@ enum ipu7_insys_mipi_dt_rename_mode {
 	N_IPU7_INSYS_MIPI_DT_MODE
 };
 
+enum insys_msg_err_capture {
+	INSYS_MSG_ERR_CAPTURE_OK = 0,
+	INSYS_MSG_ERR_CAPTURE_STREAM_ID = 1,
+	INSYS_MSG_ERR_CAPTURE_PAYLOAD_PTR = 2,
+	INSYS_MSG_ERR_CAPTURE_MEM_SLOT = 3,
+	INSYS_MSG_ERR_CAPTURE_STREAMING_MODE = 4,
+	INSYS_MSG_ERR_CAPTURE_AVAILABLE_CMD_SLOT = 5,
+	INSYS_MSG_ERR_CAPTURE_CONSUMED_CMD_SLOT = 6,
+	INSYS_MSG_ERR_CAPTURE_CMD_SLOT_PAYLOAD_PTR = 7,
+	INSYS_MSG_ERR_CAPTURE_CMD_PREPARE = 8,
+	INSYS_MSG_ERR_CAPTURE_OUTPUT_PIN = 9,
+	INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP = 10,
+	INSYS_MSG_ERR_CAPTURE_FRAME_MESSAGES_MAP = 11,
+	INSYS_MSG_ERR_CAPTURE_TIMEOUT = 12,
+	INSYS_MSG_ERR_CAPTURE_INVALID_STREAM_STATE = 13,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_MULTIBIT_PH_ERROR_DETECTED = 14,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_PAYLOAD_CRC_ERROR = 15,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_INPUT_DATA_LOSS_ELASTIC_FIFO_OVFL  = 16,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_PIXEL_BUFFER_OVERFLOW = 17,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_BAD_FRAME_DIM = 18,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_PHY_SYNC_ERR = 19,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_SECURE_TOUCH = 20,
+	INSYS_MSG_ERR_CAPTURE_HW_ERR_MASTER_SLAVE_SYNC_ERR = 21,
+	INSYS_MSG_ERR_CAPTURE_FRAME_SKIP_ERR = 22,
+	INSYS_MSG_ERR_CAPTURE_FE_INPUT_FIFO_OVERFLOW_ERR = 23,
+	INSYS_MSG_ERR_CAPTURE_CMD_SUBMIT_TO_HW = 24,
+	INSYS_MSG_ERR_CAPTURE_N
+};
+
+enum insys_msg_err_groups {
+	INSYS_MSG_ERR_GROUP_RESERVED = 0,
+	INSYS_MSG_ERR_GROUP_GENERAL = 1,
+	INSYS_MSG_ERR_GROUP_STREAM = 2,
+	INSYS_MSG_ERR_GROUP_CAPTURE = 3,
+	INSYS_MSG_ERR_GROUP_N,
+};
+
 struct ipu7_fw_isys_logger_config {
 	u8 use_source_severity;
 	u8 source_severity[IPU7_FWLOG_MAX_LOGGER_SOURCES];
@@ -254,5 +291,6 @@ struct ipu7_fw_isys_frame_buff_set {
 } __packed;
 
 struct ipu6_fw_isys_ops *ipu7_fw_isys_get_ops(void);
+irqreturn_t ipu7_isys_isr(struct ipu6_bus_device *adev);
 
 #endif
diff --git a/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
index 3ca9d65e58b9..39cd5c0890e5 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
@@ -9,4 +9,24 @@
 #define IPU7_PS_UC_CTRL_BASE                   0x130000
 #define IPU7_PSYS_DMEM_OFFSET                  0x100000
 
+#define IPU7_IS_IO_BASE				0x280000
+#define IPU7_IS_IO_CSI2_GPREGS_BASE		(IPU7_IS_IO_BASE + 0x53400)
+
+#define IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE	(IPU7_IS_IO_BASE + 0x49000)
+#define IPU7_IRQ_CTL_EDGE			0x0
+#define IPU7_IRQ_CTL_MASK			0x4
+#define IPU7_IRQ_CTL_STATUS			0x8
+#define IPU7_IRQ_CTL_CLEAR			0xc
+#define IPU7_IRQ_CTL_ENABLE			0x10
+#define IPU7_CSI_RX_LEGACY_IRQ_MASK		0x1ff
+
+#define IPU7_TO_SW_IRQ_CNTL_EDGE		0x4000
+#define IPU7_TO_SW_IRQ_CNTL_MASK_N		0x4004
+#define IPU7_TO_SW_IRQ_CNTL_STATUS		0x4008
+#define IPU7_TO_SW_IRQ_CNTL_CLEAR		0x400c
+#define IPU7_TO_SW_IRQ_CNTL_ENABLE		0x4010
+#define IPU7_IS_UC_TO_SW_IRQ_MASK		0xf
+#define IPU7_TO_SW_IRQ_FW			BIT(0)
+#define IPU7_REG_PRINTF_AXI_CNTL		0x301c
+
 #endif
-- 
2.55.0


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

* [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (25 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable Antti Laakso
                   ` (16 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The csi receiver is completely different in ipu7 compared to ipu6,
add a driver for it.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/Makefile         |    3 +-
 drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h |    4 +
 drivers/media/pci/intel/ipu6/ipu6-isys.c      |    7 +-
 drivers/media/pci/intel/ipu6/ipu6-isys.h      |    1 +
 drivers/media/pci/intel/ipu6/ipu6.c           |    6 +
 drivers/media/pci/intel/ipu6/ipu6.h           |    2 +
 .../media/pci/intel/ipu6/ipu7-isys-csi-phy.c  | 1072 +++++++++++++++++
 .../media/pci/intel/ipu6/ipu7-isys-csi-phy.h  |   16 +
 8 files changed, 1109 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h

diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 66986d5709ae..676bc978b972 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -23,6 +23,7 @@ intel-ipu6-isys-y		:= ipu6-isys.o \
 				ipu6-isys-subdev.o \
 				ipu6-isys-mcd-phy.o \
 				ipu6-isys-jsl-phy.o \
-				ipu6-isys-dwc-phy.o
+				ipu6-isys-dwc-phy.o \
+				ipu7-isys-csi-phy.o
 
 obj-$(CONFIG_VIDEO_INTEL_IPU6)	+= intel-ipu6-isys.o
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
index ef367c7dc0fa..dbaaf00af623 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
@@ -16,6 +16,9 @@ struct ipu6_isys_video;
 struct ipu6_isys;
 struct ipu6_isys_stream;
 
+#define PHY_MODE_DPHY		0
+#define PHY_MODE_CPHY		1
+
 #define NR_OF_CSI2_VC		16
 #define INVALID_VC_ID		-1
 #define NR_OF_CSI2_SINK_PADS	1
@@ -44,6 +47,7 @@ struct ipu6_isys_csi2 {
 	unsigned int nlanes;
 	unsigned int port;
 	u32 legacy_irq_mask;
+	unsigned int phy_mode;
 };
 
 struct ipu6_isys_csi2_timing {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index bcdaf96e9350..5de5fd16ca30 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -41,6 +41,9 @@
 #include "ipu6-platform-buttress-regs.h"
 #include "ipu6-platform-isys-csi2-reg.h"
 #include "ipu6-platform-regs.h"
+#include "ipu7-isys-csi-phy.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-platform-regs.h"
 
 #define IPU6_BUTTRESS_FABIC_CONTROL		0x68
 #define GDA_ENABLE_IWAKE_INDEX			2
@@ -1004,7 +1007,9 @@ static int isys_probe(struct auxiliary_device *auxdev,
 
 	isys_iwake_watermark_init(isys);
 
-	if (IS_IPU6SE(adev->isp))
+	if (IS_IPU7(adev->isp))
+		isys->phy_set_power = ipu7_isys_csi_phy_set_power;
+	else if (IS_IPU6SE(adev->isp))
 		isys->phy_set_power = ipu6_isys_jsl_phy_set_power;
 	else if (IS_IPU6EP_MTL(adev->isp))
 		isys->phy_set_power = ipu6_isys_dwc_phy_set_power;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 697c090cc3b1..30539ea5f826 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -138,6 +138,7 @@ struct ipu6_isys {
 	int streams_ref_count[IPU6_ISYS_MAX_STREAMS];
 	void *fwctx;
 	u32 phy_termcal_val;
+	u32 phy_rext_cal;
 	bool need_reset;
 	bool icache_prefetch;
 	bool csi2_cse_ipc_not_supported;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 51174cafb1b4..fd7888a011a5 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -32,6 +32,7 @@
 #include "ipu6-platform-buttress-regs.h"
 #include "ipu6-platform-isys-csi2-reg.h"
 #include "ipu6-platform-regs.h"
+#include "ipu7-isys-csi2-regs.h"
 
 #define IPU6_PCI_BAR		0
 #define IPU7_PCI_PBBAR		4
@@ -325,6 +326,11 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
 		isys_ipdata.max_devq_size = IPU6SE_DEV_SEND_QUEUE_SIZE;
 		psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
 	}
+
+	if (IS_IPU7(isp)) {
+		isys_ipdata.csi2.gpreg = IPU7_IS_IO_CSI2_GPREGS_BASE;
+		isys_ipdata.csi2.nports = 4;
+	}
 }
 
 static struct ipu6_bus_device *
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index debd571b6f6d..6bef45a02c2b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -136,6 +136,8 @@ struct ipu6_isys_internal_csi2_pdata {
 	u32 ctrl0_irq_lnp;
 	u32 ctrl0_irq_status;
 	u32 fw_access_port_ofs;
+	/* IPU7-specific field */
+	u32 gpreg;
 };
 
 struct ipu6_isys_internal_tpg_pdata {
diff --git a/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
new file mode 100644
index 000000000000..10273c687faa
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
@@ -0,0 +1,1072 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2026 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 "ipu6.h"
+#include "ipu6-bus.h"
+#include "ipu6-isys.h"
+#include "ipu6-isys-csi2.h"
+#include "ipu7-isys-csi2-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 },
+	{ 2500, 3500, 7 },
+	{ }
+};
+
+static void dwc_phy_write(struct ipu6_isys *isys, u32 id, u32 addr, u16 data)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IPU7_IS_IO_CDPHY_BASE(id);
+
+	dev_dbg(&isys->adev->auxdev.dev, "phy write: reg 0x%lx = data 0x%04x",
+		(unsigned long)(base + addr - isys_base), data);
+	writew(data, base + addr);
+}
+
+static u16 dwc_phy_read(struct ipu6_isys *isys, u32 id, u32 addr)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IPU7_IS_IO_CDPHY_BASE(id);
+	u16 data;
+
+	data = readw(base + addr);
+	dev_dbg(&isys->adev->auxdev.dev, "phy read: reg 0x%lx = data 0x%04x",
+		(unsigned long)(base + addr - isys_base), data);
+
+	return data;
+}
+
+static void dwc_csi_write(struct ipu6_isys *isys, u32 id, u32 addr, u32 data)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IPU7_IS_IO_CSI2_HOST_BASE(id);
+	struct device *dev = &isys->adev->auxdev.dev;
+
+	dev_dbg(dev, "csi write: reg 0x%lx = data 0x%08x",
+		(unsigned long)(base + addr - isys_base), data);
+	writel(data, base + addr);
+	dev_dbg(dev, "csi read: reg 0x%lx = data 0x%08x",
+		(unsigned long)(base + addr - isys_base),
+		readl(base + addr));
+}
+
+static void gpreg_write(struct ipu6_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%lx = data 0x%08x",
+		(unsigned long)(base + addr - isys_base), data);
+	writel(data, base + addr);
+	dev_dbg(dev, "gpreg read: reg 0x%lx = data 0x%08x",
+		(unsigned long)(base + addr - isys_base),
+		readl(base + addr));
+}
+
+static u32 dwc_csi_read(struct ipu6_isys *isys, u32 id, u32 addr)
+{
+	void __iomem *isys_base = isys->pdata->base;
+	void __iomem *base = isys_base + IPU7_IS_IO_CSI2_HOST_BASE(id);
+	u32 data;
+
+	data = readl(base + addr);
+	dev_dbg(&isys->adev->auxdev.dev, "csi read: reg 0x%lx = data 0x%x",
+		(unsigned long)(base + addr - isys_base), data);
+
+	return data;
+}
+
+static void dwc_phy_write_mask(struct ipu6_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 ipu6_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 ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_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, IPU7_VERSION);
+	dev_dbg(dev, "csi-%d controller version = 0x%x", id, val);
+
+	/* num of active data lanes */
+	dwc_csi_write(isys, id, IPU7_N_LANES, lanes - 1);
+	dwc_csi_write(isys, id, IPU7_CDPHY_MODE, phy_mode);
+	dwc_csi_write(isys, id, IPU7_VC_EXTENSION, 0);
+
+	/* only mask PHY_FATAL and PKT_FATAL interrupts */
+	dwc_csi_write(isys, id, IPU7_INT_MSK_PHY_FATAL, 0xff);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_PKT_FATAL, 0x3);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_PHY, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_LINE, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_BNDRY_FRAME_FATAL, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_SEQ_FRAME_FATAL, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_CRC_FRAME_FATAL, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_PLD_CRC_FATAL, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_DATA_ID, 0x0);
+	dwc_csi_write(isys, id, IPU7_INT_MSK_ECC_CORRECTED, 0x0);
+}
+
+static void ipu7_isys_csi_phy_reset(struct ipu6_isys *isys, u32 id)
+{
+	dwc_csi_write(isys, id, IPU7_PHY_SHUTDOWNZ, 0);
+	dwc_csi_write(isys, id, IPU7_DPHY_RSTZ, 0);
+	dwc_csi_write(isys, id, IPU7_CSI2_RESETN, 0);
+	gpreg_write(isys, id, IPU7_PHY_RESET, 0);
+	gpreg_write(isys, id, IPU7_PHY_SHUTDOWN, 0);
+}
+
+/* 8 Data ID monitors, each Data ID is composed by pair of VC and data type */
+static int __dids_config(struct ipu6_isys_csi2 *csi2, u32 id, u8 vc, u8 dt)
+{
+	struct ipu6_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, IPU7_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 ? IPU7_DATA_IDS_VC_1 : IPU7_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 ? IPU7_DATA_IDS_1 : IPU7_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 ipu6_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;
+	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 (%pe)\n",
+			 csi2->asd.sd.name, 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 (unsigned int i = 0; i < desc.num_entries; i++) {
+		desc_entry = &desc.entry[i];
+		if (desc_entry->bus.csi2.vc < 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 ipu6_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;
+	u32 phy_ready;
+	u32 reg, rext;
+	int ret;
+
+	dev_dbg(dev, "waiting phy ready...\n");
+	ret = readl_poll_timeout(gpreg + IPU7_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 + IPU7_PHY_READY));
+	dev_dbg(dev, "csi %u IPU7_PHY_RX = 0x%08x\n", id,
+		dwc_csi_read(isys, id, IPU7_PHY_RX));
+	dev_dbg(dev, "csi %u IPU7_PHY_STOPSTATE = 0x%08x\n", id,
+		dwc_csi_read(isys, id, IPU7_PHY_STOPSTATE));
+	dev_dbg(dev, "csi %u IPU7_PHY_CAL = 0x%08x\n", id,
+		dwc_csi_read(isys, id, IPU7_PHY_CAL));
+	for (unsigned int i = 0; i < 4U; i++) {
+		reg = IPU7_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,
+			     IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5));
+	dev_dbg(dev, "phy %u TERMCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, IPU7_PPI_R_TERMCAL_DEBUG_0));
+	dev_dbg(dev, "phy %u LPDCOCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, IPU7_PPI_R_LPDCOCAL_DEBUG_RB));
+	dev_dbg(dev, "phy %u HSDCOCAL = 0x%04x\n", id,
+		dwc_phy_read(isys, id, IPU7_PPI_R_HSDCOCAL_DEBUG_RB));
+	dev_dbg(dev, "phy %u LPDCOCAL_VT = 0x%04x\n", id,
+		dwc_phy_read(isys, id, IPU7_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,
+				    IPU7_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)
+{
+	for (unsigned int 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 ipu6_isys *isys, u8 id, u8 lanes,
+				  bool aggregation, u64 mbps)
+{
+	struct ipu6_device *isp = isys->adev->isp;
+	u16 hsrxval0 = 0;
+	u16 hsrxval1 = 0;
+	u16 hsrxval2 = 0;
+	int index;
+	u16 reg;
+	u16 val;
+	u32 i;
+
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_7, 0, 0, 9);
+	if (mbps > 1500)
+		dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_7,
+				   40, 0, 7);
+	else
+		dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_7,
+				   104, 0, 7);
+
+	dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_8,
+			   80, 0, 7);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_0, 191, 0, 9);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_7, 34, 7, 12);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_1, 38, 8, 15);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 4, 12, 15);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 2, 10, 11);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 1, 8, 8);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 38, 0, 7);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 1, 9, 9);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_4, 10, 0, 9);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_6, 20, 0, 9);
+	dwc_phy_write_mask(isys, id, IPU7_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, IPU7_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, IPU7_PPI_RW_DDLCAL_CFG_1,
+				   table1[index].phase_bound, 0, 7);
+		dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_5,
+				   table1[index].ddlcal_dll_fbk, 4, 9);
+		dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_5,
+				   table1[index].ddlcal_ddl_coarse_bank, 0, 3);
+
+		reg = IPU7_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 = IPU7_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, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2,
+			   0, 0, 0);
+	if (!IS_IPU7_MTL(isp) || id == PORT_B || id == PORT_C) {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
+				   1, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
+				   0, 0, 0);
+	} else {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
+				   0, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
+				   1, 0, 0);
+	}
+
+	if (lanes == 4 && IS_IPU7_MTL(isp)) {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
+				   0, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
+				   0, 0, 0);
+	}
+
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_6, 1, 0, 2);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_6, 1, 3, 5);
+
+	reg = IPU7_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 = IPU7_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_MTL(isp) || id == PORT_B || id == PORT_C)
+		reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9;
+	else
+		reg = IPU7_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, IPU7_CORE_DIG_RW_COMMON_0, 1,
+				   1, 1);
+
+		reg = IPU7_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 = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15;
+		dwc_phy_write_mask(isys, id, reg, val, 3, 4);
+
+		reg = IPU7_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, IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_0,
+			   28, 0, 7);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_7,
+			   6, 0, 7);
+
+	reg = IPU7_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 = IPU7_CORE_DIG_DLANE_0_RW_CFG_1;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+				   ((mbps > 1500) ? 0x1 : 0x2), 2, 3);
+
+		reg = IPU7_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 = IPU7_CORE_DIG_DLANE_0_RW_LP_0;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 12, 15);
+
+		reg = IPU7_CORE_DIG_DLANE_0_RW_LP_2;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 0);
+
+		reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_1;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 16, 0, 7);
+
+		reg = IPU7_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 = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_4;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 150, 0, 15);
+
+		reg = IPU7_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 = IPU7_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 = IPU7_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 = IPU7_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, IPU7_CORE_DIG_DLANE_CLK_RW_LP_0,
+			   1, 12, 15);
+	dwc_phy_write_mask(isys, id, IPU7_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,
+				   IPU7_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, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
+			   hsrxval0, 0, 2);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
+			   hsrxval0, 0, 2);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
+			   hsrxval0, 0, 2);
+	if (lanes == 4 && IS_IPU7_MTL(isp)) {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
+				   hsrxval0, 0, 2);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
+				   hsrxval0, 0, 2);
+	}
+
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
+			   hsrxval1, 3, 4);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
+			   hsrxval1, 3, 4);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
+			   hsrxval1, 3, 4);
+	if (lanes == 4 && IS_IPU7_MTL(isp)) {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
+				   hsrxval1, 3, 4);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
+				   hsrxval1, 3, 4);
+	}
+
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15,
+			   hsrxval2, 0, 2);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15,
+			   hsrxval2, 0, 2);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15,
+			   hsrxval2, 0, 2);
+	if (lanes == 4 && IS_IPU7_MTL(isp)) {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15,
+				   hsrxval2, 0, 2);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_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,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8,
+				   isys->phy_rext_cal, 0, 3);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
+				   1, 11, 11);
+	}
+}
+
+static void ipu7_isys_cphy_config(struct ipu6_isys *isys, u8 id, u8 lanes,
+				  bool aggregation, u64 mbps)
+{
+	struct ipu6_device *isp = isys->adev->isp;
+	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;
+	u64 r64;
+	u32 r;
+
+	if (IS_IPU7P5(isp))
+		val = 0x15;
+	else
+		val = 0x155;
+
+	if (IS_IPU7_MTL(isp))
+		trios = 3;
+
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_7, val, 0, 9);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_7,
+			   104, 0, 7);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_8,
+			   16, 0, 7);
+
+	reg = IPU7_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 = IPU7_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 = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_1;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
+
+		reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_5;
+		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
+
+		reg = IPU7_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 = IPU7_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,
+			   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, 1, 0, 0);
+	dwc_phy_write_mask(isys, id,
+			   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, 0, 0, 0);
+	dwc_phy_write_mask(isys, id,
+			   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, 1, 0, 0);
+
+	if (!IS_IPU7P5(isp) && lanes == 4) {
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
+				   1, 0, 0);
+		dwc_phy_write_mask(isys, id,
+				   IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
+				   0, 0, 0);
+	}
+
+	for (i = 0; i < trios; i++) {
+		reg = IPU7_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)div64_u64_rem(7 * 1000 * 6, mbps * 5U, &r64) + 1;
+	if (r64 != 0)
+		deass_thresh++;
+
+	reg = IPU7_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 = div64_u64((224U - (9U * 7U)) * 1000U, 5U * mbps) - 7u;
+
+	if (delay_thresh < 1)
+		delay_thresh = 1;
+
+	reg = IPU7_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 = IPU7_CORE_DIG_RW_TRIO0_0;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+				   reset_thresh, 9, 11);
+
+	/* Tuning ITMINRX to 2 for CPHY */
+	reg = IPU7_CORE_DIG_CLANE_0_RW_LP_0;
+	for (i = 0; i < trios; i++)
+		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 2, 12, 15);
+
+	reg = IPU7_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 = IPU7_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 = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 + 0x400 * i;
+		dwc_phy_write_mask(isys, id, reg, 4U, 0, 2);
+		/* Set GMODE to 2 when CPHY >= 1.5Gsps */
+		if (mbps >= 1500)
+			dwc_phy_write_mask(isys, id, reg, 2U, 3, 4);
+		else
+			dwc_phy_write_mask(isys, id, reg, 0U, 3, 4);
+
+		reg = IPU7_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 ipu6_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 = ipu6_isys_csi2_get_link_freq(&isys->csi2[0]);
+	else
+		link_freq = ipu6_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, IPU7_PPI_STARTUP_RW_COMMON_DPHY_10,
+			   48, 0, 7);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2,
+			   1, 12, 13);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0,
+			   63, 2, 7);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_STARTUP_1_1,
+			   563, 0, 11);
+	dwc_phy_write_mask(isys, id, IPU7_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, IPU7_PPI_STARTUP_RW_COMMON_DPHY_2,
+				   0x45, 0, 7);
+
+	dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_6,
+			   39, 0, 7);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_CALIBCTRL_RW_COMMON_BG_0,
+			   500, 0, 8);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_TERMCAL_CFG_0, 38, 0, 6);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_OFFSETCAL_CFG_0, 7, 0, 4);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_TIMEBASE, 153, 0, 9);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_NREF, 800, 0, 10);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_NREF_RANGE,
+			   27, 0, 4);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_TWAIT_CONFIG,
+			   47, 0, 8);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_TWAIT_CONFIG,
+			   127, 9, 15);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_VT_CONFIG, 47, 7, 15);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_VT_CONFIG, 27, 2, 6);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_VT_CONFIG, 3, 0, 1);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_COARSE_CFG, 1, 0, 1);
+	dwc_phy_write_mask(isys, id, IPU7_PPI_RW_COMMON_CFG, 3, 0, 1);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
+			   0, 10, 10);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
+			   1, 10, 10);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
+			   0, 15, 15);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3,
+			   3, 8, 9);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
+			   0, 15, 15);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6,
+			   7, 12, 14);
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
+			   0, 8, 10);
+	/* resistance tuning: 1 for 45ohm, 0 for 50ohm */
+	dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5,
+			   1, 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;
+}
+
+static int ipu7_isys_csi_phy_powerup(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_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_MTL(isys->adev->isp) && lanes > 2 && id == PORT_A) {
+		aggregation = true;
+		lanes = 2;
+	}
+
+	ipu7_isys_csi_phy_reset(isys, id);
+	gpreg_write(isys, id, IPU7_PHY_CLK_LANE_CONTROL, 0x1);
+	gpreg_write(isys, id, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0x2);
+	gpreg_write(isys, id, IPU7_PHY_LANE_CONTROL_EN, (1U << lanes) - 1U);
+	gpreg_write(isys, id, IPU7_PHY_LANE_FORCE_CONTROL, 0xf);
+	gpreg_write(isys, id, IPU7_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, IPU7_PHY_CLK_LANE_CONTROL, 0x0);
+		gpreg_write(isys, PORT_B, IPU7_PHY_LANE_CONTROL_EN, 0x3);
+		gpreg_write(isys, PORT_B, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0x2);
+		gpreg_write(isys, PORT_B, IPU7_PHY_LANE_FORCE_CONTROL, 0xf);
+		gpreg_write(isys, PORT_B, IPU7_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, IPU7_PHY_RESET, 1);
+	gpreg_write(isys, id, IPU7_PHY_SHUTDOWN, 1);
+	dwc_csi_write(isys, id, IPU7_DPHY_RSTZ, 1);
+	dwc_csi_write(isys, id, IPU7_PHY_SHUTDOWNZ, 1);
+	dwc_csi_write(isys, id, IPU7_CSI2_RESETN, 1);
+
+	ret = ipu7_isys_phy_ready(isys, id);
+	if (ret < 0)
+		return ret;
+
+	gpreg_write(isys, id, IPU7_PHY_LANE_FORCE_CONTROL, 0);
+	gpreg_write(isys, id, IPU7_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, IPU7_PHY_RESET, 1);
+		gpreg_write(isys, PORT_B, IPU7_PHY_SHUTDOWN, 1);
+		dwc_csi_write(isys, PORT_B, IPU7_DPHY_RSTZ, 1);
+		dwc_csi_write(isys, PORT_B, IPU7_PHY_SHUTDOWNZ, 1);
+		dwc_csi_write(isys, PORT_B, IPU7_CSI2_RESETN, 1);
+		ret = ipu7_isys_phy_ready(isys, PORT_B);
+		if (ret < 0)
+			return ret;
+
+		gpreg_write(isys, PORT_B, IPU7_PHY_LANE_FORCE_CONTROL, 0);
+		gpreg_write(isys, PORT_B, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0);
+	}
+
+	return 0;
+}
+
+static void ipu7_isys_csi_phy_powerdown(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys *isys = csi2->isys;
+
+	ipu7_isys_csi_phy_reset(isys, csi2->port);
+	if (!IS_IPU7_MTL(isys->adev->isp) &&
+	    csi2->nlanes > 2U && csi2->port == PORT_A)
+		ipu7_isys_csi_phy_reset(isys, PORT_B);
+}
+
+int ipu7_isys_csi_phy_set_power(struct ipu6_isys *isys,
+				struct ipu6_isys_csi2_config *cfg,
+				const struct ipu6_isys_csi2_timing *timing,
+				bool on)
+{
+	struct ipu6_isys_csi2 *csi2 = &isys->csi2[cfg->port];
+
+	if (on)
+		return ipu7_isys_csi_phy_powerup(csi2);
+
+	ipu7_isys_csi_phy_powerdown(csi2);
+
+	return 0;
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h
new file mode 100644
index 000000000000..849fe888db07
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_ISYS_CSI_PHY_H
+#define IPU7_ISYS_CSI_PHY_H
+
+struct ipu6_isys;
+struct ipu6_isys_csi2_config;
+struct ipu6_isys_csi2_timing;
+
+int ipu7_isys_csi_phy_set_power(struct ipu6_isys *isys,
+				struct ipu6_isys_csi2_config *cfg,
+				const struct ipu6_isys_csi2_timing *timing,
+				bool on);
+
+#endif /* IPU7_ISYS_CSI_PHY_H */
-- 
2.55.0


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

* [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (26 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver Antti Laakso
                   ` (15 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Instead of single function, split csi2 receiver stream enable and
disable into own functions. This make it easier to add ipu7 support.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 98 ++++++++-----------
 1 file changed, 43 insertions(+), 55 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 7e539a0c6c92..7b63b08f5c54 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -228,64 +228,55 @@ void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
 	}
 }
 
-static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
-				     const struct ipu6_isys_csi2_timing *timing,
-				     unsigned int nlanes, int enable)
+static void ipu6_isys_csi2_stream_disable(struct ipu6_isys_csi2 *csi2)
 {
-	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
-	struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
 	struct ipu6_isys *isys = csi2->isys;
-	struct device *dev = &isys->adev->auxdev.dev;
 	struct ipu6_isys_csi2_config cfg;
-	unsigned int nports;
-	int ret = 0;
-	u32 mask = 0;
-	u32 i;
+	u32 mask = isys->pdata->ipdata->csi2.irq_mask;
+
+	cfg.port = csi2->port;
+	cfg.nlanes = csi2->nlanes;
+
+	writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE);
+	writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE);
+	writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
+	       CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
+	writel(mask, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
+	       CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
+	writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+	       CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
+	writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+	       CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
 
-	dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off",
-		csi2->port, nlanes);
+	isys->phy_set_power(isys, &cfg, NULL, false);
+
+	writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
+	       (isys->pdata->ipdata->csi2.fw_access_port_ofs, csi2->port));
+	writel(0, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port));
+}
+
+static int ipu6_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys *isys = csi2->isys;
+	struct ipu6_isys_csi2_timing timing = { };
+	struct ipu6_isys_csi2_config cfg;
+	unsigned int nports;
+	u32 mask;
+	int ret;
 
 	cfg.port = csi2->port;
-	cfg.nlanes = nlanes;
+	cfg.nlanes = csi2->nlanes;
 
 	mask = isys->pdata->ipdata->csi2.irq_mask;
 	nports = isys->pdata->ipdata->csi2.nports;
 
-	if (!enable) {
-		writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE);
-		writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE);
-
-		writel(0,
-		       csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
-		       CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
-		writel(mask,
-		       csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
-		       CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
-		writel(0,
-		       csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
-		       CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
-		writel(0xffffffff,
-		       csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
-		       CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
-
-		isys->phy_set_power(isys, &cfg, timing, false);
-
-		writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
-		       (isys->pdata->ipdata->csi2.fw_access_port_ofs,
-			csi2->port));
-		writel(0, isys->pdata->base +
-		       CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port));
-
-		return ret;
-	}
-
 	/* reset port reset */
 	writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
 	usleep_range(100, 200);
 	writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST);
 
 	/* enable port clock */
-	for (i = 0; i < nports; i++) {
+	for (unsigned int i = 0; i < nports; i++) {
 		writel(1, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(i));
 		writel(1, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
 		       (isys->pdata->ipdata->csi2.fw_access_port_ofs, i));
@@ -329,18 +320,18 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
 	writel(CSI_SENSOR_INPUT, csi2->base + CSI_REG_CSI_FE_MUX_CTRL);
 	writel(CSI_CNTR_SENSOR_LINE_ID | CSI_CNTR_SENSOR_FRAME_ID,
 	       csi2->base + CSI_REG_CSI_FE_SYNC_CNTR_SEL);
-	writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK, nlanes - 1),
+	writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK,
+			  csi2->nlanes - 1),
 	       csi2->base + CSI_REG_PPI2CSI_CONFIG_PPI_INTF);
 
 	writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
 	writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
 
-	ret = isys->phy_set_power(isys, &cfg, timing, true);
+	ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
 	if (ret)
-		dev_err(dev, "csi-%d phy power up failed %d\n", csi2->port,
-			ret);
+		return ret;
 
-	return ret;
+	return isys->phy_set_power(isys, &cfg, &timing, true);
 }
 
 static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
@@ -349,7 +340,6 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
 {
 	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
 	struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
-	struct ipu6_isys_csi2_timing timing = { };
 	struct v4l2_subdev *remote_sd;
 	struct media_pad *remote_pad;
 	u64 sink_streams;
@@ -362,18 +352,14 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
 		v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
 						&streams_mask);
 
-	ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
-	if (ret)
-		return ret;
-
-	ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
+	ret = ipu6_isys_csi2_stream_enable(csi2);
 	if (ret)
 		return ret;
 
 	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
 					 sink_streams);
 	if (ret) {
-		ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+		ipu6_isys_csi2_stream_disable(csi2);
 		return ret;
 	}
 
@@ -384,6 +370,8 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
 					  struct v4l2_subdev_state *state,
 					  u32 pad, u64 streams_mask)
 {
+	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
+	struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
 	struct v4l2_subdev *remote_sd;
 	struct media_pad *remote_pad;
 	u64 sink_streams;
@@ -395,7 +383,7 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
 	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
 
-	ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+	ipu6_isys_csi2_stream_disable(csi2);
 
 	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
 
-- 
2.55.0


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

* [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (27 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7 Antti Laakso
                   ` (14 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The csi2 receiver is different in ipu7, add support for it.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 119 +++++++++++++++++-
 1 file changed, 114 insertions(+), 5 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 7b63b08f5c54..160eace947f4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -24,6 +24,7 @@
 #include "ipu6-isys-csi2.h"
 #include "ipu6-isys-subdev.h"
 #include "ipu6-platform-isys-csi2-reg.h"
+#include "ipu7-isys-csi2-regs.h"
 
 static const u32 csi2_supported_codes[] = {
 	MEDIA_BUS_FMT_RGB565_1X16,
@@ -267,6 +268,10 @@ static int ipu6_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
 	cfg.port = csi2->port;
 	cfg.nlanes = csi2->nlanes;
 
+	ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
+	if (ret)
+		return ret;
+
 	mask = isys->pdata->ipdata->csi2.irq_mask;
 	nports = isys->pdata->ipdata->csi2.nports;
 
@@ -327,11 +332,106 @@ static int ipu6_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
 	writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
 	writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
 
-	ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
+	return isys->phy_set_power(isys, &cfg, &timing, true);
+}
+
+static void ipu7_csi2_irq_enable(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys *isys = csi2->isys;
+	unsigned int offset, mask;
+
+	/* enable CSI2 legacy error irq */
+	offset = IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+	/* enable CSI2 legacy sync irq */
+	offset = IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_SYNC_IRQ_MASK;
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+	if (!IS_IPU7_MTL(isys->adev->isp)) {
+		mask = IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK;
+		writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_CLEAR);
+		writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_MASK);
+		writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_ENABLE);
+	}
+}
+
+static void ipu7_csi2_irq_disable(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys *isys = csi2->isys;
+	unsigned int offset, mask;
+
+	/* disable CSI2 legacy error irq */
+	offset = IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+	writel(0, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+	writel(0, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+	/* disable CSI2 legacy sync irq */
+	offset = IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+	mask = IPU7_CSI_RX_SYNC_IRQ_MASK;
+	writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+	writel(0, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+	writel(0, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+	if (!IS_IPU7_MTL(isys->adev->isp)) {
+		writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_CLEAR);
+		writel(0, csi2->base + offset + IPU7_IRQ1_CTL_MASK);
+		writel(0, csi2->base + offset + IPU7_IRQ1_CTL_ENABLE);
+	}
+}
+
+static void ipu7_isys_csi2_stream_disable(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys *isys = csi2->isys;
+	void __iomem *base = isys->pdata->base;
+	struct ipu6_isys_csi2_config cfg;
+
+	cfg.port = csi2->port;
+	cfg.nlanes = csi2->nlanes;
+
+	isys->phy_set_power(isys, &cfg, NULL, false);
+
+	writel(0x4,
+	       base + IPU7_IS_IO_GPREGS_BASE + IPU7_CLK_DIV_FACTOR_APB_CLK);
+	ipu7_csi2_irq_disable(csi2);
+}
+
+static int ipu7_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
+{
+	struct ipu6_isys *isys = csi2->isys;
+	void __iomem *base = isys->pdata->base;
+	struct ipu6_isys_csi2_config cfg;
+	unsigned int offset = IPU7_IS_IO_GPREGS_BASE;
+	int ret;
+
+	writel(0x2, base + offset + IPU7_CLK_DIV_FACTOR_APB_CLK);
+	if (csi2->port == 0U && csi2->nlanes == 4U &&
+	    !IS_IPU7_MTL(isys->adev->isp))
+		writel(0x1, base + offset + IPU7_CSI_PORTAB_AGGREGATION);
+
+	/* input is coming from CSI receiver (sensor) */
+	offset = IPU7_IS_IO_CSI2_ADPL_PORT_BASE(csi2->port);
+	writel(CSI_SENSOR_INPUT, base + offset + IPU7_CSI2_ADPL_INPUT_MODE);
+	writel(1, base + offset + IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN);
+
+	cfg.port = csi2->port;
+	cfg.nlanes = csi2->nlanes;
+
+	ret = isys->phy_set_power(isys, &cfg, NULL, true);
 	if (ret)
 		return ret;
 
-	return isys->phy_set_power(isys, &cfg, &timing, true);
+	ipu7_csi2_irq_enable(csi2);
+
+	return 0;
 }
 
 static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
@@ -340,6 +440,7 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
 {
 	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
 	struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
+	struct ipu6_device *isp = asd->isys->adev->isp;
 	struct v4l2_subdev *remote_sd;
 	struct media_pad *remote_pad;
 	u64 sink_streams;
@@ -352,14 +453,18 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
 		v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
 						&streams_mask);
 
-	ret = ipu6_isys_csi2_stream_enable(csi2);
+	ret = IS_IPU7(isp) ? ipu7_isys_csi2_stream_enable(csi2) :
+			     ipu6_isys_csi2_stream_enable(csi2);
 	if (ret)
 		return ret;
 
 	ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
 					 sink_streams);
 	if (ret) {
-		ipu6_isys_csi2_stream_disable(csi2);
+		if IS_IPU7(isp)
+			ipu7_isys_csi2_stream_disable(csi2);
+		else
+			ipu6_isys_csi2_stream_disable(csi2);
 		return ret;
 	}
 
@@ -372,6 +477,7 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
 {
 	struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
 	struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
+	struct ipu6_device *isp = asd->isys->adev->isp;
 	struct v4l2_subdev *remote_sd;
 	struct media_pad *remote_pad;
 	u64 sink_streams;
@@ -383,7 +489,10 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
 	remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
 
-	ipu6_isys_csi2_stream_disable(csi2);
+	if IS_IPU7(isp)
+		ipu7_isys_csi2_stream_disable(csi2);
+	else
+		ipu6_isys_csi2_stream_disable(csi2);
 
 	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
 
-- 
2.55.0


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

* [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (28 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts Antti Laakso
                   ` (13 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

For ipu7 bus type can be CPHY or DPHY.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys.c | 8 ++++++++
 drivers/media/pci/intel/ipu6/ipu6-isys.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 5de5fd16ca30..976ed064f262 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -133,6 +133,9 @@ isys_complete_ext_device_registration(struct ipu6_isys *isys,
 	}
 
 	isys->csi2[csi2->port].nlanes = csi2->nlanes;
+	isys->csi2[csi2->port].phy_mode =
+		csi2->bus_type == V4L2_MBUS_CSI2_DPHY ?
+		PHY_MODE_DPHY : PHY_MODE_CPHY;
 
 	return 0;
 
@@ -639,6 +642,10 @@ static int isys_notifier_init(struct ipu6_isys *isys)
 			continue;
 
 		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+		if (ret && IS_IPU7(isp)) {
+			vep.bus_type = V4L2_MBUS_CSI2_CPHY;
+			ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+		}
 		if (ret) {
 			dev_err(dev, "fwnode endpoint parse failed: %d\n", ret);
 			goto err_parse;
@@ -654,6 +661,7 @@ static int isys_notifier_init(struct ipu6_isys *isys)
 
 		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;
 
 		dev_dbg(dev, "remote endpoint port %d with %d lanes added\n",
 			s_asd->csi2.port, s_asd->csi2.nlanes);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 30539ea5f826..8674c041b994 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -14,6 +14,7 @@
 #include <media/media-device.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
 
 #include "ipu6.h"
 #include "ipu6-fw-isys.h"
@@ -96,6 +97,7 @@ struct isys_iwake_watermark {
 struct ipu6_isys_csi2_config {
 	u32 nlanes;
 	u32 port;
+	enum v4l2_mbus_type bus_type;
 };
 
 struct sensor_async_sd {
-- 
2.55.0


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

* [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (29 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7 Antti Laakso
                   ` (12 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Add ipu7 specific isys initialization of clocks and
enabling interrupts.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys.c | 56 +++++++++++++++++++++---
 1 file changed, 49 insertions(+), 7 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 976ed064f262..622f74021f6d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -180,13 +180,23 @@ static int isys_csi2_register_subdevices(struct ipu6_isys *isys)
 	int ret;
 
 	for (i = 0; i < csi2_pdata->nports; i++) {
-		ret = ipu6_isys_csi2_init(&isys->csi2[i], isys,
-					  isys->pdata->base +
-					  CSI_REG_PORT_BASE(i), i);
+		void __iomem *base = isys->pdata->base;
+
+		if (IS_IPU7(isys->adev->isp)) {
+			u32 mask = IS_IPU7_MTL(isys->adev->isp) ?
+					IPU7_CSI_LEGACY_IRQ_MASK(i) :
+					IPU7P5_CSI_LEGACY_IRQ_MASK(i);
+
+			isys->isr_csi2_bits |= mask;
+			isys->csi2[i].legacy_irq_mask = mask;
+		} else {
+			base += CSI_REG_PORT_BASE(i);
+			isys->isr_csi2_bits |= IPU6_ISYS_UNISPART_IRQ_CSI2(i);
+		}
+
+		ret = ipu6_isys_csi2_init(&isys->csi2[i], isys, base, i);
 		if (ret)
 			goto fail;
-
-		isys->isr_csi2_bits |= IPU6_ISYS_UNISPART_IRQ_CSI2(i);
 	}
 
 	return 0;
@@ -273,7 +283,36 @@ static int isys_register_video_devices(struct ipu6_isys *isys)
 	return ret;
 }
 
-static void isys_setup_hw(struct ipu6_isys *isys)
+static void ipu7_isys_setup_hw(struct ipu6_isys *isys)
+{
+	u32 offset, mask;
+	void __iomem *base = isys->pdata->base;
+
+	offset = IPU7_IS_IO_GPREGS_BASE;
+
+	writel(0x0, base + offset + IPU7_CLK_EN_TXCLKESC);
+	/* Update if ISYS freq updated (0: 400/1, 1:400/2, 63:400/64) */
+	writel(0x0, base + offset + IPU7_CLK_DIV_FACTOR_IS_CLK);
+	/* correct the initial printf configuration */
+	writel(0x200, base + IPU7_IS_UC_CTRL_BASE + IPU7_REG_PRINTF_AXI_CNTL);
+
+	offset = IPU7_IS_UC_CTRL_BASE;
+	mask = IPU7_IS_UC_TO_SW_IRQ_MASK;
+
+	writel(mask, base + offset + IPU7_TO_SW_IRQ_CNTL_CLEAR);
+	writel(mask, base + offset + IPU7_TO_SW_IRQ_CNTL_MASK_N);
+	writel(mask, base + offset + IPU7_TO_SW_IRQ_CNTL_ENABLE);
+
+	offset = IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE;
+	mask = IPU7_CSI_RX_LEGACY_IRQ_MASK;
+
+	writel(mask, base + offset + IPU7_IRQ_CTL_EDGE);
+	writel(mask, base + offset + IPU7_IRQ_CTL_CLEAR);
+	writel(mask, base + offset + IPU7_IRQ_CTL_MASK);
+	writel(mask, base + offset + IPU7_IRQ_CTL_ENABLE);
+}
+
+static void ipu6_isys_setup_hw(struct ipu6_isys *isys)
 {
 	void __iomem *base = isys->pdata->base;
 	const u8 *thd = isys->pdata->ipdata->hw_variant.cdc_fifo_threshold;
@@ -783,7 +822,10 @@ static int isys_runtime_pm_resume(struct device *dev)
 	isys->power = 1;
 	spin_unlock_irqrestore(&isys->power_lock, flags);
 
-	isys_setup_hw(isys);
+	if (IS_IPU7(isp))
+		ipu7_isys_setup_hw(isys);
+	else
+		ipu6_isys_setup_hw(isys);
 
 	set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
 
-- 
2.55.0


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

* [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (30 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6 Antti Laakso
                   ` (11 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 don't have watermark nor LTR support, skip it.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys-video.c |  4 +++-
 drivers/media/pci/intel/ipu6/ipu6-isys.c       | 12 +++++++-----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 560524e6e624..9634b4f232bd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -727,8 +727,10 @@ void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
 {
 	struct isys_iwake_watermark *iwake_watermark =
 		&av->isys->iwake_watermark;
+	struct ipu6_device *isp = av->isys->adev->isp;
 
-	if (!av->watermark.pixel_rate)
+	if (IS_IPU7(isp) ||
+	    !av->watermark.pixel_rate)
 		return;
 
 	if (state) {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 622f74021f6d..5a3ba5007249 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -822,12 +822,12 @@ static int isys_runtime_pm_resume(struct device *dev)
 	isys->power = 1;
 	spin_unlock_irqrestore(&isys->power_lock, flags);
 
-	if (IS_IPU7(isp))
+	if (IS_IPU7(isp)) {
 		ipu7_isys_setup_hw(isys);
-	else
+	} else {
 		ipu6_isys_setup_hw(isys);
-
-	set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
+		set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
+	}
 
 	return 0;
 }
@@ -836,6 +836,7 @@ static int isys_runtime_pm_suspend(struct device *dev)
 {
 	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
 	struct ipu6_isys *isys = dev_get_drvdata(dev);
+	struct ipu6_device *isp = adev->isp;
 	unsigned long flags;
 
 	spin_lock_irqsave(&isys->power_lock, flags);
@@ -849,7 +850,8 @@ static int isys_runtime_pm_suspend(struct device *dev)
 	isys->phy_termcal_val = 0;
 	cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
 
-	set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_OFF);
+	if (!IS_IPU7(isp))
+		set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_OFF);
 
 	ipu6_mmu_hw_cleanup(adev->mmu);
 
-- 
2.55.0


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

* [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (31 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only Antti Laakso
                   ` (10 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 don't have SPC.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index fd7888a011a5..cb1145080460 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -232,10 +232,16 @@ void ipu6_configure_spc(struct ipu6_device *isp,
 			int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
 			dma_addr_t pkg_dir_dma_addr)
 {
-	void __iomem *dmem_base = base + hw_variant->dmem_offset;
-	void __iomem *spc_regs_base = base + hw_variant->spc_offset;
+	void __iomem *dmem_base;
+	void __iomem *spc_regs_base;
 	u32 val;
 
+	if (IS_IPU7(isp))
+		return;
+
+	dmem_base = base + hw_variant->dmem_offset;
+	spc_regs_base = base + hw_variant->spc_offset;
+
 	val = readl(spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
 	val |= IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
 	writel(val, spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
-- 
2.55.0


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

* [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (32 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe Antti Laakso
                   ` (9 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 doesn't support the VC arbitration mechanism that exist in
ipu6.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index cb1145080460..7d1c3713a69b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -447,7 +447,12 @@ static int ipu6_pci_config_setup(struct pci_dev *dev)
 
 static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
 {
-	u32 val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
+	u32 val;
+
+	if (IS_IPU7(isp))
+		return;
+
+	val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
 
 	if (IPU6_BTRS_ARB_STALL_MODE_VC0 == IPU6_BTRS_ARB_MODE_TYPE_STALL)
 		val |= BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0;
-- 
2.55.0


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

* [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (33 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7 Antti Laakso
                   ` (8 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Buttress registers are stored in separate buffer, which is passed
down to bus driver. Move allocation of this buffer to subsystem init
to cleanup pci probe function a bit.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6.c | 43 +++++++++++++++--------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 7d1c3713a69b..4e4f32723904 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -90,7 +90,7 @@ static struct ipu6_psys_internal_pdata psys_ipdata = {
 	},
 };
 
-static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
+static const struct ipu6_buttress_ctrl ipu6_isys_buttress_ctrl = {
 	.subsys_id = IPU_ISYS,
 	.ratio = IPU6_IS_FREQ_CTL_DEFAULT_RATIO,
 	.qos_floor = IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
@@ -101,7 +101,7 @@ static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
 	.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
 };
 
-static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
+static const struct ipu6_buttress_ctrl ipu6_psys_buttress_ctrl = {
 	.subsys_id = IPU_PSYS,
 	.ratio = IPU6_PS_FREQ_CTL_DEFAULT_RATIO,
 	.qos_floor = IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
@@ -341,11 +341,12 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
 
 static struct ipu6_bus_device *
 ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
-	       struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
+	       const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
 	       const struct ipu6_isys_internal_pdata *ipdata)
 {
 	struct device *dev = &pdev->dev;
 	struct ipu6_bus_device *isys_adev;
+	struct ipu6_buttress_ctrl *devm_ctrl;
 	struct ipu6_isys_pdata *pdata;
 	int ret;
 
@@ -355,6 +356,10 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
 		return ERR_PTR(ret);
 	}
 
+	devm_ctrl = devm_kmemdup(dev, ctrl, sizeof(*ctrl), GFP_KERNEL);
+	if (!devm_ctrl)
+		return ERR_PTR(-ENOMEM);
+
 	pdata = kzalloc_obj(*pdata);
 	if (!pdata)
 		return ERR_PTR(-ENOMEM);
@@ -362,7 +367,7 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
 	pdata->base = base;
 	pdata->ipdata = ipdata;
 
-	isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
+	isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, devm_ctrl,
 					       IPU6_ISYS_NAME);
 	if (IS_ERR(isys_adev)) {
 		kfree(pdata);
@@ -388,13 +393,19 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
 
 static struct ipu6_bus_device *
 ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
-	       struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
+	       const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
 	       const struct ipu6_psys_internal_pdata *ipdata)
 {
+	struct device *dev = &pdev->dev;
 	struct ipu6_bus_device *psys_adev;
+	struct ipu6_buttress_ctrl *devm_ctrl;
 	struct ipu6_psys_pdata *pdata;
 	int ret;
 
+	devm_ctrl = devm_kmemdup(dev, ctrl, sizeof(*ctrl), GFP_KERNEL);
+	if (!devm_ctrl)
+		return ERR_PTR(-ENOMEM);
+
 	pdata = kzalloc_obj(*pdata);
 	if (!pdata)
 		return ERR_PTR(-ENOMEM);
@@ -402,7 +413,7 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
 	pdata->base = base;
 	pdata->ipdata = ipdata;
 
-	psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
+	psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, devm_ctrl,
 					       IPU6_PSYS_NAME);
 	if (IS_ERR(psys_adev)) {
 		kfree(pdata);
@@ -469,7 +480,7 @@ static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
 
 static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	struct ipu6_buttress_ctrl *isys_ctrl = NULL, *psys_ctrl = NULL;
+	const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
 	struct device *dev = &pdev->dev;
 	void __iomem *isys_base = NULL;
 	void __iomem *psys_base = NULL;
@@ -484,6 +495,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
 	isp->buttress.regs = &ipu6_buttress_regs;
+	isys_ctrl = &ipu6_isys_buttress_ctrl;
+	psys_ctrl = &ipu6_psys_buttress_ctrl;
 
 	switch (id->device) {
 	case PCI_DEVICE_ID_INTEL_IPU6:
@@ -513,6 +526,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		isp->hw_ver = IPU_VERSION_7;
 		isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
 		isp->buttress.regs = &ipu7_buttress_regs;
+		isys_ctrl = &ipu7_isys_buttress_ctrl;
+		psys_ctrl = &ipu7_psys_buttress_ctrl;
 		break;
 	default:
 		return dev_err_probe(dev, -ENODEV,
@@ -582,13 +597,6 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_ipu6_bus_del_devices;
 	}
 
-	isys_ctrl = devm_kmemdup(dev, &isys_buttress_ctrl,
-				 sizeof(isys_buttress_ctrl), GFP_KERNEL);
-	if (!isys_ctrl) {
-		ret = -ENOMEM;
-		goto out_ipu6_bus_del_devices;
-	}
-
 	isp->isys = ipu6_isys_init(pdev, dev, isys_ctrl, isys_base,
 				   &isys_ipdata);
 	if (IS_ERR(isp->isys)) {
@@ -596,13 +604,6 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_ipu6_bus_del_devices;
 	}
 
-	psys_ctrl = devm_kmemdup(dev, &psys_buttress_ctrl,
-				 sizeof(psys_buttress_ctrl), GFP_KERNEL);
-	if (!psys_ctrl) {
-		ret = -ENOMEM;
-		goto out_ipu6_bus_del_devices;
-	}
-
 	isp->psys = ipu6_psys_init(pdev, &isp->isys->auxdev.dev, psys_ctrl,
 				   psys_base, &psys_ipdata);
 	if (IS_ERR(isp->psys)) {
-- 
2.55.0


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

* [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (34 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 37/44] media: ipu6: Add support for fixed iova region Antti Laakso
                   ` (7 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Add SKU ID to buttress register map to get correct ID for both IPUs.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.h | 1 +
 drivers/media/pci/intel/ipu6/ipu6.c          | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index af72de2b8729..47a49e961945 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -54,6 +54,7 @@ struct ipu6_buttress_registers {
 	u32 db0_out;
 	u32 data0_in;
 	u32 data0_out;
+	u32 sku_id;
 
 	/* Bitmasks */
 	u32 irq_is;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 4e4f32723904..428ad046e239 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -153,6 +153,7 @@ static const struct ipu6_buttress_registers ipu6_buttress_regs = {
 	.db0_out	= BUTTRESS_REG_IU2CSEDB0,
 	.data0_in	= BUTTRESS_REG_CSE2IUDATA0,
 	.data0_out	= BUTTRESS_REG_IU2CSEDATA0,
+	.sku_id		= BUTTRESS_REG_SKU,
 
 	/* Bitmasks */
 	.irq_is		= BUTTRESS_ISR_IS_IRQ,
@@ -182,6 +183,7 @@ static const struct ipu6_buttress_registers ipu7_buttress_regs = {
 	.db0_out	= IPU7_BUTTRESS_REG_IU2CSEDB0,
 	.data0_in	= IPU7_BUTTRESS_REG_CSE2IUDATA0,
 	.data0_out	= IPU7_BUTTRESS_REG_IU2CSEDATA0,
+	.sku_id		= IPU7_BUTTRESS_REG_SKU,
 
 	/* Bitmasks */
 	.irq_is		= IPU7_BUTTRESS_IRQ_IS_IRQ,
@@ -657,7 +659,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	/* Configure the arbitration mechanisms for VC requests */
 	ipu6_configure_vc_mechanism(isp);
 
-	val = readl(isp->base + BUTTRESS_REG_SKU);
+	val = readl(isp->base + isp->buttress.regs->sku_id);
 	sku_id = FIELD_GET(GENMASK(6, 4), val);
 	version = FIELD_GET(GENMASK(3, 0), val);
 	dev_info(dev, "IPU%u-v%u[%x] hardware version %d\n", version, sku_id,
-- 
2.55.0


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

* [PATCH v2 37/44] media: ipu6: Add support for fixed iova region
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (35 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable Antti Laakso
                   ` (6 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7 need specific region for firmware in non-secure mode,
add support for it.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-dma.c | 20 +++++++++++++++++---
 drivers/media/pci/intel/ipu6/ipu6-dma.h |  2 ++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c
index 6e8295d9c3a3..90f530a93779 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c
@@ -371,6 +371,17 @@ void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
 }
 EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, "INTEL_IPU6");
 
+static struct iova *ipu7_get_fw_code_region(struct ipu6_bus_device *sys)
+{
+	struct ipu6_mmu *mmu = sys->mmu;
+	unsigned long lo, hi;
+
+	lo = iova_pfn(&mmu->dmap->iovad, IPU7_FW_CODE_REGION_START);
+	hi = iova_pfn(&mmu->dmap->iovad, IPU7_FW_CODE_REGION_END) - 1U;
+
+	return reserve_iova(&mmu->dmap->iovad, lo, hi);
+}
+
 int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
 		    int nents, enum dma_data_direction dir,
 		    unsigned long attrs)
@@ -397,10 +408,13 @@ int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
 	dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n",
 		nents, npages);
 
-	iova = alloc_iova(&mmu->dmap->iovad, npages,
-			  PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0);
+	if (attrs & DMA_ATTR_RESERVE_REGION)
+		iova = ipu7_get_fw_code_region(sys);
+	else
+		iova = alloc_iova(&mmu->dmap->iovad, npages,
+				  PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0);
 	if (!iova)
-		return 0;
+		return -ENOMEM;
 
 	dev_dbg(dev, "dmamap: iova low pfn %lu, high pfn %lu\n", iova->pfn_lo,
 		iova->pfn_hi);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.h b/drivers/media/pci/intel/ipu6/ipu6-dma.h
index ae9b9a5df57f..e5e0e7860423 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.h
@@ -10,6 +10,8 @@
 
 #include "ipu6-bus.h"
 
+#define DMA_ATTR_RESERVE_REGION		BIT(31)
+
 struct ipu6_mmu_info;
 
 struct ipu6_dma_mapping {
-- 
2.55.0


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

* [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (36 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 37/44] media: ipu6: Add support for fixed iova region Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
                   ` (5 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Make ipu6_map_fw_region reusable as for ipu7 we want to map other
buffers too, not only firmware. Also add DMA data direction and mapping
attributes as arguments as these are different for ipu7.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.c | 40 ++++++++++----------
 drivers/media/pci/intel/ipu6/ipu6-buttress.h | 10 ++---
 drivers/media/pci/intel/ipu6/ipu6-isys.c     |  7 ++--
 drivers/media/pci/intel/ipu6/ipu6.c          |  8 ++--
 4 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 13fd7a083b25..74db0a37561e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -676,55 +676,55 @@ int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
 	return 0;
 }
 
-int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
-			       const struct firmware *fw, struct sg_table *sgt)
+int ipu6_map_fw_region(struct ipu6_bus_device *sys, const void *data,
+		       size_t size, enum dma_data_direction dir,
+		       unsigned long attrs)
 {
-	bool is_vmalloc = is_vmalloc_addr(fw->data);
+	bool is_vmalloc = is_vmalloc_addr(data);
 	struct pci_dev *pdev = sys->isp->pdev;
+	struct sg_table *sgt = &sys->fw_sgt;
 	struct page **pages;
-	const void *addr;
 	unsigned long n_pages;
 	unsigned int i;
 	int ret;
 
-	if (!is_vmalloc && !virt_addr_valid(fw->data))
+	if (!is_vmalloc && !virt_addr_valid(data))
 		return -EDOM;
 
-	n_pages = PFN_UP(fw->size);
+	n_pages = PFN_UP(size);
 
 	pages = kmalloc_objs(*pages, n_pages);
 	if (!pages)
 		return -ENOMEM;
 
-	addr = fw->data;
 	for (i = 0; i < n_pages; i++) {
 		struct page *p = is_vmalloc ?
-			vmalloc_to_page(addr) : virt_to_page(addr);
+			vmalloc_to_page(data) : virt_to_page(data);
 
 		if (!p) {
 			ret = -ENOMEM;
 			goto out;
 		}
 		pages[i] = p;
-		addr += PAGE_SIZE;
+		data += PAGE_SIZE;
 	}
 
-	ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, fw->size,
+	ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, size,
 					GFP_KERNEL);
 	if (ret) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
+	ret = dma_map_sgtable(&pdev->dev, sgt, dir, 0);
 	if (ret) {
 		sg_free_table(sgt);
 		goto out;
 	}
 
-	ret = ipu6_dma_map_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
+	ret = ipu6_dma_map_sgtable(sys, sgt, dir, attrs);
 	if (ret) {
-		dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
+		dma_unmap_sgtable(&pdev->dev, sgt, dir, 0);
 		sg_free_table(sgt);
 		goto out;
 	}
@@ -736,18 +736,18 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
 
 	return ret;
 }
-EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, "INTEL_IPU6");
+EXPORT_SYMBOL_NS_GPL(ipu6_map_fw_region, "INTEL_IPU6");
 
-void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
-				  struct sg_table *sgt)
+void ipu6_unmap_fw_region(struct ipu6_bus_device *sys,
+			  enum dma_data_direction dir)
 {
 	struct pci_dev *pdev = sys->isp->pdev;
 
-	ipu6_dma_unmap_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
-	dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
-	sg_free_table(sgt);
+	ipu6_dma_unmap_sgtable(sys, &sys->fw_sgt, dir, 0);
+	dma_unmap_sgtable(&pdev->dev, &sys->fw_sgt, dir, 0);
+	sg_free_table(&sys->fw_sgt);
 }
-EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, "INTEL_IPU6");
+EXPORT_SYMBOL_NS_GPL(ipu6_unmap_fw_region, "INTEL_IPU6");
 
 int ipu6_buttress_authenticate(struct ipu6_device *isp)
 {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 47a49e961945..79d8f5893686 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -84,11 +84,11 @@ struct ipu6_ipc_buttress_bulk_msg {
 };
 
 int ipu6_buttress_ipc_reset(struct ipu6_device *isp);
-int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
-			       const struct firmware *fw,
-			       struct sg_table *sgt);
-void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
-				  struct sg_table *sgt);
+int ipu6_map_fw_region(struct ipu6_bus_device *sys, const void *data,
+		       size_t size, enum dma_data_direction dir,
+		       unsigned long attrs);
+void ipu6_unmap_fw_region(struct ipu6_bus_device *sys,
+			  enum dma_data_direction dir);
 int ipu6_buttress_power(struct device *dev,
 			const struct ipu6_buttress_ctrl *ctrl, bool on);
 bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 5a3ba5007249..459121e6c1cb 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1042,7 +1042,8 @@ static int isys_probe(struct auxiliary_device *auxdev,
 
 	if (!isp->secure_mode) {
 		fw = isp->cpd_fw;
-		ret = ipu6_buttress_map_fw_image(adev, fw, &adev->fw_sgt);
+		ret = ipu6_map_fw_region(adev, fw->data, fw->size,
+					 DMA_TO_DEVICE, 0);
 		if (ret)
 			goto release_firmware;
 
@@ -1082,7 +1083,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
 		ipu6_cpd_free_pkg_dir(adev);
 remove_shared_buffer:
 	if (!isp->secure_mode)
-		ipu6_buttress_unmap_fw_image(adev, &adev->fw_sgt);
+		ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
 release_firmware:
 	if (!isp->secure_mode)
 		release_firmware(adev->fw);
@@ -1112,7 +1113,7 @@ static void isys_remove(struct auxiliary_device *auxdev)
 
 	if (!isp->secure_mode) {
 		ipu6_cpd_free_pkg_dir(adev);
-		ipu6_buttress_unmap_fw_image(adev, &adev->fw_sgt);
+		ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
 		release_firmware(adev->fw);
 	}
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 428ad046e239..af5581da7149 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -624,8 +624,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_ipu6_rpm_put;
 	}
 
-	ret = ipu6_buttress_map_fw_image(isp->psys, isp->cpd_fw,
-					 &isp->psys->fw_sgt);
+	ret = ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
+				 isp->cpd_fw->size, DMA_TO_DEVICE, 0);
 	if (ret) {
 		dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
 		goto out_ipu6_rpm_put;
@@ -679,7 +679,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 out_ipu6_bus_del_devices:
 	if (!IS_ERR_OR_NULL(isp->psys)) {
 		ipu6_cpd_free_pkg_dir(isp->psys);
-		ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
+		ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
 	}
 	if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
 		ipu6_mmu_cleanup(isp->psys->mmu);
@@ -702,7 +702,7 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
 	devm_free_irq(&pdev->dev, pdev->irq, isp);
 	ipu6_cpd_free_pkg_dir(isp->psys);
 
-	ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
+	ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
 	ipu6_buttress_exit(isp);
 
 	ipu6_bus_del_devices(pdev);
-- 
2.55.0


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

* [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (37 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 18:17   ` Sakari Ailus
  2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
                   ` (4 subsequent siblings)
  43 siblings, 1 reply; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

We are bout to add ipu7 firmware mapping. It is slightly different from
ipu6. Handling this and possible errors is easier when both isys and
psys mapping is in one place.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-bus.h  |  1 -
 drivers/media/pci/intel/ipu6/ipu6-isys.c | 29 -----------
 drivers/media/pci/intel/ipu6/ipu6.c      | 63 +++++++++++++++++++-----
 3 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index aef8e4a66c4a..d2f93eb03dea 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -26,7 +26,6 @@ struct ipu6_bus_device {
 	struct ipu6_mmu *mmu;
 	struct ipu6_device *isp;
 	const struct ipu6_buttress_ctrl *ctrl;
-	const struct firmware *fw;
 	struct sg_table fw_sgt;
 	u64 *pkg_dir;
 	dma_addr_t pkg_dir_dma_addr;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 459121e6c1cb..3fb34d2d189c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -995,7 +995,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
 	const struct ipu6_isys_internal_csi2_pdata *csi2_pdata;
 	struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
 	struct ipu6_device *isp = adev->isp;
-	const struct firmware *fw;
 	struct ipu6_isys *isys;
 	unsigned int i;
 	int ret;
@@ -1040,18 +1039,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
 
 	isys_stream_init(isys);
 
-	if (!isp->secure_mode) {
-		fw = isp->cpd_fw;
-		ret = ipu6_map_fw_region(adev, fw->data, fw->size,
-					 DMA_TO_DEVICE, 0);
-		if (ret)
-			goto release_firmware;
-
-		ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
-		if (ret)
-			goto remove_shared_buffer;
-	}
-
 	cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
 
 	ret = alloc_fw_msg_bufs(isys, 20);
@@ -1079,14 +1066,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
 	free_fw_msg_bufs(isys);
 out_remove_pkg_dir_shared_buffer:
 	cpu_latency_qos_remove_request(&isys->pm_qos);
-	if (!isp->secure_mode)
-		ipu6_cpd_free_pkg_dir(adev);
-remove_shared_buffer:
-	if (!isp->secure_mode)
-		ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
-release_firmware:
-	if (!isp->secure_mode)
-		release_firmware(adev->fw);
 
 	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
 		mutex_destroy(&isys->streams[i].mutex);
@@ -1099,9 +1078,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
 
 static void isys_remove(struct auxiliary_device *auxdev)
 {
-	struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
 	struct ipu6_isys *isys = dev_get_drvdata(&auxdev->dev);
-	struct ipu6_device *isp = adev->isp;
 	unsigned int i;
 
 	free_fw_msg_bufs(isys);
@@ -1111,12 +1088,6 @@ static void isys_remove(struct auxiliary_device *auxdev)
 
 	cpu_latency_qos_remove_request(&isys->pm_qos);
 
-	if (!isp->secure_mode) {
-		ipu6_cpd_free_pkg_dir(adev);
-		ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
-		release_firmware(adev->fw);
-	}
-
 	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
 		mutex_destroy(&isys->streams[i].mutex);
 
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index af5581da7149..d27ffd7ac6f0 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -480,6 +480,40 @@ static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
 	writel(val, isp->base + BUTTRESS_REG_BTRS_CTRL);
 }
 
+static int __ipu6_map_fw_by_sys(struct ipu6_device *isp, struct ipu6_bus_device *adev)
+{
+	int ret = ipu6_map_fw_region(adev, isp->cpd_fw->data, isp->cpd_fw->size,
+				 DMA_TO_DEVICE, 0);
+
+	if (ret) {
+		dev_err_probe(&isp->pdev->dev, ret,
+			      "Firmware mapping failed\n");
+		return ret;
+	}
+
+	ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
+	if (ret) {
+		dev_err_probe(&isp->pdev->dev, ret,
+			      "failed to create pkg dir\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ipu6_map_fw(struct ipu6_device *isp)
+{
+	int ret = __ipu6_map_fw_by_sys(isp, isp->psys);
+
+	if (ret)
+		return ret;
+
+	if (!isp->secure_mode)
+		return __ipu6_map_fw_by_sys(isp, isp->isys);
+
+	return 0;
+}
+
 static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
@@ -624,19 +658,9 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_ipu6_rpm_put;
 	}
 
-	ret = ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
-				 isp->cpd_fw->size, DMA_TO_DEVICE, 0);
-	if (ret) {
-		dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
-		goto out_ipu6_rpm_put;
-	}
-
-	ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
-	if (ret) {
-		dev_err_probe(&isp->pdev->dev, ret,
-			      "failed to create pkg dir\n");
+	ret = ipu6_map_fw(isp);
+	if (ret)
 		goto out_ipu6_rpm_put;
-	}
 
 	ret = devm_request_threaded_irq(dev, pdev->irq, ipu6_buttress_isr,
 					ipu6_buttress_isr_threaded,
@@ -679,7 +703,13 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 out_ipu6_bus_del_devices:
 	if (!IS_ERR_OR_NULL(isp->psys)) {
 		ipu6_cpd_free_pkg_dir(isp->psys);
-		ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+		if (isp->psys->fw_sgt.nents)
+			ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+	}
+	if (!IS_ERR_OR_NULL(isp->isys)) {
+		ipu6_cpd_free_pkg_dir(isp->isys);
+		if (isp->isys->fw_sgt.nents)
+			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
 	}
 	if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
 		ipu6_mmu_cleanup(isp->psys->mmu);
@@ -703,6 +733,13 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
 	ipu6_cpd_free_pkg_dir(isp->psys);
 
 	ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+
+	if (isp->isys) {
+		ipu6_cpd_free_pkg_dir(isp->isys);
+		if (isp->isys->fw_sgt.nents)
+			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
+	}
+
 	ipu6_buttress_exit(isp);
 
 	ipu6_bus_del_devices(pdev);
-- 
2.55.0


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

* [PATCH v2 40/44] media: ipu6: Map ipu7 firmware
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (38 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 18:23   ` Sakari Ailus
  2026-08-21 11:42 ` [PATCH v2 41/44] media: ipu6: Set model name for ipu7 Antti Laakso
                   ` (3 subsequent siblings)
  43 siblings, 1 reply; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

Mapping of ipu7 firmware is slightly different compared to ipu6. Add
helpers for it and call them similar to ipu6.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6.c | 75 ++++++++++++++++++++++++++---
 drivers/media/pci/intel/ipu6/ipu6.h |  1 +
 2 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index d27ffd7ac6f0..93f28ec9a74d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -19,6 +19,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/vmalloc.h>
 
 #include <media/ipu-bridge.h>
 #include <media/ipu6-pci-table.h>
@@ -27,6 +28,7 @@
 #include "ipu6-bus.h"
 #include "ipu6-buttress.h"
 #include "ipu6-cpd.h"
+#include "ipu6-dma.h"
 #include "ipu6-isys.h"
 #include "ipu6-mmu.h"
 #include "ipu6-platform-buttress-regs.h"
@@ -514,6 +516,57 @@ static int ipu6_map_fw(struct ipu6_device *isp)
 	return 0;
 }
 
+static int __ipu7_map_fw_non_secure(struct ipu6_device *isp)
+{
+	int ret;
+
+	/*
+	 * Allocate and map memory for running the firmware. Not
+	 * required in secure mode, in which firmware runs in IMR.
+	 */
+	isp->fw_code_region = vmalloc(IPU7_FW_CODE_REGION_SIZE);
+	if (!isp->fw_code_region)
+		return -ENOMEM;
+
+	ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "isys",
+				   isp->fw_code_region, &isp->isys->fw_entry);
+	if (ret)
+		return ret;
+
+	ret = ipu6_map_fw_region(isp->isys, isp->fw_code_region,
+				 IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
+				 DMA_ATTR_RESERVE_REGION);
+	if (ret)
+		return ret;
+
+	ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "psys",
+				   isp->fw_code_region, &isp->psys->fw_entry);
+	if (ret)
+		return ret;
+
+	return ipu6_map_fw_region(isp->psys, isp->fw_code_region,
+				  IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
+				  DMA_ATTR_RESERVE_REGION);
+}
+
+static int ipu7_map_fw(struct ipu6_device *isp)
+{
+	int ret;
+
+	ret = isp->secure_mode ?
+		ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
+				   isp->cpd_fw->size, DMA_BIDIRECTIONAL, 0) :
+		__ipu7_map_fw_non_secure(isp);
+
+	if (ret) {
+		dev_err_probe(&isp->pdev->dev, ret,
+			      "Failed to init ipu7 firmware region\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
@@ -523,6 +576,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	struct ipu6_device *isp;
 	phys_addr_t phys;
 	u32 val, version, sku_id;
+	unsigned long dir;
 	int ret;
 
 	isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
@@ -658,7 +712,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_ipu6_rpm_put;
 	}
 
-	ret = ipu6_map_fw(isp);
+	ret = IS_IPU7(isp) ? ipu7_map_fw(isp) : ipu6_map_fw(isp);
 	if (ret)
 		goto out_ipu6_rpm_put;
 
@@ -701,15 +755,20 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 out_ipu6_rpm_put:
 	pm_runtime_put_sync(&isp->psys->auxdev.dev);
 out_ipu6_bus_del_devices:
+	dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
 	if (!IS_ERR_OR_NULL(isp->psys)) {
 		ipu6_cpd_free_pkg_dir(isp->psys);
 		if (isp->psys->fw_sgt.nents)
-			ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+			ipu6_unmap_fw_region(isp->psys, dir);
 	}
 	if (!IS_ERR_OR_NULL(isp->isys)) {
 		ipu6_cpd_free_pkg_dir(isp->isys);
 		if (isp->isys->fw_sgt.nents)
-			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
+			ipu6_unmap_fw_region(isp->isys, dir);
+	}
+	if (isp->fw_code_region) {
+		vfree(isp->fw_code_region);
+		isp->fw_code_region = NULL;
 	}
 	if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
 		ipu6_mmu_cleanup(isp->psys->mmu);
@@ -728,18 +787,22 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
 	struct ipu6_device *isp = pci_get_drvdata(pdev);
 	struct ipu6_mmu *isys_mmu = isp->isys->mmu;
 	struct ipu6_mmu *psys_mmu = isp->psys->mmu;
+	unsigned long dir;
 
 	devm_free_irq(&pdev->dev, pdev->irq, isp);
-	ipu6_cpd_free_pkg_dir(isp->psys);
 
-	ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+	dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+	ipu6_cpd_free_pkg_dir(isp->psys);
+	ipu6_unmap_fw_region(isp->psys, dir);
 
 	if (isp->isys) {
 		ipu6_cpd_free_pkg_dir(isp->isys);
 		if (isp->isys->fw_sgt.nents)
-			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
+			ipu6_unmap_fw_region(isp->isys, dir);
 	}
 
+	vfree(isp->fw_code_region);
+
 	ipu6_buttress_exit(isp);
 
 	ipu6_bus_del_devices(pdev);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 6bef45a02c2b..a2992ffe8e3c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -70,6 +70,7 @@ struct ipu6_device {
 	bool secure_mode;
 	u8 hw_ver;
 	bool bus_ready_to_probe;
+	u32 *fw_code_region;
 };
 
 #define IPU_PSYS	0
-- 
2.55.0


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

* [PATCH v2 41/44] media: ipu6: Set model name for ipu7
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (39 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
  2026-08-21 11:43 ` [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support Antti Laakso
                   ` (2 subsequent siblings)
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

We are about to enable support for ipu7 hardware, set model name
accordingly.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-isys.c | 2 +-
 drivers/media/pci/intel/ipu6/ipu6.c      | 2 ++
 drivers/media/pci/intel/ipu6/ipu6.h      | 3 +++
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 3fb34d2d189c..08f29b678d1b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -739,7 +739,7 @@ static int isys_register_devices(struct ipu6_isys *isys)
 
 	isys->media_dev.dev = dev;
 	media_device_pci_init(&isys->media_dev,
-			      pdev, IPU6_MEDIA_DEV_MODEL_NAME);
+			      pdev, isys->adev->isp->model_name);
 
 	strscpy(isys->v4l2_dev.name, isys->media_dev.model,
 		sizeof(isys->v4l2_dev.name));
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 93f28ec9a74d..a4fd7333c68b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -585,6 +585,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
 	isp->buttress.regs = &ipu6_buttress_regs;
+	isp->model_name = IPU6_MEDIA_DEV_MODEL_NAME;
 	isys_ctrl = &ipu6_isys_buttress_ctrl;
 	psys_ctrl = &ipu6_psys_buttress_ctrl;
 
@@ -615,6 +616,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	case PCI_DEVICE_ID_INTEL_IPU7:
 		isp->hw_ver = IPU_VERSION_7;
 		isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
+		isp->model_name = IPU7_MEDIA_DEV_MODEL_NAME;
 		isp->buttress.regs = &ipu7_buttress_regs;
 		isys_ctrl = &ipu7_isys_buttress_ctrl;
 		psys_ctrl = &ipu7_psys_buttress_ctrl;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index a2992ffe8e3c..8a696caf4b88 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -16,6 +16,8 @@ struct ipu6_bus_device;
 
 #define IPU6_NAME			"intel-ipu6"
 #define IPU6_MEDIA_DEV_MODEL_NAME	"ipu6"
+#define IPU7_MEDIA_DEV_MODEL_NAME	"ipu7"
+#define IPU7P5_MEDIA_DEV_MODEL_NAME	"ipu7.5"
 
 #define IPU6SE_FIRMWARE_NAME		"intel/ipu/ipu6se_fw.bin"
 #define IPU6EP_FIRMWARE_NAME		"intel/ipu/ipu6ep_fw.bin"
@@ -63,6 +65,7 @@ struct ipu6_device {
 	const struct firmware *cpd_fw;
 	const char *cpd_fw_name;
 	u32 cpd_metadata_cmpnt_size;
+	const char *model_name;
 
 	void __iomem *base;
 	void __iomem *pb_base;
-- 
2.55.0


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

* [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (40 preceding siblings ...)
  2026-08-21 11:42 ` [PATCH v2 41/44] media: ipu6: Set model name for ipu7 Antti Laakso
@ 2026-08-21 11:43 ` Antti Laakso
  2026-08-21 11:43 ` [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data Antti Laakso
  2026-08-21 11:43 ` [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5 Antti Laakso
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:43 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7.5 buttress differs from ipu7 slightly,
add support for ipu7.5.
Also set hardware version, firmware and model names
for ipu7.5.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-buttress.c  | 53 +++++++++++++++++--
 .../intel/ipu6/ipu6-platform-buttress-regs.h  |  7 +++
 drivers/media/pci/intel/ipu6/ipu6.c           | 38 +++++++++++++
 drivers/media/pci/intel/ipu6/ipu6.h           |  1 +
 4 files changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 74db0a37561e..105de1744dff 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2013--2024 Intel Corporation
  */
 
+#include <asm/cpu_device_id.h>
 #include <linux/bitfield.h>
 #include <linux/bits.h>
 #include <linux/completion.h>
@@ -900,11 +901,30 @@ static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
 	return ret;
 }
 
-int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
+static int __ipu7p5_start_tsc_sync(struct ipu6_device *isp)
 {
-	unsigned int i;
+	u32 val;
+
+	val = readl(isp->base + IPU7_BUTTRESS_REG_TSC_CTL);
+	val |= IPU7_BUTTRESS_SEL_PB_TIMESTAMP;
+	writel(val, isp->base + IPU7_BUTTRESS_REG_TSC_CTL);
+
+	for (unsigned int i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
+		val = readl(isp->base + IPU7_BUTTRESS_REG_PB_TIMESTAMP_VALID);
+		if (val == 1)
+			return 0;
+
+		usleep_range(40, 50);
+	}
+
+	dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n");
+
+	return -ETIMEDOUT;
+}
 
-	for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
+static int __ipu6_start_tsc_sync(struct ipu6_device *isp)
+{
+	for (unsigned int i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
 		u32 val;
 		int ret;
 
@@ -925,6 +945,14 @@ int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
 
 	return -ETIMEDOUT;
 }
+
+int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
+{
+	if (IS_IPU7P5(isp))
+		return __ipu7p5_start_tsc_sync(isp);
+
+	return __ipu6_start_tsc_sync(isp);
+}
 EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, "INTEL_IPU6");
 
 void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val)
@@ -987,6 +1015,13 @@ u32 ipu7_buttress_get_isys_freq(struct ipu6_device *isp)
 }
 EXPORT_SYMBOL_NS_GPL(ipu7_buttress_get_isys_freq, "INTEL_IPU6");
 
+static const struct x86_cpu_id ipu7_misc_cfg_exclusion[] = {
+	X86_MATCH_VFM_STEPS(INTEL_PANTHERLAKE_L, 0x1, 0x1, 0),
+	{},
+};
+
+#define IPU7_WRXREQOP_OVRD_VAL_MASK  GENMASK(22, 19)
+
 static void ipu7_buttress_setup(struct ipu6_device *isp)
 {
 	struct ipu6_buttress *b = &isp->buttress;
@@ -995,12 +1030,20 @@ static void ipu7_buttress_setup(struct ipu6_device *isp)
 	/* program PB BAR */
 	writel(0, isp->pb_base + IPU7_GLOBAL_INTERRUPT_MASK);
 	val = readl(isp->pb_base + IPU7_BAR2_MISC_CONFIG);
+
 	val |= 0x100U;
+	if (!IS_IPU7_MTL(isp) && !x86_match_cpu(ipu7_misc_cfg_exclusion))
+		val |= FIELD_PREP(IPU7_WRXREQOP_OVRD_VAL_MASK, 0xf) | BIT(18);
 
 	writel(val, isp->pb_base + IPU7_BAR2_MISC_CONFIG);
 
-	writel(BIT(22), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
-	writel(BIT(1), isp->pb_base + IPU7_TLBID_HASH_ENABLE_127_96);
+	if (IS_IPU7P5(isp)) {
+		writel(BIT(14), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
+		writel(BIT(9), isp->pb_base + IPU7_TLBID_HASH_ENABLE_95_64);
+	} else {
+		writel(BIT(22), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
+		writel(BIT(1), isp->pb_base + IPU7_TLBID_HASH_ENABLE_127_96);
+	}
 
 	writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
 	writel(b->regs->irq_all, isp->base + IPU7_BUTTRESS_REG_IRQ_MASK);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index c4da72c6bd8f..57e661cc2177 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -233,6 +233,8 @@ enum {
 #define IPU7_BUTTRESS_REG_TSC_CMD		0x2014
 #define IPU7_BUTTRESS_REG_TSC_CTL		0x2018
 #define IPU7_BUTTRESS_REG_TSC_LO		0x201c
+#define IPU7_BUTTRESS_REG_PB_TIMESTAMP_LO	0x2030
+#define IPU7_BUTTRESS_REG_PB_TIMESTAMP_VALID	0x2038
 #define IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ	0x2104
 #define IPU7_BUTTRESS_REG_PS_WORKPOINT_REQ	0x2100
 #define IPU7_BUTTRESS_REG_IDLE_WDT		0x218c
@@ -319,8 +321,13 @@ enum {
 
 /* PB registers */
 #define IPU7_GLOBAL_INTERRUPT_MASK		0x8
+#define IPU7_TLBID_HASH_ENABLE_31_0		0x30
 #define IPU7_TLBID_HASH_ENABLE_63_32		0x34
+#define IPU7_TLBID_HASH_ENABLE_95_64		0x38
 #define IPU7_TLBID_HASH_ENABLE_127_96		0x3c
 #define IPU7_BAR2_MISC_CONFIG			0x64
 
+/* IPU7.5 */
+#define IPU7_BUTTRESS_SEL_PB_TIMESTAMP		BIT(9)
+
 #endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index a4fd7333c68b..14cd54da2022 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -197,6 +197,36 @@ static const struct ipu6_buttress_registers ipu7_buttress_regs = {
 	.irq_sai	= IPU7_BUTTRESS_IRQ_SAI_VIOLATION,
 };
 
+static const struct ipu6_buttress_registers ipu7p5_buttress_regs = {
+	/* Registers */
+	.irq_status	= IPU7_BUTTRESS_REG_IRQ_STATUS,
+	.irq_clear	= IPU7_BUTTRESS_REG_IRQ_CLEAR,
+	.irq_enable	= IPU7_BUTTRESS_REG_IRQ_ENABLE,
+	.pwr_status	= IPU7_BUTTRESS_REG_PWR_STATUS,
+	.security_ctl	= IPU7_BUTTRESS_REG_SECURITY_CTL,
+	.fw_reset_ctl	= IPU7_BUTTRESS_REG_FW_RESET_CTL,
+	.fabric_cmd	= IPU7_BUTTRESS_REG_TSC_CMD,
+	.tsw_ctl	= IPU7_BUTTRESS_REG_TSC_CTL,
+	.tsc_lo		= IPU7_BUTTRESS_REG_PB_TIMESTAMP_LO,
+	.wdt		= IPU7_BUTTRESS_REG_IDLE_WDT,
+	.csr_in		= IPU7_BUTTRESS_REG_CSE2IUCSR,
+	.csr_out	= IPU7_BUTTRESS_REG_IU2CSECSR,
+	.db0_in		= IPU7_BUTTRESS_REG_CSE2IUDB0,
+	.db0_out	= IPU7_BUTTRESS_REG_IU2CSEDB0,
+	.data0_in	= IPU7_BUTTRESS_REG_CSE2IUDATA0,
+	.data0_out	= IPU7_BUTTRESS_REG_IU2CSEDATA0,
+	.sku_id		= IPU7_BUTTRESS_REG_SKU,
+
+	/* Bitmasks */
+	.irq_is		= IPU7_BUTTRESS_IRQ_IS_IRQ,
+	.irq_ps		= IPU7_BUTTRESS_IRQ_PS_IRQ,
+	.irq_all	= IPU7_BUTTRESS_IRQS,
+	.irq_events	= IPU7_BUTTRESS_IRQS,
+	.irq_cse_ipc	= IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING,
+	.irq_exec_done	= IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE,
+	.irq_sai	= IPU7_BUTTRESS_IRQ_SAI_VIOLATION,
+};
+
 static void
 ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
 			   const struct ipu6_hw_variants *hw_variant,
@@ -621,6 +651,14 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		isys_ctrl = &ipu7_isys_buttress_ctrl;
 		psys_ctrl = &ipu7_psys_buttress_ctrl;
 		break;
+	case PCI_DEVICE_ID_INTEL_IPU7P5:
+		isp->hw_ver = IPU_VERSION_7P5;
+		isp->cpd_fw_name = IPU7P5_FIRMWARE_NAME;
+		isp->model_name = IPU7P5_MEDIA_DEV_MODEL_NAME;
+		isp->buttress.regs = &ipu7p5_buttress_regs;
+		isys_ctrl = &ipu7_isys_buttress_ctrl;
+		psys_ctrl = &ipu7_psys_buttress_ctrl;
+		break;
 	default:
 		return dev_err_probe(dev, -ENODEV,
 				     "Unsupported IPU6 device %x\n",
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 8a696caf4b88..72c5063d5198 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -25,6 +25,7 @@ struct ipu6_bus_device;
 #define IPU6EPMTL_FIRMWARE_NAME		"intel/ipu/ipu6epmtl_fw.bin"
 #define IPU6EPADLN_FIRMWARE_NAME	"intel/ipu/ipu6epadln_fw.bin"
 #define IPU7_FIRMWARE_NAME		"intel/ipu/ipu7_fw.bin"
+#define IPU7P5_FIRMWARE_NAME		"intel/ipu/ipu7ptl_fw.bin"
 
 #define IPU_VERSION_6		BIT(0) /* TGL */
 #define IPU_VERSION_6SE		BIT(1) /* JSL */
-- 
2.55.0


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

* [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (41 preceding siblings ...)
  2026-08-21 11:43 ` [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support Antti Laakso
@ 2026-08-21 11:43 ` Antti Laakso
  2026-08-21 11:43 ` [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5 Antti Laakso
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:43 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The ipu7.5 mmu is different compared to ipu7.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c | 261 ++++++++++++++++++++-
 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h |  99 ++++++++
 2 files changed, 359 insertions(+), 1 deletion(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
index 3cd9a818733c..c9b015e89ee6 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
@@ -431,6 +431,250 @@ static struct ipu7_mmu_hw ipu7_psys_mmu_hwdata[] = {
 	},
 };
 
+static struct ipu7_mmu_hw ipu7p5_isys_mmu_hwdata[] = {
+	{
+		.name = "IS_FW_RD",
+		.offset = IPU7P5_IS_MMU_FW_RD_OFFSET,
+		.zlx_offset = IPU7P5_IS_ZLX_UC_RD_OFFSET,
+		.uao_offset = IPU7P5_IS_UAO_UC_RD_OFFSET,
+		.info_bits = 0x20005101,
+		.refill = 0x00002726,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_IS_MMU_FW_RD_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_IS_MMU_FW_RD_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_IS_MMU_FW_RD_STREAM_NUM,
+		.nr_l2streams = IPU7P5_IS_MMU_FW_RD_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x8, 0xa },
+		.l2_block_sz = { 0x0, 0x2, 0x4 },
+		.zlx_nr = IPU7P5_IS_ZLX_UC_RD_NUM,
+		.zlx_axi_pool = { 0x00000f30 },
+		.zlx_en = { 0, 1, 0, 0 },
+		.zlx_conf = { 0x0 },
+		.uao_p_num = IPU7P5_IS_UAO_UC_RD_PLANENUM,
+		.uao_p2tlb = { 0x49, 0x4c, 0x4d, 0x0 },
+	},
+	{
+		.name = "IS_FW_WR",
+		.offset = IPU7P5_IS_MMU_FW_WR_OFFSET,
+		.zlx_offset = IPU7P5_IS_ZLX_UC_WR_OFFSET,
+		.uao_offset = IPU7P5_IS_UAO_UC_WR_OFFSET,
+		.info_bits = 0x20005001,
+		.refill = 0x00002524,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_IS_MMU_FW_WR_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_IS_MMU_FW_WR_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_IS_MMU_FW_WR_STREAM_NUM,
+		.nr_l2streams = IPU7P5_IS_MMU_FW_WR_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x8, 0xa },
+		.l2_block_sz = { 0x0, 0x2, 0x4 },
+		.zlx_nr = IPU7P5_IS_ZLX_UC_WR_NUM,
+		.zlx_axi_pool = { 0x00000f20 },
+		.zlx_en = { 0, 1, 1, 0 },
+		.zlx_conf = { 0x0, 0x00010101, 0x00010101, 0x0 },
+		.uao_p_num = IPU7P5_IS_UAO_UC_WR_PLANENUM,
+		.uao_p2tlb = { 0x49, 0x4a, 0x4b, 0x0 },
+	},
+	{
+		.name = "IS_DATA_WR_ISOC",
+		.offset = IPU7P5_IS_MMU_M0_OFFSET,
+		.zlx_offset = IPU7P5_IS_ZLX_M0_OFFSET,
+		.uao_offset = IPU7P5_IS_UAO_M0_WR_OFFSET,
+		.info_bits = 0x20004e01,
+		.refill = 0x00002120,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_IS_MMU_M0_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_IS_MMU_M0_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_IS_MMU_M0_STREAM_NUM,
+		.nr_l2streams = IPU7P5_IS_MMU_M0_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+				 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x01e },
+		.l2_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+				 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
+		.zlx_nr = IPU7P5_IS_ZLX_M0_NUM,
+		.zlx_axi_pool = { 0x00000f10 },
+		.zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+		.zlx_conf = { 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+			      0x00010103, 0x00010103, 0x00010103, 0x00010103,
+			      0x00010103, 0x00010103, 0x00010103, 0x00010103,
+			      0x00010103, 0x00010103, 0x00010103, 0x00010103 },
+		.uao_p_num = IPU7P5_IS_UAO_M0_WR_PLANENUM,
+		.uao_p2tlb = { 0x00000041, 0x00000042, 0x00000043, 0x00000044,
+			       0x00000041, 0x00000042, 0x00000043, 0x00000044,
+			       0x00000041, 0x00000042, 0x00000043, 0x00000044,
+			       0x00000041, 0x00000042, 0x00000043, 0x00000044 },
+	},
+	{
+		.name = "IS_DATA_WR_SNOOP",
+		.offset = IPU7P5_IS_MMU_M1_OFFSET,
+		.zlx_offset = IPU7P5_IS_ZLX_M1_OFFSET,
+		.uao_offset = IPU7P5_IS_UAO_M1_WR_OFFSET,
+		.info_bits = 0x20004f01,
+		.refill = 0x00002322,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_IS_MMU_M1_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_IS_MMU_M1_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_IS_MMU_M1_STREAM_NUM,
+		.nr_l2streams = IPU7P5_IS_MMU_M1_STREAM_NUM,
+		.l1_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+				 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
+		.l2_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+				 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
+		.zlx_nr = IPU7P5_IS_ZLX_M1_NUM,
+		.zlx_axi_pool = { 0x00000f20 },
+		.zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+		.zlx_conf = { 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+			      0x00010103, 0x00010103, 0x00010103, 0x00010103,
+			      0x00010103, 0x00010103, 0x00010103, 0x00010103,
+			      0x00010103, 0x00010103, 0x00010103, 0x00010103 },
+		.uao_p_num = IPU7P5_IS_UAO_M1_WR_PLANENUM,
+		.uao_p2tlb = { 0x00000045, 0x00000046, 0x00000047, 0x00000048,
+			       0x00000045, 0x00000046, 0x00000047, 0x00000048,
+			       0x00000045, 0x00000046, 0x00000047, 0x00000048,
+			       0x00000045, 0x00000046, 0x00000047, 0x00000048 },
+	},
+};
+
+static struct ipu7_mmu_hw ipu7p5_psys_mmu_hwdata[] = {
+	{
+		.name = "PS_FW_RD",
+		.offset = IPU7P5_PS_MMU_FW_RD_OFFSET,
+		.zlx_offset = IPU7P5_PS_ZLX_FW_RD_OFFSET,
+		.uao_offset = IPU7P5_PS_UAO_FW_RD_OFFSET,
+		.info_bits = 0x20004001,
+		.refill = 0x00002726,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_PS_MMU_FW_RD_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_PS_MMU_FW_RD_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_PS_MMU_FW_RD_STREAM_NUM,
+		.nr_l2streams = IPU7P5_PS_MMU_FW_RD_STREAM_NUM,
+		.l1_block_sz = { 0x00, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x11,
+				 0x12, 0x13, 0x14, 0x16, 0x18, 0x19, 0x1a,
+				 0x1a, 0x1a },
+		.l2_block_sz = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c,
+				 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a,
+				 0x1c, 0x1e },
+		.zlx_nr = IPU7P5_PS_ZLX_FW_RD_NUM,
+		.zlx_axi_pool = { 0x00000f30 },
+		.zlx_en = { 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
+		.zlx_conf = { 0x00000000, 0x00010101, 0x00000000, 0x00000000,
+			      0x00010101, 0x00010101, 0x00000000, 0x00000000,
+			      0x00000000, 0x00010101, 0x00010101, 0x00000000,
+			      0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+		.uao_p_num = IPU7P5_PS_UAO_FW_RD_PLANENUM,
+		.uao_p2tlb = { 0x2e, 0x35, 0x36, 0x31, 0x37, 0x38, 0x39, 0x32,
+			       0x33, 0x3a, 0x3b, 0x3c, 0x34, 0x00, 0x00, 0x00 },
+	},
+	{
+		.name = "PS_FW_WR",
+		.offset = IPU7P5_PS_MMU_FW_WR_OFFSET,
+		.zlx_offset = IPU7P5_PS_ZLX_FW_WR_OFFSET,
+		.uao_offset = IPU7P5_PS_UAO_FW_WR_OFFSET,
+		.info_bits = 0x20003e01,
+		.refill = 0x00002322,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_PS_MMU_FW_WR_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_PS_MMU_FW_WR_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_PS_MMU_FW_WR_STREAM_NUM,
+		.nr_l2streams = IPU7P5_PS_MMU_FW_WR_STREAM_NUM,
+		.l1_block_sz = { 0x00, 0x08, 0x0a, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+				 0x10, 0x10 },
+		.l2_block_sz = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+				 0x10, 0x12 },
+		.zlx_nr = IPU7P5_PS_ZLX_FW_WR_NUM,
+		.zlx_axi_pool = { 0x00000f20 },
+		.zlx_en = { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
+		.zlx_conf = { 0x00000000, 0x00010101, 0x00010101, 0x00000000,
+			      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			      0x00000000, 0x00000000 },
+		.uao_p_num = IPU7P5_PS_UAO_FW_WR_PLANENUM,
+		.uao_p2tlb = { 0x0000002e, 0x0000002f, 0x00000030, 0x00000031,
+			       0x00000032, 0x00000033, 0x00000034, 0x00000000,
+			       0x00000000, 0x00000000 },
+	},
+	{
+		.name = "PS_DATA_RD",
+		.offset = IPU7P5_PS_MMU_SRT_RD_OFFSET,
+		.zlx_offset = IPU7P5_PS_ZLX_DATA_RD_OFFSET,
+		.uao_offset = IPU7P5_PS_UAO_SRT_RD_OFFSET,
+		.info_bits = 0x20003f01,
+		.refill = 0x00002524,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_PS_MMU_SRT_RD_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_PS_MMU_SRT_RD_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_PS_MMU_SRT_RD_STREAM_NUM,
+		.nr_l2streams = IPU7P5_PS_MMU_SRT_RD_STREAM_NUM,
+		.l1_block_sz = { 0x00, 0x04, 0x06, 0x08, 0x0b, 0x0d, 0x0f, 0x13,
+				 0x17, 0x19, 0x1b, 0x1d, 0x1f, 0x2b, 0x33, 0x3f,
+				 0x47, 0x49, 0x4b, 0x4c, 0x4d, 0x4e },
+		.l2_block_sz = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+				 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+				 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a },
+		.zlx_nr = IPU7P5_PS_ZLX_DATA_RD_NUM,
+		.zlx_axi_pool = { 0x00000f30 },
+		.zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+			    1, 1, 0, 0, 0, 0 },
+		.zlx_conf = { 0x00030303, 0x00010101, 0x00010101, 0x00030202,
+			      0x00010101, 0x00010101, 0x00030303, 0x00030303,
+			      0x00010101, 0x00030800, 0x00030500, 0x00020101,
+			      0x00042000, 0x00031000, 0x00042000, 0x00031000,
+			      0x00020400, 0x00010101, 0x00000000, 0x00000000,
+			      0x00000000, 0x00000000 },
+		.uao_p_num = IPU7P5_PS_UAO_SRT_RD_PLANENUM,
+		.uao_p2tlb = { 0x0000001c, 0x0000001d, 0x0000001e, 0x0000001f,
+			       0x00000020, 0x00000021, 0x00000022, 0x00000023,
+			       0x00000024, 0x00000025, 0x00000026, 0x00000027,
+			       0x00000028, 0x00000029, 0x0000002a, 0x0000002b,
+			       0x0000002c, 0x0000002d, 0x00000000, 0x00000000,
+			       0x00000000, 0x00000000 },
+	},
+	{
+		.name = "PS_DATA_WR",
+		.offset = IPU7P5_PS_MMU_SRT_WR_OFFSET,
+		.zlx_offset = IPU7P5_PS_ZLX_DATA_WR_OFFSET,
+		.uao_offset = IPU7P5_PS_UAO_SRT_WR_OFFSET,
+		.info_bits = 0x20003d01,
+		.refill = 0x00002120,
+		.collapse_en_bitmap = 0x1,
+		.at_sp_arb_cfg = 0x1,
+		.l1_block = IPU7P5_PS_MMU_SRT_WR_L1_BLOCKNR_REG,
+		.l2_block = IPU7P5_PS_MMU_SRT_WR_L2_BLOCKNR_REG,
+		.nr_l1streams = IPU7P5_PS_MMU_SRT_WR_STREAM_NUM,
+		.nr_l2streams = IPU7P5_PS_MMU_SRT_WR_STREAM_NUM,
+		.l1_block_sz = { 0x00, 0x02, 0x06, 0x0a, 0x0c, 0x0e, 0x10, 0x12,
+				 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22,
+				 0x24, 0x28, 0x2a, 0x36, 0x3e, 0x40, 0x42, 0x4e,
+				 0x56, 0x5c, 0x68, 0x70, 0x76, 0x77, 0x78, 0x79 },
+		.l2_block_sz = { 0x00, 0x02, 0x06, 0x0a, 0x0c, 0x0e, 0x10, 0x12,
+				 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22,
+				 0x24, 0x28, 0x2a, 0x36, 0x3e, 0x40, 0x42, 0x4e,
+				 0x56, 0x5c, 0x68, 0x70, 0x76, 0x77, 0x78, 0x79 },
+		.zlx_nr = IPU7P5_PS_ZLX_DATA_WR_NUM,
+		.zlx_axi_pool = { 0x00000f50 },
+		.zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
+			    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+		.zlx_conf = { 0x00010102, 0x00030103, 0x00030103, 0x00010101,
+			      0x00010101, 0x00030101, 0x00010101, 0x38010101,
+			      0x00000000, 0x00000000, 0x38010101, 0x38010101,
+			      0x38010101, 0x38010101, 0x38010101, 0x38010101,
+			      0x00030303, 0x00010101, 0x00042000, 0x00031000,
+			      0x00010101, 0x00010101, 0x00042000, 0x00031000,
+			      0x00031000, 0x00042000, 0x00031000, 0x00031000,
+			      0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+		.uao_p_num = IPU7P5_PS_UAO_SRT_WR_PLANENUM,
+		.uao_p2tlb = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+			       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+			       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+			       0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00 },
+	},
+};
+
 static const struct ipu7_mmu_hwdata ipu7_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
 	[IPU_PSYS] = {
 		.hwdata = ipu7_psys_mmu_hwdata,
@@ -442,6 +686,17 @@ static const struct ipu7_mmu_hwdata ipu7_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
 	},
 };
 
+static const struct ipu7_mmu_hwdata ipu7p5_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
+	[IPU_PSYS] = {
+		.hwdata = ipu7p5_psys_mmu_hwdata,
+		.nr_mmus = ARRAY_SIZE(ipu7p5_psys_mmu_hwdata),
+	},
+	[IPU_ISYS] = {
+		.hwdata = ipu7p5_isys_mmu_hwdata,
+		.nr_mmus = ARRAY_SIZE(ipu7p5_isys_mmu_hwdata),
+	},
+};
+
 static void __ipu7_tlb_invalidate(struct ipu6_mmu *mmu)
 {
 	struct ipu7_mmu_hw *mmu_hw = mmu->ipu7_mmu_hw;
@@ -561,13 +816,17 @@ static int __ipu7_mmu_hw_init(struct ipu6_mmu *mmu)
 static int __ipu7_mmu_init_hw_data(struct ipu6_mmu *mmu, struct device *dev,
 				   void __iomem *base)
 {
-	const struct ipu7_mmu_hwdata *lookup = ipu7_mmu_hwdata_lookup;
+	struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
+	const struct ipu7_mmu_hwdata *lookup;
 	struct ipu7_mmu_hw *mmu_hw, *src;
 	unsigned int i, nr_mmus;
 
 	if (mmu->mmid >= IPU_SUBSYS_NUM)
 		return -EINVAL;
 
+	lookup = IS_IPU7P5(isp) ? ipu7p5_mmu_hwdata_lookup :
+				  ipu7_mmu_hwdata_lookup;
+
 	src = lookup[mmu->mmid].hwdata;
 	nr_mmus = lookup[mmu->mmid].nr_mmus;
 
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
index 68663057138a..ba31ed31b245 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
@@ -114,6 +114,105 @@
 #define IPU7_PS_ZLX_FW_RD_NUM			16
 #define IPU7_PS_ZLX_FW_WR_NUM			10
 
+/* IPU7P5 */
+/* IS MMU Cmd RD */
+#define IPU7P5_IS_MMU_FW_RD_OFFSET		0x274000
+#define IPU7P5_IS_MMU_FW_RD_STREAM_NUM		3
+#define IPU7P5_IS_MMU_FW_RD_L1_BLOCKNR_REG	0x54
+#define IPU7P5_IS_MMU_FW_RD_L2_BLOCKNR_REG	0x60
+
+/* IS MMU Cmd WR */
+#define IPU7P5_IS_MMU_FW_WR_OFFSET		0x275000
+#define IPU7P5_IS_MMU_FW_WR_STREAM_NUM		3
+#define IPU7P5_IS_MMU_FW_WR_L1_BLOCKNR_REG	0x54
+#define IPU7P5_IS_MMU_FW_WR_L2_BLOCKNR_REG	0x60
+
+/* IS MMU Data WR Snoop */
+#define IPU7P5_IS_MMU_M0_OFFSET			0x276000
+#define IPU7P5_IS_MMU_M0_STREAM_NUM		16
+#define IPU7P5_IS_MMU_M0_L1_BLOCKNR_REG		0x54
+#define IPU7P5_IS_MMU_M0_L2_BLOCKNR_REG		0x94
+
+/* IS MMU Data WR ISOC */
+#define IPU7P5_IS_MMU_M1_OFFSET			0x277000
+#define IPU7P5_IS_MMU_M1_STREAM_NUM		16
+#define IPU7P5_IS_MMU_M1_L1_BLOCKNR_REG		0x54
+#define IPU7P5_IS_MMU_M1_L2_BLOCKNR_REG		0x94
+
+/* PS MMU FW RD */
+#define IPU7P5_PS_MMU_FW_RD_OFFSET		0x148000
+#define IPU7P5_PS_MMU_FW_RD_STREAM_NUM		16
+#define IPU7P5_PS_MMU_FW_RD_L1_BLOCKNR_REG	0x54
+#define IPU7P5_PS_MMU_FW_RD_L2_BLOCKNR_REG	0x94
+
+/* PS MMU FW WR */
+#define IPU7P5_PS_MMU_FW_WR_OFFSET		0x149000
+#define IPU7P5_PS_MMU_FW_WR_STREAM_NUM		10
+#define IPU7P5_PS_MMU_FW_WR_L1_BLOCKNR_REG	0x54
+#define IPU7P5_PS_MMU_FW_WR_L2_BLOCKNR_REG	0x7c
+
+/* PS MMU FW Data RD VC0 */
+#define IPU7P5_PS_MMU_SRT_RD_OFFSET		0x14a000
+#define IPU7P5_PS_MMU_SRT_RD_STREAM_NUM		22
+#define IPU7P5_PS_MMU_SRT_RD_L1_BLOCKNR_REG	0x54
+#define IPU7P5_PS_MMU_SRT_RD_L2_BLOCKNR_REG	0xac
+
+/* PS MMU FW Data WR VC0 */
+#define IPU7P5_PS_MMU_SRT_WR_OFFSET		0x14b000
+#define IPU7P5_PS_MMU_SRT_WR_STREAM_NUM		32
+#define IPU7P5_PS_MMU_SRT_WR_L1_BLOCKNR_REG	0x54
+#define IPU7P5_PS_MMU_SRT_WR_L2_BLOCKNR_REG	0xd4
+
+/* IS UAO UC RD */
+#define IPU7P5_IS_UAO_UC_RD_OFFSET		0x27c000
+#define IPU7P5_IS_UAO_UC_RD_PLANENUM		4
+
+/* IS UAO UC WR */
+#define IPU7P5_IS_UAO_UC_WR_OFFSET		0x27d000
+#define IPU7P5_IS_UAO_UC_WR_PLANENUM		4
+
+/* IS UAO M0 WR */
+#define IPU7P5_IS_UAO_M0_WR_OFFSET		0x27e000
+#define IPU7P5_IS_UAO_M0_WR_PLANENUM		16
+
+/* IS UAO M1 WR */
+#define IPU7P5_IS_UAO_M1_WR_OFFSET		0x27f000
+#define IPU7P5_IS_UAO_M1_WR_PLANENUM		16
+
+/* PS UAO FW RD */
+#define IPU7P5_PS_UAO_FW_RD_OFFSET		0x156000
+#define IPU7P5_PS_UAO_FW_RD_PLANENUM		16
+
+/* PS UAO FW WR */
+#define IPU7P5_PS_UAO_FW_WR_OFFSET		0x157000
+#define IPU7P5_PS_UAO_FW_WR_PLANENUM		10
+
+/* PS UAO SRT RD */
+#define IPU7P5_PS_UAO_SRT_RD_OFFSET		0x154000
+#define IPU7P5_PS_UAO_SRT_RD_PLANENUM		22
+
+/* PS UAO SRT WR */
+#define IPU7P5_PS_UAO_SRT_WR_OFFSET		0x155000
+#define IPU7P5_PS_UAO_SRT_WR_PLANENUM		32
+
+#define IPU7P5_IS_ZLX_UC_RD_OFFSET		0x278000
+#define IPU7P5_IS_ZLX_UC_WR_OFFSET		0x279000
+#define IPU7P5_IS_ZLX_M0_OFFSET			0x27a000
+#define IPU7P5_IS_ZLX_M1_OFFSET			0x27b000
+#define IPU7P5_IS_ZLX_UC_RD_NUM			4
+#define IPU7P5_IS_ZLX_UC_WR_NUM			4
+#define IPU7P5_IS_ZLX_M0_NUM			16
+#define IPU7P5_IS_ZLX_M1_NUM			16
+
+#define IPU7P5_PS_ZLX_DATA_RD_OFFSET		0x14e000
+#define IPU7P5_PS_ZLX_DATA_WR_OFFSET		0x14f000
+#define IPU7P5_PS_ZLX_FW_RD_OFFSET		0x150000
+#define IPU7P5_PS_ZLX_FW_WR_OFFSET		0x151000
+#define IPU7P5_PS_ZLX_DATA_RD_NUM		22
+#define IPU7P5_PS_ZLX_DATA_WR_NUM		32
+#define IPU7P5_PS_ZLX_FW_RD_NUM			16
+#define IPU7P5_PS_ZLX_FW_WR_NUM			10
+
 struct ipu7_mmu_hw {
 	char name[32];
 
-- 
2.55.0


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

* [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5
  2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
                   ` (42 preceding siblings ...)
  2026-08-21 11:43 ` [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data Antti Laakso
@ 2026-08-21 11:43 ` Antti Laakso
  43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:43 UTC (permalink / raw)
  To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso

The driver have now support for ipu7 and 7.5.

Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
 include/media/ipu6-pci-table.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/media/ipu6-pci-table.h b/include/media/ipu6-pci-table.h
index cd5b941fb96c..cacb8a3170d0 100644
--- a/include/media/ipu6-pci-table.h
+++ b/include/media/ipu6-pci-table.h
@@ -24,6 +24,8 @@ static const struct pci_device_id ipu6_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6EP_ADLN) },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6EP_RPLP) },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6EP_MTL) },
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) },
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) },
 	{ }
 };
 
-- 
2.55.0


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

* Re: [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe
  2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
@ 2026-08-21 18:17   ` Sakari Ailus
  0 siblings, 0 replies; 47+ messages in thread
From: Sakari Ailus @ 2026-08-21 18:17 UTC (permalink / raw)
  To: Antti Laakso; +Cc: linux-media, mchehab, daxing.li, ong.hock.yu

Moi,

Thanks for the update!

On Fri, Aug 21, 2026 at 02:42:57PM +0300, Antti Laakso wrote:
> We are bout to add ipu7 firmware mapping. It is slightly different from

s/bout/about/

> ipu6. Handling this and possible errors is easier when both isys and
> psys mapping is in one place.
> 
> Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
> ---
>  drivers/media/pci/intel/ipu6/ipu6-bus.h  |  1 -
>  drivers/media/pci/intel/ipu6/ipu6-isys.c | 29 -----------
>  drivers/media/pci/intel/ipu6/ipu6.c      | 63 +++++++++++++++++++-----
>  3 files changed, 50 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
> index aef8e4a66c4a..d2f93eb03dea 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
> +++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
> @@ -26,7 +26,6 @@ struct ipu6_bus_device {
>  	struct ipu6_mmu *mmu;
>  	struct ipu6_device *isp;
>  	const struct ipu6_buttress_ctrl *ctrl;
> -	const struct firmware *fw;
>  	struct sg_table fw_sgt;
>  	u64 *pkg_dir;
>  	dma_addr_t pkg_dir_dma_addr;
> diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
> index 459121e6c1cb..3fb34d2d189c 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
> @@ -995,7 +995,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
>  	const struct ipu6_isys_internal_csi2_pdata *csi2_pdata;
>  	struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
>  	struct ipu6_device *isp = adev->isp;
> -	const struct firmware *fw;
>  	struct ipu6_isys *isys;
>  	unsigned int i;
>  	int ret;
> @@ -1040,18 +1039,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
>  
>  	isys_stream_init(isys);
>  
> -	if (!isp->secure_mode) {
> -		fw = isp->cpd_fw;
> -		ret = ipu6_map_fw_region(adev, fw->data, fw->size,
> -					 DMA_TO_DEVICE, 0);
> -		if (ret)
> -			goto release_firmware;
> -
> -		ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
> -		if (ret)
> -			goto remove_shared_buffer;
> -	}
> -
>  	cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
>  
>  	ret = alloc_fw_msg_bufs(isys, 20);
> @@ -1079,14 +1066,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
>  	free_fw_msg_bufs(isys);
>  out_remove_pkg_dir_shared_buffer:
>  	cpu_latency_qos_remove_request(&isys->pm_qos);
> -	if (!isp->secure_mode)
> -		ipu6_cpd_free_pkg_dir(adev);
> -remove_shared_buffer:
> -	if (!isp->secure_mode)
> -		ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
> -release_firmware:
> -	if (!isp->secure_mode)
> -		release_firmware(adev->fw);
>  
>  	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
>  		mutex_destroy(&isys->streams[i].mutex);
> @@ -1099,9 +1078,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
>  
>  static void isys_remove(struct auxiliary_device *auxdev)
>  {
> -	struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
>  	struct ipu6_isys *isys = dev_get_drvdata(&auxdev->dev);
> -	struct ipu6_device *isp = adev->isp;
>  	unsigned int i;
>  
>  	free_fw_msg_bufs(isys);
> @@ -1111,12 +1088,6 @@ static void isys_remove(struct auxiliary_device *auxdev)
>  
>  	cpu_latency_qos_remove_request(&isys->pm_qos);
>  
> -	if (!isp->secure_mode) {
> -		ipu6_cpd_free_pkg_dir(adev);
> -		ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
> -		release_firmware(adev->fw);
> -	}
> -
>  	for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
>  		mutex_destroy(&isys->streams[i].mutex);
>  
> diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
> index af5581da7149..d27ffd7ac6f0 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6.c
> @@ -480,6 +480,40 @@ static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
>  	writel(val, isp->base + BUTTRESS_REG_BTRS_CTRL);
>  }
>  
> +static int __ipu6_map_fw_by_sys(struct ipu6_device *isp, struct ipu6_bus_device *adev)
> +{
> +	int ret = ipu6_map_fw_region(adev, isp->cpd_fw->data, isp->cpd_fw->size,

Please avoid assigning variables in declaration block when there are errors
to check.

> +				 DMA_TO_DEVICE, 0);
> +
> +	if (ret) {
> +		dev_err_probe(&isp->pdev->dev, ret,
> +			      "Firmware mapping failed\n");
> +		return ret;
> +	}
> +
> +	ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
> +	if (ret) {
> +		dev_err_probe(&isp->pdev->dev, ret,
> +			      "failed to create pkg dir\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipu6_map_fw(struct ipu6_device *isp)
> +{
> +	int ret = __ipu6_map_fw_by_sys(isp, isp->psys);

Ditto.

> +
> +	if (ret)
> +		return ret;
> +
> +	if (!isp->secure_mode)
> +		return __ipu6_map_fw_by_sys(isp, isp->isys);
> +
> +	return 0;
> +}
> +
>  static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  {
>  	const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
> @@ -624,19 +658,9 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  		goto out_ipu6_rpm_put;
>  	}
>  
> -	ret = ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
> -				 isp->cpd_fw->size, DMA_TO_DEVICE, 0);
> -	if (ret) {
> -		dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
> -		goto out_ipu6_rpm_put;
> -	}
> -
> -	ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
> -	if (ret) {
> -		dev_err_probe(&isp->pdev->dev, ret,
> -			      "failed to create pkg dir\n");
> +	ret = ipu6_map_fw(isp);
> +	if (ret)
>  		goto out_ipu6_rpm_put;
> -	}
>  
>  	ret = devm_request_threaded_irq(dev, pdev->irq, ipu6_buttress_isr,
>  					ipu6_buttress_isr_threaded,
> @@ -679,7 +703,13 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  out_ipu6_bus_del_devices:
>  	if (!IS_ERR_OR_NULL(isp->psys)) {
>  		ipu6_cpd_free_pkg_dir(isp->psys);
> -		ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> +		if (isp->psys->fw_sgt.nents)
> +			ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> +	}
> +	if (!IS_ERR_OR_NULL(isp->isys)) {
> +		ipu6_cpd_free_pkg_dir(isp->isys);
> +		if (isp->isys->fw_sgt.nents)
> +			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
>  	}
>  	if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
>  		ipu6_mmu_cleanup(isp->psys->mmu);
> @@ -703,6 +733,13 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
>  	ipu6_cpd_free_pkg_dir(isp->psys);
>  
>  	ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> +
> +	if (isp->isys) {
> +		ipu6_cpd_free_pkg_dir(isp->isys);
> +		if (isp->isys->fw_sgt.nents)
> +			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> +	}
> +
>  	ipu6_buttress_exit(isp);
>  
>  	ipu6_bus_del_devices(pdev);

-- 
Terveisin,

Sakari Ailus

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

* Re: [PATCH v2 40/44] media: ipu6: Map ipu7 firmware
  2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
@ 2026-08-21 18:23   ` Sakari Ailus
  0 siblings, 0 replies; 47+ messages in thread
From: Sakari Ailus @ 2026-08-21 18:23 UTC (permalink / raw)
  To: Antti Laakso; +Cc: linux-media, mchehab, daxing.li, ong.hock.yu

Moi,

On Fri, Aug 21, 2026 at 02:42:58PM +0300, Antti Laakso wrote:
> Mapping of ipu7 firmware is slightly different compared to ipu6. Add
> helpers for it and call them similar to ipu6.
> 
> Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
> ---
>  drivers/media/pci/intel/ipu6/ipu6.c | 75 ++++++++++++++++++++++++++---
>  drivers/media/pci/intel/ipu6/ipu6.h |  1 +
>  2 files changed, 70 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
> index d27ffd7ac6f0..93f28ec9a74d 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6.c
> @@ -19,6 +19,7 @@
>  #include <linux/scatterlist.h>
>  #include <linux/slab.h>
>  #include <linux/types.h>
> +#include <linux/vmalloc.h>
>  
>  #include <media/ipu-bridge.h>
>  #include <media/ipu6-pci-table.h>
> @@ -27,6 +28,7 @@
>  #include "ipu6-bus.h"
>  #include "ipu6-buttress.h"
>  #include "ipu6-cpd.h"
> +#include "ipu6-dma.h"
>  #include "ipu6-isys.h"
>  #include "ipu6-mmu.h"
>  #include "ipu6-platform-buttress-regs.h"
> @@ -514,6 +516,57 @@ static int ipu6_map_fw(struct ipu6_device *isp)
>  	return 0;
>  }
>  
> +static int __ipu7_map_fw_non_secure(struct ipu6_device *isp)
> +{
> +	int ret;
> +
> +	/*
> +	 * Allocate and map memory for running the firmware. Not
> +	 * required in secure mode, in which firmware runs in IMR.
> +	 */
> +	isp->fw_code_region = vmalloc(IPU7_FW_CODE_REGION_SIZE);
> +	if (!isp->fw_code_region)
> +		return -ENOMEM;
> +
> +	ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "isys",
> +				   isp->fw_code_region, &isp->isys->fw_entry);
> +	if (ret)
> +		return ret;
> +
> +	ret = ipu6_map_fw_region(isp->isys, isp->fw_code_region,
> +				 IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
> +				 DMA_ATTR_RESERVE_REGION);
> +	if (ret)
> +		return ret;
> +
> +	ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "psys",
> +				   isp->fw_code_region, &isp->psys->fw_entry);
> +	if (ret)
> +		return ret;
> +
> +	return ipu6_map_fw_region(isp->psys, isp->fw_code_region,
> +				  IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
> +				  DMA_ATTR_RESERVE_REGION);
> +}
> +
> +static int ipu7_map_fw(struct ipu6_device *isp)
> +{
> +	int ret;
> +
> +	ret = isp->secure_mode ?
> +		ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
> +				   isp->cpd_fw->size, DMA_BIDIRECTIONAL, 0) :
> +		__ipu7_map_fw_non_secure(isp);
> +

No newline needed here.

> +	if (ret) {
> +		dev_err_probe(&isp->pdev->dev, ret,
> +			      "Failed to init ipu7 firmware region\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  {
>  	const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
> @@ -523,6 +576,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	struct ipu6_device *isp;
>  	phys_addr_t phys;
>  	u32 val, version, sku_id;
> +	unsigned long dir;
>  	int ret;
>  
>  	isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
> @@ -658,7 +712,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  		goto out_ipu6_rpm_put;
>  	}
>  
> -	ret = ipu6_map_fw(isp);
> +	ret = IS_IPU7(isp) ? ipu7_map_fw(isp) : ipu6_map_fw(isp);
>  	if (ret)
>  		goto out_ipu6_rpm_put;
>  
> @@ -701,15 +755,20 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  out_ipu6_rpm_put:
>  	pm_runtime_put_sync(&isp->psys->auxdev.dev);
>  out_ipu6_bus_del_devices:
> +	dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
>  	if (!IS_ERR_OR_NULL(isp->psys)) {
>  		ipu6_cpd_free_pkg_dir(isp->psys);
>  		if (isp->psys->fw_sgt.nents)
> -			ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> +			ipu6_unmap_fw_region(isp->psys, dir);
>  	}
>  	if (!IS_ERR_OR_NULL(isp->isys)) {
>  		ipu6_cpd_free_pkg_dir(isp->isys);
>  		if (isp->isys->fw_sgt.nents)
> -			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> +			ipu6_unmap_fw_region(isp->isys, dir);
> +	}
> +	if (isp->fw_code_region) {
> +		vfree(isp->fw_code_region);
> +		isp->fw_code_region = NULL;

This can be done unconditionally -- as in the remove callback.

>  	}
>  	if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
>  		ipu6_mmu_cleanup(isp->psys->mmu);
> @@ -728,18 +787,22 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
>  	struct ipu6_device *isp = pci_get_drvdata(pdev);
>  	struct ipu6_mmu *isys_mmu = isp->isys->mmu;
>  	struct ipu6_mmu *psys_mmu = isp->psys->mmu;
> +	unsigned long dir;
>  
>  	devm_free_irq(&pdev->dev, pdev->irq, isp);
> -	ipu6_cpd_free_pkg_dir(isp->psys);
>  
> -	ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> +	dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;

Why is there a need for a bi-directional mapping for ipu7?

> +	ipu6_cpd_free_pkg_dir(isp->psys);
> +	ipu6_unmap_fw_region(isp->psys, dir);
>  
>  	if (isp->isys) {
>  		ipu6_cpd_free_pkg_dir(isp->isys);
>  		if (isp->isys->fw_sgt.nents)
> -			ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> +			ipu6_unmap_fw_region(isp->isys, dir);
>  	}
>  
> +	vfree(isp->fw_code_region);
> +
>  	ipu6_buttress_exit(isp);
>  
>  	ipu6_bus_del_devices(pdev);
> diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
> index 6bef45a02c2b..a2992ffe8e3c 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6.h
> +++ b/drivers/media/pci/intel/ipu6/ipu6.h
> @@ -70,6 +70,7 @@ struct ipu6_device {
>  	bool secure_mode;
>  	u8 hw_ver;
>  	bool bus_ready_to_probe;
> +	u32 *fw_code_region;
>  };
>  
>  #define IPU_PSYS	0

-- 
Terveisin,

Sakari Ailus

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

end of thread, other threads:[~2026-08-21 18:23 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
2026-08-21 11:42 ` [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation Antti Laakso
2026-08-21 11:42 ` [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context Antti Laakso
2026-08-21 11:42 ` [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer Antti Laakso
2026-08-21 11:42 ` [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation Antti Laakso
2026-08-21 11:42 ` [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct Antti Laakso
2026-08-21 11:42 ` [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init() Antti Laakso
2026-08-21 11:42 ` [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments Antti Laakso
2026-08-21 11:42 ` [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7 Antti Laakso
2026-08-21 11:42 ` [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support Antti Laakso
2026-08-21 11:42 ` [PATCH v2 10/44] media: ipu6: Use single struct for registers Antti Laakso
2026-08-21 11:42 ` [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID Antti Laakso
2026-08-21 11:42 ` [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support Antti Laakso
2026-08-21 11:42 ` [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation Antti Laakso
2026-08-21 11:42 ` [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support Antti Laakso
2026-08-21 11:42 ` [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling Antti Laakso
2026-08-21 11:42 ` [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing Antti Laakso
2026-08-21 11:42 ` [PATCH v2 17/44] media: ipu6: Rename isys fw msg union Antti Laakso
2026-08-21 11:42 ` [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file Antti Laakso
2026-08-21 11:42 ` [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down Antti Laakso
2026-08-21 11:42 ` [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling Antti Laakso
2026-08-21 11:42 ` [PATCH v2 21/44] media: ipu6: Add isys firmware ops Antti Laakso
2026-08-21 11:42 ` [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality Antti Laakso
2026-08-21 11:42 ` [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods Antti Laakso
2026-08-21 11:42 ` [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops Antti Laakso
2026-08-21 11:42 ` [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions Antti Laakso
2026-08-21 11:42 ` [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler Antti Laakso
2026-08-21 11:42 ` [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver Antti Laakso
2026-08-21 11:42 ` [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable Antti Laakso
2026-08-21 11:42 ` [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver Antti Laakso
2026-08-21 11:42 ` [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7 Antti Laakso
2026-08-21 11:42 ` [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts Antti Laakso
2026-08-21 11:42 ` [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7 Antti Laakso
2026-08-21 11:42 ` [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6 Antti Laakso
2026-08-21 11:42 ` [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only Antti Laakso
2026-08-21 11:42 ` [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe Antti Laakso
2026-08-21 11:42 ` [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7 Antti Laakso
2026-08-21 11:42 ` [PATCH v2 37/44] media: ipu6: Add support for fixed iova region Antti Laakso
2026-08-21 11:42 ` [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable Antti Laakso
2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
2026-08-21 18:17   ` Sakari Ailus
2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
2026-08-21 18:23   ` Sakari Ailus
2026-08-21 11:42 ` [PATCH v2 41/44] media: ipu6: Set model name for ipu7 Antti Laakso
2026-08-21 11:43 ` [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support Antti Laakso
2026-08-21 11:43 ` [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data Antti Laakso
2026-08-21 11:43 ` [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5 Antti Laakso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox