From e08e96de986ceb2c6b683df0bd0c4ddd4f91dcfd Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 31 Oct 2011 07:28:57 -0700 Subject: drm: Make the per-driver file_operations struct const From fdf1fdebaa00f81de18c227f32f8074c8b352d50 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 30 Oct 2011 19:06:07 -0700 Subject: [PATCH] drm: Make the per-driver file_operations struct const The DRM layer keeps a copy of struct file_operations inside its big driver struct... which prevents it from being consistent and static. For consistency (and the general security objective of having such things static), it's desirable to get this fixed. This patch splits out the file_operations field to its own struct, which is then "static const", and just stick a pointer to this into the driver struct, making it more consistent with how the rest of the kernel does this. Signed-off-by: Arjan van de Ven Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_drv.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index cc531bb..9f59270 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -788,6 +788,21 @@ static struct vm_operations_struct i915_gem_vm_ops = { .close = drm_gem_vm_close, }; +static const struct file_operations i915_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = drm_gem_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + .read = drm_read, +#ifdef CONFIG_COMPAT + .compat_ioctl = i915_compat_ioctl, +#endif + .llseek = noop_llseek, +}; + static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should * deal with them for intel hardware. @@ -821,21 +836,7 @@ static struct drm_driver driver = { .dumb_map_offset = i915_gem_mmap_gtt, .dumb_destroy = i915_gem_dumb_destroy, .ioctls = i915_ioctls, - .fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .mmap = drm_gem_mmap, - .poll = drm_poll, - .fasync = drm_fasync, - .read = drm_read, -#ifdef CONFIG_COMPAT - .compat_ioctl = i915_compat_ioctl, -#endif - .llseek = noop_llseek, - }, - + .fops = &i915_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, -- cgit v1.1 From 308e5bcbdb10452e8aba31aa21432fb67ee46d72 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 14 Nov 2011 14:51:28 -0800 Subject: drm: add an fb creation ioctl that takes a pixel format v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To properly support the various plane formats supported by different hardware, the kernel must know the pixel format of a framebuffer object. So add a new ioctl taking a format argument corresponding to a fourcc name from the new drm_fourcc.h header file. Implement the fb creation hooks in terms of the new mode_fb_cmd2 using helpers where the old bpp/depth values are needed. v2: create DRM specific fourcc header file for sharing with libdrm etc v3: fix rebase failure and use DRM fourcc codes in intel_display.c and update commit message v4: make fb_cmd2 handle field into an array for multi-object formats pull in Ville's fix for the memcpy in drm_plane_init apply Ville's cleanup to zero out fb_cmd2 arg in drm_mode_addfb v5: add 'flags' field for interlaced support (from Ville) Signed-off-by: Ville Syrjälä Acked-by: Alan Cox Reviewed-by: Rob Clark Signed-off-by: Jesse Barnes Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_display.c | 39 +++++++++++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_fb.c | 11 +++++----- 3 files changed, 28 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 981b1f1..50ae915 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6279,7 +6279,7 @@ static struct drm_display_mode load_detect_mode = { static struct drm_framebuffer * intel_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { struct intel_framebuffer *intel_fb; @@ -6321,7 +6321,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev, int depth, int bpp) { struct drm_i915_gem_object *obj; - struct drm_mode_fb_cmd mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd; obj = i915_gem_alloc_object(dev, intel_framebuffer_size_for_mode(mode, bpp)); @@ -6330,9 +6330,9 @@ intel_framebuffer_create_for_mode(struct drm_device *dev, mode_cmd.width = mode->hdisplay; mode_cmd.height = mode->vdisplay; - mode_cmd.depth = depth; - mode_cmd.bpp = bpp; - mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp); + mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width, + bpp); + mode_cmd.pixel_format = 0; return intel_framebuffer_create(dev, &mode_cmd, obj); } @@ -7573,7 +7573,7 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *intel_fb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { int ret; @@ -7581,21 +7581,23 @@ int intel_framebuffer_init(struct drm_device *dev, if (obj->tiling_mode == I915_TILING_Y) return -EINVAL; - if (mode_cmd->pitch & 63) + if (mode_cmd->pitches[0] & 63) return -EINVAL; - switch (mode_cmd->bpp) { - case 8: - case 16: - /* Only pre-ILK can handle 5:5:5 */ - if (mode_cmd->depth == 15 && !HAS_PCH_SPLIT(dev)) - return -EINVAL; + switch (mode_cmd->pixel_format) { + case DRM_FOURCC_RGB332: + case DRM_FOURCC_RGB565: + case DRM_FOURCC_RGB24: + case DRM_INTEL_RGB30: + /* RGB formats are common across chipsets */ break; - - case 24: - case 32: + case DRM_FOURCC_YUYV: + case DRM_FOURCC_UYVY: + case DRM_FOURCC_YVYU: + case DRM_FOURCC_VYUY: break; default: + DRM_ERROR("unsupported pixel format\n"); return -EINVAL; } @@ -7613,11 +7615,12 @@ int intel_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_i915_gem_object *obj; - obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); + obj = to_intel_bo(drm_gem_object_lookup(dev, filp, + mode_cmd->handles[0])); if (&obj->base == NULL) return ERR_PTR(-ENOENT); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bd9a604..23c5622 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -359,7 +359,7 @@ extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, - struct drm_mode_fb_cmd *mode_cmd, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ec49bae..dc1db4f 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -65,7 +65,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; - struct drm_mode_fb_cmd mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd; struct drm_i915_gem_object *obj; struct device *device = &dev->pdev->dev; int size, ret; @@ -77,11 +77,12 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; - mode_cmd.bpp = sizes->surface_bpp; - mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64); - mode_cmd.depth = sizes->surface_depth; + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) / + 8), 64); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); - size = mode_cmd.pitch * mode_cmd.height; + size = mode_cmd.pitches[0] * mode_cmd.height; size = ALIGN(size, PAGE_SIZE); obj = i915_gem_alloc_object(dev, size); if (!obj) { -- cgit v1.1 From 04b3924db60f974d2b4af0b2e19a0ae7ca202dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 17 Nov 2011 18:05:13 +0200 Subject: drm: Redefine pixel formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Name the formats as DRM_FORMAT_X instead of DRM_FOURCC_X. Use consistent names, especially for the RGB formats. Component order and byte order are now strictly specified for each format. The RGB format naming follows a convention where the components names and sizes are listed from left to right, matching the order within a single pixel from most significant bit to least significant bit. The YUV format names vary more. For the 4:2:2 packed formats and 2 plane formats use the fourcc. For the three plane formats the name includes the plane order and subsampling information using the standard subsampling notation. Some of those also happen to match the official fourcc definition. The fourccs for for all the RGB formats and some of the YUV formats I invented myself. The idea was that looking at just the fourcc you get some idea what the format is about without having to decode it using some external reference. Signed-off-by: Ville Syrjälä Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_display.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 50ae915..0bc93c3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7585,16 +7585,18 @@ int intel_framebuffer_init(struct drm_device *dev, return -EINVAL; switch (mode_cmd->pixel_format) { - case DRM_FOURCC_RGB332: - case DRM_FOURCC_RGB565: - case DRM_FOURCC_RGB24: - case DRM_INTEL_RGB30: + case DRM_FORMAT_RGB332: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: /* RGB formats are common across chipsets */ break; - case DRM_FOURCC_YUYV: - case DRM_FOURCC_UYVY: - case DRM_FOURCC_YVYU: - case DRM_FOURCC_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_VYUY: break; default: DRM_ERROR("unsupported pixel format\n"); -- cgit v1.1 From b3f33cbf7ace8fc149993ee35e0d0fd57f41d6d8 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:17 +0800 Subject: drm/i915: fix ELD writing for SandyBridge SandyBridge should be using the same register addresses as IvyBridge. Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d809b03..8a61b81 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5876,14 +5876,14 @@ static void ironlake_write_eld(struct drm_connector *connector, int aud_cntl_st; int aud_cntrl_st2; - if (IS_IVYBRIDGE(connector->dev)) { - hdmiw_hdmiedid = GEN7_HDMIW_HDMIEDID_A; - aud_cntl_st = GEN7_AUD_CNTRL_ST_A; - aud_cntrl_st2 = GEN7_AUD_CNTRL_ST2; - } else { + if (HAS_PCH_IBX(connector->dev)) { hdmiw_hdmiedid = GEN5_HDMIW_HDMIEDID_A; aud_cntl_st = GEN5_AUD_CNTL_ST_A; aud_cntrl_st2 = GEN5_AUD_CNTL_ST2; + } else { + hdmiw_hdmiedid = GEN7_HDMIW_HDMIEDID_A; + aud_cntl_st = GEN7_AUD_CNTRL_ST_A; + aud_cntrl_st2 = GEN7_AUD_CNTRL_ST2; } i = to_intel_crtc(crtc)->pipe; -- cgit v1.1 From 1202b4c6782e57a71c4b162a51a4e7ad8402a950 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:18 +0800 Subject: drm/i915: rename audio ELD registers Change the definitions from GEN5 to IBX as they aren't in the CPU and some SNB systems actually shipped with IBX chipsets (or, at least that's a supported configuration). The GEN7_* register addresses actually take effect since GEN6 and should be prefixed by CPT, the PCH code name. Suggested-by: Keith Packard Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_reg.h | 24 ++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a26d5b0..771a058 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3569,17 +3569,17 @@ #define G4X_ELD_ACK (1 << 4) #define G4X_HDMIW_HDMIEDID 0x6210C -#define GEN5_HDMIW_HDMIEDID_A 0xE2050 -#define GEN5_AUD_CNTL_ST_A 0xE20B4 -#define GEN5_ELD_BUFFER_SIZE (0x1f << 10) -#define GEN5_ELD_ADDRESS (0x1f << 5) -#define GEN5_ELD_ACK (1 << 4) -#define GEN5_AUD_CNTL_ST2 0xE20C0 -#define GEN5_ELD_VALIDB (1 << 0) -#define GEN5_CP_READYB (1 << 1) - -#define GEN7_HDMIW_HDMIEDID_A 0xE5050 -#define GEN7_AUD_CNTRL_ST_A 0xE50B4 -#define GEN7_AUD_CNTRL_ST2 0xE50C0 +#define IBX_HDMIW_HDMIEDID_A 0xE2050 +#define IBX_AUD_CNTL_ST_A 0xE20B4 +#define IBX_ELD_BUFFER_SIZE (0x1f << 10) +#define IBX_ELD_ADDRESS (0x1f << 5) +#define IBX_ELD_ACK (1 << 4) +#define IBX_AUD_CNTL_ST2 0xE20C0 +#define IBX_ELD_VALIDB (1 << 0) +#define IBX_CP_READYB (1 << 1) + +#define CPT_HDMIW_HDMIEDID_A 0xE5050 +#define CPT_AUD_CNTL_ST_A 0xE50B4 +#define CPT_AUD_CNTRL_ST2 0xE50C0 #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8a61b81..8d322ab 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5877,13 +5877,13 @@ static void ironlake_write_eld(struct drm_connector *connector, int aud_cntrl_st2; if (HAS_PCH_IBX(connector->dev)) { - hdmiw_hdmiedid = GEN5_HDMIW_HDMIEDID_A; - aud_cntl_st = GEN5_AUD_CNTL_ST_A; - aud_cntrl_st2 = GEN5_AUD_CNTL_ST2; + hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A; + aud_cntl_st = IBX_AUD_CNTL_ST_A; + aud_cntrl_st2 = IBX_AUD_CNTL_ST2; } else { - hdmiw_hdmiedid = GEN7_HDMIW_HDMIEDID_A; - aud_cntl_st = GEN7_AUD_CNTRL_ST_A; - aud_cntrl_st2 = GEN7_AUD_CNTRL_ST2; + hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A; + aud_cntl_st = CPT_AUD_CNTL_ST_A; + aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; } i = to_intel_crtc(crtc)->pipe; @@ -5897,12 +5897,12 @@ static void ironlake_write_eld(struct drm_connector *connector, if (!i) { DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); /* operate blindly on all ports */ - eldv = GEN5_ELD_VALIDB; - eldv |= GEN5_ELD_VALIDB << 4; - eldv |= GEN5_ELD_VALIDB << 8; + eldv = IBX_ELD_VALIDB; + eldv |= IBX_ELD_VALIDB << 4; + eldv |= IBX_ELD_VALIDB << 8; } else { DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i); - eldv = GEN5_ELD_VALIDB << ((i - 1) * 4); + eldv = IBX_ELD_VALIDB << ((i - 1) * 4); } i = I915_READ(aud_cntrl_st2); @@ -5918,7 +5918,7 @@ static void ironlake_write_eld(struct drm_connector *connector, } i = I915_READ(aud_cntl_st); - i &= ~GEN5_ELD_ADDRESS; + i &= ~IBX_ELD_ADDRESS; I915_WRITE(aud_cntl_st, i); len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ -- cgit v1.1 From 3a9627f4fbb0ec2e8f6c8a17a589b659873ee04e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:19 +0800 Subject: drm/i915: dont trigger hotplug events on unchanged ELD The ELD may or may not change when switching the video mode. If unchanged, don't trigger hot plug events to HDMI audio driver. This avoids disturbing the user with repeated printks. Reported-by: Nick Bowler Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 51 ++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8d322ab..7eaea5ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5830,6 +5830,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static bool intel_eld_uptodate(struct drm_connector *connector, + int reg_eldv, uint32_t bits_eldv, + int reg_elda, uint32_t bits_elda, + int reg_edid) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + uint32_t i; + + i = I915_READ(reg_eldv); + i &= bits_eldv; + + if (!eld[0]) + return !i; + + if (!i) + return false; + + i = I915_READ(reg_elda); + i &= ~bits_elda; + I915_WRITE(reg_elda, i); + + for (i = 0; i < eld[2]; i++) + if (I915_READ(reg_edid) != *((uint32_t *)eld + i)) + return false; + + return true; +} + static void g4x_write_eld(struct drm_connector *connector, struct drm_crtc *crtc) { @@ -5846,6 +5875,12 @@ static void g4x_write_eld(struct drm_connector *connector, else eldv = G4X_ELDV_DEVCTG; + if (intel_eld_uptodate(connector, + G4X_AUD_CNTL_ST, eldv, + G4X_AUD_CNTL_ST, G4X_ELD_ADDR, + G4X_HDMIW_HDMIEDID)) + return; + i = I915_READ(G4X_AUD_CNTL_ST); i &= ~(eldv | G4X_ELD_ADDR); len = (i >> 9) & 0x1f; /* ELD buffer size */ @@ -5905,6 +5940,17 @@ static void ironlake_write_eld(struct drm_connector *connector, eldv = IBX_ELD_VALIDB << ((i - 1) * 4); } + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); + eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ + } + + if (intel_eld_uptodate(connector, + aud_cntrl_st2, eldv, + aud_cntl_st, IBX_ELD_ADDRESS, + hdmiw_hdmiedid)) + return; + i = I915_READ(aud_cntrl_st2); i &= ~eldv; I915_WRITE(aud_cntrl_st2, i); @@ -5912,11 +5958,6 @@ static void ironlake_write_eld(struct drm_connector *connector, if (!eld[0]) return; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { - DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); - eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */ - } - i = I915_READ(aud_cntl_st); i &= ~IBX_ELD_ADDRESS; I915_WRITE(aud_cntl_st, i); -- cgit v1.1 From 2deed761188d7480eb5f7efbfe7aa77f09322ed8 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:20 +0800 Subject: drm/i915: HDMI hot remove notification to audio driver On HDMI monitor hot remove, clear SDVO_AUDIO_ENABLE accordingly, so that the audio driver will receive hot plug events and take action to refresh its device state and ELD contents. The cleared SDVO_AUDIO_ENABLE bit needs to be restored to prevent losing HDMI audio after DPMS on. CC: Wang Zhenyu Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index d4f5a0b..64541f7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -269,6 +269,10 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 temp; + u32 enable_bits = SDVO_ENABLE; + + if (intel_hdmi->has_audio) + enable_bits |= SDVO_AUDIO_ENABLE; temp = I915_READ(intel_hdmi->sdvox_reg); @@ -281,9 +285,9 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) } if (mode != DRM_MODE_DPMS_ON) { - temp &= ~SDVO_ENABLE; + temp &= ~enable_bits; } else { - temp |= SDVO_ENABLE; + temp |= enable_bits; } I915_WRITE(intel_hdmi->sdvox_reg, temp); -- cgit v1.1 From 832afda6a7d7235ef0e09f4ec46736861540da6d Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:21 +0800 Subject: drm/i915: DisplayPort hot remove notification to audio driver On DP monitor hot remove, clear DP_AUDIO_OUTPUT_ENABLE accordingly, so that the audio driver will receive hot plug events and take action to refresh its device state and ELD contents. Note that the DP_AUDIO_OUTPUT_ENABLE bit may be enabled or disabled only when the link training is complete and set to "Normal". Tested OK for both hot plug/remove and DPMS on/off. Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 92b041b..db3b461 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1926,6 +1926,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); } + DP &= ~DP_AUDIO_OUTPUT_ENABLE; I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); POSTING_READ(intel_dp->output_reg); msleep(intel_dp->panel_power_down_delay); -- cgit v1.1 From 097354eb14fa94d31a09c64d640643f58e4a5a9a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 27 Nov 2011 18:58:17 +0100 Subject: drm/i915: check ACTHD of all rings Otherwise hangcheck spuriously fires when running blitter/bsd-only workloads. Contrary to a similar patch by Ben Widawsky this does not check INSTDONE of the other rings. Chris Wilson implied that in a failure to detect a hang, most likely because INSTDONE was fluctuating. Thus only check ACTHD, which as far as I know is rather reliable. Also, blitter and bsd rings can't launch complex tasks from a single instruction (like 3D_PRIM on the render with complex or even infinite shaders). This fixes spurious gpu hang detection when running tests/gem_hangcheck_forcewake on snb/ivb. Signed-Off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 554bef7..505af3f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -337,6 +337,8 @@ typedef struct drm_i915_private { struct timer_list hangcheck_timer; int hangcheck_count; uint32_t last_acthd; + uint32_t last_acthd_bsd; + uint32_t last_acthd_blt; uint32_t last_instdone; uint32_t last_instdone1; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b40004b..d47a53b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1669,7 +1669,7 @@ void i915_hangcheck_elapsed(unsigned long data) { struct drm_device *dev = (struct drm_device *)data; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t acthd, instdone, instdone1; + uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt; bool err = false; if (!i915_enable_hangcheck) @@ -1686,16 +1686,21 @@ void i915_hangcheck_elapsed(unsigned long data) } if (INTEL_INFO(dev)->gen < 4) { - acthd = I915_READ(ACTHD); instdone = I915_READ(INSTDONE); instdone1 = 0; } else { - acthd = I915_READ(ACTHD_I965); instdone = I915_READ(INSTDONE_I965); instdone1 = I915_READ(INSTDONE1); } + acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]); + acthd_bsd = HAS_BSD(dev) ? + intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0; + acthd_blt = HAS_BLT(dev) ? + intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0; if (dev_priv->last_acthd == acthd && + dev_priv->last_acthd_bsd == acthd_bsd && + dev_priv->last_acthd_blt == acthd_blt && dev_priv->last_instdone == instdone && dev_priv->last_instdone1 == instdone1) { if (dev_priv->hangcheck_count++ > 1) { @@ -1727,6 +1732,8 @@ void i915_hangcheck_elapsed(unsigned long data) dev_priv->hangcheck_count = 0; dev_priv->last_acthd = acthd; + dev_priv->last_acthd_bsd = acthd_bsd; + dev_priv->last_acthd_blt = acthd_blt; dev_priv->last_instdone = instdone; dev_priv->last_instdone1 = instdone1; } -- cgit v1.1 From 59df7b1771c150163e522f33c638096ab0efbf42 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Mon, 19 Dec 2011 20:03:33 +0100 Subject: drm/intel: Fix initialization if startup happens in interlaced mode [v2] My EFI BIOS starts the graphics card up in my projector's preferred EDID mode, 1080@60i. The Intel driver does not clear all the interlaced bits. This patch introduces a new PIPECONF_INTERLACE_MASK define and uses it to restore progressive mode. Signed-of-by: Christian Schmidt Reviewed-by: Chris Wilson Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5a09416..517bf0c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2312,6 +2312,7 @@ #define PIPECONF_PROGRESSIVE (0 << 21) #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +#define PIPECONF_INTERLACE_MASK (7 << 21) #define PIPECONF_CXSR_DOWNCLOCK (1<<16) #define PIPECONF_BPP_MASK (0x000000e0) #define PIPECONF_BPP_8 (0<<5) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bc93c3..5dd9bf6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5136,7 +5136,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, adjusted_mode->crtc_vsync_end -= 1; adjusted_mode->crtc_vsync_start -= 1; } else - pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */ + pipeconf &= ~PIPECONF_INTERLACE_MASK; /* progressive */ I915_WRITE(HTOTAL(pipe), (adjusted_mode->crtc_hdisplay - 1) | -- cgit v1.1 From 01f2c7730e188077026c5f766f85f329c7000c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 20 Dec 2011 00:06:49 +0200 Subject: drm: Replace pitch with pitches[] in drm_framebuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise each driver would need to keep the information inside their own framebuffer object structure. Also add offsets[]. BOs on the other hand are driver specific, so those can be kept in driver specific structures. Signed-off-by: Ville Syrjälä Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_fb.c | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9ee2729..96643ee2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1204,7 +1204,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) } else { int dspaddr = DSPADDR(intel_crtc->plane); stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + - crtc->y * crtc->fb->pitch + + crtc->y * crtc->fb->pitches[0] + crtc->x * crtc->fb->bits_per_pixel/8); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5dd9bf6..8ecbc2f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1511,8 +1511,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) u32 fbc_ctl, fbc_ctl2; cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; - if (fb->pitch < cfb_pitch) - cfb_pitch = fb->pitch; + if (fb->pitches[0] < cfb_pitch) + cfb_pitch = fb->pitches[0]; /* FBC_CTL wants 64B units */ cfb_pitch = (cfb_pitch / 64) - 1; @@ -2073,11 +2073,11 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, I915_WRITE(reg, dspcntr); Start = obj->gtt_offset; - Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); + Offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", - Start, Offset, x, y, fb->pitch); - I915_WRITE(DSPSTRIDE(plane), fb->pitch); + Start, Offset, x, y, fb->pitches[0]); + I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); if (INTEL_INFO(dev)->gen >= 4) { I915_WRITE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); @@ -2154,11 +2154,11 @@ static int ironlake_update_plane(struct drm_crtc *crtc, I915_WRITE(reg, dspcntr); Start = obj->gtt_offset; - Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); + Offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", - Start, Offset, x, y, fb->pitch); - I915_WRITE(DSPSTRIDE(plane), fb->pitch); + Start, Offset, x, y, fb->pitches[0]); + I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); I915_WRITE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPADDR(plane), Offset); @@ -6353,11 +6353,11 @@ mode_fits_in_fbdev(struct drm_device *dev, return NULL; fb = &dev_priv->fbdev->ifb.base; - if (fb->pitch < intel_framebuffer_pitch_for_width(mode->hdisplay, - fb->bits_per_pixel)) + if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay, + fb->bits_per_pixel)) return NULL; - if (obj->base.size < mode->vdisplay * fb->pitch) + if (obj->base.size < mode->vdisplay * fb->pitches[0]) return NULL; return fb; @@ -6990,7 +6990,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev, goto out; /* Offset into the new buffer for cases of shared fbs between CRTCs */ - offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; + offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; ret = BEGIN_LP_RING(6); if (ret) @@ -7007,7 +7007,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev, OUT_RING(MI_NOOP); OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch); + OUT_RING(fb->pitches[0]); OUT_RING(obj->gtt_offset + offset); OUT_RING(MI_NOOP); ADVANCE_LP_RING(); @@ -7031,7 +7031,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, goto out; /* Offset into the new buffer for cases of shared fbs between CRTCs */ - offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; + offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; ret = BEGIN_LP_RING(6); if (ret) @@ -7045,7 +7045,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, OUT_RING(MI_NOOP); OUT_RING(MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch); + OUT_RING(fb->pitches[0]); OUT_RING(obj->gtt_offset + offset); OUT_RING(MI_NOOP); @@ -7078,7 +7078,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev, */ OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch); + OUT_RING(fb->pitches[0]); OUT_RING(obj->gtt_offset | obj->tiling_mode); /* XXX Enabling the panel-fitter across page-flip is so far @@ -7113,7 +7113,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev, OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch | obj->tiling_mode); + OUT_RING(fb->pitches[0] | obj->tiling_mode); OUT_RING(obj->gtt_offset); pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE; @@ -7149,7 +7149,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, goto out; intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); - intel_ring_emit(ring, (fb->pitch | obj->tiling_mode)); + intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, (obj->gtt_offset)); intel_ring_emit(ring, (MI_NOOP)); intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index dc1db4f..f02fc71 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -149,7 +149,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, // memset(info->screen_base, 0, size); - drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); info->pixmap.size = 64*1024; -- cgit v1.1 From e2971bdab2b761683353da383c0fd5ac704d1cca Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 12 Dec 2011 19:21:57 -0800 Subject: drm/i915: relative_constants_mode race fix dev_priv keeps track of the current addressing mode that gets set at execbuffer time. Unfortunately the existing code was doing this before acquiring struct_mutex which leaves a race with another thread also doing an execbuffer. If that wasn't bad enough, relocate_slow drops struct_mutex which opens a much more likely error where another thread comes in and modifies the state while relocate_slow is being slow. The solution here is to just defer setting this state until we absolutely need it, and we know we'll have struct_mutex for the remainder of our code path. v2: Keith noticed a bug in the original patch. Signed-off-by: Ben Widawsky Reviewed-by: Daniel Vetter Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c681dc1..68e5b41 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1033,19 +1033,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (INTEL_INFO(dev)->gen > 5 && mode == I915_EXEC_CONSTANTS_REL_SURFACE) return -EINVAL; - - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; - - intel_ring_emit(ring, MI_NOOP); - intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, INSTPM); - intel_ring_emit(ring, - I915_EXEC_CONSTANTS_MASK << 16 | mode); - intel_ring_advance(ring); - - dev_priv->relative_constants_mode = mode; } break; default: @@ -1176,6 +1163,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } } + if (ring == &dev_priv->ring[RCS] && + mode != dev_priv->relative_constants_mode) { + ret = intel_ring_begin(ring, 4); + if (ret) + goto err; + + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, INSTPM); + intel_ring_emit(ring, + I915_EXEC_CONSTANTS_MASK << 16 | mode); + intel_ring_advance(ring); + + dev_priv->relative_constants_mode = mode; + } + trace_i915_gem_ring_dispatch(ring, seqno); exec_start = batch_obj->gtt_offset + args->batch_start_offset; -- cgit v1.1 From 84f9f938be4156e4baea466688bd6abae1c9e6ba Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 12 Dec 2011 19:21:58 -0800 Subject: drm/i915: Force sync command ordering (Gen6+) The docs say this is required for Gen7, and since the bit was added for Gen6, we are also setting it there pit pf paranoia. Particularly as Chris points out, if PIPE_CONTROL counts as a 3d state packet. This was found through doc inspection by Ken and applies to Gen6+; Reported-by: Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Reviewed-by: Daniel Vetter Reviewed-by: Eric Anholt Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 +++++++-- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 68e5b41..11545ff 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -984,6 +984,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct intel_ring_buffer *ring; u32 exec_start, exec_len; u32 seqno; + u32 mask; int ret, mode, i; if (!i915_gem_check_execbuffer(args)) { @@ -1021,6 +1022,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } mode = args->flags & I915_EXEC_CONSTANTS_MASK; + mask = I915_EXEC_CONSTANTS_MASK; switch (mode) { case I915_EXEC_CONSTANTS_REL_GENERAL: case I915_EXEC_CONSTANTS_ABSOLUTE: @@ -1033,6 +1035,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (INTEL_INFO(dev)->gen > 5 && mode == I915_EXEC_CONSTANTS_REL_SURFACE) return -EINVAL; + + /* The HW changed the meaning on this bit on gen6 */ + if (INTEL_INFO(dev)->gen >= 6) + mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE; } break; default: @@ -1172,8 +1178,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(ring, INSTPM); - intel_ring_emit(ring, - I915_EXEC_CONSTANTS_MASK << 16 | mode); + intel_ring_emit(ring, mask << 16 | mode); intel_ring_advance(ring); dev_priv->relative_constants_mode = mode; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 194d987..3ae2c7c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -442,6 +442,7 @@ #define INSTPM_AGPBUSY_DIS (1<<11) /* gen3: when disabled, pending interrupts will not assert AGPBUSY# and will only be delivered when out of C3. */ +#define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */ #define ACTHD 0x020c8 #define FW_BLC 0x020d8 #define FW_BLC2 0x020dc diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ca70e2f..f5dae5de 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -414,6 +414,11 @@ static int init_render_ring(struct intel_ring_buffer *ring) return ret; } + if (INTEL_INFO(dev)->gen >= 6) { + I915_WRITE(INSTPM, + INSTPM_FORCE_ORDERING << 16 | INSTPM_FORCE_ORDERING); + } + return ret; } -- cgit v1.1 From 6ed55ee7da15329476174bc5821dbc723f671f44 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 12 Dec 2011 19:21:59 -0800 Subject: drm/i915: Update GEN6_RP_CONTROL definitions This matches the modern specs more accurately. This will be used by the following patch to fix the way we display RC status. Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Reviewed-by: Eugeni Dodonov Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_reg.h | 6 +++++- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3ae2c7c..583e8c7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3502,7 +3502,11 @@ #define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) #define GEN6_RP_CONTROL 0xA024 #define GEN6_RP_MEDIA_TURBO (1<<11) -#define GEN6_RP_USE_NORMAL_FREQ (1<<9) +#define GEN6_RP_MEDIA_MODE_MASK (3<<9) +#define GEN6_RP_MEDIA_HW_TURBO_MODE (3<<9) +#define GEN6_RP_MEDIA_HW_NORMAL_MODE (2<<9) +#define GEN6_RP_MEDIA_HW_MODE (1<<9) +#define GEN6_RP_MEDIA_SW_MODE (0<<9) #define GEN6_RP_MEDIA_IS_GFX (1<<8) #define GEN6_RP_ENABLE (1<<7) #define GEN6_RP_UP_IDLE_MIN (0x1<<3) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 55a5b4c..cb21d5b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8043,7 +8043,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO | - GEN6_RP_USE_NORMAL_FREQ | + GEN6_RP_MEDIA_HW_MODE | GEN6_RP_MEDIA_IS_GFX | GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG | -- cgit v1.1 From 4d85529d584856d077895a2daa703224d3aee7e1 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 12 Dec 2011 19:34:16 -0800 Subject: drm/i915: drpc debugfs update for gen6 Many of the old fields from Ironlake have gone away. Strip all those fields, and try to update to fields people care about. RC information isn't exactly ideal anymore. All we can guarantee when we read the register is that we're not using forcewake, ie. the software isn't forcing the hardware to stay awake. The downside is that in doing this we may wait a while and that causes an unnaturally idle state on the GPU. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=42578 Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_debugfs.c | 86 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 8 ++++ 2 files changed, 93 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 004b048..1180798 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1001,7 +1001,7 @@ static int i915_inttoext_table(struct seq_file *m, void *unused) return 0; } -static int i915_drpc_info(struct seq_file *m, void *unused) +static int ironlake_drpc_info(struct seq_file *m) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; @@ -1068,6 +1068,90 @@ static int i915_drpc_info(struct seq_file *m, void *unused) return 0; } +static int gen6_drpc_info(struct seq_file *m) +{ + + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 rpmodectl1, gt_core_status, rcctl1; + int count=0, ret; + + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + if (atomic_read(&dev_priv->forcewake_count)) { + seq_printf(m, "RC information inaccurate because userspace " + "holds a reference \n"); + } else { + /* NB: we cannot use forcewake, else we read the wrong values */ + while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1)) + udelay(10); + seq_printf(m, "RC information accurate: %s\n", yesno(count < 51)); + } + + gt_core_status = readl(dev_priv->regs + GEN6_GT_CORE_STATUS); + trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4); + + rpmodectl1 = I915_READ(GEN6_RP_CONTROL); + rcctl1 = I915_READ(GEN6_RC_CONTROL); + mutex_unlock(&dev->struct_mutex); + + seq_printf(m, "Video Turbo Mode: %s\n", + yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); + seq_printf(m, "HW control enabled: %s\n", + yesno(rpmodectl1 & GEN6_RP_ENABLE)); + seq_printf(m, "SW control enabled: %s\n", + yesno((rpmodectl1 & GEN6_RP_MEDIA_MODE_MASK) == + GEN6_RP_MEDIA_SW_MODE)); + seq_printf(m, "RC6 Enabled: %s\n", + yesno(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE)); + seq_printf(m, "RC6 Enabled: %s\n", + yesno(rcctl1 & GEN6_RC_CTL_RC6_ENABLE)); + seq_printf(m, "Deep RC6 Enabled: %s\n", + yesno(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE)); + seq_printf(m, "Deepest RC6 Enabled: %s\n", + yesno(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE)); + seq_printf(m, "Current RC state: "); + switch (gt_core_status & GEN6_RCn_MASK) { + case GEN6_RC0: + if (gt_core_status & GEN6_CORE_CPD_STATE_MASK) + seq_printf(m, "Core Power Down\n"); + else + seq_printf(m, "on\n"); + break; + case GEN6_RC3: + seq_printf(m, "RC3\n"); + break; + case GEN6_RC6: + seq_printf(m, "RC6\n"); + break; + case GEN6_RC7: + seq_printf(m, "RC7\n"); + break; + default: + seq_printf(m, "Unknown\n"); + break; + } + + seq_printf(m, "Core Power Down: %s\n", + yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK)); + return 0; +} + +static int i915_drpc_info(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + + if (IS_GEN6(dev) || IS_GEN7(dev)) + return gen6_drpc_info(m); + else + return ironlake_drpc_info(m); +} + static int i915_fbc_status(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 583e8c7..44eabb0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3563,6 +3563,14 @@ #define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 +#define GEN6_GT_CORE_STATUS 0x138060 +#define GEN6_CORE_CPD_STATE_MASK (7<<4) +#define GEN6_RCn_MASK 7 +#define GEN6_RC0 0 +#define GEN6_RC3 2 +#define GEN6_RC6 3 +#define GEN6_RC7 4 + #define G4X_AUD_VID_DID 0x62020 #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 -- cgit v1.1 From c7dffff7cc8de748edf0e9f6571cdabecb198705 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 9 Dec 2011 11:33:00 -0800 Subject: drm/i915: Clean up multi-threaded forcewake patch We learned that the ECOBUS register was inside the GT power well, and so *did* need force wake to be read, so it gets removed from the list of 'doesn't need force wake' registers. That means the code reading ECOBUS after forcing the mt_force_wake function to be called needs to use I915_READ_NOTRACE; it doesn't need to do more force wake fun as it's already done it manually. This also adds a comment explaining why the MT forcewake testing code only needs to call mt_forcewake_get/put and not disable RC6 manually -- the ECOBUS read will return 0 if the device is in RC6 and isn't using MT forcewake, causing the test to work correctly. Signed-off-by: Keith Packard Cc: Jesse Barnes --- drivers/gpu/drm/i915/i915_drv.c | 7 ------- drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/intel_display.c | 8 +++++++- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 22c8ab7..8f71879 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -923,13 +923,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL and additional rights"); -/* We give fast paths for the really cool registers */ -#define NEEDS_FORCE_WAKE(dev_priv, reg) \ - (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE) && \ - ((reg) != ECOBUS)) - #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 505af3f..621840c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1364,8 +1364,7 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); #define NEEDS_FORCE_WAKE(dev_priv, reg) \ (((dev_priv)->info->gen >= 6) && \ ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE) && \ - ((reg) != ECOBUS)) + ((reg) != FORCEWAKE)) #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cb21d5b..ff99fa2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8591,9 +8591,15 @@ static void intel_init_display(struct drm_device *dev) if (IS_IVYBRIDGE(dev)) { u32 ecobus; + /* A small trick here - if the bios hasn't configured MT forcewake, + * and if the device is in RC6, then force_wake_mt_get will not wake + * the device and the ECOBUS read will return zero. Which will be + * (correctly) interpreted by the test below as MT forcewake being + * disabled. + */ mutex_lock(&dev->struct_mutex); __gen6_gt_force_wake_mt_get(dev_priv); - ecobus = I915_READ(ECOBUS); + ecobus = I915_READ_NOTRACE(ECOBUS); __gen6_gt_force_wake_mt_put(dev_priv); mutex_unlock(&dev->struct_mutex); -- cgit v1.1 From b840d907fcf6d5d5ef91af4518b3dab3a5da0f75 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 13 Dec 2011 13:19:38 -0800 Subject: drm/i915: add SNB and IVB video sprite support v6 The video sprites support various video surface formats natively and can handle scaling as well. So add support for them using the new DRM core sprite support functions. v2: use drm specific fourcc header and defines v3: address Daniel's comments: - don't take struct mutex around register access (only needed for regs in the GT power well) - don't hold struct mutex across vblank waits - fix up update_plane API (pass obj instead of GTT offset) - add interlaced defines for sprite regs - drop unnecessary 'reg' variables - comment double buffered reg flushing Also fix w/h confusion when writing the scaling reg. v4: more fixes, address more comments from Daniel, and include Hai's fix - prevent divide by zero in scaling calculation (Hai Lan) - update to Ville's new DRM_FORMAT_* types - fix sprite watermark handling (calc based on CRTC size, separate from normal display wm) - remove private refcounts now that the fb cleanups handles things v5: add linear surface support v6: remove color key clearing & setting from update_plane For this version, I tested DPMS since it came up in the last review; DPMS off/on works ok when a video player is working under X, but for power saving we'll probably want to do something smarter. I'll leave that for a separate patch on top. Likewise with the refcounting/fb layer handling, which are really separate cleanups. Reviewed-by: Daniel Vetter Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/i915_reg.h | 133 +++++++++++ drivers/gpu/drm/i915/intel_display.c | 174 +++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 28 +++ drivers/gpu/drm/i915/intel_fb.c | 6 + drivers/gpu/drm/i915/intel_sprite.c | 450 +++++++++++++++++++++++++++++++++++ 7 files changed, 788 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_sprite.c (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0ae6a7c..808b255 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -28,6 +28,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_dvo.o \ intel_ringbuffer.o \ intel_overlay.o \ + intel_sprite.o \ intel_opregion.o \ dvo_ch7xxx.o \ dvo_ch7017.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 621840c..602bc80 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -207,6 +207,8 @@ struct drm_i915_display_funcs { int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); void (*update_wm)(struct drm_device *dev); + void (*update_sprite_wm)(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size); int (*crtc_mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -352,6 +354,7 @@ typedef struct drm_i915_private { /* overlay */ struct intel_overlay *overlay; + bool sprite_scaling_enabled; /* LVDS info */ int backlight_level; /* restore backlight to this value */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 44eabb0..d791043 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2461,6 +2461,8 @@ #define WM3_LP_ILK 0x45110 #define WM3_LP_EN (1<<31) #define WM1S_LP_ILK 0x45120 +#define WM2S_LP_IVB 0x45124 +#define WM3S_LP_IVB 0x45128 #define WM1S_LP_EN (1<<31) /* Memory latency timer register */ @@ -2677,6 +2679,137 @@ #define _DSPBSURF 0x7119C #define _DSPBTILEOFF 0x711A4 +/* Sprite A control */ +#define _DVSACNTR 0x72180 +#define DVS_ENABLE (1<<31) +#define DVS_GAMMA_ENABLE (1<<30) +#define DVS_PIXFORMAT_MASK (3<<25) +#define DVS_FORMAT_YUV422 (0<<25) +#define DVS_FORMAT_RGBX101010 (1<<25) +#define DVS_FORMAT_RGBX888 (2<<25) +#define DVS_FORMAT_RGBX161616 (3<<25) +#define DVS_SOURCE_KEY (1<<22) +#define DVS_RGB_ORDER_RGBX (1<<20) +#define DVS_YUV_BYTE_ORDER_MASK (3<<16) +#define DVS_YUV_ORDER_YUYV (0<<16) +#define DVS_YUV_ORDER_UYVY (1<<16) +#define DVS_YUV_ORDER_YVYU (2<<16) +#define DVS_YUV_ORDER_VYUY (3<<16) +#define DVS_DEST_KEY (1<<2) +#define DVS_TRICKLE_FEED_DISABLE (1<<14) +#define DVS_TILED (1<<10) +#define _DVSALINOFF 0x72184 +#define _DVSASTRIDE 0x72188 +#define _DVSAPOS 0x7218c +#define _DVSASIZE 0x72190 +#define _DVSAKEYVAL 0x72194 +#define _DVSAKEYMSK 0x72198 +#define _DVSASURF 0x7219c +#define _DVSAKEYMAXVAL 0x721a0 +#define _DVSATILEOFF 0x721a4 +#define _DVSASURFLIVE 0x721ac +#define _DVSASCALE 0x72204 +#define DVS_SCALE_ENABLE (1<<31) +#define DVS_FILTER_MASK (3<<29) +#define DVS_FILTER_MEDIUM (0<<29) +#define DVS_FILTER_ENHANCING (1<<29) +#define DVS_FILTER_SOFTENING (2<<29) +#define DVS_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */ +#define DVS_VERTICAL_OFFSET_ENABLE (1<<27) +#define _DVSAGAMC 0x72300 + +#define _DVSBCNTR 0x73180 +#define _DVSBLINOFF 0x73184 +#define _DVSBSTRIDE 0x73188 +#define _DVSBPOS 0x7318c +#define _DVSBSIZE 0x73190 +#define _DVSBKEYVAL 0x73194 +#define _DVSBKEYMSK 0x73198 +#define _DVSBSURF 0x7319c +#define _DVSBKEYMAXVAL 0x731a0 +#define _DVSBTILEOFF 0x731a4 +#define _DVSBSURFLIVE 0x731ac +#define _DVSBSCALE 0x73204 +#define _DVSBGAMC 0x73300 + +#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR) +#define DVSLINOFF(pipe) _PIPE(pipe, _DVSALINOFF, _DVSBLINOFF) +#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE) +#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS) +#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF) +#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE) +#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE) +#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF) + +#define _SPRA_CTL 0x70280 +#define SPRITE_ENABLE (1<<31) +#define SPRITE_GAMMA_ENABLE (1<<30) +#define SPRITE_PIXFORMAT_MASK (7<<25) +#define SPRITE_FORMAT_YUV422 (0<<25) +#define SPRITE_FORMAT_RGBX101010 (1<<25) +#define SPRITE_FORMAT_RGBX888 (2<<25) +#define SPRITE_FORMAT_RGBX161616 (3<<25) +#define SPRITE_FORMAT_YUV444 (4<<25) +#define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ +#define SPRITE_CSC_ENABLE (1<<24) +#define SPRITE_SOURCE_KEY (1<<22) +#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ +#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) +#define SPRITE_YUV_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */ +#define SPRITE_YUV_BYTE_ORDER_MASK (3<<16) +#define SPRITE_YUV_ORDER_YUYV (0<<16) +#define SPRITE_YUV_ORDER_UYVY (1<<16) +#define SPRITE_YUV_ORDER_YVYU (2<<16) +#define SPRITE_YUV_ORDER_VYUY (3<<16) +#define SPRITE_TRICKLE_FEED_DISABLE (1<<14) +#define SPRITE_INT_GAMMA_ENABLE (1<<13) +#define SPRITE_TILED (1<<10) +#define SPRITE_DEST_KEY (1<<2) +#define _SPRA_LINOFF 0x70284 +#define _SPRA_STRIDE 0x70288 +#define _SPRA_POS 0x7028c +#define _SPRA_SIZE 0x70290 +#define _SPRA_KEYVAL 0x70294 +#define _SPRA_KEYMSK 0x70298 +#define _SPRA_SURF 0x7029c +#define _SPRA_KEYMAX 0x702a0 +#define _SPRA_TILEOFF 0x702a4 +#define _SPRA_SCALE 0x70304 +#define SPRITE_SCALE_ENABLE (1<<31) +#define SPRITE_FILTER_MASK (3<<29) +#define SPRITE_FILTER_MEDIUM (0<<29) +#define SPRITE_FILTER_ENHANCING (1<<29) +#define SPRITE_FILTER_SOFTENING (2<<29) +#define SPRITE_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */ +#define SPRITE_VERTICAL_OFFSET_ENABLE (1<<27) +#define _SPRA_GAMC 0x70400 + +#define _SPRB_CTL 0x71280 +#define _SPRB_LINOFF 0x71284 +#define _SPRB_STRIDE 0x71288 +#define _SPRB_POS 0x7128c +#define _SPRB_SIZE 0x71290 +#define _SPRB_KEYVAL 0x71294 +#define _SPRB_KEYMSK 0x71298 +#define _SPRB_SURF 0x7129c +#define _SPRB_KEYMAX 0x712a0 +#define _SPRB_TILEOFF 0x712a4 +#define _SPRB_SCALE 0x71304 +#define _SPRB_GAMC 0x71400 + +#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL) +#define SPRLINOFF(pipe) _PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF) +#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE) +#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS) +#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE) +#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL) +#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK) +#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF) +#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX) +#define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF) +#define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE) +#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) + /* VBIOS regs */ #define VGACNTRL 0x71400 # define VGA_DISP_DISABLE (1 << 31) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ff99fa2..30397b7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -915,8 +915,8 @@ static void assert_panel_unlocked(struct drm_i915_private *dev_priv, pipe_name(pipe)); } -static void assert_pipe(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) +void assert_pipe(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) { int reg; u32 val; @@ -929,8 +929,6 @@ static void assert_pipe(struct drm_i915_private *dev_priv, "pipe %c assertion failure (expected %s, current %s)\n", pipe_name(pipe), state_string(state), state_string(cur_state)); } -#define assert_pipe_enabled(d, p) assert_pipe(d, p, true) -#define assert_pipe_disabled(d, p) assert_pipe(d, p, false) static void assert_plane_enabled(struct drm_i915_private *dev_priv, enum plane plane) @@ -4509,7 +4507,7 @@ static void ironlake_update_wm(struct drm_device *dev) */ } -static void sandybridge_update_wm(struct drm_device *dev) +void sandybridge_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ @@ -4569,7 +4567,8 @@ static void sandybridge_update_wm(struct drm_device *dev) I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); - if (!single_plane_enabled(enabled)) + if (!single_plane_enabled(enabled) || + dev_priv->sprite_scaling_enabled) return; enabled = ffs(enabled) - 1; @@ -4619,6 +4618,149 @@ static void sandybridge_update_wm(struct drm_device *dev) cursor_wm); } +static bool +sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, + uint32_t sprite_width, int pixel_size, + const struct intel_watermark_params *display, + int display_latency_ns, int *sprite_wm) +{ + struct drm_crtc *crtc; + int clock; + int entries, tlb_miss; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) { + *sprite_wm = display->guard_size; + return false; + } + + clock = crtc->mode.clock; + + /* Use the small buffer method to calculate the sprite watermark */ + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - + sprite_width * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *sprite_wm = entries + display->guard_size; + if (*sprite_wm > (int)display->max_wm) + *sprite_wm = display->max_wm; + + return true; +} + +static bool +sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, + uint32_t sprite_width, int pixel_size, + const struct intel_watermark_params *display, + int latency_ns, int *sprite_wm) +{ + struct drm_crtc *crtc; + unsigned long line_time_us; + int clock; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *sprite_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + clock = crtc->mode.clock; + + line_time_us = (sprite_width * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = sprite_width * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *sprite_wm = entries + display->guard_size; + + return *sprite_wm > 0x3ff ? false : true; +} + +static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ + int sprite_wm, reg; + int ret; + + switch (pipe) { + case 0: + reg = WM0_PIPEA_ILK; + break; + case 1: + reg = WM0_PIPEB_ILK; + break; + case 2: + reg = WM0_PIPEC_IVB; + break; + default: + return; /* bad pipe */ + } + + ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, + &sandybridge_display_wm_info, + latency, &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n", + pipe); + return; + } + + I915_WRITE(reg, I915_READ(reg) | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); + DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm); + + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM1_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM1S_LP_ILK, sprite_wm); + + /* Only IVB has two more LP watermarks for sprite */ + if (!IS_IVYBRIDGE(dev)) + return; + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM2_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM2S_LP_IVB, sprite_wm); + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM3_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM3S_LP_IVB, sprite_wm); +} + /** * intel_update_watermarks - update FIFO watermark values based on current modes * @@ -4659,6 +4801,16 @@ static void intel_update_watermarks(struct drm_device *dev) dev_priv->display.update_wm(dev); } +void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.update_sprite_wm) + dev_priv->display.update_sprite_wm(dev, pipe, sprite_width, + pixel_size); +} + static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { if (i915_panel_use_ssc >= 0) @@ -8631,6 +8783,7 @@ static void intel_init_display(struct drm_device *dev) } else if (IS_GEN6(dev)) { if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); @@ -8644,6 +8797,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); @@ -8827,7 +8981,7 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; + int i, ret; drm_mode_config_init(dev); @@ -8857,6 +9011,12 @@ void intel_modeset_init(struct drm_device *dev) for (i = 0; i < dev_priv->num_pipe; i++) { intel_crtc_init(dev, i); + if (HAS_PCH_SPLIT(dev)) { + ret = intel_plane_init(dev, i); + if (ret) + DRM_ERROR("plane %d init failed: %d\n", + i, ret); + } } /* Just disable it once at startup */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 82a459b..a6e2f0d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -177,10 +177,27 @@ struct intel_crtc { bool use_pll_a; }; +struct intel_plane { + struct drm_plane base; + enum pipe pipe; + struct drm_i915_gem_object *obj; + int max_downscale; + u32 lut_r[1024], lut_g[1024], lut_b[1024]; + void (*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, + uint32_t src_w, uint32_t src_h); + void (*disable_plane)(struct drm_plane *plane); +}; + #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_connector(x) container_of(x, struct intel_connector, base) #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) +#define to_intel_plane(x) container_of(x, struct intel_plane, base) #define DIP_HEADER_SIZE 5 @@ -290,6 +307,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config(struct intel_encoder *, int *, int *); extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); +extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); /* intel_panel.c */ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, @@ -380,9 +398,19 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, extern void intel_fb_output_poll_changed(struct drm_device *dev); extern void intel_fb_restore_mode(struct drm_device *dev); +extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, + bool state); +#define assert_pipe_enabled(d, p) assert_pipe(d, p, true) +#define assert_pipe_disabled(d, p) assert_pipe(d, p, false) + extern void intel_init_clock_gating(struct drm_device *dev); extern void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); +/* For use by IVB LP watermark workaround in intel_sprite.c */ +extern void sandybridge_update_wm(struct drm_device *dev); +extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, + uint32_t sprite_width, + int pixel_size); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index f02fc71..571375a 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -270,8 +270,14 @@ void intel_fb_restore_mode(struct drm_device *dev) { int ret; drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_mode_config *config = &dev->mode_config; + struct drm_plane *plane; ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); if (ret) DRM_DEBUG("failed to restore crtc mode\n"); + + /* Be sure to shut off any planes that may be active */ + list_for_each_entry(plane, &config->plane_list, head) + plane->funcs->disable_plane(plane); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c new file mode 100644 index 0000000..c77717d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -0,0 +1,450 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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. + * + * Authors: + * Jesse Barnes + * + * New plane/sprite handling. + * + * 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. + */ +#include "drmP.h" +#include "drm_crtc.h" +#include "drm_fourcc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +static void +ivb_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, + uint32_t src_w, uint32_t src_h) +{ + 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; + u32 sprctl, sprscale = 0; + int pixel_size; + + sprctl = I915_READ(SPRCTL(pipe)); + + /* Mask out pixel format bits in case we change it */ + sprctl &= ~SPRITE_PIXFORMAT_MASK; + sprctl &= ~SPRITE_RGB_ORDER_RGBX; + sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; + + switch (fb->pixel_format) { + case DRM_FORMAT_XBGR8888: + sprctl |= SPRITE_FORMAT_RGBX888; + pixel_size = 4; + break; + case DRM_FORMAT_XRGB8888: + sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; + pixel_size = 4; + 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; + } + + if (obj->tiling_mode != I915_TILING_NONE) + sprctl |= SPRITE_TILED; + + /* must disable */ + sprctl |= SPRITE_TRICKLE_FEED_DISABLE; + sprctl |= SPRITE_ENABLE; + + /* Sizes are 0 based */ + src_w--; + src_h--; + crtc_w--; + crtc_h--; + + intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * 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); + 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); + } + + I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); + I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); + if (obj->tiling_mode != I915_TILING_NONE) { + I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); + } else { + unsigned long 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); + I915_WRITE(SPRCTL(pipe), sprctl); + I915_WRITE(SPRSURF(pipe), obj->gtt_offset); + POSTING_READ(SPRSURF(pipe)); +} + +static void +ivb_disable_plane(struct drm_plane *plane) +{ + 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; + + I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); + /* Can't leave the scaler enabled... */ + I915_WRITE(SPRSCALE(pipe), 0); + /* Activate double buffered register update */ + I915_WRITE(SPRSURF(pipe), 0); + POSTING_READ(SPRSURF(pipe)); +} + +static void +snb_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, + uint32_t src_w, uint32_t src_h) +{ + 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; + + dvscntr = I915_READ(DVSCNTR(pipe)); + + /* Mask out pixel format bits in case we change it */ + dvscntr &= ~DVS_PIXFORMAT_MASK; + dvscntr &= ~DVS_RGB_ORDER_RGBX; + dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; + + switch (fb->pixel_format) { + case DRM_FORMAT_XBGR8888: + dvscntr |= DVS_FORMAT_RGBX888; + pixel_size = 4; + break; + case DRM_FORMAT_XRGB8888: + dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX; + 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; + } + + if (obj->tiling_mode != I915_TILING_NONE) + dvscntr |= DVS_TILED; + + /* must disable */ + dvscntr |= DVS_TRICKLE_FEED_DISABLE; + dvscntr |= DVS_ENABLE; + + /* Sizes are 0 based */ + src_w--; + src_h--; + crtc_w--; + crtc_h--; + + intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + + if (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) { + I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); + } else { + unsigned long 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); + POSTING_READ(DVSSURF(pipe)); +} + +static void +snb_disable_plane(struct drm_plane *plane) +{ + 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; + + I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); + /* Disable the scaler */ + I915_WRITE(DVSSCALE(pipe), 0); + /* Flush double buffered register updates */ + I915_WRITE(DVSSURF(pipe), 0); + POSTING_READ(DVSSURF(pipe)); +} + +static int +intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj, *old_obj; + int pipe = intel_plane->pipe; + int ret = 0; + int x = src_x >> 16, y = src_y >> 16; + int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; + bool disable_primary = false; + + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + + old_obj = intel_plane->obj; + + /* Pipe must be running... */ + if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) + return -EINVAL; + + if (crtc_x >= primary_w || crtc_y >= primary_h) + return -EINVAL; + + /* Don't modify another pipe's plane */ + if (intel_plane->pipe != intel_crtc->pipe) + 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. + * The caller must handle that by adjusting source offset and size. + */ + if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { + crtc_w += crtc_x; + crtc_x = 0; + } + if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ + goto out; + if ((crtc_x + crtc_w) > primary_w) + crtc_w = primary_w - crtc_x; + + if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { + crtc_h += crtc_y; + crtc_y = 0; + } + if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ + goto out; + if (crtc_y + crtc_h > primary_h) + crtc_h = primary_h - crtc_y; + + if (!crtc_w || !crtc_h) /* Again, nothing to display */ + goto out; + + /* + * We can take a larger source and scale it down, but + * only so much... 16x is the max on SNB. + */ + if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) + return -EINVAL; + + /* + * If the sprite is completely covering the primary plane, + * we can disable the primary and save power. + */ + if ((crtc_x == 0) && (crtc_y == 0) && + (crtc_w == primary_w) && (crtc_h == primary_h)) + disable_primary = true; + + mutex_lock(&dev->struct_mutex); + + ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); + if (ret) { + DRM_ERROR("failed to pin object\n"); + goto out_unlock; + } + + intel_plane->obj = obj; + + intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, + crtc_w, crtc_h, x, y, src_w, src_h); + + /* Unpin old obj after new one is active to avoid ugliness */ + if (old_obj) { + /* + * It's fairly common to simply update the position of + * an existing object. In that case, we don't need to + * wait for vblank to avoid ugliness, we only need to + * do the pin & ref bookkeeping. + */ + if (old_obj != obj) { + mutex_unlock(&dev->struct_mutex); + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); + mutex_lock(&dev->struct_mutex); + } + i915_gem_object_unpin(old_obj); + } + +out_unlock: + mutex_unlock(&dev->struct_mutex); +out: + return ret; +} + +static int +intel_disable_plane(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + struct intel_plane *intel_plane = to_intel_plane(plane); + int ret = 0; + + intel_plane->disable_plane(plane); + + if (!intel_plane->obj) + goto out; + + mutex_lock(&dev->struct_mutex); + i915_gem_object_unpin(intel_plane->obj); + intel_plane->obj = NULL; + mutex_unlock(&dev->struct_mutex); +out: + + return ret; +} + +static void intel_destroy_plane(struct drm_plane *plane) +{ + struct intel_plane *intel_plane = to_intel_plane(plane); + intel_disable_plane(plane); + drm_plane_cleanup(plane); + kfree(intel_plane); +} + +static const struct drm_plane_funcs intel_plane_funcs = { + .update_plane = intel_update_plane, + .disable_plane = intel_disable_plane, + .destroy = intel_destroy_plane, +}; + +static uint32_t snb_plane_formats[] = { + DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, +}; + +int +intel_plane_init(struct drm_device *dev, enum pipe pipe) +{ + struct intel_plane *intel_plane; + unsigned long possible_crtcs; + int ret; + + if (!(IS_GEN6(dev) || IS_GEN7(dev))) { + DRM_ERROR("new plane code only for SNB+\n"); + return -ENODEV; + } + + intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL); + if (!intel_plane) + return -ENOMEM; + + if (IS_GEN6(dev)) { + intel_plane->max_downscale = 16; + intel_plane->update_plane = snb_update_plane; + intel_plane->disable_plane = snb_disable_plane; + } else if (IS_GEN7(dev)) { + intel_plane->max_downscale = 2; + intel_plane->update_plane = ivb_update_plane; + intel_plane->disable_plane = ivb_disable_plane; + } + + intel_plane->pipe = pipe; + possible_crtcs = (1 << pipe); + ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, + &intel_plane_funcs, snb_plane_formats, + ARRAY_SIZE(snb_plane_formats)); + if (ret) + kfree(intel_plane); + + return ret; +} + -- cgit v1.1 From 175bd4204e069f8bd855ca3dcf70a78db4410936 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 13 Dec 2011 13:19:39 -0800 Subject: drm/i915: track sprite coverage and disable primary plane if possible To save power when the sprite is full screen, we can disable the primary plane on the same pipe. Track the sprite status and enable/disable the primary opportunistically. v2: remove primary plane enable/disable hooks; they're identical Reviewed-by: Daniel Vetter Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a6e2f0d..ed65121 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -181,6 +181,7 @@ struct intel_plane { struct drm_plane base; enum pipe pipe; struct drm_i915_gem_object *obj; + bool primary_disabled; int max_downscale; u32 lut_r[1024], lut_g[1024], lut_b[1024]; void (*update_plane)(struct drm_plane *plane, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index c77717d..6994e06 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -256,6 +256,28 @@ snb_disable_plane(struct drm_plane *plane) POSTING_READ(DVSSURF(pipe)); } +static void +intel_enable_primary(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int reg = DSPCNTR(intel_crtc->plane); + + I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); +} + +static void +intel_disable_primary(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int reg = DSPCNTR(intel_crtc->plane); + + I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); +} + static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -342,9 +364,23 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, intel_plane->obj = obj; + /* + * Be sure to re-enable the primary before the sprite is no longer + * covering it fully. + */ + if (!disable_primary && intel_plane->primary_disabled) { + 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) { + intel_disable_primary(crtc); + intel_plane->primary_disabled = true; + } + /* Unpin old obj after new one is active to avoid ugliness */ if (old_obj) { /* @@ -374,6 +410,11 @@ intel_disable_plane(struct drm_plane *plane) struct intel_plane *intel_plane = to_intel_plane(plane); int ret = 0; + if (intel_plane->primary_disabled) { + intel_enable_primary(plane->crtc); + intel_plane->primary_disabled = false; + } + intel_plane->disable_plane(plane); if (!intel_plane->obj) -- cgit v1.1 From 8ea30864229e54b01ac0e9fe88c4b733a940ec4e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 3 Jan 2012 08:05:39 -0800 Subject: drm/i915: add color key support v4 Add new ioctls for getting and setting the current destination color key. This allows for simple overlay display control by matching a color key value in the primary plane before blending the overlay on top. v2: remove unnecessary mutex acquire/release around reg accesses v3: add support for full color key management v4: fix copy & paste bug in snb_get_colorkey don't bother checking min/max values against docs as the docs are likely wrong (how could we handle 10bpc surface formats?) Reviewed-by: Daniel Vetter Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_dma.c | 2 + drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_drv.h | 11 +++ drivers/gpu/drm/i915/intel_sprite.c | 177 ++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a9ae374..77dace6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2305,6 +2305,8 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d791043..eb44432 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2737,9 +2737,12 @@ #define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE) #define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS) #define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF) +#define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL) #define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE) #define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE) #define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF) +#define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL) +#define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK) #define _SPRA_CTL 0x70280 #define SPRITE_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ed65121..5ac8a16 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -26,6 +26,7 @@ #define __INTEL_DRV_H__ #include +#include "i915_drm.h" #include "i915_drv.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" @@ -192,6 +193,10 @@ struct intel_plane { uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h); void (*disable_plane)(struct drm_plane *plane); + int (*update_colorkey)(struct drm_plane *plane, + struct drm_intel_sprite_colorkey *key); + void (*get_colorkey)(struct drm_plane *plane, + struct drm_intel_sprite_colorkey *key); }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) @@ -414,4 +419,10 @@ extern void sandybridge_update_wm(struct drm_device *dev); extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); + +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, + struct drm_file *file_priv); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 6994e06..b26e7c4 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -95,6 +95,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, /* must disable */ sprctl |= SPRITE_TRICKLE_FEED_DISABLE; sprctl |= SPRITE_ENABLE; + sprctl |= SPRITE_DEST_KEY; /* Sizes are 0 based */ src_w--; @@ -153,6 +154,60 @@ ivb_disable_plane(struct drm_plane *plane) POSTING_READ(SPRSURF(pipe)); } +static int +ivb_update_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; + struct intel_plane *intel_plane; + u32 sprctl; + int ret = 0; + + intel_plane = to_intel_plane(plane); + + I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value); + I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value); + I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask); + + sprctl = I915_READ(SPRCTL(intel_plane->pipe)); + sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY); + if (key->flags & I915_SET_COLORKEY_DESTINATION) + sprctl |= SPRITE_DEST_KEY; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + sprctl |= SPRITE_SOURCE_KEY; + I915_WRITE(SPRCTL(intel_plane->pipe), sprctl); + + POSTING_READ(SPRKEYMSK(intel_plane->pipe)); + + return ret; +} + +static void +ivb_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; + struct intel_plane *intel_plane; + u32 sprctl; + + intel_plane = to_intel_plane(plane); + + key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe)); + key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe)); + key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe)); + key->flags = 0; + + sprctl = I915_READ(SPRCTL(intel_plane->pipe)); + + if (sprctl & SPRITE_DEST_KEY) + key->flags = I915_SET_COLORKEY_DESTINATION; + else if (sprctl & SPRITE_SOURCE_KEY) + key->flags = I915_SET_COLORKEY_SOURCE; + else + key->flags = I915_SET_COLORKEY_NONE; +} + static void snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, @@ -279,6 +334,60 @@ intel_disable_primary(struct drm_crtc *crtc) } static int +snb_update_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; + struct intel_plane *intel_plane; + u32 dvscntr; + int ret = 0; + + intel_plane = to_intel_plane(plane); + + I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value); + I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value); + I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask); + + dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); + dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY); + if (key->flags & I915_SET_COLORKEY_DESTINATION) + dvscntr |= DVS_DEST_KEY; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + dvscntr |= DVS_SOURCE_KEY; + I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr); + + POSTING_READ(DVSKEYMSK(intel_plane->pipe)); + + return ret; +} + +static void +snb_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; + struct intel_plane *intel_plane; + u32 dvscntr; + + intel_plane = to_intel_plane(plane); + + key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe)); + key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe)); + key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe)); + key->flags = 0; + + dvscntr = I915_READ(DVSCNTR(intel_plane->pipe)); + + if (dvscntr & DVS_DEST_KEY) + key->flags = I915_SET_COLORKEY_DESTINATION; + else if (dvscntr & DVS_SOURCE_KEY) + key->flags = I915_SET_COLORKEY_SOURCE; + else + key->flags = I915_SET_COLORKEY_NONE; +} + +static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, @@ -437,6 +546,70 @@ static void intel_destroy_plane(struct drm_plane *plane) kfree(intel_plane); } +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; + + /* 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; + + mutex_lock(&dev->mode_config.mutex); + + obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); + if (!obj) { + ret = -EINVAL; + goto out_unlock; + } + + plane = obj_to_plane(obj); + intel_plane = to_intel_plane(plane); + ret = intel_plane->update_colorkey(plane, set); + +out_unlock: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +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; + + mutex_lock(&dev->mode_config.mutex); + + obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); + if (!obj) { + ret = -EINVAL; + goto out_unlock; + } + + plane = obj_to_plane(obj); + intel_plane = to_intel_plane(plane); + intel_plane->get_colorkey(plane, get); + +out_unlock: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + static const struct drm_plane_funcs intel_plane_funcs = { .update_plane = intel_update_plane, .disable_plane = intel_disable_plane, @@ -472,10 +645,14 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) 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->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; } intel_plane->pipe = pipe; -- cgit v1.1 From 116ac8d26101c06ad80a4e1cb560db1c525397f8 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 21 Dec 2011 10:31:09 -0800 Subject: drm/i915: Set two chicken bits implicated in missed IRQs on Ivybridge. They don't fix our problems alone, but we're told to set them. Signed-off-by: Eric Anholt Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index eb44432..edced95 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3020,6 +3020,10 @@ #define ILK_DPFC_DIS1 (1<<8) #define ILK_DPFC_DIS2 (1<<9) +#define IVB_CHICKEN3 0x4200c +# define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5) +# define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) + #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 30397b7..2e00c8a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8450,6 +8450,10 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + I915_WRITE(IVB_CHICKEN3, + CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | + CHICKEN3_DGMG_DONE_FIX_DISABLE); + for_each_pipe(pipe) { I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | -- cgit v1.1 From 7ea29b13e5e3e1e61e612349eb0366efdb6457f3 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 22 Dec 2011 14:54:59 -0800 Subject: drm/i915: Do the fallback non-IRQ wait in ring throttle, too. As a workaround for IRQ synchronization issues in the gen7 BLT ring, we want to turn the two wait functions into polling loops. Signed-off-by: Eric Anholt Tested-by: Eugeni Dodonov Reviewed-by: Eugeni Dodonov Acked-by: Kenneth Graunke Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_gem.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8359dc7..66e0a55 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3309,6 +3309,10 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) ret = -EIO; + } else if (wait_for(i915_seqno_passed(ring->get_seqno(ring), + seqno) || + atomic_read(&dev_priv->mm.wedged), 3000)) { + ret = -EBUSY; } } -- cgit v1.1 From 42ff6572e5a4a7414330a4ca91f0335da67deca9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 22 Dec 2011 14:55:00 -0800 Subject: drm/i915: Work around gen7 BLT ring synchronization issues. Previous to this commit, testing easily reproduced a failure where the seqno would apparently arrive after the IRQ associated with it, with test programs as simple as: for (;;) { glCopyPixels(0, 0, 1, 1); glFinish(); } Various workarounds we've seen for previous generations didn't work to fix this issue, so until new information comes in, replace the IRQ waits on the BLT ring with polling. Signed-off-by: Eric Anholt Tested-by: Eugeni Dodonov Reviewed-by: Eugeni Dodonov Acked-by: Kenneth Graunke Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_ringbuffer.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f5dae5de..d0eb228 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -792,6 +792,17 @@ ring_add_request(struct intel_ring_buffer *ring, } static bool +gen7_blt_ring_get_irq(struct intel_ring_buffer *ring) +{ + /* The BLT ring on IVB appears to have broken synchronization + * between the seqno write and the interrupt, so that the + * interrupt appears first. Returning false here makes + * i915_wait_request() do a polling loop, instead. + */ + return false; +} + +static bool gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) { struct drm_device *dev = ring->dev; @@ -1557,5 +1568,8 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) *ring = gen6_blt_ring; + if (IS_GEN7(dev)) + ring->irq_get = gen7_blt_ring_get_irq; + return intel_init_ring_buffer(dev, ring); } -- cgit v1.1 From e959b5db4aacc27bcf92889e658445326ebc4bfb Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 22 Dec 2011 14:55:01 -0800 Subject: drm/i915: Make the fallback IRQ wait not sleep. The waits we do here are generally so short that sleeping is a bad idea unless we have an IRQ to wake us up. Improves regression test performance from 18 minutes to 3.5 minutes on gen7, which is now consistent with the previous generation. Signed-off-by: Eric Anholt Tested-by: Eugeni Dodonov Reviewed-by: Eugeni Dodonov Acked-by: Kenneth Graunke Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 66e0a55..e55badb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2006,9 +2006,9 @@ i915_wait_request(struct intel_ring_buffer *ring, || atomic_read(&dev_priv->mm.wedged)); ring->irq_put(ring); - } else if (wait_for(i915_seqno_passed(ring->get_seqno(ring), - seqno) || - atomic_read(&dev_priv->mm.wedged), 3000)) + } else if (wait_for_atomic(i915_seqno_passed(ring->get_seqno(ring), + seqno) || + atomic_read(&dev_priv->mm.wedged), 3000)) ret = -EBUSY; ring->waiting_seqno = 0; @@ -3309,8 +3309,8 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) ret = -EIO; - } else if (wait_for(i915_seqno_passed(ring->get_seqno(ring), - seqno) || + } else if (wait_for_atomic(i915_seqno_passed(ring->get_seqno(ring), + seqno) || atomic_read(&dev_priv->mm.wedged), 3000)) { ret = -EBUSY; } -- cgit v1.1 From ae662d31264979e52581bd2573bf0b82812f52ab Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 3 Jan 2012 09:23:29 -0800 Subject: drm/i915: Add support for resetting the SO write pointers on gen7. These registers are automatically incremented by the hardware during transform feedback to track where the next streamed vertex output should go. Unlike the previous generation, which had a packet for setting the corresponding registers to a defined value, gen7 only has MI_LOAD_REGISTER_IMM to do so. That's a secure packet (since it loads an arbitrary register), so we need to do it from the kernel, and it needs to be settable atomically with the batchbuffer execution so that two clients doing transform feedback don't stomp on each others' state. Instead of building a more complicated interface involcing setting the registers to a specific value, just set them to 0 when asked and userland can tweak its pointers accordingly. Signed-off-by: Eric Anholt Reviewed-by: Eugeni Dodonov Reviewed-by: Kenneth Graunke Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 31 ++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ 3 files changed, 40 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 77dace6..5f4d589 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -781,6 +781,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_RELAXED_DELTA: value = 1; break; + case I915_PARAM_HAS_GEN7_SOL_RESET: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 11545ff..c01cb20 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -971,6 +971,31 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, } static int +i915_reset_gen7_sol_offsets(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, i; + + if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS]) + return 0; + + ret = intel_ring_begin(ring, 4 * 3); + if (ret) + return ret; + + for (i = 0; i < 4; i++) { + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, GEN7_SO_WRITE_OFFSET(i)); + intel_ring_emit(ring, 0); + } + + intel_ring_advance(ring); + + return 0; +} + +static int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file, struct drm_i915_gem_execbuffer2 *args, @@ -1184,6 +1209,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev_priv->relative_constants_mode = mode; } + if (args->flags & I915_EXEC_GEN7_SOL_RESET) { + ret = i915_reset_gen7_sol_offsets(dev, ring); + if (ret) + goto err; + } + trace_i915_gem_ring_dispatch(ring, seqno); exec_start = batch_obj->gtt_offset + args->batch_start_offset; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index edced95..c3afb78 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3736,4 +3736,10 @@ #define CPT_AUD_CNTL_ST_A 0xE50B4 #define CPT_AUD_CNTRL_ST2 0xE50C0 +/* These are the 4 32-bit write offset registers for each stream + * output buffer. It determines the offset from the + * 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to. + */ +#define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4) + #endif /* _I915_REG_H_ */ -- cgit v1.1 From 4e0e90dcb8a7df1229c69e30abebb59b0b3c2a1f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 14 Dec 2011 13:56:58 +0100 Subject: drm/i915: kicking rings stuck on semaphores considered harmful If our semaphore logic gets confused and we have a ring stuck waiting for one, there's a decent chance it'll just execute garbage when being kicked. Also, kicking the ring obscures the place where the error first occured, making error_state decoding much harder. So drop this an let gpu reset handle this mess in a clean fashion. In contrast, kicking rings stuck on MI_WAIT is rather harmless, at worst there'll be a bit of screen-flickering. There's also old broken userspace out there which needs this as a work-around. Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/i915_irq.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5849311..5d433fc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1649,13 +1649,6 @@ static bool kick_ring(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, tmp); return true; } - if (IS_GEN6(dev) && - (tmp & RING_WAIT_SEMAPHORE)) { - DRM_ERROR("Kicking stuck semaphore on %s\n", - ring->name); - I915_WRITE_CTL(ring, tmp); - return true; - } return false; } -- cgit v1.1 From e6bfaf854272ec4641a9ef7b1cb1ca963031ba95 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 14 Dec 2011 13:56:59 +0100 Subject: drm/i915: don't bail out of intel_wait_ring_buffer too early In the pre-gem days with non-existing hangcheck and gpu reset code, this timeout of 3 seconds was pretty important to avoid stuck processes. But now we have the hangcheck code in gem that goes to great length to ensure that the gpu is really dead before declaring it wedged. So there's no need for this timeout anymore. Actually it's even harmful because we can bail out too early (e.g. with xscreensaver slip) when running giant batchbuffers. And our code isn't robust enough to properly unroll any state-changes, we pretty much rely on the gpu reset code cleaning up the mess (like cache tracking, fencing state, active list/request tracking, ...). With this change intel_begin_ring can only fail when the gpu is wedged, and it will return -EAGAIN (like wait_request in case the gpu reset is still outstanding). v2: Chris Wilson noted that on resume timers aren't running and hence we won't ever get kicked out of this loop by the hangcheck code. Use an insanely large timeout instead for the HAS_GEM case to prevent resume bugs from totally hanging the machine. Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Acked-by: Ben Widawsky Reviewed-by: Eugeni Dodonov Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_ringbuffer.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d0eb228..77e729d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1135,7 +1135,16 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) } trace_i915_ring_wait_begin(ring); - end = jiffies + 3 * HZ; + if (drm_core_check_feature(dev, DRIVER_GEM)) + /* With GEM the hangcheck timer should kick us out of the loop, + * leaving it early runs the risk of corrupting GEM state (due + * to running on almost untested codepaths). But on resume + * timers don't work yet, so prevent a complete hang in that + * case by choosing an insanely large timeout. */ + end = jiffies + 60 * HZ; + else + end = jiffies + 3 * HZ; + do { ring->head = I915_READ_HEAD(ring); ring->space = ring_space(ring); -- cgit v1.1 From 7a4198664d46b87025a64530f1530ab2bea54c19 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 15 Nov 2011 10:28:53 -0800 Subject: drm/i915: don't disable a PCH DPLL that's in use If a PCH pipe PLL is being used by transcoder C, don't disable it. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e00c8a..bdab82b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1204,7 +1204,8 @@ static void intel_disable_pch_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { int reg; - u32 val; + u32 val, pll_mask = TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL, + pll_sel = TRANSC_DPLL_ENABLE; if (pipe > 1) return; @@ -1215,6 +1216,15 @@ static void intel_disable_pch_pll(struct drm_i915_private *dev_priv, /* Make sure transcoder isn't still depending on us */ assert_transcoder_disabled(dev_priv, pipe); + if (pipe == 0) + pll_sel |= TRANSC_DPLLA_SEL; + else if (pipe == 1) + pll_sel |= TRANSC_DPLLB_SEL; + + + if ((I915_READ(PCH_DPLL_SEL) & pll_mask) == pll_sel) + return; + reg = PCH_DPLL(pipe); val = I915_READ(reg); val &= ~DPLL_VCO_ENABLE; -- cgit v1.1 From d8e70a254d8f2da141006e496a51502b79115e80 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 15 Nov 2011 10:28:54 -0800 Subject: drm/i915: only set the intel_crtc DPMS mode to on if the mode set succeeded If it failed, leave it in the "off" state. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bdab82b..29743de 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5984,10 +5984,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, x, y, old_fb); - drm_vblank_post_modeset(dev, pipe); - intel_crtc->dpms_mode = DRM_MODE_DPMS_ON; + if (ret) + intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; + else + intel_crtc->dpms_mode = DRM_MODE_DPMS_ON; return ret; } -- cgit v1.1 From 0a7eb243db7864640134f8c57e6856f8eb3ed7c6 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 13 Dec 2011 20:19:36 -0600 Subject: drm: add support for private planes In cases where the scanout hw is sufficiently similar between "overlay" and traditional crtc layers, it might be convenient to allow the driver to create internal drm_plane helper objects used by the drm_crtc implementation, rather than duplicate code between the plane and crtc. A private plane is not exposed to userspace. Signed-off-by: Rob Clark Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b26e7c4..d13989f 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -659,7 +659,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) possible_crtcs = (1 << pipe); ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, snb_plane_formats, - ARRAY_SIZE(snb_plane_formats)); + ARRAY_SIZE(snb_plane_formats), false); if (ret) kfree(intel_plane); -- cgit v1.1 From cc1f71942944890c7e05fc55dc4427c94b63d4f1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jan 2012 09:55:22 +0000 Subject: drm: introduce drm_can_sleep and use in intel/radeon drivers. (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So we have a few places where the drm drivers would like to sleep to be nice to the system, mainly in the modesetting paths, but we also have two cases were atomic modesetting must take place, panic writing and kernel debugger. So provide a central inline to determine if a sleep or delay should be used and use this in the intel and radeon drivers. v2: drop intel_drv.h MSLEEP macro, nobody uses it. Based on patch from Michel Dänzer Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43941 Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_drv.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5ac8a16..1348705 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -40,7 +40,7 @@ ret__ = -ETIMEDOUT; \ break; \ } \ - if (W && !(in_atomic() || in_dbg_master())) msleep(W); \ + if (W && drm_can_sleep()) msleep(W); \ } \ ret__; \ }) @@ -48,13 +48,6 @@ #define wait_for(COND, MS) _wait_for(COND, MS, 1) #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) -#define MSLEEP(x) do { \ - if (in_dbg_master()) \ - mdelay(x); \ - else \ - msleep(x); \ -} while (0) - #define KHz(x) (1000*x) #define MHz(x) KHz(1000*x) -- cgit v1.1