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
next prev 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