drm/i915: Reduce differences with Linux 3.8
authorFrançois Tigeot <ftigeot@wolfpond.org>
Sat, 22 Feb 2014 12:19:56 +0000 (13:19 +0100)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Sat, 22 Feb 2014 12:22:05 +0000 (13:22 +0100)
sys/dev/drm/i915/i915_drv.h
sys/dev/drm/i915/intel_display.c
sys/dev/drm/i915/intel_drv.h
sys/dev/drm/i915/intel_modes.c
sys/dev/drm/i915/intel_sprite.c

index 030fe92..9aa5de9 100644 (file)
@@ -58,6 +58,14 @@ enum i915_pipe {
 #define pipe_name(p) ((p) + 'A')
 #define I915_NUM_PIPE  2
 
+enum transcoder {
+       TRANSCODER_A = 0,
+       TRANSCODER_B,
+       TRANSCODER_C,
+       TRANSCODER_EDP = 0xF,
+};
+#define transcoder_name(t) ((t) + 'A')
+
 enum plane {
        PLANE_A = 0,
        PLANE_B,
@@ -65,6 +73,16 @@ enum plane {
 };
 #define plane_name(p) ((p) + 'A')
 
+enum port {
+       PORT_A = 0,
+       PORT_B,
+       PORT_C,
+       PORT_D,
+       PORT_E,
+       I915_MAX_PORTS
+};
+#define port_name(p) ((p) + 'A')
+
 #define        I915_GEM_GPU_DOMAINS    (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
 
 #define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
@@ -104,12 +122,8 @@ struct intel_ddi_plls {
 #define DRIVER_PATCHLEVEL      0
 
 #define WATCH_COHERENCY        0
-#define WATCH_BUF      0
-#define WATCH_EXEC     0
-#define WATCH_LRU      0
-#define WATCH_RELOC    0
-#define WATCH_INACTIVE 0
-#define WATCH_PWRITE   0
+#define WATCH_LISTS    0
+#define WATCH_GTT      0
 
 #define I915_GEM_PHYS_CURSOR_0 1
 #define I915_GEM_PHYS_CURSOR_1 2
@@ -122,8 +136,108 @@ struct drm_i915_gem_phys_object {
        struct drm_i915_gem_object *cur_obj;
 };
 
+struct opregion_header;
+struct opregion_acpi;
+struct opregion_swsci;
+struct opregion_asle;
 struct drm_i915_private;
 
+struct intel_opregion {
+       struct opregion_header __iomem *header;
+       struct opregion_acpi __iomem *acpi;
+       struct opregion_swsci __iomem *swsci;
+       struct opregion_asle __iomem *asle;
+       void __iomem *vbt;
+       u32 __iomem *lid_state;
+};
+#define OPREGION_SIZE            (8*1024)
+
+struct intel_overlay;
+struct intel_overlay_error_state;
+
+struct drm_i915_master_private {
+       drm_local_map_t *sarea;
+       struct _drm_i915_sarea *sarea_priv;
+};
+#define I915_FENCE_REG_NONE -1
+#define I915_MAX_NUM_FENCES 16
+/* 16 fences + sign bit for FENCE_REG_NONE */
+#define I915_MAX_NUM_FENCE_BITS 5
+
+struct drm_i915_fence_reg {
+       struct list_head lru_list;
+       struct drm_i915_gem_object *obj;
+       uint32_t setup_seqno;
+       int pin_count;
+};
+
+struct sdvo_device_mapping {
+       u8 initialized;
+       u8 dvo_port;
+       u8 slave_addr;
+       u8 dvo_wiring;
+       u8 i2c_pin;
+       u8 ddc_pin;
+};
+
+struct drm_i915_error_state {
+       u32 eir;
+       u32 pgtbl_er;
+       u32 pipestat[I915_MAX_PIPES];
+       u32 tail[I915_NUM_RINGS];
+       u32 head[I915_NUM_RINGS];
+       u32 ipeir[I915_NUM_RINGS];
+       u32 ipehr[I915_NUM_RINGS];
+       u32 instdone[I915_NUM_RINGS];
+       u32 acthd[I915_NUM_RINGS];
+       u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
+       /* our own tracking of ring head and tail */
+       u32 cpu_ring_head[I915_NUM_RINGS];
+       u32 cpu_ring_tail[I915_NUM_RINGS];
+       u32 error; /* gen6+ */
+       u32 instpm[I915_NUM_RINGS];
+       u32 instps[I915_NUM_RINGS];
+       u32 instdone1;
+       u32 seqno[I915_NUM_RINGS];
+       u64 bbaddr;
+       u32 fault_reg[I915_NUM_RINGS];
+       u32 done_reg;
+       u32 faddr[I915_NUM_RINGS];
+       u64 fence[I915_MAX_NUM_FENCES];
+       struct timeval time;
+       struct drm_i915_error_ring {
+               struct drm_i915_error_object {
+                       int page_count;
+                       u32 gtt_offset;
+                       u32 *pages[0];
+               } *ringbuffer, *batchbuffer;
+               struct drm_i915_error_request {
+                       long jiffies;
+                       u32 seqno;
+                       u32 tail;
+               } *requests;
+               int num_requests;
+       } ring[I915_NUM_RINGS];
+       struct drm_i915_error_buffer {
+               u32 size;
+               u32 name;
+               u32 seqno;
+               u32 gtt_offset;
+               u32 read_domains;
+               u32 write_domain;
+               s32 fence_reg:I915_MAX_NUM_FENCE_BITS;
+               s32 pinned:2;
+               u32 tiling:2;
+               u32 dirty:1;
+               u32 purgeable:1;
+               s32 ring:4;
+               u32 cache_level:2;
+       } *active_bo, *pinned_bo;
+       u32 active_bo_count, pinned_bo_count;
+       struct intel_overlay_error_state *overlay;
+       struct intel_display_error_state *display;
+};
+
 struct drm_i915_display_funcs {
        void (*dpms)(struct drm_crtc *crtc, int mode);
        bool (*fbc_enabled)(struct drm_device *dev);
@@ -158,6 +272,37 @@ struct drm_i915_display_funcs {
        /* pll clock increase/decrease */
 };
 
+struct drm_i915_gt_funcs {
+       void (*force_wake_get)(struct drm_i915_private *dev_priv);
+       void (*force_wake_put)(struct drm_i915_private *dev_priv);
+};
+
+#define DEV_INFO_FLAGS \
+       DEV_INFO_FLAG(is_mobile) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_i85x) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_i915g) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_i945gm) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_g33) DEV_INFO_SEP \
+       DEV_INFO_FLAG(need_gfx_hws) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_g4x) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_pineview) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_broadwater) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_crestline) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_ivybridge) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_valleyview) DEV_INFO_SEP \
+       DEV_INFO_FLAG(is_haswell) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_force_wake) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_fbc) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_pipe_cxsr) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_hotplug) DEV_INFO_SEP \
+       DEV_INFO_FLAG(cursor_needs_physical) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_overlay) DEV_INFO_SEP \
+       DEV_INFO_FLAG(overlay_needs_physical) DEV_INFO_SEP \
+       DEV_INFO_FLAG(supports_tv) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_bsd_ring) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_blt_ring) DEV_INFO_SEP \
+       DEV_INFO_FLAG(has_llc)
+
 struct intel_device_info {
        u8 gen;
        u8 is_mobile:1;
@@ -223,37 +368,11 @@ struct opregion_acpi;
 struct opregion_swsci;
 struct opregion_asle;
 
-struct intel_opregion {
-       struct opregion_header *header;
-       struct opregion_acpi *acpi;
-       struct opregion_swsci *swsci;
-       struct opregion_asle *asle;
-       void *vbt;
-       u32 *lid_state;
-};
-#define OPREGION_SIZE            (8*1024)
-
 #define I915_FENCE_REG_NONE -1
 #define I915_MAX_NUM_FENCES 16
 /* 16 fences + sign bit for FENCE_REG_NONE */
 #define I915_MAX_NUM_FENCE_BITS 5
 
-struct drm_i915_fence_reg {
-       struct list_head lru_list;
-       struct drm_i915_gem_object *obj;
-       uint32_t setup_seqno;
-       int pin_count;
-};
-
-struct sdvo_device_mapping {
-       u8 initialized;
-       u8 dvo_port;
-       u8 slave_addr;
-       u8 dvo_wiring;
-       u8 i2c_pin;
-       u8 ddc_pin;
-};
-
 enum intel_pch {
        PCH_IBX,        /* Ibexpeak PCH */
        PCH_CPT,        /* Cougarpoint PCH */
@@ -964,64 +1083,6 @@ struct drm_i915_file_private {
        } mm;
 };
 
-struct drm_i915_error_state {
-       u32 eir;
-       u32 pgtbl_er;
-       u32 pipestat[I915_MAX_PIPES];
-       u32 tail[I915_NUM_RINGS];
-       u32 head[I915_NUM_RINGS];
-       u32 ipeir[I915_NUM_RINGS];
-       u32 ipehr[I915_NUM_RINGS];
-       u32 instdone[I915_NUM_RINGS];
-       u32 acthd[I915_NUM_RINGS];
-       u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
-       /* our own tracking of ring head and tail */
-       u32 cpu_ring_head[I915_NUM_RINGS];
-       u32 cpu_ring_tail[I915_NUM_RINGS];
-       u32 error; /* gen6+ */
-       u32 instpm[I915_NUM_RINGS];
-       u32 instps[I915_NUM_RINGS];
-       u32 instdone1;
-       u32 seqno[I915_NUM_RINGS];
-       u64 bbaddr;
-       u32 fault_reg[I915_NUM_RINGS];
-       u32 done_reg;
-       u32 faddr[I915_NUM_RINGS];
-       u64 fence[I915_MAX_NUM_FENCES];
-       struct timeval time;
-       struct drm_i915_error_ring {
-               struct drm_i915_error_object {
-                       int page_count;
-                       u32 gtt_offset;
-                       u32 *pages[0];
-               } *ringbuffer, *batchbuffer;
-               struct drm_i915_error_request {
-                       long jiffies;
-                       u32 seqno;
-                       u32 tail;
-               } *requests;
-               int num_requests;
-       } ring[I915_NUM_RINGS];
-       struct drm_i915_error_buffer {
-               u32 size;
-               u32 name;
-               u32 seqno;
-               u32 gtt_offset;
-               u32 read_domains;
-               u32 write_domain;
-               s32 fence_reg:I915_MAX_NUM_FENCE_BITS;
-               s32 pinned:2;
-               u32 tiling:2;
-               u32 dirty:1;
-               u32 purgeable:1;
-               s32 ring:4;
-               u32 cache_level:2;
-       } *active_bo, *pinned_bo;
-       u32 active_bo_count, pinned_bo_count;
-       struct intel_overlay_error_state *overlay;
-       struct intel_display_error_state *display;
-};
-
 /**
  * RC6 is a special power stage which allows the GPU to enter an very
  * low-voltage mode when idle, using down to 0V while at this stage.  This
index bd05e4c..f0ad061 100644 (file)
@@ -1599,6 +1599,22 @@ void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
        i915_gem_object_unpin(obj);
 }
 
+/* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
+ * is assumed to be a power-of-two. */
+unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y,
+                                              unsigned int bpp,
+                                              unsigned int pitch)
+{
+       int tile_rows, tiles;
+
+       tile_rows = *y / 8;
+       *y %= 8;
+       tiles = *x / (512/bpp);
+       *x %= 512/bpp;
+
+       return tile_rows * pitch * 8 + tiles * 4096;
+}
+
 static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                             int x, int y)
 {
index 456aed6..a333294 100644 (file)
@@ -179,6 +179,7 @@ struct intel_crtc {
        u8 lut_r[256], lut_g[256], lut_b[256];
        int dpms_mode;
        bool active; /* is the crtc on? independent of the dpms mode */
+       bool primary_disabled; /* is the crtc obscured by a plane? */
        bool busy; /* is scanout buffer being updated frequently? */
        struct callout idle_callout;
        bool lowfreq_avail;
@@ -201,7 +202,7 @@ struct intel_plane {
        struct drm_plane base;
        enum i915_pipe pipe;
        struct drm_i915_gem_object *obj;
-       bool primary_disabled;
+       bool can_scale;
        int max_downscale;
        u32 lut_r[1024], lut_g[1024], lut_b[1024];
        void (*update_plane)(struct drm_plane *plane,
@@ -318,6 +319,8 @@ struct intel_fbc_work {
        int interval;
 };
 
+int intel_connector_update_modes(struct drm_connector *connector,
+                               struct edid *edid);
 int intel_ddc_get_modes(struct drm_connector *c, device_t adapter);
 extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
@@ -378,6 +381,9 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
                                                    struct drm_crtc *crtc);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
+extern enum transcoder
+intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
+                            enum i915_pipe pipe);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
 extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
 
@@ -449,6 +455,11 @@ extern void intel_update_watermarks(struct drm_device *dev);
 extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
                                           uint32_t sprite_width,
                                           int pixel_size);
+
+extern unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y,
+                                                     unsigned int bpp,
+                                                     unsigned int pitch);
+
 extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                                     struct drm_file *file_priv);
 extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
