aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2016-08-03 23:39:39 -0400
committerAlex Deucher <alexander.deucher@amd.com>2016-08-10 14:28:07 -0400
commitb8fc75cfee43232e12673ddebb3539ea805105ea (patch)
tree6eccfc601f4f242f7e020ce08962c1797041e16c /drivers/gpu
parent3fd4b751c5409f4b9bf67d12b26356406b2af94c (diff)
drm/radeon: Provide page_flip_target hook
Now we can program a flip during a vertical blank period, if it's the one targeted by the flip (or a later one). This allows simplifying radeon_flip_work_func considerably. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/radeon/radeon.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c89
2 files changed, 25 insertions, 65 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 5633ee3eb46e..1b0dcad916b0 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -742,6 +742,7 @@ struct radeon_flip_work {
742 struct work_struct unpin_work; 742 struct work_struct unpin_work;
743 struct radeon_device *rdev; 743 struct radeon_device *rdev;
744 int crtc_id; 744 int crtc_id;
745 u32 target_vblank;
745 uint64_t base; 746 uint64_t base;
746 struct drm_pending_vblank_event *event; 747 struct drm_pending_vblank_event *event;
747 struct radeon_bo *old_rbo; 748 struct radeon_bo *old_rbo;
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index c3206fb8f4cf..890171f08987 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -400,14 +400,13 @@ static void radeon_flip_work_func(struct work_struct *__work)
400 struct radeon_flip_work *work = 400 struct radeon_flip_work *work =
401 container_of(__work, struct radeon_flip_work, flip_work); 401 container_of(__work, struct radeon_flip_work, flip_work);
402 struct radeon_device *rdev = work->rdev; 402 struct radeon_device *rdev = work->rdev;
403 struct drm_device *dev = rdev->ddev;
403 struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; 404 struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id];
404 405
405 struct drm_crtc *crtc = &radeon_crtc->base; 406 struct drm_crtc *crtc = &radeon_crtc->base;
406 unsigned long flags; 407 unsigned long flags;
407 int r; 408 int r;
408 int vpos, hpos, stat, min_udelay = 0; 409 int vpos, hpos;
409 unsigned repcnt = 4;
410 struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
411 410
412 down_read(&rdev->exclusive_lock); 411 down_read(&rdev->exclusive_lock);
413 if (work->fence) { 412 if (work->fence) {
@@ -438,59 +437,25 @@ static void radeon_flip_work_func(struct work_struct *__work)
438 work->fence = NULL; 437 work->fence = NULL;
439 } 438 }
440 439
440 /* Wait until we're out of the vertical blank period before the one
441 * targeted by the flip
442 */
443 while (radeon_crtc->enabled &&
444 (radeon_get_crtc_scanoutpos(dev, work->crtc_id, 0,
445 &vpos, &hpos, NULL, NULL,
446 &crtc->hwmode)
447 & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
448 (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
449 (int)(work->target_vblank -
450 dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0)
451 usleep_range(1000, 2000);
452
441 /* We borrow the event spin lock for protecting flip_status */ 453 /* We borrow the event spin lock for protecting flip_status */
442 spin_lock_irqsave(&crtc->dev->event_lock, flags); 454 spin_lock_irqsave(&crtc->dev->event_lock, flags);
443 455
444 /* set the proper interrupt */ 456 /* set the proper interrupt */
445 radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); 457 radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id);
446 458
447 /* If this happens to execute within the "virtually extended" vblank
448 * interval before the start of the real vblank interval then it needs
449 * to delay programming the mmio flip until the real vblank is entered.
450 * This prevents completing a flip too early due to the way we fudge
451 * our vblank counter and vblank timestamps in order to work around the
452 * problem that the hw fires vblank interrupts before actual start of
453 * vblank (when line buffer refilling is done for a frame). It
454 * complements the fudging logic in radeon_get_crtc_scanoutpos() for
455 * timestamping and radeon_get_vblank_counter_kms() for vblank counts.
456 *
457 * In practice this won't execute very often unless on very fast
458 * machines because the time window for this to happen is very small.
459 */
460 while (radeon_crtc->enabled && --repcnt) {
461 /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
462 * start in hpos, and to the "fudged earlier" vblank start in
463 * vpos.
464 */
465 stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id,
466 GET_DISTANCE_TO_VBLANKSTART,
467 &vpos, &hpos, NULL, NULL,
468 &crtc->hwmode);
469
470 if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
471 (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
472 !(vpos >= 0 && hpos <= 0))
473 break;
474
475 /* Sleep at least until estimated real start of hw vblank */
476 min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
477 if (min_udelay > vblank->framedur_ns / 2000) {
478 /* Don't wait ridiculously long - something is wrong */
479 repcnt = 0;
480 break;
481 }
482 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
483 usleep_range(min_udelay, 2 * min_udelay);
484 spin_lock_irqsave(&crtc->dev->event_lock, flags);
485 };
486
487 if (!repcnt)
488 DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
489 "framedur %d, linedur %d, stat %d, vpos %d, "
490 "hpos %d\n", work->crtc_id, min_udelay,
491 vblank->framedur_ns / 1000,
492 vblank->linedur_ns / 1000, stat, vpos, hpos);
493
494 /* do the flip (mmio) */ 459 /* do the flip (mmio) */
495 radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async); 460 radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async);
496 461
@@ -499,10 +464,11 @@ static void radeon_flip_work_func(struct work_struct *__work)
499 up_read(&rdev->exclusive_lock); 464 up_read(&rdev->exclusive_lock);
500} 465}
501 466
502static int radeon_crtc_page_flip(struct drm_crtc *crtc, 467static int radeon_crtc_page_flip_target(struct drm_crtc *crtc,
503 struct drm_framebuffer *fb, 468 struct drm_framebuffer *fb,
504 struct drm_pending_vblank_event *event, 469 struct drm_pending_vblank_event *event,
505 uint32_t page_flip_flags) 470 uint32_t page_flip_flags,
471 uint32_t target)
506{ 472{
507 struct drm_device *dev = crtc->dev; 473 struct drm_device *dev = crtc->dev;
508 struct radeon_device *rdev = dev->dev_private; 474 struct radeon_device *rdev = dev->dev_private;
@@ -599,12 +565,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
599 base &= ~7; 565 base &= ~7;
600 } 566 }
601 work->base = base; 567 work->base = base;
602 568 work->target_vblank = target - drm_crtc_vblank_count(crtc) +
603 r = drm_crtc_vblank_get(crtc); 569 dev->driver->get_vblank_counter(dev, work->crtc_id);
604 if (r) {
605 DRM_ERROR("failed to get vblank before flip\n");
606 goto pflip_cleanup;
607 }
608 570
609 /* We borrow the event spin lock for protecting flip_work */ 571 /* We borrow the event spin lock for protecting flip_work */
610 spin_lock_irqsave(&crtc->dev->event_lock, flags); 572 spin_lock_irqsave(&crtc->dev->event_lock, flags);
@@ -613,7 +575,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
613 DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); 575 DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
614 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 576 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
615 r = -EBUSY; 577 r = -EBUSY;
616 goto vblank_cleanup; 578 goto pflip_cleanup;
617 } 579 }
618 radeon_crtc->flip_status = RADEON_FLIP_PENDING; 580 radeon_crtc->flip_status = RADEON_FLIP_PENDING;
619 radeon_crtc->flip_work = work; 581 radeon_crtc->flip_work = work;
@@ -626,9 +588,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
626 queue_work(radeon_crtc->flip_queue, &work->flip_work); 588 queue_work(radeon_crtc->flip_queue, &work->flip_work);
627 return 0; 589 return 0;
628 590
629vblank_cleanup:
630 drm_crtc_vblank_put(crtc);
631
632pflip_cleanup: 591pflip_cleanup:
633 if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) { 592 if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) {
634 DRM_ERROR("failed to reserve new rbo in error path\n"); 593 DRM_ERROR("failed to reserve new rbo in error path\n");
@@ -697,7 +656,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
697 .gamma_set = radeon_crtc_gamma_set, 656 .gamma_set = radeon_crtc_gamma_set,
698 .set_config = radeon_crtc_set_config, 657 .set_config = radeon_crtc_set_config,
699 .destroy = radeon_crtc_destroy, 658 .destroy = radeon_crtc_destroy,
700 .page_flip = radeon_crtc_page_flip, 659 .page_flip_target = radeon_crtc_page_flip_target,
701}; 660};
702 661
703static void radeon_crtc_init(struct drm_device *dev, int index) 662static void radeon_crtc_init(struct drm_device *dev, int index)