1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2023 Intel Corporation
4 */
5
6 #include <linux/dma-fence.h>
7
8 #include <drm/drm_crtc.h>
9 #include <drm/drm_vblank.h>
10
11 #include "i915_reg.h"
12 #include "intel_display_core.h"
13 #include "intel_display_irq.h"
14 #include "intel_display_rps.h"
15 #include "intel_display_types.h"
16 #include "intel_parent.h"
17
18 struct wait_rps_boost {
19 struct wait_queue_entry wait;
20
21 struct drm_crtc *crtc;
22 struct dma_fence *fence;
23 };
24
do_rps_boost(struct wait_queue_entry * _wait,unsigned mode,int sync,void * key)25 static int do_rps_boost(struct wait_queue_entry *_wait,
26 unsigned mode, int sync, void *key)
27 {
28 struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait);
29 struct intel_display *display = to_intel_display(wait->crtc->dev);
30
31 /*
32 * If we missed the vblank, but the request is already running it
33 * is reasonable to assume that it will complete before the next
34 * vblank without our intervention, so leave RPS alone if not started.
35 */
36 intel_parent_rps_boost_if_not_started(display, wait->fence);
37
38 dma_fence_put(wait->fence);
39
40 drm_crtc_vblank_put(wait->crtc);
41
42 list_del(&wait->wait.entry);
43 kfree(wait);
44 return 1;
45 }
46
intel_display_rps_boost_after_vblank(struct drm_crtc * crtc,struct dma_fence * fence)47 void intel_display_rps_boost_after_vblank(struct drm_crtc *crtc,
48 struct dma_fence *fence)
49 {
50 struct intel_display *display = to_intel_display(crtc->dev);
51 struct wait_rps_boost *wait;
52
53 if (!intel_parent_rps_available(display))
54 return;
55
56 if (DISPLAY_VER(display) < 6)
57 return;
58
59 if (drm_crtc_vblank_get(crtc))
60 return;
61
62 wait = kmalloc_obj(*wait);
63 if (!wait) {
64 drm_crtc_vblank_put(crtc);
65 return;
66 }
67
68 wait->fence = dma_fence_get(fence);
69 wait->crtc = crtc;
70
71 wait->wait.func = do_rps_boost;
72 wait->wait.flags = 0;
73
74 add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait);
75 }
76
intel_display_rps_mark_interactive(struct intel_display * display,struct intel_atomic_state * state,bool interactive)77 void intel_display_rps_mark_interactive(struct intel_display *display,
78 struct intel_atomic_state *state,
79 bool interactive)
80 {
81 if (!intel_parent_rps_available(display))
82 return;
83
84 if (state->rps_interactive == interactive)
85 return;
86
87 intel_parent_rps_mark_interactive(display, interactive);
88
89 state->rps_interactive = interactive;
90 }
91
ilk_display_rps_enable(struct intel_display * display)92 void ilk_display_rps_enable(struct intel_display *display)
93 {
94 spin_lock(&display->irq.lock);
95 ilk_enable_display_irq(display, DE_PCU_EVENT);
96 spin_unlock(&display->irq.lock);
97 }
98
ilk_display_rps_disable(struct intel_display * display)99 void ilk_display_rps_disable(struct intel_display *display)
100 {
101 spin_lock(&display->irq.lock);
102 ilk_disable_display_irq(display, DE_PCU_EVENT);
103 spin_unlock(&display->irq.lock);
104 }
105
ilk_display_rps_irq_handler(struct intel_display * display)106 void ilk_display_rps_irq_handler(struct intel_display *display)
107 {
108 intel_parent_rps_ilk_irq_handler(display);
109 }
110