aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorZhenyu Wang <zhenyuw@linux.intel.com>2010-04-01 01:07:53 -0400
committerEric Anholt <eric@anholt.net>2010-04-12 12:30:43 -0400
commit7f8a85698f5c8a981641ec0bdf9926768786db9d (patch)
tree3ae3183d2ac3f9816d501afd80e06fbd34d2c683 /drivers/gpu/drm/i915/intel_display.c
parentd4294342fd4b94a3297867da00c1c5e929c28d4f (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.c160
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
2530static 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
2538static 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
2546static 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
3043static 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)) {