aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorYuanhan Liu <yuanhan.liu@linux.intel.com>2010-12-15 02:42:31 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2010-12-15 06:16:57 -0500
commit1398261a2e84c537c409259cfe9db3d0abcd9f99 (patch)
treebbf7e6a450d83775b093b5a50e976a230e46fdd3 /drivers/gpu/drm/i915/intel_display.c
parentb7f1de289c50beb4998611ba5373e539efd0f79f (diff)
drm/i915: Add self-refresh support on Sandybridge
Add the support of memory self-refresh on Sandybridge, which is now support 3 levels of watermarks and the source of the latency values for watermarks has changed. On Sandybridge, the LP0 WM value is not hardcoded any more. All the latency value is now should be extracted from MCHBAR SSKPD register. And the MCHBAR base address is changed, too. For the WM values, if any calculated watermark values is larger than the maximum value that can be programmed into the associated watermark register, that watermark must be disabled. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> [ickle: remove duplicate compute routines and fixup for checkpatch] Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c310
1 files changed, 293 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 840bfc3ae719..eaf2bc6b537d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2845,6 +2845,39 @@ static struct intel_watermark_params ironlake_cursor_srwm_info = {
2845 ILK_FIFO_LINE_SIZE 2845 ILK_FIFO_LINE_SIZE
2846}; 2846};
2847 2847
2848static struct intel_watermark_params sandybridge_display_wm_info = {
2849 SNB_DISPLAY_FIFO,
2850 SNB_DISPLAY_MAXWM,
2851 SNB_DISPLAY_DFTWM,
2852 2,
2853 SNB_FIFO_LINE_SIZE
2854};
2855
2856static struct intel_watermark_params sandybridge_cursor_wm_info = {
2857 SNB_CURSOR_FIFO,
2858 SNB_CURSOR_MAXWM,
2859 SNB_CURSOR_DFTWM,
2860 2,
2861 SNB_FIFO_LINE_SIZE
2862};
2863
2864static struct intel_watermark_params sandybridge_display_srwm_info = {
2865 SNB_DISPLAY_SR_FIFO,
2866 SNB_DISPLAY_MAX_SRWM,
2867 SNB_DISPLAY_DFT_SRWM,
2868 2,
2869 SNB_FIFO_LINE_SIZE
2870};
2871
2872static struct intel_watermark_params sandybridge_cursor_srwm_info = {
2873 SNB_CURSOR_SR_FIFO,
2874 SNB_CURSOR_MAX_SRWM,
2875 SNB_CURSOR_DFT_SRWM,
2876 2,
2877 SNB_FIFO_LINE_SIZE
2878};
2879
2880
2848/** 2881/**
2849 * intel_calculate_wm - calculate watermark level 2882 * intel_calculate_wm - calculate watermark level
2850 * @clock_in_khz: pixel clock 2883 * @clock_in_khz: pixel clock
@@ -3378,6 +3411,10 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
3378 3411
3379static bool ironlake_compute_wm0(struct drm_device *dev, 3412static bool ironlake_compute_wm0(struct drm_device *dev,
3380 int pipe, 3413 int pipe,
3414 const struct intel_watermark_params *display,
3415 int display_latency,
3416 const struct intel_watermark_params *cursor,
3417 int cursor_latency,
3381 int *plane_wm, 3418 int *plane_wm,
3382 int *cursor_wm) 3419 int *cursor_wm)
3383{ 3420{
@@ -3395,22 +3432,20 @@ static bool ironlake_compute_wm0(struct drm_device *dev,
3395 pixel_size = crtc->fb->bits_per_pixel / 8; 3432 pixel_size = crtc->fb->bits_per_pixel / 8;
3396 3433
3397 /* Use the small buffer method to calculate plane watermark */ 3434 /* Use the small buffer method to calculate plane watermark */
3398 entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000; 3435 entries = ((clock * pixel_size / 1000) * display_latency * 100) / 1000;
3399 entries = DIV_ROUND_UP(entries, 3436 entries = DIV_ROUND_UP(entries, display->cacheline_size);
3400 ironlake_display_wm_info.cacheline_size); 3437 *plane_wm = entries + display->guard_size;
3401 *plane_wm = entries + ironlake_display_wm_info.guard_size; 3438 if (*plane_wm > (int)display->max_wm)
3402 if (*plane_wm > (int)ironlake_display_wm_info.max_wm) 3439 *plane_wm = display->max_wm;
3403 *plane_wm = ironlake_display_wm_info.max_wm;
3404 3440
3405 /* Use the large buffer method to calculate cursor watermark */ 3441 /* Use the large buffer method to calculate cursor watermark */
3406 line_time_us = ((htotal * 1000) / clock); 3442 line_time_us = ((htotal * 1000) / clock);
3407 line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; 3443 line_count = (cursor_latency * 100 / line_time_us + 1000) / 1000;
3408 entries = line_count * 64 * pixel_size; 3444 entries = line_count * 64 * pixel_size;
3409 entries = DIV_ROUND_UP(entries, 3445 entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
3410 ironlake_cursor_wm_info.cacheline_size); 3446 *cursor_wm = entries + cursor->guard_size;
3411 *cursor_wm = entries + ironlake_cursor_wm_info.guard_size; 3447 if (*cursor_wm > (int)cursor->max_wm)
3412 if (*cursor_wm > ironlake_cursor_wm_info.max_wm) 3448 *cursor_wm = (int)cursor->max_wm;
3413 *cursor_wm = ironlake_cursor_wm_info.max_wm;
3414 3449
3415 return true; 3450 return true;
3416} 3451}
@@ -3425,7 +3460,12 @@ static void ironlake_update_wm(struct drm_device *dev,
3425 int tmp; 3460 int tmp;
3426 3461
3427 enabled = 0; 3462 enabled = 0;
3428 if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) { 3463 if (ironlake_compute_wm0(dev, 0,
3464 &ironlake_display_wm_info,
3465 ILK_LP0_PLANE_LATENCY,
3466 &ironlake_cursor_wm_info,
3467 ILK_LP0_CURSOR_LATENCY,
3468 &plane_wm, &cursor_wm)) {
3429 I915_WRITE(WM0_PIPEA_ILK, 3469 I915_WRITE(WM0_PIPEA_ILK,
3430 (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); 3470 (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
3431 DRM_DEBUG_KMS("FIFO watermarks For pipe A -" 3471 DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
@@ -3434,7 +3474,12 @@ static void ironlake_update_wm(struct drm_device *dev,
3434 enabled++; 3474 enabled++;
3435 } 3475 }
3436 3476
3437 if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) { 3477 if (ironlake_compute_wm0(dev, 1,
3478 &ironlake_display_wm_info,
3479 ILK_LP0_PLANE_LATENCY,
3480 &ironlake_cursor_wm_info,
3481 ILK_LP0_CURSOR_LATENCY,
3482 &plane_wm, &cursor_wm)) {
3438 I915_WRITE(WM0_PIPEB_ILK, 3483 I915_WRITE(WM0_PIPEB_ILK,
3439 (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); 3484 (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
3440 DRM_DEBUG_KMS("FIFO watermarks For pipe B -" 3485 DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
@@ -3500,6 +3545,197 @@ static void ironlake_update_wm(struct drm_device *dev,
3500 /* XXX setup WM2 and WM3 */ 3545 /* XXX setup WM2 and WM3 */
3501} 3546}
3502 3547
3548/*
3549 * Check the wm result.
3550 *
3551 * If any calculated watermark values is larger than the maximum value that
3552 * can be programmed into the associated watermark register, that watermark
3553 * must be disabled.
3554 *
3555 * Also return true if all of those watermark values is 0, which is set by
3556 * sandybridge_compute_srwm, to indicate the latency is ZERO.
3557 */
3558static bool sandybridge_check_srwm(struct drm_device *dev, int level,
3559 int fbc_wm, int display_wm, int cursor_wm)
3560{
3561 struct drm_i915_private *dev_priv = dev->dev_private;
3562
3563 DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
3564 " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
3565
3566 if (fbc_wm > SNB_FBC_MAX_SRWM) {
3567 DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
3568 fbc_wm, SNB_FBC_MAX_SRWM, level);
3569
3570 /* fbc has it's own way to disable FBC WM */
3571 I915_WRITE(DISP_ARB_CTL,
3572 I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
3573 return false;
3574 }
3575
3576 if (display_wm > SNB_DISPLAY_MAX_SRWM) {
3577 DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
3578 display_wm, SNB_DISPLAY_MAX_SRWM, level);
3579 return false;
3580 }
3581
3582 if (cursor_wm > SNB_CURSOR_MAX_SRWM) {
3583 DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
3584 cursor_wm, SNB_CURSOR_MAX_SRWM, level);
3585 return false;
3586 }
3587
3588 if (!(fbc_wm || display_wm || cursor_wm)) {
3589 DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
3590 return false;
3591 }
3592
3593 return true;
3594}
3595
3596/*
3597 * Compute watermark values of WM[1-3],
3598 */
3599static bool sandybridge_compute_srwm(struct drm_device *dev, int level,
3600 int hdisplay, int htotal, int pixel_size,
3601 int clock, int latency_ns, int *fbc_wm,
3602 int *display_wm, int *cursor_wm)
3603{
3604
3605 unsigned long line_time_us;
3606 int small, large;
3607 int entries;
3608 int line_count, line_size;
3609
3610 if (!latency_ns) {
3611 *fbc_wm = *display_wm = *cursor_wm = 0;
3612 return false;
3613 }
3614
3615 line_time_us = (htotal * 1000) / clock;
3616 line_count = (latency_ns / line_time_us + 1000) / 1000;
3617 line_size = hdisplay * pixel_size;
3618
3619 /* Use the minimum of the small and large buffer method for primary */
3620 small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
3621 large = line_count * line_size;
3622
3623 entries = DIV_ROUND_UP(min(small, large),
3624 sandybridge_display_srwm_info.cacheline_size);
3625 *display_wm = entries + sandybridge_display_srwm_info.guard_size;
3626
3627 /*
3628 * Spec said:
3629 * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
3630 */
3631 *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
3632
3633 /* calculate the self-refresh watermark for display cursor */
3634 entries = line_count * pixel_size * 64;
3635 entries = DIV_ROUND_UP(entries,
3636 sandybridge_cursor_srwm_info.cacheline_size);
3637 *cursor_wm = entries + sandybridge_cursor_srwm_info.guard_size;
3638
3639 return sandybridge_check_srwm(dev, level,
3640 *fbc_wm, *display_wm, *cursor_wm);
3641}
3642
3643static void sandybridge_update_wm(struct drm_device *dev,
3644 int planea_clock, int planeb_clock,
3645 int hdisplay, int htotal,
3646 int pixel_size)
3647{
3648 struct drm_i915_private *dev_priv = dev->dev_private;
3649 int latency = SNB_READ_WM0_LATENCY();
3650 int fbc_wm, plane_wm, cursor_wm, enabled;
3651 int clock;
3652
3653 enabled = 0;
3654 if (ironlake_compute_wm0(dev, 0,
3655 &sandybridge_display_wm_info, latency,
3656 &sandybridge_cursor_wm_info, latency,
3657 &plane_wm, &cursor_wm)) {
3658 I915_WRITE(WM0_PIPEA_ILK,
3659 (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
3660 DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
3661 " plane %d, " "cursor: %d\n",
3662 plane_wm, cursor_wm);
3663 enabled++;
3664 }
3665
3666 if (ironlake_compute_wm0(dev, 1,
3667 &sandybridge_display_wm_info, latency,
3668 &sandybridge_cursor_wm_info, latency,
3669 &plane_wm, &cursor_wm)) {
3670 I915_WRITE(WM0_PIPEB_ILK,
3671 (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
3672 DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
3673 " plane %d, cursor: %d\n",
3674 plane_wm, cursor_wm);
3675 enabled++;
3676 }
3677
3678 /*
3679 * Calculate and update the self-refresh watermark only when one
3680 * display plane is used.
3681 *
3682 * SNB support 3 levels of watermark.
3683 *
3684 * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
3685 * and disabled in the descending order
3686 *
3687 */
3688 I915_WRITE(WM3_LP_ILK, 0);
3689 I915_WRITE(WM2_LP_ILK, 0);
3690 I915_WRITE(WM1_LP_ILK, 0);
3691
3692 if (enabled != 1)
3693 return;
3694
3695 clock = planea_clock ? planea_clock : planeb_clock;
3696
3697 /* WM1 */
3698 if (!sandybridge_compute_srwm(dev, 1, hdisplay, htotal, pixel_size,
3699 clock, SNB_READ_WM1_LATENCY() * 500,
3700 &fbc_wm, &plane_wm, &cursor_wm))
3701 return;
3702
3703 I915_WRITE(WM1_LP_ILK,
3704 WM1_LP_SR_EN |
3705 (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
3706 (fbc_wm << WM1_LP_FBC_SHIFT) |
3707 (plane_wm << WM1_LP_SR_SHIFT) |
3708 cursor_wm);
3709
3710 /* WM2 */
3711 if (!sandybridge_compute_srwm(dev, 2,
3712 hdisplay, htotal, pixel_size,
3713 clock, SNB_READ_WM2_LATENCY() * 500,
3714 &fbc_wm, &plane_wm, &cursor_wm))
3715 return;
3716
3717 I915_WRITE(WM2_LP_ILK,
3718 WM2_LP_EN |
3719 (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
3720 (fbc_wm << WM1_LP_FBC_SHIFT) |
3721 (plane_wm << WM1_LP_SR_SHIFT) |
3722 cursor_wm);
3723
3724 /* WM3 */
3725 if (!sandybridge_compute_srwm(dev, 3,
3726 hdisplay, htotal, pixel_size,
3727 clock, SNB_READ_WM3_LATENCY() * 500,
3728 &fbc_wm, &plane_wm, &cursor_wm))
3729 return;
3730
3731 I915_WRITE(WM3_LP_ILK,
3732 WM3_LP_EN |
3733 (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
3734 (fbc_wm << WM1_LP_FBC_SHIFT) |
3735 (plane_wm << WM1_LP_SR_SHIFT) |
3736 cursor_wm);
3737}
3738
3503/** 3739/**
3504 * intel_update_watermarks - update FIFO watermark values based on current modes 3740 * intel_update_watermarks - update FIFO watermark values based on current modes
3505 * 3741 *
@@ -5975,9 +6211,9 @@ void intel_enable_clock_gating(struct drm_device *dev)
5975 I915_WRITE(DISP_ARB_CTL, 6211 I915_WRITE(DISP_ARB_CTL,
5976 (I915_READ(DISP_ARB_CTL) | 6212 (I915_READ(DISP_ARB_CTL) |
5977 DISP_FBC_WM_DIS)); 6213 DISP_FBC_WM_DIS));
5978 I915_WRITE(WM3_LP_ILK, 0); 6214 I915_WRITE(WM3_LP_ILK, 0);
5979 I915_WRITE(WM2_LP_ILK, 0); 6215 I915_WRITE(WM2_LP_ILK, 0);
5980 I915_WRITE(WM1_LP_ILK, 0); 6216 I915_WRITE(WM1_LP_ILK, 0);
5981 } 6217 }
5982 /* 6218 /*
5983 * Based on the document from hardware guys the following bits 6219 * Based on the document from hardware guys the following bits
@@ -6010,6 +6246,38 @@ void intel_enable_clock_gating(struct drm_device *dev)
6010 _3D_CHICKEN2_WM_READ_PIPELINED); 6246 _3D_CHICKEN2_WM_READ_PIPELINED);
6011 } 6247 }
6012 6248
6249 if (IS_GEN6(dev)) {
6250 I915_WRITE(WM3_LP_ILK, 0);
6251 I915_WRITE(WM2_LP_ILK, 0);
6252 I915_WRITE(WM1_LP_ILK, 0);
6253
6254 /*
6255 * According to the spec the following bits should be
6256 * set in order to enable memory self-refresh and fbc:
6257 * The bit21 and bit22 of 0x42000
6258 * The bit21 and bit22 of 0x42004
6259 * The bit5 and bit7 of 0x42020
6260 * The bit14 of 0x70180
6261 * The bit14 of 0x71180
6262 */
6263 I915_WRITE(ILK_DISPLAY_CHICKEN1,
6264 I915_READ(ILK_DISPLAY_CHICKEN1) |
6265 ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
6266 I915_WRITE(ILK_DISPLAY_CHICKEN2,
6267 I915_READ(ILK_DISPLAY_CHICKEN2) |
6268 ILK_DPARB_GATE | ILK_VSDPFD_FULL);
6269 I915_WRITE(ILK_DSPCLK_GATE,
6270 I915_READ(ILK_DSPCLK_GATE) |
6271 ILK_DPARB_CLK_GATE |
6272 ILK_DPFD_CLK_GATE);
6273
6274 I915_WRITE(DSPACNTR,
6275 I915_READ(DSPACNTR) |
6276 DISPPLANE_TRICKLE_FEED_DISABLE);
6277 I915_WRITE(DSPBCNTR,
6278 I915_READ(DSPBCNTR) |
6279 DISPPLANE_TRICKLE_FEED_DISABLE);
6280 }
6013 } else if (IS_G4X(dev)) { 6281 } else if (IS_G4X(dev)) {
6014 uint32_t dspclk_gate; 6282 uint32_t dspclk_gate;
6015 I915_WRITE(RENCLK_GATE_D1, 0); 6283 I915_WRITE(RENCLK_GATE_D1, 0);
@@ -6176,6 +6444,14 @@ static void intel_init_display(struct drm_device *dev)
6176 "Disable CxSR\n"); 6444 "Disable CxSR\n");
6177 dev_priv->display.update_wm = NULL; 6445 dev_priv->display.update_wm = NULL;
6178 } 6446 }
6447 } else if (IS_GEN6(dev)) {
6448 if (SNB_READ_WM0_LATENCY()) {
6449 dev_priv->display.update_wm = sandybridge_update_wm;
6450 } else {
6451 DRM_DEBUG_KMS("Failed to read display plane latency. "
6452 "Disable CxSR\n");
6453 dev_priv->display.update_wm = NULL;
6454 }
6179 } else 6455 } else
6180 dev_priv->display.update_wm = NULL; 6456 dev_priv->display.update_wm = NULL;
6181 } else if (IS_PINEVIEW(dev)) { 6457 } else if (IS_PINEVIEW(dev)) {