diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-09-30 04:56:46 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-10-24 10:33:53 -0400 |
commit | 47339cd9ff07376df1639260ecc088adf1856bfe (patch) | |
tree | 998ddfe277a2380209eed2e7d9a17d77f2162422 /drivers/gpu/drm/i915/intel_fifo_underrun.c | |
parent | cacc6c837b799b058d59d2af02c11140640cc1d2 (diff) |
drm/i915: Extract intel_fifo_underrun.c
Prep work for some nice documentation. Requires that we export the
display irq enable/disable functions on ilk/ibx. But we already export
them for vlv/i915. So not more inconsistency.
v2: Rebase on top of skl stage 1.
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fifo_underrun.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_fifo_underrun.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c new file mode 100644 index 000000000000..8e79d2ba787d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c | |||
@@ -0,0 +1,311 @@ | |||
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 DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Daniel Vetter <daniel.vetter@ffwll.ch> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "i915_drv.h" | ||
29 | #include "intel_drv.h" | ||
30 | |||
31 | static bool ivb_can_enable_err_int(struct drm_device *dev) | ||
32 | { | ||
33 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
34 | struct intel_crtc *crtc; | ||
35 | enum pipe pipe; | ||
36 | |||
37 | assert_spin_locked(&dev_priv->irq_lock); | ||
38 | |||
39 | for_each_pipe(dev_priv, pipe) { | ||
40 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); | ||
41 | |||
42 | if (crtc->cpu_fifo_underrun_disabled) | ||
43 | return false; | ||
44 | } | ||
45 | |||
46 | return true; | ||
47 | } | ||
48 | |||
49 | static bool cpt_can_enable_serr_int(struct drm_device *dev) | ||
50 | { | ||
51 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
52 | enum pipe pipe; | ||
53 | struct intel_crtc *crtc; | ||
54 | |||
55 | assert_spin_locked(&dev_priv->irq_lock); | ||
56 | |||
57 | for_each_pipe(dev_priv, pipe) { | ||
58 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); | ||
59 | |||
60 | if (crtc->pch_fifo_underrun_disabled) | ||
61 | return false; | ||
62 | } | ||
63 | |||
64 | return true; | ||
65 | } | ||
66 | |||
67 | void i9xx_check_fifo_underruns(struct drm_device *dev) | ||
68 | { | ||
69 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
70 | struct intel_crtc *crtc; | ||
71 | |||
72 | spin_lock_irq(&dev_priv->irq_lock); | ||
73 | |||
74 | for_each_intel_crtc(dev, crtc) { | ||
75 | u32 reg = PIPESTAT(crtc->pipe); | ||
76 | u32 pipestat; | ||
77 | |||
78 | if (crtc->cpu_fifo_underrun_disabled) | ||
79 | continue; | ||
80 | |||
81 | pipestat = I915_READ(reg) & 0xffff0000; | ||
82 | if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0) | ||
83 | continue; | ||
84 | |||
85 | I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); | ||
86 | POSTING_READ(reg); | ||
87 | |||
88 | DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe)); | ||
89 | } | ||
90 | |||
91 | spin_unlock_irq(&dev_priv->irq_lock); | ||
92 | } | ||
93 | |||
94 | static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, | ||
95 | enum pipe pipe, | ||
96 | bool enable, bool old) | ||
97 | { | ||
98 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
99 | u32 reg = PIPESTAT(pipe); | ||
100 | u32 pipestat = I915_READ(reg) & 0xffff0000; | ||
101 | |||
102 | assert_spin_locked(&dev_priv->irq_lock); | ||
103 | |||
104 | if (enable) { | ||
105 | I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); | ||
106 | POSTING_READ(reg); | ||
107 | } else { | ||
108 | if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS) | ||
109 | DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, | ||
114 | enum pipe pipe, bool enable) | ||
115 | { | ||
116 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
117 | uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : | ||
118 | DE_PIPEB_FIFO_UNDERRUN; | ||
119 | |||
120 | if (enable) | ||
121 | ironlake_enable_display_irq(dev_priv, bit); | ||
122 | else | ||
123 | ironlake_disable_display_irq(dev_priv, bit); | ||
124 | } | ||
125 | |||
126 | static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, | ||
127 | enum pipe pipe, | ||
128 | bool enable, bool old) | ||
129 | { | ||
130 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
131 | if (enable) { | ||
132 | I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe)); | ||
133 | |||
134 | if (!ivb_can_enable_err_int(dev)) | ||
135 | return; | ||
136 | |||
137 | ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); | ||
138 | } else { | ||
139 | ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); | ||
140 | |||
141 | if (old && | ||
142 | I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) { | ||
143 | DRM_ERROR("uncleared fifo underrun on pipe %c\n", | ||
144 | pipe_name(pipe)); | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev, | ||
150 | enum pipe pipe, bool enable) | ||
151 | { | ||
152 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
153 | |||
154 | assert_spin_locked(&dev_priv->irq_lock); | ||
155 | |||
156 | if (enable) | ||
157 | dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN; | ||
158 | else | ||
159 | dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN; | ||
160 | I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); | ||
161 | POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); | ||
162 | } | ||
163 | |||
164 | static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, | ||
165 | enum transcoder pch_transcoder, | ||
166 | bool enable) | ||
167 | { | ||
168 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
169 | uint32_t bit = (pch_transcoder == TRANSCODER_A) ? | ||
170 | SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER; | ||
171 | |||
172 | if (enable) | ||
173 | ibx_enable_display_interrupt(dev_priv, bit); | ||
174 | else | ||
175 | ibx_disable_display_interrupt(dev_priv, bit); | ||
176 | } | ||
177 | |||
178 | static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, | ||
179 | enum transcoder pch_transcoder, | ||
180 | bool enable, bool old) | ||
181 | { | ||
182 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
183 | |||
184 | if (enable) { | ||
185 | I915_WRITE(SERR_INT, | ||
186 | SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)); | ||
187 | |||
188 | if (!cpt_can_enable_serr_int(dev)) | ||
189 | return; | ||
190 | |||
191 | ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); | ||
192 | } else { | ||
193 | ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); | ||
194 | |||
195 | if (old && I915_READ(SERR_INT) & | ||
196 | SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) { | ||
197 | DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n", | ||
198 | transcoder_name(pch_transcoder)); | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages | ||
205 | * @dev: drm device | ||
206 | * @pipe: pipe | ||
207 | * @enable: true if we want to report FIFO underrun errors, false otherwise | ||
208 | * | ||
209 | * This function makes us disable or enable CPU fifo underruns for a specific | ||
210 | * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun | ||
211 | * reporting for one pipe may also disable all the other CPU error interruts for | ||
212 | * the other pipes, due to the fact that there's just one interrupt mask/enable | ||
213 | * bit for all the pipes. | ||
214 | * | ||
215 | * Returns the previous state of underrun reporting. | ||
216 | */ | ||
217 | static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | ||
218 | enum pipe pipe, bool enable) | ||
219 | { | ||
220 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
221 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
222 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
223 | bool old; | ||
224 | |||
225 | assert_spin_locked(&dev_priv->irq_lock); | ||
226 | |||
227 | old = !intel_crtc->cpu_fifo_underrun_disabled; | ||
228 | intel_crtc->cpu_fifo_underrun_disabled = !enable; | ||
229 | |||
230 | if (HAS_GMCH_DISPLAY(dev)) | ||
231 | i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); | ||
232 | else if (IS_GEN5(dev) || IS_GEN6(dev)) | ||
233 | ironlake_set_fifo_underrun_reporting(dev, pipe, enable); | ||
234 | else if (IS_GEN7(dev)) | ||
235 | ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old); | ||
236 | else if (IS_GEN8(dev) || IS_GEN9(dev)) | ||
237 | broadwell_set_fifo_underrun_reporting(dev, pipe, enable); | ||
238 | |||
239 | return old; | ||
240 | } | ||
241 | |||
242 | bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | ||
243 | enum pipe pipe, bool enable) | ||
244 | { | ||
245 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
246 | unsigned long flags; | ||
247 | bool ret; | ||
248 | |||
249 | spin_lock_irqsave(&dev_priv->irq_lock, flags); | ||
250 | ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable); | ||
251 | spin_unlock_irqrestore(&dev_priv->irq_lock, flags); | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev, | ||
257 | enum pipe pipe) | ||
258 | { | ||
259 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
260 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
261 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
262 | |||
263 | return !intel_crtc->cpu_fifo_underrun_disabled; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages | ||
268 | * @dev: drm device | ||
269 | * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older) | ||
270 | * @enable: true if we want to report FIFO underrun errors, false otherwise | ||
271 | * | ||
272 | * This function makes us disable or enable PCH fifo underruns for a specific | ||
273 | * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO | ||
274 | * underrun reporting for one transcoder may also disable all the other PCH | ||
275 | * error interruts for the other transcoders, due to the fact that there's just | ||
276 | * one interrupt mask/enable bit for all the transcoders. | ||
277 | * | ||
278 | * Returns the previous state of underrun reporting. | ||
279 | */ | ||
280 | bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, | ||
281 | enum transcoder pch_transcoder, | ||
282 | bool enable) | ||
283 | { | ||
284 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
285 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; | ||
286 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
287 | unsigned long flags; | ||
288 | bool old; | ||
289 | |||
290 | /* | ||
291 | * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT | ||
292 | * has only one pch transcoder A that all pipes can use. To avoid racy | ||
293 | * pch transcoder -> pipe lookups from interrupt code simply store the | ||
294 | * underrun statistics in crtc A. Since we never expose this anywhere | ||
295 | * nor use it outside of the fifo underrun code here using the "wrong" | ||
296 | * crtc on LPT won't cause issues. | ||
297 | */ | ||
298 | |||
299 | spin_lock_irqsave(&dev_priv->irq_lock, flags); | ||
300 | |||
301 | old = !intel_crtc->pch_fifo_underrun_disabled; | ||
302 | intel_crtc->pch_fifo_underrun_disabled = !enable; | ||
303 | |||
304 | if (HAS_PCH_IBX(dev)) | ||
305 | ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); | ||
306 | else | ||
307 | cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old); | ||
308 | |||
309 | spin_unlock_irqrestore(&dev_priv->irq_lock, flags); | ||
310 | return old; | ||
311 | } | ||