aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/intel_display.c218
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h7
2 files changed, 160 insertions, 65 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2f58d97972d..2c2ecab6627 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3604,89 +3604,177 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
3604 } 3604 }
3605} 3605}
3606 3606
3607static void g4x_update_wm(struct drm_device *dev, int planea_clock, 3607static bool g4x_compute_wm0(struct drm_device *dev,
3608 int planeb_clock, int sr_hdisplay, int sr_htotal, 3608 int plane,
3609 int pixel_size) 3609 const struct intel_watermark_params *display,
3610 int display_latency_ns,
3611 const struct intel_watermark_params *cursor,
3612 int cursor_latency_ns,
3613 int *plane_wm,
3614 int *cursor_wm)
3610{ 3615{
3611 struct drm_i915_private *dev_priv = dev->dev_private; 3616 struct drm_crtc *crtc;
3612 int total_size, cacheline_size; 3617 int htotal, hdisplay, clock, pixel_size;
3613 int planea_wm, planeb_wm, cursora_wm, cursorb_wm, cursor_sr; 3618 int line_time_us, line_count;
3614 struct intel_watermark_params planea_params, planeb_params; 3619 int entries, tlb_miss;
3615 unsigned long line_time_us;
3616 int sr_clock, sr_entries = 0, entries_required;
3617 3620
3618 /* Create copies of the base settings for each pipe */ 3621 crtc = intel_get_crtc_for_plane(dev, plane);
3619 planea_params = planeb_params = g4x_wm_info; 3622 if (crtc->fb == NULL || !crtc->enabled)
3623 return false;
3620 3624
3621 /* Grab a couple of global values before we overwrite them */ 3625 htotal = crtc->mode.htotal;
3622 total_size = planea_params.fifo_size; 3626 hdisplay = crtc->mode.hdisplay;
3623 cacheline_size = planea_params.cacheline_size; 3627 clock = crtc->mode.clock;
3628 pixel_size = crtc->fb->bits_per_pixel / 8;
3624 3629
3625 /* 3630 /* Use the small buffer method to calculate plane watermark */
3626 * Note: we need to make sure we don't overflow for various clock & 3631 entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
3627 * latency values. 3632 tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
3628 * clocks go from a few thousand to several hundred thousand. 3633 if (tlb_miss > 0)
3629 * latency is usually a few thousand 3634 entries += tlb_miss;
3630 */ 3635 entries = DIV_ROUND_UP(entries, display->cacheline_size);
3631 entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) / 3636 *plane_wm = entries + display->guard_size;
3632 1000; 3637 if (*plane_wm > (int)display->max_wm)
3633 entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE); 3638 *plane_wm = display->max_wm;
3634 planea_wm = entries_required + planea_params.guard_size;
3635 3639
3636 entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) / 3640 /* Use the large buffer method to calculate cursor watermark */
3637 1000; 3641 line_time_us = ((htotal * 1000) / clock);
3638 entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE); 3642 line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
3639 planeb_wm = entries_required + planeb_params.guard_size; 3643 entries = line_count * 64 * pixel_size;
3644 tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
3645 if (tlb_miss > 0)
3646 entries += tlb_miss;
3647 entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
3648 *cursor_wm = entries + cursor->guard_size;
3649 if (*cursor_wm > (int)cursor->max_wm)
3650 *cursor_wm = (int)cursor->max_wm;
3640 3651
3641 cursora_wm = cursorb_wm = 16; 3652 return true;
3642 cursor_sr = 32; 3653}
3643 3654
3644 DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); 3655/*
3656 * Check the wm result.
3657 *
3658 * If any calculated watermark values is larger than the maximum value that
3659 * can be programmed into the associated watermark register, that watermark
3660 * must be disabled.
3661 */
3662static bool g4x_check_srwm(struct drm_device *dev,
3663 int display_wm, int cursor_wm,
3664 const struct intel_watermark_params *display,
3665 const struct intel_watermark_params *cursor)
3666{
3667 DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n",
3668 display_wm, cursor_wm);
3645 3669
3646 /* Calc sr entries for one plane configs */ 3670 if (display_wm > display->max_wm) {
3647 if (sr_hdisplay && (!planea_clock || !planeb_clock)) { 3671 DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n",
3648 /* self-refresh has much higher latency */ 3672 display_wm, display->max_wm);
3649 static const int sr_latency_ns = 12000; 3673 return false;
3674 }
3650 3675
3651 sr_clock = planea_clock ? planea_clock : planeb_clock; 3676 if (cursor_wm > cursor->max_wm) {
3652 line_time_us = ((sr_htotal * 1000) / sr_clock); 3677 DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n",
3678 cursor_wm, cursor->max_wm);
3679 return false;
3680 }
3653 3681
3654 /* Use ns/us then divide to preserve precision */ 3682 if (!(display_wm || cursor_wm)) {
3655 sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * 3683 DRM_DEBUG_KMS("SR latency is 0, disabling\n");
3656 pixel_size * sr_hdisplay; 3684 return false;
3657 sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); 3685 }
3658 3686
3659 entries_required = (((sr_latency_ns / line_time_us) + 3687 return true;
3660 1000) / 1000) * pixel_size * 64; 3688}
3661 entries_required = DIV_ROUND_UP(entries_required,
3662 g4x_cursor_wm_info.cacheline_size);
3663 cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
3664 3689
3665 if (cursor_sr > g4x_cursor_wm_info.max_wm) 3690static bool g4x_compute_srwm(struct drm_device *dev,
3666 cursor_sr = g4x_cursor_wm_info.max_wm; 3691 int hdisplay, int htotal,
3667 DRM_DEBUG_KMS("self-refresh watermark: display plane %d " 3692 int pixel_size, int clock, int latency_ns,
3668 "cursor %d\n", sr_entries, cursor_sr); 3693 const struct intel_watermark_params *display,
3694 const struct intel_watermark_params *cursor,
3695 int *display_wm, int *cursor_wm)
3696{
3697 unsigned long line_time_us;
3698 int line_count, line_size;
3699 int small, large;
3700 int entries;
3669 3701
3670 I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); 3702 if (!latency_ns) {
3671 } else { 3703 *display_wm = *cursor_wm = 0;
3672 /* Turn off self refresh if both pipes are enabled */ 3704 return false;
3673 I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
3674 & ~FW_BLC_SELF_EN);
3675 } 3705 }
3676 3706
3677 DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n", 3707 line_time_us = (htotal * 1000) / clock;
3678 planea_wm, planeb_wm, sr_entries); 3708 line_count = (latency_ns / line_time_us + 1000) / 1000;
3709 line_size = hdisplay * pixel_size;
3710
3711 /* Use the minimum of the small and large buffer method for primary */
3712 small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
3713 large = line_count * line_size;
3714
3715 entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
3716 *display_wm = entries + display->guard_size;
3717
3718 /* calculate the self-refresh watermark for display cursor */
3719 entries = line_count * pixel_size * 64;
3720 entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
3721 *cursor_wm = entries + cursor->guard_size;
3722
3723 return g4x_check_srwm(dev,
3724 *display_wm, *cursor_wm,
3725 display, cursor);
3726}
3727
3728static void g4x_update_wm(struct drm_device *dev,
3729 int planea_clock, int planeb_clock,
3730 int hdisplay, int htotal, int pixel_size)
3731{
3732 static const int sr_latency_ns = 12000;
3733 struct drm_i915_private *dev_priv = dev->dev_private;
3734 int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
3735 int enabled = 0, plane_sr, cursor_sr, clock;
3736
3737 if (g4x_compute_wm0(dev, 0,
3738 &g4x_wm_info, latency_ns,
3739 &g4x_cursor_wm_info, latency_ns,
3740 &planea_wm, &cursora_wm))
3741 enabled++;
3742
3743 if (g4x_compute_wm0(dev, 1,
3744 &g4x_wm_info, latency_ns,
3745 &g4x_cursor_wm_info, latency_ns,
3746 &planeb_wm, &cursorb_wm))
3747 enabled++;
3748
3749 plane_sr = cursor_sr = 0;
3750 clock = planea_clock ? planea_clock : planeb_clock;
3751 if (enabled == 1 &&
3752 g4x_compute_srwm(dev, hdisplay, htotal, pixel_size,
3753 clock, sr_latency_ns,
3754 &g4x_wm_info,
3755 &g4x_cursor_wm_info,
3756 &plane_sr, &cursor_sr))
3757 I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
3758 else
3759 I915_WRITE(FW_BLC_SELF,
3760 I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN);
3679 3761
3680 planea_wm &= 0x3f; 3762 DRM_DEBUG("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
3681 planeb_wm &= 0x3f; 3763 planea_wm, cursora_wm,
3764 planeb_wm, cursorb_wm,
3765 plane_sr, cursor_sr);
3682 3766
3683 I915_WRITE(DSPFW1, (sr_entries << DSPFW_SR_SHIFT) | 3767 I915_WRITE(DSPFW1,
3768 (plane_sr << DSPFW_SR_SHIFT) |
3684 (cursorb_wm << DSPFW_CURSORB_SHIFT) | 3769 (cursorb_wm << DSPFW_CURSORB_SHIFT) |
3685 (planeb_wm << DSPFW_PLANEB_SHIFT) | planea_wm); 3770 (planeb_wm << DSPFW_PLANEB_SHIFT) |
3686 I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | 3771 planea_wm);
3772 I915_WRITE(DSPFW2,
3773 (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
3687 (cursora_wm << DSPFW_CURSORA_SHIFT)); 3774 (cursora_wm << DSPFW_CURSORA_SHIFT));
3688 /* HPLL off in SR has some issues on G4x... disable it */ 3775 /* HPLL off in SR has some issues on G4x... disable it */
3689 I915_WRITE(DSPFW3, (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | 3776 I915_WRITE(DSPFW3,
3777 (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
3690 (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); 3778 (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
3691} 3779}
3692 3780
@@ -3743,8 +3831,8 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
3743 srwm); 3831 srwm);
3744 3832
3745 /* 965 has limitations... */ 3833 /* 965 has limitations... */
3746 I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) | 3834 I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
3747 (8 << 0)); 3835 (8 << 16) | (8 << 8) | (8 << 0));
3748 I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); 3836 I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
3749 /* update cursor SR watermark */ 3837 /* update cursor SR watermark */
3750 I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); 3838 I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 74db2557d64..5ce4a5f13de 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -217,6 +217,13 @@ intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
217 return dev_priv->pipe_to_crtc_mapping[pipe]; 217 return dev_priv->pipe_to_crtc_mapping[pipe];
218} 218}
219 219
220static inline struct drm_crtc *
221intel_get_crtc_for_plane(struct drm_device *dev, int plane)
222{
223 struct drm_i915_private *dev_priv = dev->dev_private;
224 return dev_priv->plane_to_crtc_mapping[plane];
225}
226
220struct intel_unpin_work { 227struct intel_unpin_work {
221 struct work_struct work; 228 struct work_struct work;
222 struct drm_device *dev; 229 struct drm_device *dev;