From a5071c2fd91f320bc40952df59517053a7346fa9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 19 Jul 2011 15:38:56 -0700 Subject: drm/i915: provide more error output when mode sets fail If a mode set fails we may get a message from drm_crtc_helper if we're lucky, but it won't tell us anything about *why* we failed to set a mode. So add a few DRM_ERRORs for the cases that shouldn't happen so we can debug things more easily. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b5b15bd..261ffe4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2096,7 +2096,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG_KMS("No FB bound\n"); + DRM_ERROR("No FB bound\n"); return 0; } @@ -2105,6 +2105,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, case 1: break; default: + DRM_ERROR("no plane for crtc\n"); return -EINVAL; } @@ -2114,6 +2115,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, NULL); if (ret != 0) { mutex_unlock(&dev->struct_mutex); + DRM_ERROR("pin & fence failed\n"); return ret; } @@ -2142,6 +2144,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (ret) { i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); + DRM_ERROR("failed to update base address\n"); return ret; } -- cgit v0.10.2 From f0b69efc29b024747a88ce020dada425e3193d5a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 19 Jul 2011 16:21:40 -0700 Subject: drm/i915: Skip GPU wait for scanout pin while wedged Failing to pin a scanout buffer will most likely lead to a black screen, so if the GPU is wedged, then just let the pin happen and hope that things work out OK. v2: Just ignore any error from i915_gem_object_wait_rendering, as suggested by Chris Wilson Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e9d1d5c..e46f273 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3113,7 +3113,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, if (pipelined != obj->ring) { ret = i915_gem_object_wait_rendering(obj); - if (ret) + if (ret == -ERESTARTSYS) return ret; } -- cgit v0.10.2 From 842d452985300f4ec14c68cb86046e8a1a3b7251 Mon Sep 17 00:00:00 2001 From: Ole Henrik Jahren Date: Fri, 22 Jul 2011 15:56:01 +0200 Subject: drm/i915: Fix typo in DRM_I915_OVERLAY_PUT_IMAGE ioctl define Because of a typo, calling ioctl with DRM_IOCTL_I915_OVERLAY_PUT_IMAGE is broken if the macro is used directly. When using libdrm the bug is not hit, since libdrm handles the ioctl encoding internally. The typo also leads to the .cmd and .cmd_drv fields of the drm_ioctl structure for DRM_I915_OVERLAY_PUT_IMAGE having inconsistent content. Signed-off-by: Ole Henrik Jahren Acked-by: Daniel Vetter Cc: stable@kernel.org Signed-off-by: Keith Packard diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index c4d6dbf..28c0d11 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -237,7 +237,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture) #define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id) #define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise) -#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_ATTRS, struct drm_intel_overlay_put_image) +#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image) #define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) /* Allow drivers to submit batchbuffers directly to hardware, relying -- cgit v0.10.2 From f3234706a77bd6e1592ae71fb3268e04cb030dba Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 22 Jul 2011 10:44:39 -0700 Subject: drm/i915: Initialize RCS ring status page address in intel_render_ring_init_dri Physically-addressed hardware status pages are initialized early in the driver load process by i915_init_phys_hws. For UMS environments, the ring structure is not initialized until the X server starts. At that point, the entire ring structure is re-initialized with all new values. Any values set in the ring structure (including ring->status_page.page_addr) will be lost when the ring is re-initialized. This patch moves the initialization of the status_page.page_addr value to intel_render_ring_init_dri. Signed-off-by: Keith Packard Cc: stable@kernel.org diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 296fbd6..7eef6e1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -61,7 +61,6 @@ static void i915_write_hws_pga(struct drm_device *dev) static int i915_init_phys_hws(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring = LP_RING(dev_priv); /* Program Hardware Status Page */ dev_priv->status_page_dmah = @@ -71,10 +70,9 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - ring->status_page.page_addr = - (void __force __iomem *)dev_priv->status_page_dmah->vaddr; - memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); + memset_io((void __force __iomem *)dev_priv->status_page_dmah->vaddr, + 0, PAGE_SIZE); i915_write_hws_pga(dev); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 95c4b14..1f61fc7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1319,6 +1319,9 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->get_seqno = pc_render_get_seqno; } + if (!I915_NEED_GFX_HWS(dev)) + ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; + ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); -- cgit v0.10.2 From 9c54c0dd948d715ccfd79e97d852f80eeb53254a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 15 Jun 2011 23:32:33 +0200 Subject: drm/i915: load the LUT before pipe enable on ILK+ Per the specs and to address https://bugs.freedesktop.org/show_bug.cgi?id=36888. Signed-off-by: Jesse Barnes Cc: stable@kernel.org Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f1c799..5609c06 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2699,14 +2699,18 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); } + /* + * On ILK+ LUT must be loaded before the pipe is running but with + * clocks enabled + */ + intel_crtc_load_lut(crtc); + intel_enable_pipe(dev_priv, pipe, is_pch_port); intel_enable_plane(dev_priv, plane, pipe); if (is_pch_port) ironlake_pch_enable(crtc); - intel_crtc_load_lut(crtc); - mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); -- cgit v0.10.2 From 97cdd7101079adc3c626d159c62d43de949516c8 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 12 Jul 2011 17:38:00 -0400 Subject: drm/i915/dp: Zero the DPCD data before connection probe Signed-off-by: Adam Jackson Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e2aced6..de24f31 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1673,6 +1673,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct edid *edid = NULL; intel_dp->has_audio = false; + memset(intel_dp->dpcd, 0, sizeof(intel_dp->dpcd)); if (HAS_PCH_SPLIT(dev)) status = ironlake_dp_detect(intel_dp); -- cgit v0.10.2 From 1b9be9d09d85b3697418dc444db30d069203ff7d Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 12 Jul 2011 17:38:01 -0400 Subject: drm/i915/dp: Move DPCD dump to common code instead of PCH-only No reason not to see this on g4x, after all. Signed-off-by: Adam Jackson Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index de24f31..0be85a0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1615,8 +1615,6 @@ ironlake_dp_detect(struct intel_dp *intel_dp) sizeof (intel_dp->dpcd)); if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0) status = connector_status_connected; - DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], - intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); return status; } @@ -1679,6 +1677,10 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = ironlake_dp_detect(intel_dp); else status = g4x_dp_detect(intel_dp); + + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], + intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); + if (status != connector_status_connected) return status; -- cgit v0.10.2 From 9de88e6e89a2222061af8e1448f6f346e3413fc8 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 12 Jul 2011 17:38:02 -0400 Subject: drm/i915/dp: Read more DPCD registers on connection probe For parity with radeon and nouveau, and also because I suspect we're going to need it to get format-conversion dongles right. Signed-off-by: Adam Jackson Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0be85a0..2f0566b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -52,7 +52,7 @@ struct intel_dp { uint32_t color_range; uint8_t link_bw; uint8_t lane_count; - uint8_t dpcd[4]; + uint8_t dpcd[8]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; @@ -1678,8 +1678,10 @@ intel_dp_detect(struct drm_connector *connector, bool force) else status = g4x_dp_detect(intel_dp); - DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], - intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx%hx%hx%hx%hx\n", intel_dp->dpcd[0], + intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3], + intel_dp->dpcd[4], intel_dp->dpcd[5], intel_dp->dpcd[6], + intel_dp->dpcd[7]); if (status != connector_status_connected) return status; -- cgit v0.10.2 From ac66ae8346fff704301e24ac55da1d76020660b2 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 12 Jul 2011 17:38:03 -0400 Subject: drm/i915/dp: Better hexdump of DPCD %hx alone prints 0 as "0", not "00". Signed-off-by: Adam Jackson Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2f0566b..13bddd3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1678,10 +1678,10 @@ intel_dp_detect(struct drm_connector *connector, bool force) else status = g4x_dp_detect(intel_dp); - DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx%hx%hx%hx%hx\n", intel_dp->dpcd[0], - intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3], - intel_dp->dpcd[4], intel_dp->dpcd[5], intel_dp->dpcd[6], - intel_dp->dpcd[7]); + DRM_DEBUG_KMS("DPCD: %02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n", + intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], + intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5], + intel_dp->dpcd[6], intel_dp->dpcd[7]); if (status != connector_status_connected) return status; -- cgit v0.10.2 From 71ba9000e673d6171a52f2a8b14e0419087f7199 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 12 Jul 2011 17:38:04 -0400 Subject: drm/i915/dp: Retry DPCD fetch on G4X too Signed-off-by: Adam Jackson Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 13bddd3..9a0c3ca 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1596,10 +1596,22 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) } static enum drm_connector_status +i915_dp_detect_common(struct intel_dp *intel_dp) +{ + enum drm_connector_status status = connector_status_disconnected; + + if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) && + (intel_dp->dpcd[DP_DPCD_REV] != 0)) + status = connector_status_connected; + + return status; +} + +static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; - bool ret; /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) { @@ -1609,13 +1621,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp) return status; } - status = connector_status_disconnected; - ret = intel_dp_aux_native_read_retry(intel_dp, - 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)); - if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0) - status = connector_status_connected; - return status; + return i915_dp_detect_common(intel_dp); } static enum drm_connector_status @@ -1623,7 +1629,6 @@ g4x_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - enum drm_connector_status status; uint32_t temp, bit; switch (intel_dp->output_reg) { @@ -1645,15 +1650,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) if ((temp & bit) == 0) return connector_status_disconnected; - status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) - { - if (intel_dp->dpcd[DP_DPCD_REV] != 0) - status = connector_status_connected; - } - - return status; + return i915_dp_detect_common(intel_dp); } /** -- cgit v0.10.2 From a2cab1b24a4ea75a68fa21bfb7d5b1a45121583c Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 12 Jul 2011 17:38:05 -0400 Subject: drm/i915/dp: Explicitly request 8/10 channel coding It's not clear what a sink would do if you wrote zero to this register - which I guess would mean "I don't support any channel encodings, good luck" - but let's not find out. Signed-off-by: Adam Jackson Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9a0c3ca..1c3a36f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -769,6 +769,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); intel_dp->link_configuration[0] = intel_dp->link_bw; intel_dp->link_configuration[1] = intel_dp->lane_count; + intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B; /* * Check for DPCD version > 1.1 and enhanced framing support -- cgit v0.10.2 From a65e34c79c88895766ab1f8a5afa451eed26622b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jul 2011 10:04:56 -0700 Subject: drm/i915: Hold mode_config->mutex during hotplug processing Hotplug detection is a mode setting operation and must hold the struct_mutex or risk colliding with other mode setting operations. In particular, the display port hotplug function attempts to re-train the link if the monitor is supposed to be running when plugged back in. If that happens while mode setting is underway, the link will get scrambled, leaving it in an inconsistent state. This is a special case -- usually the driver mode setting entry points are covered by the upper level DRM code, but in this case the function is invoked as a work function not under the control of DRM. Signed-off-by: Keith Packard Cc: stable@kernel.org Reviewed-by: Jesse Barnes diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3b03f85..9da2a2c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -306,6 +306,7 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; + mutex_lock(&mode_config->mutex); DRM_DEBUG_KMS("running encoder hotplug functions\n"); list_for_each_entry(encoder, &mode_config->encoder_list, base.head) @@ -314,6 +315,8 @@ static void i915_hotplug_work_func(struct work_struct *work) /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); + + mutex_unlock(&mode_config->mutex); } static void i915_handle_rps_change(struct drm_device *dev) -- cgit v0.10.2 From 302983e9059e9ef5de3ca7671918eeb237c5971e Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Wed, 13 Jul 2011 16:32:32 -0400 Subject: drm/i915/pch: Fix integer math bugs in panel fitting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consider a 1600x900 panel, upscaling a 1360x768 mode, full-aspect. The old math would give you: scaled_width = 1600 * 768; /* 1228800 */ scaled_height = 1360 * 900; /* 1224000 */ if (scaled_width > scaled_height) { /* pillarbox, and true */ width = 1224000 / 768; /* int(1593.75) = 1593 */ x = (1600 - 1593 + 1) / 2; /* 4 */ y = 0; height = 768; } /* ... */ This is broken. The total width of scanout would then be 1593 + 4 + 4, or 1601, which is wider than the panel itself. The hardware very dutifully implements this, and you end up with a black 45° diagonal from the top-left corner to the bottom edge of the screen. It's a cool effect and all, but not what you wanted. Similar things happen for the letterbox case. The problem is that you have an integer number of pixels, which means it's usually impossible to upscale equally on both axes. 1360/768 is 1.7708, 1600/900 is 1.7777. Since we're constrained on the one axis, the other one wants to come out as an even number of pixels (the panel is almost certainly even on both axes, and the x/y offsets will be applied on both sides). In the math above, if 'width' comes out even, rounding down is correct; if it's odd, you'd rather round up. So just increment width/height in those cases. Tested on a Lenovo T500 (Ironlake). Signed-off-by: Adam Jackson Tested-By: Daniel Manrique Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=38851 Reviewed-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a06ff07..05f500c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -83,11 +83,15 @@ intel_pch_panel_fitting(struct drm_device *dev, u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; if (scaled_width > scaled_height) { /* pillar */ width = scaled_height / mode->vdisplay; + if (width & 1) + width++; x = (adjusted_mode->hdisplay - width + 1) / 2; y = 0; height = adjusted_mode->vdisplay; } else if (scaled_width < scaled_height) { /* letter */ height = scaled_width / mode->hdisplay; + if (height & 1) + height++; y = (adjusted_mode->vdisplay - height + 1) / 2; x = 0; width = adjusted_mode->hdisplay; -- cgit v0.10.2 From 81055854d096959898fdc17ed11729eb019eff07 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 21 Jul 2011 17:48:37 -0400 Subject: drm/i915/dp: Explicitly disable symbol scrambling while training The DP spec says training patterns 1 and 2 are to be sent non-scrambled, and the GPU docs claim that happens (or at least, there's no explicit scrambling control). But the sink may be confused if we don't explicitly tell it what we're doing, so play it safe. Signed-off-by: Adam Jackson Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1c3a36f..8aecb07 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1370,7 +1370,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) reg = DP | DP_LINK_TRAIN_PAT_1; if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_1)) + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE)) break; /* Set training pattern 1 */ @@ -1445,7 +1446,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_2)) + DP_TRAINING_PATTERN_2 | + DP_LINK_SCRAMBLING_DISABLE)) break; udelay(400); -- cgit v0.10.2 From e85194641bec56179dcf5e1704ce5c6bf30340c6 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 21 Jul 2011 17:48:38 -0400 Subject: drm/i915/dp: Don't turn CPT DP ports on too early The docs say the port has to come on in training pattern 1; at this point, though, ->DP is in normal mode. The intent here is to wait until the port is in fact sending data, but that doesn't happen since we've broken the sequence the hardware expects, and the vblank wait will time out and kvetch in the log. Signed-off-by: Adam Jackson Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8aecb07..dcc7ae6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1334,10 +1334,16 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) u32 reg; uint32_t DP = intel_dp->DP; - /* Enable output, wait for it to become active */ - I915_WRITE(intel_dp->output_reg, intel_dp->DP); - POSTING_READ(intel_dp->output_reg); - intel_wait_for_vblank(dev, intel_crtc->pipe); + /* + * On CPT we have to enable the port in training pattern 1, which + * will happen below in intel_dp_set_link_train. Otherwise, enable + * the port and wait for it to become active. + */ + if (!HAS_PCH_CPT(dev)) { + I915_WRITE(intel_dp->output_reg, intel_dp->DP); + POSTING_READ(intel_dp->output_reg); + intel_wait_for_vblank(dev, intel_crtc->pipe); + } /* Write the link configuration data */ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, -- cgit v0.10.2 From 40ee3381dd1010432acc13e907329029096c5bfc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Jul 2011 15:31:19 -0700 Subject: drm/i915: Fixup for 'Hold mode_config->mutex during hotplug' drm_helper_hpd_irq_event queues another work proc to go and deliver the user-space event, and that function also wants to hold the config mutex, so we shouldn't hold the mutex across the drm_helper_hpd_irq_event call. Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9da2a2c..9b1d669 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -313,10 +313,10 @@ static void i915_hotplug_work_func(struct work_struct *work) if (encoder->hot_plug) encoder->hot_plug(encoder); + mutex_unlock(&mode_config->mutex); + /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); - - mutex_unlock(&mode_config->mutex); } static void i915_handle_rps_change(struct drm_device *dev) -- cgit v0.10.2 From 92fd8fd13b7570f6a8ba519c4e8ec98f10a86ce9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jul 2011 19:50:10 -0700 Subject: drm/i915: Use dp_detect_common in hotplug helper function This uses the common dpcd reading routine, i915_dp_detect_common, instead of open-coding a call to intel_dp_aux_native_read. Besides reducing duplicated code, this also gains the read retries which may be necessary when a cable is first plugged back in and the link needs to be retrained. Signed-off-by: Keith Packard Reviewed-by: Jesse Barnes Reviewed-by: Adam Jackson diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index dcc7ae6..45db8106 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1567,6 +1567,20 @@ intel_dp_link_down(struct intel_dp *intel_dp) POSTING_READ(intel_dp->output_reg); } +static enum drm_connector_status +i915_dp_detect_common(struct intel_dp *intel_dp) +{ + enum drm_connector_status status = connector_status_disconnected; + + if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) && + (intel_dp->dpcd[DP_DPCD_REV] != 0)) { + status = connector_status_connected; + } + + return status; +} + /* * According to DP spec * 5.1.2: @@ -1579,45 +1593,30 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { - int ret; - if (!intel_dp->base.base.crtc) return; + /* Try to read receiver status if the link appears to be up */ if (!intel_dp_get_link_status(intel_dp)) { intel_dp_link_down(intel_dp); return; } - /* Try to read receiver status if the link appears to be up */ - ret = intel_dp_aux_native_read(intel_dp, - 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)); - if (ret != sizeof(intel_dp->dpcd)) { + /* Now read the DPCD to see if it's actually running */ + if (i915_dp_detect_common(intel_dp) != connector_status_connected) { intel_dp_link_down(intel_dp); return; } if (!intel_channel_eq_ok(intel_dp)) { + DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", + drm_get_encoder_name(&intel_dp->base.base)); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); } } static enum drm_connector_status -i915_dp_detect_common(struct intel_dp *intel_dp) -{ - enum drm_connector_status status = connector_status_disconnected; - - if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)) && - (intel_dp->dpcd[DP_DPCD_REV] != 0)) - status = connector_status_connected; - - return status; -} - -static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; -- cgit v0.10.2 From 26d61aad7a46115628341e9eb95433f30efef21a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jul 2011 20:01:09 -0700 Subject: drm/i915: Rename i915_dp_detect_common to intel_dp_get_dpcd This describes the function better, allowing it to be used where the DPCD value is relevant. Signed-off-by: Keith Packard Reviewed-by: Jesse Barnes Reviewed-by: Adam Jackson diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 45db8106..41674e1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1567,18 +1567,16 @@ intel_dp_link_down(struct intel_dp *intel_dp) POSTING_READ(intel_dp->output_reg); } -static enum drm_connector_status -i915_dp_detect_common(struct intel_dp *intel_dp) +static bool +intel_dp_get_dpcd(struct intel_dp *intel_dp) { - enum drm_connector_status status = connector_status_disconnected; - if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, sizeof (intel_dp->dpcd)) && (intel_dp->dpcd[DP_DPCD_REV] != 0)) { - status = connector_status_connected; + return true; } - return status; + return false; } /* @@ -1603,7 +1601,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) } /* Now read the DPCD to see if it's actually running */ - if (i915_dp_detect_common(intel_dp) != connector_status_connected) { + if (!intel_dp_get_dpcd(intel_dp)) { intel_dp_link_down(intel_dp); return; } @@ -1617,6 +1615,14 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) } static enum drm_connector_status +intel_dp_detect_dpcd(struct intel_dp *intel_dp) +{ + if (intel_dp_get_dpcd(intel_dp)) + return connector_status_connected; + return connector_status_disconnected; +} + +static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; @@ -1629,7 +1635,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp) return status; } - return i915_dp_detect_common(intel_dp); + return intel_dp_detect_dpcd(intel_dp); } static enum drm_connector_status @@ -1658,7 +1664,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) if ((temp & bit) == 0) return connector_status_disconnected; - return i915_dp_detect_common(intel_dp); + return intel_dp_detect_dpcd(intel_dp); } /** -- cgit v0.10.2 From 59f3e272d788305e16098f0b18309919c9216d67 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jul 2011 20:01:56 -0700 Subject: drm/i915: In intel_dp_init, replace read of DPCD with intel_dp_get_dpcd Eliminates an open-coded read and also gains the retry behaviour of intel_dp_get_dpcd, which seems like a good idea. Signed-off-by: Keith Packard Reviewed-by: Jesse Barnes Reviewed-by: Adam Jackson diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 41674e1..9f134d2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2015,7 +2015,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) /* Cache some DPCD data in the eDP case */ if (is_edp(intel_dp)) { - int ret; + bool ret; u32 pp_on, pp_div; pp_on = I915_READ(PCH_PP_ON_DELAYS); @@ -2028,11 +2028,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ ironlake_edp_panel_vdd_on(intel_dp); - ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV, - intel_dp->dpcd, - sizeof(intel_dp->dpcd)); + ret = intel_dp_get_dpcd(intel_dp); ironlake_edp_panel_vdd_off(intel_dp); - if (ret == sizeof(intel_dp->dpcd)) { + if (ret) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & -- cgit v0.10.2 From f0575e92974d328e8816ed89704c985a7d7d90ac Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jul 2011 22:12:43 -0700 Subject: drm/i915: DP_PIPE_ENABLED must check transcoder on CPT Display port pipe selection on CPT is not done with a bit in the output register, rather it is controlled by a couple of bits in the separate transcoder register which indicate which display port output is connected to the transcoder. This patch replaces the simplistic macro DP_PIPE_ENABLED with the rather more complicated function dp_pipe_enabled which checks the output register to see if that is enabled, and then goes on to either check the output register pipe selection bit (on non-CPT) or the transcoder DP selection bits (on CPT). Before this patch, any time the mode of pipe A was changed, any display port outputs on pipe B would get disabled as intel_disable_pch_ports would ensure that the mode setting operation could occur on pipe A without interference from other outputs connected to that pch port Signed-off-by: Keith Packard Reviewed-by: Jesse Barnes Reviewed-by: Adam Jackson diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5d5def7..f731565 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2083,9 +2083,6 @@ #define DP_PIPEB_SELECT (1 << 30) #define DP_PIPE_MASK (1 << 30) -#define DP_PIPE_ENABLED(V, P) \ - (((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN)) - /* Link training mode - select a suitable mode for each stage */ #define DP_LINK_TRAIN_PAT_1 (0 << 28) #define DP_LINK_TRAIN_PAT_2 (1 << 28) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5609c06..fc26cb4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -979,11 +979,29 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv, pipe_name(pipe)); } +static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe, + int reg, u32 port_sel, u32 val) +{ + if ((val & DP_PORT_EN) == 0) + return false; + + if (HAS_PCH_CPT(dev_priv->dev)) { + u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe); + u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg); + if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) + return false; + } else { + if ((val & DP_PIPE_MASK) != (pipe << 30)) + return false; + } + return true; +} + static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg) + enum pipe pipe, int reg, u32 port_sel) { u32 val = I915_READ(reg); - WARN(DP_PIPE_ENABLED(val, pipe), + WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val), "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); } @@ -1003,9 +1021,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, int reg; u32 val; - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); reg = PCH_ADPA; val = I915_READ(reg); @@ -1334,19 +1352,24 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, } static void disable_pch_dp(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg) + enum pipe pipe, int reg, u32 port_sel) { u32 val = I915_READ(reg); - if (DP_PIPE_ENABLED(val, pipe)) + if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) { + DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe); I915_WRITE(reg, val & ~DP_PORT_EN); + } } static void disable_pch_hdmi(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - if (HDMI_PIPE_ENABLED(val, pipe)) + if (HDMI_PIPE_ENABLED(val, pipe)) { + DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n", + reg, pipe); I915_WRITE(reg, val & ~PORT_ENABLE); + } } /* Disable any ports connected to this transcoder */ @@ -1358,9 +1381,9 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, val = I915_READ(PCH_PP_CONTROL); I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS); - disable_pch_dp(dev_priv, pipe, PCH_DP_B); - disable_pch_dp(dev_priv, pipe, PCH_DP_C); - disable_pch_dp(dev_priv, pipe, PCH_DP_D); + disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); + disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); + disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); reg = PCH_ADPA; val = I915_READ(reg); -- cgit v0.10.2 From d2b996ac698aebb28557355857927b8b934bb4f9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Jul 2011 22:37:51 -0700 Subject: Revert and fix "drm/i915/dp: remove DPMS mode tracking from DP" This reverts commit 885a50147f00a8a80108904bf58a18af357717f3. We actually *do* need to track DPMS state so that on hotplug, we don't retrain the link until DPMS is disabled. However, that code had avery small bug -- it wouldn't set the dpms_mode at mode set time, and so link retraining would not actually occur on monitor hotplug until the monitor had gone through a DPMS off/DPMS on cycle. Signed-off-by: Keith Packard Tested-by: Andrew Lutomirski diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9f134d2..4493641 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -50,6 +50,7 @@ struct intel_dp { bool has_audio; int force_audio; uint32_t color_range; + int dpms_mode; uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[8]; @@ -1011,6 +1012,8 @@ static void intel_dp_commit(struct drm_encoder *encoder) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); + + intel_dp->dpms_mode = DRM_MODE_DPMS_ON; } static void @@ -1045,6 +1048,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); } + intel_dp->dpms_mode = mode; } /* @@ -1591,6 +1595,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { + if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON) + return; + if (!intel_dp->base.base.crtc) return; @@ -1939,6 +1946,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) return; intel_dp->output_reg = output_reg; + intel_dp->dpms_mode = -1; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { -- cgit v0.10.2 From 120eced9efe7fdb5123db4ea47e9adee9b66284e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 27 Jul 2011 01:21:40 -0700 Subject: drm/i915: Set crtc DPMS mode to ON in intel_crtc_mode_set This corrects the DPMS mode tracking so that the DPMS code will actually turn the CRTC off the next time the screen saves. Signed-off-by: Keith Packard Reviewed-by: Jesse Barnes diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fc26cb4..d9b8c15 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5273,6 +5273,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, drm_vblank_post_modeset(dev, pipe); + intel_crtc->dpms_mode = DRM_MODE_DPMS_ON; + return ret; } -- cgit v0.10.2 From 3bcf603f6d5d18bd9d076dc280de71f48add4101 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 27 Jul 2011 11:51:40 -0700 Subject: drm/i915: apply timing generator bug workaround on CPT and PPT On CougarPoint and PantherPoint PCH chips, the timing generator may fail to start after DP training completes. This is due to a bug in the FDI autotraining detect logic (which will stall the timing generator and re-enable it once training completes), so disable it to avoid silent DP mode setting failures. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f731565..00bd510 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3072,6 +3072,11 @@ #define TRANS_6BPC (2<<5) #define TRANS_12BPC (3<<5) +#define _TRANSA_CHICKEN2 0xf0064 +#define _TRANSB_CHICKEN2 0xf1064 +#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) +#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31) + #define SOUTH_CHICKEN2 0xc2004 #define DPLS_EDP_PPS_FIX_DIS (1<<0) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d9b8c15..502efc3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7524,6 +7524,7 @@ static void ibx_init_clock_gating(struct drm_device *dev) static void cpt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; /* * On Ibex Peak and Cougar Point, we need to disable clock @@ -7533,6 +7534,9 @@ static void cpt_init_clock_gating(struct drm_device *dev) I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | DPLS_EDP_PPS_FIX_DIS); + /* Without this, mode sets may fail silently on FDI */ + for_each_pipe(pipe) + I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); } static void ironlake_teardown_rc6(struct drm_device *dev) -- cgit v0.10.2 From 2704cf5fbd248871a745d210733c6319959d2b0c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 28 Jul 2011 11:52:45 -0700 Subject: drm/i915: flush plane control changes on ILK+ as well After writing to the plane control reg we need to write to the surface reg to trigger the double buffered register latch. On previous chipsets, writing to DSPADDR was enough, but on ILK+ DSPSURF is the reg that triggers the double buffer latch. v2: write DSPADDR too to cover pre-965 chipsets v3: use flush_display_plane instead, that's what it's for v4: send the right patch Signed-off-by: Jesse Barnes Tested-by: Keith Packard Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 502efc3..a7a7b67 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1323,8 +1323,8 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, static void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane) { - u32 reg = DSPADDR(plane); - I915_WRITE(reg, I915_READ(reg)); + I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); + I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); } /** -- cgit v0.10.2 From d74362c9e45689d8d7e3d4bcf6681c4358ef4f2e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Jul 2011 14:47:14 -0700 Subject: drm/i915: Flush other plane register writes Writes to the plane control register are buffered in the chip until a write to the DSPADDR (pre-965) or DSPSURF (post-965) register occurs. This patch adds flushes in: intel_enable_plane gen6_init_clock_gating ivybridge_init_clock_gating Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7a7b67..8f7ed73 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1290,6 +1290,17 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, intel_wait_for_pipe_off(dev_priv->dev, pipe); } +/* + * Plane regs are double buffered, going from enabled->disabled needs a + * trigger in order to latch. The display address reg provides this. + */ +static void intel_flush_display_plane(struct drm_i915_private *dev_priv, + enum plane plane) +{ + I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); + I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); +} + /** * intel_enable_plane - enable a display plane on a given pipe * @dev_priv: i915 private structure @@ -1313,20 +1324,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, return; I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); + intel_flush_display_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } -/* - * Plane regs are double buffered, going from enabled->disabled needs a - * trigger in order to latch. The display address reg provides this. - */ -static void intel_flush_display_plane(struct drm_i915_private *dev_priv, - enum plane plane) -{ - I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); - I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); -} - /** * intel_disable_plane - disable a display plane * @dev_priv: i915 private structure @@ -7418,10 +7419,12 @@ static void gen6_init_clock_gating(struct drm_device *dev) ILK_DPARB_CLK_GATE | ILK_DPFD_CLK_GATE); - for_each_pipe(pipe) + for_each_pipe(pipe) { I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } } static void ivybridge_init_clock_gating(struct drm_device *dev) @@ -7438,10 +7441,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - for_each_pipe(pipe) + for_each_pipe(pipe) { I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } } static void g4x_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From cb0e093162d7b6589c2217a00e2abfef686b32d6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 28 Jul 2011 14:50:30 -0700 Subject: drm/i915: fix CB tuning check for ILK+ CB tuning is needed to handle potential process variations that might cause clock jitter for certain PLL settings. However, we were setting it incorrectly since we were using the wrong M value as a check (M1 when we needed to use the whole M value). Fix it up, making my HDMI attached display a little prettier (used to have occasional dots crawl across the display). Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8f7ed73..32c8c95 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4994,7 +4994,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock.m1 < factor * clock.n) + if (clock.m < factor * clock.n) fp |= FP_CB_TUNE; dpll = 0; -- cgit v0.10.2 From b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 8 Jul 2011 11:31:57 -0700 Subject: drm/i915/hdmi: send AVI info frames on ILK+ as well On Ironlake and above, we have per-transcoder DIP registers, so use them for sending DIPs like AVI infoframes on ILK and above. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 00bd510..30d8aae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3020,6 +3020,20 @@ #define _TRANSA_DP_LINK_M2 0xe0048 #define _TRANSA_DP_LINK_N2 0xe004c +/* Per-transcoder DIP controls */ + +#define _VIDEO_DIP_CTL_A 0xe0200 +#define _VIDEO_DIP_DATA_A 0xe0208 +#define _VIDEO_DIP_GCP_A 0xe0210 + +#define _VIDEO_DIP_CTL_B 0xe1200 +#define _VIDEO_DIP_DATA_B 0xe1208 +#define _VIDEO_DIP_GCP_B 0xe1210 + +#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B) +#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) +#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) + #define _TRANS_HTOTAL_B 0xe1000 #define _TRANS_HBLANK_B 0xe1004 #define _TRANS_HSYNC_B 0xe1008 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index aa0a8e8..c220255 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -112,6 +112,40 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) VIDEO_DIP_ENABLE_AVI); } +static void intel_ironlake_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +{ + struct dip_infoframe avi_if = { + .type = DIP_TYPE_AVI, + .ver = DIP_VERSION_AVI, + .len = DIP_LEN_AVI, + }; + uint32_t *data = (uint32_t *)&avi_if; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + unsigned i; + + if (!intel_hdmi->has_hdmi_sink) + return; + + intel_wait_for_vblank(dev, intel_crtc->pipe); + + I915_WRITE(reg, VIDEO_DIP_SELECT_AVI); + + intel_dip_infoframe_csum(&avi_if); + for (i = 0; i < sizeof(avi_if); i += 4) { + I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); + data++; + } + + I915_WRITE(reg, VIDEO_DIP_ENABLE | VIDEO_DIP_SELECT_AVI | + VIDEO_DIP_FREQ_VSYNC | (DIP_LEN_AVI << 8) | + VIDEO_DIP_ENABLE_AVI); +} + static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -149,7 +183,10 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, I915_WRITE(intel_hdmi->sdvox_reg, sdvox); POSTING_READ(intel_hdmi->sdvox_reg); - intel_hdmi_set_avi_infoframe(encoder); + if (HAS_PCH_SPLIT(dev)) + intel_ironlake_hdmi_set_avi_infoframe(encoder); + else + intel_hdmi_set_avi_infoframe(encoder); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) -- cgit v0.10.2 From e0e3fb482105c65ce6f5480a86092e966a29ed79 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 29 Jul 2011 14:45:21 -0700 Subject: drm/i915: Ignore GPU wedged errors while pinning scanout buffers Failing to pin a scanout buffer will most likely lead to a black screen, so if the GPU is wedged, then just let the pin happen and hope that things work out OK. Signed-off-by: Keith Packard Reviewed-by: Chris Wilson diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a087e1b..d5c7c7b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3019,7 +3019,7 @@ i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, /* Currently, we are always called from an non-interruptible context. */ if (pipelined != obj->ring) { ret = i915_gem_object_wait_rendering(obj); - if (ret) + if (ret == -ERESTARTSYS) return ret; } -- cgit v0.10.2 From b066254fee2b0b4d1323295f8ae34c9442222165 Mon Sep 17 00:00:00 2001 From: Pieterjan Camerlynck Date: Tue, 26 Jul 2011 16:23:54 +0200 Subject: i915: add Dell OptiPlex FX170 to intel_no_lvds The Dell OptiPlex FX170 claims to have LVDS, but doesn't. Signed-off-by: Pieterjan Camerlynck Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b28f7bd..2e8ddfc 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -690,6 +690,14 @@ static const struct dmi_system_id intel_no_lvds[] = { }, { .callback = intel_no_lvds_dmi_callback, + .ident = "Dell OptiPlex FX170", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex FX170"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, .ident = "AOpen Mini PC", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "AOpen"), -- cgit v0.10.2 From 358733e9047cafcc185ca19b8c369c659ac0c4cf Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 27 Jul 2011 11:53:01 -0700 Subject: drm/i915: add GPU max frequency control file Mainly for use in debugging and benchmarking, this file allows the user to control the max frequency used by the GPU. Frequency may still vary based on workload (if the frequency is set to higher than the minimum) but won't go over the newly set value. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0a893f7..782b781 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1300,6 +1300,76 @@ static const struct file_operations i915_wedged_fops = { .llseek = default_llseek, }; +static int +i915_max_freq_open(struct inode *inode, + struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t +i915_max_freq_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + drm_i915_private_t *dev_priv = dev->dev_private; + char buf[80]; + int len; + + len = snprintf(buf, sizeof (buf), + "max freq: %d\n", dev_priv->max_delay * 50); + + if (len > sizeof (buf)) + len = sizeof (buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_max_freq_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + char buf[20]; + int val = 1; + + if (cnt > 0) { + if (cnt > sizeof (buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtoul(buf, NULL, 0); + } + + DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val); + + /* + * Turbo will still be enabled, but won't go above the set value. + */ + dev_priv->max_delay = val / 50; + + gen6_set_rps(dev, val / 50); + + return cnt; +} + +static const struct file_operations i915_max_freq_fops = { + .owner = THIS_MODULE, + .open = i915_max_freq_open, + .read = i915_max_freq_read, + .write = i915_max_freq_write, + .llseek = default_llseek, +}; + /* As the drm_debugfs_init() routines are called before dev->dev_private is * allocated we need to hook into the minor for release. */ static int @@ -1399,6 +1469,21 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); } +static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_max_freq", + S_IRUGO | S_IWUSR, + root, dev, + &i915_max_freq_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops); +} + static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -1451,6 +1536,9 @@ int i915_debugfs_init(struct drm_minor *minor) ret = i915_forcewake_create(minor->debugfs_root, minor); if (ret) return ret; + ret = i915_max_freq_create(minor->debugfs_root, minor); + if (ret) + return ret; return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, @@ -1465,6 +1553,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops, + 1, minor); } #endif /* CONFIG_DEBUG_FS */ -- cgit v0.10.2 From 013a41ec541d5daa0c9f2b5126d2e820902c052d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 19 Jul 2011 15:38:56 -0700 Subject: drm/i915: provide more error output when mode sets fail If a mode set fails we may get a message from drm_crtc_helper if we're lucky, but it won't tell us anything about *why* we failed to set a mode. So add a few DRM_ERRORs for the cases that shouldn't happen so we can debug things more easily. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 32c8c95..d2fb8cf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1958,7 +1958,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG_KMS("No FB bound\n"); + DRM_ERROR("No FB bound\n"); return 0; } @@ -1967,6 +1967,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, case 1: break; default: + DRM_ERROR("no plane for crtc\n"); return -EINVAL; } @@ -1976,6 +1977,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, NULL); if (ret != 0) { mutex_unlock(&dev->struct_mutex); + DRM_ERROR("pin & fence failed\n"); return ret; } @@ -2004,6 +2006,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (ret) { i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); + DRM_ERROR("failed to update base address\n"); return ret; } -- cgit v0.10.2 From 070d329ae52e2fde341771d753a5b728145881f4 Mon Sep 17 00:00:00 2001 From: Michel Alexandre Salim Date: Thu, 28 Jul 2011 18:52:06 +0200 Subject: drm/i915: Add quirk to disable SSC on Sony Vaio Y2 Using the new quirk added to support disabling SSC on Lenovo U160 (#36656, commit 435793dfb8aec7b2e19f72d5bce8a22fd0b57839), also register the Vaio as a special case and disable SSC for it. This patch fixes #34437 on fdo bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=34437 Signed-off-by: Michel Alexandre Salim Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d2fb8cf..3d2900c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7892,6 +7892,9 @@ struct intel_quirk intel_quirks[] = { /* Lenovo U160 cannot use SSC on LVDS */ { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable }, + + /* Sony Vaio Y cannot use SSC on LVDS */ + { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, }; static void intel_init_quirks(struct drm_device *dev) -- cgit v0.10.2 From 291427f5fdadec6e4be2924172e83588880e1539 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 29 Jul 2011 12:42:37 -0700 Subject: drm/i915: apply phase pointer override on SNB+ too These bits moved around on SNB and above. v2: again with the git send-email fail v3: add macros for getting per-pipe override & enable bits v4: enable phase sync pointer on SNB and IVB configs as well Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 30d8aae..a7f7a34 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3091,6 +3091,11 @@ #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) #define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31) +#define SOUTH_CHICKEN1 0xc2000 +#define FDIA_PHASE_SYNC_SHIFT_OVR 19 +#define FDIA_PHASE_SYNC_SHIFT_EN 18 +#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) +#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) #define SOUTH_CHICKEN2 0xc2004 #define DPLS_EDP_PPS_FIX_DIS (1<<0) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d2900c..5316460 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2113,6 +2113,18 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } +static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 flags = I915_READ(SOUTH_CHICKEN1); + + flags |= FDI_PHASE_SYNC_OVR(pipe); + I915_WRITE(SOUTH_CHICKEN1, flags); /* once to unlock... */ + flags |= FDI_PHASE_SYNC_EN(pipe); + I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to enable */ + POSTING_READ(SOUTH_CHICKEN1); +} + /* The FDI link training functions for ILK/Ibexpeak. */ static void ironlake_fdi_link_train(struct drm_crtc *crtc) { @@ -2263,6 +2275,9 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); + if (HAS_PCH_CPT(dev)) + cpt_phase_pointer_enable(dev, pipe); + for (i = 0; i < 4; i++ ) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2379,6 +2394,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); + if (HAS_PCH_CPT(dev)) + cpt_phase_pointer_enable(dev, pipe); + for (i = 0; i < 4; i++ ) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2488,6 +2506,17 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) } } +static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 flags = I915_READ(SOUTH_CHICKEN1); + + flags &= ~(FDI_PHASE_SYNC_EN(pipe)); + I915_WRITE(SOUTH_CHICKEN1, flags); /* once to disable... */ + flags &= ~(FDI_PHASE_SYNC_OVR(pipe)); + I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to lock */ + POSTING_READ(SOUTH_CHICKEN1); +} static void ironlake_fdi_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2517,6 +2546,8 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) I915_WRITE(FDI_RX_CHICKEN(pipe), I915_READ(FDI_RX_CHICKEN(pipe) & ~FDI_RX_PHASE_SYNC_POINTER_EN)); + } else if (HAS_PCH_CPT(dev)) { + cpt_phase_pointer_disable(dev, pipe); } /* still set train pattern 1 */ -- cgit v0.10.2 From cda2bb78c24de7674eafa3210314dc75bed344a6 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 26 Jul 2011 16:53:06 -0400 Subject: drm/i915/pch: Save/restore PCH_PORT_HOTPLUG across suspend At least on a Lenovo X220 the HPD bits of this are enabled at boot but cleared after resume, which means plug interrupts stop working. This also happens to fix DP displays re-lighting on resume. I'm quite certain that's an accident: the first DP link train inevitably fails on that machine, and it's only serendipity that we're getting multiple plug interrupts and the second train works. But I shall take my victories where I get them. Signed-off-by: Adam Jackson Tested-by: Keith Packard Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ce7914c..e0d0e27 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -541,6 +541,7 @@ typedef struct drm_i915_private { u32 savePIPEB_LINK_M1; u32 savePIPEB_LINK_N1; u32 saveMCHBAR_RENDER_STANDBY; + u32 savePCH_PORT_HOTPLUG; struct { /** Bridge to intel-gtt-ko */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 5257cfc..27693c0 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -814,6 +814,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); dev_priv->saveMCHBAR_RENDER_STANDBY = I915_READ(RSTDBYCTL); + dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); } else { dev_priv->saveIER = I915_READ(IER); dev_priv->saveIMR = I915_READ(IMR); @@ -865,6 +866,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(GTIMR, dev_priv->saveGTIMR); I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); + I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG); } else { I915_WRITE(IER, dev_priv->saveIER); I915_WRITE(IMR, dev_priv->saveIMR); -- cgit v0.10.2 From 62ac41a6e443ef26b9de862c6e20c088e2b04dde Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 28 Jul 2011 12:55:14 -0700 Subject: drm/i915: don't use uninitialized EDID bpc values when picking pipe bpp The EDID parser will zero out the bpc value, and the driver needs to handle that case. In our picker, we'll just ignore 0 values as far as bpp picking goes. Fixes https://bugs.freedesktop.org/show_bug.cgi?id=39323. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2bf5bb6..35364e6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4600,7 +4600,9 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, if (connector->encoder != encoder) continue; - if (connector->display_info.bpc < display_bpc) { + /* Don't use an invalid EDID bpc value */ + if (connector->display_info.bpc && + connector->display_info.bpc < display_bpc) { DRM_DEBUG_DRIVER("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); display_bpc = connector->display_info.bpc; } @@ -5215,7 +5217,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, temp |= PIPE_12BPC; break; default: - WARN(1, "intel_choose_pipe_bpp returned invalid value\n"); + WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n", + pipe_bpp); temp |= PIPE_8BPC; pipe_bpp = 24; break; -- cgit v0.10.2 From 11bee43ebba0bfc92165c059f6e9869197ea8889 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 1 Aug 2011 15:02:20 -0700 Subject: drm/i915/dp: wait for previous AUX channel activity to clear Before initiating a new read or write on the DP AUX channel, wait for any outstanding activity to complete. This may happen during normal retry behavior. If the wait fails (i.e. after 1ms the AUX channel is still busy) dump a backtrace to make the caller easier to spot. v2: use msleep instead, and timeout after 3ms (only ever saw 1 retry with msleep in testing) v3: fix backtrace check to trigger if the 3ms wait times out Fixes https://bugs.freedesktop.org/show_bug.cgi?id=38136. Signed-off-by: Jesse Barnes Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4493641..ba72fbc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -315,9 +315,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, else precharge = 5; - if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) { - DRM_ERROR("dp_aux_ch not started status 0x%08x\n", - I915_READ(ch_ctl)); + /* Try to wait for any previous AUX channel activity */ + for (try = 0; try < 3; try++) { + status = I915_READ(ch_ctl); + if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) + break; + msleep(1); + } + + if (try == 3) { + WARN(1, "dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); return -EBUSY; } -- cgit v0.10.2 From 4edd17a25c99f34bd7a75c1daf31afe840237da8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 3 Aug 2011 10:34:58 -0700 Subject: Revert "drm/i915/dp: Zero the DPCD data before connection probe" This reverts commit 97cdd7101079adc3c626d159c62d43de949516c8. Clearing the dpcd data means that if the fetch fails, any previous data will be lost. On eDP, this is no fun as we only fetch dpcd at init time, so the memset will destroy that the next time through. diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ba72fbc..2f901c0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1697,7 +1697,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct edid *edid = NULL; intel_dp->has_audio = false; - memset(intel_dp->dpcd, 0, sizeof(intel_dp->dpcd)); if (HAS_PCH_SPLIT(dev)) status = ironlake_dp_detect(intel_dp); -- cgit v0.10.2 From 4e20fa65a3ea789510eed1a15deb9e8aab2b8202 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 3 Aug 2011 10:52:24 -0700 Subject: drm/i915: Try enabling RC6 by default (again) Jesse Barnes and I found a couple of issues where incorrect mode setting would cause problems with RC6 enabled. We're hopeful that fixing those will resolve the outstanding issues with a few machines that had trouble before 3.0 with rc6. Cc: Pekka Enberg Cc: Francesco Allertsen Cc: Ted Phelps Cc: Gu Rui Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=38567 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=38332 Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ce045a8..60e4b9e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -62,7 +62,7 @@ module_param_named(semaphores, i915_semaphores, int, 0600); MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync (default: false)"); -unsigned int i915_enable_rc6 __read_mostly = 0; +unsigned int i915_enable_rc6 __read_mostly = 1; module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); MODULE_PARM_DESC(i915_enable_rc6, "Enable power-saving render C-state 6 (default: true)"); -- cgit v0.10.2 From ebec9a7bf11f843b0602b06c402f04bf4213b35a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 3 Aug 2011 09:22:54 -0700 Subject: drm: track CEA version number if present Drivers need to know the CEA version number in addition to other display info (like whether the display is an HDMI sink) before enabling certain features. So track the CEA version number in the display info structure. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0929219..e12f8b0 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1439,6 +1439,8 @@ EXPORT_SYMBOL(drm_detect_monitor_audio); static void drm_add_display_info(struct edid *edid, struct drm_display_info *info) { + u8 *edid_ext; + info->width_mm = edid->width_cm * 10; info->height_mm = edid->height_cm * 10; @@ -1483,6 +1485,13 @@ static void drm_add_display_info(struct edid *edid, info->color_formats = DRM_COLOR_FORMAT_YCRCB444; if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422) info->color_formats = DRM_COLOR_FORMAT_YCRCB422; + + /* Get data from CEA blocks if present */ + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return; + + info->cea_rev = edid_ext[1]; } /** diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 33d12f8..d515bc8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -205,6 +205,8 @@ struct drm_display_info { enum subpixel_order subpixel_order; u32 color_formats; + u8 cea_rev; + char *raw_edid; /* if any */ }; -- cgit v0.10.2 From 45187ace97f7b3deb559b25348ccb7e301c158c9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 3 Aug 2011 09:22:55 -0700 Subject: drm/i915/hdmi: split infoframe setting from infoframe type code This makes it easier to add support for other infoframes (e.g. SPD, vendor specific). Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index be67a59..56cae72 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1506,6 +1506,7 @@ #define VIDEO_DIP_SELECT_AVI (0 << 19) #define VIDEO_DIP_SELECT_VENDOR (1 << 19) #define VIDEO_DIP_SELECT_SPD (3 << 19) +#define VIDEO_DIP_SELECT_MASK (3 << 19) #define VIDEO_DIP_FREQ_ONCE (0 << 16) #define VIDEO_DIP_FREQ_VSYNC (1 << 16) #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6e990f9..2f47dcf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -178,6 +178,8 @@ struct intel_crtc { #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 DIP_HEADER_SIZE 5 + #define DIP_TYPE_AVI 0x82 #define DIP_VERSION_AVI 0x2 #define DIP_LEN_AVI 13 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 105e2b8..d43cebd 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -45,6 +45,8 @@ struct intel_hdmi { bool has_hdmi_sink; bool has_audio; int force_audio; + void (*write_infoframe)(struct drm_encoder *encoder, + struct dip_infoframe *frame); }; static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) @@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) struct intel_hdmi, base); } -void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) +void intel_dip_infoframe_csum(struct dip_infoframe *frame) { - uint8_t *data = (uint8_t *)avi_if; + uint8_t *data = (uint8_t *)frame; uint8_t sum = 0; unsigned i; - avi_if->checksum = 0; - avi_if->ecc = 0; + frame->checksum = 0; + frame->ecc = 0; - for (i = 0; i < sizeof(*avi_if); i++) + /* Header isn't part of the checksum */ + for (i = 5; i < frame->len; i++) sum += data[i]; - avi_if->checksum = 0x100 - sum; + frame->checksum = 0x100 - sum; } -static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +static u32 intel_infoframe_index(struct dip_infoframe *frame) { - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; - uint32_t *data = (uint32_t *)&avi_if; + u32 flags = 0; + + switch (frame->type) { + case DIP_TYPE_AVI: + flags |= VIDEO_DIP_SELECT_AVI; + break; + case DIP_TYPE_SPD: + flags |= VIDEO_DIP_SELECT_SPD; + break; + default: + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + break; + } + + return flags; +} + +static u32 intel_infoframe_flags(struct dip_infoframe *frame) +{ + u32 flags = 0; + + switch (frame->type) { + case DIP_TYPE_AVI: + flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; + break; + case DIP_TYPE_SPD: + flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC; + break; + default: + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + break; + } + + return flags; +} + +static void i9xx_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 port; - unsigned i; + u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); + unsigned i, len = DIP_HEADER_SIZE + frame->len; - if (!intel_hdmi->has_hdmi_sink) - return; /* XXX first guess at handling video port, is this corrent? */ if (intel_hdmi->sdvox_reg == SDVOB) @@ -98,52 +133,72 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) else return; - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | - VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); + flags = intel_infoframe_index(frame); + + val &= ~VIDEO_DIP_SELECT_MASK; + + I915_WRITE(VIDEO_DIP_CTL, val | port | flags); - intel_dip_infoframe_csum(&avi_if); - for (i = 0; i < sizeof(avi_if); i += 4) { + for (i = 0; i < len; i += 4) { I915_WRITE(VIDEO_DIP_DATA, *data); data++; } - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | - VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC | - VIDEO_DIP_ENABLE_AVI); + flags |= intel_infoframe_flags(frame); + + I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); } -static void intel_ironlake_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +static void ironlake_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) { - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; - uint32_t *data = (uint32_t *)&avi_if; + uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); - unsigned i; - - if (!intel_hdmi->has_hdmi_sink) - return; + unsigned i, len = DIP_HEADER_SIZE + frame->len; + u32 flags, val = I915_READ(reg); intel_wait_for_vblank(dev, intel_crtc->pipe); - I915_WRITE(reg, VIDEO_DIP_SELECT_AVI); + flags = intel_infoframe_index(frame); - intel_dip_infoframe_csum(&avi_if); - for (i = 0; i < sizeof(avi_if); i += 4) { + val &= ~VIDEO_DIP_SELECT_MASK; + + I915_WRITE(reg, val | flags); + + for (i = 0; i < len; i += 4) { I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); data++; } - I915_WRITE(reg, VIDEO_DIP_ENABLE | VIDEO_DIP_SELECT_AVI | - VIDEO_DIP_FREQ_VSYNC | (DIP_LEN_AVI << 8) | - VIDEO_DIP_ENABLE_AVI); + flags |= intel_infoframe_flags(frame); + + I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); +} +static void intel_set_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (!intel_hdmi->has_hdmi_sink) + return; + + intel_dip_infoframe_csum(frame); + intel_hdmi->write_infoframe(encoder, frame); +} + +static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +{ + struct dip_infoframe avi_if = { + .type = DIP_TYPE_AVI, + .ver = DIP_VERSION_AVI, + .len = DIP_LEN_AVI, + }; + + intel_set_infoframe(encoder, &avi_if); } static void intel_hdmi_mode_set(struct drm_encoder *encoder, @@ -189,10 +244,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, I915_WRITE(intel_hdmi->sdvox_reg, sdvox); POSTING_READ(intel_hdmi->sdvox_reg); - if (HAS_PCH_SPLIT(dev)) - intel_ironlake_hdmi_set_avi_infoframe(encoder); - else - intel_hdmi_set_avi_infoframe(encoder); + intel_hdmi_set_avi_infoframe(encoder); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) @@ -470,6 +522,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_hdmi->sdvox_reg = sdvox_reg; + if (!HAS_PCH_SPLIT(dev)) + intel_hdmi->write_infoframe = i9xx_write_infoframe; + else + intel_hdmi->write_infoframe = ironlake_write_infoframe; + drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); intel_hdmi_add_properties(intel_hdmi, connector); -- cgit v0.10.2 From c0864cb39c68696e80657360eba63da5e743b7aa Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 3 Aug 2011 09:22:56 -0700 Subject: drm/i915/hdmi: HDMI source product description infoframe support Set an SPD infoframe if the sink supports it. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2f47dcf..7b330e7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -184,6 +184,22 @@ struct intel_crtc { #define DIP_VERSION_AVI 0x2 #define DIP_LEN_AVI 13 +#define DIP_TYPE_SPD 0x3 +#define DIP_VERSION_SPD 0x1 +#define DIP_LEN_SPD 25 +#define DIP_SPD_UNKNOWN 0 +#define DIP_SPD_DSTB 0x1 +#define DIP_SPD_DVDP 0x2 +#define DIP_SPD_DVHS 0x3 +#define DIP_SPD_HDDVR 0x4 +#define DIP_SPD_DVC 0x5 +#define DIP_SPD_DSC 0x6 +#define DIP_SPD_VCD 0x7 +#define DIP_SPD_GAME 0x8 +#define DIP_SPD_PC 0x9 +#define DIP_SPD_BD 0xa +#define DIP_SPD_SCD 0xb + struct dip_infoframe { uint8_t type; /* HB0 */ uint8_t ver; /* HB1 */ @@ -208,6 +224,11 @@ struct dip_infoframe { uint16_t left_bar_end; uint16_t right_bar_start; } avi; + struct { + uint8_t vn[8]; + uint8_t pd[16]; + uint8_t sdi; + } spd; uint8_t payload[27]; } __attribute__ ((packed)) body; } __attribute__((packed)); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index d43cebd..226ba83 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -201,6 +201,21 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) intel_set_infoframe(encoder, &avi_if); } +static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) +{ + struct dip_infoframe spd_if; + + memset(&spd_if, 0, sizeof(spd_if)); + spd_if.type = DIP_TYPE_SPD; + spd_if.ver = DIP_VERSION_SPD; + spd_if.len = DIP_LEN_SPD; + strcpy(spd_if.body.spd.vn, "Intel"); + strcpy(spd_if.body.spd.pd, "Integrated gfx"); + spd_if.body.spd.sdi = DIP_SPD_PC; + + intel_set_infoframe(encoder, &spd_if); +} + static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -245,6 +260,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, POSTING_READ(intel_hdmi->sdvox_reg); intel_hdmi_set_avi_infoframe(encoder); + intel_hdmi_set_spd_infoframe(encoder); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) -- cgit v0.10.2 From 07b7ddd9b7f17a567e3ac2b33a4dffcb2a4524e0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 3 Aug 2011 11:28:44 -0700 Subject: drm/i915: allow cache sharing policy control Expose the SNB+ cache sharing policy register in debugfs. The new file, i915_cache_sharing, has 4 values, 0-3, with 0 being "max uncore resources" and 3 being the minimum. Exposing this control should make benchmarking easier and help us choose a good default. Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5bf7bf5..a8ab626 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1408,6 +1408,85 @@ static const struct file_operations i915_max_freq_fops = { .llseek = default_llseek, }; +static int +i915_cache_sharing_open(struct inode *inode, + struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t +i915_cache_sharing_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + drm_i915_private_t *dev_priv = dev->dev_private; + char buf[80]; + u32 snpcr; + int len; + + mutex_lock(&dev_priv->dev->struct_mutex); + snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + mutex_unlock(&dev_priv->dev->struct_mutex); + + len = snprintf(buf, sizeof (buf), + "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >> + GEN6_MBC_SNPCR_SHIFT); + + if (len > sizeof (buf)) + len = sizeof (buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_cache_sharing_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + char buf[20]; + u32 snpcr; + int val = 1; + + if (cnt > 0) { + if (cnt > sizeof (buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtoul(buf, NULL, 0); + } + + if (val < 0 || val > 3) + return -EINVAL; + + DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val); + + /* Update the cache sharing policy here as well */ + snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + snpcr &= ~GEN6_MBC_SNPCR_MASK; + snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); + I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); + + return cnt; +} + +static const struct file_operations i915_cache_sharing_fops = { + .owner = THIS_MODULE, + .open = i915_cache_sharing_open, + .read = i915_cache_sharing_read, + .write = i915_cache_sharing_write, + .llseek = default_llseek, +}; + /* As the drm_debugfs_init() routines are called before dev->dev_private is * allocated we need to hook into the minor for release. */ static int @@ -1522,6 +1601,21 @@ static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops); } +static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_cache_sharing", + S_IRUGO | S_IWUSR, + root, dev, + &i915_cache_sharing_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops); +} + static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -1578,6 +1672,9 @@ int i915_debugfs_init(struct drm_minor *minor) ret = i915_max_freq_create(minor->debugfs_root, minor); if (ret) return ret; + ret = i915_cache_sharing_create(minor->debugfs_root, minor); + if (ret) + return ret; return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, @@ -1594,6 +1691,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, + 1, minor); } #endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 56cae72..d1331f7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -78,6 +78,14 @@ #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) +#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ +#define GEN6_MBC_SNPCR_SHIFT 21 +#define GEN6_MBC_SNPCR_MASK (3<<21) +#define GEN6_MBC_SNPCR_MAX (0<<21) +#define GEN6_MBC_SNPCR_MED (1<<21) +#define GEN6_MBC_SNPCR_LOW (2<<21) +#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ + #define GEN6_GDRST 0x941c #define GEN6_GRDOM_FULL (1 << 0) #define GEN6_GRDOM_RENDER (1 << 1) -- cgit v0.10.2