aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2014-09-19 12:27:27 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-09-19 13:46:49 -0400
commitb680c37a4d145cf4d8f2b24e46b1163e5ceb1d35 (patch)
tree558b29d308708c2329ed2e3435d9dd7ae74d576c
parent1893a71b1eba79a46ac5b356208e80f822543fa4 (diff)
drm/i915: DocBook integration for frontbuffer tracking
I shouldn't ask everyone to do this and fail myself ... This extracts all the frontbuffer tracking functions into intel_frontbuffer.c, adds a DOC overview section and also adds the missing kerneldoc for i915_gem_track_fb and also pulls it into the same section for convenience. v2: Don't forget about the header files. v3: Oops, might check compilation next time around. To make my life easier drop the increase_pllclock from set_base_atomic since really, it doesn't matter if you see your Oops or kgdb with a tiny bit of lag. v4: Try to better explain how to actually use this, requested by Paulo on irc. v5: Explain invalidate/flush a bit clearer. v6: s/business/busyness/ Acked-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Vandana Kannan <vandana.kannan@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
-rw-r--r--Documentation/DocBook/drm.tmpl7
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c9
-rw-r--r--drivers/gpu/drm/i915/intel_display.c218
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h15
-rw-r--r--drivers/gpu/drm/i915/intel_frontbuffer.c277
6 files changed, 306 insertions, 221 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index ca44d9fe7d7d..7ad61284ad5f 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -3804,6 +3804,13 @@ int num_ioctls;</synopsis>
3804 </para> 3804 </para>
3805 </sect2> 3805 </sect2>
3806 <sect2> 3806 <sect2>
3807 <title>Frontbuffer Tracking</title>
3808!Pdrivers/gpu/drm/i915/intel_frontbuffer.c frontbuffer tracking
3809!Idrivers/gpu/drm/i915/intel_frontbuffer.c
3810!Fdrivers/gpu/drm/i915/intel_drv.h intel_frontbuffer_flip
3811!Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb
3812 </sect2>
3813 <sect2>
3807 <title>Plane Configuration</title> 3814 <title>Plane Configuration</title>
3808 <para> 3815 <para>
3809 This section covers plane configuration and composition with the 3816 This section covers plane configuration and composition with the
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index c1dd485aeb6c..2d8317d36e09 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -43,6 +43,7 @@ i915-y += intel_renderstate_gen6.o \
43# modesetting core code 43# modesetting core code
44i915-y += intel_bios.o \ 44i915-y += intel_bios.o \
45 intel_display.o \ 45 intel_display.o \
46 intel_frontbuffer.o \
46 intel_modes.o \ 47 intel_modes.o \
47 intel_overlay.o \ 48 intel_overlay.o \
48 intel_sideband.o \ 49 intel_sideband.o \
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2fb87cfa5b82..55a2ebb510bf 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5077,6 +5077,15 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
5077 return ret; 5077 return ret;
5078} 5078}
5079 5079
5080/**
5081 * i915_gem_track_fb - update frontbuffer tracking
5082 * old: current GEM buffer for the frontbuffer slots
5083 * new: new GEM buffer for the frontbuffer slots
5084 * frontbuffer_bits: bitmask of frontbuffer slots
5085 *
5086 * This updates the frontbuffer tracking bits @frontbuffer_bits by clearing them
5087 * from @old and setting them in @new. Both @old and @new can be NULL.
5088 */
5080void i915_gem_track_fb(struct drm_i915_gem_object *old, 5089void i915_gem_track_fb(struct drm_i915_gem_object *old,
5081 struct drm_i915_gem_object *new, 5090 struct drm_i915_gem_object *new,
5082 unsigned frontbuffer_bits) 5091 unsigned frontbuffer_bits)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5b05ddbfa46f..858011d22482 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -76,8 +76,6 @@ static const uint32_t intel_cursor_formats[] = {
76#define DIV_ROUND_CLOSEST_ULL(ll, d) \ 76#define DIV_ROUND_CLOSEST_ULL(ll, d) \
77({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) 77({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
78 78
79static void intel_increase_pllclock(struct drm_device *dev,
80 enum pipe pipe);
81static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); 79static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
82 80
83static void i9xx_crtc_clock_get(struct intel_crtc *crtc, 81static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
@@ -1138,8 +1136,8 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
1138 state_string(state), state_string(cur_state)); 1136 state_string(state), state_string(cur_state));
1139} 1137}
1140 1138
1141static void assert_panel_unlocked(struct drm_i915_private *dev_priv, 1139void assert_panel_unlocked(struct drm_i915_private *dev_priv,
1142 enum pipe pipe) 1140 enum pipe pipe)
1143{ 1141{
1144 struct drm_device *dev = dev_priv->dev; 1142 struct drm_device *dev = dev_priv->dev;
1145 int pp_reg; 1143 int pp_reg;
@@ -2631,7 +2629,6 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
2631 2629
2632 if (dev_priv->display.disable_fbc) 2630 if (dev_priv->display.disable_fbc)
2633 dev_priv->display.disable_fbc(dev); 2631 dev_priv->display.disable_fbc(dev);
2634 intel_increase_pllclock(dev, to_intel_crtc(crtc)->pipe);
2635 2632
2636 dev_priv->display.update_primary_plane(crtc, fb, x, y); 2633 dev_priv->display.update_primary_plane(crtc, fb, x, y);
2637 2634
@@ -8986,35 +8983,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
8986 return mode; 8983 return mode;
8987} 8984}
8988 8985
8989static void intel_increase_pllclock(struct drm_device *dev,
8990 enum pipe pipe)
8991{
8992 struct drm_i915_private *dev_priv = dev->dev_private;
8993 int dpll_reg = DPLL(pipe);
8994 int dpll;
8995
8996 if (!HAS_GMCH_DISPLAY(dev))
8997 return;
8998
8999 if (!dev_priv->lvds_downclock_avail)
9000 return;
9001
9002 dpll = I915_READ(dpll_reg);
9003 if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
9004 DRM_DEBUG_DRIVER("upclocking LVDS\n");
9005
9006 assert_panel_unlocked(dev_priv, pipe);
9007
9008 dpll &= ~DISPLAY_RATE_SELECT_FPA1;
9009 I915_WRITE(dpll_reg, dpll);
9010 intel_wait_for_vblank(dev, pipe);
9011
9012 dpll = I915_READ(dpll_reg);
9013 if (dpll & DISPLAY_RATE_SELECT_FPA1)
9014 DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
9015 }
9016}
9017
9018static void intel_decrease_pllclock(struct drm_crtc *crtc) 8986static void intel_decrease_pllclock(struct drm_crtc *crtc)
9019{ 8987{
9020 struct drm_device *dev = crtc->dev; 8988 struct drm_device *dev = crtc->dev;
@@ -9090,188 +9058,6 @@ out:
9090 intel_runtime_pm_put(dev_priv); 9058 intel_runtime_pm_put(dev_priv);
9091} 9059}
9092 9060
9093
9094/**
9095 * intel_mark_fb_busy - mark given planes as busy
9096 * @dev: DRM device
9097 * @frontbuffer_bits: bits for the affected planes
9098 * @ring: optional ring for asynchronous commands
9099 *
9100 * This function gets called every time the screen contents change. It can be
9101 * used to keep e.g. the update rate at the nominal refresh rate with DRRS.
9102 */
9103static void intel_mark_fb_busy(struct drm_device *dev,
9104 unsigned frontbuffer_bits,
9105 struct intel_engine_cs *ring)
9106{
9107 struct drm_i915_private *dev_priv = dev->dev_private;
9108 enum pipe pipe;
9109
9110 if (!i915.powersave)
9111 return;
9112
9113 for_each_pipe(dev_priv, pipe) {
9114 if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)))
9115 continue;
9116
9117 intel_increase_pllclock(dev, pipe);
9118 if (ring && intel_fbc_enabled(dev))
9119 ring->fbc_dirty = true;
9120 }
9121}
9122
9123/**
9124 * intel_fb_obj_invalidate - invalidate frontbuffer object
9125 * @obj: GEM object to invalidate
9126 * @ring: set for asynchronous rendering
9127 *
9128 * This function gets called every time rendering on the given object starts and
9129 * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must
9130 * be invalidated. If @ring is non-NULL any subsequent invalidation will be delayed
9131 * until the rendering completes or a flip on this frontbuffer plane is
9132 * scheduled.
9133 */
9134void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
9135 struct intel_engine_cs *ring)
9136{
9137 struct drm_device *dev = obj->base.dev;
9138 struct drm_i915_private *dev_priv = dev->dev_private;
9139
9140 WARN_ON(!mutex_is_locked(&dev->struct_mutex));
9141
9142 if (!obj->frontbuffer_bits)
9143 return;
9144
9145 if (ring) {
9146 mutex_lock(&dev_priv->fb_tracking.lock);
9147 dev_priv->fb_tracking.busy_bits
9148 |= obj->frontbuffer_bits;
9149 dev_priv->fb_tracking.flip_bits
9150 &= ~obj->frontbuffer_bits;
9151 mutex_unlock(&dev_priv->fb_tracking.lock);
9152 }
9153
9154 intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring);
9155
9156 intel_edp_psr_invalidate(dev, obj->frontbuffer_bits);
9157}
9158
9159/**
9160 * intel_frontbuffer_flush - flush frontbuffer
9161 * @dev: DRM device
9162 * @frontbuffer_bits: frontbuffer plane tracking bits
9163 *
9164 * This function gets called every time rendering on the given planes has
9165 * completed and frontbuffer caching can be started again. Flushes will get
9166 * delayed if they're blocked by some oustanding asynchronous rendering.
9167 *
9168 * Can be called without any locks held.
9169 */
9170void intel_frontbuffer_flush(struct drm_device *dev,
9171 unsigned frontbuffer_bits)
9172{
9173 struct drm_i915_private *dev_priv = dev->dev_private;
9174
9175 /* Delay flushing when rings are still busy.*/
9176 mutex_lock(&dev_priv->fb_tracking.lock);
9177 frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits;
9178 mutex_unlock(&dev_priv->fb_tracking.lock);
9179
9180 intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
9181
9182 intel_edp_psr_flush(dev, frontbuffer_bits);
9183
9184 /*
9185 * FIXME: Unconditional fbc flushing here is a rather gross hack and
9186 * needs to be reworked into a proper frontbuffer tracking scheme like
9187 * psr employs.
9188 */
9189 if (IS_BROADWELL(dev))
9190 gen8_fbc_sw_flush(dev, FBC_REND_CACHE_CLEAN);
9191}
9192
9193/**
9194 * intel_fb_obj_flush - flush frontbuffer object
9195 * @obj: GEM object to flush
9196 * @retire: set when retiring asynchronous rendering
9197 *
9198 * This function gets called every time rendering on the given object has
9199 * completed and frontbuffer caching can be started again. If @retire is true
9200 * then any delayed flushes will be unblocked.
9201 */
9202void intel_fb_obj_flush(struct drm_i915_gem_object *obj,
9203 bool retire)
9204{
9205 struct drm_device *dev = obj->base.dev;
9206 struct drm_i915_private *dev_priv = dev->dev_private;
9207 unsigned frontbuffer_bits;
9208
9209 WARN_ON(!mutex_is_locked(&dev->struct_mutex));
9210
9211 if (!obj->frontbuffer_bits)
9212 return;
9213
9214 frontbuffer_bits = obj->frontbuffer_bits;
9215
9216 if (retire) {
9217 mutex_lock(&dev_priv->fb_tracking.lock);
9218 /* Filter out new bits since rendering started. */
9219 frontbuffer_bits &= dev_priv->fb_tracking.busy_bits;
9220
9221 dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits;
9222 mutex_unlock(&dev_priv->fb_tracking.lock);
9223 }
9224
9225 intel_frontbuffer_flush(dev, frontbuffer_bits);
9226}
9227
9228/**
9229 * intel_frontbuffer_flip_prepare - prepare asnychronous frontbuffer flip
9230 * @dev: DRM device
9231 * @frontbuffer_bits: frontbuffer plane tracking bits
9232 *
9233 * This function gets called after scheduling a flip on @obj. The actual
9234 * frontbuffer flushing will be delayed until completion is signalled with
9235 * intel_frontbuffer_flip_complete. If an invalidate happens in between this
9236 * flush will be cancelled.
9237 *
9238 * Can be called without any locks held.
9239 */
9240void intel_frontbuffer_flip_prepare(struct drm_device *dev,
9241 unsigned frontbuffer_bits)
9242{
9243 struct drm_i915_private *dev_priv = dev->dev_private;
9244
9245 mutex_lock(&dev_priv->fb_tracking.lock);
9246 dev_priv->fb_tracking.flip_bits
9247 |= frontbuffer_bits;
9248 mutex_unlock(&dev_priv->fb_tracking.lock);
9249}
9250
9251/**
9252 * intel_frontbuffer_flip_complete - complete asynchronous frontbuffer flush
9253 * @dev: DRM device
9254 * @frontbuffer_bits: frontbuffer plane tracking bits
9255 *
9256 * This function gets called after the flip has been latched and will complete
9257 * on the next vblank. It will execute the fush if it hasn't been cancalled yet.
9258 *
9259 * Can be called without any locks held.
9260 */
9261void intel_frontbuffer_flip_complete(struct drm_device *dev,
9262 unsigned frontbuffer_bits)
9263{
9264 struct drm_i915_private *dev_priv = dev->dev_private;
9265
9266 mutex_lock(&dev_priv->fb_tracking.lock);
9267 /* Mask any cancelled flips. */
9268 frontbuffer_bits &= dev_priv->fb_tracking.flip_bits;
9269 dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits;
9270 mutex_unlock(&dev_priv->fb_tracking.lock);
9271
9272 intel_frontbuffer_flush(dev, frontbuffer_bits);
9273}
9274
9275static void intel_crtc_destroy(struct drm_crtc *crtc) 9061static void intel_crtc_destroy(struct drm_crtc *crtc)
9276{ 9062{
9277 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 9063 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1b72c15db907..617126786819 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -801,11 +801,7 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
801 struct intel_crtc_config *pipe_config); 801 struct intel_crtc_config *pipe_config);
802void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state); 802void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
803 803
804/* intel_display.c */ 804/* intel_frontbuffer.c */
805const char *intel_output_name(int output);
806bool intel_has_pending_fb_unpin(struct drm_device *dev);
807int intel_pch_rawclk(struct drm_device *dev);
808void intel_mark_busy(struct drm_device *dev);
809void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, 805void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
810 struct intel_engine_cs *ring); 806 struct intel_engine_cs *ring);
811void intel_frontbuffer_flip_prepare(struct drm_device *dev, 807void intel_frontbuffer_flip_prepare(struct drm_device *dev,
@@ -833,6 +829,13 @@ void intel_frontbuffer_flip(struct drm_device *dev,
833} 829}
834 830
835void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); 831void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
832
833
834/* intel_display.c */
835const char *intel_output_name(int output);
836bool intel_has_pending_fb_unpin(struct drm_device *dev);
837int intel_pch_rawclk(struct drm_device *dev);
838void intel_mark_busy(struct drm_device *dev);
836void intel_mark_idle(struct drm_device *dev); 839void intel_mark_idle(struct drm_device *dev);
837void intel_crtc_restore_mode(struct drm_crtc *crtc); 840void intel_crtc_restore_mode(struct drm_crtc *crtc);
838void intel_crtc_control(struct drm_crtc *crtc, bool enable); 841void intel_crtc_control(struct drm_crtc *crtc, bool enable);
@@ -891,6 +894,8 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc);
891void intel_put_shared_dpll(struct intel_crtc *crtc); 894void intel_put_shared_dpll(struct intel_crtc *crtc);
892 895
893/* modesetting asserts */ 896/* modesetting asserts */
897void assert_panel_unlocked(struct drm_i915_private *dev_priv,
898 enum pipe pipe);
894void assert_pll(struct drm_i915_private *dev_priv, 899void assert_pll(struct drm_i915_private *dev_priv,
895 enum pipe pipe, bool state); 900 enum pipe pipe, bool state);
896#define assert_pll_enabled(d, p) assert_pll(d, p, true) 901#define assert_pll_enabled(d, p) assert_pll(d, p, true)
diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c
new file mode 100644
index 000000000000..f74744c091cb
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_frontbuffer.c
@@ -0,0 +1,277 @@
1/*
2 * Copyright © 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Daniel Vetter <daniel.vetter@ffwll.ch>
25 */
26
27/**
28 * DOC: frontbuffer tracking
29 *
30 * Many features require us to track changes to the currently active
31 * frontbuffer, especially rendering targetted at the frontbuffer.
32 *
33 * To be able to do so GEM tracks frontbuffers using a bitmask for all possible
34 * frontbuffer slots through i915_gem_track_fb(). The function in this file are
35 * then called when the contents of the frontbuffer are invalidated, when
36 * frontbuffer rendering has stopped again to flush out all the changes and when
37 * the frontbuffer is exchanged with a flip. Subsystems interested in
38 * frontbuffer changes (e.g. PSR, FBC, DRRS) should directly put their callbacks
39 * into the relevant places and filter for the frontbuffer slots that they are
40 * interested int.
41 *
42 * On a high level there are two types of powersaving features. The first one
43 * work like a special cache (FBC and PSR) and are interested when they should
44 * stop caching and when to restart caching. This is done by placing callbacks
45 * into the invalidate and the flush functions: At invalidate the caching must
46 * be stopped and at flush time it can be restarted. And maybe they need to know
47 * when the frontbuffer changes (e.g. when the hw doesn't initiate an invalidate
48 * and flush on its own) which can be achieved with placing callbacks into the
49 * flip functions.
50 *
51 * The other type of display power saving feature only cares about busyness
52 * (e.g. DRRS). In that case all three (invalidate, flush and flip) indicate
53 * busyness. There is no direct way to detect idleness. Instead an idle timer
54 * work delayed work should be started from the flush and flip functions and
55 * cancelled as soon as busyness is detected.
56 *
57 * Note that there's also an older frontbuffer activity tracking scheme which
58 * just trackings general activity. This is done by the various mark_busy and
59 * mark_idle functions. For display power management features using these
60 * functions is deprecated and should be avoided.
61 */
62
63#include <drm/drmP.h>
64
65#include "intel_drv.h"
66#include "i915_drv.h"
67
68static void intel_increase_pllclock(struct drm_device *dev,
69 enum pipe pipe)
70{
71 struct drm_i915_private *dev_priv = dev->dev_private;
72 int dpll_reg = DPLL(pipe);
73 int dpll;
74
75 if (!HAS_GMCH_DISPLAY(dev))
76 return;
77
78 if (!dev_priv->lvds_downclock_avail)
79 return;
80
81 dpll = I915_READ(dpll_reg);
82 if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
83 DRM_DEBUG_DRIVER("upclocking LVDS\n");
84
85 assert_panel_unlocked(dev_priv, pipe);
86
87 dpll &= ~DISPLAY_RATE_SELECT_FPA1;
88 I915_WRITE(dpll_reg, dpll);
89 intel_wait_for_vblank(dev, pipe);
90
91 dpll = I915_READ(dpll_reg);
92 if (dpll & DISPLAY_RATE_SELECT_FPA1)
93 DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
94 }
95}
96
97/**
98 * intel_mark_fb_busy - mark given planes as busy
99 * @dev: DRM device
100 * @frontbuffer_bits: bits for the affected planes
101 * @ring: optional ring for asynchronous commands
102 *
103 * This function gets called every time the screen contents change. It can be
104 * used to keep e.g. the update rate at the nominal refresh rate with DRRS.
105 */
106static void intel_mark_fb_busy(struct drm_device *dev,
107 unsigned frontbuffer_bits,
108 struct intel_engine_cs *ring)
109{
110 struct drm_i915_private *dev_priv = dev->dev_private;
111 enum pipe pipe;
112
113 if (!i915.powersave)
114 return;
115
116 for_each_pipe(dev_priv, pipe) {
117 if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)))
118 continue;
119
120 intel_increase_pllclock(dev, pipe);
121 if (ring && intel_fbc_enabled(dev))
122 ring->fbc_dirty = true;
123 }
124}
125
126/**
127 * intel_fb_obj_invalidate - invalidate frontbuffer object
128 * @obj: GEM object to invalidate
129 * @ring: set for asynchronous rendering
130 *
131 * This function gets called every time rendering on the given object starts and
132 * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must
133 * be invalidated. If @ring is non-NULL any subsequent invalidation will be delayed
134 * until the rendering completes or a flip on this frontbuffer plane is
135 * scheduled.
136 */
137void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
138 struct intel_engine_cs *ring)
139{
140 struct drm_device *dev = obj->base.dev;
141 struct drm_i915_private *dev_priv = dev->dev_private;
142
143 WARN_ON(!mutex_is_locked(&dev->struct_mutex));
144
145 if (!obj->frontbuffer_bits)
146 return;
147
148 if (ring) {
149 mutex_lock(&dev_priv->fb_tracking.lock);
150 dev_priv->fb_tracking.busy_bits
151 |= obj->frontbuffer_bits;
152 dev_priv->fb_tracking.flip_bits
153 &= ~obj->frontbuffer_bits;
154 mutex_unlock(&dev_priv->fb_tracking.lock);
155 }
156
157 intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring);
158
159 intel_edp_psr_invalidate(dev, obj->frontbuffer_bits);
160}
161
162/**
163 * intel_frontbuffer_flush - flush frontbuffer
164 * @dev: DRM device
165 * @frontbuffer_bits: frontbuffer plane tracking bits
166 *
167 * This function gets called every time rendering on the given planes has
168 * completed and frontbuffer caching can be started again. Flushes will get
169 * delayed if they're blocked by some oustanding asynchronous rendering.
170 *
171 * Can be called without any locks held.
172 */
173void intel_frontbuffer_flush(struct drm_device *dev,
174 unsigned frontbuffer_bits)
175{
176 struct drm_i915_private *dev_priv = dev->dev_private;
177
178 /* Delay flushing when rings are still busy.*/
179 mutex_lock(&dev_priv->fb_tracking.lock);
180 frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits;
181 mutex_unlock(&dev_priv->fb_tracking.lock);
182
183 intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
184
185 intel_edp_psr_flush(dev, frontbuffer_bits);
186
187 /*
188 * FIXME: Unconditional fbc flushing here is a rather gross hack and
189 * needs to be reworked into a proper frontbuffer tracking scheme like
190 * psr employs.
191 */
192 if (IS_BROADWELL(dev))
193 gen8_fbc_sw_flush(dev, FBC_REND_CACHE_CLEAN);
194}
195
196/**
197 * intel_fb_obj_flush - flush frontbuffer object
198 * @obj: GEM object to flush
199 * @retire: set when retiring asynchronous rendering
200 *
201 * This function gets called every time rendering on the given object has
202 * completed and frontbuffer caching can be started again. If @retire is true
203 * then any delayed flushes will be unblocked.
204 */
205void intel_fb_obj_flush(struct drm_i915_gem_object *obj,
206 bool retire)
207{
208 struct drm_device *dev = obj->base.dev;
209 struct drm_i915_private *dev_priv = dev->dev_private;
210 unsigned frontbuffer_bits;
211
212 WARN_ON(!mutex_is_locked(&dev->struct_mutex));
213
214 if (!obj->frontbuffer_bits)
215 return;
216
217 frontbuffer_bits = obj->frontbuffer_bits;
218
219 if (retire) {
220 mutex_lock(&dev_priv->fb_tracking.lock);
221 /* Filter out new bits since rendering started. */
222 frontbuffer_bits &= dev_priv->fb_tracking.busy_bits;
223
224 dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits;
225 mutex_unlock(&dev_priv->fb_tracking.lock);
226 }
227
228 intel_frontbuffer_flush(dev, frontbuffer_bits);
229}
230
231/**
232 * intel_frontbuffer_flip_prepare - prepare asnychronous frontbuffer flip
233 * @dev: DRM device
234 * @frontbuffer_bits: frontbuffer plane tracking bits
235 *
236 * This function gets called after scheduling a flip on @obj. The actual
237 * frontbuffer flushing will be delayed until completion is signalled with
238 * intel_frontbuffer_flip_complete. If an invalidate happens in between this
239 * flush will be cancelled.
240 *
241 * Can be called without any locks held.
242 */
243void intel_frontbuffer_flip_prepare(struct drm_device *dev,
244 unsigned frontbuffer_bits)
245{
246 struct drm_i915_private *dev_priv = dev->dev_private;
247
248 mutex_lock(&dev_priv->fb_tracking.lock);
249 dev_priv->fb_tracking.flip_bits
250 |= frontbuffer_bits;
251 mutex_unlock(&dev_priv->fb_tracking.lock);
252}
253
254/**
255 * intel_frontbuffer_flip_complete - complete asynchronous frontbuffer flush
256 * @dev: DRM device
257 * @frontbuffer_bits: frontbuffer plane tracking bits
258 *
259 * This function gets called after the flip has been latched and will complete
260 * on the next vblank. It will execute the fush if it hasn't been cancalled yet.
261 *
262 * Can be called without any locks held.
263 */
264void intel_frontbuffer_flip_complete(struct drm_device *dev,
265 unsigned frontbuffer_bits)
266{
267 struct drm_i915_private *dev_priv = dev->dev_private;
268
269 mutex_lock(&dev_priv->fb_tracking.lock);
270 /* Mask any cancelled flips. */
271 frontbuffer_bits &= dev_priv->fb_tracking.flip_bits;
272 dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits;
273 mutex_unlock(&dev_priv->fb_tracking.lock);
274
275 intel_frontbuffer_flush(dev, frontbuffer_bits);
276}
277