diff options
author | Zhenyu Wang <zhenyuw@linux.intel.com> | 2010-04-01 01:07:53 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-04-12 12:30:43 -0400 |
commit | 7f8a85698f5c8a981641ec0bdf9926768786db9d (patch) | |
tree | 3ae3183d2ac3f9816d501afd80e06fbd34d2c683 /drivers/gpu/drm/i915/intel_display.c | |
parent | d4294342fd4b94a3297867da00c1c5e929c28d4f (diff) |
drm/i915: Add the support of memory self-refresh on Ironlake
Update the self-refresh watermark for display plane/cursor and enable
the memory self-refresh on Ironlake. The watermark is also updated for
the active display plane.
More than 1W idle power is saved on one Ironlake laptop after enabling
memory self-refresh.
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 160 |
1 files changed, 157 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e38c9068a04e..9fdea06f3e73 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -2527,6 +2527,30 @@ static struct intel_watermark_params i830_wm_info = { | |||
2527 | I830_FIFO_LINE_SIZE | 2527 | I830_FIFO_LINE_SIZE |
2528 | }; | 2528 | }; |
2529 | 2529 | ||
2530 | static struct intel_watermark_params ironlake_display_wm_info = { | ||
2531 | ILK_DISPLAY_FIFO, | ||
2532 | ILK_DISPLAY_MAXWM, | ||
2533 | ILK_DISPLAY_DFTWM, | ||
2534 | 2, | ||
2535 | ILK_FIFO_LINE_SIZE | ||
2536 | }; | ||
2537 | |||
2538 | static struct intel_watermark_params ironlake_display_srwm_info = { | ||
2539 | ILK_DISPLAY_SR_FIFO, | ||
2540 | ILK_DISPLAY_MAX_SRWM, | ||
2541 | ILK_DISPLAY_DFT_SRWM, | ||
2542 | 2, | ||
2543 | ILK_FIFO_LINE_SIZE | ||
2544 | }; | ||
2545 | |||
2546 | static struct intel_watermark_params ironlake_cursor_srwm_info = { | ||
2547 | ILK_CURSOR_SR_FIFO, | ||
2548 | ILK_CURSOR_MAX_SRWM, | ||
2549 | ILK_CURSOR_DFT_SRWM, | ||
2550 | 2, | ||
2551 | ILK_FIFO_LINE_SIZE | ||
2552 | }; | ||
2553 | |||
2530 | /** | 2554 | /** |
2531 | * intel_calculate_wm - calculate watermark level | 2555 | * intel_calculate_wm - calculate watermark level |
2532 | * @clock_in_khz: pixel clock | 2556 | * @clock_in_khz: pixel clock |
@@ -3014,6 +3038,108 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, | |||
3014 | I915_WRITE(FW_BLC, fwater_lo); | 3038 | I915_WRITE(FW_BLC, fwater_lo); |
3015 | } | 3039 | } |
3016 | 3040 | ||
3041 | #define ILK_LP0_PLANE_LATENCY 700 | ||
3042 | |||
3043 | static void ironlake_update_wm(struct drm_device *dev, int planea_clock, | ||
3044 | int planeb_clock, int sr_hdisplay, int pixel_size) | ||
3045 | { | ||
3046 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
3047 | int planea_wm, planeb_wm, cursora_wm, cursorb_wm; | ||
3048 | int sr_wm, cursor_wm; | ||
3049 | unsigned long line_time_us; | ||
3050 | int sr_clock, entries_required; | ||
3051 | u32 reg_value; | ||
3052 | |||
3053 | /* Calculate and update the watermark for plane A */ | ||
3054 | if (planea_clock) { | ||
3055 | entries_required = ((planea_clock / 1000) * pixel_size * | ||
3056 | ILK_LP0_PLANE_LATENCY) / 1000; | ||
3057 | entries_required = DIV_ROUND_UP(entries_required, | ||
3058 | ironlake_display_wm_info.cacheline_size); | ||
3059 | planea_wm = entries_required + | ||
3060 | ironlake_display_wm_info.guard_size; | ||
3061 | |||
3062 | if (planea_wm > (int)ironlake_display_wm_info.max_wm) | ||
3063 | planea_wm = ironlake_display_wm_info.max_wm; | ||
3064 | |||
3065 | cursora_wm = 16; | ||
3066 | reg_value = I915_READ(WM0_PIPEA_ILK); | ||
3067 | reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); | ||
3068 | reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) | | ||
3069 | (cursora_wm & WM0_PIPE_CURSOR_MASK); | ||
3070 | I915_WRITE(WM0_PIPEA_ILK, reg_value); | ||
3071 | DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, " | ||
3072 | "cursor: %d\n", planea_wm, cursora_wm); | ||
3073 | } | ||
3074 | /* Calculate and update the watermark for plane B */ | ||
3075 | if (planeb_clock) { | ||
3076 | entries_required = ((planeb_clock / 1000) * pixel_size * | ||
3077 | ILK_LP0_PLANE_LATENCY) / 1000; | ||
3078 | entries_required = DIV_ROUND_UP(entries_required, | ||
3079 | ironlake_display_wm_info.cacheline_size); | ||
3080 | planeb_wm = entries_required + | ||
3081 | ironlake_display_wm_info.guard_size; | ||
3082 | |||
3083 | if (planeb_wm > (int)ironlake_display_wm_info.max_wm) | ||
3084 | planeb_wm = ironlake_display_wm_info.max_wm; | ||
3085 | |||
3086 | cursorb_wm = 16; | ||
3087 | reg_value = I915_READ(WM0_PIPEB_ILK); | ||
3088 | reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); | ||
3089 | reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) | | ||
3090 | (cursorb_wm & WM0_PIPE_CURSOR_MASK); | ||
3091 | I915_WRITE(WM0_PIPEB_ILK, reg_value); | ||
3092 | DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, " | ||
3093 | "cursor: %d\n", planeb_wm, cursorb_wm); | ||
3094 | } | ||
3095 | |||
3096 | /* | ||
3097 | * Calculate and update the self-refresh watermark only when one | ||
3098 | * display plane is used. | ||
3099 | */ | ||
3100 | if (!planea_clock || !planeb_clock) { | ||
3101 | int line_count; | ||
3102 | /* Read the self-refresh latency. The unit is 0.5us */ | ||
3103 | int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK; | ||
3104 | |||
3105 | sr_clock = planea_clock ? planea_clock : planeb_clock; | ||
3106 | line_time_us = ((sr_hdisplay * 1000) / sr_clock); | ||
3107 | |||
3108 | /* Use ns/us then divide to preserve precision */ | ||
3109 | line_count = ((ilk_sr_latency * 500) / line_time_us + 1000) | ||
3110 | / 1000; | ||
3111 | |||
3112 | /* calculate the self-refresh watermark for display plane */ | ||
3113 | entries_required = line_count * sr_hdisplay * pixel_size; | ||
3114 | entries_required = DIV_ROUND_UP(entries_required, | ||
3115 | ironlake_display_srwm_info.cacheline_size); | ||
3116 | sr_wm = entries_required + | ||
3117 | ironlake_display_srwm_info.guard_size; | ||
3118 | |||
3119 | /* calculate the self-refresh watermark for display cursor */ | ||
3120 | entries_required = line_count * pixel_size * 64; | ||
3121 | entries_required = DIV_ROUND_UP(entries_required, | ||
3122 | ironlake_cursor_srwm_info.cacheline_size); | ||
3123 | cursor_wm = entries_required + | ||
3124 | ironlake_cursor_srwm_info.guard_size; | ||
3125 | |||
3126 | /* configure watermark and enable self-refresh */ | ||
3127 | reg_value = I915_READ(WM1_LP_ILK); | ||
3128 | reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK | | ||
3129 | WM1_LP_CURSOR_MASK); | ||
3130 | reg_value |= WM1_LP_SR_EN | | ||
3131 | (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | | ||
3132 | (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm; | ||
3133 | |||
3134 | I915_WRITE(WM1_LP_ILK, reg_value); | ||
3135 | DRM_DEBUG_KMS("self-refresh watermark: display plane %d " | ||
3136 | "cursor %d\n", sr_wm, cursor_wm); | ||
3137 | |||
3138 | } else { | ||
3139 | /* Turn off self refresh if both pipes are enabled */ | ||
3140 | I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN); | ||
3141 | } | ||
3142 | } | ||
3017 | /** | 3143 | /** |
3018 | * intel_update_watermarks - update FIFO watermark values based on current modes | 3144 | * intel_update_watermarks - update FIFO watermark values based on current modes |
3019 | * | 3145 | * |
@@ -4973,6 +5099,25 @@ void intel_init_clock_gating(struct drm_device *dev) | |||
4973 | } | 5099 | } |
4974 | 5100 | ||
4975 | I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); | 5101 | I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); |
5102 | |||
5103 | /* | ||
5104 | * According to the spec the following bits should be set in | ||
5105 | * order to enable memory self-refresh | ||
5106 | * The bit 22/21 of 0x42004 | ||
5107 | * The bit 5 of 0x42020 | ||
5108 | * The bit 15 of 0x45000 | ||
5109 | */ | ||
5110 | if (IS_IRONLAKE(dev)) { | ||
5111 | I915_WRITE(ILK_DISPLAY_CHICKEN2, | ||
5112 | (I915_READ(ILK_DISPLAY_CHICKEN2) | | ||
5113 | ILK_DPARB_GATE | ILK_VSDPFD_FULL)); | ||
5114 | I915_WRITE(ILK_DSPCLK_GATE, | ||
5115 | (I915_READ(ILK_DSPCLK_GATE) | | ||
5116 | ILK_DPARB_CLK_GATE)); | ||
5117 | I915_WRITE(DISP_ARB_CTL, | ||
5118 | (I915_READ(DISP_ARB_CTL) | | ||
5119 | DISP_FBC_WM_DIS)); | ||
5120 | } | ||
4976 | return; | 5121 | return; |
4977 | } else if (IS_G4X(dev)) { | 5122 | } else if (IS_G4X(dev)) { |
4978 | uint32_t dspclk_gate; | 5123 | uint32_t dspclk_gate; |
@@ -5088,9 +5233,18 @@ static void intel_init_display(struct drm_device *dev) | |||
5088 | i830_get_display_clock_speed; | 5233 | i830_get_display_clock_speed; |
5089 | 5234 | ||
5090 | /* For FIFO watermark updates */ | 5235 | /* For FIFO watermark updates */ |
5091 | if (HAS_PCH_SPLIT(dev)) | 5236 | if (HAS_PCH_SPLIT(dev)) { |
5092 | dev_priv->display.update_wm = NULL; | 5237 | if (IS_IRONLAKE(dev)) { |
5093 | else if (IS_PINEVIEW(dev)) { | 5238 | if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) |
5239 | dev_priv->display.update_wm = ironlake_update_wm; | ||
5240 | else { | ||
5241 | DRM_DEBUG_KMS("Failed to get proper latency. " | ||
5242 | "Disable CxSR\n"); | ||
5243 | dev_priv->display.update_wm = NULL; | ||
5244 | } | ||
5245 | } else | ||
5246 | dev_priv->display.update_wm = NULL; | ||
5247 | } else if (IS_PINEVIEW(dev)) { | ||
5094 | if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), | 5248 | if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), |
5095 | dev_priv->fsb_freq, | 5249 | dev_priv->fsb_freq, |
5096 | dev_priv->mem_freq)) { | 5250 | dev_priv->mem_freq)) { |