diff options
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 218 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 7 |
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 | ||
3607 | static void g4x_update_wm(struct drm_device *dev, int planea_clock, | 3607 | static 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 | */ | ||
3662 | static 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) | 3690 | static 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 | |||
3728 | static 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 | ||
220 | static inline struct drm_crtc * | ||
221 | intel_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 | |||
220 | struct intel_unpin_work { | 227 | struct intel_unpin_work { |
221 | struct work_struct work; | 228 | struct work_struct work; |
222 | struct drm_device *dev; | 229 | struct drm_device *dev; |