]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm/i915: lock correct mutex around object unreference.
[linux-2.6-omap-h63xx.git] / drivers / gpu / drm / i915 / intel_display.c
index 6e8b9ab83e9737ce8f3894c365590d76b3e5dd3c..31c3732b7a690aa7d813f4ecad46a071a7ef684f 100644 (file)
@@ -344,7 +344,8 @@ intel_wait_for_vblank(struct drm_device *dev)
 }
 
 static void
-intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
+intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+                   struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -359,7 +360,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
        int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
        int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
        int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
-       u32 dspcntr;
+       u32 dspcntr, alignment;
 
        /* no fb bound */
        if (!crtc->fb) {
@@ -368,16 +369,40 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
        }
 
        intel_fb = to_intel_framebuffer(crtc->fb);
-
        obj = intel_fb->obj;
        obj_priv = obj->driver_private;
 
+       switch (obj_priv->tiling_mode) {
+       case I915_TILING_NONE:
+               alignment = 64 * 1024;
+               break;
+       case I915_TILING_X:
+               if (IS_I9XX(dev))
+                       alignment = 1024 * 1024;
+               else
+                       alignment = 512 * 1024;
+               break;
+       case I915_TILING_Y:
+               /* FIXME: Is this true? */
+               DRM_ERROR("Y tiled not allowed for scan out buffers\n");
+               return;
+       default:
+               BUG();
+       }
+
+       if (i915_gem_object_pin(intel_fb->obj, alignment))
+               return;
+
+       i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
+
        Start = obj_priv->gtt_offset;
        Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
 
        I915_WRITE(dspstride, crtc->fb->pitch);
 
        dspcntr = I915_READ(dspcntr_reg);
+       /* Mask out pixel format bits in case we change it */
+       dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (crtc->fb->bits_per_pixel) {
        case 8:
                dspcntr |= DISPPLANE_8BPP;
@@ -409,6 +434,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
                I915_READ(dspbase);
        }
 
+       intel_wait_for_vblank(dev);
+
+       if (old_fb) {
+               intel_fb = to_intel_framebuffer(old_fb);
+               i915_gem_object_unpin(intel_fb->obj);
+       }
 
        if (!dev->primary->master)
                return;
@@ -680,7 +711,8 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
 static void intel_crtc_mode_set(struct drm_crtc *crtc,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode,
-                               int x, int y)
+                               int x, int y,
+                               struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -721,6 +753,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
                        is_lvds = true;
                        break;
                case INTEL_OUTPUT_SDVO:
+               case INTEL_OUTPUT_HDMI:
                        is_sdvo = true;
                        break;
                case INTEL_OUTPUT_DVO:
@@ -915,9 +948,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        I915_WRITE(dspcntr_reg, dspcntr);
 
        /* Flush the plane changes */
-       intel_pipe_set_base(crtc, x, y);
-
-       intel_wait_for_vblank(dev);
+       intel_pipe_set_base(crtc, x, y, old_fb);
 
        drm_vblank_post_modeset(dev, pipe);
 }
@@ -958,19 +989,17 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
        uint32_t temp;
        size_t addr;
+       int ret;
 
        DRM_DEBUG("\n");
 
        /* if we want to turn off the cursor ignore width and height */
        if (!handle) {
                DRM_DEBUG("cursor off\n");
-               /* turn of the cursor */
-               temp = 0;
-               temp |= CURSOR_MODE_DISABLE;
-
-               I915_WRITE(control, temp);
-               I915_WRITE(base, 0);
-               return 0;
+               temp = CURSOR_MODE_DISABLE;
+               addr = 0;
+               bo = NULL;
+               goto finish;
        }
 
        /* Currently we only support 64x64 cursors */
@@ -987,26 +1016,56 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 
        if (bo->size < width * height * 4) {
                DRM_ERROR("buffer is to small\n");
-               drm_gem_object_unreference(bo);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto fail;
        }
 
-       if (dev_priv->cursor_needs_physical) {
-               addr = dev->agp->base + obj_priv->gtt_offset;
-       } else {
+       /* we only need to pin inside GTT if cursor is non-phy */
+       if (!dev_priv->cursor_needs_physical) {
+               ret = i915_gem_object_pin(bo, PAGE_SIZE);
+               if (ret) {
+                       DRM_ERROR("failed to pin cursor bo\n");
+                       goto fail;
+               }
                addr = obj_priv->gtt_offset;
+       } else {
+               ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
+               if (ret) {
+                       DRM_ERROR("failed to attach phys object\n");
+                       goto fail;
+               }
+               addr = obj_priv->phys_obj->handle->busaddr;
        }
 
-       intel_crtc->cursor_addr = addr;
        temp = 0;
        /* set the pipe for the cursor */
        temp |= (pipe << 28);
        temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
 
+ finish:
        I915_WRITE(control, temp);
        I915_WRITE(base, addr);
 
+       if (intel_crtc->cursor_bo) {
+               if (dev_priv->cursor_needs_physical) {
+                       if (intel_crtc->cursor_bo != bo)
+                               i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
+               } else
+                       i915_gem_object_unpin(intel_crtc->cursor_bo);
+               mutex_lock(&dev->struct_mutex);
+               drm_gem_object_unreference(intel_crtc->cursor_bo);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       intel_crtc->cursor_addr = addr;
+       intel_crtc->cursor_bo = bo;
+
        return 0;
+fail:
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(bo);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
 }
 
 static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
@@ -1153,7 +1212,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
        if (!crtc->enabled) {
                if (!mode)
                        mode = &load_detect_mode;
-               drm_crtc_helper_set_mode(crtc, mode, 0, 0);
+               drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
        } else {
                if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
                        crtc_funcs = crtc->helper_private;
@@ -1402,12 +1461,19 @@ static void intel_setup_outputs(struct drm_device *dev)
                intel_lvds_init(dev);
 
        if (IS_I9XX(dev)) {
-               intel_sdvo_init(dev, SDVOB);
-               intel_sdvo_init(dev, SDVOC);
+               int found;
+
+               found = intel_sdvo_init(dev, SDVOB);
+               if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
+                       intel_hdmi_init(dev, SDVOB);
+
+               found = intel_sdvo_init(dev, SDVOC);
+               if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
+                       intel_hdmi_init(dev, SDVOC);
        } else
                intel_dvo_init(dev);
 
-       if (IS_I9XX(dev) && !IS_I915G(dev))
+       if (IS_I9XX(dev) && IS_MOBILE(dev))
                intel_tv_init(dev);
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -1417,6 +1483,11 @@ static void intel_setup_outputs(struct drm_device *dev)
 
                /* valid crtcs */
                switch(intel_output->type) {
+               case INTEL_OUTPUT_HDMI:
+                       crtc_mask = ((1 << 0)|
+                                    (1 << 1));
+                       clone_mask = ((1 << INTEL_OUTPUT_HDMI));
+                       break;
                case INTEL_OUTPUT_DVO:
                case INTEL_OUTPUT_SDVO:
                        crtc_mask = ((1 << 0)|