index 71cb647..8c35a4d 100644 (file)
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
- *
- * $FreeBSD: head/sys/dev/drm2/i915/intel_modes.c 249041 2013-04-03 08:27:35Z dumbbell $
  */
 
+#include <linux/i2c.h>
 #include <drm/drmP.h>
 #include <drm/drm_edid.h>
 #include "intel_drv.h"
 #include "i915_drv.h"
 #include <bus/iicbus/iiconf.h>
 
-/**
- * intel_ddc_probe
- *
- */
 bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
 {
        struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
@@ -59,6 +54,23 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
            == 0/* XXXKIB  2*/);
 }
 
+/**
+ * intel_connector_update_modes - update connector from edid
+ * @connector: DRM connector device to use
+ * @edid: previously read EDID information
+ */
+int intel_connector_update_modes(struct drm_connector *connector,
+                               struct edid *edid)
+{
+       int ret;
+
+       drm_mode_connector_update_edid_property(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+       drm_edid_to_eld(connector, edid);
+
+       return ret;
+}
+
 /**
  * intel_ddc_get_modes - get modelist from monitor
  * @connector: DRM connector device to use
@@ -66,19 +78,18 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
  *
  * Fetch the EDID information from @connector using the DDC bus.
  */
-int
-intel_ddc_get_modes(struct drm_connector *connector, device_t adapter)
+int intel_ddc_get_modes(struct drm_connector *connector,
+                       device_t adapter)
 {
        struct edid *edid;
-       int ret = 0;
+       int ret;
 
        edid = drm_get_edid(connector, adapter);
-       if (edid) {
-               drm_mode_connector_update_edid_property(connector, edid);
-               ret = drm_add_edid_modes(connector, edid);
-               drm_edid_to_eld(connector, edid);
-               drm_free(edid, DRM_MEM_KMS);
-       }
+       if (!edid)
+               return 0;
+
+       ret = intel_connector_update_modes(connector, edid);
+       kfree(edid, DRM_MEM_KMS);
 
        return ret;
 }
@@ -102,7 +113,7 @@ intel_attach_force_audio_property(struct drm_connector *connector)
                prop = drm_property_create_enum(dev, 0,
                                           "audio",
                                           force_audio_names,
-                                          DRM_ARRAY_SIZE(force_audio_names));
+                                          ARRAY_SIZE(force_audio_names));
                if (prop == NULL)
                        return;
 
