Linux Media Controller development
 help / color / mirror / Atom feed
From: Antti Laakso <antti.laakso@linux.intel.com>
To: linux-media@vger.kernel.org, mchehab@kernel.org,
	sakari.ailus@linux.intel.com
Cc: daxing.li@intel.com, ong.hock.yu@intel.com, antti.laakso@linux.intel.com
Subject: [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation
Date: Fri, 21 Aug 2026 14:42:31 +0300	[thread overview]
Message-ID: <20260821114302.365532-14-antti.laakso@linux.intel.com> (raw)
In-Reply-To: <20260821114302.365532-1-antti.laakso@linux.intel.com>

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


  parent reply	other threads:[~2026-08-21 11:44 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Antti Laakso [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260821114302.365532-14-antti.laakso@linux.intel.com \
    --to=antti.laakso@linux.intel.com \
    --cc=daxing.li@intel.com \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=ong.hock.yu@intel.com \
    --cc=sakari.ailus@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox