From: Ville Syrjala <ville.syrjala@linux.intel.com>
To: intel-gfx@lists.freedesktop.org
Cc: intel-xe@lists.freedesktop.org, Jani Nikula <jani.nikula@intel.com>
Subject: [PATCH v3 18/19] drm/i915/overlay: Move i915 specific code into i915_overlay.c
Date: Thu, 26 Feb 2026 15:38:55 +0200 [thread overview]
Message-ID: <20260226133855.17690-1-ville.syrjala@linux.intel.com> (raw)
In-Reply-To: <20260226100738.29997-19-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Relocate the i915 driver specific parts of the overlay code
into i915_overlay.c. This leaves intel_overlay.c with just
the display specific code.
The one annoyance here is the DSPCLK_GATE_D register access
being done from i830_overlay_clock_gating(). The register
definition lives on the display side as we do need to access
it on other platforms there. Since it's just one register
and bit, I decided to just duplicate that part in i915_reg.h.
v2: Use kzalloc_obj()
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/Makefile | 1 +
.../gpu/drm/i915/display/intel_display_regs.h | 2 -
drivers/gpu/drm/i915/display/intel_overlay.c | 490 +----------------
drivers/gpu/drm/i915/i915_overlay.c | 500 ++++++++++++++++++
drivers/gpu/drm/i915/i915_overlay.h | 43 ++
drivers/gpu/drm/i915/i915_reg.h | 4 +
6 files changed, 550 insertions(+), 490 deletions(-)
create mode 100644 drivers/gpu/drm/i915/i915_overlay.c
create mode 100644 drivers/gpu/drm/i915/i915_overlay.h
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 4d6c528d9881..45171de63ef9 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -80,6 +80,7 @@ i915-y += \
i915_dsb_buffer.o \
i915_hdcp_gsc.o \
i915_initial_plane.o \
+ i915_overlay.o \
i915_panic.o
# "Graphics Technology" (aka we talk to the gpu)
diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h
index 49e2a9e3ee0e..4746e9ebd920 100644
--- a/drivers/gpu/drm/i915/display/intel_display_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_display_regs.h
@@ -117,8 +117,6 @@
#define VLV_ERROR_PAGE_TABLE (1 << 4)
#define VLV_ERROR_CLAIM (1 << 0)
-#define GEN2_ISR _MMIO(0x20ac)
-
#define VLV_ERROR_REGS I915_ERROR_REGS(VLV_EMR, VLV_EIR)
#define _MBUS_ABOX0_CTL 0x45038
diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c
index 37c60c08dd56..497bd4ec2224 100644
--- a/drivers/gpu/drm/i915/display/intel_overlay.c
+++ b/drivers/gpu/drm/i915/display/intel_overlay.c
@@ -27,24 +27,16 @@
*/
#include <drm/drm_fourcc.h>
+#include <drm/drm_gem.h>
#include <drm/drm_print.h>
-#include <drm/intel/intel_gmd_interrupt_regs.h>
-#include "gem/i915_gem_internal.h"
-#include "gem/i915_gem_object_frontbuffer.h"
-#include "gem/i915_gem_pm.h"
-
-#include "gt/intel_gpu_commands.h"
-#include "gt/intel_ring.h"
-
-#include "i915_drv.h"
+#include "i915_overlay.h"
#include "intel_color_regs.h"
#include "intel_de.h"
#include "intel_display_regs.h"
#include "intel_display_types.h"
#include "intel_frontbuffer.h"
#include "intel_overlay.h"
-#include "intel_pci_config.h"
#include "intel_pfit_regs.h"
/* Limits for overlay size. According to intel doc, the real limits are:
@@ -121,9 +113,6 @@
#define RGB8I_TO_COLORKEY(c) \
((((c) & 0xff) << 16) | (((c) & 0xff) << 8) | (((c) & 0xff) << 0))
-/* overlay flip addr flag */
-#define OFC_UPDATE 0x1
-
/* polyphase filter coefficients */
#define N_HORIZ_Y_TAPS 5
#define N_VERT_Y_TAPS 3
@@ -187,22 +176,6 @@ struct overlay_registers {
u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
};
-struct i915_overlay {
- struct drm_i915_private *i915;
- struct intel_context *context;
- struct i915_vma *vma;
- struct i915_vma *old_vma;
- struct intel_frontbuffer *frontbuffer;
- /* register access */
- struct drm_i915_gem_object *reg_bo;
- void __iomem *regs;
- u32 flip_addr;
- u32 frontbuffer_bits;
- /* flip handling */
- struct i915_active last_flip;
- void (*flip_complete)(struct i915_overlay *overlay);
-};
-
struct intel_overlay {
struct intel_display *display;
struct intel_crtc *crtc;
@@ -215,314 +188,6 @@ struct intel_overlay {
struct overlay_registers __iomem *regs;
};
-static void i830_overlay_clock_gating(struct drm_i915_private *i915,
- bool enable)
-{
- struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
- u8 val;
-
- /*
- * WA_OVERLAY_CLKGATE:alm
- *
- * FIXME should perhaps be done on the display side?
- */
- if (enable)
- intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, 0);
- else
- intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
-
- /* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */
- pci_bus_read_config_byte(pdev->bus,
- PCI_DEVFN(0, 0), I830_CLOCK_GATE, &val);
- if (enable)
- val &= ~I830_L2_CACHE_CLOCK_GATE_DISABLE;
- else
- val |= I830_L2_CACHE_CLOCK_GATE_DISABLE;
- pci_bus_write_config_byte(pdev->bus,
- PCI_DEVFN(0, 0), I830_CLOCK_GATE, val);
-}
-
-static struct i915_request *
-alloc_request(struct i915_overlay *overlay, void (*fn)(struct i915_overlay *))
-{
- struct i915_request *rq;
- int err;
-
- overlay->flip_complete = fn;
-
- rq = i915_request_create(overlay->context);
- if (IS_ERR(rq))
- return rq;
-
- err = i915_active_add_request(&overlay->last_flip, rq);
- if (err) {
- i915_request_add(rq);
- return ERR_PTR(err);
- }
-
- return rq;
-}
-
-static bool i915_overlay_is_active(struct drm_device *drm)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
-
- return overlay->frontbuffer_bits;
-}
-
-/* overlay needs to be disable in OCMD reg */
-static int i915_overlay_on(struct drm_device *drm,
- u32 frontbuffer_bits)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
- struct i915_request *rq;
- u32 *cs;
-
- drm_WARN_ON(drm, i915_overlay_is_active(drm));
-
- rq = alloc_request(overlay, NULL);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
-
- cs = intel_ring_begin(rq, 4);
- if (IS_ERR(cs)) {
- i915_request_add(rq);
- return PTR_ERR(cs);
- }
-
- overlay->frontbuffer_bits = frontbuffer_bits;
-
- if (IS_I830(i915))
- i830_overlay_clock_gating(i915, false);
-
- *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_ON;
- *cs++ = overlay->flip_addr | OFC_UPDATE;
- *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
- *cs++ = MI_NOOP;
- intel_ring_advance(rq, cs);
-
- i915_request_add(rq);
-
- return i915_active_wait(&overlay->last_flip);
-}
-
-static void i915_overlay_flip_prepare(struct i915_overlay *overlay,
- struct i915_vma *vma)
-{
- struct drm_i915_private *i915 = overlay->i915;
- struct intel_frontbuffer *frontbuffer = NULL;
-
- drm_WARN_ON(&i915->drm, overlay->old_vma);
-
- if (vma)
- frontbuffer = intel_frontbuffer_get(intel_bo_to_drm_bo(vma->obj));
-
- intel_frontbuffer_track(overlay->frontbuffer, frontbuffer,
- overlay->frontbuffer_bits);
-
- if (overlay->frontbuffer)
- intel_frontbuffer_put(overlay->frontbuffer);
- overlay->frontbuffer = frontbuffer;
-
- overlay->old_vma = overlay->vma;
- if (vma)
- overlay->vma = i915_vma_get(vma);
- else
- overlay->vma = NULL;
-}
-
-/* overlay needs to be enabled in OCMD reg */
-static int i915_overlay_continue(struct drm_device *drm,
- struct i915_vma *vma,
- bool load_polyphase_filter)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
- struct i915_request *rq;
- u32 flip_addr = overlay->flip_addr;
- u32 *cs;
-
- drm_WARN_ON(drm, !i915_overlay_is_active(drm));
-
- if (load_polyphase_filter)
- flip_addr |= OFC_UPDATE;
-
- rq = alloc_request(overlay, NULL);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
-
- cs = intel_ring_begin(rq, 2);
- if (IS_ERR(cs)) {
- i915_request_add(rq);
- return PTR_ERR(cs);
- }
-
- *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
- *cs++ = flip_addr;
- intel_ring_advance(rq, cs);
-
- i915_overlay_flip_prepare(overlay, vma);
- i915_request_add(rq);
-
- return 0;
-}
-
-static void i915_overlay_release_old_vma(struct i915_overlay *overlay)
-{
- struct drm_i915_private *i915 = overlay->i915;
- struct intel_display *display = i915->display;
- struct i915_vma *vma;
-
- vma = fetch_and_zero(&overlay->old_vma);
- if (drm_WARN_ON(&i915->drm, !vma))
- return;
-
- intel_frontbuffer_flip(display, overlay->frontbuffer_bits);
-
- i915_vma_unpin(vma);
- i915_vma_put(vma);
-}
-
-static void i915_overlay_release_old_vid_tail(struct i915_overlay *overlay)
-{
- i915_overlay_release_old_vma(overlay);
-}
-
-static void i915_overlay_off_tail(struct i915_overlay *overlay)
-{
- struct drm_i915_private *i915 = overlay->i915;
-
- i915_overlay_release_old_vma(overlay);
-
- overlay->frontbuffer_bits = 0;
-
- if (IS_I830(i915))
- i830_overlay_clock_gating(i915, true);
-}
-
-static void i915_overlay_last_flip_retire(struct i915_active *active)
-{
- struct i915_overlay *overlay =
- container_of(active, typeof(*overlay), last_flip);
-
- if (overlay->flip_complete)
- overlay->flip_complete(overlay);
-}
-
-/* overlay needs to be disabled in OCMD reg */
-static int i915_overlay_off(struct drm_device *drm)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
- struct i915_request *rq;
- u32 *cs, flip_addr = overlay->flip_addr;
-
- drm_WARN_ON(drm, !i915_overlay_is_active(drm));
-
- /*
- * According to intel docs the overlay hw may hang (when switching
- * off) without loading the filter coeffs. It is however unclear whether
- * this applies to the disabling of the overlay or to the switching off
- * of the hw. Do it in both cases.
- */
- flip_addr |= OFC_UPDATE;
-
- rq = alloc_request(overlay, i915_overlay_off_tail);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
-
- cs = intel_ring_begin(rq, 6);
- if (IS_ERR(cs)) {
- i915_request_add(rq);
- return PTR_ERR(cs);
- }
-
- /* wait for overlay to go idle */
- *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
- *cs++ = flip_addr;
- *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
-
- /* turn overlay off */
- *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_OFF;
- *cs++ = flip_addr;
- *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
-
- intel_ring_advance(rq, cs);
-
- i915_overlay_flip_prepare(overlay, NULL);
- i915_request_add(rq);
-
- return i915_active_wait(&overlay->last_flip);
-}
-
-/*
- * Recover from an interruption due to a signal.
- * We have to be careful not to repeat work forever an make forward progress.
- */
-static int i915_overlay_recover_from_interrupt(struct drm_device *drm)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
-
- return i915_active_wait(&overlay->last_flip);
-}
-
-/*
- * Wait for pending overlay flip and release old frame.
- * Needs to be called before the overlay register are changed
- * via intel_overlay_(un)map_regs.
- */
-static int i915_overlay_release_old_vid(struct drm_device *drm)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
- struct i915_request *rq;
- u32 *cs;
-
- /*
- * Only wait if there is actually an old frame to release to
- * guarantee forward progress.
- */
- if (!overlay->old_vma)
- return 0;
-
- if (!(intel_uncore_read(&i915->uncore, GEN2_ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) {
- i915_overlay_release_old_vid_tail(overlay);
- return 0;
- }
-
- rq = alloc_request(overlay, i915_overlay_release_old_vid_tail);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
-
- cs = intel_ring_begin(rq, 2);
- if (IS_ERR(cs)) {
- i915_request_add(rq);
- return PTR_ERR(cs);
- }
-
- *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
- *cs++ = MI_NOOP;
- intel_ring_advance(rq, cs);
-
- i915_request_add(rq);
-
- return i915_active_wait(&overlay->last_flip);
-}
-
-static void i915_overlay_reset(struct drm_device *drm)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay = i915->overlay;
-
- if (!overlay)
- return;
-
- overlay->frontbuffer_bits = 0;
-}
-
void intel_overlay_reset(struct intel_display *display)
{
struct intel_overlay *overlay = display->overlay;
@@ -796,43 +461,6 @@ static u32 overlay_cmd_reg(struct drm_intel_overlay_put_image *params)
return cmd;
}
-static struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm,
- struct drm_gem_object *obj,
- u32 *offset)
-{
- struct drm_i915_gem_object *new_bo = to_intel_bo(obj);
- struct i915_gem_ww_ctx ww;
- struct i915_vma *vma;
- int ret;
-
- i915_gem_ww_ctx_init(&ww, true);
-retry:
- ret = i915_gem_object_lock(new_bo, &ww);
- if (!ret) {
- vma = i915_gem_object_pin_to_display_plane(new_bo, &ww, 0, 0,
- NULL, PIN_MAPPABLE);
- ret = PTR_ERR_OR_ZERO(vma);
- }
- if (ret == -EDEADLK) {
- ret = i915_gem_ww_ctx_backoff(&ww);
- if (!ret)
- goto retry;
- }
- i915_gem_ww_ctx_fini(&ww);
- if (ret)
- return ERR_PTR(ret);
-
- *offset = i915_ggtt_offset(vma);
-
- return vma;
-}
-
-static void i915_overlay_unpin_fb(struct drm_device *drm,
- struct i915_vma *vma)
-{
- i915_vma_unpin(vma);
-}
-
static int intel_overlay_do_put_image(struct intel_overlay *overlay,
struct drm_gem_object *obj,
struct drm_intel_overlay_put_image *params)
@@ -1164,26 +792,6 @@ static int check_overlay_src(struct intel_display *display,
return 0;
}
-static struct drm_gem_object *
-i915_overlay_obj_lookup(struct drm_device *drm,
- struct drm_file *file_priv,
- u32 handle)
-{
- struct drm_i915_gem_object *bo;
-
- bo = i915_gem_object_lookup(file_priv, handle);
- if (!bo)
- return ERR_PTR(-ENOENT);
-
- if (i915_gem_object_is_tiled(bo)) {
- drm_dbg(drm, "buffer used for overlay image can not be tiled\n");
- i915_gem_object_put(bo);
- return ERR_PTR(-EINVAL);
- }
-
- return intel_bo_to_drm_bo(bo);
-}
-
int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -1416,78 +1024,6 @@ int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data,
return ret;
}
-static int get_registers(struct i915_overlay *overlay, bool use_phys)
-{
- struct drm_i915_private *i915 = overlay->i915;
- struct drm_i915_gem_object *obj;
- struct i915_vma *vma;
- int err;
-
- obj = i915_gem_object_create_stolen(i915, PAGE_SIZE);
- if (IS_ERR(obj))
- obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
- if (IS_ERR(obj))
- return PTR_ERR(obj);
-
- vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
- if (IS_ERR(vma)) {
- err = PTR_ERR(vma);
- goto err_put_bo;
- }
-
- if (use_phys)
- overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl);
- else
- overlay->flip_addr = i915_ggtt_offset(vma);
- overlay->regs = i915_vma_pin_iomap(vma);
- i915_vma_unpin(vma);
-
- if (IS_ERR(overlay->regs)) {
- err = PTR_ERR(overlay->regs);
- goto err_put_bo;
- }
-
- overlay->reg_bo = obj;
- return 0;
-
-err_put_bo:
- i915_gem_object_put(obj);
- return err;
-}
-
-static void __iomem *i915_overlay_setup(struct drm_device *drm,
- bool needs_physical)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct intel_engine_cs *engine;
- struct i915_overlay *overlay;
- int ret;
-
- engine = to_gt(i915)->engine[RCS0];
- if (!engine || !engine->kernel_context)
- return ERR_PTR(-ENOENT);
-
- overlay = kzalloc_obj(*overlay);
- if (!overlay)
- return ERR_PTR(-ENOMEM);
-
- overlay->i915 = i915;
- overlay->context = engine->kernel_context;
-
- i915_active_init(&overlay->last_flip,
- NULL, i915_overlay_last_flip_retire, 0);
-
- ret = get_registers(overlay, needs_physical);
- if (ret) {
- kfree(overlay);
- return ERR_PTR(ret);
- }
-
- i915->overlay = overlay;
-
- return overlay->regs;
-}
-
void intel_overlay_setup(struct intel_display *display)
{
struct intel_overlay *overlay;
@@ -1530,28 +1066,6 @@ bool intel_overlay_available(struct intel_display *display)
return display->overlay;
}
-static void i915_overlay_cleanup(struct drm_device *drm)
-{
- struct drm_i915_private *i915 = to_i915(drm);
- struct i915_overlay *overlay;
-
- overlay = fetch_and_zero(&i915->overlay);
- if (!overlay)
- return;
-
- /*
- * The bo's should be free'd by the generic code already.
- * Furthermore modesetting teardown happens beforehand so the
- * hardware should be off already.
- */
- drm_WARN_ON(drm, i915_overlay_is_active(drm));
-
- i915_gem_object_put(overlay->reg_bo);
- i915_active_fini(&overlay->last_flip);
-
- kfree(overlay);
-}
-
void intel_overlay_cleanup(struct intel_display *display)
{
if (!display->overlay)
diff --git a/drivers/gpu/drm/i915/i915_overlay.c b/drivers/gpu/drm/i915/i915_overlay.c
new file mode 100644
index 000000000000..61869747c6bb
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_overlay.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2026, Intel Corporation.
+ */
+
+#include <drm/drm_print.h>
+
+#include <drm/intel/intel_gmd_interrupt_regs.h>
+
+#include "gem/i915_gem_internal.h"
+#include "gem/i915_gem_object_frontbuffer.h"
+#include "gem/i915_gem_pm.h"
+
+#include "gt/intel_gpu_commands.h"
+#include "gt/intel_ring.h"
+
+#include "i915_drv.h"
+#include "i915_overlay.h"
+#include "i915_reg.h"
+#include "intel_pci_config.h"
+
+#include "display/intel_frontbuffer.h"
+
+/* overlay flip addr flag */
+#define OFC_UPDATE 0x1
+
+struct i915_overlay {
+ struct drm_i915_private *i915;
+ struct intel_context *context;
+ struct i915_vma *vma;
+ struct i915_vma *old_vma;
+ struct intel_frontbuffer *frontbuffer;
+ /* register access */
+ struct drm_i915_gem_object *reg_bo;
+ void __iomem *regs;
+ u32 flip_addr;
+ u32 frontbuffer_bits;
+ /* flip handling */
+ struct i915_active last_flip;
+ void (*flip_complete)(struct i915_overlay *overlay);
+};
+
+static void i830_overlay_clock_gating(struct drm_i915_private *i915,
+ bool enable)
+{
+ struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+ u8 val;
+
+ /*
+ * WA_OVERLAY_CLKGATE:alm
+ *
+ * FIXME should perhaps be done on the display side?
+ */
+ if (enable)
+ intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, 0);
+ else
+ intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+
+ /* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */
+ pci_bus_read_config_byte(pdev->bus,
+ PCI_DEVFN(0, 0), I830_CLOCK_GATE, &val);
+ if (enable)
+ val &= ~I830_L2_CACHE_CLOCK_GATE_DISABLE;
+ else
+ val |= I830_L2_CACHE_CLOCK_GATE_DISABLE;
+ pci_bus_write_config_byte(pdev->bus,
+ PCI_DEVFN(0, 0), I830_CLOCK_GATE, val);
+}
+
+static struct i915_request *
+alloc_request(struct i915_overlay *overlay, void (*fn)(struct i915_overlay *))
+{
+ struct i915_request *rq;
+ int err;
+
+ overlay->flip_complete = fn;
+
+ rq = i915_request_create(overlay->context);
+ if (IS_ERR(rq))
+ return rq;
+
+ err = i915_active_add_request(&overlay->last_flip, rq);
+ if (err) {
+ i915_request_add(rq);
+ return ERR_PTR(err);
+ }
+
+ return rq;
+}
+
+bool i915_overlay_is_active(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+
+ return overlay->frontbuffer_bits;
+}
+
+/* overlay needs to be disable in OCMD reg */
+int i915_overlay_on(struct drm_device *drm,
+ u32 frontbuffer_bits)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+ struct i915_request *rq;
+ u32 *cs;
+
+ drm_WARN_ON(drm, i915_overlay_is_active(drm));
+
+ rq = alloc_request(overlay, NULL);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ cs = intel_ring_begin(rq, 4);
+ if (IS_ERR(cs)) {
+ i915_request_add(rq);
+ return PTR_ERR(cs);
+ }
+
+ overlay->frontbuffer_bits = frontbuffer_bits;
+
+ if (IS_I830(i915))
+ i830_overlay_clock_gating(i915, false);
+
+ *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_ON;
+ *cs++ = overlay->flip_addr | OFC_UPDATE;
+ *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
+ *cs++ = MI_NOOP;
+ intel_ring_advance(rq, cs);
+
+ i915_request_add(rq);
+
+ return i915_active_wait(&overlay->last_flip);
+}
+
+static void i915_overlay_flip_prepare(struct i915_overlay *overlay,
+ struct i915_vma *vma)
+{
+ struct drm_i915_private *i915 = overlay->i915;
+ struct intel_frontbuffer *frontbuffer = NULL;
+
+ drm_WARN_ON(&i915->drm, overlay->old_vma);
+
+ if (vma)
+ frontbuffer = intel_frontbuffer_get(intel_bo_to_drm_bo(vma->obj));
+
+ intel_frontbuffer_track(overlay->frontbuffer, frontbuffer,
+ overlay->frontbuffer_bits);
+
+ if (overlay->frontbuffer)
+ intel_frontbuffer_put(overlay->frontbuffer);
+ overlay->frontbuffer = frontbuffer;
+
+ overlay->old_vma = overlay->vma;
+ if (vma)
+ overlay->vma = i915_vma_get(vma);
+ else
+ overlay->vma = NULL;
+}
+
+/* overlay needs to be enabled in OCMD reg */
+int i915_overlay_continue(struct drm_device *drm,
+ struct i915_vma *vma,
+ bool load_polyphase_filter)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+ struct i915_request *rq;
+ u32 flip_addr = overlay->flip_addr;
+ u32 *cs;
+
+ drm_WARN_ON(drm, !i915_overlay_is_active(drm));
+
+ if (load_polyphase_filter)
+ flip_addr |= OFC_UPDATE;
+
+ rq = alloc_request(overlay, NULL);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ cs = intel_ring_begin(rq, 2);
+ if (IS_ERR(cs)) {
+ i915_request_add(rq);
+ return PTR_ERR(cs);
+ }
+
+ *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
+ *cs++ = flip_addr;
+ intel_ring_advance(rq, cs);
+
+ i915_overlay_flip_prepare(overlay, vma);
+ i915_request_add(rq);
+
+ return 0;
+}
+
+static void i915_overlay_release_old_vma(struct i915_overlay *overlay)
+{
+ struct drm_i915_private *i915 = overlay->i915;
+ struct intel_display *display = i915->display;
+ struct i915_vma *vma;
+
+ vma = fetch_and_zero(&overlay->old_vma);
+ if (drm_WARN_ON(&i915->drm, !vma))
+ return;
+
+ intel_frontbuffer_flip(display, overlay->frontbuffer_bits);
+
+ i915_vma_unpin(vma);
+ i915_vma_put(vma);
+}
+
+static void i915_overlay_release_old_vid_tail(struct i915_overlay *overlay)
+{
+ i915_overlay_release_old_vma(overlay);
+}
+
+static void i915_overlay_off_tail(struct i915_overlay *overlay)
+{
+ struct drm_i915_private *i915 = overlay->i915;
+
+ i915_overlay_release_old_vma(overlay);
+
+ overlay->frontbuffer_bits = 0;
+
+ if (IS_I830(i915))
+ i830_overlay_clock_gating(i915, true);
+}
+
+static void i915_overlay_last_flip_retire(struct i915_active *active)
+{
+ struct i915_overlay *overlay =
+ container_of(active, typeof(*overlay), last_flip);
+
+ if (overlay->flip_complete)
+ overlay->flip_complete(overlay);
+}
+
+/* overlay needs to be disabled in OCMD reg */
+int i915_overlay_off(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+ struct i915_request *rq;
+ u32 *cs, flip_addr = overlay->flip_addr;
+
+ drm_WARN_ON(drm, !i915_overlay_is_active(drm));
+
+ /*
+ * According to intel docs the overlay hw may hang (when switching
+ * off) without loading the filter coeffs. It is however unclear whether
+ * this applies to the disabling of the overlay or to the switching off
+ * of the hw. Do it in both cases.
+ */
+ flip_addr |= OFC_UPDATE;
+
+ rq = alloc_request(overlay, i915_overlay_off_tail);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ cs = intel_ring_begin(rq, 6);
+ if (IS_ERR(cs)) {
+ i915_request_add(rq);
+ return PTR_ERR(cs);
+ }
+
+ /* wait for overlay to go idle */
+ *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
+ *cs++ = flip_addr;
+ *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
+
+ /* turn overlay off */
+ *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_OFF;
+ *cs++ = flip_addr;
+ *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
+
+ intel_ring_advance(rq, cs);
+
+ i915_overlay_flip_prepare(overlay, NULL);
+ i915_request_add(rq);
+
+ return i915_active_wait(&overlay->last_flip);
+}
+
+/*
+ * Recover from an interruption due to a signal.
+ * We have to be careful not to repeat work forever an make forward progress.
+ */
+int i915_overlay_recover_from_interrupt(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+
+ return i915_active_wait(&overlay->last_flip);
+}
+
+/*
+ * Wait for pending overlay flip and release old frame.
+ * Needs to be called before the overlay register are changed
+ * via intel_overlay_(un)map_regs.
+ */
+int i915_overlay_release_old_vid(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+ struct i915_request *rq;
+ u32 *cs;
+
+ /*
+ * Only wait if there is actually an old frame to release to
+ * guarantee forward progress.
+ */
+ if (!overlay->old_vma)
+ return 0;
+
+ if (!(intel_uncore_read(&i915->uncore, GEN2_ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) {
+ i915_overlay_release_old_vid_tail(overlay);
+ return 0;
+ }
+
+ rq = alloc_request(overlay, i915_overlay_release_old_vid_tail);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ cs = intel_ring_begin(rq, 2);
+ if (IS_ERR(cs)) {
+ i915_request_add(rq);
+ return PTR_ERR(cs);
+ }
+
+ *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
+ *cs++ = MI_NOOP;
+ intel_ring_advance(rq, cs);
+
+ i915_request_add(rq);
+
+ return i915_active_wait(&overlay->last_flip);
+}
+
+void i915_overlay_reset(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay = i915->overlay;
+
+ if (!overlay)
+ return;
+
+ overlay->frontbuffer_bits = 0;
+}
+
+struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm,
+ struct drm_gem_object *obj,
+ u32 *offset)
+{
+ struct drm_i915_gem_object *new_bo = to_intel_bo(obj);
+ struct i915_gem_ww_ctx ww;
+ struct i915_vma *vma;
+ int ret;
+
+ i915_gem_ww_ctx_init(&ww, true);
+retry:
+ ret = i915_gem_object_lock(new_bo, &ww);
+ if (!ret) {
+ vma = i915_gem_object_pin_to_display_plane(new_bo, &ww, 0, 0,
+ NULL, PIN_MAPPABLE);
+ ret = PTR_ERR_OR_ZERO(vma);
+ }
+ if (ret == -EDEADLK) {
+ ret = i915_gem_ww_ctx_backoff(&ww);
+ if (!ret)
+ goto retry;
+ }
+ i915_gem_ww_ctx_fini(&ww);
+ if (ret)
+ return ERR_PTR(ret);
+
+ *offset = i915_ggtt_offset(vma);
+
+ return vma;
+}
+
+void i915_overlay_unpin_fb(struct drm_device *drm,
+ struct i915_vma *vma)
+{
+ i915_vma_unpin(vma);
+}
+
+struct drm_gem_object *
+i915_overlay_obj_lookup(struct drm_device *drm,
+ struct drm_file *file_priv,
+ u32 handle)
+{
+ struct drm_i915_gem_object *bo;
+
+ bo = i915_gem_object_lookup(file_priv, handle);
+ if (!bo)
+ return ERR_PTR(-ENOENT);
+
+ if (i915_gem_object_is_tiled(bo)) {
+ drm_dbg(drm, "buffer used for overlay image can not be tiled\n");
+ i915_gem_object_put(bo);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return intel_bo_to_drm_bo(bo);
+}
+
+static int get_registers(struct i915_overlay *overlay, bool use_phys)
+{
+ struct drm_i915_private *i915 = overlay->i915;
+ struct drm_i915_gem_object *obj;
+ struct i915_vma *vma;
+ int err;
+
+ obj = i915_gem_object_create_stolen(i915, PAGE_SIZE);
+ if (IS_ERR(obj))
+ obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
+ if (IS_ERR(vma)) {
+ err = PTR_ERR(vma);
+ goto err_put_bo;
+ }
+
+ if (use_phys)
+ overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl);
+ else
+ overlay->flip_addr = i915_ggtt_offset(vma);
+ overlay->regs = i915_vma_pin_iomap(vma);
+ i915_vma_unpin(vma);
+
+ if (IS_ERR(overlay->regs)) {
+ err = PTR_ERR(overlay->regs);
+ goto err_put_bo;
+ }
+
+ overlay->reg_bo = obj;
+ return 0;
+
+err_put_bo:
+ i915_gem_object_put(obj);
+ return err;
+}
+
+void __iomem *i915_overlay_setup(struct drm_device *drm,
+ bool needs_physical)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct intel_engine_cs *engine;
+ struct i915_overlay *overlay;
+ int ret;
+
+ engine = to_gt(i915)->engine[RCS0];
+ if (!engine || !engine->kernel_context)
+ return ERR_PTR(-ENOENT);
+
+ overlay = kzalloc_obj(*overlay);
+ if (!overlay)
+ return ERR_PTR(-ENOMEM);
+
+ overlay->i915 = i915;
+ overlay->context = engine->kernel_context;
+
+ i915_active_init(&overlay->last_flip,
+ NULL, i915_overlay_last_flip_retire, 0);
+
+ ret = get_registers(overlay, needs_physical);
+ if (ret) {
+ kfree(overlay);
+ return ERR_PTR(ret);
+ }
+
+ i915->overlay = overlay;
+
+ return overlay->regs;
+}
+
+void i915_overlay_cleanup(struct drm_device *drm)
+{
+ struct drm_i915_private *i915 = to_i915(drm);
+ struct i915_overlay *overlay;
+
+ overlay = fetch_and_zero(&i915->overlay);
+ if (!overlay)
+ return;
+
+ /*
+ * The bo's should be free'd by the generic code already.
+ * Furthermore modesetting teardown happens beforehand so the
+ * hardware should be off already.
+ */
+ drm_WARN_ON(drm, i915_overlay_is_active(drm));
+
+ i915_gem_object_put(overlay->reg_bo);
+ i915_active_fini(&overlay->last_flip);
+
+ kfree(overlay);
+}
diff --git a/drivers/gpu/drm/i915/i915_overlay.h b/drivers/gpu/drm/i915/i915_overlay.h
new file mode 100644
index 000000000000..f553de2abeaa
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_overlay.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef __I915_OVERLAY_H__
+#define __I915_OVERLAY_H__
+
+#include <linux/types.h>
+
+struct drm_device;
+struct drm_file;
+struct drm_gem_object;
+struct i915_vma;
+
+bool i915_overlay_is_active(struct drm_device *drm);
+int i915_overlay_on(struct drm_device *drm,
+ u32 frontbuffer_bits);
+int i915_overlay_continue(struct drm_device *drm,
+ struct i915_vma *vma,
+ bool load_polyphase_filter);
+int i915_overlay_off(struct drm_device *drm);
+int i915_overlay_recover_from_interrupt(struct drm_device *drm);
+int i915_overlay_release_old_vid(struct drm_device *drm);
+
+void i915_overlay_reset(struct drm_device *drm);
+
+struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm,
+ struct drm_gem_object *obj,
+ u32 *offset);
+void i915_overlay_unpin_fb(struct drm_device *drm,
+ struct i915_vma *vma);
+
+struct drm_gem_object *
+i915_overlay_obj_lookup(struct drm_device *drm,
+ struct drm_file *file_priv,
+ u32 handle);
+
+void __iomem *i915_overlay_setup(struct drm_device *drm,
+ bool needs_physical);
+void i915_overlay_cleanup(struct drm_device *drm);
+
+#endif /* __I915_OVERLAY_H__ */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 784d99afde64..5d99b99b0c57 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -338,6 +338,7 @@
#define GEN2_IER _MMIO(0x20a0)
#define GEN2_IIR _MMIO(0x20a4)
#define GEN2_IMR _MMIO(0x20a8)
+#define GEN2_ISR _MMIO(0x20ac)
#define GEN2_IRQ_REGS I915_IRQ_REGS(GEN2_IMR, \
GEN2_IER, \
@@ -777,4 +778,7 @@
#define MTL_MEDIA_GSI_BASE 0x380000
+#define DSPCLK_GATE_D _MMIO(0x6200)
+# define OVRUNIT_CLOCK_GATE_DISABLE (1 << 3)
+
#endif /* _I915_REG_H_ */
--
2.52.0
next prev parent reply other threads:[~2026-02-26 13:39 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-26 10:07 [PATCH v2 00/19] drm/i915/overlay: Convert to parent interface Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 01/19] drm/i915/overlay: Remove GPU hang snapshot stuff Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 02/19] drm/i915/overlay: Track current frontbuffer_bits Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 03/19] drm/i915/overlay: Extract i915_overlay_is_active() Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 04/19] drm/i915/overlay: Remove redundant overlay->active Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 05/19] drm/i915/overlay: Relocate the underrun check Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 06/19] drm/i915/overlay: Introduce i915_overlay_obj_lookup() Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 07/19] drm/i915/overlay: Use struct drm_gem_object as the type Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 08/19] drm/i915/overlay: Extract i915_overlay_reset() Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 09/19] drm/i915/overlay: Extract i915_overlay_setup() Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 10/19] drm/i915/overlay: Extract i915_overlay_cleanup() Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 11/19] drm/i915/overlay: Abstract buffer (un)pinning Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 12/19] drm/i915/overlay: Rename low level i915 specific functions Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 13/19] drm/i915/overlay: Adjust i915 specific interfaces Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 14/19] drm/i915/overlay: Make i830_overlay_clock_gating() i915 specific Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 15/19] drm/i915/overlay: s/dev_priv/i915/ Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 16/19] drm/i915/overlay: Split 'struct intel_overlay' Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 17/19] drm/i915/overlay: Don't use fetch_and_zero() in display code Ville Syrjala
2026-02-26 13:01 ` [PATCH v3 " Ville Syrjala
2026-02-26 10:07 ` [PATCH v2 18/19] drm/i915/overlay: Move i915 specific code into i915_overlay.c Ville Syrjala
2026-02-26 13:38 ` Ville Syrjala [this message]
2026-02-26 10:07 ` [PATCH v2 19/19] drm/i915/overlay: Convert overlay to parent interface Ville Syrjala
2026-02-26 13:01 ` [PATCH v3 " Ville Syrjala
2026-02-26 10:15 ` ✗ CI.checkpatch: warning for drm/i915/overlay: Convert to parent interface (rev2) Patchwork
2026-02-26 10:16 ` ✓ CI.KUnit: success " Patchwork
2026-02-26 11:03 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-02-26 12:27 ` ✗ Xe.CI.FULL: " Patchwork
2026-02-26 13:45 ` ✗ CI.checkpatch: warning for drm/i915/overlay: Convert to parent interface (rev5) Patchwork
2026-02-26 13:47 ` ✓ CI.KUnit: success " Patchwork
2026-02-26 14:42 ` ✓ Xe.CI.BAT: " Patchwork
2026-02-26 16:14 ` ✓ Xe.CI.FULL: " Patchwork
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=20260226133855.17690-1-ville.syrjala@linux.intel.com \
--to=ville.syrjala@linux.intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--cc=jani.nikula@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