@@ -126,9 +137,9 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector)
        prop = dev_priv->broadcast_rgb_property;
        if (prop == NULL) {
                prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
-                   "Broadcast RGB",
-                   broadcast_rgb_names,
-                   DRM_ARRAY_SIZE(broadcast_rgb_names));
+                                          "Broadcast RGB",
+                                          broadcast_rgb_names,
+                                          ARRAY_SIZE(broadcast_rgb_names));
                if (prop == NULL)
                        return;
 
index b5dcc50..b7c5cfc 100644 (file)
  * The older chips had a separate interface for programming plane related
  * registers; newer ones are much simpler and we can use the new DRM plane
  * support.
- *
- * $FreeBSD: src/sys/dev/drm2/i915/intel_sprite.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
-
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
 #include <uapi_drm/drm_fourcc.h>
@@ -51,7 +48,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        struct intel_plane *intel_plane = to_intel_plane(plane);
        int pipe = intel_plane->pipe;
        u32 sprctl, sprscale = 0;
-       int pixel_size;
+       unsigned long sprsurf_offset, linear_offset;
+       int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
        sprctl = I915_READ(SPRCTL(pipe));
 
@@ -59,37 +57,29 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        sprctl &= ~SPRITE_PIXFORMAT_MASK;
        sprctl &= ~SPRITE_RGB_ORDER_RGBX;
        sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
+       sprctl &= ~SPRITE_TILED;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
-               sprctl |= SPRITE_FORMAT_RGBX888;
-               pixel_size = 4;
+               sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
                break;
        case DRM_FORMAT_XRGB8888:
-               sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
-               pixel_size = 4;
+               sprctl |= SPRITE_FORMAT_RGBX888;
                break;
        case DRM_FORMAT_YUYV:
                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
-               pixel_size = 2;
                break;
        case DRM_FORMAT_YVYU:
                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
-               pixel_size = 2;
                break;
        case DRM_FORMAT_UYVY:
                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
-               pixel_size = 2;
                break;
        case DRM_FORMAT_VYUY:
                sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
-               pixel_size = 2;
                break;
        default:
-               DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
-               sprctl |= DVS_FORMAT_RGBX888;
-               pixel_size = 4;
-               break;
+               BUG();
        }
 
        if (obj->tiling_mode != I915_TILING_NONE)
@@ -113,30 +103,43 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
         * when scaling is disabled.
         */
        if (crtc_w != src_w || crtc_h != src_h) {
-               dev_priv->sprite_scaling_enabled = true;
-               sandybridge_update_wm(dev);
-               intel_wait_for_vblank(dev, pipe);
+               if (!dev_priv->sprite_scaling_enabled) {
+                       dev_priv->sprite_scaling_enabled = true;
+                       intel_update_watermarks(dev);
+                       intel_wait_for_vblank(dev, pipe);
+               }
                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
        } else {
-               dev_priv->sprite_scaling_enabled = false;
-               /* potentially re-enable LP watermarks */
-               sandybridge_update_wm(dev);
+               if (dev_priv->sprite_scaling_enabled) {
+                       dev_priv->sprite_scaling_enabled = false;
+                       /* potentially re-enable LP watermarks */
+                       intel_update_watermarks(dev);
+               }
        }
 
        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
