]>
Commit | Line | Data |
---|---|---|
b840d907 JB |
1 | /* |
2 | * Copyright © 2011 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 FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
21 | * SOFTWARE. | |
22 | * | |
23 | * Authors: | |
24 | * Jesse Barnes <jbarnes@virtuousgeek.org> | |
25 | * | |
26 | * New plane/sprite handling. | |
27 | * | |
28 | * The older chips had a separate interface for programming plane related | |
29 | * registers; newer ones are much simpler and we can use the new DRM plane | |
30 | * support. | |
31 | */ | |
760285e7 | 32 | #include <drm/drmP.h> |
714244e2 | 33 | #include <drm/drm_atomic_helper.h> |
760285e7 DH |
34 | #include <drm/drm_crtc.h> |
35 | #include <drm/drm_fourcc.h> | |
1731693a | 36 | #include <drm/drm_rect.h> |
c331879c | 37 | #include <drm/drm_atomic.h> |
ea2c67bb | 38 | #include <drm/drm_plane_helper.h> |
b840d907 | 39 | #include "intel_drv.h" |
5d723d7a | 40 | #include "intel_frontbuffer.h" |
760285e7 | 41 | #include <drm/i915_drm.h> |
b840d907 JB |
42 | #include "i915_drv.h" |
43 | ||
38f24f21 | 44 | bool intel_format_is_yuv(u32 format) |
6ca2aeb2 VS |
45 | { |
46 | switch (format) { | |
47 | case DRM_FORMAT_YUYV: | |
48 | case DRM_FORMAT_UYVY: | |
49 | case DRM_FORMAT_VYUY: | |
50 | case DRM_FORMAT_YVYU: | |
a589b138 | 51 | case DRM_FORMAT_NV12: |
6ca2aeb2 VS |
52 | return true; |
53 | default: | |
54 | return false; | |
55 | } | |
56 | } | |
57 | ||
dfd2e9ab VS |
58 | int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, |
59 | int usecs) | |
8d7849db VS |
60 | { |
61 | /* paranoia */ | |
5e7234c9 | 62 | if (!adjusted_mode->crtc_htotal) |
8d7849db VS |
63 | return 1; |
64 | ||
5e7234c9 VS |
65 | return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, |
66 | 1000 * adjusted_mode->crtc_htotal); | |
8d7849db VS |
67 | } |
68 | ||
69208c9e DV |
69 | /* FIXME: We should instead only take spinlocks once for the entire update |
70 | * instead of once per mmio. */ | |
71 | #if IS_ENABLED(CONFIG_PROVE_LOCKING) | |
72 | #define VBLANK_EVASION_TIME_US 250 | |
73 | #else | |
e1edbd44 | 74 | #define VBLANK_EVASION_TIME_US 100 |
69208c9e | 75 | #endif |
e1edbd44 | 76 | |
26ff2762 ACO |
77 | /** |
78 | * intel_pipe_update_start() - start update of a set of display registers | |
d3a8fb32 | 79 | * @new_crtc_state: the new crtc state |
26ff2762 ACO |
80 | * |
81 | * Mark the start of an update to pipe registers that should be updated | |
82 | * atomically regarding vblank. If the next vblank will happens within | |
83 | * the next 100 us, this function waits until the vblank passes. | |
84 | * | |
85 | * After a successful call to this function, interrupts will be disabled | |
86 | * until a subsequent call to intel_pipe_update_end(). That is done to | |
d3a8fb32 | 87 | * avoid random delays. |
26ff2762 | 88 | */ |
d3a8fb32 | 89 | void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) |
8d7849db | 90 | { |
d3a8fb32 | 91 | struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); |
ec1b4ee2 | 92 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
d3a8fb32 | 93 | const struct drm_display_mode *adjusted_mode = &new_crtc_state->base.adjusted_mode; |
8d7849db VS |
94 | long timeout = msecs_to_jiffies_timeout(1); |
95 | int scanline, min, max, vblank_start; | |
210871b6 | 96 | wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); |
ec1b4ee2 | 97 | bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && |
d3a8fb32 | 98 | intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); |
8d7849db VS |
99 | DEFINE_WAIT(wait); |
100 | ||
124abe07 VS |
101 | vblank_start = adjusted_mode->crtc_vblank_start; |
102 | if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) | |
8d7849db VS |
103 | vblank_start = DIV_ROUND_UP(vblank_start, 2); |
104 | ||
105 | /* FIXME needs to be calibrated sensibly */ | |
e1edbd44 ML |
106 | min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, |
107 | VBLANK_EVASION_TIME_US); | |
8d7849db VS |
108 | max = vblank_start - 1; |
109 | ||
8f539a83 | 110 | local_irq_disable(); |
8f539a83 | 111 | |
8d7849db | 112 | if (min <= 0 || max <= 0) |
8f539a83 | 113 | return; |
8d7849db | 114 | |
1e3feefd | 115 | if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) |
8f539a83 | 116 | return; |
8d7849db | 117 | |
d637ce3f JB |
118 | crtc->debug.min_vbl = min; |
119 | crtc->debug.max_vbl = max; | |
120 | trace_i915_pipe_update_start(crtc); | |
25ef284a | 121 | |
8d7849db VS |
122 | for (;;) { |
123 | /* | |
124 | * prepare_to_wait() has a memory barrier, which guarantees | |
125 | * other CPUs can see the task state update by the time we | |
126 | * read the scanline. | |
127 | */ | |
210871b6 | 128 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); |
8d7849db VS |
129 | |
130 | scanline = intel_get_crtc_scanline(crtc); | |
131 | if (scanline < min || scanline > max) | |
132 | break; | |
133 | ||
9ba59b79 | 134 | if (!timeout) { |
8d7849db VS |
135 | DRM_ERROR("Potential atomic update failure on pipe %c\n", |
136 | pipe_name(crtc->pipe)); | |
137 | break; | |
138 | } | |
139 | ||
140 | local_irq_enable(); | |
141 | ||
142 | timeout = schedule_timeout(timeout); | |
143 | ||
144 | local_irq_disable(); | |
145 | } | |
146 | ||
210871b6 | 147 | finish_wait(wq, &wait); |
8d7849db | 148 | |
1e3feefd | 149 | drm_crtc_vblank_put(&crtc->base); |
8d7849db | 150 | |
ec1b4ee2 VS |
151 | /* |
152 | * On VLV/CHV DSI the scanline counter would appear to | |
153 | * increment approx. 1/3 of a scanline before start of vblank. | |
154 | * The registers still get latched at start of vblank however. | |
155 | * This means we must not write any registers on the first | |
156 | * line of vblank (since not the whole line is actually in | |
157 | * vblank). And unfortunately we can't use the interrupt to | |
158 | * wait here since it will fire too soon. We could use the | |
159 | * frame start interrupt instead since it will fire after the | |
160 | * critical scanline, but that would require more changes | |
161 | * in the interrupt code. So for now we'll just do the nasty | |
162 | * thing and poll for the bad scanline to pass us by. | |
163 | * | |
164 | * FIXME figure out if BXT+ DSI suffers from this as well | |
165 | */ | |
166 | while (need_vlv_dsi_wa && scanline == vblank_start) | |
167 | scanline = intel_get_crtc_scanline(crtc); | |
168 | ||
eb120ef6 JB |
169 | crtc->debug.scanline_start = scanline; |
170 | crtc->debug.start_vbl_time = ktime_get(); | |
a2991414 | 171 | crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); |
8d7849db | 172 | |
d637ce3f | 173 | trace_i915_pipe_update_vblank_evaded(crtc); |
8d7849db VS |
174 | } |
175 | ||
26ff2762 ACO |
176 | /** |
177 | * intel_pipe_update_end() - end update of a set of display registers | |
d3a8fb32 | 178 | * @new_crtc_state: the new crtc state |
26ff2762 ACO |
179 | * |
180 | * Mark the end of an update started with intel_pipe_update_start(). This | |
181 | * re-enables interrupts and verifies the update was actually completed | |
d3a8fb32 | 182 | * before a vblank. |
26ff2762 | 183 | */ |
d3a8fb32 | 184 | void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) |
8d7849db | 185 | { |
d3a8fb32 | 186 | struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); |
8d7849db | 187 | enum pipe pipe = crtc->pipe; |
eb120ef6 | 188 | int scanline_end = intel_get_crtc_scanline(crtc); |
a2991414 | 189 | u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); |
85a62bf9 | 190 | ktime_t end_vbl_time = ktime_get(); |
a94f2b92 | 191 | struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); |
8d7849db | 192 | |
d637ce3f | 193 | trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end); |
25ef284a | 194 | |
1f7528c4 DV |
195 | /* We're still in the vblank-evade critical section, this can't race. |
196 | * Would be slightly nice to just grab the vblank count and arm the | |
197 | * event outside of the critical section - the spinlock might spin for a | |
198 | * while ... */ | |
d3a8fb32 | 199 | if (new_crtc_state->base.event) { |
1f7528c4 DV |
200 | WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0); |
201 | ||
202 | spin_lock(&crtc->base.dev->event_lock); | |
d3a8fb32 | 203 | drm_crtc_arm_vblank_event(&crtc->base, new_crtc_state->base.event); |
1f7528c4 DV |
204 | spin_unlock(&crtc->base.dev->event_lock); |
205 | ||
d3a8fb32 | 206 | new_crtc_state->base.event = NULL; |
1f7528c4 DV |
207 | } |
208 | ||
8d7849db VS |
209 | local_irq_enable(); |
210 | ||
a94f2b92 BN |
211 | if (intel_vgpu_active(dev_priv)) |
212 | return; | |
213 | ||
eb120ef6 JB |
214 | if (crtc->debug.start_vbl_count && |
215 | crtc->debug.start_vbl_count != end_vbl_count) { | |
216 | DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", | |
217 | pipe_name(pipe), crtc->debug.start_vbl_count, | |
218 | end_vbl_count, | |
219 | ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), | |
220 | crtc->debug.min_vbl, crtc->debug.max_vbl, | |
221 | crtc->debug.scanline_start, scanline_end); | |
7b8cd336 VS |
222 | } |
223 | #ifdef CONFIG_DRM_I915_DEBUG_VBLANK_EVADE | |
224 | else if (ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time) > | |
225 | VBLANK_EVASION_TIME_US) | |
e1edbd44 ML |
226 | DRM_WARN("Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n", |
227 | pipe_name(pipe), | |
228 | ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time), | |
229 | VBLANK_EVASION_TIME_US); | |
7b8cd336 | 230 | #endif |
8d7849db VS |
231 | } |
232 | ||
9a8cc576 | 233 | void |
282dbf9b | 234 | skl_update_plane(struct intel_plane *plane, |
2fde1391 ML |
235 | const struct intel_crtc_state *crtc_state, |
236 | const struct intel_plane_state *plane_state) | |
dc2a41b4 | 237 | { |
282dbf9b VS |
238 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
239 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
240 | enum plane_id plane_id = plane->id; | |
241 | enum pipe pipe = plane->pipe; | |
a0864d59 | 242 | u32 plane_ctl = plane_state->ctl; |
2fde1391 | 243 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
b63a16f6 | 244 | u32 surf_addr = plane_state->main.offset; |
8d0deca8 | 245 | unsigned int rotation = plane_state->base.rotation; |
d2196774 | 246 | u32 stride = skl_plane_stride(fb, 0, rotation); |
2e2adb05 | 247 | u32 aux_stride = skl_plane_stride(fb, 1, rotation); |
936e71e3 VS |
248 | int crtc_x = plane_state->base.dst.x1; |
249 | int crtc_y = plane_state->base.dst.y1; | |
250 | uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); | |
251 | uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); | |
b63a16f6 VS |
252 | uint32_t x = plane_state->main.x; |
253 | uint32_t y = plane_state->main.y; | |
936e71e3 VS |
254 | uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; |
255 | uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; | |
dd584fc0 | 256 | unsigned long irqflags; |
dc2a41b4 | 257 | |
6687c906 VS |
258 | /* Sizes are 0 based */ |
259 | src_w--; | |
260 | src_h--; | |
261 | crtc_w--; | |
262 | crtc_h--; | |
263 | ||
dd584fc0 VS |
264 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
265 | ||
4036c78c | 266 | if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) |
dd584fc0 | 267 | I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id), |
4036c78c | 268 | plane_state->color_ctl); |
38f24f21 | 269 | |
78587de2 | 270 | if (key->flags) { |
dd584fc0 VS |
271 | I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value); |
272 | I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value); | |
273 | I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), key->channel_mask); | |
78587de2 VS |
274 | } |
275 | ||
dd584fc0 VS |
276 | I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x); |
277 | I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride); | |
278 | I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w); | |
2e2adb05 VS |
279 | I915_WRITE_FW(PLANE_AUX_DIST(pipe, plane_id), |
280 | (plane_state->aux.offset - surf_addr) | aux_stride); | |
281 | I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id), | |
282 | (plane_state->aux.y << 16) | plane_state->aux.x); | |
c331879c CK |
283 | |
284 | /* program plane scaler */ | |
2fde1391 | 285 | if (plane_state->scaler_id >= 0) { |
2fde1391 | 286 | int scaler_id = plane_state->scaler_id; |
0a59952b VS |
287 | const struct intel_scaler *scaler = |
288 | &crtc_state->scaler_state.scalers[scaler_id]; | |
289 | u16 y_hphase, uv_rgb_hphase; | |
290 | u16 y_vphase, uv_rgb_vphase; | |
291 | ||
292 | /* TODO: handle sub-pixel coordinates */ | |
293 | if (fb->format->format == DRM_FORMAT_NV12) { | |
294 | y_hphase = skl_scaler_calc_phase(1, false); | |
295 | y_vphase = skl_scaler_calc_phase(1, false); | |
296 | ||
297 | /* MPEG2 chroma siting convention */ | |
298 | uv_rgb_hphase = skl_scaler_calc_phase(2, true); | |
299 | uv_rgb_vphase = skl_scaler_calc_phase(2, false); | |
300 | } else { | |
301 | /* not used */ | |
302 | y_hphase = 0; | |
303 | y_vphase = 0; | |
c331879c | 304 | |
0a59952b VS |
305 | uv_rgb_hphase = skl_scaler_calc_phase(1, false); |
306 | uv_rgb_vphase = skl_scaler_calc_phase(1, false); | |
307 | } | |
7494bcdc | 308 | |
dd584fc0 VS |
309 | I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id), |
310 | PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode); | |
311 | I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0); | |
0a59952b VS |
312 | I915_WRITE_FW(SKL_PS_VPHASE(pipe, scaler_id), |
313 | PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); | |
314 | I915_WRITE_FW(SKL_PS_HPHASE(pipe, scaler_id), | |
315 | PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); | |
dd584fc0 VS |
316 | I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); |
317 | I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id), | |
318 | ((crtc_w + 1) << 16)|(crtc_h + 1)); | |
c331879c | 319 | |
dd584fc0 | 320 | I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0); |
c331879c | 321 | } else { |
dd584fc0 | 322 | I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x); |
c331879c CK |
323 | } |
324 | ||
dd584fc0 VS |
325 | I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl); |
326 | I915_WRITE_FW(PLANE_SURF(pipe, plane_id), | |
327 | intel_plane_ggtt_offset(plane_state) + surf_addr); | |
328 | POSTING_READ_FW(PLANE_SURF(pipe, plane_id)); | |
329 | ||
330 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
dc2a41b4 DL |
331 | } |
332 | ||
779d4d8f | 333 | void |
282dbf9b | 334 | skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) |
dc2a41b4 | 335 | { |
282dbf9b VS |
336 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
337 | enum plane_id plane_id = plane->id; | |
338 | enum pipe pipe = plane->pipe; | |
dd584fc0 VS |
339 | unsigned long irqflags; |
340 | ||
341 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); | |
dc2a41b4 | 342 | |
dd584fc0 | 343 | I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0); |
dc2a41b4 | 344 | |
dd584fc0 VS |
345 | I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0); |
346 | POSTING_READ_FW(PLANE_SURF(pipe, plane_id)); | |
347 | ||
348 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
dc2a41b4 DL |
349 | } |
350 | ||
51f5a096 | 351 | bool |
eade6c89 VS |
352 | skl_plane_get_hw_state(struct intel_plane *plane, |
353 | enum pipe *pipe) | |
51f5a096 VS |
354 | { |
355 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); | |
356 | enum intel_display_power_domain power_domain; | |
357 | enum plane_id plane_id = plane->id; | |
51f5a096 VS |
358 | bool ret; |
359 | ||
eade6c89 | 360 | power_domain = POWER_DOMAIN_PIPE(plane->pipe); |
51f5a096 VS |
361 | if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) |
362 | return false; | |
363 | ||
eade6c89 VS |
364 | ret = I915_READ(PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE; |
365 | ||
366 | *pipe = plane->pipe; | |
51f5a096 VS |
367 | |
368 | intel_display_power_put(dev_priv, power_domain); | |
369 | ||
370 | return ret; | |
371 | } | |
372 | ||
6ca2aeb2 | 373 | static void |
5deae919 | 374 | chv_update_csc(const struct intel_plane_state *plane_state) |
6ca2aeb2 | 375 | { |
5deae919 | 376 | struct intel_plane *plane = to_intel_plane(plane_state->base.plane); |
282dbf9b | 377 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
5deae919 | 378 | const struct drm_framebuffer *fb = plane_state->base.fb; |
282dbf9b | 379 | enum plane_id plane_id = plane->id; |
6ca2aeb2 | 380 | /* |
b0f5c0ba VS |
381 | * |r| | c0 c1 c2 | |cr| |
382 | * |g| = | c3 c4 c5 | x |y | | |
383 | * |b| | c6 c7 c8 | |cb| | |
6ca2aeb2 | 384 | * |
b0f5c0ba | 385 | * Coefficients are s3.12. |
6ca2aeb2 | 386 | * |
b0f5c0ba VS |
387 | * Cb and Cr apparently come in as signed already, and |
388 | * we always get full range data in on account of CLRC0/1. | |
6ca2aeb2 | 389 | */ |
b0f5c0ba VS |
390 | static const s16 csc_matrix[][9] = { |
391 | /* BT.601 full range YCbCr -> full range RGB */ | |
392 | [DRM_COLOR_YCBCR_BT601] = { | |
393 | 5743, 4096, 0, | |
394 | -2925, 4096, -1410, | |
395 | 0, 4096, 7258, | |
396 | }, | |
397 | /* BT.709 full range YCbCr -> full range RGB */ | |
398 | [DRM_COLOR_YCBCR_BT709] = { | |
399 | 6450, 4096, 0, | |
400 | -1917, 4096, -767, | |
401 | 0, 4096, 7601, | |
402 | }, | |
403 | }; | |
404 | const s16 *csc = csc_matrix[plane_state->base.color_encoding]; | |
6ca2aeb2 VS |
405 | |
406 | /* Seems RGB data bypasses the CSC always */ | |
38f24f21 | 407 | if (!intel_format_is_yuv(fb->format->format)) |
6ca2aeb2 VS |
408 | return; |
409 | ||
5deae919 | 410 | I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); |
dd584fc0 VS |
411 | I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); |
412 | I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); | |
413 | ||
b0f5c0ba VS |
414 | I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(csc[1]) | SPCSC_C0(csc[0])); |
415 | I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(csc[3]) | SPCSC_C0(csc[2])); | |
416 | I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(csc[5]) | SPCSC_C0(csc[4])); | |
417 | I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(csc[7]) | SPCSC_C0(csc[6])); | |
418 | I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(csc[8])); | |
dd584fc0 | 419 | |
5deae919 VS |
420 | I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0)); |
421 | I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); | |
422 | I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); | |
dd584fc0 VS |
423 | |
424 | I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); | |
425 | I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); | |
426 | I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); | |
6ca2aeb2 VS |
427 | } |
428 | ||
5deae919 VS |
429 | #define SIN_0 0 |
430 | #define COS_0 1 | |
431 | ||
432 | static void | |
433 | vlv_update_clrc(const struct intel_plane_state *plane_state) | |
434 | { | |
435 | struct intel_plane *plane = to_intel_plane(plane_state->base.plane); | |
436 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); | |
437 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
438 | enum pipe pipe = plane->pipe; | |
439 | enum plane_id plane_id = plane->id; | |
440 | int contrast, brightness, sh_scale, sh_sin, sh_cos; | |
441 | ||
c8624ede VS |
442 | if (intel_format_is_yuv(fb->format->format) && |
443 | plane_state->base.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) { | |
5deae919 VS |
444 | /* |
445 | * Expand limited range to full range: | |
446 | * Contrast is applied first and is used to expand Y range. | |
447 | * Brightness is applied second and is used to remove the | |
448 | * offset from Y. Saturation/hue is used to expand CbCr range. | |
449 | */ | |
450 | contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16); | |
451 | brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16); | |
452 | sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128); | |
453 | sh_sin = SIN_0 * sh_scale; | |
454 | sh_cos = COS_0 * sh_scale; | |
455 | } else { | |
456 | /* Pass-through everything. */ | |
457 | contrast = 1 << 6; | |
458 | brightness = 0; | |
459 | sh_scale = 1 << 7; | |
460 | sh_sin = SIN_0 * sh_scale; | |
461 | sh_cos = COS_0 * sh_scale; | |
462 | } | |
463 | ||
464 | /* FIXME these register are single buffered :( */ | |
465 | I915_WRITE_FW(SPCLRC0(pipe, plane_id), | |
466 | SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness)); | |
467 | I915_WRITE_FW(SPCLRC1(pipe, plane_id), | |
468 | SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos)); | |
469 | } | |
470 | ||
96ef6854 VS |
471 | static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, |
472 | const struct intel_plane_state *plane_state) | |
7f1f3851 | 473 | { |
96ef6854 | 474 | const struct drm_framebuffer *fb = plane_state->base.fb; |
11df4d95 | 475 | unsigned int rotation = plane_state->base.rotation; |
2fde1391 | 476 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
96ef6854 | 477 | u32 sprctl; |
7f1f3851 | 478 | |
96ef6854 | 479 | sprctl = SP_ENABLE | SP_GAMMA_ENABLE; |
7f1f3851 | 480 | |
438b74a5 | 481 | switch (fb->format->format) { |
7f1f3851 JB |
482 | case DRM_FORMAT_YUYV: |
483 | sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; | |
484 | break; | |
485 | case DRM_FORMAT_YVYU: | |
486 | sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; | |
487 | break; | |
488 | case DRM_FORMAT_UYVY: | |
489 | sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; | |
490 | break; | |
491 | case DRM_FORMAT_VYUY: | |
492 | sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; | |
493 | break; | |
494 | case DRM_FORMAT_RGB565: | |
495 | sprctl |= SP_FORMAT_BGR565; | |
496 | break; | |
497 | case DRM_FORMAT_XRGB8888: | |
498 | sprctl |= SP_FORMAT_BGRX8888; | |
499 | break; | |
500 | case DRM_FORMAT_ARGB8888: | |
501 | sprctl |= SP_FORMAT_BGRA8888; | |
502 | break; | |
503 | case DRM_FORMAT_XBGR2101010: | |
504 | sprctl |= SP_FORMAT_RGBX1010102; | |
505 | break; | |
506 | case DRM_FORMAT_ABGR2101010: | |
507 | sprctl |= SP_FORMAT_RGBA1010102; | |
508 | break; | |
509 | case DRM_FORMAT_XBGR8888: | |
510 | sprctl |= SP_FORMAT_RGBX8888; | |
511 | break; | |
512 | case DRM_FORMAT_ABGR8888: | |
513 | sprctl |= SP_FORMAT_RGBA8888; | |
514 | break; | |
515 | default: | |
96ef6854 VS |
516 | MISSING_CASE(fb->format->format); |
517 | return 0; | |
7f1f3851 JB |
518 | } |
519 | ||
b0f5c0ba VS |
520 | if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) |
521 | sprctl |= SP_YUV_FORMAT_BT709; | |
522 | ||
bae781b2 | 523 | if (fb->modifier == I915_FORMAT_MOD_X_TILED) |
7f1f3851 JB |
524 | sprctl |= SP_TILED; |
525 | ||
c2c446ad | 526 | if (rotation & DRM_MODE_ROTATE_180) |
df0cd455 VS |
527 | sprctl |= SP_ROTATE_180; |
528 | ||
c2c446ad | 529 | if (rotation & DRM_MODE_REFLECT_X) |
4ea7be2b VS |
530 | sprctl |= SP_MIRROR; |
531 | ||
78587de2 VS |
532 | if (key->flags & I915_SET_COLORKEY_SOURCE) |
533 | sprctl |= SP_SOURCE_KEY; | |
534 | ||
96ef6854 VS |
535 | return sprctl; |
536 | } | |
537 | ||
538 | static void | |
282dbf9b | 539 | vlv_update_plane(struct intel_plane *plane, |
96ef6854 VS |
540 | const struct intel_crtc_state *crtc_state, |
541 | const struct intel_plane_state *plane_state) | |
542 | { | |
282dbf9b VS |
543 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
544 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
545 | enum pipe pipe = plane->pipe; | |
546 | enum plane_id plane_id = plane->id; | |
a0864d59 | 547 | u32 sprctl = plane_state->ctl; |
f9407ae1 VS |
548 | u32 sprsurf_offset = plane_state->main.offset; |
549 | u32 linear_offset; | |
96ef6854 VS |
550 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
551 | int crtc_x = plane_state->base.dst.x1; | |
552 | int crtc_y = plane_state->base.dst.y1; | |
553 | uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); | |
554 | uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); | |
f9407ae1 VS |
555 | uint32_t x = plane_state->main.x; |
556 | uint32_t y = plane_state->main.y; | |
96ef6854 VS |
557 | unsigned long irqflags; |
558 | ||
7f1f3851 | 559 | /* Sizes are 0 based */ |
7f1f3851 JB |
560 | crtc_w--; |
561 | crtc_h--; | |
562 | ||
2949056c | 563 | linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); |
6687c906 | 564 | |
dd584fc0 VS |
565 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
566 | ||
5deae919 VS |
567 | vlv_update_clrc(plane_state); |
568 | ||
78587de2 | 569 | if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) |
5deae919 | 570 | chv_update_csc(plane_state); |
78587de2 | 571 | |
47ecbb20 | 572 | if (key->flags) { |
dd584fc0 VS |
573 | I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value); |
574 | I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value); | |
575 | I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask); | |
47ecbb20 | 576 | } |
dd584fc0 VS |
577 | I915_WRITE_FW(SPSTRIDE(pipe, plane_id), fb->pitches[0]); |
578 | I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x); | |
ca6ad025 | 579 | |
bae781b2 | 580 | if (fb->modifier == I915_FORMAT_MOD_X_TILED) |
dd584fc0 | 581 | I915_WRITE_FW(SPTILEOFF(pipe, plane_id), (y << 16) | x); |
7f1f3851 | 582 | else |
dd584fc0 | 583 | I915_WRITE_FW(SPLINOFF(pipe, plane_id), linear_offset); |
7f1f3851 | 584 | |
dd584fc0 | 585 | I915_WRITE_FW(SPCONSTALPHA(pipe, plane_id), 0); |
c14b0485 | 586 | |
dd584fc0 VS |
587 | I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w); |
588 | I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl); | |
589 | I915_WRITE_FW(SPSURF(pipe, plane_id), | |
590 | intel_plane_ggtt_offset(plane_state) + sprsurf_offset); | |
591 | POSTING_READ_FW(SPSURF(pipe, plane_id)); | |
592 | ||
593 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
7f1f3851 JB |
594 | } |
595 | ||
596 | static void | |
282dbf9b | 597 | vlv_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) |
7f1f3851 | 598 | { |
282dbf9b VS |
599 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
600 | enum pipe pipe = plane->pipe; | |
601 | enum plane_id plane_id = plane->id; | |
dd584fc0 VS |
602 | unsigned long irqflags; |
603 | ||
604 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); | |
7f1f3851 | 605 | |
dd584fc0 | 606 | I915_WRITE_FW(SPCNTR(pipe, plane_id), 0); |
48fe4691 | 607 | |
dd584fc0 VS |
608 | I915_WRITE_FW(SPSURF(pipe, plane_id), 0); |
609 | POSTING_READ_FW(SPSURF(pipe, plane_id)); | |
610 | ||
611 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
7f1f3851 JB |
612 | } |
613 | ||
51f5a096 | 614 | static bool |
eade6c89 VS |
615 | vlv_plane_get_hw_state(struct intel_plane *plane, |
616 | enum pipe *pipe) | |
51f5a096 VS |
617 | { |
618 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); | |
619 | enum intel_display_power_domain power_domain; | |
620 | enum plane_id plane_id = plane->id; | |
51f5a096 VS |
621 | bool ret; |
622 | ||
eade6c89 | 623 | power_domain = POWER_DOMAIN_PIPE(plane->pipe); |
51f5a096 VS |
624 | if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) |
625 | return false; | |
626 | ||
eade6c89 VS |
627 | ret = I915_READ(SPCNTR(plane->pipe, plane_id)) & SP_ENABLE; |
628 | ||
629 | *pipe = plane->pipe; | |
51f5a096 VS |
630 | |
631 | intel_display_power_put(dev_priv, power_domain); | |
632 | ||
633 | return ret; | |
634 | } | |
635 | ||
45dea7b0 VS |
636 | static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state, |
637 | const struct intel_plane_state *plane_state) | |
b840d907 | 638 | { |
45dea7b0 VS |
639 | struct drm_i915_private *dev_priv = |
640 | to_i915(plane_state->base.plane->dev); | |
641 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
8d0deca8 | 642 | unsigned int rotation = plane_state->base.rotation; |
2fde1391 | 643 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
45dea7b0 VS |
644 | u32 sprctl; |
645 | ||
646 | sprctl = SPRITE_ENABLE | SPRITE_GAMMA_ENABLE; | |
b840d907 | 647 | |
45dea7b0 VS |
648 | if (IS_IVYBRIDGE(dev_priv)) |
649 | sprctl |= SPRITE_TRICKLE_FEED_DISABLE; | |
650 | ||
651 | if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) | |
652 | sprctl |= SPRITE_PIPE_CSC_ENABLE; | |
b840d907 | 653 | |
438b74a5 | 654 | switch (fb->format->format) { |
b840d907 | 655 | case DRM_FORMAT_XBGR8888: |
5ee36913 | 656 | sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; |
b840d907 JB |
657 | break; |
658 | case DRM_FORMAT_XRGB8888: | |
5ee36913 | 659 | sprctl |= SPRITE_FORMAT_RGBX888; |
b840d907 JB |
660 | break; |
661 | case DRM_FORMAT_YUYV: | |
662 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; | |
b840d907 JB |
663 | break; |
664 | case DRM_FORMAT_YVYU: | |
665 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; | |
b840d907 JB |
666 | break; |
667 | case DRM_FORMAT_UYVY: | |
668 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; | |
b840d907 JB |
669 | break; |
670 | case DRM_FORMAT_VYUY: | |
671 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; | |
b840d907 JB |
672 | break; |
673 | default: | |
45dea7b0 VS |
674 | MISSING_CASE(fb->format->format); |
675 | return 0; | |
b840d907 JB |
676 | } |
677 | ||
b0f5c0ba VS |
678 | if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) |
679 | sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709; | |
680 | ||
c8624ede VS |
681 | if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) |
682 | sprctl |= SPRITE_YUV_RANGE_CORRECTION_DISABLE; | |
683 | ||
bae781b2 | 684 | if (fb->modifier == I915_FORMAT_MOD_X_TILED) |
b840d907 JB |
685 | sprctl |= SPRITE_TILED; |
686 | ||
c2c446ad | 687 | if (rotation & DRM_MODE_ROTATE_180) |
df0cd455 VS |
688 | sprctl |= SPRITE_ROTATE_180; |
689 | ||
78587de2 VS |
690 | if (key->flags & I915_SET_COLORKEY_DESTINATION) |
691 | sprctl |= SPRITE_DEST_KEY; | |
692 | else if (key->flags & I915_SET_COLORKEY_SOURCE) | |
693 | sprctl |= SPRITE_SOURCE_KEY; | |
694 | ||
45dea7b0 VS |
695 | return sprctl; |
696 | } | |
697 | ||
698 | static void | |
282dbf9b | 699 | ivb_update_plane(struct intel_plane *plane, |
45dea7b0 VS |
700 | const struct intel_crtc_state *crtc_state, |
701 | const struct intel_plane_state *plane_state) | |
702 | { | |
282dbf9b VS |
703 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
704 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
705 | enum pipe pipe = plane->pipe; | |
a0864d59 | 706 | u32 sprctl = plane_state->ctl, sprscale = 0; |
f9407ae1 VS |
707 | u32 sprsurf_offset = plane_state->main.offset; |
708 | u32 linear_offset; | |
45dea7b0 VS |
709 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
710 | int crtc_x = plane_state->base.dst.x1; | |
711 | int crtc_y = plane_state->base.dst.y1; | |
712 | uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); | |
713 | uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); | |
f9407ae1 VS |
714 | uint32_t x = plane_state->main.x; |
715 | uint32_t y = plane_state->main.y; | |
45dea7b0 VS |
716 | uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; |
717 | uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; | |
718 | unsigned long irqflags; | |
719 | ||
b840d907 JB |
720 | /* Sizes are 0 based */ |
721 | src_w--; | |
722 | src_h--; | |
723 | crtc_w--; | |
724 | crtc_h--; | |
725 | ||
8553c18e | 726 | if (crtc_w != src_w || crtc_h != src_h) |
b840d907 | 727 | sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; |
b840d907 | 728 | |
2949056c | 729 | linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); |
6687c906 | 730 | |
dd584fc0 VS |
731 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
732 | ||
47ecbb20 | 733 | if (key->flags) { |
dd584fc0 VS |
734 | I915_WRITE_FW(SPRKEYVAL(pipe), key->min_value); |
735 | I915_WRITE_FW(SPRKEYMAX(pipe), key->max_value); | |
736 | I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask); | |
47ecbb20 VS |
737 | } |
738 | ||
dd584fc0 VS |
739 | I915_WRITE_FW(SPRSTRIDE(pipe), fb->pitches[0]); |
740 | I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x); | |
ca6ad025 | 741 | |
5a35e99e DL |
742 | /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET |
743 | * register */ | |
8652744b | 744 | if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) |
dd584fc0 | 745 | I915_WRITE_FW(SPROFFSET(pipe), (y << 16) | x); |
bae781b2 | 746 | else if (fb->modifier == I915_FORMAT_MOD_X_TILED) |
dd584fc0 | 747 | I915_WRITE_FW(SPRTILEOFF(pipe), (y << 16) | x); |
5a35e99e | 748 | else |
dd584fc0 | 749 | I915_WRITE_FW(SPRLINOFF(pipe), linear_offset); |
c54173a8 | 750 | |
dd584fc0 | 751 | I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); |
282dbf9b | 752 | if (plane->can_scale) |
dd584fc0 VS |
753 | I915_WRITE_FW(SPRSCALE(pipe), sprscale); |
754 | I915_WRITE_FW(SPRCTL(pipe), sprctl); | |
755 | I915_WRITE_FW(SPRSURF(pipe), | |
756 | intel_plane_ggtt_offset(plane_state) + sprsurf_offset); | |
757 | POSTING_READ_FW(SPRSURF(pipe)); | |
758 | ||
759 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
b840d907 JB |
760 | } |
761 | ||
762 | static void | |
282dbf9b | 763 | ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) |
b840d907 | 764 | { |
282dbf9b VS |
765 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
766 | enum pipe pipe = plane->pipe; | |
dd584fc0 VS |
767 | unsigned long irqflags; |
768 | ||
769 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); | |
b840d907 | 770 | |
dd584fc0 | 771 | I915_WRITE_FW(SPRCTL(pipe), 0); |
b840d907 | 772 | /* Can't leave the scaler enabled... */ |
282dbf9b | 773 | if (plane->can_scale) |
dd584fc0 | 774 | I915_WRITE_FW(SPRSCALE(pipe), 0); |
5b633d6b | 775 | |
dd584fc0 VS |
776 | I915_WRITE_FW(SPRSURF(pipe), 0); |
777 | POSTING_READ_FW(SPRSURF(pipe)); | |
778 | ||
779 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
b840d907 JB |
780 | } |
781 | ||
51f5a096 | 782 | static bool |
eade6c89 VS |
783 | ivb_plane_get_hw_state(struct intel_plane *plane, |
784 | enum pipe *pipe) | |
51f5a096 VS |
785 | { |
786 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); | |
787 | enum intel_display_power_domain power_domain; | |
51f5a096 VS |
788 | bool ret; |
789 | ||
eade6c89 | 790 | power_domain = POWER_DOMAIN_PIPE(plane->pipe); |
51f5a096 VS |
791 | if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) |
792 | return false; | |
793 | ||
eade6c89 VS |
794 | ret = I915_READ(SPRCTL(plane->pipe)) & SPRITE_ENABLE; |
795 | ||
796 | *pipe = plane->pipe; | |
51f5a096 VS |
797 | |
798 | intel_display_power_put(dev_priv, power_domain); | |
799 | ||
800 | return ret; | |
801 | } | |
802 | ||
ab33081a | 803 | static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, |
0a375147 | 804 | const struct intel_plane_state *plane_state) |
b840d907 | 805 | { |
0a375147 VS |
806 | struct drm_i915_private *dev_priv = |
807 | to_i915(plane_state->base.plane->dev); | |
808 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
8d0deca8 | 809 | unsigned int rotation = plane_state->base.rotation; |
2fde1391 | 810 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
0a375147 VS |
811 | u32 dvscntr; |
812 | ||
813 | dvscntr = DVS_ENABLE | DVS_GAMMA_ENABLE; | |
b840d907 | 814 | |
0a375147 VS |
815 | if (IS_GEN6(dev_priv)) |
816 | dvscntr |= DVS_TRICKLE_FEED_DISABLE; | |
b840d907 | 817 | |
438b74a5 | 818 | switch (fb->format->format) { |
b840d907 | 819 | case DRM_FORMAT_XBGR8888: |
ab2f9df1 | 820 | dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; |
b840d907 JB |
821 | break; |
822 | case DRM_FORMAT_XRGB8888: | |
ab2f9df1 | 823 | dvscntr |= DVS_FORMAT_RGBX888; |
b840d907 JB |
824 | break; |
825 | case DRM_FORMAT_YUYV: | |
826 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; | |
b840d907 JB |
827 | break; |
828 | case DRM_FORMAT_YVYU: | |
829 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; | |
b840d907 JB |
830 | break; |
831 | case DRM_FORMAT_UYVY: | |
832 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; | |
b840d907 JB |
833 | break; |
834 | case DRM_FORMAT_VYUY: | |
835 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; | |
b840d907 JB |
836 | break; |
837 | default: | |
0a375147 VS |
838 | MISSING_CASE(fb->format->format); |
839 | return 0; | |
b840d907 JB |
840 | } |
841 | ||
b0f5c0ba VS |
842 | if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) |
843 | dvscntr |= DVS_YUV_FORMAT_BT709; | |
844 | ||
c8624ede VS |
845 | if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) |
846 | dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE; | |
847 | ||
bae781b2 | 848 | if (fb->modifier == I915_FORMAT_MOD_X_TILED) |
b840d907 JB |
849 | dvscntr |= DVS_TILED; |
850 | ||
c2c446ad | 851 | if (rotation & DRM_MODE_ROTATE_180) |
df0cd455 VS |
852 | dvscntr |= DVS_ROTATE_180; |
853 | ||
78587de2 VS |
854 | if (key->flags & I915_SET_COLORKEY_DESTINATION) |
855 | dvscntr |= DVS_DEST_KEY; | |
856 | else if (key->flags & I915_SET_COLORKEY_SOURCE) | |
857 | dvscntr |= DVS_SOURCE_KEY; | |
858 | ||
0a375147 VS |
859 | return dvscntr; |
860 | } | |
861 | ||
862 | static void | |
282dbf9b | 863 | g4x_update_plane(struct intel_plane *plane, |
0a375147 VS |
864 | const struct intel_crtc_state *crtc_state, |
865 | const struct intel_plane_state *plane_state) | |
866 | { | |
282dbf9b VS |
867 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
868 | const struct drm_framebuffer *fb = plane_state->base.fb; | |
869 | enum pipe pipe = plane->pipe; | |
f9407ae1 VS |
870 | u32 dvscntr = plane_state->ctl, dvsscale = 0; |
871 | u32 dvssurf_offset = plane_state->main.offset; | |
872 | u32 linear_offset; | |
0a375147 VS |
873 | const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; |
874 | int crtc_x = plane_state->base.dst.x1; | |
875 | int crtc_y = plane_state->base.dst.y1; | |
876 | uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); | |
877 | uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); | |
f9407ae1 VS |
878 | uint32_t x = plane_state->main.x; |
879 | uint32_t y = plane_state->main.y; | |
0a375147 VS |
880 | uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; |
881 | uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; | |
882 | unsigned long irqflags; | |
883 | ||
b840d907 JB |
884 | /* Sizes are 0 based */ |
885 | src_w--; | |
886 | src_h--; | |
887 | crtc_w--; | |
888 | crtc_h--; | |
889 | ||
8368f014 | 890 | if (crtc_w != src_w || crtc_h != src_h) |
b840d907 JB |
891 | dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; |
892 | ||
2949056c | 893 | linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); |
6687c906 | 894 | |
dd584fc0 VS |
895 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
896 | ||
47ecbb20 | 897 | if (key->flags) { |
dd584fc0 VS |
898 | I915_WRITE_FW(DVSKEYVAL(pipe), key->min_value); |
899 | I915_WRITE_FW(DVSKEYMAX(pipe), key->max_value); | |
900 | I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask); | |
47ecbb20 VS |
901 | } |
902 | ||
dd584fc0 VS |
903 | I915_WRITE_FW(DVSSTRIDE(pipe), fb->pitches[0]); |
904 | I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x); | |
ca6ad025 | 905 | |
bae781b2 | 906 | if (fb->modifier == I915_FORMAT_MOD_X_TILED) |
dd584fc0 | 907 | I915_WRITE_FW(DVSTILEOFF(pipe), (y << 16) | x); |
5a35e99e | 908 | else |
dd584fc0 VS |
909 | I915_WRITE_FW(DVSLINOFF(pipe), linear_offset); |
910 | ||
911 | I915_WRITE_FW(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); | |
912 | I915_WRITE_FW(DVSSCALE(pipe), dvsscale); | |
913 | I915_WRITE_FW(DVSCNTR(pipe), dvscntr); | |
914 | I915_WRITE_FW(DVSSURF(pipe), | |
915 | intel_plane_ggtt_offset(plane_state) + dvssurf_offset); | |
916 | POSTING_READ_FW(DVSSURF(pipe)); | |
917 | ||
918 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); | |
b840d907 JB |
919 | } |
920 | ||
921 | static void | |
282dbf9b | 922 | g4x_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) |
b840d907 | 923 | { |
282dbf9b VS |
924 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
925 | enum pipe pipe = plane->pipe; | |
dd584fc0 | 926 | unsigned long irqflags; |
b840d907 | 927 | |
dd584fc0 VS |
928 | spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
929 | ||
930 | I915_WRITE_FW(DVSCNTR(pipe), 0); | |
b840d907 | 931 | /* Disable the scaler */ |
dd584fc0 VS |
932 | I915_WRITE_FW(DVSSCALE(pipe), 0); |
933 | ||
934 | I915_WRITE_FW(DVSSURF(pipe), 0); | |
935 | POSTING_READ_FW(DVSSURF(pipe)); | |
48fe4691 | 936 | |
dd584fc0 | 937 | spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); |
b840d907 JB |
938 | } |
939 | ||
51f5a096 | 940 | static bool |
eade6c89 VS |
941 | g4x_plane_get_hw_state(struct intel_plane *plane, |
942 | enum pipe *pipe) | |
51f5a096 VS |
943 | { |
944 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); | |
945 | enum intel_display_power_domain power_domain; | |
51f5a096 VS |
946 | bool ret; |
947 | ||
eade6c89 | 948 | power_domain = POWER_DOMAIN_PIPE(plane->pipe); |
51f5a096 VS |
949 | if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) |
950 | return false; | |
951 | ||
eade6c89 VS |
952 | ret = I915_READ(DVSCNTR(plane->pipe)) & DVS_ENABLE; |
953 | ||
954 | *pipe = plane->pipe; | |
51f5a096 VS |
955 | |
956 | intel_display_power_put(dev_priv, power_domain); | |
957 | ||
958 | return ret; | |
959 | } | |
960 | ||
b840d907 | 961 | static int |
282dbf9b | 962 | intel_check_sprite_plane(struct intel_plane *plane, |
061e4b8d | 963 | struct intel_crtc_state *crtc_state, |
96d61a7f | 964 | struct intel_plane_state *state) |
b840d907 | 965 | { |
282dbf9b VS |
966 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
967 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); | |
2b875c22 | 968 | struct drm_framebuffer *fb = state->base.fb; |
8a97bbcc | 969 | int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384; |
1731693a | 970 | int max_scale, min_scale; |
225c228a | 971 | bool can_scale; |
b63a16f6 | 972 | int ret; |
77224cd5 | 973 | uint32_t pixel_format = 0; |
cf4c7c12 MR |
974 | |
975 | if (!fb) { | |
936e71e3 | 976 | state->base.visible = false; |
da20eabd | 977 | return 0; |
cf4c7c12 | 978 | } |
5e1bac2f | 979 | |
1731693a | 980 | /* Don't modify another pipe's plane */ |
282dbf9b | 981 | if (plane->pipe != crtc->pipe) { |
1731693a | 982 | DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); |
b840d907 | 983 | return -EINVAL; |
1731693a | 984 | } |
b840d907 | 985 | |
1731693a | 986 | /* FIXME check all gen limits */ |
8a97bbcc | 987 | if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > max_stride) { |
1731693a | 988 | DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); |
b840d907 | 989 | return -EINVAL; |
1731693a | 990 | } |
b840d907 | 991 | |
225c228a | 992 | /* setup can_scale, min_scale, max_scale */ |
55b8f2a7 | 993 | if (INTEL_GEN(dev_priv) >= 9) { |
77224cd5 CK |
994 | if (state->base.fb) |
995 | pixel_format = state->base.fb->format->format; | |
225c228a | 996 | /* use scaler when colorkey is not required */ |
6ec5bd34 | 997 | if (!state->ckey.flags) { |
225c228a CK |
998 | can_scale = 1; |
999 | min_scale = 1; | |
77224cd5 CK |
1000 | max_scale = |
1001 | skl_max_scale(crtc, crtc_state, pixel_format); | |
225c228a CK |
1002 | } else { |
1003 | can_scale = 0; | |
1004 | min_scale = DRM_PLANE_HELPER_NO_SCALING; | |
1005 | max_scale = DRM_PLANE_HELPER_NO_SCALING; | |
1006 | } | |
1007 | } else { | |
282dbf9b VS |
1008 | can_scale = plane->can_scale; |
1009 | max_scale = plane->max_downscale << 16; | |
1010 | min_scale = plane->can_scale ? 1 : (1 << 16); | |
225c228a CK |
1011 | } |
1012 | ||
9c1659eb ML |
1013 | ret = drm_atomic_helper_check_plane_state(&state->base, |
1014 | &crtc_state->base, | |
1015 | min_scale, max_scale, | |
1016 | true, true); | |
1017 | if (ret) | |
1018 | return ret; | |
2d354c34 | 1019 | |
936e71e3 | 1020 | if (state->base.visible) { |
9c1659eb ML |
1021 | struct drm_rect *src = &state->base.src; |
1022 | struct drm_rect *dst = &state->base.dst; | |
1023 | unsigned int crtc_w = drm_rect_width(dst); | |
1024 | unsigned int crtc_h = drm_rect_height(dst); | |
1025 | uint32_t src_x, src_y, src_w, src_h; | |
1731693a VS |
1026 | |
1027 | /* | |
1028 | * Hardware doesn't handle subpixel coordinates. | |
1029 | * Adjust to (macro)pixel boundary, but be careful not to | |
1030 | * increase the source viewport size, because that could | |
1031 | * push the downscaling factor out of bounds. | |
1731693a | 1032 | */ |
96d61a7f GP |
1033 | src_x = src->x1 >> 16; |
1034 | src_w = drm_rect_width(src) >> 16; | |
1035 | src_y = src->y1 >> 16; | |
1036 | src_h = drm_rect_height(src) >> 16; | |
1731693a | 1037 | |
9c1659eb ML |
1038 | src->x1 = src_x << 16; |
1039 | src->x2 = (src_x + src_w) << 16; | |
1040 | src->y1 = src_y << 16; | |
1041 | src->y2 = (src_y + src_h) << 16; | |
1731693a | 1042 | |
9c1659eb | 1043 | if (intel_format_is_yuv(fb->format->format) && |
b8a71080 | 1044 | fb->format->format != DRM_FORMAT_NV12 && |
9c1659eb ML |
1045 | (src_x % 2 || src_w % 2)) { |
1046 | DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n", | |
1047 | src_x, src_w); | |
1048 | return -EINVAL; | |
1731693a | 1049 | } |
1731693a | 1050 | |
9c1659eb ML |
1051 | /* Check size restrictions when scaling */ |
1052 | if (src_w != crtc_w || src_h != crtc_h) { | |
1053 | unsigned int width_bytes; | |
1054 | int cpp = fb->format->cpp[0]; | |
1731693a | 1055 | |
9c1659eb | 1056 | WARN_ON(!can_scale); |
1731693a | 1057 | |
9c1659eb | 1058 | width_bytes = ((src_x * cpp) & 63) + src_w * cpp; |
1731693a | 1059 | |
9c1659eb ML |
1060 | /* FIXME interlacing min height is 6 */ |
1061 | if (INTEL_GEN(dev_priv) < 9 && ( | |
1062 | src_w < 3 || src_h < 3 || | |
1063 | src_w > 2048 || src_h > 2048 || | |
1064 | crtc_w < 3 || crtc_h < 3 || | |
1065 | width_bytes > 4096 || fb->pitches[0] > 4096)) { | |
1066 | DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); | |
1067 | return -EINVAL; | |
1068 | } | |
1731693a VS |
1069 | } |
1070 | } | |
1071 | ||
55b8f2a7 | 1072 | if (INTEL_GEN(dev_priv) >= 9) { |
c322c649 | 1073 | ret = skl_check_plane_surface(crtc_state, state); |
b63a16f6 VS |
1074 | if (ret) |
1075 | return ret; | |
a0864d59 VS |
1076 | |
1077 | state->ctl = skl_plane_ctl(crtc_state, state); | |
1078 | } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { | |
f9407ae1 VS |
1079 | ret = i9xx_check_plane_surface(state); |
1080 | if (ret) | |
1081 | return ret; | |
1082 | ||
a0864d59 VS |
1083 | state->ctl = vlv_sprite_ctl(crtc_state, state); |
1084 | } else if (INTEL_GEN(dev_priv) >= 7) { | |
f9407ae1 VS |
1085 | ret = i9xx_check_plane_surface(state); |
1086 | if (ret) | |
1087 | return ret; | |
1088 | ||
a0864d59 VS |
1089 | state->ctl = ivb_sprite_ctl(crtc_state, state); |
1090 | } else { | |
f9407ae1 VS |
1091 | ret = i9xx_check_plane_surface(state); |
1092 | if (ret) | |
1093 | return ret; | |
1094 | ||
ab33081a | 1095 | state->ctl = g4x_sprite_ctl(crtc_state, state); |
b63a16f6 VS |
1096 | } |
1097 | ||
4036c78c JA |
1098 | if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) |
1099 | state->color_ctl = glk_plane_color_ctl(crtc_state, state); | |
1100 | ||
96d61a7f GP |
1101 | return 0; |
1102 | } | |
1103 | ||
6a20fe7b VS |
1104 | int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, |
1105 | struct drm_file *file_priv) | |
8ea30864 | 1106 | { |
920a14b2 | 1107 | struct drm_i915_private *dev_priv = to_i915(dev); |
8ea30864 | 1108 | struct drm_intel_sprite_colorkey *set = data; |
8ea30864 | 1109 | struct drm_plane *plane; |
818ed961 ML |
1110 | struct drm_plane_state *plane_state; |
1111 | struct drm_atomic_state *state; | |
1112 | struct drm_modeset_acquire_ctx ctx; | |
8ea30864 JB |
1113 | int ret = 0; |
1114 | ||
6ec5bd34 VS |
1115 | /* ignore the pointless "none" flag */ |
1116 | set->flags &= ~I915_SET_COLORKEY_NONE; | |
1117 | ||
89746e79 VS |
1118 | if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) |
1119 | return -EINVAL; | |
1120 | ||
8ea30864 JB |
1121 | /* Make sure we don't try to enable both src & dest simultaneously */ |
1122 | if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) | |
1123 | return -EINVAL; | |
1124 | ||
920a14b2 | 1125 | if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && |
47ecbb20 VS |
1126 | set->flags & I915_SET_COLORKEY_DESTINATION) |
1127 | return -EINVAL; | |
1128 | ||
418da172 | 1129 | plane = drm_plane_find(dev, file_priv, set->plane_id); |
818ed961 ML |
1130 | if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) |
1131 | return -ENOENT; | |
8ea30864 | 1132 | |
818ed961 | 1133 | drm_modeset_acquire_init(&ctx, 0); |
6156a456 | 1134 | |
818ed961 ML |
1135 | state = drm_atomic_state_alloc(plane->dev); |
1136 | if (!state) { | |
1137 | ret = -ENOMEM; | |
1138 | goto out; | |
6156a456 | 1139 | } |
818ed961 ML |
1140 | state->acquire_ctx = &ctx; |
1141 | ||
1142 | while (1) { | |
1143 | plane_state = drm_atomic_get_plane_state(state, plane); | |
1144 | ret = PTR_ERR_OR_ZERO(plane_state); | |
1145 | if (!ret) { | |
1146 | to_intel_plane_state(plane_state)->ckey = *set; | |
1147 | ret = drm_atomic_commit(state); | |
1148 | } | |
6156a456 | 1149 | |
818ed961 ML |
1150 | if (ret != -EDEADLK) |
1151 | break; | |
8ea30864 | 1152 | |
818ed961 ML |
1153 | drm_atomic_state_clear(state); |
1154 | drm_modeset_backoff(&ctx); | |
1155 | } | |
8ea30864 | 1156 | |
0853695c | 1157 | drm_atomic_state_put(state); |
818ed961 ML |
1158 | out: |
1159 | drm_modeset_drop_locks(&ctx); | |
1160 | drm_modeset_acquire_fini(&ctx); | |
1161 | return ret; | |
5e1bac2f JB |
1162 | } |
1163 | ||
ab33081a | 1164 | static const uint32_t g4x_plane_formats[] = { |
d1686ae3 CW |
1165 | DRM_FORMAT_XRGB8888, |
1166 | DRM_FORMAT_YUYV, | |
1167 | DRM_FORMAT_YVYU, | |
1168 | DRM_FORMAT_UYVY, | |
1169 | DRM_FORMAT_VYUY, | |
1170 | }; | |
1171 | ||
714244e2 BW |
1172 | static const uint64_t i9xx_plane_format_modifiers[] = { |
1173 | I915_FORMAT_MOD_X_TILED, | |
1174 | DRM_FORMAT_MOD_LINEAR, | |
1175 | DRM_FORMAT_MOD_INVALID | |
1176 | }; | |
1177 | ||
dada2d53 | 1178 | static const uint32_t snb_plane_formats[] = { |
b840d907 JB |
1179 | DRM_FORMAT_XBGR8888, |
1180 | DRM_FORMAT_XRGB8888, | |
1181 | DRM_FORMAT_YUYV, | |
1182 | DRM_FORMAT_YVYU, | |
1183 | DRM_FORMAT_UYVY, | |
1184 | DRM_FORMAT_VYUY, | |
1185 | }; | |
1186 | ||
dada2d53 | 1187 | static const uint32_t vlv_plane_formats[] = { |
7f1f3851 JB |
1188 | DRM_FORMAT_RGB565, |
1189 | DRM_FORMAT_ABGR8888, | |
1190 | DRM_FORMAT_ARGB8888, | |
1191 | DRM_FORMAT_XBGR8888, | |
1192 | DRM_FORMAT_XRGB8888, | |
1193 | DRM_FORMAT_XBGR2101010, | |
1194 | DRM_FORMAT_ABGR2101010, | |
1195 | DRM_FORMAT_YUYV, | |
1196 | DRM_FORMAT_YVYU, | |
1197 | DRM_FORMAT_UYVY, | |
1198 | DRM_FORMAT_VYUY, | |
1199 | }; | |
1200 | ||
dc2a41b4 DL |
1201 | static uint32_t skl_plane_formats[] = { |
1202 | DRM_FORMAT_RGB565, | |
1203 | DRM_FORMAT_ABGR8888, | |
1204 | DRM_FORMAT_ARGB8888, | |
1205 | DRM_FORMAT_XBGR8888, | |
1206 | DRM_FORMAT_XRGB8888, | |
1207 | DRM_FORMAT_YUYV, | |
1208 | DRM_FORMAT_YVYU, | |
1209 | DRM_FORMAT_UYVY, | |
1210 | DRM_FORMAT_VYUY, | |
1211 | }; | |
1212 | ||
429204f1 CK |
1213 | static uint32_t skl_planar_formats[] = { |
1214 | DRM_FORMAT_RGB565, | |
1215 | DRM_FORMAT_ABGR8888, | |
1216 | DRM_FORMAT_ARGB8888, | |
1217 | DRM_FORMAT_XBGR8888, | |
1218 | DRM_FORMAT_XRGB8888, | |
1219 | DRM_FORMAT_YUYV, | |
1220 | DRM_FORMAT_YVYU, | |
1221 | DRM_FORMAT_UYVY, | |
1222 | DRM_FORMAT_VYUY, | |
1223 | DRM_FORMAT_NV12, | |
1224 | }; | |
1225 | ||
77064e2e VS |
1226 | static const uint64_t skl_plane_format_modifiers_noccs[] = { |
1227 | I915_FORMAT_MOD_Yf_TILED, | |
1228 | I915_FORMAT_MOD_Y_TILED, | |
1229 | I915_FORMAT_MOD_X_TILED, | |
1230 | DRM_FORMAT_MOD_LINEAR, | |
1231 | DRM_FORMAT_MOD_INVALID | |
1232 | }; | |
1233 | ||
1234 | static const uint64_t skl_plane_format_modifiers_ccs[] = { | |
1235 | I915_FORMAT_MOD_Yf_TILED_CCS, | |
1236 | I915_FORMAT_MOD_Y_TILED_CCS, | |
74ac160b VS |
1237 | I915_FORMAT_MOD_Yf_TILED, |
1238 | I915_FORMAT_MOD_Y_TILED, | |
714244e2 BW |
1239 | I915_FORMAT_MOD_X_TILED, |
1240 | DRM_FORMAT_MOD_LINEAR, | |
1241 | DRM_FORMAT_MOD_INVALID | |
1242 | }; | |
1243 | ||
a38189c5 VS |
1244 | static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane, |
1245 | u32 format, u64 modifier) | |
714244e2 | 1246 | { |
a38189c5 VS |
1247 | switch (modifier) { |
1248 | case DRM_FORMAT_MOD_LINEAR: | |
1249 | case I915_FORMAT_MOD_X_TILED: | |
1250 | break; | |
1251 | default: | |
1252 | return false; | |
1253 | } | |
1254 | ||
714244e2 | 1255 | switch (format) { |
714244e2 BW |
1256 | case DRM_FORMAT_XRGB8888: |
1257 | case DRM_FORMAT_YUYV: | |
1258 | case DRM_FORMAT_YVYU: | |
1259 | case DRM_FORMAT_UYVY: | |
1260 | case DRM_FORMAT_VYUY: | |
1261 | if (modifier == DRM_FORMAT_MOD_LINEAR || | |
1262 | modifier == I915_FORMAT_MOD_X_TILED) | |
1263 | return true; | |
1264 | /* fall through */ | |
1265 | default: | |
1266 | return false; | |
1267 | } | |
1268 | } | |
1269 | ||
a38189c5 VS |
1270 | static bool snb_sprite_format_mod_supported(struct drm_plane *_plane, |
1271 | u32 format, u64 modifier) | |
714244e2 | 1272 | { |
a38189c5 VS |
1273 | switch (modifier) { |
1274 | case DRM_FORMAT_MOD_LINEAR: | |
1275 | case I915_FORMAT_MOD_X_TILED: | |
1276 | break; | |
1277 | default: | |
1278 | return false; | |
1279 | } | |
1280 | ||
714244e2 | 1281 | switch (format) { |
c21f7904 VS |
1282 | case DRM_FORMAT_XRGB8888: |
1283 | case DRM_FORMAT_XBGR8888: | |
714244e2 BW |
1284 | case DRM_FORMAT_YUYV: |
1285 | case DRM_FORMAT_YVYU: | |
1286 | case DRM_FORMAT_UYVY: | |
1287 | case DRM_FORMAT_VYUY: | |
c21f7904 VS |
1288 | if (modifier == DRM_FORMAT_MOD_LINEAR || |
1289 | modifier == I915_FORMAT_MOD_X_TILED) | |
1290 | return true; | |
1291 | /* fall through */ | |
1292 | default: | |
1293 | return false; | |
1294 | } | |
1295 | } | |
1296 | ||
a38189c5 VS |
1297 | static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane, |
1298 | u32 format, u64 modifier) | |
c21f7904 | 1299 | { |
a38189c5 VS |
1300 | switch (modifier) { |
1301 | case DRM_FORMAT_MOD_LINEAR: | |
1302 | case I915_FORMAT_MOD_X_TILED: | |
1303 | break; | |
1304 | default: | |
1305 | return false; | |
1306 | } | |
1307 | ||
c21f7904 | 1308 | switch (format) { |
714244e2 | 1309 | case DRM_FORMAT_RGB565: |
c21f7904 | 1310 | case DRM_FORMAT_ABGR8888: |
714244e2 | 1311 | case DRM_FORMAT_ARGB8888: |
c21f7904 VS |
1312 | case DRM_FORMAT_XBGR8888: |
1313 | case DRM_FORMAT_XRGB8888: | |
714244e2 BW |
1314 | case DRM_FORMAT_XBGR2101010: |
1315 | case DRM_FORMAT_ABGR2101010: | |
c21f7904 VS |
1316 | case DRM_FORMAT_YUYV: |
1317 | case DRM_FORMAT_YVYU: | |
1318 | case DRM_FORMAT_UYVY: | |
1319 | case DRM_FORMAT_VYUY: | |
714244e2 BW |
1320 | if (modifier == DRM_FORMAT_MOD_LINEAR || |
1321 | modifier == I915_FORMAT_MOD_X_TILED) | |
1322 | return true; | |
1323 | /* fall through */ | |
1324 | default: | |
1325 | return false; | |
1326 | } | |
1327 | } | |
1328 | ||
a38189c5 VS |
1329 | static bool skl_plane_format_mod_supported(struct drm_plane *_plane, |
1330 | u32 format, u64 modifier) | |
714244e2 | 1331 | { |
a38189c5 VS |
1332 | struct intel_plane *plane = to_intel_plane(_plane); |
1333 | ||
1334 | switch (modifier) { | |
1335 | case DRM_FORMAT_MOD_LINEAR: | |
1336 | case I915_FORMAT_MOD_X_TILED: | |
1337 | case I915_FORMAT_MOD_Y_TILED: | |
1338 | case I915_FORMAT_MOD_Yf_TILED: | |
1339 | break; | |
1340 | case I915_FORMAT_MOD_Y_TILED_CCS: | |
1341 | case I915_FORMAT_MOD_Yf_TILED_CCS: | |
1342 | if (!plane->has_ccs) | |
1343 | return false; | |
1344 | break; | |
1345 | default: | |
1346 | return false; | |
1347 | } | |
1348 | ||
714244e2 BW |
1349 | switch (format) { |
1350 | case DRM_FORMAT_XRGB8888: | |
1351 | case DRM_FORMAT_XBGR8888: | |
1352 | case DRM_FORMAT_ARGB8888: | |
1353 | case DRM_FORMAT_ABGR8888: | |
77064e2e VS |
1354 | if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS || |
1355 | modifier == I915_FORMAT_MOD_Y_TILED_CCS) | |
1356 | return true; | |
1357 | /* fall through */ | |
714244e2 BW |
1358 | case DRM_FORMAT_RGB565: |
1359 | case DRM_FORMAT_XRGB2101010: | |
1360 | case DRM_FORMAT_XBGR2101010: | |
1361 | case DRM_FORMAT_YUYV: | |
1362 | case DRM_FORMAT_YVYU: | |
1363 | case DRM_FORMAT_UYVY: | |
1364 | case DRM_FORMAT_VYUY: | |
429204f1 | 1365 | case DRM_FORMAT_NV12: |
714244e2 BW |
1366 | if (modifier == I915_FORMAT_MOD_Yf_TILED) |
1367 | return true; | |
1368 | /* fall through */ | |
1369 | case DRM_FORMAT_C8: | |
1370 | if (modifier == DRM_FORMAT_MOD_LINEAR || | |
1371 | modifier == I915_FORMAT_MOD_X_TILED || | |
1372 | modifier == I915_FORMAT_MOD_Y_TILED) | |
1373 | return true; | |
1374 | /* fall through */ | |
1375 | default: | |
1376 | return false; | |
1377 | } | |
1378 | } | |
1379 | ||
a38189c5 VS |
1380 | static const struct drm_plane_funcs g4x_sprite_funcs = { |
1381 | .update_plane = drm_atomic_helper_update_plane, | |
1382 | .disable_plane = drm_atomic_helper_disable_plane, | |
1383 | .destroy = intel_plane_destroy, | |
1384 | .atomic_get_property = intel_plane_atomic_get_property, | |
1385 | .atomic_set_property = intel_plane_atomic_set_property, | |
1386 | .atomic_duplicate_state = intel_plane_duplicate_state, | |
1387 | .atomic_destroy_state = intel_plane_destroy_state, | |
1388 | .format_mod_supported = g4x_sprite_format_mod_supported, | |
1389 | }; | |
714244e2 | 1390 | |
a38189c5 VS |
1391 | static const struct drm_plane_funcs snb_sprite_funcs = { |
1392 | .update_plane = drm_atomic_helper_update_plane, | |
1393 | .disable_plane = drm_atomic_helper_disable_plane, | |
1394 | .destroy = intel_plane_destroy, | |
1395 | .atomic_get_property = intel_plane_atomic_get_property, | |
1396 | .atomic_set_property = intel_plane_atomic_set_property, | |
1397 | .atomic_duplicate_state = intel_plane_duplicate_state, | |
1398 | .atomic_destroy_state = intel_plane_destroy_state, | |
1399 | .format_mod_supported = snb_sprite_format_mod_supported, | |
1400 | }; | |
714244e2 | 1401 | |
a38189c5 VS |
1402 | static const struct drm_plane_funcs vlv_sprite_funcs = { |
1403 | .update_plane = drm_atomic_helper_update_plane, | |
1404 | .disable_plane = drm_atomic_helper_disable_plane, | |
1405 | .destroy = intel_plane_destroy, | |
1406 | .atomic_get_property = intel_plane_atomic_get_property, | |
1407 | .atomic_set_property = intel_plane_atomic_set_property, | |
1408 | .atomic_duplicate_state = intel_plane_duplicate_state, | |
1409 | .atomic_destroy_state = intel_plane_destroy_state, | |
1410 | .format_mod_supported = vlv_sprite_format_mod_supported, | |
1411 | }; | |
714244e2 | 1412 | |
a38189c5 | 1413 | static const struct drm_plane_funcs skl_plane_funcs = { |
b4686c48 VS |
1414 | .update_plane = drm_atomic_helper_update_plane, |
1415 | .disable_plane = drm_atomic_helper_disable_plane, | |
1416 | .destroy = intel_plane_destroy, | |
1417 | .atomic_get_property = intel_plane_atomic_get_property, | |
1418 | .atomic_set_property = intel_plane_atomic_set_property, | |
1419 | .atomic_duplicate_state = intel_plane_duplicate_state, | |
1420 | .atomic_destroy_state = intel_plane_destroy_state, | |
a38189c5 | 1421 | .format_mod_supported = skl_plane_format_mod_supported, |
714244e2 BW |
1422 | }; |
1423 | ||
77064e2e VS |
1424 | bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, |
1425 | enum pipe pipe, enum plane_id plane_id) | |
1426 | { | |
1427 | if (plane_id == PLANE_CURSOR) | |
1428 | return false; | |
1429 | ||
1430 | if (INTEL_GEN(dev_priv) >= 10) | |
1431 | return true; | |
1432 | ||
1433 | if (IS_GEMINILAKE(dev_priv)) | |
1434 | return pipe != PIPE_C; | |
1435 | ||
1436 | return pipe != PIPE_C && | |
1437 | (plane_id == PLANE_PRIMARY || | |
1438 | plane_id == PLANE_SPRITE0); | |
1439 | } | |
1440 | ||
b079bd17 | 1441 | struct intel_plane * |
580503c7 VS |
1442 | intel_sprite_plane_create(struct drm_i915_private *dev_priv, |
1443 | enum pipe pipe, int plane) | |
b840d907 | 1444 | { |
fca0ce2a VS |
1445 | struct intel_plane *intel_plane = NULL; |
1446 | struct intel_plane_state *state = NULL; | |
a38189c5 | 1447 | const struct drm_plane_funcs *plane_funcs; |
b840d907 | 1448 | unsigned long possible_crtcs; |
d1686ae3 | 1449 | const uint32_t *plane_formats; |
714244e2 | 1450 | const uint64_t *modifiers; |
93ca7e00 | 1451 | unsigned int supported_rotations; |
d1686ae3 | 1452 | int num_plane_formats; |
b840d907 JB |
1453 | int ret; |
1454 | ||
b14c5679 | 1455 | intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL); |
fca0ce2a VS |
1456 | if (!intel_plane) { |
1457 | ret = -ENOMEM; | |
1458 | goto fail; | |
1459 | } | |
b840d907 | 1460 | |
8e7d688b MR |
1461 | state = intel_create_plane_state(&intel_plane->base); |
1462 | if (!state) { | |
fca0ce2a VS |
1463 | ret = -ENOMEM; |
1464 | goto fail; | |
ea2c67bb | 1465 | } |
8e7d688b | 1466 | intel_plane->base.state = &state->base; |
ea2c67bb | 1467 | |
77064e2e | 1468 | if (INTEL_GEN(dev_priv) >= 9) { |
714244e2 BW |
1469 | intel_plane->can_scale = true; |
1470 | state->scaler_id = -1; | |
1471 | ||
a38189c5 VS |
1472 | intel_plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, |
1473 | PLANE_SPRITE0 + plane); | |
1474 | ||
714244e2 BW |
1475 | intel_plane->update_plane = skl_update_plane; |
1476 | intel_plane->disable_plane = skl_disable_plane; | |
51f5a096 | 1477 | intel_plane->get_hw_state = skl_plane_get_hw_state; |
714244e2 | 1478 | |
429204f1 CK |
1479 | if (skl_plane_has_planar(dev_priv, pipe, |
1480 | PLANE_SPRITE0 + plane)) { | |
1481 | plane_formats = skl_planar_formats; | |
1482 | num_plane_formats = ARRAY_SIZE(skl_planar_formats); | |
1483 | } else { | |
1484 | plane_formats = skl_plane_formats; | |
1485 | num_plane_formats = ARRAY_SIZE(skl_plane_formats); | |
1486 | } | |
d1686ae3 | 1487 | |
a38189c5 | 1488 | if (intel_plane->has_ccs) |
77064e2e VS |
1489 | modifiers = skl_plane_format_modifiers_ccs; |
1490 | else | |
1491 | modifiers = skl_plane_format_modifiers_noccs; | |
a38189c5 VS |
1492 | |
1493 | plane_funcs = &skl_plane_funcs; | |
1890ae64 VS |
1494 | } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { |
1495 | intel_plane->can_scale = false; | |
1496 | intel_plane->max_downscale = 1; | |
1497 | ||
1498 | intel_plane->update_plane = vlv_update_plane; | |
1499 | intel_plane->disable_plane = vlv_disable_plane; | |
51f5a096 | 1500 | intel_plane->get_hw_state = vlv_plane_get_hw_state; |
d1686ae3 | 1501 | |
1890ae64 VS |
1502 | plane_formats = vlv_plane_formats; |
1503 | num_plane_formats = ARRAY_SIZE(vlv_plane_formats); | |
714244e2 | 1504 | modifiers = i9xx_plane_format_modifiers; |
a38189c5 VS |
1505 | |
1506 | plane_funcs = &vlv_sprite_funcs; | |
1890ae64 | 1507 | } else if (INTEL_GEN(dev_priv) >= 7) { |
920a14b2 | 1508 | if (IS_IVYBRIDGE(dev_priv)) { |
2d354c34 | 1509 | intel_plane->can_scale = true; |
d49f7091 DL |
1510 | intel_plane->max_downscale = 2; |
1511 | } else { | |
1512 | intel_plane->can_scale = false; | |
1513 | intel_plane->max_downscale = 1; | |
1514 | } | |
7f1f3851 | 1515 | |
1890ae64 VS |
1516 | intel_plane->update_plane = ivb_update_plane; |
1517 | intel_plane->disable_plane = ivb_disable_plane; | |
51f5a096 | 1518 | intel_plane->get_hw_state = ivb_plane_get_hw_state; |
7f1f3851 | 1519 | |
1890ae64 VS |
1520 | plane_formats = snb_plane_formats; |
1521 | num_plane_formats = ARRAY_SIZE(snb_plane_formats); | |
714244e2 | 1522 | modifiers = i9xx_plane_format_modifiers; |
a38189c5 VS |
1523 | |
1524 | plane_funcs = &snb_sprite_funcs; | |
1890ae64 VS |
1525 | } else { |
1526 | intel_plane->can_scale = true; | |
1527 | intel_plane->max_downscale = 16; | |
1528 | ||
ab33081a VS |
1529 | intel_plane->update_plane = g4x_update_plane; |
1530 | intel_plane->disable_plane = g4x_disable_plane; | |
51f5a096 | 1531 | intel_plane->get_hw_state = g4x_plane_get_hw_state; |
7f1f3851 | 1532 | |
714244e2 | 1533 | modifiers = i9xx_plane_format_modifiers; |
1890ae64 | 1534 | if (IS_GEN6(dev_priv)) { |
7f1f3851 JB |
1535 | plane_formats = snb_plane_formats; |
1536 | num_plane_formats = ARRAY_SIZE(snb_plane_formats); | |
a38189c5 VS |
1537 | |
1538 | plane_funcs = &snb_sprite_funcs; | |
1890ae64 | 1539 | } else { |
ab33081a VS |
1540 | plane_formats = g4x_plane_formats; |
1541 | num_plane_formats = ARRAY_SIZE(g4x_plane_formats); | |
a38189c5 VS |
1542 | |
1543 | plane_funcs = &g4x_sprite_funcs; | |
7f1f3851 | 1544 | } |
b840d907 JB |
1545 | } |
1546 | ||
5481e27f | 1547 | if (INTEL_GEN(dev_priv) >= 9) { |
93ca7e00 | 1548 | supported_rotations = |
c2c446ad RF |
1549 | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | |
1550 | DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; | |
4ea7be2b VS |
1551 | } else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) { |
1552 | supported_rotations = | |
c2c446ad RF |
1553 | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | |
1554 | DRM_MODE_REFLECT_X; | |
93ca7e00 VS |
1555 | } else { |
1556 | supported_rotations = | |
c2c446ad | 1557 | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180; |
93ca7e00 VS |
1558 | } |
1559 | ||
b840d907 | 1560 | intel_plane->pipe = pipe; |
ed15030d | 1561 | intel_plane->i9xx_plane = plane; |
b14e5848 | 1562 | intel_plane->id = PLANE_SPRITE0 + plane; |
c19e1124 | 1563 | intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id); |
c59cb179 | 1564 | intel_plane->check_plane = intel_check_sprite_plane; |
fca0ce2a | 1565 | |
b840d907 | 1566 | possible_crtcs = (1 << pipe); |
fca0ce2a | 1567 | |
1890ae64 | 1568 | if (INTEL_GEN(dev_priv) >= 9) |
580503c7 | 1569 | ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base, |
a38189c5 | 1570 | possible_crtcs, plane_funcs, |
38573dc1 | 1571 | plane_formats, num_plane_formats, |
714244e2 BW |
1572 | modifiers, |
1573 | DRM_PLANE_TYPE_OVERLAY, | |
38573dc1 VS |
1574 | "plane %d%c", plane + 2, pipe_name(pipe)); |
1575 | else | |
580503c7 | 1576 | ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base, |
a38189c5 | 1577 | possible_crtcs, plane_funcs, |
38573dc1 | 1578 | plane_formats, num_plane_formats, |
714244e2 BW |
1579 | modifiers, |
1580 | DRM_PLANE_TYPE_OVERLAY, | |
38573dc1 | 1581 | "sprite %c", sprite_name(pipe, plane)); |
fca0ce2a VS |
1582 | if (ret) |
1583 | goto fail; | |
7ed6eeee | 1584 | |
93ca7e00 | 1585 | drm_plane_create_rotation_property(&intel_plane->base, |
c2c446ad | 1586 | DRM_MODE_ROTATE_0, |
93ca7e00 | 1587 | supported_rotations); |
b840d907 | 1588 | |
b0f5c0ba VS |
1589 | drm_plane_create_color_properties(&intel_plane->base, |
1590 | BIT(DRM_COLOR_YCBCR_BT601) | | |
1591 | BIT(DRM_COLOR_YCBCR_BT709), | |
c8624ede VS |
1592 | BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | |
1593 | BIT(DRM_COLOR_YCBCR_FULL_RANGE), | |
23b28089 | 1594 | DRM_COLOR_YCBCR_BT709, |
b0f5c0ba VS |
1595 | DRM_COLOR_YCBCR_LIMITED_RANGE); |
1596 | ||
ea2c67bb MR |
1597 | drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); |
1598 | ||
b079bd17 | 1599 | return intel_plane; |
fca0ce2a VS |
1600 | |
1601 | fail: | |
1602 | kfree(state); | |
1603 | kfree(intel_plane); | |
1604 | ||
b079bd17 | 1605 | return ERR_PTR(ret); |
b840d907 | 1606 | } |