Rev 2344 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2342 | Serge | 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 |
||
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 | */ |
||
32 | #include "drmP.h" |
||
33 | #include "drm_crtc.h" |
||
34 | #include "drm_fourcc.h" |
||
35 | #include "intel_drv.h" |
||
36 | #include "i915_drm.h" |
||
37 | #include "i915_drv.h" |
||
38 | |||
39 | static void |
||
40 | ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, |
||
41 | struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, |
||
42 | unsigned int crtc_w, unsigned int crtc_h, |
||
43 | uint32_t x, uint32_t y, |
||
44 | uint32_t src_w, uint32_t src_h) |
||
45 | { |
||
46 | struct drm_device *dev = plane->dev; |
||
47 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
48 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
49 | int pipe = intel_plane->pipe; |
||
50 | u32 sprctl, sprscale = 0; |
||
51 | int pixel_size; |
||
52 | |||
53 | sprctl = I915_READ(SPRCTL(pipe)); |
||
54 | |||
55 | /* Mask out pixel format bits in case we change it */ |
||
56 | sprctl &= ~SPRITE_PIXFORMAT_MASK; |
||
57 | sprctl &= ~SPRITE_RGB_ORDER_RGBX; |
||
58 | sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; |
||
59 | |||
60 | switch (fb->pixel_format) { |
||
61 | case DRM_FORMAT_XBGR8888: |
||
62 | sprctl |= SPRITE_FORMAT_RGBX888; |
||
63 | pixel_size = 4; |
||
64 | break; |
||
65 | case DRM_FORMAT_XRGB8888: |
||
66 | sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; |
||
67 | pixel_size = 4; |
||
68 | break; |
||
69 | case DRM_FORMAT_YUYV: |
||
70 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; |
||
71 | pixel_size = 2; |
||
72 | break; |
||
73 | case DRM_FORMAT_YVYU: |
||
74 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; |
||
75 | pixel_size = 2; |
||
76 | break; |
||
77 | case DRM_FORMAT_UYVY: |
||
78 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; |
||
79 | pixel_size = 2; |
||
80 | break; |
||
81 | case DRM_FORMAT_VYUY: |
||
82 | sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; |
||
83 | pixel_size = 2; |
||
84 | break; |
||
85 | default: |
||
86 | DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); |
||
87 | sprctl |= DVS_FORMAT_RGBX888; |
||
88 | pixel_size = 4; |
||
89 | break; |
||
90 | } |
||
91 | |||
92 | if (obj->tiling_mode != I915_TILING_NONE) |
||
93 | sprctl |= SPRITE_TILED; |
||
94 | |||
95 | /* must disable */ |
||
96 | sprctl |= SPRITE_TRICKLE_FEED_DISABLE; |
||
97 | sprctl |= SPRITE_ENABLE; |
||
98 | sprctl |= SPRITE_DEST_KEY; |
||
99 | |||
100 | /* Sizes are 0 based */ |
||
101 | src_w--; |
||
102 | src_h--; |
||
103 | crtc_w--; |
||
104 | crtc_h--; |
||
105 | |||
106 | intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); |
||
107 | |||
108 | /* |
||
109 | * IVB workaround: must disable low power watermarks for at least |
||
110 | * one frame before enabling scaling. LP watermarks can be re-enabled |
||
111 | * when scaling is disabled. |
||
112 | */ |
||
113 | if (crtc_w != src_w || crtc_h != src_h) { |
||
114 | dev_priv->sprite_scaling_enabled = true; |
||
115 | sandybridge_update_wm(dev); |
||
116 | intel_wait_for_vblank(dev, pipe); |
||
117 | sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; |
||
118 | } else { |
||
119 | dev_priv->sprite_scaling_enabled = false; |
||
120 | /* potentially re-enable LP watermarks */ |
||
121 | sandybridge_update_wm(dev); |
||
122 | } |
||
123 | |||
124 | I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); |
||
125 | I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); |
||
126 | if (obj->tiling_mode != I915_TILING_NONE) { |
||
127 | I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); |
||
128 | } else { |
||
129 | unsigned long offset; |
||
130 | |||
131 | offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); |
||
132 | I915_WRITE(SPRLINOFF(pipe), offset); |
||
133 | } |
||
134 | I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); |
||
135 | I915_WRITE(SPRSCALE(pipe), sprscale); |
||
136 | I915_WRITE(SPRCTL(pipe), sprctl); |
||
137 | I915_WRITE(SPRSURF(pipe), obj->gtt_offset); |
||
138 | POSTING_READ(SPRSURF(pipe)); |
||
139 | } |
||
140 | |||
141 | static void |
||
142 | ivb_disable_plane(struct drm_plane *plane) |
||
143 | { |
||
144 | struct drm_device *dev = plane->dev; |
||
145 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
146 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
147 | int pipe = intel_plane->pipe; |
||
148 | |||
149 | I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); |
||
150 | /* Can't leave the scaler enabled... */ |
||
151 | I915_WRITE(SPRSCALE(pipe), 0); |
||
152 | /* Activate double buffered register update */ |
||
153 | I915_WRITE(SPRSURF(pipe), 0); |
||
154 | POSTING_READ(SPRSURF(pipe)); |
||
155 | } |
||
156 | |||
157 | static int |
||
158 | ivb_update_colorkey(struct drm_plane *plane, |
||
159 | struct drm_intel_sprite_colorkey *key) |
||
160 | { |
||
161 | struct drm_device *dev = plane->dev; |
||
162 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
163 | struct intel_plane *intel_plane; |
||
164 | u32 sprctl; |
||
165 | int ret = 0; |
||
166 | |||
167 | intel_plane = to_intel_plane(plane); |
||
168 | |||
169 | I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); |
||
170 | I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); |
||
171 | I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); |
||
172 | |||
173 | sprctl = I915_READ(SPRCTL(intel_plane->pipe)); |
||
174 | sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); |
||
175 | if (key->flags & I915_SET_COLORKEY_DESTINATION) |
||
176 | sprctl |= SPRITE_DEST_KEY; |
||
177 | else if (key->flags & I915_SET_COLORKEY_SOURCE) |
||
178 | sprctl |= SPRITE_SOURCE_KEY; |
||
179 | I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); |
||
180 | |||
181 | POSTING_READ(SPRKEYMSK(intel_plane->pipe)); |
||
182 | |||
183 | return ret; |
||
184 | } |
||
185 | |||
186 | static void |
||
187 | ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) |
||
188 | { |
||
189 | struct drm_device *dev = plane->dev; |
||
190 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
191 | struct intel_plane *intel_plane; |
||
192 | u32 sprctl; |
||
193 | |||
194 | intel_plane = to_intel_plane(plane); |
||
195 | |||
196 | key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); |
||
197 | key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); |
||
198 | key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); |
||
199 | key->flags = 0; |
||
200 | |||
201 | sprctl = I915_READ(SPRCTL(intel_plane->pipe)); |
||
202 | |||
203 | if (sprctl & SPRITE_DEST_KEY) |
||
204 | key->flags = I915_SET_COLORKEY_DESTINATION; |
||
205 | else if (sprctl & SPRITE_SOURCE_KEY) |
||
206 | key->flags = I915_SET_COLORKEY_SOURCE; |
||
207 | else |
||
208 | key->flags = I915_SET_COLORKEY_NONE; |
||
209 | } |
||
210 | |||
211 | static void |
||
212 | snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, |
||
213 | struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, |
||
214 | unsigned int crtc_w, unsigned int crtc_h, |
||
215 | uint32_t x, uint32_t y, |
||
216 | uint32_t src_w, uint32_t src_h) |
||
217 | { |
||
218 | struct drm_device *dev = plane->dev; |
||
219 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
220 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
221 | int pipe = intel_plane->pipe, pixel_size; |
||
222 | u32 dvscntr, dvsscale = 0; |
||
223 | |||
224 | dvscntr = I915_READ(DVSCNTR(pipe)); |
||
225 | |||
226 | /* Mask out pixel format bits in case we change it */ |
||
227 | dvscntr &= ~DVS_PIXFORMAT_MASK; |
||
228 | dvscntr &= ~DVS_RGB_ORDER_RGBX; |
||
229 | dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; |
||
230 | |||
231 | switch (fb->pixel_format) { |
||
232 | case DRM_FORMAT_XBGR8888: |
||
233 | dvscntr |= DVS_FORMAT_RGBX888; |
||
234 | pixel_size = 4; |
||
235 | break; |
||
236 | case DRM_FORMAT_XRGB8888: |
||
237 | dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX; |
||
238 | pixel_size = 4; |
||
239 | break; |
||
240 | case DRM_FORMAT_YUYV: |
||
241 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; |
||
242 | pixel_size = 2; |
||
243 | break; |
||
244 | case DRM_FORMAT_YVYU: |
||
245 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; |
||
246 | pixel_size = 2; |
||
247 | break; |
||
248 | case DRM_FORMAT_UYVY: |
||
249 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; |
||
250 | pixel_size = 2; |
||
251 | break; |
||
252 | case DRM_FORMAT_VYUY: |
||
253 | dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; |
||
254 | pixel_size = 2; |
||
255 | break; |
||
256 | default: |
||
257 | DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); |
||
258 | dvscntr |= DVS_FORMAT_RGBX888; |
||
259 | pixel_size = 4; |
||
260 | break; |
||
261 | } |
||
262 | |||
263 | if (obj->tiling_mode != I915_TILING_NONE) |
||
264 | dvscntr |= DVS_TILED; |
||
265 | |||
266 | /* must disable */ |
||
267 | dvscntr |= DVS_TRICKLE_FEED_DISABLE; |
||
268 | dvscntr |= DVS_ENABLE; |
||
269 | |||
270 | /* Sizes are 0 based */ |
||
271 | src_w--; |
||
272 | src_h--; |
||
273 | crtc_w--; |
||
274 | crtc_h--; |
||
275 | |||
276 | intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); |
||
277 | |||
278 | if (crtc_w != src_w || crtc_h != src_h) |
||
279 | dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; |
||
280 | |||
281 | I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); |
||
282 | I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); |
||
283 | if (obj->tiling_mode != I915_TILING_NONE) { |
||
284 | I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); |
||
285 | } else { |
||
286 | unsigned long offset; |
||
287 | |||
288 | offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); |
||
289 | I915_WRITE(DVSLINOFF(pipe), offset); |
||
290 | } |
||
291 | I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); |
||
292 | I915_WRITE(DVSSCALE(pipe), dvsscale); |
||
293 | I915_WRITE(DVSCNTR(pipe), dvscntr); |
||
294 | I915_WRITE(DVSSURF(pipe), obj->gtt_offset); |
||
295 | POSTING_READ(DVSSURF(pipe)); |
||
296 | } |
||
297 | |||
298 | static void |
||
299 | snb_disable_plane(struct drm_plane *plane) |
||
300 | { |
||
301 | struct drm_device *dev = plane->dev; |
||
302 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
303 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
304 | int pipe = intel_plane->pipe; |
||
305 | |||
306 | I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); |
||
307 | /* Disable the scaler */ |
||
308 | I915_WRITE(DVSSCALE(pipe), 0); |
||
309 | /* Flush double buffered register updates */ |
||
310 | I915_WRITE(DVSSURF(pipe), 0); |
||
311 | POSTING_READ(DVSSURF(pipe)); |
||
312 | } |
||
313 | |||
314 | static void |
||
315 | intel_enable_primary(struct drm_crtc *crtc) |
||
316 | { |
||
317 | struct drm_device *dev = crtc->dev; |
||
318 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
319 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
||
320 | int reg = DSPCNTR(intel_crtc->plane); |
||
321 | |||
322 | I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); |
||
323 | } |
||
324 | |||
325 | static void |
||
326 | intel_disable_primary(struct drm_crtc *crtc) |
||
327 | { |
||
328 | struct drm_device *dev = crtc->dev; |
||
329 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
330 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
||
331 | int reg = DSPCNTR(intel_crtc->plane); |
||
332 | |||
333 | I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); |
||
334 | } |
||
335 | |||
336 | static int |
||
337 | snb_update_colorkey(struct drm_plane *plane, |
||
338 | struct drm_intel_sprite_colorkey *key) |
||
339 | { |
||
340 | struct drm_device *dev = plane->dev; |
||
341 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
342 | struct intel_plane *intel_plane; |
||
343 | u32 dvscntr; |
||
344 | int ret = 0; |
||
345 | |||
346 | intel_plane = to_intel_plane(plane); |
||
347 | |||
348 | I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); |
||
349 | I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); |
||
350 | I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); |
||
351 | |||
352 | dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); |
||
353 | dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); |
||
354 | if (key->flags & I915_SET_COLORKEY_DESTINATION) |
||
355 | dvscntr |= DVS_DEST_KEY; |
||
356 | else if (key->flags & I915_SET_COLORKEY_SOURCE) |
||
357 | dvscntr |= DVS_SOURCE_KEY; |
||
358 | I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); |
||
359 | |||
360 | POSTING_READ(DVSKEYMSK(intel_plane->pipe)); |
||
361 | |||
362 | return ret; |
||
363 | } |
||
364 | |||
365 | static void |
||
366 | snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) |
||
367 | { |
||
368 | struct drm_device *dev = plane->dev; |
||
369 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
370 | struct intel_plane *intel_plane; |
||
371 | u32 dvscntr; |
||
372 | |||
373 | intel_plane = to_intel_plane(plane); |
||
374 | |||
375 | key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); |
||
376 | key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); |
||
377 | key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); |
||
378 | key->flags = 0; |
||
379 | |||
380 | dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); |
||
381 | |||
382 | if (dvscntr & DVS_DEST_KEY) |
||
383 | key->flags = I915_SET_COLORKEY_DESTINATION; |
||
384 | else if (dvscntr & DVS_SOURCE_KEY) |
||
385 | key->flags = I915_SET_COLORKEY_SOURCE; |
||
386 | else |
||
387 | key->flags = I915_SET_COLORKEY_NONE; |
||
388 | } |
||
389 | |||
390 | static int |
||
391 | intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, |
||
392 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, |
||
393 | unsigned int crtc_w, unsigned int crtc_h, |
||
394 | uint32_t src_x, uint32_t src_y, |
||
395 | uint32_t src_w, uint32_t src_h) |
||
396 | { |
||
397 | struct drm_device *dev = plane->dev; |
||
398 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
399 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
||
400 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
401 | struct intel_framebuffer *intel_fb; |
||
402 | struct drm_i915_gem_object *obj, *old_obj; |
||
403 | int pipe = intel_plane->pipe; |
||
404 | int ret = 0; |
||
405 | int x = src_x >> 16, y = src_y >> 16; |
||
406 | int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; |
||
407 | bool disable_primary = false; |
||
408 | |||
409 | intel_fb = to_intel_framebuffer(fb); |
||
410 | obj = intel_fb->obj; |
||
411 | |||
412 | old_obj = intel_plane->obj; |
||
413 | |||
414 | /* Pipe must be running... */ |
||
415 | if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) |
||
416 | return -EINVAL; |
||
417 | |||
418 | if (crtc_x >= primary_w || crtc_y >= primary_h) |
||
419 | return -EINVAL; |
||
420 | |||
421 | /* Don't modify another pipe's plane */ |
||
422 | if (intel_plane->pipe != intel_crtc->pipe) |
||
423 | return -EINVAL; |
||
424 | |||
425 | /* |
||
426 | * Clamp the width & height into the visible area. Note we don't |
||
427 | * try to scale the source if part of the visible region is offscreen. |
||
428 | * The caller must handle that by adjusting source offset and size. |
||
429 | */ |
||
430 | if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { |
||
431 | crtc_w += crtc_x; |
||
432 | crtc_x = 0; |
||
433 | } |
||
434 | if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ |
||
435 | goto out; |
||
436 | if ((crtc_x + crtc_w) > primary_w) |
||
437 | crtc_w = primary_w - crtc_x; |
||
438 | |||
439 | if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { |
||
440 | crtc_h += crtc_y; |
||
441 | crtc_y = 0; |
||
442 | } |
||
443 | if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ |
||
444 | goto out; |
||
445 | if (crtc_y + crtc_h > primary_h) |
||
446 | crtc_h = primary_h - crtc_y; |
||
447 | |||
448 | if (!crtc_w || !crtc_h) /* Again, nothing to display */ |
||
449 | goto out; |
||
450 | |||
451 | /* |
||
452 | * We can take a larger source and scale it down, but |
||
453 | * only so much... 16x is the max on SNB. |
||
454 | */ |
||
455 | if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) |
||
456 | return -EINVAL; |
||
457 | |||
458 | /* |
||
459 | * If the sprite is completely covering the primary plane, |
||
460 | * we can disable the primary and save power. |
||
461 | */ |
||
462 | if ((crtc_x == 0) && (crtc_y == 0) && |
||
463 | (crtc_w == primary_w) && (crtc_h == primary_h)) |
||
464 | disable_primary = true; |
||
465 | |||
466 | mutex_lock(&dev->struct_mutex); |
||
467 | |||
468 | ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); |
||
469 | if (ret) |
||
470 | goto out_unlock; |
||
471 | |||
472 | intel_plane->obj = obj; |
||
473 | |||
474 | /* |
||
475 | * Be sure to re-enable the primary before the sprite is no longer |
||
476 | * covering it fully. |
||
477 | */ |
||
478 | if (!disable_primary && intel_plane->primary_disabled) { |
||
479 | intel_enable_primary(crtc); |
||
480 | intel_plane->primary_disabled = false; |
||
481 | } |
||
482 | |||
483 | intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, |
||
484 | crtc_w, crtc_h, x, y, src_w, src_h); |
||
485 | |||
486 | if (disable_primary) { |
||
487 | intel_disable_primary(crtc); |
||
488 | intel_plane->primary_disabled = true; |
||
489 | } |
||
490 | |||
491 | /* Unpin old obj after new one is active to avoid ugliness */ |
||
492 | if (old_obj) { |
||
493 | /* |
||
494 | * It's fairly common to simply update the position of |
||
495 | * an existing object. In that case, we don't need to |
||
496 | * wait for vblank to avoid ugliness, we only need to |
||
497 | * do the pin & ref bookkeeping. |
||
498 | */ |
||
499 | if (old_obj != obj) { |
||
500 | mutex_unlock(&dev->struct_mutex); |
||
501 | intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); |
||
502 | mutex_lock(&dev->struct_mutex); |
||
503 | } |
||
504 | // i915_gem_object_unpin(old_obj); |
||
505 | } |
||
506 | |||
507 | out_unlock: |
||
508 | mutex_unlock(&dev->struct_mutex); |
||
509 | out: |
||
510 | return ret; |
||
511 | } |
||
512 | |||
513 | static int |
||
514 | intel_disable_plane(struct drm_plane *plane) |
||
515 | { |
||
516 | struct drm_device *dev = plane->dev; |
||
517 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
518 | int ret = 0; |
||
519 | |||
520 | if (intel_plane->primary_disabled) { |
||
521 | intel_enable_primary(plane->crtc); |
||
522 | intel_plane->primary_disabled = false; |
||
523 | } |
||
524 | |||
525 | intel_plane->disable_plane(plane); |
||
526 | |||
527 | if (!intel_plane->obj) |
||
528 | goto out; |
||
529 | |||
530 | mutex_lock(&dev->struct_mutex); |
||
531 | // i915_gem_object_unpin(intel_plane->obj); |
||
532 | intel_plane->obj = NULL; |
||
533 | mutex_unlock(&dev->struct_mutex); |
||
534 | out: |
||
535 | |||
536 | return ret; |
||
537 | } |
||
538 | |||
539 | static void intel_destroy_plane(struct drm_plane *plane) |
||
540 | { |
||
541 | struct intel_plane *intel_plane = to_intel_plane(plane); |
||
542 | intel_disable_plane(plane); |
||
543 | drm_plane_cleanup(plane); |
||
544 | kfree(intel_plane); |
||
545 | } |
||
546 | |||
547 | int intel_sprite_set_colorkey(struct drm_device *dev, void *data, |
||
548 | struct drm_file *file_priv) |
||
549 | { |
||
550 | struct drm_intel_sprite_colorkey *set = data; |
||
551 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
552 | struct drm_mode_object *obj; |
||
553 | struct drm_plane *plane; |
||
554 | struct intel_plane *intel_plane; |
||
555 | int ret = 0; |
||
556 | |||
557 | if (!dev_priv) |
||
558 | return -EINVAL; |
||
559 | |||
560 | /* Make sure we don't try to enable both src & dest simultaneously */ |
||
561 | if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) |
||
562 | return -EINVAL; |
||
563 | |||
564 | mutex_lock(&dev->mode_config.mutex); |
||
565 | |||
566 | obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); |
||
567 | if (!obj) { |
||
568 | ret = -EINVAL; |
||
569 | goto out_unlock; |
||
570 | } |
||
571 | |||
572 | plane = obj_to_plane(obj); |
||
573 | intel_plane = to_intel_plane(plane); |
||
574 | ret = intel_plane->update_colorkey(plane, set); |
||
575 | |||
576 | out_unlock: |
||
577 | mutex_unlock(&dev->mode_config.mutex); |
||
578 | return ret; |
||
579 | } |
||
580 | |||
581 | int intel_sprite_get_colorkey(struct drm_device *dev, void *data, |
||
582 | struct drm_file *file_priv) |
||
583 | { |
||
584 | struct drm_intel_sprite_colorkey *get = data; |
||
585 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
586 | struct drm_mode_object *obj; |
||
587 | struct drm_plane *plane; |
||
588 | struct intel_plane *intel_plane; |
||
589 | int ret = 0; |
||
590 | |||
591 | if (!dev_priv) |
||
592 | return -EINVAL; |
||
593 | |||
594 | mutex_lock(&dev->mode_config.mutex); |
||
595 | |||
596 | obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); |
||
597 | if (!obj) { |
||
598 | ret = -EINVAL; |
||
599 | goto out_unlock; |
||
600 | } |
||
601 | |||
602 | plane = obj_to_plane(obj); |
||
603 | intel_plane = to_intel_plane(plane); |
||
604 | intel_plane->get_colorkey(plane, get); |
||
605 | |||
606 | out_unlock: |
||
607 | mutex_unlock(&dev->mode_config.mutex); |
||
608 | return ret; |
||
609 | } |
||
610 | |||
611 | static const struct drm_plane_funcs intel_plane_funcs = { |
||
612 | .update_plane = intel_update_plane, |
||
613 | .disable_plane = intel_disable_plane, |
||
614 | .destroy = intel_destroy_plane, |
||
615 | }; |
||
616 | |||
617 | static uint32_t snb_plane_formats[] = { |
||
618 | DRM_FORMAT_XBGR8888, |
||
619 | DRM_FORMAT_XRGB8888, |
||
620 | DRM_FORMAT_YUYV, |
||
621 | DRM_FORMAT_YVYU, |
||
622 | DRM_FORMAT_UYVY, |
||
623 | DRM_FORMAT_VYUY, |
||
624 | }; |
||
625 | |||
626 | int |
||
627 | intel_plane_init(struct drm_device *dev, enum pipe pipe) |
||
628 | { |
||
629 | struct intel_plane *intel_plane; |
||
630 | unsigned long possible_crtcs; |
||
631 | int ret; |
||
632 | |||
633 | if (!(IS_GEN6(dev) || IS_GEN7(dev))) |
||
634 | return -ENODEV; |
||
635 | |||
636 | intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL); |
||
637 | if (!intel_plane) |
||
638 | return -ENOMEM; |
||
639 | |||
640 | if (IS_GEN6(dev)) { |
||
641 | intel_plane->max_downscale = 16; |
||
642 | intel_plane->update_plane = snb_update_plane; |
||
643 | intel_plane->disable_plane = snb_disable_plane; |
||
644 | intel_plane->update_colorkey = snb_update_colorkey; |
||
645 | intel_plane->get_colorkey = snb_get_colorkey; |
||
646 | } else if (IS_GEN7(dev)) { |
||
647 | intel_plane->max_downscale = 2; |
||
648 | intel_plane->update_plane = ivb_update_plane; |
||
649 | intel_plane->disable_plane = ivb_disable_plane; |
||
650 | intel_plane->update_colorkey = ivb_update_colorkey; |
||
651 | intel_plane->get_colorkey = ivb_get_colorkey; |
||
652 | } |
||
653 | |||
654 | intel_plane->pipe = pipe; |
||
655 | possible_crtcs = (1 << pipe); |
||
656 | ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, |
||
657 | &intel_plane_funcs, snb_plane_formats, |
||
658 | ARRAY_SIZE(snb_plane_formats), false); |
||
659 | if (ret) |
||
660 | kfree(intel_plane); |
||
661 | |||
662 | return ret; |
||
663 | }><>=>>=>>><>><>><>><>><>><>><>><> |
||
664 |