-       if (obj->tiling_mode != I915_TILING_NONE) {
+
+       linear_offset = y * fb->pitches[0] + x * pixel_size;
+       sprsurf_offset =
+               intel_gen4_compute_offset_xtiled(&x, &y,
+                                                pixel_size, fb->pitches[0]);
+       linear_offset -= sprsurf_offset;
+
+       /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
+        * register */
+       if (IS_HASWELL(dev))
+               I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
+       else if (obj->tiling_mode != I915_TILING_NONE)
                I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
-       } else {
-               unsigned long offset;
+       else
+               I915_WRITE(SPRLINOFF(pipe), linear_offset);
 
-               offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
-               I915_WRITE(SPRLINOFF(pipe), offset);
-       }
        I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
-       I915_WRITE(SPRSCALE(pipe), sprscale);
+       if (intel_plane->can_scale)
+               I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
-       I915_WRITE(SPRSURF(pipe), obj->gtt_offset);
+       I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset);
        POSTING_READ(SPRSURF(pipe));
 }
 
@@ -150,10 +153,14 @@ ivb_disable_plane(struct drm_plane *plane)
 
        I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
        /* Can't leave the scaler enabled... */
-       I915_WRITE(SPRSCALE(pipe), 0);
+       if (intel_plane->can_scale)
+               I915_WRITE(SPRSCALE(pipe), 0);
        /* Activate double buffered register update */
-       I915_WRITE(SPRSURF(pipe), 0);
+       I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
        POSTING_READ(SPRSURF(pipe));
+
+       dev_priv->sprite_scaling_enabled = false;
+       intel_update_watermarks(dev);
 }
 
 static int
@@ -211,7 +218,7 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 }
 
 static void
-snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
+ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
                 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
@@ -220,8 +227,10 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(plane);
-       int pipe = intel_plane->pipe, pixel_size;
-       u32 dvscntr, dvsscale = 0;
+       int pipe = intel_plane->pipe;
+       unsigned long dvssurf_offset, linear_offset;
+       u32 dvscntr, dvsscale;
+       int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
        dvscntr = I915_READ(DVSCNTR(pipe));
 
@@ -229,44 +238,36 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        dvscntr &= ~DVS_PIXFORMAT_MASK;
        dvscntr &= ~DVS_RGB_ORDER_XBGR;
        dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
+       dvscntr &= ~DVS_TILED;
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_XBGR8888:
                dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
-               pixel_size = 4;
                break;
        case DRM_FORMAT_XRGB8888:
                dvscntr |= DVS_FORMAT_RGBX888;
-               pixel_size = 4;
                break;
        case DRM_FORMAT_YUYV:
                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
-               pixel_size = 2;
                break;
        case DRM_FORMAT_YVYU:
                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
-               pixel_size = 2;
                break;
        case DRM_FORMAT_UYVY:
                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
