diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 21:57:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 21:57:59 -0400 |
commit | c48c43e422c1404fd72c57d1d21a6f6d01e18900 (patch) | |
tree | 48e5d3828b4f5479361986535f71a1ae44e4f3c1 /drivers/gpu/drm/i915/intel_overlay.c | |
parent | 520045db940a381d2bee1c1b2179f7921b40fb10 (diff) | |
parent | 135cba0dc399fdd47bd3ae305c1db75fcd77243f (diff) |
Merge branch 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (476 commits)
vmwgfx: Implement a proper GMR eviction mechanism
drm/radeon/kms: fix r6xx/7xx 1D tiling CS checker v2
drm/radeon/kms: properly compute group_size on 6xx/7xx
drm/radeon/kms: fix 2D tile height alignment in the r600 CS checker
drm/radeon/kms/evergreen: set the clear state to the blit state
drm/radeon/kms: don't poll dac load detect.
gpu: Add Intel GMA500(Poulsbo) Stub Driver
drm/radeon/kms: MC vram map needs to be >= pci aperture size
drm/radeon/kms: implement display watermark support for evergreen
drm/radeon/kms/evergreen: add some additional safe regs v2
drm/radeon/r600: fix tiling issues in CS checker.
drm/i915: Move gpu_write_list to per-ring
drm/i915: Invalidate the to-ring, flush the old-ring when updating domains
drm/i915/ringbuffer: Write the value passed in to the tail register
agp/intel: Restore valid PTE bit for Sandybridge after bdd3072
drm/i915: Fix flushing regression from 9af90d19f
drm/i915/sdvo: Remove unused encoding member
i915: enable AVI infoframe for intel_hdmi.c [v4]
drm/i915: Fix current fb blocking for page flip
drm/i915: IS_IRONLAKE is synonymous with gen == 5
...
Fix up conflicts in
- drivers/gpu/drm/i915/{i915_gem.c, i915/intel_overlay.c}: due to the
new simplified stack-based kmap_atomic() interface
- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c: added .llseek entry due to BKL
removal cleanups.
Diffstat (limited to 'drivers/gpu/drm/i915/intel_overlay.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_overlay.c | 1000 |
1 files changed, 531 insertions, 469 deletions
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3264bbd47e65..afb96d25219a 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c | |||
@@ -170,56 +170,143 @@ struct overlay_registers { | |||
170 | u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; | 170 | u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; |
171 | }; | 171 | }; |
172 | 172 | ||
173 | /* overlay flip addr flag */ | 173 | struct intel_overlay { |
174 | #define OFC_UPDATE 0x1 | 174 | struct drm_device *dev; |
175 | 175 | struct intel_crtc *crtc; | |
176 | #define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev)) | 176 | struct drm_i915_gem_object *vid_bo; |
177 | #define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev)) | 177 | struct drm_i915_gem_object *old_vid_bo; |
178 | 178 | int active; | |
179 | int pfit_active; | ||
180 | u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ | ||
181 | u32 color_key; | ||
182 | u32 brightness, contrast, saturation; | ||
183 | u32 old_xscale, old_yscale; | ||
184 | /* register access */ | ||
185 | u32 flip_addr; | ||
186 | struct drm_i915_gem_object *reg_bo; | ||
187 | /* flip handling */ | ||
188 | uint32_t last_flip_req; | ||
189 | void (*flip_tail)(struct intel_overlay *); | ||
190 | }; | ||
179 | 191 | ||
180 | static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) | 192 | static struct overlay_registers * |
193 | intel_overlay_map_regs(struct intel_overlay *overlay) | ||
181 | { | 194 | { |
182 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; | 195 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; |
183 | struct overlay_registers *regs; | 196 | struct overlay_registers *regs; |
184 | 197 | ||
185 | /* no recursive mappings */ | 198 | if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) |
186 | BUG_ON(overlay->virt_addr); | 199 | regs = overlay->reg_bo->phys_obj->handle->vaddr; |
200 | else | ||
201 | regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping, | ||
202 | overlay->reg_bo->gtt_offset); | ||
187 | 203 | ||
188 | if (OVERLAY_NONPHYSICAL(overlay->dev)) { | 204 | return regs; |
189 | regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, | 205 | } |
190 | overlay->reg_bo->gtt_offset); | ||
191 | 206 | ||
192 | if (!regs) { | 207 | static void intel_overlay_unmap_regs(struct intel_overlay *overlay, |
193 | DRM_ERROR("failed to map overlay regs in GTT\n"); | 208 | struct overlay_registers *regs) |
194 | return NULL; | 209 | { |
195 | } | 210 | if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) |
196 | } else | 211 | io_mapping_unmap(regs); |
197 | regs = overlay->reg_bo->phys_obj->handle->vaddr; | 212 | } |
213 | |||
214 | static int intel_overlay_do_wait_request(struct intel_overlay *overlay, | ||
215 | struct drm_i915_gem_request *request, | ||
216 | bool interruptible, | ||
217 | void (*tail)(struct intel_overlay *)) | ||
218 | { | ||
219 | struct drm_device *dev = overlay->dev; | ||
220 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
221 | int ret; | ||
222 | |||
223 | BUG_ON(overlay->last_flip_req); | ||
224 | overlay->last_flip_req = | ||
225 | i915_add_request(dev, NULL, request, &dev_priv->render_ring); | ||
226 | if (overlay->last_flip_req == 0) | ||
227 | return -ENOMEM; | ||
198 | 228 | ||
199 | return overlay->virt_addr = regs; | 229 | overlay->flip_tail = tail; |
230 | ret = i915_do_wait_request(dev, | ||
231 | overlay->last_flip_req, true, | ||
232 | &dev_priv->render_ring); | ||
233 | if (ret) | ||
234 | return ret; | ||
235 | |||
236 | overlay->last_flip_req = 0; | ||
237 | return 0; | ||
200 | } | 238 | } |
201 | 239 | ||
202 | static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) | 240 | /* Workaround for i830 bug where pipe a must be enable to change control regs */ |
241 | static int | ||
242 | i830_activate_pipe_a(struct drm_device *dev) | ||
203 | { | 243 | { |
204 | if (OVERLAY_NONPHYSICAL(overlay->dev)) | 244 | drm_i915_private_t *dev_priv = dev->dev_private; |
205 | io_mapping_unmap_atomic(overlay->virt_addr); | 245 | struct intel_crtc *crtc; |
246 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
247 | struct drm_display_mode vesa_640x480 = { | ||
248 | DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, | ||
249 | 752, 800, 0, 480, 489, 492, 525, 0, | ||
250 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) | ||
251 | }, *mode; | ||
252 | |||
253 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]); | ||
254 | if (crtc->dpms_mode == DRM_MODE_DPMS_ON) | ||
255 | return 0; | ||
206 | 256 | ||
207 | overlay->virt_addr = NULL; | 257 | /* most i8xx have pipe a forced on, so don't trust dpms mode */ |
258 | if (I915_READ(PIPEACONF) & PIPECONF_ENABLE) | ||
259 | return 0; | ||
208 | 260 | ||
209 | return; | 261 | crtc_funcs = crtc->base.helper_private; |
262 | if (crtc_funcs->dpms == NULL) | ||
263 | return 0; | ||
264 | |||
265 | DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); | ||
266 | |||
267 | mode = drm_mode_duplicate(dev, &vesa_640x480); | ||
268 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
269 | if(!drm_crtc_helper_set_mode(&crtc->base, mode, | ||
270 | crtc->base.x, crtc->base.y, | ||
271 | crtc->base.fb)) | ||
272 | return 0; | ||
273 | |||
274 | crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON); | ||
275 | return 1; | ||
276 | } | ||
277 | |||
278 | static void | ||
279 | i830_deactivate_pipe_a(struct drm_device *dev) | ||
280 | { | ||
281 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
282 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; | ||
283 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
284 | |||
285 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
210 | } | 286 | } |
211 | 287 | ||
212 | /* overlay needs to be disable in OCMD reg */ | 288 | /* overlay needs to be disable in OCMD reg */ |
213 | static int intel_overlay_on(struct intel_overlay *overlay) | 289 | static int intel_overlay_on(struct intel_overlay *overlay) |
214 | { | 290 | { |
215 | struct drm_device *dev = overlay->dev; | 291 | struct drm_device *dev = overlay->dev; |
292 | struct drm_i915_gem_request *request; | ||
293 | int pipe_a_quirk = 0; | ||
216 | int ret; | 294 | int ret; |
217 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
218 | 295 | ||
219 | BUG_ON(overlay->active); | 296 | BUG_ON(overlay->active); |
220 | |||
221 | overlay->active = 1; | 297 | overlay->active = 1; |
222 | overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP; | 298 | |
299 | if (IS_I830(dev)) { | ||
300 | pipe_a_quirk = i830_activate_pipe_a(dev); | ||
301 | if (pipe_a_quirk < 0) | ||
302 | return pipe_a_quirk; | ||
303 | } | ||
304 | |||
305 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
306 | if (request == NULL) { | ||
307 | ret = -ENOMEM; | ||
308 | goto out; | ||
309 | } | ||
223 | 310 | ||
224 | BEGIN_LP_RING(4); | 311 | BEGIN_LP_RING(4); |
225 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); | 312 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); |
@@ -228,32 +315,30 @@ static int intel_overlay_on(struct intel_overlay *overlay) | |||
228 | OUT_RING(MI_NOOP); | 315 | OUT_RING(MI_NOOP); |
229 | ADVANCE_LP_RING(); | 316 | ADVANCE_LP_RING(); |
230 | 317 | ||
231 | overlay->last_flip_req = | 318 | ret = intel_overlay_do_wait_request(overlay, request, true, NULL); |
232 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 319 | out: |
233 | if (overlay->last_flip_req == 0) | 320 | if (pipe_a_quirk) |
234 | return -ENOMEM; | 321 | i830_deactivate_pipe_a(dev); |
235 | |||
236 | ret = i915_do_wait_request(dev, | ||
237 | overlay->last_flip_req, 1, &dev_priv->render_ring); | ||
238 | if (ret != 0) | ||
239 | return ret; | ||
240 | 322 | ||
241 | overlay->hw_wedged = 0; | 323 | return ret; |
242 | overlay->last_flip_req = 0; | ||
243 | return 0; | ||
244 | } | 324 | } |
245 | 325 | ||
246 | /* overlay needs to be enabled in OCMD reg */ | 326 | /* overlay needs to be enabled in OCMD reg */ |
247 | static void intel_overlay_continue(struct intel_overlay *overlay, | 327 | static int intel_overlay_continue(struct intel_overlay *overlay, |
248 | bool load_polyphase_filter) | 328 | bool load_polyphase_filter) |
249 | { | 329 | { |
250 | struct drm_device *dev = overlay->dev; | 330 | struct drm_device *dev = overlay->dev; |
251 | drm_i915_private_t *dev_priv = dev->dev_private; | 331 | drm_i915_private_t *dev_priv = dev->dev_private; |
332 | struct drm_i915_gem_request *request; | ||
252 | u32 flip_addr = overlay->flip_addr; | 333 | u32 flip_addr = overlay->flip_addr; |
253 | u32 tmp; | 334 | u32 tmp; |
254 | 335 | ||
255 | BUG_ON(!overlay->active); | 336 | BUG_ON(!overlay->active); |
256 | 337 | ||
338 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
339 | if (request == NULL) | ||
340 | return -ENOMEM; | ||
341 | |||
257 | if (load_polyphase_filter) | 342 | if (load_polyphase_filter) |
258 | flip_addr |= OFC_UPDATE; | 343 | flip_addr |= OFC_UPDATE; |
259 | 344 | ||
@@ -268,220 +353,132 @@ static void intel_overlay_continue(struct intel_overlay *overlay, | |||
268 | ADVANCE_LP_RING(); | 353 | ADVANCE_LP_RING(); |
269 | 354 | ||
270 | overlay->last_flip_req = | 355 | overlay->last_flip_req = |
271 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 356 | i915_add_request(dev, NULL, request, &dev_priv->render_ring); |
357 | return 0; | ||
272 | } | 358 | } |
273 | 359 | ||
274 | static int intel_overlay_wait_flip(struct intel_overlay *overlay) | 360 | static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) |
275 | { | 361 | { |
276 | struct drm_device *dev = overlay->dev; | 362 | struct drm_gem_object *obj = &overlay->old_vid_bo->base; |
277 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
278 | int ret; | ||
279 | u32 tmp; | ||
280 | |||
281 | if (overlay->last_flip_req != 0) { | ||
282 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
283 | 1, &dev_priv->render_ring); | ||
284 | if (ret == 0) { | ||
285 | overlay->last_flip_req = 0; | ||
286 | |||
287 | tmp = I915_READ(ISR); | ||
288 | 363 | ||
289 | if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) | 364 | i915_gem_object_unpin(obj); |
290 | return 0; | 365 | drm_gem_object_unreference(obj); |
291 | } | ||
292 | } | ||
293 | 366 | ||
294 | /* synchronous slowpath */ | 367 | overlay->old_vid_bo = NULL; |
295 | overlay->hw_wedged = RELEASE_OLD_VID; | 368 | } |
296 | 369 | ||
297 | BEGIN_LP_RING(2); | 370 | static void intel_overlay_off_tail(struct intel_overlay *overlay) |
298 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 371 | { |
299 | OUT_RING(MI_NOOP); | 372 | struct drm_gem_object *obj; |
300 | ADVANCE_LP_RING(); | ||
301 | 373 | ||
302 | overlay->last_flip_req = | 374 | /* never have the overlay hw on without showing a frame */ |
303 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 375 | BUG_ON(!overlay->vid_bo); |
304 | if (overlay->last_flip_req == 0) | 376 | obj = &overlay->vid_bo->base; |
305 | return -ENOMEM; | ||
306 | 377 | ||
307 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | 378 | i915_gem_object_unpin(obj); |
308 | 1, &dev_priv->render_ring); | 379 | drm_gem_object_unreference(obj); |
309 | if (ret != 0) | 380 | overlay->vid_bo = NULL; |
310 | return ret; | ||
311 | 381 | ||
312 | overlay->hw_wedged = 0; | 382 | overlay->crtc->overlay = NULL; |
313 | overlay->last_flip_req = 0; | 383 | overlay->crtc = NULL; |
314 | return 0; | 384 | overlay->active = 0; |
315 | } | 385 | } |
316 | 386 | ||
317 | /* overlay needs to be disabled in OCMD reg */ | 387 | /* overlay needs to be disabled in OCMD reg */ |
318 | static int intel_overlay_off(struct intel_overlay *overlay) | 388 | static int intel_overlay_off(struct intel_overlay *overlay, |
389 | bool interruptible) | ||
319 | { | 390 | { |
320 | u32 flip_addr = overlay->flip_addr; | ||
321 | struct drm_device *dev = overlay->dev; | 391 | struct drm_device *dev = overlay->dev; |
322 | drm_i915_private_t *dev_priv = dev->dev_private; | 392 | u32 flip_addr = overlay->flip_addr; |
323 | int ret; | 393 | struct drm_i915_gem_request *request; |
324 | 394 | ||
325 | BUG_ON(!overlay->active); | 395 | BUG_ON(!overlay->active); |
326 | 396 | ||
397 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
398 | if (request == NULL) | ||
399 | return -ENOMEM; | ||
400 | |||
327 | /* According to intel docs the overlay hw may hang (when switching | 401 | /* According to intel docs the overlay hw may hang (when switching |
328 | * off) without loading the filter coeffs. It is however unclear whether | 402 | * off) without loading the filter coeffs. It is however unclear whether |
329 | * this applies to the disabling of the overlay or to the switching off | 403 | * this applies to the disabling of the overlay or to the switching off |
330 | * of the hw. Do it in both cases */ | 404 | * of the hw. Do it in both cases */ |
331 | flip_addr |= OFC_UPDATE; | 405 | flip_addr |= OFC_UPDATE; |
332 | 406 | ||
407 | BEGIN_LP_RING(6); | ||
333 | /* wait for overlay to go idle */ | 408 | /* wait for overlay to go idle */ |
334 | overlay->hw_wedged = SWITCH_OFF_STAGE_1; | ||
335 | |||
336 | BEGIN_LP_RING(4); | ||
337 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); | 409 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); |
338 | OUT_RING(flip_addr); | 410 | OUT_RING(flip_addr); |
339 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 411 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); |
340 | OUT_RING(MI_NOOP); | ||
341 | ADVANCE_LP_RING(); | ||
342 | |||
343 | overlay->last_flip_req = | ||
344 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | ||
345 | if (overlay->last_flip_req == 0) | ||
346 | return -ENOMEM; | ||
347 | |||
348 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
349 | 1, &dev_priv->render_ring); | ||
350 | if (ret != 0) | ||
351 | return ret; | ||
352 | |||
353 | /* turn overlay off */ | 412 | /* turn overlay off */ |
354 | overlay->hw_wedged = SWITCH_OFF_STAGE_2; | 413 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); |
355 | |||
356 | BEGIN_LP_RING(4); | ||
357 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); | ||
358 | OUT_RING(flip_addr); | 414 | OUT_RING(flip_addr); |
359 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | 415 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); |
360 | OUT_RING(MI_NOOP); | ||
361 | ADVANCE_LP_RING(); | 416 | ADVANCE_LP_RING(); |
362 | 417 | ||
363 | overlay->last_flip_req = | 418 | return intel_overlay_do_wait_request(overlay, request, interruptible, |
364 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | 419 | intel_overlay_off_tail); |
365 | if (overlay->last_flip_req == 0) | ||
366 | return -ENOMEM; | ||
367 | |||
368 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
369 | 1, &dev_priv->render_ring); | ||
370 | if (ret != 0) | ||
371 | return ret; | ||
372 | |||
373 | overlay->hw_wedged = 0; | ||
374 | overlay->last_flip_req = 0; | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | static void intel_overlay_off_tail(struct intel_overlay *overlay) | ||
379 | { | ||
380 | struct drm_gem_object *obj; | ||
381 | |||
382 | /* never have the overlay hw on without showing a frame */ | ||
383 | BUG_ON(!overlay->vid_bo); | ||
384 | obj = &overlay->vid_bo->base; | ||
385 | |||
386 | i915_gem_object_unpin(obj); | ||
387 | drm_gem_object_unreference(obj); | ||
388 | overlay->vid_bo = NULL; | ||
389 | |||
390 | overlay->crtc->overlay = NULL; | ||
391 | overlay->crtc = NULL; | ||
392 | overlay->active = 0; | ||
393 | } | 420 | } |
394 | 421 | ||
395 | /* recover from an interruption due to a signal | 422 | /* recover from an interruption due to a signal |
396 | * We have to be careful not to repeat work forever an make forward progess. */ | 423 | * We have to be careful not to repeat work forever an make forward progess. */ |
397 | int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, | 424 | static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, |
398 | int interruptible) | 425 | bool interruptible) |
399 | { | 426 | { |
400 | struct drm_device *dev = overlay->dev; | 427 | struct drm_device *dev = overlay->dev; |
401 | struct drm_gem_object *obj; | ||
402 | drm_i915_private_t *dev_priv = dev->dev_private; | 428 | drm_i915_private_t *dev_priv = dev->dev_private; |
403 | u32 flip_addr; | ||
404 | int ret; | 429 | int ret; |
405 | 430 | ||
406 | if (overlay->hw_wedged == HW_WEDGED) | 431 | if (overlay->last_flip_req == 0) |
407 | return -EIO; | 432 | return 0; |
408 | |||
409 | if (overlay->last_flip_req == 0) { | ||
410 | overlay->last_flip_req = | ||
411 | i915_add_request(dev, NULL, 0, &dev_priv->render_ring); | ||
412 | if (overlay->last_flip_req == 0) | ||
413 | return -ENOMEM; | ||
414 | } | ||
415 | 433 | ||
416 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | 434 | ret = i915_do_wait_request(dev, overlay->last_flip_req, |
417 | interruptible, &dev_priv->render_ring); | 435 | interruptible, &dev_priv->render_ring); |
418 | if (ret != 0) | 436 | if (ret) |
419 | return ret; | 437 | return ret; |
420 | 438 | ||
421 | switch (overlay->hw_wedged) { | 439 | if (overlay->flip_tail) |
422 | case RELEASE_OLD_VID: | 440 | overlay->flip_tail(overlay); |
423 | obj = &overlay->old_vid_bo->base; | ||
424 | i915_gem_object_unpin(obj); | ||
425 | drm_gem_object_unreference(obj); | ||
426 | overlay->old_vid_bo = NULL; | ||
427 | break; | ||
428 | case SWITCH_OFF_STAGE_1: | ||
429 | flip_addr = overlay->flip_addr; | ||
430 | flip_addr |= OFC_UPDATE; | ||
431 | |||
432 | overlay->hw_wedged = SWITCH_OFF_STAGE_2; | ||
433 | |||
434 | BEGIN_LP_RING(4); | ||
435 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); | ||
436 | OUT_RING(flip_addr); | ||
437 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | ||
438 | OUT_RING(MI_NOOP); | ||
439 | ADVANCE_LP_RING(); | ||
440 | |||
441 | overlay->last_flip_req = i915_add_request(dev, NULL, | ||
442 | 0, &dev_priv->render_ring); | ||
443 | if (overlay->last_flip_req == 0) | ||
444 | return -ENOMEM; | ||
445 | |||
446 | ret = i915_do_wait_request(dev, overlay->last_flip_req, | ||
447 | interruptible, &dev_priv->render_ring); | ||
448 | if (ret != 0) | ||
449 | return ret; | ||
450 | |||
451 | case SWITCH_OFF_STAGE_2: | ||
452 | intel_overlay_off_tail(overlay); | ||
453 | break; | ||
454 | default: | ||
455 | BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP); | ||
456 | } | ||
457 | 441 | ||
458 | overlay->hw_wedged = 0; | ||
459 | overlay->last_flip_req = 0; | 442 | overlay->last_flip_req = 0; |
460 | return 0; | 443 | return 0; |
461 | } | 444 | } |
462 | 445 | ||
463 | /* Wait for pending overlay flip and release old frame. | 446 | /* Wait for pending overlay flip and release old frame. |
464 | * Needs to be called before the overlay register are changed | 447 | * Needs to be called before the overlay register are changed |
465 | * via intel_overlay_(un)map_regs_atomic */ | 448 | * via intel_overlay_(un)map_regs |
449 | */ | ||
466 | static int intel_overlay_release_old_vid(struct intel_overlay *overlay) | 450 | static int intel_overlay_release_old_vid(struct intel_overlay *overlay) |
467 | { | 451 | { |
452 | struct drm_device *dev = overlay->dev; | ||
453 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
468 | int ret; | 454 | int ret; |
469 | struct drm_gem_object *obj; | ||
470 | 455 | ||
471 | /* only wait if there is actually an old frame to release to | 456 | /* Only wait if there is actually an old frame to release to |
472 | * guarantee forward progress */ | 457 | * guarantee forward progress. |
458 | */ | ||
473 | if (!overlay->old_vid_bo) | 459 | if (!overlay->old_vid_bo) |
474 | return 0; | 460 | return 0; |
475 | 461 | ||
476 | ret = intel_overlay_wait_flip(overlay); | 462 | if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { |
477 | if (ret != 0) | 463 | struct drm_i915_gem_request *request; |
478 | return ret; | ||
479 | 464 | ||
480 | obj = &overlay->old_vid_bo->base; | 465 | /* synchronous slowpath */ |
481 | i915_gem_object_unpin(obj); | 466 | request = kzalloc(sizeof(*request), GFP_KERNEL); |
482 | drm_gem_object_unreference(obj); | 467 | if (request == NULL) |
483 | overlay->old_vid_bo = NULL; | 468 | return -ENOMEM; |
484 | 469 | ||
470 | BEGIN_LP_RING(2); | ||
471 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); | ||
472 | OUT_RING(MI_NOOP); | ||
473 | ADVANCE_LP_RING(); | ||
474 | |||
475 | ret = intel_overlay_do_wait_request(overlay, request, true, | ||
476 | intel_overlay_release_old_vid_tail); | ||
477 | if (ret) | ||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | intel_overlay_release_old_vid_tail(overlay); | ||
485 | return 0; | 482 | return 0; |
486 | } | 483 | } |
487 | 484 | ||
@@ -505,65 +502,65 @@ struct put_image_params { | |||
505 | static int packed_depth_bytes(u32 format) | 502 | static int packed_depth_bytes(u32 format) |
506 | { | 503 | { |
507 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 504 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
508 | case I915_OVERLAY_YUV422: | 505 | case I915_OVERLAY_YUV422: |
509 | return 4; | 506 | return 4; |
510 | case I915_OVERLAY_YUV411: | 507 | case I915_OVERLAY_YUV411: |
511 | /* return 6; not implemented */ | 508 | /* return 6; not implemented */ |
512 | default: | 509 | default: |
513 | return -EINVAL; | 510 | return -EINVAL; |
514 | } | 511 | } |
515 | } | 512 | } |
516 | 513 | ||
517 | static int packed_width_bytes(u32 format, short width) | 514 | static int packed_width_bytes(u32 format, short width) |
518 | { | 515 | { |
519 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 516 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
520 | case I915_OVERLAY_YUV422: | 517 | case I915_OVERLAY_YUV422: |
521 | return width << 1; | 518 | return width << 1; |
522 | default: | 519 | default: |
523 | return -EINVAL; | 520 | return -EINVAL; |
524 | } | 521 | } |
525 | } | 522 | } |
526 | 523 | ||
527 | static int uv_hsubsampling(u32 format) | 524 | static int uv_hsubsampling(u32 format) |
528 | { | 525 | { |
529 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 526 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
530 | case I915_OVERLAY_YUV422: | 527 | case I915_OVERLAY_YUV422: |
531 | case I915_OVERLAY_YUV420: | 528 | case I915_OVERLAY_YUV420: |
532 | return 2; | 529 | return 2; |
533 | case I915_OVERLAY_YUV411: | 530 | case I915_OVERLAY_YUV411: |
534 | case I915_OVERLAY_YUV410: | 531 | case I915_OVERLAY_YUV410: |
535 | return 4; | 532 | return 4; |
536 | default: | 533 | default: |
537 | return -EINVAL; | 534 | return -EINVAL; |
538 | } | 535 | } |
539 | } | 536 | } |
540 | 537 | ||
541 | static int uv_vsubsampling(u32 format) | 538 | static int uv_vsubsampling(u32 format) |
542 | { | 539 | { |
543 | switch (format & I915_OVERLAY_DEPTH_MASK) { | 540 | switch (format & I915_OVERLAY_DEPTH_MASK) { |
544 | case I915_OVERLAY_YUV420: | 541 | case I915_OVERLAY_YUV420: |
545 | case I915_OVERLAY_YUV410: | 542 | case I915_OVERLAY_YUV410: |
546 | return 2; | 543 | return 2; |
547 | case I915_OVERLAY_YUV422: | 544 | case I915_OVERLAY_YUV422: |
548 | case I915_OVERLAY_YUV411: | 545 | case I915_OVERLAY_YUV411: |
549 | return 1; | 546 | return 1; |
550 | default: | 547 | default: |
551 | return -EINVAL; | 548 | return -EINVAL; |
552 | } | 549 | } |
553 | } | 550 | } |
554 | 551 | ||
555 | static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) | 552 | static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width) |
556 | { | 553 | { |
557 | u32 mask, shift, ret; | 554 | u32 mask, shift, ret; |
558 | if (IS_I9XX(dev)) { | 555 | if (IS_GEN2(dev)) { |
559 | mask = 0x3f; | ||
560 | shift = 6; | ||
561 | } else { | ||
562 | mask = 0x1f; | 556 | mask = 0x1f; |
563 | shift = 5; | 557 | shift = 5; |
558 | } else { | ||
559 | mask = 0x3f; | ||
560 | shift = 6; | ||
564 | } | 561 | } |
565 | ret = ((offset + width + mask) >> shift) - (offset >> shift); | 562 | ret = ((offset + width + mask) >> shift) - (offset >> shift); |
566 | if (IS_I9XX(dev)) | 563 | if (!IS_GEN2(dev)) |
567 | ret <<= 1; | 564 | ret <<= 1; |
568 | ret -=1; | 565 | ret -=1; |
569 | return ret << 2; | 566 | return ret << 2; |
@@ -586,7 +583,9 @@ static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = { | |||
586 | 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, | 583 | 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, |
587 | 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, | 584 | 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, |
588 | 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, | 585 | 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, |
589 | 0xb000, 0x3000, 0x0800, 0x3000, 0xb000}; | 586 | 0xb000, 0x3000, 0x0800, 0x3000, 0xb000 |
587 | }; | ||
588 | |||
590 | static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { | 589 | static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { |
591 | 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, | 590 | 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60, |
592 | 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, | 591 | 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40, |
@@ -596,7 +595,8 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = { | |||
596 | 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, | 595 | 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0, |
597 | 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, | 596 | 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240, |
598 | 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, | 597 | 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0, |
599 | 0x3000, 0x0800, 0x3000}; | 598 | 0x3000, 0x0800, 0x3000 |
599 | }; | ||
600 | 600 | ||
601 | static void update_polyphase_filter(struct overlay_registers *regs) | 601 | static void update_polyphase_filter(struct overlay_registers *regs) |
602 | { | 602 | { |
@@ -629,29 +629,31 @@ static bool update_scaling_factors(struct intel_overlay *overlay, | |||
629 | yscale = 1 << FP_SHIFT; | 629 | yscale = 1 << FP_SHIFT; |
630 | 630 | ||
631 | /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ | 631 | /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/ |
632 | xscale_UV = xscale/uv_hscale; | 632 | xscale_UV = xscale/uv_hscale; |
633 | yscale_UV = yscale/uv_vscale; | 633 | yscale_UV = yscale/uv_vscale; |
634 | /* make the Y scale to UV scale ratio an exact multiply */ | 634 | /* make the Y scale to UV scale ratio an exact multiply */ |
635 | xscale = xscale_UV * uv_hscale; | 635 | xscale = xscale_UV * uv_hscale; |
636 | yscale = yscale_UV * uv_vscale; | 636 | yscale = yscale_UV * uv_vscale; |
637 | /*} else { | 637 | /*} else { |
638 | xscale_UV = 0; | 638 | xscale_UV = 0; |
639 | yscale_UV = 0; | 639 | yscale_UV = 0; |
640 | }*/ | 640 | }*/ |
641 | 641 | ||
642 | if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) | 642 | if (xscale != overlay->old_xscale || yscale != overlay->old_yscale) |
643 | scale_changed = true; | 643 | scale_changed = true; |
644 | overlay->old_xscale = xscale; | 644 | overlay->old_xscale = xscale; |
645 | overlay->old_yscale = yscale; | 645 | overlay->old_yscale = yscale; |
646 | 646 | ||
647 | regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20) | 647 | regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) | |
648 | | ((xscale >> FP_SHIFT) << 16) | 648 | ((xscale >> FP_SHIFT) << 16) | |
649 | | ((xscale & FRACT_MASK) << 3); | 649 | ((xscale & FRACT_MASK) << 3)); |
650 | regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20) | 650 | |
651 | | ((xscale_UV >> FP_SHIFT) << 16) | 651 | regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) | |
652 | | ((xscale_UV & FRACT_MASK) << 3); | 652 | ((xscale_UV >> FP_SHIFT) << 16) | |
653 | regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16) | 653 | ((xscale_UV & FRACT_MASK) << 3)); |
654 | | ((yscale_UV >> FP_SHIFT) << 0); | 654 | |
655 | regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) | | ||
656 | ((yscale_UV >> FP_SHIFT) << 0))); | ||
655 | 657 | ||
656 | if (scale_changed) | 658 | if (scale_changed) |
657 | update_polyphase_filter(regs); | 659 | update_polyphase_filter(regs); |
@@ -663,22 +665,28 @@ static void update_colorkey(struct intel_overlay *overlay, | |||
663 | struct overlay_registers *regs) | 665 | struct overlay_registers *regs) |
664 | { | 666 | { |
665 | u32 key = overlay->color_key; | 667 | u32 key = overlay->color_key; |
668 | |||
666 | switch (overlay->crtc->base.fb->bits_per_pixel) { | 669 | switch (overlay->crtc->base.fb->bits_per_pixel) { |
667 | case 8: | 670 | case 8: |
668 | regs->DCLRKV = 0; | 671 | regs->DCLRKV = 0; |
669 | regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; | 672 | regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE; |
670 | case 16: | 673 | break; |
671 | if (overlay->crtc->base.fb->depth == 15) { | 674 | |
672 | regs->DCLRKV = RGB15_TO_COLORKEY(key); | 675 | case 16: |
673 | regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; | 676 | if (overlay->crtc->base.fb->depth == 15) { |
674 | } else { | 677 | regs->DCLRKV = RGB15_TO_COLORKEY(key); |
675 | regs->DCLRKV = RGB16_TO_COLORKEY(key); | 678 | regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE; |
676 | regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; | 679 | } else { |
677 | } | 680 | regs->DCLRKV = RGB16_TO_COLORKEY(key); |
678 | case 24: | 681 | regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE; |
679 | case 32: | 682 | } |
680 | regs->DCLRKV = key; | 683 | break; |
681 | regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; | 684 | |
685 | case 24: | ||
686 | case 32: | ||
687 | regs->DCLRKV = key; | ||
688 | regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE; | ||
689 | break; | ||
682 | } | 690 | } |
683 | } | 691 | } |
684 | 692 | ||
@@ -688,48 +696,48 @@ static u32 overlay_cmd_reg(struct put_image_params *params) | |||
688 | 696 | ||
689 | if (params->format & I915_OVERLAY_YUV_PLANAR) { | 697 | if (params->format & I915_OVERLAY_YUV_PLANAR) { |
690 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { | 698 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { |
691 | case I915_OVERLAY_YUV422: | 699 | case I915_OVERLAY_YUV422: |
692 | cmd |= OCMD_YUV_422_PLANAR; | 700 | cmd |= OCMD_YUV_422_PLANAR; |
693 | break; | 701 | break; |
694 | case I915_OVERLAY_YUV420: | 702 | case I915_OVERLAY_YUV420: |
695 | cmd |= OCMD_YUV_420_PLANAR; | 703 | cmd |= OCMD_YUV_420_PLANAR; |
696 | break; | 704 | break; |
697 | case I915_OVERLAY_YUV411: | 705 | case I915_OVERLAY_YUV411: |
698 | case I915_OVERLAY_YUV410: | 706 | case I915_OVERLAY_YUV410: |
699 | cmd |= OCMD_YUV_410_PLANAR; | 707 | cmd |= OCMD_YUV_410_PLANAR; |
700 | break; | 708 | break; |
701 | } | 709 | } |
702 | } else { /* YUV packed */ | 710 | } else { /* YUV packed */ |
703 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { | 711 | switch (params->format & I915_OVERLAY_DEPTH_MASK) { |
704 | case I915_OVERLAY_YUV422: | 712 | case I915_OVERLAY_YUV422: |
705 | cmd |= OCMD_YUV_422_PACKED; | 713 | cmd |= OCMD_YUV_422_PACKED; |
706 | break; | 714 | break; |
707 | case I915_OVERLAY_YUV411: | 715 | case I915_OVERLAY_YUV411: |
708 | cmd |= OCMD_YUV_411_PACKED; | 716 | cmd |= OCMD_YUV_411_PACKED; |
709 | break; | 717 | break; |
710 | } | 718 | } |
711 | 719 | ||
712 | switch (params->format & I915_OVERLAY_SWAP_MASK) { | 720 | switch (params->format & I915_OVERLAY_SWAP_MASK) { |
713 | case I915_OVERLAY_NO_SWAP: | 721 | case I915_OVERLAY_NO_SWAP: |
714 | break; | 722 | break; |
715 | case I915_OVERLAY_UV_SWAP: | 723 | case I915_OVERLAY_UV_SWAP: |
716 | cmd |= OCMD_UV_SWAP; | 724 | cmd |= OCMD_UV_SWAP; |
717 | break; | 725 | break; |
718 | case I915_OVERLAY_Y_SWAP: | 726 | case I915_OVERLAY_Y_SWAP: |
719 | cmd |= OCMD_Y_SWAP; | 727 | cmd |= OCMD_Y_SWAP; |
720 | break; | 728 | break; |
721 | case I915_OVERLAY_Y_AND_UV_SWAP: | 729 | case I915_OVERLAY_Y_AND_UV_SWAP: |
722 | cmd |= OCMD_Y_AND_UV_SWAP; | 730 | cmd |= OCMD_Y_AND_UV_SWAP; |
723 | break; | 731 | break; |
724 | } | 732 | } |
725 | } | 733 | } |
726 | 734 | ||
727 | return cmd; | 735 | return cmd; |
728 | } | 736 | } |
729 | 737 | ||
730 | int intel_overlay_do_put_image(struct intel_overlay *overlay, | 738 | static int intel_overlay_do_put_image(struct intel_overlay *overlay, |
731 | struct drm_gem_object *new_bo, | 739 | struct drm_gem_object *new_bo, |
732 | struct put_image_params *params) | 740 | struct put_image_params *params) |
733 | { | 741 | { |
734 | int ret, tmp_width; | 742 | int ret, tmp_width; |
735 | struct overlay_registers *regs; | 743 | struct overlay_registers *regs; |
@@ -754,24 +762,24 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
754 | goto out_unpin; | 762 | goto out_unpin; |
755 | 763 | ||
756 | if (!overlay->active) { | 764 | if (!overlay->active) { |
757 | regs = intel_overlay_map_regs_atomic(overlay); | 765 | regs = intel_overlay_map_regs(overlay); |
758 | if (!regs) { | 766 | if (!regs) { |
759 | ret = -ENOMEM; | 767 | ret = -ENOMEM; |
760 | goto out_unpin; | 768 | goto out_unpin; |
761 | } | 769 | } |
762 | regs->OCONFIG = OCONF_CC_OUT_8BIT; | 770 | regs->OCONFIG = OCONF_CC_OUT_8BIT; |
763 | if (IS_I965GM(overlay->dev)) | 771 | if (IS_GEN4(overlay->dev)) |
764 | regs->OCONFIG |= OCONF_CSC_MODE_BT709; | 772 | regs->OCONFIG |= OCONF_CSC_MODE_BT709; |
765 | regs->OCONFIG |= overlay->crtc->pipe == 0 ? | 773 | regs->OCONFIG |= overlay->crtc->pipe == 0 ? |
766 | OCONF_PIPE_A : OCONF_PIPE_B; | 774 | OCONF_PIPE_A : OCONF_PIPE_B; |
767 | intel_overlay_unmap_regs_atomic(overlay); | 775 | intel_overlay_unmap_regs(overlay, regs); |
768 | 776 | ||
769 | ret = intel_overlay_on(overlay); | 777 | ret = intel_overlay_on(overlay); |
770 | if (ret != 0) | 778 | if (ret != 0) |
771 | goto out_unpin; | 779 | goto out_unpin; |
772 | } | 780 | } |
773 | 781 | ||
774 | regs = intel_overlay_map_regs_atomic(overlay); | 782 | regs = intel_overlay_map_regs(overlay); |
775 | if (!regs) { | 783 | if (!regs) { |
776 | ret = -ENOMEM; | 784 | ret = -ENOMEM; |
777 | goto out_unpin; | 785 | goto out_unpin; |
@@ -787,7 +795,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
787 | 795 | ||
788 | regs->SWIDTH = params->src_w; | 796 | regs->SWIDTH = params->src_w; |
789 | regs->SWIDTHSW = calc_swidthsw(overlay->dev, | 797 | regs->SWIDTHSW = calc_swidthsw(overlay->dev, |
790 | params->offset_Y, tmp_width); | 798 | params->offset_Y, tmp_width); |
791 | regs->SHEIGHT = params->src_h; | 799 | regs->SHEIGHT = params->src_h; |
792 | regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y; | 800 | regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y; |
793 | regs->OSTRIDE = params->stride_Y; | 801 | regs->OSTRIDE = params->stride_Y; |
@@ -798,9 +806,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
798 | u32 tmp_U, tmp_V; | 806 | u32 tmp_U, tmp_V; |
799 | regs->SWIDTH |= (params->src_w/uv_hscale) << 16; | 807 | regs->SWIDTH |= (params->src_w/uv_hscale) << 16; |
800 | tmp_U = calc_swidthsw(overlay->dev, params->offset_U, | 808 | tmp_U = calc_swidthsw(overlay->dev, params->offset_U, |
801 | params->src_w/uv_hscale); | 809 | params->src_w/uv_hscale); |
802 | tmp_V = calc_swidthsw(overlay->dev, params->offset_V, | 810 | tmp_V = calc_swidthsw(overlay->dev, params->offset_V, |
803 | params->src_w/uv_hscale); | 811 | params->src_w/uv_hscale); |
804 | regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16; | 812 | regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16; |
805 | regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; | 813 | regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; |
806 | regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U; | 814 | regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U; |
@@ -814,9 +822,11 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay, | |||
814 | 822 | ||
815 | regs->OCMD = overlay_cmd_reg(params); | 823 | regs->OCMD = overlay_cmd_reg(params); |
816 | 824 | ||
817 | intel_overlay_unmap_regs_atomic(overlay); | 825 | intel_overlay_unmap_regs(overlay, regs); |
818 | 826 | ||
819 | intel_overlay_continue(overlay, scale_changed); | 827 | ret = intel_overlay_continue(overlay, scale_changed); |
828 | if (ret) | ||
829 | goto out_unpin; | ||
820 | 830 | ||
821 | overlay->old_vid_bo = overlay->vid_bo; | 831 | overlay->old_vid_bo = overlay->vid_bo; |
822 | overlay->vid_bo = to_intel_bo(new_bo); | 832 | overlay->vid_bo = to_intel_bo(new_bo); |
@@ -828,20 +838,19 @@ out_unpin: | |||
828 | return ret; | 838 | return ret; |
829 | } | 839 | } |
830 | 840 | ||
831 | int intel_overlay_switch_off(struct intel_overlay *overlay) | 841 | int intel_overlay_switch_off(struct intel_overlay *overlay, |
842 | bool interruptible) | ||
832 | { | 843 | { |
833 | int ret; | ||
834 | struct overlay_registers *regs; | 844 | struct overlay_registers *regs; |
835 | struct drm_device *dev = overlay->dev; | 845 | struct drm_device *dev = overlay->dev; |
846 | int ret; | ||
836 | 847 | ||
837 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); | 848 | BUG_ON(!mutex_is_locked(&dev->struct_mutex)); |
838 | BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); | 849 | BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
839 | 850 | ||
840 | if (overlay->hw_wedged) { | 851 | ret = intel_overlay_recover_from_interrupt(overlay, interruptible); |
841 | ret = intel_overlay_recover_from_interrupt(overlay, 1); | 852 | if (ret != 0) |
842 | if (ret != 0) | 853 | return ret; |
843 | return ret; | ||
844 | } | ||
845 | 854 | ||
846 | if (!overlay->active) | 855 | if (!overlay->active) |
847 | return 0; | 856 | return 0; |
@@ -850,33 +859,29 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) | |||
850 | if (ret != 0) | 859 | if (ret != 0) |
851 | return ret; | 860 | return ret; |
852 | 861 | ||
853 | regs = intel_overlay_map_regs_atomic(overlay); | 862 | regs = intel_overlay_map_regs(overlay); |
854 | regs->OCMD = 0; | 863 | regs->OCMD = 0; |
855 | intel_overlay_unmap_regs_atomic(overlay); | 864 | intel_overlay_unmap_regs(overlay, regs); |
856 | 865 | ||
857 | ret = intel_overlay_off(overlay); | 866 | ret = intel_overlay_off(overlay, interruptible); |
858 | if (ret != 0) | 867 | if (ret != 0) |
859 | return ret; | 868 | return ret; |
860 | 869 | ||
861 | intel_overlay_off_tail(overlay); | 870 | intel_overlay_off_tail(overlay); |
862 | |||
863 | return 0; | 871 | return 0; |
864 | } | 872 | } |
865 | 873 | ||
866 | static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, | 874 | static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, |
867 | struct intel_crtc *crtc) | 875 | struct intel_crtc *crtc) |
868 | { | 876 | { |
869 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; | 877 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; |
870 | u32 pipeconf; | ||
871 | int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
872 | 878 | ||
873 | if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON) | 879 | if (!crtc->active) |
874 | return -EINVAL; | 880 | return -EINVAL; |
875 | 881 | ||
876 | pipeconf = I915_READ(pipeconf_reg); | ||
877 | |||
878 | /* can't use the overlay with double wide pipe */ | 882 | /* can't use the overlay with double wide pipe */ |
879 | if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE) | 883 | if (INTEL_INFO(overlay->dev)->gen < 4 && |
884 | (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) | ||
880 | return -EINVAL; | 885 | return -EINVAL; |
881 | 886 | ||
882 | return 0; | 887 | return 0; |
@@ -885,20 +890,22 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay, | |||
885 | static void update_pfit_vscale_ratio(struct intel_overlay *overlay) | 890 | static void update_pfit_vscale_ratio(struct intel_overlay *overlay) |
886 | { | 891 | { |
887 | struct drm_device *dev = overlay->dev; | 892 | struct drm_device *dev = overlay->dev; |
888 | drm_i915_private_t *dev_priv = dev->dev_private; | 893 | drm_i915_private_t *dev_priv = dev->dev_private; |
889 | u32 ratio; | ||
890 | u32 pfit_control = I915_READ(PFIT_CONTROL); | 894 | u32 pfit_control = I915_READ(PFIT_CONTROL); |
895 | u32 ratio; | ||
891 | 896 | ||
892 | /* XXX: This is not the same logic as in the xorg driver, but more in | 897 | /* XXX: This is not the same logic as in the xorg driver, but more in |
893 | * line with the intel documentation for the i965 */ | 898 | * line with the intel documentation for the i965 |
894 | if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) { | 899 | */ |
895 | ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT; | 900 | if (INTEL_INFO(dev)->gen >= 4) { |
896 | } else { /* on i965 use the PGM reg to read out the autoscaler values */ | 901 | /* on i965 use the PGM reg to read out the autoscaler values */ |
897 | ratio = I915_READ(PFIT_PGM_RATIOS); | 902 | ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965; |
898 | if (IS_I965G(dev)) | 903 | } else { |
899 | ratio >>= PFIT_VERT_SCALE_SHIFT_965; | 904 | if (pfit_control & VERT_AUTO_SCALE) |
905 | ratio = I915_READ(PFIT_AUTO_RATIOS); | ||
900 | else | 906 | else |
901 | ratio >>= PFIT_VERT_SCALE_SHIFT; | 907 | ratio = I915_READ(PFIT_PGM_RATIOS); |
908 | ratio >>= PFIT_VERT_SCALE_SHIFT; | ||
902 | } | 909 | } |
903 | 910 | ||
904 | overlay->pfit_vscale_ratio = ratio; | 911 | overlay->pfit_vscale_ratio = ratio; |
@@ -909,12 +916,10 @@ static int check_overlay_dst(struct intel_overlay *overlay, | |||
909 | { | 916 | { |
910 | struct drm_display_mode *mode = &overlay->crtc->base.mode; | 917 | struct drm_display_mode *mode = &overlay->crtc->base.mode; |
911 | 918 | ||
912 | if ((rec->dst_x < mode->crtc_hdisplay) | 919 | if (rec->dst_x < mode->crtc_hdisplay && |
913 | && (rec->dst_x + rec->dst_width | 920 | rec->dst_x + rec->dst_width <= mode->crtc_hdisplay && |
914 | <= mode->crtc_hdisplay) | 921 | rec->dst_y < mode->crtc_vdisplay && |
915 | && (rec->dst_y < mode->crtc_vdisplay) | 922 | rec->dst_y + rec->dst_height <= mode->crtc_vdisplay) |
916 | && (rec->dst_y + rec->dst_height | ||
917 | <= mode->crtc_vdisplay)) | ||
918 | return 0; | 923 | return 0; |
919 | else | 924 | else |
920 | return -EINVAL; | 925 | return -EINVAL; |
@@ -939,53 +944,57 @@ static int check_overlay_src(struct drm_device *dev, | |||
939 | struct drm_intel_overlay_put_image *rec, | 944 | struct drm_intel_overlay_put_image *rec, |
940 | struct drm_gem_object *new_bo) | 945 | struct drm_gem_object *new_bo) |
941 | { | 946 | { |
942 | u32 stride_mask; | ||
943 | int depth; | ||
944 | int uv_hscale = uv_hsubsampling(rec->flags); | 947 | int uv_hscale = uv_hsubsampling(rec->flags); |
945 | int uv_vscale = uv_vsubsampling(rec->flags); | 948 | int uv_vscale = uv_vsubsampling(rec->flags); |
946 | size_t tmp; | 949 | u32 stride_mask, depth, tmp; |
947 | 950 | ||
948 | /* check src dimensions */ | 951 | /* check src dimensions */ |
949 | if (IS_845G(dev) || IS_I830(dev)) { | 952 | if (IS_845G(dev) || IS_I830(dev)) { |
950 | if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY | 953 | if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY || |
951 | || rec->src_width > IMAGE_MAX_WIDTH_LEGACY) | 954 | rec->src_width > IMAGE_MAX_WIDTH_LEGACY) |
952 | return -EINVAL; | 955 | return -EINVAL; |
953 | } else { | 956 | } else { |
954 | if (rec->src_height > IMAGE_MAX_HEIGHT | 957 | if (rec->src_height > IMAGE_MAX_HEIGHT || |
955 | || rec->src_width > IMAGE_MAX_WIDTH) | 958 | rec->src_width > IMAGE_MAX_WIDTH) |
956 | return -EINVAL; | 959 | return -EINVAL; |
957 | } | 960 | } |
961 | |||
958 | /* better safe than sorry, use 4 as the maximal subsampling ratio */ | 962 | /* better safe than sorry, use 4 as the maximal subsampling ratio */ |
959 | if (rec->src_height < N_VERT_Y_TAPS*4 | 963 | if (rec->src_height < N_VERT_Y_TAPS*4 || |
960 | || rec->src_width < N_HORIZ_Y_TAPS*4) | 964 | rec->src_width < N_HORIZ_Y_TAPS*4) |
961 | return -EINVAL; | 965 | return -EINVAL; |
962 | 966 | ||
963 | /* check alignment constraints */ | 967 | /* check alignment constraints */ |
964 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { | 968 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { |
965 | case I915_OVERLAY_RGB: | 969 | case I915_OVERLAY_RGB: |
966 | /* not implemented */ | 970 | /* not implemented */ |
971 | return -EINVAL; | ||
972 | |||
973 | case I915_OVERLAY_YUV_PACKED: | ||
974 | if (uv_vscale != 1) | ||
967 | return -EINVAL; | 975 | return -EINVAL; |
968 | case I915_OVERLAY_YUV_PACKED: | 976 | |
969 | depth = packed_depth_bytes(rec->flags); | 977 | depth = packed_depth_bytes(rec->flags); |
970 | if (uv_vscale != 1) | 978 | if (depth < 0) |
971 | return -EINVAL; | 979 | return depth; |
972 | if (depth < 0) | 980 | |
973 | return depth; | 981 | /* ignore UV planes */ |
974 | /* ignore UV planes */ | 982 | rec->stride_UV = 0; |
975 | rec->stride_UV = 0; | 983 | rec->offset_U = 0; |
976 | rec->offset_U = 0; | 984 | rec->offset_V = 0; |
977 | rec->offset_V = 0; | 985 | /* check pixel alignment */ |
978 | /* check pixel alignment */ | 986 | if (rec->offset_Y % depth) |
979 | if (rec->offset_Y % depth) | 987 | return -EINVAL; |
980 | return -EINVAL; | 988 | break; |
981 | break; | 989 | |
982 | case I915_OVERLAY_YUV_PLANAR: | 990 | case I915_OVERLAY_YUV_PLANAR: |
983 | if (uv_vscale < 0 || uv_hscale < 0) | 991 | if (uv_vscale < 0 || uv_hscale < 0) |
984 | return -EINVAL; | ||
985 | /* no offset restrictions for planar formats */ | ||
986 | break; | ||
987 | default: | ||
988 | return -EINVAL; | 992 | return -EINVAL; |
993 | /* no offset restrictions for planar formats */ | ||
994 | break; | ||
995 | |||
996 | default: | ||
997 | return -EINVAL; | ||
989 | } | 998 | } |
990 | 999 | ||
991 | if (rec->src_width % uv_hscale) | 1000 | if (rec->src_width % uv_hscale) |
@@ -999,47 +1008,74 @@ static int check_overlay_src(struct drm_device *dev, | |||
999 | 1008 | ||
1000 | if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) | 1009 | if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) |
1001 | return -EINVAL; | 1010 | return -EINVAL; |
1002 | if (IS_I965G(dev) && rec->stride_Y < 512) | 1011 | if (IS_GEN4(dev) && rec->stride_Y < 512) |
1003 | return -EINVAL; | 1012 | return -EINVAL; |
1004 | 1013 | ||
1005 | tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? | 1014 | tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? |
1006 | 4 : 8; | 1015 | 4096 : 8192; |
1007 | if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024) | 1016 | if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) |
1008 | return -EINVAL; | 1017 | return -EINVAL; |
1009 | 1018 | ||
1010 | /* check buffer dimensions */ | 1019 | /* check buffer dimensions */ |
1011 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { | 1020 | switch (rec->flags & I915_OVERLAY_TYPE_MASK) { |
1012 | case I915_OVERLAY_RGB: | 1021 | case I915_OVERLAY_RGB: |
1013 | case I915_OVERLAY_YUV_PACKED: | 1022 | case I915_OVERLAY_YUV_PACKED: |
1014 | /* always 4 Y values per depth pixels */ | 1023 | /* always 4 Y values per depth pixels */ |
1015 | if (packed_width_bytes(rec->flags, rec->src_width) | 1024 | if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y) |
1016 | > rec->stride_Y) | 1025 | return -EINVAL; |
1017 | return -EINVAL; | 1026 | |
1018 | 1027 | tmp = rec->stride_Y*rec->src_height; | |
1019 | tmp = rec->stride_Y*rec->src_height; | 1028 | if (rec->offset_Y + tmp > new_bo->size) |
1020 | if (rec->offset_Y + tmp > new_bo->size) | 1029 | return -EINVAL; |
1021 | return -EINVAL; | 1030 | break; |
1022 | break; | 1031 | |
1023 | case I915_OVERLAY_YUV_PLANAR: | 1032 | case I915_OVERLAY_YUV_PLANAR: |
1024 | if (rec->src_width > rec->stride_Y) | 1033 | if (rec->src_width > rec->stride_Y) |
1025 | return -EINVAL; | 1034 | return -EINVAL; |
1026 | if (rec->src_width/uv_hscale > rec->stride_UV) | 1035 | if (rec->src_width/uv_hscale > rec->stride_UV) |
1027 | return -EINVAL; | 1036 | return -EINVAL; |
1028 | 1037 | ||
1029 | tmp = rec->stride_Y*rec->src_height; | 1038 | tmp = rec->stride_Y * rec->src_height; |
1030 | if (rec->offset_Y + tmp > new_bo->size) | 1039 | if (rec->offset_Y + tmp > new_bo->size) |
1031 | return -EINVAL; | 1040 | return -EINVAL; |
1032 | tmp = rec->stride_UV*rec->src_height; | 1041 | |
1033 | tmp /= uv_vscale; | 1042 | tmp = rec->stride_UV * (rec->src_height / uv_vscale); |
1034 | if (rec->offset_U + tmp > new_bo->size | 1043 | if (rec->offset_U + tmp > new_bo->size || |
1035 | || rec->offset_V + tmp > new_bo->size) | 1044 | rec->offset_V + tmp > new_bo->size) |
1036 | return -EINVAL; | 1045 | return -EINVAL; |
1037 | break; | 1046 | break; |
1038 | } | 1047 | } |
1039 | 1048 | ||
1040 | return 0; | 1049 | return 0; |
1041 | } | 1050 | } |
1042 | 1051 | ||
1052 | /** | ||
1053 | * Return the pipe currently connected to the panel fitter, | ||
1054 | * or -1 if the panel fitter is not present or not in use | ||
1055 | */ | ||
1056 | static int intel_panel_fitter_pipe(struct drm_device *dev) | ||
1057 | { | ||
1058 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1059 | u32 pfit_control; | ||
1060 | |||
1061 | /* i830 doesn't have a panel fitter */ | ||
1062 | if (IS_I830(dev)) | ||
1063 | return -1; | ||
1064 | |||
1065 | pfit_control = I915_READ(PFIT_CONTROL); | ||
1066 | |||
1067 | /* See if the panel fitter is in use */ | ||
1068 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
1069 | return -1; | ||
1070 | |||
1071 | /* 965 can place panel fitter on either pipe */ | ||
1072 | if (IS_GEN4(dev)) | ||
1073 | return (pfit_control >> 29) & 0x3; | ||
1074 | |||
1075 | /* older chips can only use pipe 1 */ | ||
1076 | return 1; | ||
1077 | } | ||
1078 | |||
1043 | int intel_overlay_put_image(struct drm_device *dev, void *data, | 1079 | int intel_overlay_put_image(struct drm_device *dev, void *data, |
1044 | struct drm_file *file_priv) | 1080 | struct drm_file *file_priv) |
1045 | { | 1081 | { |
@@ -1067,7 +1103,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1067 | mutex_lock(&dev->mode_config.mutex); | 1103 | mutex_lock(&dev->mode_config.mutex); |
1068 | mutex_lock(&dev->struct_mutex); | 1104 | mutex_lock(&dev->struct_mutex); |
1069 | 1105 | ||
1070 | ret = intel_overlay_switch_off(overlay); | 1106 | ret = intel_overlay_switch_off(overlay, true); |
1071 | 1107 | ||
1072 | mutex_unlock(&dev->struct_mutex); | 1108 | mutex_unlock(&dev->struct_mutex); |
1073 | mutex_unlock(&dev->mode_config.mutex); | 1109 | mutex_unlock(&dev->mode_config.mutex); |
@@ -1080,7 +1116,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1080 | return -ENOMEM; | 1116 | return -ENOMEM; |
1081 | 1117 | ||
1082 | drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, | 1118 | drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id, |
1083 | DRM_MODE_OBJECT_CRTC); | 1119 | DRM_MODE_OBJECT_CRTC); |
1084 | if (!drmmode_obj) { | 1120 | if (!drmmode_obj) { |
1085 | ret = -ENOENT; | 1121 | ret = -ENOENT; |
1086 | goto out_free; | 1122 | goto out_free; |
@@ -1088,7 +1124,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1088 | crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); | 1124 | crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); |
1089 | 1125 | ||
1090 | new_bo = drm_gem_object_lookup(dev, file_priv, | 1126 | new_bo = drm_gem_object_lookup(dev, file_priv, |
1091 | put_image_rec->bo_handle); | 1127 | put_image_rec->bo_handle); |
1092 | if (!new_bo) { | 1128 | if (!new_bo) { |
1093 | ret = -ENOENT; | 1129 | ret = -ENOENT; |
1094 | goto out_free; | 1130 | goto out_free; |
@@ -1097,15 +1133,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1097 | mutex_lock(&dev->mode_config.mutex); | 1133 | mutex_lock(&dev->mode_config.mutex); |
1098 | mutex_lock(&dev->struct_mutex); | 1134 | mutex_lock(&dev->struct_mutex); |
1099 | 1135 | ||
1100 | if (overlay->hw_wedged) { | 1136 | ret = intel_overlay_recover_from_interrupt(overlay, true); |
1101 | ret = intel_overlay_recover_from_interrupt(overlay, 1); | 1137 | if (ret != 0) |
1102 | if (ret != 0) | 1138 | goto out_unlock; |
1103 | goto out_unlock; | ||
1104 | } | ||
1105 | 1139 | ||
1106 | if (overlay->crtc != crtc) { | 1140 | if (overlay->crtc != crtc) { |
1107 | struct drm_display_mode *mode = &crtc->base.mode; | 1141 | struct drm_display_mode *mode = &crtc->base.mode; |
1108 | ret = intel_overlay_switch_off(overlay); | 1142 | ret = intel_overlay_switch_off(overlay, true); |
1109 | if (ret != 0) | 1143 | if (ret != 0) |
1110 | goto out_unlock; | 1144 | goto out_unlock; |
1111 | 1145 | ||
@@ -1116,9 +1150,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1116 | overlay->crtc = crtc; | 1150 | overlay->crtc = crtc; |
1117 | crtc->overlay = overlay; | 1151 | crtc->overlay = overlay; |
1118 | 1152 | ||
1119 | if (intel_panel_fitter_pipe(dev) == crtc->pipe | 1153 | /* line too wide, i.e. one-line-mode */ |
1120 | /* and line to wide, i.e. one-line-mode */ | 1154 | if (mode->hdisplay > 1024 && |
1121 | && mode->hdisplay > 1024) { | 1155 | intel_panel_fitter_pipe(dev) == crtc->pipe) { |
1122 | overlay->pfit_active = 1; | 1156 | overlay->pfit_active = 1; |
1123 | update_pfit_vscale_ratio(overlay); | 1157 | update_pfit_vscale_ratio(overlay); |
1124 | } else | 1158 | } else |
@@ -1131,10 +1165,10 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1131 | 1165 | ||
1132 | if (overlay->pfit_active) { | 1166 | if (overlay->pfit_active) { |
1133 | params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / | 1167 | params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / |
1134 | overlay->pfit_vscale_ratio); | 1168 | overlay->pfit_vscale_ratio); |
1135 | /* shifting right rounds downwards, so add 1 */ | 1169 | /* shifting right rounds downwards, so add 1 */ |
1136 | params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / | 1170 | params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / |
1137 | overlay->pfit_vscale_ratio) + 1; | 1171 | overlay->pfit_vscale_ratio) + 1; |
1138 | } else { | 1172 | } else { |
1139 | params->dst_y = put_image_rec->dst_y; | 1173 | params->dst_y = put_image_rec->dst_y; |
1140 | params->dst_h = put_image_rec->dst_height; | 1174 | params->dst_h = put_image_rec->dst_height; |
@@ -1146,8 +1180,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1146 | params->src_h = put_image_rec->src_height; | 1180 | params->src_h = put_image_rec->src_height; |
1147 | params->src_scan_w = put_image_rec->src_scan_width; | 1181 | params->src_scan_w = put_image_rec->src_scan_width; |
1148 | params->src_scan_h = put_image_rec->src_scan_height; | 1182 | params->src_scan_h = put_image_rec->src_scan_height; |
1149 | if (params->src_scan_h > params->src_h | 1183 | if (params->src_scan_h > params->src_h || |
1150 | || params->src_scan_w > params->src_w) { | 1184 | params->src_scan_w > params->src_w) { |
1151 | ret = -EINVAL; | 1185 | ret = -EINVAL; |
1152 | goto out_unlock; | 1186 | goto out_unlock; |
1153 | } | 1187 | } |
@@ -1203,7 +1237,7 @@ static bool check_gamma_bounds(u32 gamma1, u32 gamma2) | |||
1203 | return false; | 1237 | return false; |
1204 | 1238 | ||
1205 | for (i = 0; i < 3; i++) { | 1239 | for (i = 0; i < 3; i++) { |
1206 | if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) | 1240 | if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff)) |
1207 | return false; | 1241 | return false; |
1208 | } | 1242 | } |
1209 | 1243 | ||
@@ -1224,16 +1258,18 @@ static bool check_gamma5_errata(u32 gamma5) | |||
1224 | 1258 | ||
1225 | static int check_gamma(struct drm_intel_overlay_attrs *attrs) | 1259 | static int check_gamma(struct drm_intel_overlay_attrs *attrs) |
1226 | { | 1260 | { |
1227 | if (!check_gamma_bounds(0, attrs->gamma0) | 1261 | if (!check_gamma_bounds(0, attrs->gamma0) || |
1228 | || !check_gamma_bounds(attrs->gamma0, attrs->gamma1) | 1262 | !check_gamma_bounds(attrs->gamma0, attrs->gamma1) || |
1229 | || !check_gamma_bounds(attrs->gamma1, attrs->gamma2) | 1263 | !check_gamma_bounds(attrs->gamma1, attrs->gamma2) || |
1230 | || !check_gamma_bounds(attrs->gamma2, attrs->gamma3) | 1264 | !check_gamma_bounds(attrs->gamma2, attrs->gamma3) || |
1231 | || !check_gamma_bounds(attrs->gamma3, attrs->gamma4) | 1265 | !check_gamma_bounds(attrs->gamma3, attrs->gamma4) || |
1232 | || !check_gamma_bounds(attrs->gamma4, attrs->gamma5) | 1266 | !check_gamma_bounds(attrs->gamma4, attrs->gamma5) || |
1233 | || !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) | 1267 | !check_gamma_bounds(attrs->gamma5, 0x00ffffff)) |
1234 | return -EINVAL; | 1268 | return -EINVAL; |
1269 | |||
1235 | if (!check_gamma5_errata(attrs->gamma5)) | 1270 | if (!check_gamma5_errata(attrs->gamma5)) |
1236 | return -EINVAL; | 1271 | return -EINVAL; |
1272 | |||
1237 | return 0; | 1273 | return 0; |
1238 | } | 1274 | } |
1239 | 1275 | ||
@@ -1260,13 +1296,14 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1260 | mutex_lock(&dev->mode_config.mutex); | 1296 | mutex_lock(&dev->mode_config.mutex); |
1261 | mutex_lock(&dev->struct_mutex); | 1297 | mutex_lock(&dev->struct_mutex); |
1262 | 1298 | ||
1299 | ret = -EINVAL; | ||
1263 | if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { | 1300 | if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { |
1264 | attrs->color_key = overlay->color_key; | 1301 | attrs->color_key = overlay->color_key; |
1265 | attrs->brightness = overlay->brightness; | 1302 | attrs->brightness = overlay->brightness; |
1266 | attrs->contrast = overlay->contrast; | 1303 | attrs->contrast = overlay->contrast; |
1267 | attrs->saturation = overlay->saturation; | 1304 | attrs->saturation = overlay->saturation; |
1268 | 1305 | ||
1269 | if (IS_I9XX(dev)) { | 1306 | if (!IS_GEN2(dev)) { |
1270 | attrs->gamma0 = I915_READ(OGAMC0); | 1307 | attrs->gamma0 = I915_READ(OGAMC0); |
1271 | attrs->gamma1 = I915_READ(OGAMC1); | 1308 | attrs->gamma1 = I915_READ(OGAMC1); |
1272 | attrs->gamma2 = I915_READ(OGAMC2); | 1309 | attrs->gamma2 = I915_READ(OGAMC2); |
@@ -1274,29 +1311,20 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1274 | attrs->gamma4 = I915_READ(OGAMC4); | 1311 | attrs->gamma4 = I915_READ(OGAMC4); |
1275 | attrs->gamma5 = I915_READ(OGAMC5); | 1312 | attrs->gamma5 = I915_READ(OGAMC5); |
1276 | } | 1313 | } |
1277 | ret = 0; | ||
1278 | } else { | 1314 | } else { |
1279 | overlay->color_key = attrs->color_key; | 1315 | if (attrs->brightness < -128 || attrs->brightness > 127) |
1280 | if (attrs->brightness >= -128 && attrs->brightness <= 127) { | ||
1281 | overlay->brightness = attrs->brightness; | ||
1282 | } else { | ||
1283 | ret = -EINVAL; | ||
1284 | goto out_unlock; | 1316 | goto out_unlock; |
1285 | } | 1317 | if (attrs->contrast > 255) |
1286 | if (attrs->contrast <= 255) { | ||
1287 | overlay->contrast = attrs->contrast; | ||
1288 | } else { | ||
1289 | ret = -EINVAL; | ||
1290 | goto out_unlock; | 1318 | goto out_unlock; |
1291 | } | 1319 | if (attrs->saturation > 1023) |
1292 | if (attrs->saturation <= 1023) { | ||
1293 | overlay->saturation = attrs->saturation; | ||
1294 | } else { | ||
1295 | ret = -EINVAL; | ||
1296 | goto out_unlock; | 1320 | goto out_unlock; |
1297 | } | ||
1298 | 1321 | ||
1299 | regs = intel_overlay_map_regs_atomic(overlay); | 1322 | overlay->color_key = attrs->color_key; |
1323 | overlay->brightness = attrs->brightness; | ||
1324 | overlay->contrast = attrs->contrast; | ||
1325 | overlay->saturation = attrs->saturation; | ||
1326 | |||
1327 | regs = intel_overlay_map_regs(overlay); | ||
1300 | if (!regs) { | 1328 | if (!regs) { |
1301 | ret = -ENOMEM; | 1329 | ret = -ENOMEM; |
1302 | goto out_unlock; | 1330 | goto out_unlock; |
@@ -1304,13 +1332,11 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1304 | 1332 | ||
1305 | update_reg_attrs(overlay, regs); | 1333 | update_reg_attrs(overlay, regs); |
1306 | 1334 | ||
1307 | intel_overlay_unmap_regs_atomic(overlay); | 1335 | intel_overlay_unmap_regs(overlay, regs); |
1308 | 1336 | ||
1309 | if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { | 1337 | if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { |
1310 | if (!IS_I9XX(dev)) { | 1338 | if (IS_GEN2(dev)) |
1311 | ret = -EINVAL; | ||
1312 | goto out_unlock; | 1339 | goto out_unlock; |
1313 | } | ||
1314 | 1340 | ||
1315 | if (overlay->active) { | 1341 | if (overlay->active) { |
1316 | ret = -EBUSY; | 1342 | ret = -EBUSY; |
@@ -1318,7 +1344,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1318 | } | 1344 | } |
1319 | 1345 | ||
1320 | ret = check_gamma(attrs); | 1346 | ret = check_gamma(attrs); |
1321 | if (ret != 0) | 1347 | if (ret) |
1322 | goto out_unlock; | 1348 | goto out_unlock; |
1323 | 1349 | ||
1324 | I915_WRITE(OGAMC0, attrs->gamma0); | 1350 | I915_WRITE(OGAMC0, attrs->gamma0); |
@@ -1328,9 +1354,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1328 | I915_WRITE(OGAMC4, attrs->gamma4); | 1354 | I915_WRITE(OGAMC4, attrs->gamma4); |
1329 | I915_WRITE(OGAMC5, attrs->gamma5); | 1355 | I915_WRITE(OGAMC5, attrs->gamma5); |
1330 | } | 1356 | } |
1331 | ret = 0; | ||
1332 | } | 1357 | } |
1333 | 1358 | ||
1359 | ret = 0; | ||
1334 | out_unlock: | 1360 | out_unlock: |
1335 | mutex_unlock(&dev->struct_mutex); | 1361 | mutex_unlock(&dev->struct_mutex); |
1336 | mutex_unlock(&dev->mode_config.mutex); | 1362 | mutex_unlock(&dev->mode_config.mutex); |
@@ -1346,7 +1372,7 @@ void intel_setup_overlay(struct drm_device *dev) | |||
1346 | struct overlay_registers *regs; | 1372 | struct overlay_registers *regs; |
1347 | int ret; | 1373 | int ret; |
1348 | 1374 | ||
1349 | if (!OVERLAY_EXISTS(dev)) | 1375 | if (!HAS_OVERLAY(dev)) |
1350 | return; | 1376 | return; |
1351 | 1377 | ||
1352 | overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL); | 1378 | overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL); |
@@ -1359,22 +1385,28 @@ void intel_setup_overlay(struct drm_device *dev) | |||
1359 | goto out_free; | 1385 | goto out_free; |
1360 | overlay->reg_bo = to_intel_bo(reg_bo); | 1386 | overlay->reg_bo = to_intel_bo(reg_bo); |
1361 | 1387 | ||
1362 | if (OVERLAY_NONPHYSICAL(dev)) { | 1388 | if (OVERLAY_NEEDS_PHYSICAL(dev)) { |
1363 | ret = i915_gem_object_pin(reg_bo, PAGE_SIZE); | ||
1364 | if (ret) { | ||
1365 | DRM_ERROR("failed to pin overlay register bo\n"); | ||
1366 | goto out_free_bo; | ||
1367 | } | ||
1368 | overlay->flip_addr = overlay->reg_bo->gtt_offset; | ||
1369 | } else { | ||
1370 | ret = i915_gem_attach_phys_object(dev, reg_bo, | 1389 | ret = i915_gem_attach_phys_object(dev, reg_bo, |
1371 | I915_GEM_PHYS_OVERLAY_REGS, | 1390 | I915_GEM_PHYS_OVERLAY_REGS, |
1372 | 0); | 1391 | PAGE_SIZE); |
1373 | if (ret) { | 1392 | if (ret) { |
1374 | DRM_ERROR("failed to attach phys overlay regs\n"); | 1393 | DRM_ERROR("failed to attach phys overlay regs\n"); |
1375 | goto out_free_bo; | 1394 | goto out_free_bo; |
1376 | } | 1395 | } |
1377 | overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; | 1396 | overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; |
1397 | } else { | ||
1398 | ret = i915_gem_object_pin(reg_bo, PAGE_SIZE); | ||
1399 | if (ret) { | ||
1400 | DRM_ERROR("failed to pin overlay register bo\n"); | ||
1401 | goto out_free_bo; | ||
1402 | } | ||
1403 | overlay->flip_addr = overlay->reg_bo->gtt_offset; | ||
1404 | |||
1405 | ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); | ||
1406 | if (ret) { | ||
1407 | DRM_ERROR("failed to move overlay register bo into the GTT\n"); | ||
1408 | goto out_unpin_bo; | ||
1409 | } | ||
1378 | } | 1410 | } |
1379 | 1411 | ||
1380 | /* init all values */ | 1412 | /* init all values */ |
@@ -1383,21 +1415,22 @@ void intel_setup_overlay(struct drm_device *dev) | |||
1383 | overlay->contrast = 75; | 1415 | overlay->contrast = 75; |
1384 | overlay->saturation = 146; | 1416 | overlay->saturation = 146; |
1385 | 1417 | ||
1386 | regs = intel_overlay_map_regs_atomic(overlay); | 1418 | regs = intel_overlay_map_regs(overlay); |
1387 | if (!regs) | 1419 | if (!regs) |
1388 | goto out_free_bo; | 1420 | goto out_free_bo; |
1389 | 1421 | ||
1390 | memset(regs, 0, sizeof(struct overlay_registers)); | 1422 | memset(regs, 0, sizeof(struct overlay_registers)); |
1391 | update_polyphase_filter(regs); | 1423 | update_polyphase_filter(regs); |
1392 | |||
1393 | update_reg_attrs(overlay, regs); | 1424 | update_reg_attrs(overlay, regs); |
1394 | 1425 | ||
1395 | intel_overlay_unmap_regs_atomic(overlay); | 1426 | intel_overlay_unmap_regs(overlay, regs); |
1396 | 1427 | ||
1397 | dev_priv->overlay = overlay; | 1428 | dev_priv->overlay = overlay; |
1398 | DRM_INFO("initialized overlay support\n"); | 1429 | DRM_INFO("initialized overlay support\n"); |
1399 | return; | 1430 | return; |
1400 | 1431 | ||
1432 | out_unpin_bo: | ||
1433 | i915_gem_object_unpin(reg_bo); | ||
1401 | out_free_bo: | 1434 | out_free_bo: |
1402 | drm_gem_object_unreference(reg_bo); | 1435 | drm_gem_object_unreference(reg_bo); |
1403 | out_free: | 1436 | out_free: |
@@ -1407,18 +1440,23 @@ out_free: | |||
1407 | 1440 | ||
1408 | void intel_cleanup_overlay(struct drm_device *dev) | 1441 | void intel_cleanup_overlay(struct drm_device *dev) |
1409 | { | 1442 | { |
1410 | drm_i915_private_t *dev_priv = dev->dev_private; | 1443 | drm_i915_private_t *dev_priv = dev->dev_private; |
1411 | 1444 | ||
1412 | if (dev_priv->overlay) { | 1445 | if (!dev_priv->overlay) |
1413 | /* The bo's should be free'd by the generic code already. | 1446 | return; |
1414 | * Furthermore modesetting teardown happens beforehand so the | ||
1415 | * hardware should be off already */ | ||
1416 | BUG_ON(dev_priv->overlay->active); | ||
1417 | 1447 | ||
1418 | kfree(dev_priv->overlay); | 1448 | /* The bo's should be free'd by the generic code already. |
1419 | } | 1449 | * Furthermore modesetting teardown happens beforehand so the |
1450 | * hardware should be off already */ | ||
1451 | BUG_ON(dev_priv->overlay->active); | ||
1452 | |||
1453 | drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base); | ||
1454 | kfree(dev_priv->overlay); | ||
1420 | } | 1455 | } |
1421 | 1456 | ||
1457 | #ifdef CONFIG_DEBUG_FS | ||
1458 | #include <linux/seq_file.h> | ||
1459 | |||
1422 | struct intel_overlay_error_state { | 1460 | struct intel_overlay_error_state { |
1423 | struct overlay_registers regs; | 1461 | struct overlay_registers regs; |
1424 | unsigned long base; | 1462 | unsigned long base; |
@@ -1426,6 +1464,29 @@ struct intel_overlay_error_state { | |||
1426 | u32 isr; | 1464 | u32 isr; |
1427 | }; | 1465 | }; |
1428 | 1466 | ||
1467 | static struct overlay_registers * | ||
1468 | intel_overlay_map_regs_atomic(struct intel_overlay *overlay) | ||
1469 | { | ||
1470 | drm_i915_private_t *dev_priv = overlay->dev->dev_private; | ||
1471 | struct overlay_registers *regs; | ||
1472 | |||
1473 | if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) | ||
1474 | regs = overlay->reg_bo->phys_obj->handle->vaddr; | ||
1475 | else | ||
1476 | regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, | ||
1477 | overlay->reg_bo->gtt_offset); | ||
1478 | |||
1479 | return regs; | ||
1480 | } | ||
1481 | |||
1482 | static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay, | ||
1483 | struct overlay_registers *regs) | ||
1484 | { | ||
1485 | if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) | ||
1486 | io_mapping_unmap_atomic(regs); | ||
1487 | } | ||
1488 | |||
1489 | |||
1429 | struct intel_overlay_error_state * | 1490 | struct intel_overlay_error_state * |
1430 | intel_overlay_capture_error_state(struct drm_device *dev) | 1491 | intel_overlay_capture_error_state(struct drm_device *dev) |
1431 | { | 1492 | { |
@@ -1443,17 +1504,17 @@ intel_overlay_capture_error_state(struct drm_device *dev) | |||
1443 | 1504 | ||
1444 | error->dovsta = I915_READ(DOVSTA); | 1505 | error->dovsta = I915_READ(DOVSTA); |
1445 | error->isr = I915_READ(ISR); | 1506 | error->isr = I915_READ(ISR); |
1446 | if (OVERLAY_NONPHYSICAL(overlay->dev)) | 1507 | if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) |
1447 | error->base = (long) overlay->reg_bo->gtt_offset; | ||
1448 | else | ||
1449 | error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; | 1508 | error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; |
1509 | else | ||
1510 | error->base = (long) overlay->reg_bo->gtt_offset; | ||
1450 | 1511 | ||
1451 | regs = intel_overlay_map_regs_atomic(overlay); | 1512 | regs = intel_overlay_map_regs_atomic(overlay); |
1452 | if (!regs) | 1513 | if (!regs) |
1453 | goto err; | 1514 | goto err; |
1454 | 1515 | ||
1455 | memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); | 1516 | memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); |
1456 | intel_overlay_unmap_regs_atomic(overlay); | 1517 | intel_overlay_unmap_regs_atomic(overlay, regs); |
1457 | 1518 | ||
1458 | return error; | 1519 | return error; |
1459 | 1520 | ||
@@ -1514,3 +1575,4 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s | |||
1514 | P(UVSCALEV); | 1575 | P(UVSCALEV); |
1515 | #undef P | 1576 | #undef P |
1516 | } | 1577 | } |
1578 | #endif | ||