]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm: handle depth & bpp changes correctly
[linux-2.6-omap-h63xx.git] / drivers / gpu / drm / i915 / intel_display.c
index 96c2da5b74e35a797fbc7ff6617b5466eeab28b4..4372acff5a016327d336e452e76be2f41bd27a97 100644 (file)
@@ -213,9 +213,9 @@ static void intel_clock(struct drm_device *dev, int refclk,
                        intel_clock_t *clock)
 {
        if (IS_I9XX(dev))
-               return i9xx_clock (refclk, clock);
+               i9xx_clock (refclk, clock);
        else
-               return i8xx_clock (refclk, clock);
+               i8xx_clock (refclk, clock);
 }
 
 /**
@@ -343,8 +343,9 @@ intel_wait_for_vblank(struct drm_device *dev)
        udelay(20000);
 }
 
-void
-intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
+static void
+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 */
@@ -997,15 +1026,30 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                addr = obj_priv->gtt_offset;
        }
 
-       intel_crtc->cursor_addr = addr;
+       ret = i915_gem_object_pin(bo, PAGE_SIZE);
+       if (ret) {
+               DRM_ERROR("failed to pin cursor bo\n");
+               drm_gem_object_unreference(bo);
+               return ret;
+       }
+
        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) {
+               i915_gem_object_unpin(intel_crtc->cursor_bo);
+               drm_gem_object_unreference(intel_crtc->cursor_bo);
+       }
+
+       intel_crtc->cursor_addr = addr;
+       intel_crtc->cursor_bo = bo;
+
        return 0;
 }
 
@@ -1153,7 +1197,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;
@@ -1329,7 +1373,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
 };
 
 
-void intel_crtc_init(struct drm_device *dev, int pipe)
+static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
        struct intel_crtc *intel_crtc;
        int i;
@@ -1375,7 +1419,7 @@ struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
        return crtc;
 }
 
-int intel_connector_clones(struct drm_device *dev, int type_mask)
+static int intel_connector_clones(struct drm_device *dev, int type_mask)
 {
        int index_mask = 0;
        struct drm_connector *connector;
@@ -1402,12 +1446,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 +1468,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)|
@@ -1528,38 +1584,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
        return fb;
 }
 
-static int intel_insert_new_fb(struct drm_device *dev,
-                              struct drm_file *file_priv,
-                              struct drm_framebuffer *fb,
-                              struct drm_mode_fb_cmd *mode_cmd)
-{
-       struct intel_framebuffer *intel_fb;
-       struct drm_gem_object *obj;
-       struct drm_crtc *crtc;
-
-       intel_fb = to_intel_framebuffer(fb);
-
-       obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
-
-       if (!obj)
-               return -EINVAL;
-
-       intel_fb->obj = obj;
-       drm_gem_object_unreference(intel_fb->obj);
-       drm_helper_mode_fill_fb_struct(fb, mode_cmd);
-       mutex_unlock(&dev->struct_mutex);
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (crtc->fb == fb) {
-                       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-                       crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y);
-               }
-       }
-       return 0;
-}
-
 static const struct drm_mode_config_funcs intel_mode_funcs = {
-       .resize_fb = intel_insert_new_fb,
        .fb_create = intel_user_framebuffer_create,
        .fb_changed = intelfb_probe,
 };