From: Ville Syrjälä <[email protected]>

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.

Signed-off-by: Ville Syrjälä <[email protected]>
---
 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 7d726e8c21bf..f731b9a44b3f 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 6a2af1f356ed..bc7e2b3cbda1 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(sizeof(*overlay), GFP_KERNEL);
-       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)
 {
        i915_overlay_cleanup(display->drm);
diff --git a/drivers/gpu/drm/i915/i915_overlay.c 
b/drivers/gpu/drm/i915/i915_overlay.c
new file mode 100644
index 000000000000..e87b0a4f7ef4
--- /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(sizeof(*overlay), GFP_KERNEL);
+       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

Reply via email to