|
@@ -2527,6 +2527,30 @@ static struct intel_watermark_params i830_wm_info = {
|
|
I830_FIFO_LINE_SIZE
|
|
I830_FIFO_LINE_SIZE
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static struct intel_watermark_params ironlake_display_wm_info = {
|
|
|
|
+ ILK_DISPLAY_FIFO,
|
|
|
|
+ ILK_DISPLAY_MAXWM,
|
|
|
|
+ ILK_DISPLAY_DFTWM,
|
|
|
|
+ 2,
|
|
|
|
+ ILK_FIFO_LINE_SIZE
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct intel_watermark_params ironlake_display_srwm_info = {
|
|
|
|
+ ILK_DISPLAY_SR_FIFO,
|
|
|
|
+ ILK_DISPLAY_MAX_SRWM,
|
|
|
|
+ ILK_DISPLAY_DFT_SRWM,
|
|
|
|
+ 2,
|
|
|
|
+ ILK_FIFO_LINE_SIZE
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct intel_watermark_params ironlake_cursor_srwm_info = {
|
|
|
|
+ ILK_CURSOR_SR_FIFO,
|
|
|
|
+ ILK_CURSOR_MAX_SRWM,
|
|
|
|
+ ILK_CURSOR_DFT_SRWM,
|
|
|
|
+ 2,
|
|
|
|
+ ILK_FIFO_LINE_SIZE
|
|
|
|
+};
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* intel_calculate_wm - calculate watermark level
|
|
* intel_calculate_wm - calculate watermark level
|
|
* @clock_in_khz: pixel clock
|
|
* @clock_in_khz: pixel clock
|
|
@@ -3014,6 +3038,108 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
|
|
I915_WRITE(FW_BLC, fwater_lo);
|
|
I915_WRITE(FW_BLC, fwater_lo);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define ILK_LP0_PLANE_LATENCY 700
|
|
|
|
+
|
|
|
|
+static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
|
|
|
|
+ int planeb_clock, int sr_hdisplay, int pixel_size)
|
|
|
|
+{
|
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
+ int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
|
|
|
|
+ int sr_wm, cursor_wm;
|
|
|
|
+ unsigned long line_time_us;
|
|
|
|
+ int sr_clock, entries_required;
|
|
|
|
+ u32 reg_value;
|
|
|
|
+
|
|
|
|
+ /* Calculate and update the watermark for plane A */
|
|
|
|
+ if (planea_clock) {
|
|
|
|
+ entries_required = ((planea_clock / 1000) * pixel_size *
|
|
|
|
+ ILK_LP0_PLANE_LATENCY) / 1000;
|
|
|
|
+ entries_required = DIV_ROUND_UP(entries_required,
|
|
|
|
+ ironlake_display_wm_info.cacheline_size);
|
|
|
|
+ planea_wm = entries_required +
|
|
|
|
+ ironlake_display_wm_info.guard_size;
|
|
|
|
+
|
|
|
|
+ if (planea_wm > (int)ironlake_display_wm_info.max_wm)
|
|
|
|
+ planea_wm = ironlake_display_wm_info.max_wm;
|
|
|
|
+
|
|
|
|
+ cursora_wm = 16;
|
|
|
|
+ reg_value = I915_READ(WM0_PIPEA_ILK);
|
|
|
|
+ reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
|
|
|
|
+ reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
|
|
|
|
+ (cursora_wm & WM0_PIPE_CURSOR_MASK);
|
|
|
|
+ I915_WRITE(WM0_PIPEA_ILK, reg_value);
|
|
|
|
+ DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
|
|
|
|
+ "cursor: %d\n", planea_wm, cursora_wm);
|
|
|
|
+ }
|
|
|
|
+ /* Calculate and update the watermark for plane B */
|
|
|
|
+ if (planeb_clock) {
|
|
|
|
+ entries_required = ((planeb_clock / 1000) * pixel_size *
|
|
|
|
+ ILK_LP0_PLANE_LATENCY) / 1000;
|
|
|
|
+ entries_required = DIV_ROUND_UP(entries_required,
|
|
|
|
+ ironlake_display_wm_info.cacheline_size);
|
|
|
|
+ planeb_wm = entries_required +
|
|
|
|
+ ironlake_display_wm_info.guard_size;
|
|
|
|
+
|
|
|
|
+ if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
|
|
|
|
+ planeb_wm = ironlake_display_wm_info.max_wm;
|
|
|
|
+
|
|
|
|
+ cursorb_wm = 16;
|
|
|
|
+ reg_value = I915_READ(WM0_PIPEB_ILK);
|
|
|
|
+ reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
|
|
|
|
+ reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
|
|
|
|
+ (cursorb_wm & WM0_PIPE_CURSOR_MASK);
|
|
|
|
+ I915_WRITE(WM0_PIPEB_ILK, reg_value);
|
|
|
|
+ DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
|
|
|
|
+ "cursor: %d\n", planeb_wm, cursorb_wm);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Calculate and update the self-refresh watermark only when one
|
|
|
|
+ * display plane is used.
|
|
|
|
+ */
|
|
|
|
+ if (!planea_clock || !planeb_clock) {
|
|
|
|
+ int line_count;
|
|
|
|
+ /* Read the self-refresh latency. The unit is 0.5us */
|
|
|
|
+ int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
|
|
|
|
+
|
|
|
|
+ sr_clock = planea_clock ? planea_clock : planeb_clock;
|
|
|
|
+ line_time_us = ((sr_hdisplay * 1000) / sr_clock);
|
|
|
|
+
|
|
|
|
+ /* Use ns/us then divide to preserve precision */
|
|
|
|
+ line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
|
|
|
|
+ / 1000;
|
|
|
|
+
|
|
|
|
+ /* calculate the self-refresh watermark for display plane */
|
|
|
|
+ entries_required = line_count * sr_hdisplay * pixel_size;
|
|
|
|
+ entries_required = DIV_ROUND_UP(entries_required,
|
|
|
|
+ ironlake_display_srwm_info.cacheline_size);
|
|
|
|
+ sr_wm = entries_required +
|
|
|
|
+ ironlake_display_srwm_info.guard_size;
|
|
|
|
+
|
|
|
|
+ /* calculate the self-refresh watermark for display cursor */
|
|
|
|
+ entries_required = line_count * pixel_size * 64;
|
|
|
|
+ entries_required = DIV_ROUND_UP(entries_required,
|
|
|
|
+ ironlake_cursor_srwm_info.cacheline_size);
|
|
|
|
+ cursor_wm = entries_required +
|
|
|
|
+ ironlake_cursor_srwm_info.guard_size;
|
|
|
|
+
|
|
|
|
+ /* configure watermark and enable self-refresh */
|
|
|
|
+ reg_value = I915_READ(WM1_LP_ILK);
|
|
|
|
+ reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
|
|
|
|
+ WM1_LP_CURSOR_MASK);
|
|
|
|
+ reg_value |= WM1_LP_SR_EN |
|
|
|
|
+ (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
|
|
|
|
+ (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
|
|
|
|
+
|
|
|
|
+ I915_WRITE(WM1_LP_ILK, reg_value);
|
|
|
|
+ DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
|
|
|
|
+ "cursor %d\n", sr_wm, cursor_wm);
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+ /* Turn off self refresh if both pipes are enabled */
|
|
|
|
+ I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
|
|
|
|
+ }
|
|
|
|
+}
|
|
/**
|
|
/**
|
|
* intel_update_watermarks - update FIFO watermark values based on current modes
|
|
* intel_update_watermarks - update FIFO watermark values based on current modes
|
|
*
|
|
*
|
|
@@ -4973,6 +5099,25 @@ void intel_init_clock_gating(struct drm_device *dev)
|
|
}
|
|
}
|
|
|
|
|
|
I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
|
|
I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * According to the spec the following bits should be set in
|
|
|
|
+ * order to enable memory self-refresh
|
|
|
|
+ * The bit 22/21 of 0x42004
|
|
|
|
+ * The bit 5 of 0x42020
|
|
|
|
+ * The bit 15 of 0x45000
|
|
|
|
+ */
|
|
|
|
+ if (IS_IRONLAKE(dev)) {
|
|
|
|
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
|
|
|
|
+ (I915_READ(ILK_DISPLAY_CHICKEN2) |
|
|
|
|
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL));
|
|
|
|
+ I915_WRITE(ILK_DSPCLK_GATE,
|
|
|
|
+ (I915_READ(ILK_DSPCLK_GATE) |
|
|
|
|
+ ILK_DPARB_CLK_GATE));
|
|
|
|
+ I915_WRITE(DISP_ARB_CTL,
|
|
|
|
+ (I915_READ(DISP_ARB_CTL) |
|
|
|
|
+ DISP_FBC_WM_DIS));
|
|
|
|
+ }
|
|
return;
|
|
return;
|
|
} else if (IS_G4X(dev)) {
|
|
} else if (IS_G4X(dev)) {
|
|
uint32_t dspclk_gate;
|
|
uint32_t dspclk_gate;
|
|
@@ -5088,9 +5233,18 @@ static void intel_init_display(struct drm_device *dev)
|
|
i830_get_display_clock_speed;
|
|
i830_get_display_clock_speed;
|
|
|
|
|
|
/* For FIFO watermark updates */
|
|
/* For FIFO watermark updates */
|
|
- if (HAS_PCH_SPLIT(dev))
|
|
|
|
- dev_priv->display.update_wm = NULL;
|
|
|
|
- else if (IS_PINEVIEW(dev)) {
|
|
|
|
|
|
+ if (HAS_PCH_SPLIT(dev)) {
|
|
|
|
+ if (IS_IRONLAKE(dev)) {
|
|
|
|
+ if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
|
|
|
|
+ dev_priv->display.update_wm = ironlake_update_wm;
|
|
|
|
+ else {
|
|
|
|
+ DRM_DEBUG_KMS("Failed to get proper latency. "
|
|
|
|
+ "Disable CxSR\n");
|
|
|
|
+ dev_priv->display.update_wm = NULL;
|
|
|
|
+ }
|
|
|
|
+ } else
|
|
|
|
+ dev_priv->display.update_wm = NULL;
|
|
|
|
+ } else if (IS_PINEVIEW(dev)) {
|
|
if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
|
|
if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
|
|
dev_priv->fsb_freq,
|
|
dev_priv->fsb_freq,
|
|
dev_priv->mem_freq)) {
|
|
dev_priv->mem_freq)) {
|