-               pixel_size = 2;
                break;
        case DRM_FORMAT_VYUY:
                dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
-               pixel_size = 2;
                break;
        default:
-               DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
-               dvscntr |= DVS_FORMAT_RGBX888;
-               pixel_size = 4;
-               break;
+               BUG();
        }
 
        if (obj->tiling_mode != I915_TILING_NONE)
                dvscntr |= DVS_TILED;
 
-       /* must disable */
-       dvscntr |= DVS_TRICKLE_FEED_DISABLE;
+       if (IS_GEN6(dev))
+               dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
        dvscntr |= DVS_ENABLE;
 
        /* Sizes are 0 based */
@@ -277,28 +278,33 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 
        intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
 
-       if (crtc_w != src_w || crtc_h != src_h)
+       dvsscale = 0;
+       if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
-       if (obj->tiling_mode != I915_TILING_NONE) {
+
+       linear_offset = y * fb->pitches[0] + x * pixel_size;
+       dvssurf_offset =
+               intel_gen4_compute_offset_xtiled(&x, &y,
+                                                pixel_size, fb->pitches[0]);
+       linear_offset -= dvssurf_offset;
+
+       if (obj->tiling_mode != I915_TILING_NONE)
                I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
-       } else {
-               unsigned long offset;
+       else
+               I915_WRITE(DVSLINOFF(pipe), linear_offset);
 
-               offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
-               I915_WRITE(DVSLINOFF(pipe), offset);
-       }
        I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
-       I915_WRITE(DVSSURF(pipe), obj->gtt_offset);
+       I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset);
        POSTING_READ(DVSSURF(pipe));
 }
 
 static void
-snb_disable_plane(struct drm_plane *plane)
+ilk_disable_plane(struct drm_plane *plane)
 {
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -309,7 +315,7 @@ snb_disable_plane(struct drm_plane *plane)
        /* Disable the scaler */
        I915_WRITE(DVSSCALE(pipe), 0);
        /* Flush double buffered register updates */
-       I915_WRITE(DVSSURF(pipe), 0);
+       I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
        POSTING_READ(DVSSURF(pipe));
 }
 
@@ -321,6 +327,12 @@ intel_enable_primary(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int reg = DSPCNTR(intel_crtc->plane);
 
+       if (!intel_crtc->primary_disabled)
+               return;
+
+       intel_crtc->primary_disabled = false;
+       intel_update_fbc(dev);
+
        I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
 }
 
@@ -332,11 +344,17 @@ intel_disable_primary(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int reg = DSPCNTR(intel_crtc->plane);
 
+       if (intel_crtc->primary_disabled)
+               return;
+
        I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
+
+       intel_crtc->primary_disabled = true;
+       intel_update_fbc(dev);
 }
 
 static int
