Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/i915/overlay: Move i915 specific code into i915_overlay.c

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>
Link: https://patch.msgid.link/20260226133855.17690-1-ville.syrjala@linux.intel.com

+550 -490
+1
drivers/gpu/drm/i915/Makefile
··· 81 81 i915_dsb_buffer.o \ 82 82 i915_hdcp_gsc.o \ 83 83 i915_initial_plane.o \ 84 + i915_overlay.o \ 84 85 i915_panic.o 85 86 86 87 # "Graphics Technology" (aka we talk to the gpu)
-2
drivers/gpu/drm/i915/display/intel_display_regs.h
··· 117 117 #define VLV_ERROR_PAGE_TABLE (1 << 4) 118 118 #define VLV_ERROR_CLAIM (1 << 0) 119 119 120 - #define GEN2_ISR _MMIO(0x20ac) 121 - 122 120 #define VLV_ERROR_REGS I915_ERROR_REGS(VLV_EMR, VLV_EIR) 123 121 124 122 #define _MBUS_ABOX0_CTL 0x45038
+2 -488
drivers/gpu/drm/i915/display/intel_overlay.c
··· 27 27 */ 28 28 29 29 #include <drm/drm_fourcc.h> 30 + #include <drm/drm_gem.h> 30 31 #include <drm/drm_print.h> 31 - #include <drm/intel/intel_gmd_interrupt_regs.h> 32 32 33 - #include "gem/i915_gem_internal.h" 34 - #include "gem/i915_gem_object_frontbuffer.h" 35 - #include "gem/i915_gem_pm.h" 36 - 37 - #include "gt/intel_gpu_commands.h" 38 - #include "gt/intel_ring.h" 39 - 40 - #include "i915_drv.h" 33 + #include "i915_overlay.h" 41 34 #include "intel_color_regs.h" 42 35 #include "intel_de.h" 43 36 #include "intel_display_regs.h" 44 37 #include "intel_display_types.h" 45 38 #include "intel_frontbuffer.h" 46 39 #include "intel_overlay.h" 47 - #include "intel_pci_config.h" 48 40 #include "intel_pfit_regs.h" 49 41 50 42 /* Limits for overlay size. According to intel doc, the real limits are: ··· 113 121 #define RGB8I_TO_COLORKEY(c) \ 114 122 ((((c) & 0xff) << 16) | (((c) & 0xff) << 8) | (((c) & 0xff) << 0)) 115 123 116 - /* overlay flip addr flag */ 117 - #define OFC_UPDATE 0x1 118 - 119 124 /* polyphase filter coefficients */ 120 125 #define N_HORIZ_Y_TAPS 5 121 126 #define N_VERT_Y_TAPS 3 ··· 176 187 u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; 177 188 }; 178 189 179 - struct i915_overlay { 180 - struct drm_i915_private *i915; 181 - struct intel_context *context; 182 - struct i915_vma *vma; 183 - struct i915_vma *old_vma; 184 - struct intel_frontbuffer *frontbuffer; 185 - /* register access */ 186 - struct drm_i915_gem_object *reg_bo; 187 - void __iomem *regs; 188 - u32 flip_addr; 189 - u32 frontbuffer_bits; 190 - /* flip handling */ 191 - struct i915_active last_flip; 192 - void (*flip_complete)(struct i915_overlay *overlay); 193 - }; 194 - 195 190 struct intel_overlay { 196 191 struct intel_display *display; 197 192 struct intel_crtc *crtc; ··· 187 214 u32 old_xscale, old_yscale; 188 215 struct overlay_registers __iomem *regs; 189 216 }; 190 - 191 - static void i830_overlay_clock_gating(struct drm_i915_private *i915, 192 - bool enable) 193 - { 194 - struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 195 - u8 val; 196 - 197 - /* 198 - * WA_OVERLAY_CLKGATE:alm 199 - * 200 - * FIXME should perhaps be done on the display side? 201 - */ 202 - if (enable) 203 - intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, 0); 204 - else 205 - intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); 206 - 207 - /* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */ 208 - pci_bus_read_config_byte(pdev->bus, 209 - PCI_DEVFN(0, 0), I830_CLOCK_GATE, &val); 210 - if (enable) 211 - val &= ~I830_L2_CACHE_CLOCK_GATE_DISABLE; 212 - else 213 - val |= I830_L2_CACHE_CLOCK_GATE_DISABLE; 214 - pci_bus_write_config_byte(pdev->bus, 215 - PCI_DEVFN(0, 0), I830_CLOCK_GATE, val); 216 - } 217 - 218 - static struct i915_request * 219 - alloc_request(struct i915_overlay *overlay, void (*fn)(struct i915_overlay *)) 220 - { 221 - struct i915_request *rq; 222 - int err; 223 - 224 - overlay->flip_complete = fn; 225 - 226 - rq = i915_request_create(overlay->context); 227 - if (IS_ERR(rq)) 228 - return rq; 229 - 230 - err = i915_active_add_request(&overlay->last_flip, rq); 231 - if (err) { 232 - i915_request_add(rq); 233 - return ERR_PTR(err); 234 - } 235 - 236 - return rq; 237 - } 238 - 239 - static bool i915_overlay_is_active(struct drm_device *drm) 240 - { 241 - struct drm_i915_private *i915 = to_i915(drm); 242 - struct i915_overlay *overlay = i915->overlay; 243 - 244 - return overlay->frontbuffer_bits; 245 - } 246 - 247 - /* overlay needs to be disable in OCMD reg */ 248 - static int i915_overlay_on(struct drm_device *drm, 249 - u32 frontbuffer_bits) 250 - { 251 - struct drm_i915_private *i915 = to_i915(drm); 252 - struct i915_overlay *overlay = i915->overlay; 253 - struct i915_request *rq; 254 - u32 *cs; 255 - 256 - drm_WARN_ON(drm, i915_overlay_is_active(drm)); 257 - 258 - rq = alloc_request(overlay, NULL); 259 - if (IS_ERR(rq)) 260 - return PTR_ERR(rq); 261 - 262 - cs = intel_ring_begin(rq, 4); 263 - if (IS_ERR(cs)) { 264 - i915_request_add(rq); 265 - return PTR_ERR(cs); 266 - } 267 - 268 - overlay->frontbuffer_bits = frontbuffer_bits; 269 - 270 - if (IS_I830(i915)) 271 - i830_overlay_clock_gating(i915, false); 272 - 273 - *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_ON; 274 - *cs++ = overlay->flip_addr | OFC_UPDATE; 275 - *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 276 - *cs++ = MI_NOOP; 277 - intel_ring_advance(rq, cs); 278 - 279 - i915_request_add(rq); 280 - 281 - return i915_active_wait(&overlay->last_flip); 282 - } 283 - 284 - static void i915_overlay_flip_prepare(struct i915_overlay *overlay, 285 - struct i915_vma *vma) 286 - { 287 - struct drm_i915_private *i915 = overlay->i915; 288 - struct intel_frontbuffer *frontbuffer = NULL; 289 - 290 - drm_WARN_ON(&i915->drm, overlay->old_vma); 291 - 292 - if (vma) 293 - frontbuffer = intel_frontbuffer_get(intel_bo_to_drm_bo(vma->obj)); 294 - 295 - intel_frontbuffer_track(overlay->frontbuffer, frontbuffer, 296 - overlay->frontbuffer_bits); 297 - 298 - if (overlay->frontbuffer) 299 - intel_frontbuffer_put(overlay->frontbuffer); 300 - overlay->frontbuffer = frontbuffer; 301 - 302 - overlay->old_vma = overlay->vma; 303 - if (vma) 304 - overlay->vma = i915_vma_get(vma); 305 - else 306 - overlay->vma = NULL; 307 - } 308 - 309 - /* overlay needs to be enabled in OCMD reg */ 310 - static int i915_overlay_continue(struct drm_device *drm, 311 - struct i915_vma *vma, 312 - bool load_polyphase_filter) 313 - { 314 - struct drm_i915_private *i915 = to_i915(drm); 315 - struct i915_overlay *overlay = i915->overlay; 316 - struct i915_request *rq; 317 - u32 flip_addr = overlay->flip_addr; 318 - u32 *cs; 319 - 320 - drm_WARN_ON(drm, !i915_overlay_is_active(drm)); 321 - 322 - if (load_polyphase_filter) 323 - flip_addr |= OFC_UPDATE; 324 - 325 - rq = alloc_request(overlay, NULL); 326 - if (IS_ERR(rq)) 327 - return PTR_ERR(rq); 328 - 329 - cs = intel_ring_begin(rq, 2); 330 - if (IS_ERR(cs)) { 331 - i915_request_add(rq); 332 - return PTR_ERR(cs); 333 - } 334 - 335 - *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE; 336 - *cs++ = flip_addr; 337 - intel_ring_advance(rq, cs); 338 - 339 - i915_overlay_flip_prepare(overlay, vma); 340 - i915_request_add(rq); 341 - 342 - return 0; 343 - } 344 - 345 - static void i915_overlay_release_old_vma(struct i915_overlay *overlay) 346 - { 347 - struct drm_i915_private *i915 = overlay->i915; 348 - struct intel_display *display = i915->display; 349 - struct i915_vma *vma; 350 - 351 - vma = fetch_and_zero(&overlay->old_vma); 352 - if (drm_WARN_ON(&i915->drm, !vma)) 353 - return; 354 - 355 - intel_frontbuffer_flip(display, overlay->frontbuffer_bits); 356 - 357 - i915_vma_unpin(vma); 358 - i915_vma_put(vma); 359 - } 360 - 361 - static void i915_overlay_release_old_vid_tail(struct i915_overlay *overlay) 362 - { 363 - i915_overlay_release_old_vma(overlay); 364 - } 365 - 366 - static void i915_overlay_off_tail(struct i915_overlay *overlay) 367 - { 368 - struct drm_i915_private *i915 = overlay->i915; 369 - 370 - i915_overlay_release_old_vma(overlay); 371 - 372 - overlay->frontbuffer_bits = 0; 373 - 374 - if (IS_I830(i915)) 375 - i830_overlay_clock_gating(i915, true); 376 - } 377 - 378 - static void i915_overlay_last_flip_retire(struct i915_active *active) 379 - { 380 - struct i915_overlay *overlay = 381 - container_of(active, typeof(*overlay), last_flip); 382 - 383 - if (overlay->flip_complete) 384 - overlay->flip_complete(overlay); 385 - } 386 - 387 - /* overlay needs to be disabled in OCMD reg */ 388 - static int i915_overlay_off(struct drm_device *drm) 389 - { 390 - struct drm_i915_private *i915 = to_i915(drm); 391 - struct i915_overlay *overlay = i915->overlay; 392 - struct i915_request *rq; 393 - u32 *cs, flip_addr = overlay->flip_addr; 394 - 395 - drm_WARN_ON(drm, !i915_overlay_is_active(drm)); 396 - 397 - /* 398 - * According to intel docs the overlay hw may hang (when switching 399 - * off) without loading the filter coeffs. It is however unclear whether 400 - * this applies to the disabling of the overlay or to the switching off 401 - * of the hw. Do it in both cases. 402 - */ 403 - flip_addr |= OFC_UPDATE; 404 - 405 - rq = alloc_request(overlay, i915_overlay_off_tail); 406 - if (IS_ERR(rq)) 407 - return PTR_ERR(rq); 408 - 409 - cs = intel_ring_begin(rq, 6); 410 - if (IS_ERR(cs)) { 411 - i915_request_add(rq); 412 - return PTR_ERR(cs); 413 - } 414 - 415 - /* wait for overlay to go idle */ 416 - *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE; 417 - *cs++ = flip_addr; 418 - *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 419 - 420 - /* turn overlay off */ 421 - *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_OFF; 422 - *cs++ = flip_addr; 423 - *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 424 - 425 - intel_ring_advance(rq, cs); 426 - 427 - i915_overlay_flip_prepare(overlay, NULL); 428 - i915_request_add(rq); 429 - 430 - return i915_active_wait(&overlay->last_flip); 431 - } 432 - 433 - /* 434 - * Recover from an interruption due to a signal. 435 - * We have to be careful not to repeat work forever an make forward progress. 436 - */ 437 - static int i915_overlay_recover_from_interrupt(struct drm_device *drm) 438 - { 439 - struct drm_i915_private *i915 = to_i915(drm); 440 - struct i915_overlay *overlay = i915->overlay; 441 - 442 - return i915_active_wait(&overlay->last_flip); 443 - } 444 - 445 - /* 446 - * Wait for pending overlay flip and release old frame. 447 - * Needs to be called before the overlay register are changed 448 - * via intel_overlay_(un)map_regs. 449 - */ 450 - static int i915_overlay_release_old_vid(struct drm_device *drm) 451 - { 452 - struct drm_i915_private *i915 = to_i915(drm); 453 - struct i915_overlay *overlay = i915->overlay; 454 - struct i915_request *rq; 455 - u32 *cs; 456 - 457 - /* 458 - * Only wait if there is actually an old frame to release to 459 - * guarantee forward progress. 460 - */ 461 - if (!overlay->old_vma) 462 - return 0; 463 - 464 - if (!(intel_uncore_read(&i915->uncore, GEN2_ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) { 465 - i915_overlay_release_old_vid_tail(overlay); 466 - return 0; 467 - } 468 - 469 - rq = alloc_request(overlay, i915_overlay_release_old_vid_tail); 470 - if (IS_ERR(rq)) 471 - return PTR_ERR(rq); 472 - 473 - cs = intel_ring_begin(rq, 2); 474 - if (IS_ERR(cs)) { 475 - i915_request_add(rq); 476 - return PTR_ERR(cs); 477 - } 478 - 479 - *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 480 - *cs++ = MI_NOOP; 481 - intel_ring_advance(rq, cs); 482 - 483 - i915_request_add(rq); 484 - 485 - return i915_active_wait(&overlay->last_flip); 486 - } 487 - 488 - static void i915_overlay_reset(struct drm_device *drm) 489 - { 490 - struct drm_i915_private *i915 = to_i915(drm); 491 - struct i915_overlay *overlay = i915->overlay; 492 - 493 - if (!overlay) 494 - return; 495 - 496 - overlay->frontbuffer_bits = 0; 497 - } 498 217 499 218 void intel_overlay_reset(struct intel_display *display) 500 219 { ··· 459 794 } 460 795 461 796 return cmd; 462 - } 463 - 464 - static struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm, 465 - struct drm_gem_object *obj, 466 - u32 *offset) 467 - { 468 - struct drm_i915_gem_object *new_bo = to_intel_bo(obj); 469 - struct i915_gem_ww_ctx ww; 470 - struct i915_vma *vma; 471 - int ret; 472 - 473 - i915_gem_ww_ctx_init(&ww, true); 474 - retry: 475 - ret = i915_gem_object_lock(new_bo, &ww); 476 - if (!ret) { 477 - vma = i915_gem_object_pin_to_display_plane(new_bo, &ww, 0, 0, 478 - NULL, PIN_MAPPABLE); 479 - ret = PTR_ERR_OR_ZERO(vma); 480 - } 481 - if (ret == -EDEADLK) { 482 - ret = i915_gem_ww_ctx_backoff(&ww); 483 - if (!ret) 484 - goto retry; 485 - } 486 - i915_gem_ww_ctx_fini(&ww); 487 - if (ret) 488 - return ERR_PTR(ret); 489 - 490 - *offset = i915_ggtt_offset(vma); 491 - 492 - return vma; 493 - } 494 - 495 - static void i915_overlay_unpin_fb(struct drm_device *drm, 496 - struct i915_vma *vma) 497 - { 498 - i915_vma_unpin(vma); 499 797 } 500 798 501 799 static int intel_overlay_do_put_image(struct intel_overlay *overlay, ··· 792 1164 return 0; 793 1165 } 794 1166 795 - static struct drm_gem_object * 796 - i915_overlay_obj_lookup(struct drm_device *drm, 797 - struct drm_file *file_priv, 798 - u32 handle) 799 - { 800 - struct drm_i915_gem_object *bo; 801 - 802 - bo = i915_gem_object_lookup(file_priv, handle); 803 - if (!bo) 804 - return ERR_PTR(-ENOENT); 805 - 806 - if (i915_gem_object_is_tiled(bo)) { 807 - drm_dbg(drm, "buffer used for overlay image can not be tiled\n"); 808 - i915_gem_object_put(bo); 809 - return ERR_PTR(-EINVAL); 810 - } 811 - 812 - return intel_bo_to_drm_bo(bo); 813 - } 814 - 815 1167 int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, 816 1168 struct drm_file *file_priv) 817 1169 { ··· 1024 1416 return ret; 1025 1417 } 1026 1418 1027 - static int get_registers(struct i915_overlay *overlay, bool use_phys) 1028 - { 1029 - struct drm_i915_private *i915 = overlay->i915; 1030 - struct drm_i915_gem_object *obj; 1031 - struct i915_vma *vma; 1032 - int err; 1033 - 1034 - obj = i915_gem_object_create_stolen(i915, PAGE_SIZE); 1035 - if (IS_ERR(obj)) 1036 - obj = i915_gem_object_create_internal(i915, PAGE_SIZE); 1037 - if (IS_ERR(obj)) 1038 - return PTR_ERR(obj); 1039 - 1040 - vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE); 1041 - if (IS_ERR(vma)) { 1042 - err = PTR_ERR(vma); 1043 - goto err_put_bo; 1044 - } 1045 - 1046 - if (use_phys) 1047 - overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl); 1048 - else 1049 - overlay->flip_addr = i915_ggtt_offset(vma); 1050 - overlay->regs = i915_vma_pin_iomap(vma); 1051 - i915_vma_unpin(vma); 1052 - 1053 - if (IS_ERR(overlay->regs)) { 1054 - err = PTR_ERR(overlay->regs); 1055 - goto err_put_bo; 1056 - } 1057 - 1058 - overlay->reg_bo = obj; 1059 - return 0; 1060 - 1061 - err_put_bo: 1062 - i915_gem_object_put(obj); 1063 - return err; 1064 - } 1065 - 1066 - static void __iomem *i915_overlay_setup(struct drm_device *drm, 1067 - bool needs_physical) 1068 - { 1069 - struct drm_i915_private *i915 = to_i915(drm); 1070 - struct intel_engine_cs *engine; 1071 - struct i915_overlay *overlay; 1072 - int ret; 1073 - 1074 - engine = to_gt(i915)->engine[RCS0]; 1075 - if (!engine || !engine->kernel_context) 1076 - return ERR_PTR(-ENOENT); 1077 - 1078 - overlay = kzalloc_obj(*overlay); 1079 - if (!overlay) 1080 - return ERR_PTR(-ENOMEM); 1081 - 1082 - overlay->i915 = i915; 1083 - overlay->context = engine->kernel_context; 1084 - 1085 - i915_active_init(&overlay->last_flip, 1086 - NULL, i915_overlay_last_flip_retire, 0); 1087 - 1088 - ret = get_registers(overlay, needs_physical); 1089 - if (ret) { 1090 - kfree(overlay); 1091 - return ERR_PTR(ret); 1092 - } 1093 - 1094 - i915->overlay = overlay; 1095 - 1096 - return overlay->regs; 1097 - } 1098 - 1099 1419 void intel_overlay_setup(struct intel_display *display) 1100 1420 { 1101 1421 struct intel_overlay *overlay; ··· 1064 1528 bool intel_overlay_available(struct intel_display *display) 1065 1529 { 1066 1530 return display->overlay; 1067 - } 1068 - 1069 - static void i915_overlay_cleanup(struct drm_device *drm) 1070 - { 1071 - struct drm_i915_private *i915 = to_i915(drm); 1072 - struct i915_overlay *overlay; 1073 - 1074 - overlay = fetch_and_zero(&i915->overlay); 1075 - if (!overlay) 1076 - return; 1077 - 1078 - /* 1079 - * The bo's should be free'd by the generic code already. 1080 - * Furthermore modesetting teardown happens beforehand so the 1081 - * hardware should be off already. 1082 - */ 1083 - drm_WARN_ON(drm, i915_overlay_is_active(drm)); 1084 - 1085 - i915_gem_object_put(overlay->reg_bo); 1086 - i915_active_fini(&overlay->last_flip); 1087 - 1088 - kfree(overlay); 1089 1531 } 1090 1532 1091 1533 void intel_overlay_cleanup(struct intel_display *display)
+500
drivers/gpu/drm/i915/i915_overlay.c
··· 1 + // SPDX-License-Identifier: MIT 2 + /* 3 + * Copyright 2026, Intel Corporation. 4 + */ 5 + 6 + #include <drm/drm_print.h> 7 + 8 + #include <drm/intel/intel_gmd_interrupt_regs.h> 9 + 10 + #include "gem/i915_gem_internal.h" 11 + #include "gem/i915_gem_object_frontbuffer.h" 12 + #include "gem/i915_gem_pm.h" 13 + 14 + #include "gt/intel_gpu_commands.h" 15 + #include "gt/intel_ring.h" 16 + 17 + #include "i915_drv.h" 18 + #include "i915_overlay.h" 19 + #include "i915_reg.h" 20 + #include "intel_pci_config.h" 21 + 22 + #include "display/intel_frontbuffer.h" 23 + 24 + /* overlay flip addr flag */ 25 + #define OFC_UPDATE 0x1 26 + 27 + struct i915_overlay { 28 + struct drm_i915_private *i915; 29 + struct intel_context *context; 30 + struct i915_vma *vma; 31 + struct i915_vma *old_vma; 32 + struct intel_frontbuffer *frontbuffer; 33 + /* register access */ 34 + struct drm_i915_gem_object *reg_bo; 35 + void __iomem *regs; 36 + u32 flip_addr; 37 + u32 frontbuffer_bits; 38 + /* flip handling */ 39 + struct i915_active last_flip; 40 + void (*flip_complete)(struct i915_overlay *overlay); 41 + }; 42 + 43 + static void i830_overlay_clock_gating(struct drm_i915_private *i915, 44 + bool enable) 45 + { 46 + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 47 + u8 val; 48 + 49 + /* 50 + * WA_OVERLAY_CLKGATE:alm 51 + * 52 + * FIXME should perhaps be done on the display side? 53 + */ 54 + if (enable) 55 + intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, 0); 56 + else 57 + intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); 58 + 59 + /* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */ 60 + pci_bus_read_config_byte(pdev->bus, 61 + PCI_DEVFN(0, 0), I830_CLOCK_GATE, &val); 62 + if (enable) 63 + val &= ~I830_L2_CACHE_CLOCK_GATE_DISABLE; 64 + else 65 + val |= I830_L2_CACHE_CLOCK_GATE_DISABLE; 66 + pci_bus_write_config_byte(pdev->bus, 67 + PCI_DEVFN(0, 0), I830_CLOCK_GATE, val); 68 + } 69 + 70 + static struct i915_request * 71 + alloc_request(struct i915_overlay *overlay, void (*fn)(struct i915_overlay *)) 72 + { 73 + struct i915_request *rq; 74 + int err; 75 + 76 + overlay->flip_complete = fn; 77 + 78 + rq = i915_request_create(overlay->context); 79 + if (IS_ERR(rq)) 80 + return rq; 81 + 82 + err = i915_active_add_request(&overlay->last_flip, rq); 83 + if (err) { 84 + i915_request_add(rq); 85 + return ERR_PTR(err); 86 + } 87 + 88 + return rq; 89 + } 90 + 91 + bool i915_overlay_is_active(struct drm_device *drm) 92 + { 93 + struct drm_i915_private *i915 = to_i915(drm); 94 + struct i915_overlay *overlay = i915->overlay; 95 + 96 + return overlay->frontbuffer_bits; 97 + } 98 + 99 + /* overlay needs to be disable in OCMD reg */ 100 + int i915_overlay_on(struct drm_device *drm, 101 + u32 frontbuffer_bits) 102 + { 103 + struct drm_i915_private *i915 = to_i915(drm); 104 + struct i915_overlay *overlay = i915->overlay; 105 + struct i915_request *rq; 106 + u32 *cs; 107 + 108 + drm_WARN_ON(drm, i915_overlay_is_active(drm)); 109 + 110 + rq = alloc_request(overlay, NULL); 111 + if (IS_ERR(rq)) 112 + return PTR_ERR(rq); 113 + 114 + cs = intel_ring_begin(rq, 4); 115 + if (IS_ERR(cs)) { 116 + i915_request_add(rq); 117 + return PTR_ERR(cs); 118 + } 119 + 120 + overlay->frontbuffer_bits = frontbuffer_bits; 121 + 122 + if (IS_I830(i915)) 123 + i830_overlay_clock_gating(i915, false); 124 + 125 + *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_ON; 126 + *cs++ = overlay->flip_addr | OFC_UPDATE; 127 + *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 128 + *cs++ = MI_NOOP; 129 + intel_ring_advance(rq, cs); 130 + 131 + i915_request_add(rq); 132 + 133 + return i915_active_wait(&overlay->last_flip); 134 + } 135 + 136 + static void i915_overlay_flip_prepare(struct i915_overlay *overlay, 137 + struct i915_vma *vma) 138 + { 139 + struct drm_i915_private *i915 = overlay->i915; 140 + struct intel_frontbuffer *frontbuffer = NULL; 141 + 142 + drm_WARN_ON(&i915->drm, overlay->old_vma); 143 + 144 + if (vma) 145 + frontbuffer = intel_frontbuffer_get(intel_bo_to_drm_bo(vma->obj)); 146 + 147 + intel_frontbuffer_track(overlay->frontbuffer, frontbuffer, 148 + overlay->frontbuffer_bits); 149 + 150 + if (overlay->frontbuffer) 151 + intel_frontbuffer_put(overlay->frontbuffer); 152 + overlay->frontbuffer = frontbuffer; 153 + 154 + overlay->old_vma = overlay->vma; 155 + if (vma) 156 + overlay->vma = i915_vma_get(vma); 157 + else 158 + overlay->vma = NULL; 159 + } 160 + 161 + /* overlay needs to be enabled in OCMD reg */ 162 + int i915_overlay_continue(struct drm_device *drm, 163 + struct i915_vma *vma, 164 + bool load_polyphase_filter) 165 + { 166 + struct drm_i915_private *i915 = to_i915(drm); 167 + struct i915_overlay *overlay = i915->overlay; 168 + struct i915_request *rq; 169 + u32 flip_addr = overlay->flip_addr; 170 + u32 *cs; 171 + 172 + drm_WARN_ON(drm, !i915_overlay_is_active(drm)); 173 + 174 + if (load_polyphase_filter) 175 + flip_addr |= OFC_UPDATE; 176 + 177 + rq = alloc_request(overlay, NULL); 178 + if (IS_ERR(rq)) 179 + return PTR_ERR(rq); 180 + 181 + cs = intel_ring_begin(rq, 2); 182 + if (IS_ERR(cs)) { 183 + i915_request_add(rq); 184 + return PTR_ERR(cs); 185 + } 186 + 187 + *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE; 188 + *cs++ = flip_addr; 189 + intel_ring_advance(rq, cs); 190 + 191 + i915_overlay_flip_prepare(overlay, vma); 192 + i915_request_add(rq); 193 + 194 + return 0; 195 + } 196 + 197 + static void i915_overlay_release_old_vma(struct i915_overlay *overlay) 198 + { 199 + struct drm_i915_private *i915 = overlay->i915; 200 + struct intel_display *display = i915->display; 201 + struct i915_vma *vma; 202 + 203 + vma = fetch_and_zero(&overlay->old_vma); 204 + if (drm_WARN_ON(&i915->drm, !vma)) 205 + return; 206 + 207 + intel_frontbuffer_flip(display, overlay->frontbuffer_bits); 208 + 209 + i915_vma_unpin(vma); 210 + i915_vma_put(vma); 211 + } 212 + 213 + static void i915_overlay_release_old_vid_tail(struct i915_overlay *overlay) 214 + { 215 + i915_overlay_release_old_vma(overlay); 216 + } 217 + 218 + static void i915_overlay_off_tail(struct i915_overlay *overlay) 219 + { 220 + struct drm_i915_private *i915 = overlay->i915; 221 + 222 + i915_overlay_release_old_vma(overlay); 223 + 224 + overlay->frontbuffer_bits = 0; 225 + 226 + if (IS_I830(i915)) 227 + i830_overlay_clock_gating(i915, true); 228 + } 229 + 230 + static void i915_overlay_last_flip_retire(struct i915_active *active) 231 + { 232 + struct i915_overlay *overlay = 233 + container_of(active, typeof(*overlay), last_flip); 234 + 235 + if (overlay->flip_complete) 236 + overlay->flip_complete(overlay); 237 + } 238 + 239 + /* overlay needs to be disabled in OCMD reg */ 240 + int i915_overlay_off(struct drm_device *drm) 241 + { 242 + struct drm_i915_private *i915 = to_i915(drm); 243 + struct i915_overlay *overlay = i915->overlay; 244 + struct i915_request *rq; 245 + u32 *cs, flip_addr = overlay->flip_addr; 246 + 247 + drm_WARN_ON(drm, !i915_overlay_is_active(drm)); 248 + 249 + /* 250 + * According to intel docs the overlay hw may hang (when switching 251 + * off) without loading the filter coeffs. It is however unclear whether 252 + * this applies to the disabling of the overlay or to the switching off 253 + * of the hw. Do it in both cases. 254 + */ 255 + flip_addr |= OFC_UPDATE; 256 + 257 + rq = alloc_request(overlay, i915_overlay_off_tail); 258 + if (IS_ERR(rq)) 259 + return PTR_ERR(rq); 260 + 261 + cs = intel_ring_begin(rq, 6); 262 + if (IS_ERR(cs)) { 263 + i915_request_add(rq); 264 + return PTR_ERR(cs); 265 + } 266 + 267 + /* wait for overlay to go idle */ 268 + *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE; 269 + *cs++ = flip_addr; 270 + *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 271 + 272 + /* turn overlay off */ 273 + *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_OFF; 274 + *cs++ = flip_addr; 275 + *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 276 + 277 + intel_ring_advance(rq, cs); 278 + 279 + i915_overlay_flip_prepare(overlay, NULL); 280 + i915_request_add(rq); 281 + 282 + return i915_active_wait(&overlay->last_flip); 283 + } 284 + 285 + /* 286 + * Recover from an interruption due to a signal. 287 + * We have to be careful not to repeat work forever an make forward progress. 288 + */ 289 + int i915_overlay_recover_from_interrupt(struct drm_device *drm) 290 + { 291 + struct drm_i915_private *i915 = to_i915(drm); 292 + struct i915_overlay *overlay = i915->overlay; 293 + 294 + return i915_active_wait(&overlay->last_flip); 295 + } 296 + 297 + /* 298 + * Wait for pending overlay flip and release old frame. 299 + * Needs to be called before the overlay register are changed 300 + * via intel_overlay_(un)map_regs. 301 + */ 302 + int i915_overlay_release_old_vid(struct drm_device *drm) 303 + { 304 + struct drm_i915_private *i915 = to_i915(drm); 305 + struct i915_overlay *overlay = i915->overlay; 306 + struct i915_request *rq; 307 + u32 *cs; 308 + 309 + /* 310 + * Only wait if there is actually an old frame to release to 311 + * guarantee forward progress. 312 + */ 313 + if (!overlay->old_vma) 314 + return 0; 315 + 316 + if (!(intel_uncore_read(&i915->uncore, GEN2_ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) { 317 + i915_overlay_release_old_vid_tail(overlay); 318 + return 0; 319 + } 320 + 321 + rq = alloc_request(overlay, i915_overlay_release_old_vid_tail); 322 + if (IS_ERR(rq)) 323 + return PTR_ERR(rq); 324 + 325 + cs = intel_ring_begin(rq, 2); 326 + if (IS_ERR(cs)) { 327 + i915_request_add(rq); 328 + return PTR_ERR(cs); 329 + } 330 + 331 + *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP; 332 + *cs++ = MI_NOOP; 333 + intel_ring_advance(rq, cs); 334 + 335 + i915_request_add(rq); 336 + 337 + return i915_active_wait(&overlay->last_flip); 338 + } 339 + 340 + void i915_overlay_reset(struct drm_device *drm) 341 + { 342 + struct drm_i915_private *i915 = to_i915(drm); 343 + struct i915_overlay *overlay = i915->overlay; 344 + 345 + if (!overlay) 346 + return; 347 + 348 + overlay->frontbuffer_bits = 0; 349 + } 350 + 351 + struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm, 352 + struct drm_gem_object *obj, 353 + u32 *offset) 354 + { 355 + struct drm_i915_gem_object *new_bo = to_intel_bo(obj); 356 + struct i915_gem_ww_ctx ww; 357 + struct i915_vma *vma; 358 + int ret; 359 + 360 + i915_gem_ww_ctx_init(&ww, true); 361 + retry: 362 + ret = i915_gem_object_lock(new_bo, &ww); 363 + if (!ret) { 364 + vma = i915_gem_object_pin_to_display_plane(new_bo, &ww, 0, 0, 365 + NULL, PIN_MAPPABLE); 366 + ret = PTR_ERR_OR_ZERO(vma); 367 + } 368 + if (ret == -EDEADLK) { 369 + ret = i915_gem_ww_ctx_backoff(&ww); 370 + if (!ret) 371 + goto retry; 372 + } 373 + i915_gem_ww_ctx_fini(&ww); 374 + if (ret) 375 + return ERR_PTR(ret); 376 + 377 + *offset = i915_ggtt_offset(vma); 378 + 379 + return vma; 380 + } 381 + 382 + void i915_overlay_unpin_fb(struct drm_device *drm, 383 + struct i915_vma *vma) 384 + { 385 + i915_vma_unpin(vma); 386 + } 387 + 388 + struct drm_gem_object * 389 + i915_overlay_obj_lookup(struct drm_device *drm, 390 + struct drm_file *file_priv, 391 + u32 handle) 392 + { 393 + struct drm_i915_gem_object *bo; 394 + 395 + bo = i915_gem_object_lookup(file_priv, handle); 396 + if (!bo) 397 + return ERR_PTR(-ENOENT); 398 + 399 + if (i915_gem_object_is_tiled(bo)) { 400 + drm_dbg(drm, "buffer used for overlay image can not be tiled\n"); 401 + i915_gem_object_put(bo); 402 + return ERR_PTR(-EINVAL); 403 + } 404 + 405 + return intel_bo_to_drm_bo(bo); 406 + } 407 + 408 + static int get_registers(struct i915_overlay *overlay, bool use_phys) 409 + { 410 + struct drm_i915_private *i915 = overlay->i915; 411 + struct drm_i915_gem_object *obj; 412 + struct i915_vma *vma; 413 + int err; 414 + 415 + obj = i915_gem_object_create_stolen(i915, PAGE_SIZE); 416 + if (IS_ERR(obj)) 417 + obj = i915_gem_object_create_internal(i915, PAGE_SIZE); 418 + if (IS_ERR(obj)) 419 + return PTR_ERR(obj); 420 + 421 + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE); 422 + if (IS_ERR(vma)) { 423 + err = PTR_ERR(vma); 424 + goto err_put_bo; 425 + } 426 + 427 + if (use_phys) 428 + overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl); 429 + else 430 + overlay->flip_addr = i915_ggtt_offset(vma); 431 + overlay->regs = i915_vma_pin_iomap(vma); 432 + i915_vma_unpin(vma); 433 + 434 + if (IS_ERR(overlay->regs)) { 435 + err = PTR_ERR(overlay->regs); 436 + goto err_put_bo; 437 + } 438 + 439 + overlay->reg_bo = obj; 440 + return 0; 441 + 442 + err_put_bo: 443 + i915_gem_object_put(obj); 444 + return err; 445 + } 446 + 447 + void __iomem *i915_overlay_setup(struct drm_device *drm, 448 + bool needs_physical) 449 + { 450 + struct drm_i915_private *i915 = to_i915(drm); 451 + struct intel_engine_cs *engine; 452 + struct i915_overlay *overlay; 453 + int ret; 454 + 455 + engine = to_gt(i915)->engine[RCS0]; 456 + if (!engine || !engine->kernel_context) 457 + return ERR_PTR(-ENOENT); 458 + 459 + overlay = kzalloc_obj(*overlay); 460 + if (!overlay) 461 + return ERR_PTR(-ENOMEM); 462 + 463 + overlay->i915 = i915; 464 + overlay->context = engine->kernel_context; 465 + 466 + i915_active_init(&overlay->last_flip, 467 + NULL, i915_overlay_last_flip_retire, 0); 468 + 469 + ret = get_registers(overlay, needs_physical); 470 + if (ret) { 471 + kfree(overlay); 472 + return ERR_PTR(ret); 473 + } 474 + 475 + i915->overlay = overlay; 476 + 477 + return overlay->regs; 478 + } 479 + 480 + void i915_overlay_cleanup(struct drm_device *drm) 481 + { 482 + struct drm_i915_private *i915 = to_i915(drm); 483 + struct i915_overlay *overlay; 484 + 485 + overlay = fetch_and_zero(&i915->overlay); 486 + if (!overlay) 487 + return; 488 + 489 + /* 490 + * The bo's should be free'd by the generic code already. 491 + * Furthermore modesetting teardown happens beforehand so the 492 + * hardware should be off already. 493 + */ 494 + drm_WARN_ON(drm, i915_overlay_is_active(drm)); 495 + 496 + i915_gem_object_put(overlay->reg_bo); 497 + i915_active_fini(&overlay->last_flip); 498 + 499 + kfree(overlay); 500 + }
+43
drivers/gpu/drm/i915/i915_overlay.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + /* 3 + * Copyright © 2026 Intel Corporation 4 + */ 5 + 6 + #ifndef __I915_OVERLAY_H__ 7 + #define __I915_OVERLAY_H__ 8 + 9 + #include <linux/types.h> 10 + 11 + struct drm_device; 12 + struct drm_file; 13 + struct drm_gem_object; 14 + struct i915_vma; 15 + 16 + bool i915_overlay_is_active(struct drm_device *drm); 17 + int i915_overlay_on(struct drm_device *drm, 18 + u32 frontbuffer_bits); 19 + int i915_overlay_continue(struct drm_device *drm, 20 + struct i915_vma *vma, 21 + bool load_polyphase_filter); 22 + int i915_overlay_off(struct drm_device *drm); 23 + int i915_overlay_recover_from_interrupt(struct drm_device *drm); 24 + int i915_overlay_release_old_vid(struct drm_device *drm); 25 + 26 + void i915_overlay_reset(struct drm_device *drm); 27 + 28 + struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm, 29 + struct drm_gem_object *obj, 30 + u32 *offset); 31 + void i915_overlay_unpin_fb(struct drm_device *drm, 32 + struct i915_vma *vma); 33 + 34 + struct drm_gem_object * 35 + i915_overlay_obj_lookup(struct drm_device *drm, 36 + struct drm_file *file_priv, 37 + u32 handle); 38 + 39 + void __iomem *i915_overlay_setup(struct drm_device *drm, 40 + bool needs_physical); 41 + void i915_overlay_cleanup(struct drm_device *drm); 42 + 43 + #endif /* __I915_OVERLAY_H__ */
+4
drivers/gpu/drm/i915/i915_reg.h
··· 338 338 #define GEN2_IER _MMIO(0x20a0) 339 339 #define GEN2_IIR _MMIO(0x20a4) 340 340 #define GEN2_IMR _MMIO(0x20a8) 341 + #define GEN2_ISR _MMIO(0x20ac) 341 342 342 343 #define GEN2_IRQ_REGS I915_IRQ_REGS(GEN2_IMR, \ 343 344 GEN2_IER, \ ··· 777 776 #define SGR_DIS REG_BIT(13) 778 777 779 778 #define MTL_MEDIA_GSI_BASE 0x380000 779 + 780 + #define DSPCLK_GATE_D _MMIO(0x6200) 781 + # define OVRUNIT_CLOCK_GATE_DISABLE (1 << 3) 780 782 781 783 #endif /* _I915_REG_H_ */