drm/i915: Make G4X-style PLL search more permissive
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / intel_display.c
index cc8131f..f28691f 100644 (file)
@@ -862,8 +862,8 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        intel_clock_t clock;
        int max_n;
        bool found;
-       /* approximately equals target * 0.00488 */
-       int err_most = (target >> 8) + (target >> 10);
+       /* approximately equals target * 0.00585 */
+       int err_most = (target >> 8) + (target >> 9);
        found = false;
 
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
@@ -2970,11 +2970,13 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                if (srwm < 0)
                        srwm = 1;
                srwm &= 0x3f;
-               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+               if (IS_I965GM(dev))
+                       I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
        } else {
                /* Turn off self refresh if both pipes are enabled */
-               I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-                                       & ~FW_BLC_SELF_EN);
+               if (IS_I965GM(dev))
+                       I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+                                  & ~FW_BLC_SELF_EN);
        }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
@@ -3734,6 +3736,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        if (dev_priv->lvds_dither) {
                                if (HAS_PCH_SPLIT(dev)) {
                                        pipeconf |= PIPE_ENABLE_DITHER;
+                                       pipeconf &= ~PIPE_DITHER_TYPE_MASK;
                                        pipeconf |= PIPE_DITHER_TYPE_ST01;
                                } else
                                        lvds |= LVDS_ENABLE_DITHER;
@@ -4483,6 +4486,7 @@ static void intel_idle_update(struct work_struct *work)
        struct drm_device *dev = dev_priv->dev;
        struct drm_crtc *crtc;
        struct intel_crtc *intel_crtc;
+       int enabled = 0;
 
        if (!i915_powersave)
                return;
@@ -4491,21 +4495,22 @@ static void intel_idle_update(struct work_struct *work)
 
        i915_update_gfx_val(dev_priv);
 
-       if (IS_I945G(dev) || IS_I945GM(dev)) {
-               DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
-               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
-       }
-
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
                if (!crtc->fb)
                        continue;
 
+               enabled++;
                intel_crtc = to_intel_crtc(crtc);
                if (!intel_crtc->busy)
                        intel_decrease_pllclock(crtc);
        }
 
+       if ((enabled == 1) && (IS_I945G(dev) || IS_I945GM(dev))) {
+               DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
+               I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
+       }
+
        mutex_unlock(&dev->struct_mutex);
 }
 
@@ -4601,10 +4606,10 @@ static void intel_unpin_work_fn(struct work_struct *__work)
        kfree(work);
 }
 
-void intel_finish_page_flip(struct drm_device *dev, int pipe)
+static void do_intel_finish_page_flip(struct drm_device *dev,
+                                     struct drm_crtc *crtc)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
        struct drm_i915_gem_object *obj_priv;
@@ -4648,6 +4653,22 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
        schedule_work(&work->work);
 }
 
+void intel_finish_page_flip(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+       do_intel_finish_page_flip(dev, crtc);
+}
+
+void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
+
+       do_intel_finish_page_flip(dev, crtc);
+}
+
 void intel_prepare_page_flip(struct drm_device *dev, int plane)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4675,9 +4696,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        struct drm_gem_object *obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
-       unsigned long flags;
+       unsigned long flags, offset;
        int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
        int ret, pipesrc;
+       u32 flip_mask;
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (work == NULL)
@@ -4731,16 +4753,33 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        atomic_inc(&obj_priv->pending_flip);
        work->pending_flip_obj = obj;
 
+       if (intel_crtc->plane)
+               flip_mask = I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+       else
+               flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
+
+       /* Wait for any previous flip to finish */
+       if (IS_GEN3(dev))
+               while (I915_READ(ISR) & flip_mask)
+                       ;
+
+       /* Offset into the new buffer for cases of shared fbs between CRTCs */
+       offset = obj_priv->gtt_offset;
+       offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8);
+
        BEGIN_LP_RING(4);
-       OUT_RING(MI_DISPLAY_FLIP |
-                MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
-       OUT_RING(fb->pitch);
        if (IS_I965G(dev)) {
-               OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
+               OUT_RING(MI_DISPLAY_FLIP |
+                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+               OUT_RING(fb->pitch);
+               OUT_RING(offset | obj_priv->tiling_mode);
                pipesrc = I915_READ(pipesrc_reg); 
                OUT_RING(pipesrc & 0x0fff0fff);
        } else {
-               OUT_RING(obj_priv->gtt_offset);
+               OUT_RING(MI_DISPLAY_FLIP_I915 |
+                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+               OUT_RING(fb->pitch);
+               OUT_RING(offset);
                OUT_RING(MI_NOOP);
        }
        ADVANCE_LP_RING();