-snb_update_colorkey(struct drm_plane *plane,
+ilk_update_colorkey(struct drm_plane *plane,
                    struct drm_intel_sprite_colorkey *key)
 {
        struct drm_device *dev = plane->dev;
@@ -365,7 +383,7 @@ snb_update_colorkey(struct drm_plane *plane,
 }
 
 static void
-snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
+ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 {
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -427,6 +445,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (intel_plane->pipe != intel_crtc->pipe)
                return -EINVAL;
 
+       /* Sprite planes can be linear or x-tiled surfaces */
+       switch (obj->tiling_mode) {
+               case I915_TILING_NONE:
+               case I915_TILING_X:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
        /*
         * Clamp the width & height into the visible area.  Note we don't
         * try to scale the source if part of the visible region is offscreen.
@@ -453,6 +480,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (!crtc_w || !crtc_h) /* Again, nothing to display */
                goto out;
 
+       /*
+        * We may not have a scaler, eg. HSW does not have it any more
+        */
+       if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h))
+               return -EINVAL;
+
        /*
         * We can take a larger source and scale it down, but
         * only so much...  16x is the max on SNB.
@@ -480,18 +513,14 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
         * Be sure to re-enable the primary before the sprite is no longer
         * covering it fully.
         */
-       if (!disable_primary && intel_plane->primary_disabled) {
+       if (!disable_primary)
                intel_enable_primary(crtc);
-               intel_plane->primary_disabled = false;
-       }
 
        intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
                                  crtc_w, crtc_h, x, y, src_w, src_h);
 
-       if (disable_primary) {
+       if (disable_primary)
                intel_disable_primary(crtc);
-               intel_plane->primary_disabled = true;
-       }
 
        /* Unpin old obj after new one is active to avoid ugliness */
        if (old_obj) {
@@ -522,11 +551,8 @@ intel_disable_plane(struct drm_plane *plane)
        struct intel_plane *intel_plane = to_intel_plane(plane);
        int ret = 0;
 
-       if (intel_plane->primary_disabled) {
+       if (plane->crtc)
                intel_enable_primary(plane->crtc);
-               intel_plane->primary_disabled = false;
-       }
-
        intel_plane->disable_plane(plane);
 
        if (!intel_plane->obj)
@@ -553,21 +579,20 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv)
 {
        struct drm_intel_sprite_colorkey *set = data;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_object *obj;
        struct drm_plane *plane;
        struct intel_plane *intel_plane;
        int ret = 0;
 
-       if (!dev_priv)
-               return -EINVAL;
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -ENODEV;
 
        /* Make sure we don't try to enable both src & dest simultaneously */
        if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
                return -EINVAL;
 
        lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE);
-       
+
        obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
        if (!obj) {
                ret = -EINVAL;
@@ -587,14 +612,13 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv)
 {
        struct drm_intel_sprite_colorkey *get = data;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_object *obj;
        struct drm_plane *plane;
        struct intel_plane *intel_plane;
        int ret = 0;
 
-       if (!dev_priv)
-               return -EINVAL;
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -ENODEV;
 
        lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE);
 
@@ -619,6 +643,14 @@ static const struct drm_plane_funcs intel_plane_funcs = {
        .destroy = intel_destroy_plane,
 };
 
+static uint32_t ilk_plane_formats[] = {
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
+};
+
 static uint32_t snb_plane_formats[] = {
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
@@ -633,36 +665,65 @@ intel_plane_init(struct drm_device *dev, enum i915_pipe pipe)
 {
        struct intel_plane *intel_plane;
        unsigned long possible_crtcs;
+       const uint32_t *plane_formats;
+       int num_plane_formats;
        int ret;
 
-       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+       if (INTEL_INFO(dev)->gen < 5)
                return -ENODEV;
 
        intel_plane = kmalloc(sizeof(struct intel_plane), DRM_MEM_KMS,
            M_WAITOK | M_ZERO);
+       if (!intel_plane)
+               return -ENOMEM;
 
-       if (IS_GEN6(dev)) {
+       switch (INTEL_INFO(dev)->gen) {
+       case 5:
+       case 6:
+               intel_plane->can_scale = true;
                intel_plane->max_downscale = 16;
-               intel_plane->update_plane = snb_update_plane;
-               intel_plane->disable_plane = snb_disable_plane;
-               intel_plane->update_colorkey = snb_update_colorkey;
-               intel_plane->get_colorkey = snb_get_colorkey;
-       } else if (IS_GEN7(dev)) {
+               intel_plane->update_plane = ilk_update_plane;
+               intel_plane->disable_plane = ilk_disable_plane;
+               intel_plane->update_colorkey = ilk_update_colorkey;
+               intel_plane->get_colorkey = ilk_get_colorkey;
+
+               if (IS_GEN6(dev)) {
+                       plane_formats = snb_plane_formats;
+                       num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+               } else {
+                       plane_formats = ilk_plane_formats;
+                       num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
+               }
+               break;
+
+       case 7:
+               if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev))
+                       intel_plane->can_scale = false;
+               else
+                       intel_plane->can_scale = true;
                intel_plane->max_downscale = 2;
                intel_plane->update_plane = ivb_update_plane;
                intel_plane->disable_plane = ivb_disable_plane;
                intel_plane->update_colorkey = ivb_update_colorkey;
                intel_plane->get_colorkey = ivb_get_colorkey;
+
+               plane_formats = snb_plane_formats;
+               num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+               break;
+
+       default:
+               kfree(intel_plane, DRM_MEM_KMS);
+               return -ENODEV;
        }
 
        intel_plane->pipe = pipe;
        possible_crtcs = (1 << pipe);
        ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
-                            &intel_plane_funcs, snb_plane_formats,
-                            DRM_ARRAY_SIZE(snb_plane_formats), false);
+                            &intel_plane_funcs,
+                            plane_formats, num_plane_formats,
+                            false);
        if (ret)
                drm_free(intel_plane, DRM_MEM_KMS);
 
        return ret;
 }
-