From 66a9278eecbef1c746e7fac8f4bcb0485d7aa4d0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 12 Jul 2012 20:08:18 +0200 Subject: drm/i915: simplify possible_clones computation Intel hw only has one MUX for encoders, so outputs are either not cloneable or all in the same group of cloneable outputs. This neatly simplifies the code and allows us to ditch some ugly if cascades in the dp and hdmi init code (well, we need these if cascades for other stuff still, but that can be taken care of in follow-up patches). Note that this changes two things: - dvo can now be cloned with sdvo, but dvo is gen2 whereas sdvo is gen3+, so no problem. Note that the old code had a bug and didn't allow cloning crt with dvo (but only the other way round). - sdvo-lvds can now be cloned with sdvo-non-tv. Spec says this won't work, but the only reason I've found is that you can't use the panel-fitter (used for lvds upscaling) with anything else. But we don't use the panel fitter for sdvo-lvds. Imo this part of Bspec is a) rather confusing b) mostly as a guideline to implementors (i.e. explicitly stating what is already implicit from the spec, without always going into the details of why). So I think we can ignore this - worst case we'll get a bug report from a user with with sdvo-lvds and sdvo-tmds and have to add that special case back in. Because sdvo lvds is a bit special explain in comments why sdvo LVDS outputs can be cloned, but native LVDS and eDP can't be cloned - we use the panel fitter for the later, but not for sdvo. Note that this also uncoditionally initializes the panel_vdd work used by eDP. Trying to be clever doesn't buy us anything (but strange bugs) and this way we can kill the is_edp check. v2: Incorporate review from Paulo - Add in a missing space. - Pimp comment message to address his concerns. Reviewed-by: Paulo Zanoni Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9e476eca89f..5c0a72606225 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6707,15 +6707,23 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, return 0; } -static int intel_encoder_clones(struct drm_device *dev, int type_mask) +static int intel_encoder_clones(struct intel_encoder *encoder) { - struct intel_encoder *encoder; + struct drm_device *dev = encoder->base.dev; + struct intel_encoder *source_encoder; int index_mask = 0; int entry = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { - if (type_mask & encoder->clone_mask) + list_for_each_entry(source_encoder, + &dev->mode_config.encoder_list, base.head) { + + if (encoder == source_encoder) index_mask |= (1 << entry); + + /* Intel hw has only one MUX where enocoders could be cloned. */ + if (encoder->cloneable && source_encoder->cloneable) + index_mask |= (1 << entry); + entry++; } @@ -6874,7 +6882,7 @@ static void intel_setup_outputs(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { encoder->base.possible_crtcs = encoder->crtc_mask; encoder->base.possible_clones = - intel_encoder_clones(dev, encoder->clone_mask); + intel_encoder_clones(encoder); } /* disable all the possible outputs/crtcs before entering KMS mode */ -- cgit v1.2.3 From 08d644add0e5f799a47dbe7849401606c522e59e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 12 Jul 2012 20:19:59 +0200 Subject: drm/i915: add port parameter to intel_hdmi_init Instead of having a giant if cascade to figure this out according to the passed-in register. We could do quite a bit more cleaning up and all by using the port at more places, but I think this should be part of a bigger rework to introduce a struct intel_digital_port which would keep track of all these things. I guess this will be part of some haswell-DP-induced refactoring. For now this rips out the big cascade, which is what annoyed me so much. v2: Add port variable name back for the func decl (I've tried to trick myself below the 80 char limit). Reviewed-by: Paulo Zanoni Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 14 ++++++------ drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_hdmi.c | 41 +++++++++++------------------------- 4 files changed, 22 insertions(+), 38 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 933c74859172..32604ac80204 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -250,7 +250,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) case PORT_B: case PORT_C: case PORT_D: - intel_hdmi_init(dev, DDI_BUF_CTL(port)); + intel_hdmi_init(dev, DDI_BUF_CTL(port), port); break; default: DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n", diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5c0a72606225..e86fd3977f73 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6798,16 +6798,16 @@ static void intel_setup_outputs(struct drm_device *dev) /* PCH SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, PCH_SDVOB, true); if (!found) - intel_hdmi_init(dev, HDMIB); + intel_hdmi_init(dev, HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) intel_dp_init(dev, PCH_DP_B); } if (I915_READ(HDMIC) & PORT_DETECTED) - intel_hdmi_init(dev, HDMIC); + intel_hdmi_init(dev, HDMIC, PORT_C); if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED) - intel_hdmi_init(dev, HDMID); + intel_hdmi_init(dev, HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) intel_dp_init(dev, PCH_DP_C); @@ -6821,13 +6821,13 @@ static void intel_setup_outputs(struct drm_device *dev) /* SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, SDVOB, true); if (!found) - intel_hdmi_init(dev, SDVOB); + intel_hdmi_init(dev, SDVOB, PORT_B); if (!found && (I915_READ(DP_B) & DP_DETECTED)) intel_dp_init(dev, DP_B); } if (I915_READ(SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, SDVOC); + intel_hdmi_init(dev, SDVOC, PORT_C); /* Shares lanes with HDMI on SDVOC */ if (I915_READ(DP_C) & DP_DETECTED) @@ -6840,7 +6840,7 @@ static void intel_setup_outputs(struct drm_device *dev) found = intel_sdvo_init(dev, SDVOB, true); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); - intel_hdmi_init(dev, SDVOB); + intel_hdmi_init(dev, SDVOB, PORT_B); } if (!found && SUPPORTS_INTEGRATED_DP(dev)) { @@ -6860,7 +6860,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); - intel_hdmi_init(dev, SDVOC); + intel_hdmi_init(dev, SDVOC, PORT_C); } if (SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_C\n"); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 76ba554f6592..d234f1af5db5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -364,7 +364,8 @@ extern void intel_attach_force_audio_property(struct drm_connector *connector); extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector); extern void intel_crt_init(struct drm_device *dev); -extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); +extern void intel_hdmi_init(struct drm_device *dev, + int sdvox_reg, enum port port); extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 593b8fe2e00a..e4c37bb572e8 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -889,7 +889,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c intel_attach_broadcast_rgb_property(connector); } -void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) +void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; @@ -925,40 +925,23 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_encoder->cloneable = false; - /* Set up the DDC bus. */ - if (sdvox_reg == SDVOB) { + intel_hdmi->ddi_port = port; + switch (port) { + case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == SDVOC) { - intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMIB) { - intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMIC) { - intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMID) { - intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) { - DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n"); - intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - intel_hdmi->ddi_port = PORT_B; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) { - DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n"); + break; + case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - intel_hdmi->ddi_port = PORT_C; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) { - DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n"); + break; + case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - intel_hdmi->ddi_port = PORT_D; dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; - } else { - /* If we got an unknown sdvox_reg, things are pretty much broken - * in a way that we should let the kernel know about it */ + break; + case PORT_A: + /* Internal port only for eDP. */ + default: BUG(); } -- cgit v1.2.3 From ab9d7c302af858e1bc8f613c3a6f1eea3c4c0364 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 17 Jul 2012 17:53:45 -0300 Subject: drm/i915: add port field to struct intel_dp and use it This will be needed for Haswell, but already has its uses here. This patch started as a small patch written patch by Shobhit Kumar, but it has changed so much that none of its original lines remain. Credits-to: Shobhit Kumar Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++-------- drivers/gpu/drm/i915/intel_dp.c | 44 +++++++++++++++++------------------- drivers/gpu/drm/i915/intel_drv.h | 4 +++- 3 files changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e86fd3977f73..f8c2aa1ec27a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6764,10 +6764,10 @@ static void intel_setup_outputs(struct drm_device *dev) dpd_is_edp = intel_dpd_is_edp(dev); if (has_edp_a(dev)) - intel_dp_init(dev, DP_A); + intel_dp_init(dev, DP_A, PORT_A); if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_D); + intel_dp_init(dev, PCH_DP_D, PORT_D); } intel_crt_init(dev); @@ -6800,7 +6800,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found) intel_hdmi_init(dev, HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_B); + intel_dp_init(dev, PCH_DP_B, PORT_B); } if (I915_READ(HDMIC) & PORT_DETECTED) @@ -6810,10 +6810,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_hdmi_init(dev, HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) - intel_dp_init(dev, PCH_DP_C); + intel_dp_init(dev, PCH_DP_C, PORT_C); if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_D); + intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { int found; @@ -6823,7 +6823,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found) intel_hdmi_init(dev, SDVOB, PORT_B); if (!found && (I915_READ(DP_B) & DP_DETECTED)) - intel_dp_init(dev, DP_B); + intel_dp_init(dev, DP_B, PORT_B); } if (I915_READ(SDVOC) & PORT_DETECTED) @@ -6831,7 +6831,7 @@ static void intel_setup_outputs(struct drm_device *dev) /* Shares lanes with HDMI on SDVOC */ if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C); + intel_dp_init(dev, DP_C, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; @@ -6845,7 +6845,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found && SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_B\n"); - intel_dp_init(dev, DP_B); + intel_dp_init(dev, DP_B, PORT_B); } } @@ -6864,14 +6864,14 @@ static void intel_setup_outputs(struct drm_device *dev) } if (SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_C\n"); - intel_dp_init(dev, DP_C); + intel_dp_init(dev, DP_C, PORT_C); } } if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) { DRM_DEBUG_KMS("probing DP_D\n"); - intel_dp_init(dev, DP_D); + intel_dp_init(dev, DP_D, PORT_D); } } else if (IS_GEN2(dev)) intel_dvo_init(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 61400c1fef0f..ad90a499dab7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2426,7 +2426,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect } void -intel_dp_init(struct drm_device *dev, int output_reg) +intel_dp_init(struct drm_device *dev, int output_reg, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; @@ -2441,6 +2441,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) return; intel_dp->output_reg = output_reg; + intel_dp->port = port; intel_dp->dpms_mode = -1; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); @@ -2486,28 +2487,25 @@ intel_dp_init(struct drm_device *dev, int output_reg) drm_sysfs_connector_add(connector); /* Set up the DDC bus. */ - switch (output_reg) { - case DP_A: - name = "DPDDC-A"; - break; - case DP_B: - case PCH_DP_B: - dev_priv->hotplug_supported_mask |= - DPB_HOTPLUG_INT_STATUS; - name = "DPDDC-B"; - break; - case DP_C: - case PCH_DP_C: - dev_priv->hotplug_supported_mask |= - DPC_HOTPLUG_INT_STATUS; - name = "DPDDC-C"; - break; - case DP_D: - case PCH_DP_D: - dev_priv->hotplug_supported_mask |= - DPD_HOTPLUG_INT_STATUS; - name = "DPDDC-D"; - break; + switch (port) { + case PORT_A: + name = "DPDDC-A"; + break; + case PORT_B: + dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS; + name = "DPDDC-B"; + break; + case PORT_C: + dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS; + name = "DPDDC-C"; + break; + case PORT_D: + dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS; + name = "DPDDC-D"; + break; + default: + WARN(1, "Invalid port %c\n", port_name(port)); + break; } intel_dp_i2c_init(intel_dp, intel_connector, name); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d234f1af5db5..2846f5e8cca3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -306,6 +306,7 @@ struct intel_dp { uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; bool has_audio; enum hdmi_force_audio force_audio; + enum port port; uint32_t color_range; int dpms_mode; uint8_t link_bw; @@ -375,7 +376,8 @@ extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj); extern bool intel_lvds_init(struct drm_device *dev); -extern void intel_dp_init(struct drm_device *dev, int dp_reg); +extern void intel_dp_init(struct drm_device *dev, int output_reg, + enum port port); void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -- cgit v1.2.3 From 7434a255a5cf42819b7e42377f18aaa02f6be52b Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 18 Jul 2012 19:22:30 +0200 Subject: drm/i915: Support for ns2501-DVO This patch adds support for the ns2501 DVO, found in some older Fujitsu/Siemens Labtops. It is in the state of "works for me". Includes now proper DPMS support. Includes switching between resolutions - from 640x480 to 1024x768. Currently assumes that the native display resolution is 1024x768. The ns2501 seems to be rather critical - if the output PLL is not running, the chip doesn't seem to be clocked and then doesn't react on i2c messages. Thus, a quick'n-dirty trick ensures that the DVO is active before submitting any i2c messages to it. This is probably to be reviewed. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=17902 Signed-off-by: Thomas Richter [danvet: fixup whitespace fail.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/dvo.h | 1 + drivers/gpu/drm/i915/dvo_ns2501.c | 582 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_dvo.c | 10 +- 5 files changed, 596 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/dvo_ns2501.c (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b0bacdba6d7e..0f2c5493242b 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -40,6 +40,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ dvo_ivch.o \ dvo_tfp410.o \ dvo_sil164.o \ + dvo_ns2501.o \ i915_gem_dmabuf.o i915-$(CONFIG_COMPAT) += i915_ioc32.o diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 58914691a77b..0c8ac4d92deb 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -140,5 +140,6 @@ extern struct intel_dvo_dev_ops ch7xxx_ops; extern struct intel_dvo_dev_ops ivch_ops; extern struct intel_dvo_dev_ops tfp410_ops; extern struct intel_dvo_dev_ops ch7017_ops; +extern struct intel_dvo_dev_ops ns2501_ops; #endif /* _INTEL_DVO_H */ diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c new file mode 100644 index 000000000000..1a0bad9a5fab --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -0,0 +1,582 @@ +/* + * + * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter + * + * All Rights Reserved. + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHOR 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. + * + */ + +#include "dvo.h" +#include "i915_reg.h" +#include "i915_drv.h" + +#define NS2501_VID 0x1305 +#define NS2501_DID 0x6726 + +#define NS2501_VID_LO 0x00 +#define NS2501_VID_HI 0x01 +#define NS2501_DID_LO 0x02 +#define NS2501_DID_HI 0x03 +#define NS2501_REV 0x04 +#define NS2501_RSVD 0x05 +#define NS2501_FREQ_LO 0x06 +#define NS2501_FREQ_HI 0x07 + +#define NS2501_REG8 0x08 +#define NS2501_8_VEN (1<<5) +#define NS2501_8_HEN (1<<4) +#define NS2501_8_DSEL (1<<3) +#define NS2501_8_BPAS (1<<2) +#define NS2501_8_RSVD (1<<1) +#define NS2501_8_PD (1<<0) + +#define NS2501_REG9 0x09 +#define NS2501_9_VLOW (1<<7) +#define NS2501_9_MSEL_MASK (0x7<<4) +#define NS2501_9_TSEL (1<<3) +#define NS2501_9_RSEN (1<<2) +#define NS2501_9_RSVD (1<<1) +#define NS2501_9_MDI (1<<0) + +#define NS2501_REGC 0x0c + +struct ns2501_priv { + //I2CDevRec d; + bool quiet; + int reg_8_shadow; + int reg_8_set; + // Shadow registers for i915 + int dvoc; + int pll_a; + int srcdim; + int fw_blc; +}; + +#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr)) + +/* + * Include the PLL launcher prototype + */ +extern void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); + +/* + * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens + * laptops does not react on the i2c bus unless + * both the PLL is running and the display is configured in its native + * resolution. + * This function forces the DVO on, and stores the registers it touches. + * Afterwards, registers are restored to regular values. + * + * This is pretty much a hack, though it works. + * Without that, ns2501_readb and ns2501_writeb fail + * when switching the resolution. + */ + +static void enable_dvo(struct intel_dvo_device *dvo) +{ + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_gmbus *bus = container_of(adapter, + struct intel_gmbus, + adapter); + struct drm_i915_private *dev_priv = bus->dev_priv; + + DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__); + + ns->dvoc = I915_READ(DVO_C); + ns->pll_a = I915_READ(_DPLL_A); + ns->srcdim = I915_READ(DVOC_SRCDIM); + ns->fw_blc = I915_READ(FW_BLC); + + I915_WRITE(DVOC, 0x10004084); + I915_WRITE(_DPLL_A, 0xd0820000); + I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768 + I915_WRITE(FW_BLC, 0x1080304); + + intel_enable_pll(dev_priv, 0); + + I915_WRITE(DVOC, 0x90004084); +} + +/* + * Restore the I915 registers modified by the above + * trigger function. + */ +static void restore_dvo(struct intel_dvo_device *dvo) +{ + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_gmbus *bus = container_of(adapter, + struct intel_gmbus, + adapter); + struct drm_i915_private *dev_priv = bus->dev_priv; + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + + I915_WRITE(DVOC, ns->dvoc); + I915_WRITE(_DPLL_A, ns->pll_a); + I915_WRITE(DVOC_SRCDIM, ns->srcdim); + I915_WRITE(FW_BLC, ns->fw_blc); +} + +/* +** Read a register from the ns2501. +** Returns true if successful, false otherwise. +** If it returns false, it might be wise to enable the +** DVO with the above function. +*/ +static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) +{ + struct ns2501_priv *ns = dvo->dev_priv; + struct i2c_adapter *adapter = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = dvo->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = dvo->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(adapter, msgs, 2) == 2) { + *ch = in_buf[0]; + return true; + }; + + if (!ns->quiet) { + DRM_DEBUG_KMS + ("Unable to read register 0x%02x from %s:0x%02x.\n", addr, + adapter->name, dvo->slave_addr); + } + + return false; +} + +/* +** Write a register to the ns2501. +** Returns true if successful, false otherwise. +** If it returns false, it might be wise to enable the +** DVO with the above function. +*/ +static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +{ + struct ns2501_priv *ns = dvo->dev_priv; + struct i2c_adapter *adapter = dvo->i2c_bus; + uint8_t out_buf[2]; + + struct i2c_msg msg = { + .addr = dvo->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = ch; + + if (i2c_transfer(adapter, &msg, 1) == 1) { + return true; + } + + if (!ns->quiet) { + DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n", + addr, adapter->name, dvo->slave_addr); + } + + return false; +} + +/* National Semiconductor 2501 driver for chip on i2c bus + * scan for the chip on the bus. + * Hope the VBIOS initialized the PLL correctly so we can + * talk to it. If not, it will not be seen and not detected. + * Bummer! + */ +static bool ns2501_init(struct intel_dvo_device *dvo, + struct i2c_adapter *adapter) +{ + /* this will detect the NS2501 chip on the specified i2c bus */ + struct ns2501_priv *ns; + unsigned char ch; + + ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL); + if (ns == NULL) + return false; + + dvo->i2c_bus = adapter; + dvo->dev_priv = ns; + ns->quiet = true; + + if (!ns2501_readb(dvo, NS2501_VID_LO, &ch)) + goto out; + + if (ch != (NS2501_VID & 0xff)) { + DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", + ch, adapter->name, dvo->slave_addr); + goto out; + } + + if (!ns2501_readb(dvo, NS2501_DID_LO, &ch)) + goto out; + + if (ch != (NS2501_DID & 0xff)) { + DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", + ch, adapter->name, dvo->slave_addr); + goto out; + } + ns->quiet = false; + ns->reg_8_set = 0; + ns->reg_8_shadow = + NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN; + + DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n"); + return true; + +out: + kfree(ns); + return false; +} + +static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo) +{ + /* + * This is a Laptop display, it doesn't have hotplugging. + * Even if not, the detection bit of the 2501 is unreliable as + * it only works for some display types. + * It is even more unreliable as the PLL must be active for + * allowing reading from the chiop. + */ + return connector_status_connected; +} + +static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + DRM_DEBUG_KMS + ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", + __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, + mode->vtotal); + + /* + * Currently, these are all the modes I have data from. + * More might exist. Unclear how to find the native resolution + * of the panel in here so we could always accept it + * by disabling the scaler. + */ + if ((mode->hdisplay == 800 && mode->vdisplay == 600) || + (mode->hdisplay == 640 && mode->vdisplay == 480) || + (mode->hdisplay == 1024 && mode->vdisplay == 768)) { + return MODE_OK; + } else { + return MODE_ONE_SIZE; /* Is this a reasonable error? */ + } +} + +static void ns2501_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + bool ok; + bool restore = false; + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + + DRM_DEBUG_KMS + ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", + __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, + mode->vtotal); + + /* + * Where do I find the native resolution for which scaling is not required??? + * + * First trigger the DVO on as otherwise the chip does not appear on the i2c + * bus. + */ + do { + ok = true; + + if (mode->hdisplay == 800 && mode->vdisplay == 600) { + /* mode 277 */ + ns->reg_8_shadow &= ~NS2501_8_BPAS; + DRM_DEBUG_KMS("%s: switching to 800x600\n", + __FUNCTION__); + + /* + * No, I do not know where this data comes from. + * It is just what the video bios left in the DVO, so + * I'm just copying it here over. + * This also means that I cannot support any other modes + * except the ones supported by the bios. + */ + ok &= ns2501_writeb(dvo, 0x11, 0xc8); // 0xc7 also works. + ok &= ns2501_writeb(dvo, 0x1b, 0x19); + ok &= ns2501_writeb(dvo, 0x1c, 0x62); // VBIOS left 0x64 here, but 0x62 works nicer + ok &= ns2501_writeb(dvo, 0x1d, 0x02); + + ok &= ns2501_writeb(dvo, 0x34, 0x03); + ok &= ns2501_writeb(dvo, 0x35, 0xff); + + ok &= ns2501_writeb(dvo, 0x80, 0x27); + ok &= ns2501_writeb(dvo, 0x81, 0x03); + ok &= ns2501_writeb(dvo, 0x82, 0x41); + ok &= ns2501_writeb(dvo, 0x83, 0x05); + + ok &= ns2501_writeb(dvo, 0x8d, 0x02); + ok &= ns2501_writeb(dvo, 0x8e, 0x04); + ok &= ns2501_writeb(dvo, 0x8f, 0x00); + + ok &= ns2501_writeb(dvo, 0x90, 0xfe); /* vertical. VBIOS left 0xff here, but 0xfe works better */ + ok &= ns2501_writeb(dvo, 0x91, 0x07); + ok &= ns2501_writeb(dvo, 0x94, 0x00); + ok &= ns2501_writeb(dvo, 0x95, 0x00); + + ok &= ns2501_writeb(dvo, 0x96, 0x00); + + ok &= ns2501_writeb(dvo, 0x99, 0x00); + ok &= ns2501_writeb(dvo, 0x9a, 0x88); + + ok &= ns2501_writeb(dvo, 0x9c, 0x23); /* Looks like first and last line of the image. */ + ok &= ns2501_writeb(dvo, 0x9d, 0x00); + ok &= ns2501_writeb(dvo, 0x9e, 0x25); + ok &= ns2501_writeb(dvo, 0x9f, 0x03); + + ok &= ns2501_writeb(dvo, 0xa4, 0x80); + + ok &= ns2501_writeb(dvo, 0xb6, 0x00); + + ok &= ns2501_writeb(dvo, 0xb9, 0xc8); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */ + + ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xc1, 0xd7); + + ok &= ns2501_writeb(dvo, 0xc2, 0x00); + ok &= ns2501_writeb(dvo, 0xc3, 0xf8); + + ok &= ns2501_writeb(dvo, 0xc4, 0x03); + ok &= ns2501_writeb(dvo, 0xc5, 0x1a); + + ok &= ns2501_writeb(dvo, 0xc6, 0x00); + ok &= ns2501_writeb(dvo, 0xc7, 0x73); + ok &= ns2501_writeb(dvo, 0xc8, 0x02); + + } else if (mode->hdisplay == 640 && mode->vdisplay == 480) { + /* mode 274 */ + DRM_DEBUG_KMS("%s: switching to 640x480\n", + __FUNCTION__); + /* + * No, I do not know where this data comes from. + * It is just what the video bios left in the DVO, so + * I'm just copying it here over. + * This also means that I cannot support any other modes + * except the ones supported by the bios. + */ + ns->reg_8_shadow &= ~NS2501_8_BPAS; + + ok &= ns2501_writeb(dvo, 0x11, 0xa0); + ok &= ns2501_writeb(dvo, 0x1b, 0x11); + ok &= ns2501_writeb(dvo, 0x1c, 0x54); + ok &= ns2501_writeb(dvo, 0x1d, 0x03); + + ok &= ns2501_writeb(dvo, 0x34, 0x03); + ok &= ns2501_writeb(dvo, 0x35, 0xff); + + ok &= ns2501_writeb(dvo, 0x80, 0xff); + ok &= ns2501_writeb(dvo, 0x81, 0x07); + ok &= ns2501_writeb(dvo, 0x82, 0x3d); + ok &= ns2501_writeb(dvo, 0x83, 0x05); + + ok &= ns2501_writeb(dvo, 0x8d, 0x02); + ok &= ns2501_writeb(dvo, 0x8e, 0x10); + ok &= ns2501_writeb(dvo, 0x8f, 0x00); + + ok &= ns2501_writeb(dvo, 0x90, 0xff); /* vertical */ + ok &= ns2501_writeb(dvo, 0x91, 0x07); + ok &= ns2501_writeb(dvo, 0x94, 0x00); + ok &= ns2501_writeb(dvo, 0x95, 0x00); + + ok &= ns2501_writeb(dvo, 0x96, 0x05); + + ok &= ns2501_writeb(dvo, 0x99, 0x00); + ok &= ns2501_writeb(dvo, 0x9a, 0x88); + + ok &= ns2501_writeb(dvo, 0x9c, 0x24); + ok &= ns2501_writeb(dvo, 0x9d, 0x00); + ok &= ns2501_writeb(dvo, 0x9e, 0x25); + ok &= ns2501_writeb(dvo, 0x9f, 0x03); + + ok &= ns2501_writeb(dvo, 0xa4, 0x84); + + ok &= ns2501_writeb(dvo, 0xb6, 0x09); + + ok &= ns2501_writeb(dvo, 0xb9, 0xa0); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */ + + ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xc1, 0x90); + + ok &= ns2501_writeb(dvo, 0xc2, 0x00); + ok &= ns2501_writeb(dvo, 0xc3, 0x0f); + + ok &= ns2501_writeb(dvo, 0xc4, 0x03); + ok &= ns2501_writeb(dvo, 0xc5, 0x16); + + ok &= ns2501_writeb(dvo, 0xc6, 0x00); + ok &= ns2501_writeb(dvo, 0xc7, 0x02); + ok &= ns2501_writeb(dvo, 0xc8, 0x02); + + } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) { + /* mode 280 */ + DRM_DEBUG_KMS("%s: switching to 1024x768\n", + __FUNCTION__); + /* + * This might or might not work, actually. I'm silently + * assuming here that the native panel resolution is + * 1024x768. If not, then this leaves the scaler disabled + * generating a picture that is likely not the expected. + * + * Problem is that I do not know where to take the panel + * dimensions from. + * + * Enable the bypass, scaling not required. + * + * The scaler registers are irrelevant here.... + * + */ + ns->reg_8_shadow |= NS2501_8_BPAS; + ok &= ns2501_writeb(dvo, 0x37, 0x44); + } else { + /* + * Data not known. Bummer! + * Hopefully, the code should not go here + * as mode_OK delivered no other modes. + */ + ns->reg_8_shadow |= NS2501_8_BPAS; + } + ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow); + + if (!ok) { + if (restore) + restore_dvo(dvo); + enable_dvo(dvo); + restore = true; + } + } while (!ok); + /* + * Restore the old i915 registers before + * forcing the ns2501 on. + */ + if (restore) + restore_dvo(dvo); +} + +/* set the NS2501 power state */ +static void ns2501_dpms(struct intel_dvo_device *dvo, int mode) +{ + bool ok; + bool restore = false; + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + unsigned char ch; + + DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %d\n", + __FUNCTION__, mode); + + ch = ns->reg_8_shadow; + + if (mode == DRM_MODE_DPMS_ON) + ch |= NS2501_8_PD; + else + ch &= ~NS2501_8_PD; + + if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) { + ns->reg_8_set = 1; + ns->reg_8_shadow = ch; + + do { + ok = true; + ok &= ns2501_writeb(dvo, NS2501_REG8, ch); + ok &= + ns2501_writeb(dvo, 0x34, + (mode == + DRM_MODE_DPMS_ON) ? (0x03) : (0x00)); + ok &= + ns2501_writeb(dvo, 0x35, + (mode == + DRM_MODE_DPMS_ON) ? (0xff) : (0x00)); + if (!ok) { + if (restore) + restore_dvo(dvo); + enable_dvo(dvo); + restore = true; + } + } while (!ok); + + if (restore) + restore_dvo(dvo); + } +} + +static void ns2501_dump_regs(struct intel_dvo_device *dvo) +{ + uint8_t val; + + ns2501_readb(dvo, NS2501_FREQ_LO, &val); + DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_FREQ_HI, &val); + DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_REG8, &val); + DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_REG9, &val); + DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_REGC, &val); + DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val); +} + +static void ns2501_destroy(struct intel_dvo_device *dvo) +{ + struct ns2501_priv *ns = dvo->dev_priv; + + if (ns) { + kfree(ns); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ns2501_ops = { + .init = ns2501_init, + .detect = ns2501_detect, + .mode_valid = ns2501_mode_valid, + .mode_set = ns2501_mode_set, + .dpms = ns2501_dpms, + .dump_regs = ns2501_dump_regs, + .destroy = ns2501_destroy, +}; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f8c2aa1ec27a..93d9934ba328 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1428,8 +1428,10 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, * protect mechanism may be enabled. * * Note! This is for pre-ILK only. + * + * Unfortunately needed by dvo_ns2501 since the dvo depends on it running. */ -static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { int reg; u32 val; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 556cf6bf2a55..03dfdff8e003 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -37,6 +37,7 @@ #define SIL164_ADDR 0x38 #define CH7xxx_ADDR 0x76 #define TFP410_ADDR 0x38 +#define NS2501_ADDR 0x38 static const struct intel_dvo_device intel_dvo_devices[] = { { @@ -74,7 +75,14 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .slave_addr = 0x75, .gpio = GMBUS_PORT_DPB, .dev_ops = &ch7017_ops, - } + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ns2501", + .dvo_reg = DVOC, + .slave_addr = NS2501_ADDR, + .dev_ops = &ns2501_ops, + } }; struct intel_dvo { -- cgit v1.2.3 From f047e395ddc9da6c307a10629a237502e627ed85 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Jul 2012 12:31:41 +0100 Subject: drm/i915: Avoid concurrent access when marking the device as idle/busy As suggested by Daniel, rip out the independent timers for device and crtc busyness and integrate the manual powermanagement of the display engine into the GEM core and its request tracking. The benefits are that the code is a lot smaller, fewer moving parts and should fit more neatly into the overall activity tracking of the driver. v2: Complete overhaul and removal of the racy timers and workers. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 - drivers/gpu/drm/i915/i915_gem.c | 13 ++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 146 +++++------------------------ drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_pm.c | 5 +- 6 files changed, 41 insertions(+), 138 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 700dc838c57f..f1765893da60 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -785,9 +785,6 @@ typedef struct drm_i915_private { bool lvds_downclock_avail; /* indicates the reduced downclock for LVDS*/ int lvds_downclock; - struct work_struct idle_work; - struct timer_list idle_timer; - bool busy; u16 orig_clock; int child_dev_num; struct child_device_config *child_dev; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f26e2b201bad..b274810eaeab 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1462,11 +1462,14 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); + if (obj->pin_count) /* are we a framebuffer? */ + intel_mark_fb_idle(obj); + + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + list_del_init(&obj->ring_list); obj->ring = NULL; @@ -1602,9 +1605,11 @@ i915_add_request(struct intel_ring_buffer *ring, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } - if (was_empty) + if (was_empty) { queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + intel_mark_busy(dev_priv->dev); + } } return 0; @@ -1810,6 +1815,8 @@ i915_gem_retire_work_handler(struct work_struct *work) if (!dev_priv->mm.suspended && !idle) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + if (idle) + intel_mark_idle(dev); mutex_unlock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6be1a8920a84..25b2c54e1261 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -767,13 +767,11 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, obj->dirty = 1; obj->last_write_seqno = seqno; if (obj->pin_count) /* check for potential scanout */ - intel_mark_busy(ring->dev, obj); + intel_mark_fb_busy(obj); } trace_i915_gem_object_change_domain(obj, old_read, old_write); } - - intel_mark_busy(ring->dev, NULL); } static void diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 93d9934ba328..b463829b92eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5860,46 +5860,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } -#define GPU_IDLE_TIMEOUT 500 /* ms */ - -/* When this timer fires, we've been idle for awhile */ -static void intel_gpu_idle_timer(unsigned long arg) -{ - struct drm_device *dev = (struct drm_device *)arg; - drm_i915_private_t *dev_priv = dev->dev_private; - - if (!list_empty(&dev_priv->mm.active_list)) { - /* Still processing requests, so just re-arm the timer. */ - mod_timer(&dev_priv->idle_timer, jiffies + - msecs_to_jiffies(GPU_IDLE_TIMEOUT)); - return; - } - - dev_priv->busy = false; - queue_work(dev_priv->wq, &dev_priv->idle_work); -} - -#define CRTC_IDLE_TIMEOUT 1000 /* ms */ - -static void intel_crtc_idle_timer(unsigned long arg) -{ - struct intel_crtc *intel_crtc = (struct intel_crtc *)arg; - struct drm_crtc *crtc = &intel_crtc->base; - drm_i915_private_t *dev_priv = crtc->dev->dev_private; - struct intel_framebuffer *intel_fb; - - intel_fb = to_intel_framebuffer(crtc->fb); - if (intel_fb && intel_fb->obj->active) { - /* The framebuffer is still being accessed by the GPU. */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); - return; - } - - intel_crtc->busy = false; - queue_work(dev_priv->wq, &dev_priv->idle_work); -} - static void intel_increase_pllclock(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -5929,10 +5889,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) if (dpll & DISPLAY_RATE_SELECT_FPA1) DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); } - - /* Schedule downclock */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); } static void intel_decrease_pllclock(struct drm_crtc *crtc) @@ -5971,89 +5927,48 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) } -/** - * intel_idle_update - adjust clocks for idleness - * @work: work struct - * - * Either the GPU or display (or both) went idle. Check the busy status - * here and adjust the CRTC and GPU clocks as necessary. - */ -static void intel_idle_update(struct work_struct *work) +void intel_mark_busy(struct drm_device *dev) +{ + intel_sanitize_pm(dev); + i915_update_gfx_val(dev->dev_private); +} + +void intel_mark_idle(struct drm_device *dev) { - drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - idle_work); - struct drm_device *dev = dev_priv->dev; + intel_sanitize_pm(dev); +} + +void intel_mark_fb_busy(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; if (!i915_powersave) return; - mutex_lock(&dev->struct_mutex); - - i915_update_gfx_val(dev_priv); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - /* Skip inactive CRTCs */ if (!crtc->fb) continue; - intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->busy) - intel_decrease_pllclock(crtc); + if (to_intel_framebuffer(crtc->fb)->obj == obj) + intel_increase_pllclock(crtc); } - - - mutex_unlock(&dev->struct_mutex); } -/** - * intel_mark_busy - mark the GPU and possibly the display busy - * @dev: drm device - * @obj: object we're operating on - * - * Callers can use this function to indicate that the GPU is busy processing - * commands. If @obj matches one of the CRTC objects (i.e. it's a scanout - * buffer), we'll also mark the display as busy, so we know to increase its - * clock frequency. - */ -void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj) +void intel_mark_fb_idle(struct drm_i915_gem_object *obj) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_crtc *crtc = NULL; - struct intel_framebuffer *intel_fb; - struct intel_crtc *intel_crtc; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return; - - if (!dev_priv->busy) { - intel_sanitize_pm(dev); - dev_priv->busy = true; - } else - mod_timer(&dev_priv->idle_timer, jiffies + - msecs_to_jiffies(GPU_IDLE_TIMEOUT)); + struct drm_device *dev = obj->base.dev; + struct drm_crtc *crtc; - if (obj == NULL) + if (!i915_powersave) return; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->fb) continue; - intel_crtc = to_intel_crtc(crtc); - intel_fb = to_intel_framebuffer(crtc->fb); - if (intel_fb->obj == obj) { - if (!intel_crtc->busy) { - /* Non-busy -> busy, upclock */ - intel_increase_pllclock(crtc); - intel_crtc->busy = true; - } else { - /* Busy -> busy, put off timer */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); - } - } + if (to_intel_framebuffer(crtc->fb)->obj == obj) + intel_decrease_pllclock(crtc); } } @@ -6512,7 +6427,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_pending; intel_disable_fbc(dev); - intel_mark_busy(dev, obj); + intel_mark_fb_busy(obj); mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); @@ -6678,11 +6593,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) } drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); - - intel_crtc->busy = false; - - setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, - (unsigned long)intel_crtc); } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, @@ -7265,10 +7175,6 @@ void intel_modeset_init(struct drm_device *dev) /* Just disable it once at startup */ i915_disable_vga(dev); intel_setup_outputs(dev); - - INIT_WORK(&dev_priv->idle_work, intel_idle_update); - setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, - (unsigned long)dev); } void intel_modeset_gem_init(struct drm_device *dev) @@ -7319,14 +7225,6 @@ void intel_modeset_cleanup(struct drm_device *dev) /* flush any delayed tasks or pending work */ flush_scheduled_work(); - /* Shut off idle work before the crtcs get freed. */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - del_timer_sync(&intel_crtc->idle_timer); - } - del_timer_sync(&dev_priv->idle_timer); - cancel_work_sync(&dev_priv->idle_work); - drm_mode_config_cleanup(dev); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2846f5e8cca3..8c7f48310842 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -156,8 +156,6 @@ struct intel_crtc { int dpms_mode; bool active; /* is the crtc on? independent of the dpms mode */ bool primary_disabled; /* is the crtc obscured by a plane? */ - bool busy; /* is scanout buffer being updated frequently? */ - struct timer_list idle_timer; bool lowfreq_avail; struct intel_overlay *overlay; struct intel_unpin_work *unpin_work; @@ -373,8 +371,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); -extern void intel_mark_busy(struct drm_device *dev, - struct drm_i915_gem_object *obj); +extern void intel_mark_busy(struct drm_device *dev); +extern void intel_mark_idle(struct drm_device *dev); +extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj); +extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj); extern bool intel_lvds_init(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 94aabcaa3a67..85d1b1c57df2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3075,14 +3075,17 @@ EXPORT_SYMBOL_GPL(i915_gpu_lower); bool i915_gpu_busy(void) { struct drm_i915_private *dev_priv; + struct intel_ring_buffer *ring; bool ret = false; + int i; spin_lock(&mchdev_lock); if (!i915_mch_dev) goto out_unlock; dev_priv = i915_mch_dev; - ret = dev_priv->busy; + for_each_ring(ring, dev_priv, i) + ret |= !list_empty(&ring->request_list); out_unlock: spin_unlock(&mchdev_lock); -- cgit v1.2.3 From acbe9475505de68540fab8653131d41d424c4fa3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 26 Jul 2012 11:50:05 +0200 Subject: drm/i915: rip out sanitize_pm again We believe to have squashed all issues around the gen6+ rps interrupt generation and why the gpu sometimes got stuck. With that cleared up, there's no user left for the sanitize_pm infrastructure, so let's just rip it out. Note that 'intel_reg_write 0xa014 0x13070000' is the w/a if we find ourselves stuck again. Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 2 -- drivers/gpu/drm/i915/intel_pm.c | 39 +++++------------------------------- 4 files changed, 5 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0dc89a42a80a..0b2eb17fb381 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -249,7 +249,6 @@ struct drm_i915_display_funcs { void (*update_wm)(struct drm_device *dev); void (*update_sprite_wm)(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); - void (*sanitize_pm)(struct drm_device *dev); void (*update_linetime_wm)(struct drm_device *dev, int pipe, struct drm_display_mode *mode); int (*crtc_mode_set)(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b463829b92eb..17020cdff338 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5929,13 +5929,11 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) void intel_mark_busy(struct drm_device *dev) { - intel_sanitize_pm(dev); i915_update_gfx_val(dev->dev_private); } void intel_mark_idle(struct drm_device *dev) { - intel_sanitize_pm(dev); } void intel_mark_fb_busy(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8c7f48310842..13f0467c1f4d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -390,8 +390,6 @@ extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane); -void intel_sanitize_pm(struct drm_device *dev); - /* intel_panel.c */ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e8727da06b0b..d0ce894ba6e6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2267,6 +2267,11 @@ static void ironlake_disable_drps(struct drm_device *dev) } +/* There's a funny hw issue where the hw returns all 0 when reading from + * GEN6_RP_INTERRUPT_LIMITS. Hence we always need to compute the desired value + * ourselves, instead of doing a rmw cycle (which might result in us clearing + * all limits and the gpu stuck at whatever frequency it is at atm). + */ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val) { u32 limits; @@ -3750,37 +3755,6 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_pch_clock_gating(dev); } -static void gen6_sanitize_pm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits, current_limits; - - gen6_gt_force_wake_get(dev_priv); - - current_limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS); - /* Make sure we continue to get interrupts - * until we hit the minimum or maximum frequencies. - */ - limits = gen6_rps_limits(dev_priv, dev_priv->cur_delay); - - if (current_limits != limits) { - /* Note that the known failure case is to read back 0. */ - DRM_DEBUG_DRIVER("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS " - "expected %08x, was %08x\n", limits, current_limits); - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); - } - - gen6_gt_force_wake_put(dev_priv); -} - -void intel_sanitize_pm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.sanitize_pm) - dev_priv->display.sanitize_pm(dev); -} - /* Starting with Haswell, we have different power wells for * different parts of the GPU. This attempts to enable them all. */ @@ -3866,7 +3840,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = NULL; } dev_priv->display.init_clock_gating = gen6_init_clock_gating; - dev_priv->display.sanitize_pm = gen6_sanitize_pm; } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ if (SNB_READ_WM0_LATENCY()) { @@ -3878,7 +3851,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = NULL; } dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; - dev_priv->display.sanitize_pm = gen6_sanitize_pm; } else if (IS_HASWELL(dev)) { if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = sandybridge_update_wm; @@ -3890,7 +3862,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = NULL; } dev_priv->display.init_clock_gating = haswell_init_clock_gating; - dev_priv->display.sanitize_pm = gen6_sanitize_pm; } else dev_priv->display.update_wm = NULL; } else if (IS_VALLEYVIEW(dev)) { -- cgit v1.2.3 From ab3951eb74e7c33a2f5b7b64d72e82f1eea61571 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Mon, 18 Jun 2012 19:03:38 -0300 Subject: drm/i915: prevent possible pin leak on error path We should not hit this under any sane conditions, but still, this does not looks right. CC: Chris Wilson CC: Daniel Vetter CC: stable@vger.kernel.org Reported-by: Herton Ronaldo Krzesinski Reviewed-by: Chris Wlison Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17020cdff338..2e1f28f38ee9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6317,7 +6317,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, default: WARN_ONCE(1, "unknown plane in flip command\n"); ret = -ENODEV; - goto err; + goto err_unpin; } ret = intel_ring_begin(ring, 4); -- cgit v1.2.3 From c6a828d3269a5d0b9adda1438cf8d7cb2007ca71 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Aug 2012 23:35:35 +0200 Subject: drm/i915: move all rps state into dev_priv->rps This way it's easier so see what belongs together, and what is used by the ilk ips code. Also add some comments that explain the locking. Note that (cur|min|max)_delay need to be duplicated, because they're also used by the ips code. v2: Missed one place that the dev_priv->ips change caught ... Reviewed-by: Ben Widawsky Reviewed-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 11 +++++---- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 18 +++++++++++--- drivers/gpu/drm/i915/i915_irq.c | 32 ++++++++++++------------ drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 47 ++++++++++++++++++------------------ 6 files changed, 63 insertions(+), 49 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9c9e199970af..ed4bc98095b1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1274,7 +1274,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n"); - for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay; + for (gpu_freq = dev_priv->rps.min_delay; + gpu_freq <= dev_priv->rps.max_delay; gpu_freq++) { I915_WRITE(GEN6_PCODE_DATA, gpu_freq); I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | @@ -1712,7 +1713,7 @@ i915_max_freq_read(struct file *filp, return ret; len = snprintf(buf, sizeof(buf), - "max freq: %d\n", dev_priv->max_delay * 50); + "max freq: %d\n", dev_priv->rps.max_delay * 50); mutex_unlock(&dev->struct_mutex); if (len > sizeof(buf)) @@ -1755,7 +1756,7 @@ i915_max_freq_write(struct file *filp, /* * Turbo will still be enabled, but won't go above the set value. */ - dev_priv->max_delay = val / 50; + dev_priv->rps.max_delay = val / 50; gen6_set_rps(dev, val / 50); mutex_unlock(&dev->struct_mutex); @@ -1788,7 +1789,7 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, return ret; len = snprintf(buf, sizeof(buf), - "min freq: %d\n", dev_priv->min_delay * 50); + "min freq: %d\n", dev_priv->rps.min_delay * 50); mutex_unlock(&dev->struct_mutex); if (len > sizeof(buf)) @@ -1829,7 +1830,7 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, /* * Turbo will still be enabled, but won't go below the set value. */ - dev_priv->min_delay = val / 50; + dev_priv->rps.min_delay = val / 50; gen6_set_rps(dev, val / 50); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a7a213cf06fb..0a1b64f8d442 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1605,7 +1605,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->error_lock); - spin_lock_init(&dev_priv->rps_lock); + spin_lock_init(&dev_priv->rps.lock); if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 26a2cf6da3a2..1614097f975a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -819,9 +819,21 @@ typedef struct drm_i915_private { bool mchbar_need_disable; - struct work_struct rps_work; - spinlock_t rps_lock; - u32 pm_iir; + /* gen6+ rps state */ + struct { + struct work_struct work; + u32 pm_iir; + /* lock - irqsave spinlock that protectects the work_struct and + * pm_iir. */ + spinlock_t lock; + + /* The below variables an all the rps hw state are protected by + * dev->struct mutext. */ + u8 cur_delay; + u8 min_delay; + u8 max_delay; + } rps; + u8 cur_delay; u8 min_delay; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 440c9051aa9b..74c9a0e52507 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -349,16 +349,16 @@ static void notify_ring(struct drm_device *dev, static void gen6_pm_rps_work(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - rps_work); + rps.work); u32 pm_iir, pm_imr; u8 new_delay; - spin_lock_irq(&dev_priv->rps_lock); - pm_iir = dev_priv->pm_iir; - dev_priv->pm_iir = 0; + spin_lock_irq(&dev_priv->rps.lock); + pm_iir = dev_priv->rps.pm_iir; + dev_priv->rps.pm_iir = 0; pm_imr = I915_READ(GEN6_PMIMR); I915_WRITE(GEN6_PMIMR, 0); - spin_unlock_irq(&dev_priv->rps_lock); + spin_unlock_irq(&dev_priv->rps.lock); if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) return; @@ -366,9 +366,9 @@ static void gen6_pm_rps_work(struct work_struct *work) mutex_lock(&dev_priv->dev->struct_mutex); if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) - new_delay = dev_priv->cur_delay + 1; + new_delay = dev_priv->rps.cur_delay + 1; else - new_delay = dev_priv->cur_delay - 1; + new_delay = dev_priv->rps.cur_delay - 1; gen6_set_rps(dev_priv->dev, new_delay); @@ -488,20 +488,20 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, * IIR bits should never already be set because IMR should * prevent an interrupt from being shown in IIR. The warning * displays a case where we've unsafely cleared - * dev_priv->pm_iir. Although missing an interrupt of the same + * dev_priv->rps.pm_iir. Although missing an interrupt of the same * type is not a problem, it displays a problem in the logic. * - * The mask bit in IMR is cleared by rps_work. + * The mask bit in IMR is cleared by dev_priv->rps.work. */ - spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); + spin_lock_irqsave(&dev_priv->rps.lock, flags); + WARN(dev_priv->rps.pm_iir & pm_iir, "Missed a PM interrupt\n"); + dev_priv->rps.pm_iir |= pm_iir; + I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps_lock, flags); + spin_unlock_irqrestore(&dev_priv->rps.lock, flags); - queue_work(dev_priv->wq, &dev_priv->rps_work); + queue_work(dev_priv->wq, &dev_priv->rps.work); } static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) @@ -2649,7 +2649,7 @@ void intel_irq_init(struct drm_device *dev) INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); INIT_WORK(&dev_priv->error_work, i915_error_work_func); - INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work); + INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work); dev->driver->get_vblank_counter = i915_get_vblank_counter; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e1f28f38ee9..bddb29002c03 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7218,7 +7218,7 @@ void intel_modeset_cleanup(struct drm_device *dev) * enqueue unpin/hotplug work. */ drm_irq_uninstall(dev); cancel_work_sync(&dev_priv->hotplug_work); - cancel_work_sync(&dev_priv->rps_work); + cancel_work_sync(&dev_priv->rps.work); /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4fe8d0a9975b..e1439ae3556b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2277,9 +2277,10 @@ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 *val) u32 limits; limits = 0; - if (*val >= dev_priv->max_delay) - *val = dev_priv->max_delay; - limits |= dev_priv->max_delay << 24; + + if (*val >= dev_priv->rps.max_delay) + *val = dev_priv->rps.max_delay; + limits |= dev_priv->rps.max_delay << 24; /* Only set the down limit when we've reached the lowest level to avoid * getting more interrupts, otherwise leave this clear. This prevents a @@ -2287,9 +2288,9 @@ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 *val) * the hw runs at the minimal clock before selecting the desired * frequency, if the down threshold expires in that window we will not * receive a down interrupt. */ - if (*val <= dev_priv->min_delay) { - *val = dev_priv->min_delay; - limits |= dev_priv->min_delay << 16; + if (*val <= dev_priv->rps.min_delay) { + *val = dev_priv->rps.min_delay; + limits |= dev_priv->rps.min_delay << 16; } return limits; @@ -2302,7 +2303,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val) WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - if (val == dev_priv->cur_delay) + if (val == dev_priv->rps.cur_delay) return; I915_WRITE(GEN6_RPNSWREQ, @@ -2315,7 +2316,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val) */ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); - dev_priv->cur_delay = val; + dev_priv->rps.cur_delay = val; } static void gen6_disable_rps(struct drm_device *dev) @@ -2331,9 +2332,9 @@ static void gen6_disable_rps(struct drm_device *dev) * register (PMIMR) to mask PM interrupts. The only risk is in leaving * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ - spin_lock_irq(&dev_priv->rps_lock); - dev_priv->pm_iir = 0; - spin_unlock_irq(&dev_priv->rps_lock); + spin_lock_irq(&dev_priv->rps.lock); + dev_priv->rps.pm_iir = 0; + spin_unlock_irq(&dev_priv->rps.lock); I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); } @@ -2402,9 +2403,9 @@ static void gen6_enable_rps(struct drm_device *dev) gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); /* In units of 100MHz */ - dev_priv->max_delay = rp_state_cap & 0xff; - dev_priv->min_delay = (rp_state_cap & 0xff0000) >> 16; - dev_priv->cur_delay = 0; + dev_priv->rps.max_delay = rp_state_cap & 0xff; + dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16; + dev_priv->rps.cur_delay = 0; /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -2457,8 +2458,8 @@ static void gen6_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, - dev_priv->max_delay << 24 | - dev_priv->min_delay << 16); + dev_priv->rps.max_delay << 24 | + dev_priv->rps.min_delay << 16); if (IS_HASWELL(dev)) { I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400); @@ -2503,7 +2504,7 @@ static void gen6_enable_rps(struct drm_device *dev) 500)) DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); if (pcu_mbox & (1<<31)) { /* OC supported */ - dev_priv->max_delay = pcu_mbox & 0xff; + dev_priv->rps.max_delay = pcu_mbox & 0xff; DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); } @@ -2511,10 +2512,10 @@ static void gen6_enable_rps(struct drm_device *dev) /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); - spin_lock_irq(&dev_priv->rps_lock); - WARN_ON(dev_priv->pm_iir != 0); + spin_lock_irq(&dev_priv->rps.lock); + WARN_ON(dev_priv->rps.pm_iir != 0); I915_WRITE(GEN6_PMIMR, 0); - spin_unlock_irq(&dev_priv->rps_lock); + spin_unlock_irq(&dev_priv->rps.lock); /* enable all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); @@ -2546,9 +2547,9 @@ static void gen6_update_ring_freq(struct drm_device *dev) * to use for memory access. We do this by specifying the IA frequency * the PCU should use as a reference to determine the ring frequency. */ - for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay; + for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay; gpu_freq--) { - int diff = dev_priv->max_delay - gpu_freq; + int diff = dev_priv->rps.max_delay - gpu_freq; /* * For GPU frequencies less than 750MHz, just use the lowest @@ -2991,7 +2992,7 @@ unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) assert_spin_locked(&mchdev_lock); - pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); + pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_delay * 4)); pxvid = (pxvid >> 24) & 0x7f; ext_v = pvid_to_extvid(dev_priv, pxvid); -- cgit v1.2.3 From 228d3e367c91af16d672fb8bff78b030acb5efc3 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 10 Aug 2012 10:05:10 -0300 Subject: drm/i915: use the correct encoder type when comparing - intel_encoder->type is INTEL_OUTPUT_SOMETHING - drm_encoder->encoder_type is DRM_MODE_ENCODER_SOMETHING Here we're using intel_encoder, so compare the oranges against oranges. While at it, rename the variable to "intel_encoder" so we keep our naming standards used everywhere. Luckily this was not a bug because both DRM_MODE_ENCODER_DAC and INTEL_OUTPUT_ANALOG are defined as 1. This is the only case where the drm definition matches the intel definition. Signed-off-by: Paulo Zanoni Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bddb29002c03..e3afe9688905 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2837,13 +2837,13 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) static bool intel_crtc_driving_pch(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct intel_encoder *encoder; + struct intel_encoder *intel_encoder; /* * If there's a non-PCH eDP on this crtc, it must be DP_A, and that * must be driven by its own crtc; no sharing is possible. */ - for_each_encoder_on_crtc(dev, crtc, encoder) { + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { /* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell * CPU handles all others */ @@ -2851,19 +2851,19 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc) /* It is still unclear how this will work on PPT, so throw up a warning */ WARN_ON(!HAS_PCH_LPT(dev)); - if (encoder->type == DRM_MODE_ENCODER_DAC) { + if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n"); return true; } else { DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n", - encoder->type); + intel_encoder->type); return false; } } - switch (encoder->type) { + switch (intel_encoder->type) { case INTEL_OUTPUT_EDP: - if (!intel_encoder_is_pch_edp(&encoder->base)) + if (!intel_encoder_is_pch_edp(&intel_encoder->base)) return false; continue; } -- cgit v1.2.3 From e9a851ed634628489ca4a392740694d0ded78cb9 Mon Sep 17 00:00:00 2001 From: "Xu, Anhua" Date: Mon, 13 Aug 2012 03:08:33 +0000 Subject: drm/i915: fix wrong order of parameters in port checking functions Wrong order of parameters passed-in when calling hdmi/adpa /lvds_pipe_enabled(), 2nd and 3rd parameters are reversed. This bug was indroduced by commit 1519b9956eb4b4180fa3f47c73341463cdcfaa37 Author: Keith Packard Date: Sat Aug 6 10:35:34 2011 -0700 drm/i915: Fix PCH port pipe select in CPT disable paths The reachable tag for this commit is v3.1-rc1-3-g1519b99 Signed-off-by: Anhua Xu Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a9ab1aff2c77..46a4c921a174 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1384,7 +1384,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - WARN(hdmi_pipe_enabled(dev_priv, val, pipe), + WARN(hdmi_pipe_enabled(dev_priv, pipe, val), "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); @@ -1404,13 +1404,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - WARN(adpa_pipe_enabled(dev_priv, val, pipe), + WARN(adpa_pipe_enabled(dev_priv, pipe, val), "PCH VGA enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); reg = PCH_LVDS; val = I915_READ(reg); - WARN(lvds_pipe_enabled(dev_priv, val, pipe), + WARN(lvds_pipe_enabled(dev_priv, pipe, val), "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); @@ -1874,7 +1874,7 @@ 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(dev_priv, val, pipe)) { + if (hdmi_pipe_enabled(dev_priv, pipe, val)) { DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n", reg, pipe); I915_WRITE(reg, val & ~PORT_ENABLE); @@ -1896,12 +1896,12 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - if (adpa_pipe_enabled(dev_priv, val, pipe)) + if (adpa_pipe_enabled(dev_priv, pipe, val)) I915_WRITE(reg, val & ~ADPA_DAC_ENABLE); reg = PCH_LVDS; val = I915_READ(reg); - if (lvds_pipe_enabled(dev_priv, val, pipe)) { + if (lvds_pipe_enabled(dev_priv, pipe, val)) { DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val); I915_WRITE(reg, val & ~LVDS_PORT_EN); POSTING_READ(reg); -- cgit v1.2.3 From dcdaed6eae0d7ed0c68aaa1ebfceb242625b3bf0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Aug 2012 21:19:34 +0200 Subject: drm/i915: add missing gen2 pipe A quirk entries For some odd reason we've missed i830 and a i855 variant. Also kill the two now redundant i830 entries. v2: Don't add the missing 855 id to the pipe A quirk list, we seem to lack justification for it. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 46a4c921a174..dd760f43f577 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7017,21 +7017,16 @@ static struct intel_quirk intel_quirks[] = { /* HP Mini needs pipe A force quirk (LP: #322104) */ { 0x27ae, 0x103c, 0x361a, quirk_pipea_force }, - /* Thinkpad R31 needs pipe A force quirk */ - { 0x3577, 0x1014, 0x0505, quirk_pipea_force }, /* Toshiba Protege R-205, S-209 needs pipe A force quirk */ { 0x2592, 0x1179, 0x0001, quirk_pipea_force }, - /* ThinkPad X30 needs pipe A force quirk (LP: #304614) */ - { 0x3577, 0x1014, 0x0513, quirk_pipea_force }, - /* ThinkPad X40 needs pipe A force quirk */ - /* ThinkPad T60 needs pipe A force quirk (bug #16494) */ { 0x2782, 0x17aa, 0x201a, quirk_pipea_force }, /* 855 & before need to leave pipe A & dpll A up */ { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, + { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force }, /* Lenovo U160 cannot use SSC on LVDS */ { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable }, -- cgit v1.2.3 From a37b9b349ef26cb44f0e8d59c3efbcd9485018b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Aug 2012 19:27:09 +0200 Subject: drm/i915/ns2501: kill pll A enabling hack With the pipe A quirk properly fixed up for i830M, this shouldn't be required any longer. Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo_ns2501.c | 7 ------- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index 1a0bad9a5fab..6bd383dfbb09 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -74,11 +74,6 @@ struct ns2501_priv { #define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr)) -/* - * Include the PLL launcher prototype - */ -extern void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); - /* * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens * laptops does not react on the i2c bus unless @@ -113,8 +108,6 @@ static void enable_dvo(struct intel_dvo_device *dvo) I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768 I915_WRITE(FW_BLC, 0x1080304); - intel_enable_pll(dev_priv, 0); - I915_WRITE(DVOC, 0x90004084); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dd760f43f577..a55f6642be20 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1432,7 +1432,7 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, * * Unfortunately needed by dvo_ns2501 since the dvo depends on it running. */ -void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { int reg; u32 val; -- cgit v1.2.3 From 24218aacac65f5b731bbff8eeb09ea7847dda2ef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Aug 2012 19:27:11 +0200 Subject: drm/i915: prepare load-detect pipe code for dpms changes A few things need adjustement: - Change the dpms state by calling the dpms connector function and not some crtc helper internal callbacks. Otherwise this will break once we switch to our own dpms handling. - Instead of tracking and restoring intel_crtc->dpms_mode use the connector's dpms variable - the former relies on the dpms compuation rules used by the crtc helper. And it would break when the encoder is cloned and the other output has a different dpms state. But luckily no one is crazy enough for that. - Properly clear the connector -> encoder -> crtc linking, even when failing (note that the crtc helper removes the encoder -> crtc link in disabled_unused_functions for us). Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 38 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a55f6642be20..f851474fe066 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5615,21 +5615,12 @@ bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, if (encoder->crtc) { crtc = encoder->crtc; - intel_crtc = to_intel_crtc(crtc); - old->dpms_mode = intel_crtc->dpms_mode; + old->dpms_mode = connector->dpms; old->load_detect_temp = false; /* Make sure the crtc and connector are running */ - if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { - struct drm_encoder_helper_funcs *encoder_funcs; - struct drm_crtc_helper_funcs *crtc_funcs; - - crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - - encoder_funcs = encoder->helper_private; - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - } + if (connector->dpms != DRM_MODE_DPMS_ON) + connector->funcs->dpms(connector, DRM_MODE_DPMS_ON); return true; } @@ -5657,7 +5648,7 @@ bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, connector->encoder = encoder; intel_crtc = to_intel_crtc(crtc); - old->dpms_mode = intel_crtc->dpms_mode; + old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -5682,22 +5673,25 @@ bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); if (IS_ERR(crtc->fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); - crtc->fb = old_fb; - return false; + goto fail; } if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); - crtc->fb = old_fb; - return false; + goto fail; } /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev, intel_crtc->pipe); return true; +fail: + connector->encoder = NULL; + encoder->crtc = NULL; + crtc->fb = old_fb; + return false; } void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, @@ -5706,9 +5700,6 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, { struct drm_encoder *encoder = &intel_encoder->base; struct drm_device *dev = encoder->dev; - struct drm_crtc *crtc = encoder->crtc; - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, drm_get_connector_name(connector), @@ -5716,6 +5707,7 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, if (old->load_detect_temp) { connector->encoder = NULL; + encoder->crtc = NULL; drm_helper_disable_unused_functions(dev); if (old->release_fb) @@ -5725,10 +5717,8 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, } /* Switch crtc and encoder back off if necessary */ - if (old->dpms_mode != DRM_MODE_DPMS_ON) { - encoder_funcs->dpms(encoder, old->dpms_mode); - crtc_funcs->dpms(crtc, old->dpms_mode); - } + if (old->dpms_mode != DRM_MODE_DPMS_ON) + connector->funcs->dpms(connector, old->dpms_mode); } /* Returns the clock of the currently programmed mode of the given pipe. */ -- cgit v1.2.3 From d2434ab7fb085ac6848acd9d82366f96a642e471 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Aug 2012 21:20:10 +0200 Subject: drm/i915: drop intel_encoder argument to load_detect_pipe functions Since it's redundant - we can get the attached encoder in the functions themselves. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 6 ++---- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- drivers/gpu/drm/i915/intel_drv.h | 6 ++---- drivers/gpu/drm/i915/intel_tv.c | 7 ++----- 4 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index bc5e2c97db61..62b6555cfa27 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -517,14 +517,12 @@ intel_crt_detect(struct drm_connector *connector, bool force) return connector->status; /* for pre-945g platforms use load detect */ - if (intel_get_load_detect_pipe(&crt->base, connector, NULL, - &tmp)) { + if (intel_get_load_detect_pipe(connector, NULL, &tmp)) { if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else status = intel_crt_load_detect(crt); - intel_release_load_detect_pipe(&crt->base, connector, - &tmp); + intel_release_load_detect_pipe(connector, &tmp); } else status = connector_status_unknown; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f851474fe066..62524b036bd1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5584,12 +5584,13 @@ mode_fits_in_fbdev(struct drm_device *dev, return fb; } -bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, +bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, struct intel_load_detect_pipe *old) { struct intel_crtc *intel_crtc; + struct intel_encoder *intel_encoder = + intel_attached_encoder(connector); struct drm_crtc *possible_crtc; struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = NULL; @@ -5694,10 +5695,11 @@ fail: return false; } -void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, +void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old) { + struct intel_encoder *intel_encoder = + intel_attached_encoder(connector); struct drm_encoder *encoder = &intel_encoder->base; struct drm_device *dev = encoder->dev; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6920bc26a2e9..95f635b70b5b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -433,12 +433,10 @@ struct intel_load_detect_pipe { bool load_detect_temp; int dpms_mode; }; -extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, +extern bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, struct intel_load_detect_pipe *old); -extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, - struct drm_connector *connector, +extern void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old); extern void intelfb_restore(void); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 1a0bab07699e..95653a508987 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1303,12 +1303,9 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (force) { struct intel_load_detect_pipe tmp; - if (intel_get_load_detect_pipe(&intel_tv->base, connector, - &mode, &tmp)) { + if (intel_get_load_detect_pipe(connector, &mode, &tmp)) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(&intel_tv->base, - connector, - &tmp); + intel_release_load_detect_pipe(connector, &tmp); } else return connector_status_unknown; } else -- cgit v1.2.3 From 88cefb6c60712982f739f6bbd9f82968aca46033 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 12 Aug 2012 19:27:14 +0200 Subject: drm/i915: extract ironlake_fdi_pll_disable Simply to make the ilk+ crtc disable path clearer and more symmetric with the enable function. Also switch to intel_crtc for the enable function. Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 57 +++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 62524b036bd1..b580d949d7d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2709,11 +2709,10 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } -static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) +static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; u32 reg, temp; @@ -2754,6 +2753,35 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) } } +static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = intel_crtc->pipe; + u32 reg, temp; + + /* Switch from PCDclk to Rawclk */ + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_PCDCLK); + + /* Disable CPU FDI TX PLL */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE); + + POSTING_READ(reg); + udelay(100); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE); + + /* Wait for the clocks to turn off. */ + POSTING_READ(reg); + udelay(100); +} + static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3201,7 +3229,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) is_pch_port = intel_crtc_driving_pch(crtc); if (is_pch_port) - ironlake_fdi_pll_enable(crtc); + ironlake_fdi_pll_enable(intel_crtc); else ironlake_fdi_disable(crtc); @@ -3304,26 +3332,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) /* disable PCH DPLL */ intel_disable_pch_pll(intel_crtc); - /* Switch from PCDclk to Rawclk */ - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_PCDCLK); - - /* Disable CPU FDI TX PLL */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE); - - POSTING_READ(reg); - udelay(100); - - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE); - - /* Wait for the clocks to turn off. */ - POSTING_READ(reg); - udelay(100); + ironlake_fdi_pll_disable(intel_crtc); intel_crtc->active = false; intel_update_watermarks(dev); -- cgit v1.2.3 From 9b138a83675364366388af8b6986b2e52be36bcc Mon Sep 17 00:00:00 2001 From: Wang Xingchao Date: Thu, 9 Aug 2012 16:52:18 +0800 Subject: drm/i915: ironlake_write_eld code cleanup Use _PIPE macro to get correct register definition for IBX/CPT, discard old variable "i" way. Signed-off-by: Wang Xingchao Reviewed-by: Imre Deak [danvet: Added the DIP_PORT_SEL #define from a preceeding patch in the series that needs more work.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 25 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 22 +++++++++------------- 2 files changed, 34 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cbddc7d8e169..fd6a26a49b42 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4247,7 +4247,15 @@ #define G4X_HDMIW_HDMIEDID 0x6210C #define IBX_HDMIW_HDMIEDID_A 0xE2050 +#define IBX_HDMIW_HDMIEDID_B 0xE2150 +#define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ + IBX_HDMIW_HDMIEDID_A, \ + IBX_HDMIW_HDMIEDID_B) #define IBX_AUD_CNTL_ST_A 0xE20B4 +#define IBX_AUD_CNTL_ST_B 0xE21B4 +#define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \ + IBX_AUD_CNTL_ST_A, \ + IBX_AUD_CNTL_ST_B) #define IBX_ELD_BUFFER_SIZE (0x1f << 10) #define IBX_ELD_ADDRESS (0x1f << 5) #define IBX_ELD_ACK (1 << 4) @@ -4256,7 +4264,15 @@ #define IBX_CP_READYB (1 << 1) #define CPT_HDMIW_HDMIEDID_A 0xE5050 +#define CPT_HDMIW_HDMIEDID_B 0xE5150 +#define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ + CPT_HDMIW_HDMIEDID_A, \ + CPT_HDMIW_HDMIEDID_B) #define CPT_AUD_CNTL_ST_A 0xE50B4 +#define CPT_AUD_CNTL_ST_B 0xE51B4 +#define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \ + CPT_AUD_CNTL_ST_A, \ + CPT_AUD_CNTL_ST_B) #define CPT_AUD_CNTRL_ST2 0xE50C0 /* These are the 4 32-bit write offset registers for each stream @@ -4266,7 +4282,15 @@ #define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4) #define IBX_AUD_CONFIG_A 0xe2000 +#define IBX_AUD_CONFIG_B 0xe2100 +#define IBX_AUD_CFG(pipe) _PIPE(pipe, \ + IBX_AUD_CONFIG_A, \ + IBX_AUD_CONFIG_B) #define CPT_AUD_CONFIG_A 0xe5000 +#define CPT_AUD_CONFIG_B 0xe5100 +#define CPT_AUD_CFG(pipe) _PIPE(pipe, \ + CPT_AUD_CONFIG_A, \ + CPT_AUD_CONFIG_B) #define AUD_CONFIG_N_VALUE_INDEX (1 << 29) #define AUD_CONFIG_N_PROG_ENABLE (1 << 28) #define AUD_CONFIG_UPPER_N_SHIFT 20 @@ -4302,6 +4326,7 @@ #define AUD_DIG_CNVT(pipe) _PIPE(pipe, \ HSW_AUD_DIG_CNVT_1, \ HSW_AUD_DIG_CNVT_2) +#define DIP_PORT_SEL_MASK 0x3 #define HSW_AUD_EDID_DATA_A 0x65050 #define HSW_AUD_EDID_DATA_B 0x65150 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b580d949d7d2..f55e024c6df9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5078,28 +5078,24 @@ static void ironlake_write_eld(struct drm_connector *connector, int aud_config; int aud_cntl_st; int aud_cntrl_st2; + int pipe = to_intel_crtc(crtc)->pipe; if (HAS_PCH_IBX(connector->dev)) { - hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A; - aud_config = IBX_AUD_CONFIG_A; - aud_cntl_st = IBX_AUD_CNTL_ST_A; + hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); + aud_config = IBX_AUD_CFG(pipe); + aud_cntl_st = IBX_AUD_CNTL_ST(pipe); aud_cntrl_st2 = IBX_AUD_CNTL_ST2; } else { - hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A; - aud_config = CPT_AUD_CONFIG_A; - aud_cntl_st = CPT_AUD_CNTL_ST_A; + hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe); + aud_config = CPT_AUD_CFG(pipe); + aud_cntl_st = CPT_AUD_CNTL_ST(pipe); aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; } - i = to_intel_crtc(crtc)->pipe; - hdmiw_hdmiedid += i * 0x100; - aud_cntl_st += i * 0x100; - aud_config += i * 0x100; - - DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i)); + DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); i = I915_READ(aud_cntl_st); - i = (i >> 29) & 0x3; /* DIP_Port_Select, 0x1 = PortB */ + i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ if (!i) { DRM_DEBUG_DRIVER("Audio directed to unknown port\n"); /* operate blindly on all ports */ -- cgit v1.2.3 From 523313092abffb21bfe7cd8d37615402b2228850 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 15 Aug 2012 19:23:25 +0100 Subject: drm/i915: Don't hardcode the number of pipes in the error state dump New-ish devices have 3 pipes, so let's not just hardcode 2 but use the for_each_pipe() macro and make struct intel_display_error_state is big enough. V2: Also add the number of pipes emitted (Chris Wilson) Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f55e024c6df9..7a1c19756884 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7234,7 +7234,7 @@ struct intel_display_error_state { u32 position; u32 base; u32 size; - } cursor[2]; + } cursor[I915_MAX_PIPES]; struct intel_pipe_error_state { u32 conf; @@ -7246,7 +7246,7 @@ struct intel_display_error_state { u32 vtotal; u32 vblank; u32 vsync; - } pipe[2]; + } pipe[I915_MAX_PIPES]; struct intel_plane_error_state { u32 control; @@ -7256,7 +7256,7 @@ struct intel_display_error_state { u32 addr; u32 surface; u32 tile_offset; - } plane[2]; + } plane[I915_MAX_PIPES]; }; struct intel_display_error_state * @@ -7270,7 +7270,7 @@ intel_display_capture_error_state(struct drm_device *dev) if (error == NULL) return NULL; - for (i = 0; i < 2; i++) { + for_each_pipe(i) { error->cursor[i].control = I915_READ(CURCNTR(i)); error->cursor[i].position = I915_READ(CURPOS(i)); error->cursor[i].base = I915_READ(CURBASE(i)); @@ -7303,9 +7303,11 @@ intel_display_print_error_state(struct seq_file *m, struct drm_device *dev, struct intel_display_error_state *error) { + drm_i915_private_t *dev_priv = dev->dev_private; int i; - for (i = 0; i < 2; i++) { + seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe); + for_each_pipe(i) { seq_printf(m, "Pipe [%d]:\n", i); seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); seq_printf(m, " SRC: %08x\n", error->pipe[i].source); -- cgit v1.2.3 From 83358c85866ebd2af1229fc9870b93e126690671 Mon Sep 17 00:00:00 2001 From: Wang Xingchao Date: Thu, 16 Aug 2012 22:43:37 +0800 Subject: drm/i915: Haswell HDMI audio initialization Added new haswell_write_eld() to initialize Haswell HDMI audio registers to generate an unsolicited response to the audio controller driver to indicate that the controller sequence should start. Reviewed-by: Imre Deak Signed-off-by: Wang Xingchao Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 87 +++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7a1c19756884..42c57581c53f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5066,6 +5066,91 @@ static void g4x_write_eld(struct drm_connector *connector, I915_WRITE(G4X_AUD_CNTL_ST, i); } +static void haswell_write_eld(struct drm_connector *connector, + struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = connector->dev->dev_private; + uint8_t *eld = connector->eld; + struct drm_device *dev = crtc->dev; + uint32_t eldv; + uint32_t i; + int len; + int pipe = to_intel_crtc(crtc)->pipe; + int tmp; + + int hdmiw_hdmiedid = HSW_AUD_EDID_DATA(pipe); + int aud_cntl_st = HSW_AUD_DIP_ELD_CTRL(pipe); + int aud_config = HSW_AUD_CFG(pipe); + int aud_cntrl_st2 = HSW_AUD_PIN_ELD_CP_VLD; + + + DRM_DEBUG_DRIVER("HDMI: Haswell Audio initialize....\n"); + + /* Audio output enable */ + DRM_DEBUG_DRIVER("HDMI audio: enable codec\n"); + tmp = I915_READ(aud_cntrl_st2); + tmp |= (AUDIO_OUTPUT_ENABLE_A << (pipe * 4)); + I915_WRITE(aud_cntrl_st2, tmp); + + /* Wait for 1 vertical blank */ + intel_wait_for_vblank(dev, pipe); + + /* Set ELD valid state */ + tmp = I915_READ(aud_cntrl_st2); + DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp); + tmp |= (AUDIO_ELD_VALID_A << (pipe * 4)); + I915_WRITE(aud_cntrl_st2, tmp); + tmp = I915_READ(aud_cntrl_st2); + DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp); + + /* Enable HDMI mode */ + tmp = I915_READ(aud_config); + DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp); + /* clear N_programing_enable and N_value_index */ + tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE); + I915_WRITE(aud_config, tmp); + + DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); + + eldv = AUDIO_ELD_VALID_A << (pipe * 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 */ + I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */ + } else + I915_WRITE(aud_config, 0); + + 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); + + if (!eld[0]) + return; + + i = I915_READ(aud_cntl_st); + i &= ~IBX_ELD_ADDRESS; + I915_WRITE(aud_cntl_st, i); + i = (i >> 29) & DIP_PORT_SEL_MASK; /* DIP_Port_Select, 0x1 = PortB */ + DRM_DEBUG_DRIVER("port num:%d\n", i); + + len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */ + DRM_DEBUG_DRIVER("ELD size %d\n", len); + for (i = 0; i < len; i++) + I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + + i = I915_READ(aud_cntrl_st2); + i |= eldv; + I915_WRITE(aud_cntrl_st2, i); + +} + static void ironlake_write_eld(struct drm_connector *connector, struct drm_crtc *crtc) { @@ -6936,7 +7021,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.write_eld = ironlake_write_eld; } else if (IS_HASWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; - dev_priv->display.write_eld = ironlake_write_eld; + dev_priv->display.write_eld = haswell_write_eld; } else dev_priv->display.update_wm = NULL; } else if (IS_G4X(dev)) { -- cgit v1.2.3 From 44f46b4222a9ba5b21dcdf13f93dc53f48768d2b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 21 Jun 2012 13:19:59 +0300 Subject: drm/i915: Cantiga+ cannot handle a hsync front porch of 0 This addresses WaPruneModeWithIncorrectHsyncOffset. Bugzilla: http://bugs.freedesktop.org/show_bug.cgi?id=50236 Signed-off-by: Chris Wilson Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 42c57581c53f..778cbb88bddc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3602,6 +3602,13 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET)) drm_mode_set_crtcinfo(adjusted_mode, 0); + /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes + * with a hsync front porch of 0. + */ + if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && + adjusted_mode->hsync_start == adjusted_mode->hdisplay) + return false; + return true; } -- cgit v1.2.3 From 76e5a89c0a01c43b09512da633910dd0d8b398be Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 29 Jun 2012 22:39:33 +0200 Subject: drm/i915: add crtc->enable/disable vfuncs insted of dpms Because that's what we're essentially calling. This is the first step in untangling the crtc_helper induced dpms handling mess we have - at the crtc level we only have 2 states and the magic is just in selecting which one (and atm there isn't even much magic, but on recent platforms where not even the crt output has more than 2 states we could do better). Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 62 +++++++++++------------------------- 2 files changed, 20 insertions(+), 45 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ed3ba70923ac..fb46c6f356e4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -240,7 +240,6 @@ struct drm_i915_error_state { }; struct drm_i915_display_funcs { - void (*dpms)(struct drm_crtc *crtc, int mode); bool (*fbc_enabled)(struct drm_device *dev); void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); void (*disable_fbc)(struct drm_device *dev); @@ -256,6 +255,8 @@ struct drm_i915_display_funcs { struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); + void (*crtc_enable)(struct drm_crtc *crtc); + void (*crtc_disable)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc); void (*write_eld)(struct drm_connector *connector, struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 42c57581c53f..adc98680b693 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3342,30 +3342,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; - - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane); - ironlake_crtc_enable(crtc); - break; - - case DRM_MODE_DPMS_OFF: - DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); - ironlake_crtc_disable(crtc); - break; - } -} - static void ironlake_crtc_off(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -3445,23 +3421,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_update_watermarks(dev); } -static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - i9xx_crtc_enable(crtc); - break; - case DRM_MODE_DPMS_OFF: - i9xx_crtc_disable(crtc); - break; - } -} - static void i9xx_crtc_off(struct drm_crtc *crtc) { } @@ -3483,7 +3442,20 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc->dpms_mode = mode; - dev_priv->display.dpms(crtc, mode); + /* XXX: When our outputs are all unaware of DPMS modes other than off + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. + */ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + dev_priv->display.crtc_enable(crtc); + break; + + case DRM_MODE_DPMS_OFF: + dev_priv->display.crtc_disable(crtc); + break; + } if (!dev->primary->master) return; @@ -6971,13 +6943,15 @@ static void intel_init_display(struct drm_device *dev) /* We always want a DPMS function */ if (HAS_PCH_SPLIT(dev)) { - dev_priv->display.dpms = ironlake_crtc_dpms; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; + dev_priv->display.crtc_enable = ironlake_crtc_enable; + dev_priv->display.crtc_disable = ironlake_crtc_disable; dev_priv->display.off = ironlake_crtc_off; dev_priv->display.update_plane = ironlake_update_plane; } else { - dev_priv->display.dpms = i9xx_crtc_dpms; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.crtc_enable = i9xx_crtc_enable; + dev_priv->display.crtc_disable = i9xx_crtc_disable; dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_plane = i9xx_update_plane; } -- cgit v1.2.3 From eae307a5304f8c0956b8eab75596abba7ad58a5c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 29 Jun 2012 22:53:09 +0200 Subject: drm/i915: rip out crtc prepare/commit indirection Just impendance matching with the the crtc helper stuff. ... and somehow the design of this all ended up in this commit here, too ;-) The big plan is that this new set of crtc display_funcs take full responsibility of modeset operations for the entire display output pipeline (by calling down into object-specific callbacks and functions). The platform-specific callbacks simply know best what the proper order is. This has the drawback that we can't do minimal change-overs any more if a modeset just disables one encoder in a cloned configuration (because we will only expose a disable/enable action that takes down/sets up the entire crtc including all encoders). Imo that's the only sane way to do it though: - The use-case for this is pretty minimal, even when presenting (at least sane people) should use a dual-screen output so that you can see your notes on your panel. Clone mode is imo BS. - With all the clone mode constrains, shared resources, and special ordering requirements (which differ even on the same platform sometimes for different outputs) there's no way we'd get this right for all cases. Especially since this is a under-used feature. - And to top it off: On haswell even dp link re-training requires us to take down the entire display pipe - otherwise the chip dies. So the only sane way is to do a full modeset on every crtc where the output config changes in any way. To support global modeset (i.e. set the configuration for all crtcs at once) we'd then add one more function to allocate global and shared objects in the best ways (e.g. fdi links, pch plls, ...). The crtc functions would then simply use the pre-allocated stuff (and shouldn't be able to fail, ever). We could even do all the object pinning in there (and maybe try to defragment the global gtt if we fail)! Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 37 ++---------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index adc98680b693..04bec4bd0acb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3500,34 +3500,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc) } } -/* Prepare for a mode set. - * - * Note we could be a lot smarter here. We need to figure out which outputs - * will be enabled, which disabled (in short, how the config will changes) - * and perform the minimum necessary steps to accomplish that, e.g. updating - * watermarks, FBC configuration, making sure PLLs are programmed correctly, - * panel fitting is in the proper state, etc. - */ -static void i9xx_crtc_prepare(struct drm_crtc *crtc) -{ - i9xx_crtc_disable(crtc); -} - -static void i9xx_crtc_commit(struct drm_crtc *crtc) -{ - i9xx_crtc_enable(crtc); -} - -static void ironlake_crtc_prepare(struct drm_crtc *crtc) -{ - ironlake_crtc_disable(crtc); -} - -static void ironlake_crtc_commit(struct drm_crtc *crtc) -{ - ironlake_crtc_enable(crtc); -} - void intel_encoder_prepare(struct drm_encoder *encoder) { struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -6626,13 +6598,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->active = true; /* force the pipe off on setup_init_config */ intel_crtc->bpp = 24; /* default for pre-Ironlake */ - if (HAS_PCH_SPLIT(dev)) { - intel_helper_funcs.prepare = ironlake_crtc_prepare; - intel_helper_funcs.commit = ironlake_crtc_commit; - } else { - intel_helper_funcs.prepare = i9xx_crtc_prepare; - intel_helper_funcs.commit = i9xx_crtc_commit; - } + intel_helper_funcs.prepare = dev_priv->display.crtc_disable; + intel_helper_funcs.commit = dev_priv->display.crtc_enable; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); } -- cgit v1.2.3 From ef9c3aee60442d1eaf81fbd7b63f256410cc0aa9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 29 Jun 2012 22:40:09 +0200 Subject: drm/i915: add direct encoder disable/enable infrastructure Just prep work, not yet put to some use. Note that because we're still using the crtc helper to switch modes (and their complicated way to do partial modesets), we need to call the encoder's disable function unconditionally. But once this is cleaned up we shouldn't call the encoder's disable function unconditionally any more, because then we know that we'll only call it if the encoder is actually enabled. Also note that we then need to be careful about which crtc we're filtering the encoder list on: We want to filter on the crtc of the _current_ mode, not the one we're about to set up. For the enabling side we need to do the same trick. And again, we should be able to simplify this quite a bit when things have settled into place. Also note that this simply does not take cloning into account, so dpms needs to be handled specially for the few outputs where we even bother with it. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 04bec4bd0acb..82aaded6713b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3209,13 +3209,16 @@ static void ironlake_crtc_enable(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); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; u32 temp; bool is_pch_port; + /* XXX: For compatability with the crtc helper code, call the encoder's + * enable function unconditionally for now. */ if (intel_crtc->active) - return; + goto encoders; intel_crtc->active = true; intel_update_watermarks(dev); @@ -3262,6 +3265,12 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); intel_crtc_update_cursor(crtc, true); + +encoders: + for_each_encoder_on_crtc(dev, crtc, encoder) { + if (encoder->enable) + encoder->enable(encoder); + } } static void ironlake_crtc_disable(struct drm_crtc *crtc) @@ -3269,10 +3278,18 @@ static void ironlake_crtc_disable(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); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; u32 reg, temp; + /* XXX: For compatability with the crtc helper code, call the encoder's + * disable function unconditionally for now. */ + for_each_encoder_on_crtc(dev, crtc, encoder) { + if (encoder->disable) + encoder->disable(encoder); + } + if (!intel_crtc->active) return; @@ -3371,11 +3388,14 @@ static void i9xx_crtc_enable(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); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + /* XXX: For compatability with the crtc helper code, call the encoder's + * enable function unconditionally for now. */ if (intel_crtc->active) - return; + goto encoders; intel_crtc->active = true; intel_update_watermarks(dev); @@ -3390,6 +3410,12 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); intel_crtc_update_cursor(crtc, true); + +encoders: + for_each_encoder_on_crtc(dev, crtc, encoder) { + if (encoder->enable) + encoder->enable(encoder); + } } static void i9xx_crtc_disable(struct drm_crtc *crtc) @@ -3397,9 +3423,17 @@ static void i9xx_crtc_disable(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); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + /* XXX: For compatability with the crtc helper code, call the encoder's + * disable function unconditionally for now. */ + for_each_encoder_on_crtc(dev, crtc, encoder) { + if (encoder->disable) + encoder->disable(encoder); + } + if (!intel_crtc->active) return; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 95f635b70b5b..9a5adcc35bde 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -141,6 +141,8 @@ struct intel_encoder { */ bool cloneable; void (*hot_plug)(struct intel_encoder *); + void (*enable)(struct intel_encoder *); + void (*disable)(struct intel_encoder *); int crtc_mask; }; -- cgit v1.2.3 From 5ab432ef4997ce32c9406721b37ef6e97e57dae1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 30 Jun 2012 08:59:56 +0200 Subject: drm/i915/hdmi: convert to encoder->disable/enable I've picked hdmi as the first encoder to convert because it's rather simple: - no cloning possible - no differences between prepare/commit and dpms off/on switching. A few changes are required to do so: - Split up the dpms code into an enable/disable function and wire it up with the intel encoder. - Noop out the existing encoder prepare/commit functions used by the crtc helper - our crtc enable/disable code now calls back into the encoder enable/disable code at the right spot. - Create new helper functions to handle dpms changes. - Add intel_encoder->connectors_active to better track dpms state. Atm this is unused, but it will be useful to correctly disable the entire display pipe for cloned configurations. Also note that for now this is only useful in the dpms code - thanks to the crtc helper's dpms confusion across a modeset operation we can't (yet) rely on this having a sensible value in all circumstances. - Rip out the encoder helper dpms callback, if this is still getting called somewhere we have a bug. The slight issue with that is that the crtc helper abuses dpms off to disable unused functions. Hence we also need to implement a default encoder disable function to do just that with the new encoder->disable callback. - Note that we drop the cpt modeset verification in the commit callback, too. The right place to do this would be in the crtc's enable function, _after_ all the encoders are set up. But because not all encoders are converted yet, we can't do that. Hence disable this check temporarily as a minor concession to bisectability. v2: Squash the dpms mode to only the supported values - connector->dpms is for internal tracking only, we can hence avoid needless state-changes a bit whithout causing harm. v3: Apply bikeshed to disable|enable_ddi, suggested by Paulo Zanoni. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 30 ++++++--- drivers/gpu/drm/i915/intel_display.c | 49 ++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 8 ++- drivers/gpu/drm/i915/intel_hdmi.c | 126 +++++++++++++++++++++++------------ 4 files changed, 160 insertions(+), 53 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 170e3861aa4e..38a7006a84f4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -757,26 +757,34 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, intel_hdmi->set_infoframes(encoder, adjusted_mode); } -void intel_ddi_dpms(struct drm_encoder *encoder, int mode) +void intel_enable_ddi(struct intel_encoder *encoder) { - struct drm_device *dev = encoder->dev; + struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); int port = intel_hdmi->ddi_port; u32 temp; temp = I915_READ(DDI_BUF_CTL(port)); - - if (mode != DRM_MODE_DPMS_ON) { - temp &= ~DDI_BUF_CTL_ENABLE; - } else { - temp |= DDI_BUF_CTL_ENABLE; - } + temp |= DDI_BUF_CTL_ENABLE; /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width, * and swing/emphasis values are ignored so nothing special needs * to be done besides enabling the port. */ - I915_WRITE(DDI_BUF_CTL(port), - temp); + I915_WRITE(DDI_BUF_CTL(port), temp); +} + +void intel_disable_ddi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + int port = intel_hdmi->ddi_port; + u32 temp; + + temp = I915_READ(DDI_BUF_CTL(port)); + temp &= ~DDI_BUF_CTL_ENABLE; + + I915_WRITE(DDI_BUF_CTL(port), temp); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 82aaded6713b..cbd356f43d35 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3554,6 +3554,17 @@ void intel_encoder_commit(struct drm_encoder *encoder) intel_cpt_verify_modeset(dev, intel_crtc->pipe); } +void intel_encoder_noop(struct drm_encoder *encoder) +{ +} + +void intel_encoder_disable(struct drm_encoder *encoder) +{ + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + + intel_encoder->disable(intel_encoder); +} + void intel_encoder_destroy(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -3562,6 +3573,44 @@ void intel_encoder_destroy(struct drm_encoder *encoder) kfree(intel_encoder); } +/* Simple dpms helper for encodres with just one connector, no cloning and only + * one kind of off state. It clamps all !ON modes to fully OFF and changes the + * state of the entire output pipe. */ +void intel_encoder_dpms(struct intel_encoder *encoder, int mode) +{ + if (mode == DRM_MODE_DPMS_ON) { + encoder->connectors_active = true; + + intel_crtc_dpms(encoder->base.crtc, DRM_MODE_DPMS_ON); + } else { + encoder->connectors_active = false; + + intel_crtc_dpms(encoder->base.crtc, DRM_MODE_DPMS_OFF); + } +} + +/* Even simpler default implementation, if there's really no special case to + * consider. */ +void intel_connector_dpms(struct drm_connector *connector, int mode) +{ + struct intel_encoder *encoder = intel_attached_encoder(connector); + + /* All the simple cases only support two dpms states. */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (mode == connector->dpms) + return; + + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + if (encoder->base.crtc) + intel_encoder_dpms(encoder, mode); + else + encoder->connectors_active = false; +} + static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9a5adcc35bde..759dcbab0e5d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -140,6 +140,7 @@ struct intel_encoder { * simple flag is enough to compute the possible_clones mask. */ bool cloneable; + bool connectors_active; void (*hot_plug)(struct intel_encoder *); void (*enable)(struct intel_encoder *); void (*disable)(struct intel_encoder *); @@ -412,7 +413,11 @@ extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare(struct drm_encoder *encoder); extern void intel_encoder_commit(struct drm_encoder *encoder); +extern void intel_encoder_noop(struct drm_encoder *encoder); +extern void intel_encoder_disable(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); +extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); +extern void intel_connector_dpms(struct drm_connector *, int mode); static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) { @@ -519,7 +524,8 @@ extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); extern void ironlake_teardown_rc6(struct drm_device *dev); -extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode); +extern void intel_enable_ddi(struct intel_encoder *encoder); +extern void intel_disable_ddi(struct intel_encoder *encoder); extern void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e4c37bb572e8..acddaaa5f04c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -601,11 +601,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, intel_hdmi->set_infoframes(encoder, adjusted_mode); } -static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) +static void intel_enable_hdmi(struct intel_encoder *encoder) { - struct drm_device *dev = encoder->dev; + struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 temp; u32 enable_bits = SDVO_ENABLE; @@ -617,31 +617,12 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) /* HW workaround for IBX, we need to move the port to transcoder A * before disabling it. */ if (HAS_PCH_IBX(dev)) { - struct drm_crtc *crtc = encoder->crtc; + struct drm_crtc *crtc = encoder->base.crtc; int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; - if (mode != DRM_MODE_DPMS_ON) { - if (temp & SDVO_PIPE_B_SELECT) { - temp &= ~SDVO_PIPE_B_SELECT; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); - - /* Again we need to write this twice. */ - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); - - /* Transcoder selection bits only update - * effectively on vblank. */ - if (crtc) - intel_wait_for_vblank(dev, pipe); - else - msleep(50); - } - } else { - /* Restore the transcoder select bit. */ - if (pipe == PIPE_B) - enable_bits |= SDVO_PIPE_B_SELECT; - } + /* Restore the transcoder select bit. */ + if (pipe == PIPE_B) + enable_bits |= SDVO_PIPE_B_SELECT; } /* HW workaround, need to toggle enable bit off and on for 12bpc, but @@ -652,12 +633,67 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) POSTING_READ(intel_hdmi->sdvox_reg); } - if (mode != DRM_MODE_DPMS_ON) { - temp &= ~enable_bits; - } else { - temp |= enable_bits; + temp |= enable_bits; + + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + + /* HW workaround, need to write this twice for issue that may result + * in first write getting masked. + */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + } +} + +static void intel_disable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + u32 temp; + u32 enable_bits = SDVO_ENABLE; + + if (intel_hdmi->has_audio) + enable_bits |= SDVO_AUDIO_ENABLE; + + temp = I915_READ(intel_hdmi->sdvox_reg); + + /* HW workaround for IBX, we need to move the port to transcoder A + * before disabling it. */ + if (HAS_PCH_IBX(dev)) { + struct drm_crtc *crtc = encoder->base.crtc; + int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; + + if (temp & SDVO_PIPE_B_SELECT) { + temp &= ~SDVO_PIPE_B_SELECT; + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + + /* Again we need to write this twice. */ + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); + + /* Transcoder selection bits only update + * effectively on vblank. */ + if (crtc) + intel_wait_for_vblank(dev, pipe); + else + msleep(50); + } } + /* HW workaround, need to toggle enable bit off and on for 12bpc, but + * we do this anyway which shows more stable in testing. + */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->sdvox_reg); + } + + temp &= ~enable_bits; + I915_WRITE(intel_hdmi->sdvox_reg, temp); POSTING_READ(intel_hdmi->sdvox_reg); @@ -849,23 +885,23 @@ static void intel_hdmi_destroy(struct drm_connector *connector) } static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { - .dpms = intel_ddi_dpms, .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_prepare, + .prepare = intel_encoder_noop, .mode_set = intel_ddi_mode_set, - .commit = intel_encoder_commit, + .commit = intel_encoder_noop, + .disable = intel_encoder_disable, }; static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { - .dpms = intel_hdmi_dpms, .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_prepare, + .prepare = intel_encoder_noop, .mode_set = intel_hdmi_mode_set, - .commit = intel_encoder_commit, + .commit = intel_encoder_noop, + .disable = intel_encoder_disable, }; static const struct drm_connector_funcs intel_hdmi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = intel_connector_dpms, .detect = intel_hdmi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_hdmi_set_property, @@ -964,10 +1000,18 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) intel_hdmi->set_infoframes = cpt_set_infoframes; } - if (IS_HASWELL(dev)) - drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw); - else - drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); + if (IS_HASWELL(dev)) { + intel_encoder->enable = intel_enable_ddi; + intel_encoder->disable = intel_disable_ddi; + drm_encoder_helper_add(&intel_encoder->base, + &intel_hdmi_helper_funcs_hsw); + } else { + intel_encoder->enable = intel_enable_hdmi; + intel_encoder->disable = intel_disable_hdmi; + drm_encoder_helper_add(&intel_encoder->base, + &intel_hdmi_helper_funcs); + } + intel_hdmi_add_properties(intel_hdmi, connector); -- cgit v1.2.3 From b2cabb0e1d205708dab11bd9e1b97fd080537096 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 1 Jul 2012 22:42:24 +0200 Subject: drm/i915: convert dpms functions of dvo/sdvo/crt Yeah, big patch but I couldn't come up with a neat idea of how to split it up further, that wouldn't break dpms on cloned configs somehow. But the changes in dvo/sdvo/crt are all pretty much orthonogal, so it's not too bad a patch. These are the only encoders that support cloning, which requires a few special changes compared to the previous patches. - Compute the desired state of the display pipe by walking all connected encoders and checking whether any has active connectors. To make this clearer, drop the old mode parameter to the crtc dpms function and rename it to intel_crtc_update_dpms. - There's the curious case of intel_crtc->dpms_mode. With the previous patches to remove the overlay pipe A code and to rework the load detect pipe code, the big users are gone. We still keep it to avoid enabling the pipe twice, but we duplicate this logic with crtc->active, too. Still, leave this for now and just push a fake dpms mode into it that reflects the state of the display pipe. Changes in the encoder dpms functions: - We clamp the dpms state to the supported range right away. This is escpecially important for the VGA outputs, where only older hw supports the intermediate states. This (and the crt->adpa_reg patch) allows us to unify the crt dpms code again between all variants (gmch, vlv and pch). - We only enable/disable the output for dvo/sdvo and leave the encoder running. The encoder will be disabled/enabled when we switch the state of the entire output pipeline (which will happen right away for non-cloned setups). This way the duplication is reduced and strange interaction when disabling output ports at the wrong time avoided. The dpms code for all three types of connectors contains a bit of duplicated logic, but I think keeping these special cases separate is simpler: CRT is the only one that hanldes intermediate dpms state (which requires extra logic to enable/disable things in the right order), and introducing some abstraction just to share the code between dvo and sdvo smells like overkill. We can do that once someone bothers to implement cloning for the more modern outputs. But I doubt that this will ever happen. v2: s/crtc/crt/_set_dpms, noticed by Paulo Zanoni. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 97 +++++++++++++++++++----------------- drivers/gpu/drm/i915/intel_display.c | 37 +++++++------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_dvo.c | 39 +++++++++++---- drivers/gpu/drm/i915/intel_sdvo.c | 60 ++++++++++------------ 5 files changed, 122 insertions(+), 112 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 543ea4063edd..76646c715a42 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -84,13 +84,17 @@ static void intel_enable_crt(struct intel_encoder *encoder) I915_WRITE(crt->adpa_reg, temp); } -static void pch_crt_dpms(struct drm_encoder *encoder, int mode) +/* Note: The caller is required to filter out dpms modes not supported by the + * platform. */ +static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) { - struct drm_device *dev = encoder->dev; + struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crt *crt = intel_encoder_to_crt(encoder); u32 temp; - temp = I915_READ(PCH_ADPA); + temp = I915_READ(crt->adpa_reg); + temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp &= ~ADPA_DAC_ENABLE; switch (mode) { @@ -98,44 +102,59 @@ static void pch_crt_dpms(struct drm_encoder *encoder, int mode) temp |= ADPA_DAC_ENABLE; break; case DRM_MODE_DPMS_STANDBY: + temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; + break; case DRM_MODE_DPMS_SUSPEND: + temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; + break; case DRM_MODE_DPMS_OFF: - /* Just leave port enable cleared */ + temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; break; } - I915_WRITE(PCH_ADPA, temp); + I915_WRITE(crt->adpa_reg, temp); } -static void gmch_crt_dpms(struct drm_encoder *encoder, int mode) +static void intel_crt_dpms(struct drm_connector *connector, int mode) { - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 temp; - - temp = I915_READ(ADPA); - temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); - temp &= ~ADPA_DAC_ENABLE; + struct drm_device *dev = connector->dev; + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct drm_crtc *crtc; + int old_dpms; - if (IS_VALLEYVIEW(dev) && mode != DRM_MODE_DPMS_ON) + /* PCH platforms and VLV only support on/off. */ + if (INTEL_INFO(dev)->gen < 5 && mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; - switch (mode) { - case DRM_MODE_DPMS_ON: - temp |= ADPA_DAC_ENABLE; - break; - case DRM_MODE_DPMS_STANDBY: - temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; - break; - case DRM_MODE_DPMS_SUSPEND: - temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; - break; - case DRM_MODE_DPMS_OFF: - temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; - break; + if (mode == connector->dpms) + return; + + old_dpms = connector->dpms; + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + crtc = encoder->base.crtc; + if (!crtc) { + encoder->connectors_active = false; + return; } - I915_WRITE(ADPA, temp); + /* We need the pipe to run for anything but OFF. */ + if (mode == DRM_MODE_DPMS_OFF) + encoder->connectors_active = false; + else + encoder->connectors_active = true; + + if (mode < old_dpms) { + /* From off to on, enable the pipe first. */ + intel_crtc_update_dpms(crtc); + + intel_crt_set_dpms(encoder, mode); + } else { + intel_crt_set_dpms(encoder, mode); + + intel_crtc_update_dpms(crtc); + } } static int intel_crt_mode_valid(struct drm_connector *connector, @@ -596,27 +615,17 @@ static void intel_crt_reset(struct drm_connector *connector) * Routines for controlling stuff on the analog port */ -static const struct drm_encoder_helper_funcs pch_encoder_funcs = { - .mode_fixup = intel_crt_mode_fixup, - .prepare = intel_encoder_noop, - .commit = intel_encoder_noop, - .mode_set = intel_crt_mode_set, - .dpms = pch_crt_dpms, - .disable = intel_encoder_disable, -}; - -static const struct drm_encoder_helper_funcs gmch_encoder_funcs = { +static const struct drm_encoder_helper_funcs crt_encoder_funcs = { .mode_fixup = intel_crt_mode_fixup, .prepare = intel_encoder_noop, .commit = intel_encoder_noop, .mode_set = intel_crt_mode_set, - .dpms = gmch_crt_dpms, .disable = intel_encoder_disable, }; static const struct drm_connector_funcs intel_crt_connector_funcs = { .reset = intel_crt_reset, - .dpms = drm_helper_connector_dpms, + .dpms = intel_crt_dpms, .detect = intel_crt_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = intel_crt_destroy, @@ -657,7 +666,6 @@ void intel_crt_init(struct drm_device *dev) struct intel_crt *crt; struct intel_connector *intel_connector; struct drm_i915_private *dev_priv = dev->dev_private; - const struct drm_encoder_helper_funcs *encoder_helper_funcs; /* Skip machines without VGA that falsely report hotplug events */ if (dmi_check_system(intel_no_crt)) @@ -695,11 +703,6 @@ void intel_crt_init(struct drm_device *dev) connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - if (HAS_PCH_SPLIT(dev)) - encoder_helper_funcs = &pch_encoder_funcs; - else - encoder_helper_funcs = &gmch_encoder_funcs; - if (HAS_PCH_SPLIT(dev)) crt->adpa_reg = PCH_ADPA; else if (IS_VALLEYVIEW(dev)) @@ -710,7 +713,7 @@ void intel_crt_init(struct drm_device *dev) crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; - drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs); + drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cbd356f43d35..0d48ebe6ac9d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3462,34 +3462,31 @@ static void i9xx_crtc_off(struct drm_crtc *crtc) /** * Sets the power management mode of the pipe and plane. */ -static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) +void intel_crtc_update_dpms(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder; int pipe = intel_crtc->pipe; - bool enabled; + bool enabled, enable = false; + int mode; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) + enable |= intel_encoder->connectors_active; + + mode = enable ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF; if (intel_crtc->dpms_mode == mode) return; intel_crtc->dpms_mode = mode; - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: + if (enable) dev_priv->display.crtc_enable(crtc); - break; - - case DRM_MODE_DPMS_OFF: + else dev_priv->display.crtc_disable(crtc); - break; - } if (!dev->primary->master) return; @@ -3498,7 +3495,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) if (!master_priv->sarea_priv) return; - enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; + enabled = crtc->enabled && enable; switch (pipe) { case 0: @@ -3517,11 +3514,12 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) static void intel_crtc_disable(struct drm_crtc *crtc) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + /* crtc->disable is only called when we have no encoders, hence this + * will disable the pipe. */ + intel_crtc_update_dpms(crtc); dev_priv->display.off(crtc); assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); @@ -3581,11 +3579,11 @@ void intel_encoder_dpms(struct intel_encoder *encoder, int mode) if (mode == DRM_MODE_DPMS_ON) { encoder->connectors_active = true; - intel_crtc_dpms(encoder->base.crtc, DRM_MODE_DPMS_ON); + intel_crtc_update_dpms(encoder->base.crtc); } else { encoder->connectors_active = false; - intel_crtc_dpms(encoder->base.crtc, DRM_MODE_DPMS_OFF); + intel_crtc_update_dpms(encoder->base.crtc); } } @@ -6609,7 +6607,6 @@ static void intel_crtc_reset(struct drm_crtc *crtc) } static struct drm_crtc_helper_funcs intel_helper_funcs = { - .dpms = intel_crtc_dpms, .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 759dcbab0e5d..245624587db1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -411,6 +411,7 @@ extern void intel_panel_destroy_backlight(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); +extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_prepare(struct drm_encoder *encoder); extern void intel_encoder_commit(struct drm_encoder *encoder); extern void intel_encoder_noop(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 4ad988fb8685..c55a13ea7ae8 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -129,21 +129,39 @@ static void intel_enable_dvo(struct intel_encoder *encoder) intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true); } -static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) +static void intel_dvo_dpms(struct drm_connector *connector, int mode) { - struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); - u32 dvo_reg = intel_dvo->dev.dvo_reg; - u32 temp = I915_READ(dvo_reg); + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_crtc *crtc; + + /* dvo supports only 2 dpms states. */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (mode == connector->dpms) + return; + + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + crtc = intel_dvo->base.base.crtc; + if (!crtc) { + intel_dvo->base.connectors_active = false; + return; + } if (mode == DRM_MODE_DPMS_ON) { - I915_WRITE(dvo_reg, temp | DVO_ENABLE); - I915_READ(dvo_reg); + intel_dvo->base.connectors_active = true; + + intel_crtc_update_dpms(crtc); + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true); } else { intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false); - I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); - I915_READ(dvo_reg); + + intel_dvo->base.connectors_active = false; + + intel_crtc_update_dpms(crtc); } } @@ -299,7 +317,6 @@ static void intel_dvo_destroy(struct drm_connector *connector) } static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { - .dpms = intel_dvo_dpms, .mode_fixup = intel_dvo_mode_fixup, .prepare = intel_encoder_noop, .mode_set = intel_dvo_mode_set, @@ -308,7 +325,7 @@ static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { }; static const struct drm_connector_funcs intel_dvo_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = intel_dvo_dpms, .detect = intel_dvo_detect, .destroy = intel_dvo_destroy, .fill_modes = drm_helper_probe_single_connector_modes, diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 20feaa34b063..a01c47021f53 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1192,51 +1192,44 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } -static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) +static void intel_sdvo_dpms(struct drm_connector *connector, int mode) { - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - u32 temp; + struct drm_crtc *crtc; + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + + /* dvo supports only 2 dpms states. */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (mode == connector->dpms) + return; + + connector->dpms = mode; + + /* Only need to change hw state when actually enabled */ + crtc = intel_sdvo->base.base.crtc; + if (!crtc) { + intel_sdvo->base.connectors_active = false; + return; + } if (mode != DRM_MODE_DPMS_ON) { intel_sdvo_set_active_outputs(intel_sdvo, 0); if (0) intel_sdvo_set_encoder_power_state(intel_sdvo, mode); - if (mode == DRM_MODE_DPMS_OFF) { - temp = I915_READ(intel_sdvo->sdvo_reg); - if ((temp & SDVO_ENABLE) != 0) { - intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE); - } - } + intel_sdvo->base.connectors_active = false; + + intel_crtc_update_dpms(crtc); } else { - bool input1, input2; - int i; - u8 status; - - temp = I915_READ(intel_sdvo->sdvo_reg); - if ((temp & SDVO_ENABLE) == 0) - intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); - for (i = 0; i < 2; i++) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); - /* Warn if the device reported failure to sync. - * A lot of SDVO devices fail to notify of sync, but it's - * a given it the status is a success, we succeeded. - */ - if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { - DRM_DEBUG_KMS("First %s output reported failure to " - "sync\n", SDVO_NAME(intel_sdvo)); - } + intel_sdvo->base.connectors_active = true; + + intel_crtc_update_dpms(crtc); if (0) intel_sdvo_set_encoder_power_state(intel_sdvo, mode); intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } - return; } static int intel_sdvo_mode_valid(struct drm_connector *connector, @@ -1895,7 +1888,6 @@ done: } static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { - .dpms = intel_sdvo_dpms, .mode_fixup = intel_sdvo_mode_fixup, .prepare = intel_encoder_noop, .mode_set = intel_sdvo_mode_set, @@ -1904,7 +1896,7 @@ static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { }; static const struct drm_connector_funcs intel_sdvo_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = intel_sdvo_dpms, .detect = intel_sdvo_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_sdvo_set_property, -- cgit v1.2.3 From fa5c73b1b20ffc7e9df83a5e763af1e3b7cc96d3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 1 Jul 2012 23:24:36 +0200 Subject: drm/i915: rip out encoder->disable/enable checks All encoders are now converted so there's no need for these checks any more. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0d48ebe6ac9d..4805385a49ed 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3267,10 +3267,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc_update_cursor(crtc, true); encoders: - for_each_encoder_on_crtc(dev, crtc, encoder) { - if (encoder->enable) - encoder->enable(encoder); - } + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); } static void ironlake_crtc_disable(struct drm_crtc *crtc) @@ -3285,10 +3283,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) /* XXX: For compatability with the crtc helper code, call the encoder's * disable function unconditionally for now. */ - for_each_encoder_on_crtc(dev, crtc, encoder) { - if (encoder->disable) - encoder->disable(encoder); - } + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); if (!intel_crtc->active) return; @@ -3412,10 +3408,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_crtc_update_cursor(crtc, true); encoders: - for_each_encoder_on_crtc(dev, crtc, encoder) { - if (encoder->enable) - encoder->enable(encoder); - } + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); } static void i9xx_crtc_disable(struct drm_crtc *crtc) @@ -3429,10 +3423,8 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) /* XXX: For compatability with the crtc helper code, call the encoder's * disable function unconditionally for now. */ - for_each_encoder_on_crtc(dev, crtc, encoder) { - if (encoder->disable) - encoder->disable(encoder); - } + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); if (!intel_crtc->active) return; -- cgit v1.2.3 From 61b77ddda6cf6f1f6f543339cfeee4c623f82784 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 00:16:19 +0200 Subject: drm/i915: clean up encoder_prepare/commit We no longer need them. And now that all encoders are converted, we can finally move the cpt modeset check to the right place - at the end of the crtc_enable function. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 23 +++-------------------- drivers/gpu/drm/i915/intel_drv.h | 2 -- 2 files changed, 3 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4805385a49ed..07077b1fcd7b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3269,6 +3269,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) encoders: for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); + + if (HAS_PCH_CPT(dev)) + intel_cpt_verify_modeset(dev, intel_crtc->pipe); } static void ironlake_crtc_disable(struct drm_crtc *crtc) @@ -3524,26 +3527,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc) } } -void intel_encoder_prepare(struct drm_encoder *encoder) -{ - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - /* lvds has its own version of prepare see intel_lvds_prepare */ - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); -} - -void intel_encoder_commit(struct drm_encoder *encoder) -{ - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - struct drm_device *dev = encoder->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - - /* lvds has its own version of commit see intel_lvds_commit */ - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - - if (HAS_PCH_CPT(dev)) - intel_cpt_verify_modeset(dev, intel_crtc->pipe); -} - void intel_encoder_noop(struct drm_encoder *encoder) { } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 245624587db1..e59cac34ec68 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -412,8 +412,6 @@ extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); -extern void intel_encoder_prepare(struct drm_encoder *encoder); -extern void intel_encoder_commit(struct drm_encoder *encoder); extern void intel_encoder_noop(struct drm_encoder *encoder); extern void intel_encoder_disable(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); -- cgit v1.2.3 From 50f56119efcb7ad763c14a9b6c2c8e684050cab0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 09:35:43 +0200 Subject: drm/i915: copy&paste drm_crtc_helper_set_config And the following static functions required by it: drm_encoder_crtc_ok, drm_crtc_helper_disable No changes safe for the s/drm/intel prefix change. Acked-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 314 ++++++++++++++++++++++++++++++++++- 1 file changed, 313 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 07077b1fcd7b..33a519117e2f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6590,12 +6590,324 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = { .disable = intel_crtc_disable, }; +static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, + struct drm_crtc *crtc) +{ + struct drm_device *dev; + struct drm_crtc *tmp; + int crtc_mask = 1; + + WARN(!crtc, "checking null crtc?\n"); + + dev = crtc->dev; + + list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { + if (tmp == crtc) + break; + crtc_mask <<= 1; + } + + if (encoder->possible_crtcs & crtc_mask) + return true; + return false; +} + +static int +intel_crtc_helper_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector *connector; + struct drm_encoder *encoder; + + /* Decouple all encoders and their attached connectors from this crtc */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder != encoder) + continue; + + connector->encoder = NULL; + } + } + + drm_helper_disable_unused_functions(dev); + return 0; +} + +static int intel_crtc_set_config(struct drm_mode_set *set) +{ + struct drm_device *dev; + struct drm_crtc *save_crtcs, *new_crtc, *crtc; + struct drm_encoder *save_encoders, *new_encoder, *encoder; + struct drm_framebuffer *old_fb = NULL; + bool mode_changed = false; /* if true do a full mode set */ + bool fb_changed = false; /* if true and !mode_changed just do a flip */ + struct drm_connector *save_connectors, *connector; + int count = 0, ro, fail = 0; + struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_mode_set save_set; + int ret; + int i; + + DRM_DEBUG_KMS("\n"); + + if (!set) + return -EINVAL; + + if (!set->crtc) + return -EINVAL; + + if (!set->crtc->helper_private) + return -EINVAL; + + crtc_funcs = set->crtc->helper_private; + + if (!set->mode) + set->fb = NULL; + + if (set->fb) { + DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", + set->crtc->base.id, set->fb->base.id, + (int)set->num_connectors, set->x, set->y); + } else { + DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); + return intel_crtc_helper_disable(set->crtc); + } + + dev = set->crtc->dev; + + /* Allocate space for the backup of all (non-pointer) crtc, encoder and + * connector data. */ + save_crtcs = kzalloc(dev->mode_config.num_crtc * + sizeof(struct drm_crtc), GFP_KERNEL); + if (!save_crtcs) + return -ENOMEM; + + save_encoders = kzalloc(dev->mode_config.num_encoder * + sizeof(struct drm_encoder), GFP_KERNEL); + if (!save_encoders) { + kfree(save_crtcs); + return -ENOMEM; + } + + save_connectors = kzalloc(dev->mode_config.num_connector * + sizeof(struct drm_connector), GFP_KERNEL); + if (!save_connectors) { + kfree(save_crtcs); + kfree(save_encoders); + return -ENOMEM; + } + + /* Copy data. Note that driver private data is not affected. + * Should anything bad happen only the expected state is + * restored, not the drivers personal bookkeeping. + */ + count = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + save_crtcs[count++] = *crtc; + } + + count = 0; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + save_encoders[count++] = *encoder; + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + save_connectors[count++] = *connector; + } + + save_set.crtc = set->crtc; + save_set.mode = &set->crtc->mode; + save_set.x = set->crtc->x; + save_set.y = set->crtc->y; + save_set.fb = set->crtc->fb; + + /* We should be able to check here if the fb has the same properties + * and then just flip_or_move it */ + if (set->crtc->fb != set->fb) { + /* If we have no fb then treat it as a full mode set */ + if (set->crtc->fb == NULL) { + DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); + mode_changed = true; + } else if (set->fb == NULL) { + mode_changed = true; + } else if (set->fb->depth != set->crtc->fb->depth) { + mode_changed = true; + } else if (set->fb->bits_per_pixel != + set->crtc->fb->bits_per_pixel) { + mode_changed = true; + } else + fb_changed = true; + } + + if (set->x != set->crtc->x || set->y != set->crtc->y) + fb_changed = true; + + if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { + DRM_DEBUG_KMS("modes are different, full mode set\n"); + drm_mode_debug_printmodeline(&set->crtc->mode); + drm_mode_debug_printmodeline(set->mode); + mode_changed = true; + } + + /* a) traverse passed in connector list and get encoders for them */ + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_connector_helper_funcs *connector_funcs = + connector->helper_private; + new_encoder = connector->encoder; + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == connector) { + new_encoder = connector_funcs->best_encoder(connector); + /* if we can't get an encoder for a connector + we are setting now - then fail */ + if (new_encoder == NULL) + /* don't break so fail path works correct */ + fail = 1; + break; + } + } + + if (new_encoder != connector->encoder) { + DRM_DEBUG_KMS("encoder changed, full mode switch\n"); + mode_changed = true; + /* If the encoder is reused for another connector, then + * the appropriate crtc will be set later. + */ + if (connector->encoder) + connector->encoder->crtc = NULL; + connector->encoder = new_encoder; + } + } + + if (fail) { + ret = -EINVAL; + goto fail; + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->encoder) + continue; + + if (connector->encoder->crtc == set->crtc) + new_crtc = NULL; + else + new_crtc = connector->encoder->crtc; + + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == connector) + new_crtc = set->crtc; + } + + /* Make sure the new CRTC will work with the encoder */ + if (new_crtc && + !intel_encoder_crtc_ok(connector->encoder, new_crtc)) { + ret = -EINVAL; + goto fail; + } + if (new_crtc != connector->encoder->crtc) { + DRM_DEBUG_KMS("crtc changed, full mode switch\n"); + mode_changed = true; + connector->encoder->crtc = new_crtc; + } + if (new_crtc) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", + connector->base.id, drm_get_connector_name(connector), + new_crtc->base.id); + } else { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", + connector->base.id, drm_get_connector_name(connector)); + } + } + + /* mode_set_base is not a required function */ + if (fb_changed && !crtc_funcs->mode_set_base) + mode_changed = true; + + if (mode_changed) { + set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); + if (set->crtc->enabled) { + DRM_DEBUG_KMS("attempting to set mode from" + " userspace\n"); + drm_mode_debug_printmodeline(set->mode); + old_fb = set->crtc->fb; + set->crtc->fb = set->fb; + if (!drm_crtc_helper_set_mode(set->crtc, set->mode, + set->x, set->y, + old_fb)) { + DRM_ERROR("failed to set mode on [CRTC:%d]\n", + set->crtc->base.id); + set->crtc->fb = old_fb; + ret = -EINVAL; + goto fail; + } + DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); + for (i = 0; i < set->num_connectors; i++) { + DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, + drm_get_connector_name(set->connectors[i])); + set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); + } + } + drm_helper_disable_unused_functions(dev); + } else if (fb_changed) { + set->crtc->x = set->x; + set->crtc->y = set->y; + + old_fb = set->crtc->fb; + if (set->crtc->fb != set->fb) + set->crtc->fb = set->fb; + ret = crtc_funcs->mode_set_base(set->crtc, + set->x, set->y, old_fb); + if (ret != 0) { + set->crtc->fb = old_fb; + goto fail; + } + } + + kfree(save_connectors); + kfree(save_encoders); + kfree(save_crtcs); + return 0; + +fail: + /* Restore all previous data. */ + count = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + *crtc = save_crtcs[count++]; + } + + count = 0; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + *encoder = save_encoders[count++]; + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + *connector = save_connectors[count++]; + } + + /* Try to restore the config */ + if (mode_changed && + !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, + save_set.y, save_set.fb)) + DRM_ERROR("failed to restore config after modeset failure\n"); + + kfree(save_connectors); + kfree(save_encoders); + kfree(save_crtcs); + return ret; +} + static const struct drm_crtc_funcs intel_crtc_funcs = { .reset = intel_crtc_reset, .cursor_set = intel_crtc_cursor_set, .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, + .set_config = intel_crtc_set_config, .destroy = intel_crtc_destroy, .page_flip = intel_crtc_page_flip, }; -- cgit v1.2.3 From 4f660f49b9d68e53d85f5ce4f5bbf167257e7fc2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 09:47:37 +0200 Subject: drm/i915: call set_base directly And drop the check, we always have it. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 33a519117e2f..5dbe03ae4e4d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6584,7 +6584,6 @@ static void intel_crtc_reset(struct drm_crtc *crtc) static struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, - .mode_set_base = intel_pipe_set_base, .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, .disable = intel_crtc_disable, @@ -6646,7 +6645,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) bool fb_changed = false; /* if true and !mode_changed just do a flip */ struct drm_connector *save_connectors, *connector; int count = 0, ro, fail = 0; - struct drm_crtc_helper_funcs *crtc_funcs; struct drm_mode_set save_set; int ret; int i; @@ -6662,7 +6660,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (!set->crtc->helper_private) return -EINVAL; - crtc_funcs = set->crtc->helper_private; if (!set->mode) set->fb = NULL; @@ -6824,10 +6821,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } } - /* mode_set_base is not a required function */ - if (fb_changed && !crtc_funcs->mode_set_base) - mode_changed = true; - if (mode_changed) { set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); if (set->crtc->enabled) { @@ -6860,8 +6853,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) old_fb = set->crtc->fb; if (set->crtc->fb != set->fb) set->crtc->fb = set->fb; - ret = crtc_funcs->mode_set_base(set->crtc, - set->x, set->y, old_fb); + ret = intel_pipe_set_base(set->crtc, + set->x, set->y, old_fb); if (ret != 0) { set->crtc->fb = old_fb; goto fail; -- cgit v1.2.3 From 6d832d189bb671cfa2c681d97625bab2d6463c66 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 10:45:45 +0200 Subject: drm/i915: inline intel_best_encoder Also kill the error-path, we have a fixed connector->encoder mapping. Unfortunately we can't rip out all the ->best_encoder callbacks, these are all still used by the fb_helper. Neat helper layering violation there. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5dbe03ae4e4d..9d5c575385b2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6644,7 +6644,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) bool mode_changed = false; /* if true do a full mode set */ bool fb_changed = false; /* if true and !mode_changed just do a flip */ struct drm_connector *save_connectors, *connector; - int count = 0, ro, fail = 0; + int count = 0, ro; struct drm_mode_set save_set; int ret; int i; @@ -6660,7 +6660,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (!set->crtc->helper_private) return -EINVAL; - if (!set->mode) set->fb = NULL; @@ -6753,17 +6752,11 @@ static int intel_crtc_set_config(struct drm_mode_set *set) /* a) traverse passed in connector list and get encoders for them */ count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_connector_helper_funcs *connector_funcs = - connector->helper_private; new_encoder = connector->encoder; for (ro = 0; ro < set->num_connectors; ro++) { if (set->connectors[ro] == connector) { - new_encoder = connector_funcs->best_encoder(connector); - /* if we can't get an encoder for a connector - we are setting now - then fail */ - if (new_encoder == NULL) - /* don't break so fail path works correct */ - fail = 1; + new_encoder = + &intel_attached_encoder(connector)->base; break; } } @@ -6780,11 +6773,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } } - if (fail) { - ret = -EINVAL; - goto fail; - } - count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) -- cgit v1.2.3 From a6778b3cfd7711951d8973286b783bc061281256 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 09:56:42 +0200 Subject: drm/i915: copy&paste drm_crtc_helper_set_mode Together with the static helper functions drm_crtc_prepare_encoders and drm_encoder_disable (which will be simplified in the next patch, but for now are 1:1 copies). Again, no changes beside new names for these functions. Also call our new set_mode instead of the crtc helper one now in all the places we've done so far. v2: Call the function just intel_set_mode to better differentia it from intel_crtc_mode_set which really only does the ->mode_set step of the entire modeset sequence on one crtc. Whereas this function does the global change. Acked-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 162 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dp.c | 5 +- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_hdmi.c | 5 +- drivers/gpu/drm/i915/intel_lvds.c | 4 +- drivers/gpu/drm/i915/intel_sdvo.c | 4 +- drivers/gpu/drm/i915/intel_tv.c | 4 +- 7 files changed, 168 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9d5c575385b2..3e119a62888d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5767,7 +5767,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, goto fail; } - if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) { + if (!intel_set_mode(crtc, mode, 0, 0, old_fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -6635,6 +6635,157 @@ intel_crtc_helper_disable(struct drm_crtc *crtc) return 0; } +static void +intel_encoder_disable_helper(struct drm_encoder *encoder) +{ + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + + if (encoder_funcs->disable) + (*encoder_funcs->disable)(encoder); + else + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); +} + +static void +intel_crtc_prepare_encoders(struct drm_device *dev) +{ + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder_funcs = encoder->helper_private; + /* Disable unused encoders */ + if (encoder->crtc == NULL) + intel_encoder_disable_helper(encoder); + /* Disable encoders whose CRTC is about to change */ + if (encoder_funcs->get_crtc && + encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) + intel_encoder_disable_helper(encoder); + } +} + +bool intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_encoder_helper_funcs *encoder_funcs; + int saved_x, saved_y; + struct drm_encoder *encoder; + bool ret = true; + + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) + return true; + + adjusted_mode = drm_mode_duplicate(dev, mode); + if (!adjusted_mode) + return false; + + saved_hwmode = crtc->hwmode; + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + + /* Pass our mode to the connectors and the CRTC to give them a chance to + * adjust it according to limitations or connector properties, and also + * a chance to reject the mode entirely. + */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + encoder_funcs = encoder->helper_private; + if (!(ret = encoder_funcs->mode_fixup(encoder, mode, + adjusted_mode))) { + DRM_DEBUG_KMS("Encoder fixup failed\n"); + goto done; + } + } + + if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { + DRM_DEBUG_KMS("CRTC fixup failed\n"); + goto done; + } + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + + /* Prepare the encoders and CRTCs before setting the mode. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + encoder_funcs = encoder->helper_private; + /* Disable the encoders as the first thing we do. */ + encoder_funcs->prepare(encoder); + } + + intel_crtc_prepare_encoders(dev); + + crtc_funcs->prepare(crtc); + + /* Set up the DPLL and any encoders state that needs to adjust or depend + * on the DPLL. + */ + ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); + if (!ret) + goto done; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", + encoder->base.id, drm_get_encoder_name(encoder), + mode->base.id, mode->name); + encoder_funcs = encoder->helper_private; + encoder_funcs->mode_set(encoder, mode, adjusted_mode); + } + + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ + crtc_funcs->commit(crtc); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + + encoder_funcs = encoder->helper_private; + encoder_funcs->commit(encoder); + + } + + /* Store real post-adjustment hardware mode. */ + crtc->hwmode = *adjusted_mode; + + /* Calculate and store various constants which + * are later needed by vblank and swap-completion + * timestamping. They are derived from true hwmode. + */ + drm_calc_timestamping_constants(crtc); + + /* FIXME: add subpixel order */ +done: + drm_mode_destroy(dev, adjusted_mode); + if (!ret) { + crtc->hwmode = saved_hwmode; + crtc->mode = saved_mode; + crtc->x = saved_x; + crtc->y = saved_y; + } + + return ret; +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; @@ -6817,9 +6968,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) drm_mode_debug_printmodeline(set->mode); old_fb = set->crtc->fb; set->crtc->fb = set->fb; - if (!drm_crtc_helper_set_mode(set->crtc, set->mode, - set->x, set->y, - old_fb)) { + if (!intel_set_mode(set->crtc, set->mode, + set->x, set->y, old_fb)) { DRM_ERROR("failed to set mode on [CRTC:%d]\n", set->crtc->base.id); set->crtc->fb = old_fb; @@ -6873,8 +7023,8 @@ fail: /* Try to restore the config */ if (mode_changed && - !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, - save_set.y, save_set.fb)) + !intel_set_mode(save_set.crtc, save_set.mode, + save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); kfree(save_connectors); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7ee954c39c91..2abaaf65ae8d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2312,9 +2312,8 @@ intel_dp_set_property(struct drm_connector *connector, done: if (intel_dp->base.base.crtc) { struct drm_crtc *crtc = intel_dp->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, - crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e59cac34ec68..c28fadae8758 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -410,6 +410,8 @@ extern void intel_panel_disable_backlight(struct drm_device *dev); extern void intel_panel_destroy_backlight(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); +extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *old_fb); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_noop(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index acddaaa5f04c..ef8409794ab6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -869,9 +869,8 @@ intel_hdmi_set_property(struct drm_connector *connector, done: if (intel_hdmi->base.base.crtc) { struct drm_crtc *crtc = intel_hdmi->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, - crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3baa224ab966..fad82b2721ed 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -560,8 +560,8 @@ static int intel_lvds_set_property(struct drm_connector *connector, * If the CRTC is enabled, the display will be changed * according to the new panel fitting mode. */ - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a01c47021f53..88fb30dff758 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1879,8 +1879,8 @@ set_value: done: if (intel_sdvo->base.base.crtc) { struct drm_crtc *crtc = intel_sdvo->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 281e0cf6f606..16cb11405068 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1471,8 +1471,8 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop } if (changed && crtc) - drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); out: return ret; } -- cgit v1.2.3 From 821112aa413285ae8a49f787ba01ab30e930ad85 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 10:16:35 +0200 Subject: drm/i915: simplify intel_crtc_prepare_encoders - We don't have the ->get_crtc callback. - Call intel_encoder->disable directly. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3e119a62888d..343f99104c39 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6635,32 +6635,15 @@ intel_crtc_helper_disable(struct drm_crtc *crtc) return 0; } -static void -intel_encoder_disable_helper(struct drm_encoder *encoder) -{ - struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; - - if (encoder_funcs->disable) - (*encoder_funcs->disable)(encoder); - else - (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); -} - static void intel_crtc_prepare_encoders(struct drm_device *dev) { - struct drm_encoder_helper_funcs *encoder_funcs; - struct drm_encoder *encoder; + struct intel_encoder *encoder; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - encoder_funcs = encoder->helper_private; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { /* Disable unused encoders */ - if (encoder->crtc == NULL) - intel_encoder_disable_helper(encoder); - /* Disable encoders whose CRTC is about to change */ - if (encoder_funcs->get_crtc && - encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) - intel_encoder_disable_helper(encoder); + if (encoder->base.crtc == NULL) + encoder->disable(encoder); } } -- cgit v1.2.3 From c9deac9776b0a95b876bd845ea359d5975c3ba80 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 10:21:35 +0200 Subject: drm/i915: rip out encoder->prepare/commit With the new infrastructure we're doing this when enabling/disabling the entire display pipe. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 -- drivers/gpu/drm/i915/intel_display.c | 24 ------------------------ drivers/gpu/drm/i915/intel_dp.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_dvo.c | 2 -- drivers/gpu/drm/i915/intel_hdmi.c | 4 ---- drivers/gpu/drm/i915/intel_lvds.c | 2 -- drivers/gpu/drm/i915/intel_sdvo.c | 2 -- drivers/gpu/drm/i915/intel_tv.c | 2 -- 9 files changed, 41 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 76646c715a42..2e2581098d32 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -617,8 +617,6 @@ static void intel_crt_reset(struct drm_connector *connector) static const struct drm_encoder_helper_funcs crt_encoder_funcs = { .mode_fixup = intel_crt_mode_fixup, - .prepare = intel_encoder_noop, - .commit = intel_encoder_noop, .mode_set = intel_crt_mode_set, .disable = intel_encoder_disable, }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 343f99104c39..d37a851d0b2d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3527,10 +3527,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc) } } -void intel_encoder_noop(struct drm_encoder *encoder) -{ -} - void intel_encoder_disable(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -6701,16 +6697,6 @@ bool intel_set_mode(struct drm_crtc *crtc, } DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - /* Prepare the encoders and CRTCs before setting the mode. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - - if (encoder->crtc != crtc) - continue; - encoder_funcs = encoder->helper_private; - /* Disable the encoders as the first thing we do. */ - encoder_funcs->prepare(encoder); - } - intel_crtc_prepare_encoders(dev); crtc_funcs->prepare(crtc); @@ -6737,16 +6723,6 @@ bool intel_set_mode(struct drm_crtc *crtc, /* Now enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - - if (encoder->crtc != crtc) - continue; - - encoder_funcs = encoder->helper_private; - encoder_funcs->commit(encoder); - - } - /* Store real post-adjustment hardware mode. */ crtc->hwmode = *adjusted_mode; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2abaaf65ae8d..ff993a01d039 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2348,9 +2348,7 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder) static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .mode_fixup = intel_dp_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_dp_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable, }; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c28fadae8758..673e8d484bfa 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -414,7 +414,6 @@ extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); -extern void intel_encoder_noop(struct drm_encoder *encoder); extern void intel_encoder_disable(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index c55a13ea7ae8..84c0867e212b 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -318,9 +318,7 @@ static void intel_dvo_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { .mode_fixup = intel_dvo_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_dvo_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable, }; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ef8409794ab6..c9535cee1a73 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -885,17 +885,13 @@ static void intel_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_ddi_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable, }; static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_hdmi_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable, }; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index fad82b2721ed..5fc7abca28ee 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -570,9 +570,7 @@ static int intel_lvds_set_property(struct drm_connector *connector, static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_lvds_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable, }; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 88fb30dff758..8cdc674ff4b7 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1889,9 +1889,7 @@ done: static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { .mode_fixup = intel_sdvo_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_sdvo_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable }; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 16cb11405068..5dc08b931ff9 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1479,9 +1479,7 @@ out: static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { .mode_fixup = intel_tv_mode_fixup, - .prepare = intel_encoder_noop, .mode_set = intel_tv_mode_set, - .commit = intel_encoder_noop, .disable = intel_encoder_disable, }; -- cgit v1.2.3 From dbf2b54e78c6976af1f92cd370055a777ae99208 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 11:18:29 +0200 Subject: drm/i915: call crtc functions directly Instead of going through the crtc helper function tables. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d37a851d0b2d..ca1701081c56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6578,8 +6578,6 @@ static void intel_crtc_reset(struct drm_crtc *crtc) } static struct drm_crtc_helper_funcs intel_helper_funcs = { - .mode_fixup = intel_crtc_mode_fixup, - .mode_set = intel_crtc_mode_set, .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, .disable = intel_crtc_disable, @@ -6648,8 +6646,8 @@ bool intel_set_mode(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_encoder_helper_funcs *encoder_funcs; int saved_x, saved_y; struct drm_encoder *encoder; @@ -6691,7 +6689,7 @@ bool intel_set_mode(struct drm_crtc *crtc, } } - if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { + if (!(ret = intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) { DRM_DEBUG_KMS("CRTC fixup failed\n"); goto done; } @@ -6699,12 +6697,12 @@ bool intel_set_mode(struct drm_crtc *crtc, intel_crtc_prepare_encoders(dev); - crtc_funcs->prepare(crtc); + dev_priv->display.crtc_disable(crtc); /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ - ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); + ret = !intel_crtc_mode_set(crtc, mode, adjusted_mode, x, y, old_fb); if (!ret) goto done; @@ -6721,7 +6719,7 @@ bool intel_set_mode(struct drm_crtc *crtc, } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ - crtc_funcs->commit(crtc); + dev_priv->display.crtc_enable(crtc); /* Store real post-adjustment hardware mode. */ crtc->hwmode = *adjusted_mode; @@ -7055,9 +7053,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->active = true; /* force the pipe off on setup_init_config */ intel_crtc->bpp = 24; /* default for pre-Ironlake */ - intel_helper_funcs.prepare = dev_priv->display.crtc_disable; - intel_helper_funcs.commit = dev_priv->display.crtc_enable; - drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); } -- cgit v1.2.3 From 08a48469691a1b9ed6ee92e726b66d4e59ffc253 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 11:43:47 +0200 Subject: drm/i915: WARN when trying to enabled an unused crtc This is the first tiny step towards cross-checking the entire modeset state machine with WARNs. A crtc can only be enabled when it's actually in use, i.e. crtc->active imlies crtc->enabled. Unfortunately we can't (yet) check this when disabling the crtc, because the crtc helpers are a bit slopy with updating state and unconditionally update crtc->enabled before changing the hw state. Fixing that requires quite some more work. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ drivers/gpu/drm/i915/intel_drv.h | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca1701081c56..5ab86949014f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3215,6 +3215,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) u32 temp; bool is_pch_port; + WARN_ON(!crtc->enabled); + /* XXX: For compatability with the crtc helper code, call the encoder's * enable function unconditionally for now. */ if (intel_crtc->active) @@ -3391,6 +3393,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + WARN_ON(!crtc->enabled); + /* XXX: For compatability with the crtc helper code, call the encoder's * enable function unconditionally for now. */ if (intel_crtc->active) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 673e8d484bfa..36991dee2d40 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -158,7 +158,15 @@ struct intel_crtc { enum plane plane; u8 lut_r[256], lut_g[256], lut_b[256]; int dpms_mode; - bool active; /* is the crtc on? independent of the dpms mode */ + /* + * Whether the crtc and the connected output pipeline is active. Implies + * that crtc->enabled is set, i.e. the current mode configuration has + * some outputs connected to this crtc. + * + * Atm crtc->enabled is unconditionally updated _before_ the hw state is + * changed, hence we can only check this when enabling the crtc. + */ + bool active; bool primary_disabled; /* is the crtc obscured by a plane? */ bool lowfreq_avail; struct intel_overlay *overlay; -- cgit v1.2.3 From f0947c376f6944ade7079df9f84bbc958a893e0f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 13:10:34 +0200 Subject: drm/i915: Add interfaces to read out encoder/connector hw state It is all glorious if we try really hard to only enable/disable an entire display pipe to ensure that everyting happens in the right order. But if we don't know the output configuration when the driver takes over, this will all be for vain because we'll make the hw angry right on the first modeset - we don't know what outputs/ports are enabled and hence have to disable everything in a rather ad-hoc way. Hence we need to be able to read out the current hw state, so that we can properly tear down the current hw state on the first modeset. Obviously this is also a nice preparation for the fastboot work, where we try to avoid the modeset on driver load if it matches what the hw is currently using. Furthermore we'll be using these functions to cross-check the actual hw state with what we think it should be, to ensure that the modeset state machine actually works as advertised. This patch only contains the interface definitions and a little helper for the simple case where we have a 1:1 encoder to connector mapping. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_drv.h | 8 ++++++++ 2 files changed, 19 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5ab86949014f..7e7569b68039 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3584,6 +3584,17 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) encoder->connectors_active = false; } +/* Simple connector->get_hw_state implementation for encoders that support only + * one connector and no cloning and hence the encoder state determines the state + * of the connector. */ +bool intel_connector_get_hw_state(struct intel_connector *connector) +{ + enum pipe pipe; + struct intel_encoder *encoder = connector->encoder; + + return encoder->get_hw_state(encoder, &pipe); +} + static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 36991dee2d40..c39c70554891 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -144,12 +144,19 @@ struct intel_encoder { void (*hot_plug)(struct intel_encoder *); void (*enable)(struct intel_encoder *); void (*disable)(struct intel_encoder *); + /* Read out the current hw state of this connector, returning true if + * the encoder is active. If the encoder is enabled it also set the pipe + * it is connected to in the pipe parameter. */ + bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); int crtc_mask; }; struct intel_connector { struct drm_connector base; struct intel_encoder *encoder; + /* Reads out the current hw, returning true if the connector is enabled + * and active (i.e. dpms ON state). */ + bool (*get_hw_state)(struct intel_connector *); }; struct intel_crtc { @@ -426,6 +433,7 @@ extern void intel_encoder_disable(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); extern void intel_connector_dpms(struct drm_connector *, int mode); +extern bool intel_connector_get_hw_state(struct intel_connector *connector); static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) { -- cgit v1.2.3 From 24929352481f085c5f85d4d4cbc919ddf106d381 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 20:28:59 +0200 Subject: drm/i915: read out the modeset hw state at load and resume time ... instead of resetting a few things and hoping that this will work out. To properly disable the output pipelines at the initial modeset after resume or boot up we need to have an accurate picture of which outputs are enabled and connected to which crtcs. Otherwise we risk disabling things at the wrong time, which can lead to hangs (or at least royally confused panels), both requiring a walk to the reset button to fix. Hence read out the hw state with the freshly introduce get_hw_state functions and then sanitize it afterwards. For a full modeset readout (which would allow us to avoid the initial modeset at boot up) a few things are still missing: - Reading out the mode from the pipe, especially the dotclock computation is quite some fun. - Reading out the parameters for the stolen memory framebuffer and wrapping it up. - Reading out the pch pll connections - luckily the disable code simply bails out if the crtc doesn't have a pch pll attached (even for configurations that would need one). This patch here turned up tons of smelly stuff around resume: We restore tons of register in seemingly random way (well, not quite, but we're not too careful either), which leaves the hw in a rather ill-defined state: E.g. the port registers are sometimes unconditionally restore (lvds, crt), leaving us with an active encoder/connector but no active pipe connected to it. Luckily the hw state sanitizer detects this madness and fixes things up a bit. v2: When checking whether an encoder with active connectors has a crtc wire up to it, check for both the crtc _and_ it's active state. v3: - Extract intel_sanitize_encoder. - Manually disable active encoders without an active pipe. v4: Correclty fix up the pipe<->plane mapping on machines where we switch pipes/planes. Noticed by Chris Wilson, who also provided the fixup. v5: Spelling fix in a comment, noticed by Paulo Zanoni Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 278 ++++++++++++++++++++++++++--------- 3 files changed, 214 insertions(+), 66 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7ebb13b65133..4abac6d6c3e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -543,6 +543,7 @@ static int i915_drm_thaw(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); intel_modeset_init_hw(dev); + intel_modeset_setup_hw_state(dev); drm_mode_config_reset(dev); drm_irq_install(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fb46c6f356e4..9fce7820d96f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1539,6 +1539,7 @@ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); +extern void intel_modeset_setup_hw_state(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e7569b68039..8c8dbc90faf1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3589,7 +3589,7 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) * of the connector. */ bool intel_connector_get_hw_state(struct intel_connector *connector) { - enum pipe pipe; + enum pipe pipe = 0; struct intel_encoder *encoder = connector->encoder; return encoder->get_hw_state(encoder, &pipe); @@ -6533,65 +6533,6 @@ free_work: return ret; } -static void intel_sanitize_modesetting(struct drm_device *dev, - int pipe, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg, val; - int i; - - /* Clear any frame start delays used for debugging left by the BIOS */ - for_each_pipe(i) { - reg = PIPECONF(i); - I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); - } - - if (HAS_PCH_SPLIT(dev)) - return; - - /* Who knows what state these registers were left in by the BIOS or - * grub? - * - * If we leave the registers in a conflicting state (e.g. with the - * display plane reading from the other pipe than the one we intend - * to use) then when we attempt to teardown the active mode, we will - * not disable the pipes and planes in the correct order -- leaving - * a plane reading from a disabled pipe and possibly leading to - * undefined behaviour. - */ - - reg = DSPCNTR(plane); - val = I915_READ(reg); - - if ((val & DISPLAY_PLANE_ENABLE) == 0) - return; - if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe) - return; - - /* This display plane is active and attached to the other CPU pipe. */ - pipe = !pipe; - - /* Disable the plane and wait for it to stop reading from the pipe. */ - intel_disable_plane(dev_priv, plane, pipe); - intel_disable_pipe(dev_priv, pipe); -} - -static void intel_crtc_reset(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* Reset flags back to the 'unknown' status so that they - * will be correctly set on the initial modeset. - */ - intel_crtc->dpms_mode = -1; - - /* We need to fix up any BIOS configuration that conflicts with - * our expectations. - */ - intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); -} - static struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, @@ -7006,7 +6947,6 @@ fail: } static const struct drm_crtc_funcs intel_crtc_funcs = { - .reset = intel_crtc_reset, .cursor_set = intel_crtc_cursor_set, .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, @@ -7064,8 +7004,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; - intel_crtc_reset(&intel_crtc->base); - intel_crtc->active = true; /* force the pipe off on setup_init_config */ intel_crtc->bpp = 24; /* default for pre-Ironlake */ drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); @@ -7273,9 +7211,6 @@ static void intel_setup_outputs(struct drm_device *dev) intel_encoder_clones(encoder); } - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) ironlake_init_pch_refclk(dev); } @@ -7634,11 +7569,222 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); } +static void +intel_connector_break_all_links(struct intel_connector *connector) +{ + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + connector->encoder->connectors_active = false; + connector->encoder->base.crtc = NULL; +} + +static void intel_sanitize_crtc(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg, val; + + /* Clear the dpms state for compatibility with code still using that + * deprecated state variable. */ + crtc->dpms_mode = -1; + + /* Clear any frame start delays used for debugging left by the BIOS */ + reg = PIPECONF(crtc->pipe); + I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); + + /* We need to sanitize the plane -> pipe mapping first because this will + * disable the crtc (and hence change the state) if it is wrong. */ + if (!HAS_PCH_SPLIT(dev)) { + struct intel_connector *connector; + bool plane; + + reg = DSPCNTR(crtc->plane); + val = I915_READ(reg); + + if ((val & DISPLAY_PLANE_ENABLE) == 0 && + (!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe)) + goto ok; + + DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", + crtc->base.base.id); + + /* Pipe has the wrong plane attached and the plane is active. + * Temporarily change the plane mapping and disable everything + * ... */ + plane = crtc->plane; + crtc->plane = !plane; + dev_priv->display.crtc_disable(&crtc->base); + crtc->plane = plane; + + /* ... and break all links. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->encoder->base.crtc != &crtc->base) + continue; + + intel_connector_break_all_links(connector); + } + + WARN_ON(crtc->active); + crtc->base.enabled = false; + } +ok: + + /* Adjust the state of the output pipe according to whether we + * have active connectors/encoders. */ + intel_crtc_update_dpms(&crtc->base); + + if (crtc->active != crtc->base.enabled) { + struct intel_encoder *encoder; + + /* This can happen either due to bugs in the get_hw_state + * functions or because the pipe is force-enabled due to the + * pipe A quirk. */ + DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n", + crtc->base.base.id, + crtc->base.enabled ? "enabled" : "disabled", + crtc->active ? "enabled" : "disabled"); + + crtc->base.enabled = crtc->active; + + /* Because we only establish the connector -> encoder -> + * crtc links if something is active, this means the + * crtc is now deactivated. Break the links. connector + * -> encoder links are only establish when things are + * actually up, hence no need to break them. */ + WARN_ON(crtc->active); + + for_each_encoder_on_crtc(dev, &crtc->base, encoder) { + WARN_ON(encoder->connectors_active); + encoder->base.crtc = NULL; + } + } +} + +static void intel_sanitize_encoder(struct intel_encoder *encoder) +{ + struct intel_connector *connector; + struct drm_device *dev = encoder->base.dev; + + /* We need to check both for a crtc link (meaning that the + * encoder is active and trying to read from a pipe) and the + * pipe itself being active. */ + bool has_active_crtc = encoder->base.crtc && + to_intel_crtc(encoder->base.crtc)->active; + + if (encoder->connectors_active && !has_active_crtc) { + DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base)); + + /* Connector is active, but has no active pipe. This is + * fallout from our resume register restoring. Disable + * the encoder manually again. */ + if (encoder->base.crtc) { + DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base)); + encoder->disable(encoder); + } + + /* Inconsistent output/port/pipe state happens presumably due to + * a bug in one of the get_hw_state functions. Or someplace else + * in our code, like the register restore mess on resume. Clamp + * things to off as a safer default. */ + list_for_each_entry(connector, + &dev->mode_config.connector_list, + base.head) { + if (connector->encoder != encoder) + continue; + + intel_connector_break_all_links(connector); + } + } + /* Enabled encoders without active connectors will be fixed in + * the crtc fixup. */ +} + +/* Scan out the current hw modeset state, sanitizes it and maps it into the drm + * and i915 state tracking structures. */ +void intel_modeset_setup_hw_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + u32 tmp; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + + for_each_pipe(pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + + tmp = I915_READ(PIPECONF(pipe)); + if (tmp & PIPECONF_ENABLE) + crtc->active = true; + else + crtc->active = false; + + crtc->base.enabled = crtc->active; + + DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", + crtc->base.base.id, + crtc->active ? "enabled" : "disabled"); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + pipe = 0; + + if (encoder->get_hw_state(encoder, &pipe)) { + encoder->base.crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + } else { + encoder->base.crtc = NULL; + } + + encoder->connectors_active = false; + DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe=%i\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base), + encoder->base.crtc ? "enabled" : "disabled", + pipe); + } + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->get_hw_state(connector)) { + connector->base.dpms = DRM_MODE_DPMS_ON; + connector->encoder->connectors_active = true; + connector->base.encoder = &connector->encoder->base; + } else { + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + } + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", + connector->base.base.id, + drm_get_connector_name(&connector->base), + connector->base.encoder ? "enabled" : "disabled"); + } + + /* HW state is read out, now we need to sanitize this mess. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + intel_sanitize_encoder(encoder); + } + + for_each_pipe(pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + intel_sanitize_crtc(crtc); + } +} + void intel_modeset_gem_init(struct drm_device *dev) { intel_modeset_init_hw(dev); intel_setup_overlay(dev); + + intel_modeset_setup_hw_state(dev); } void intel_modeset_cleanup(struct drm_device *dev) -- cgit v1.2.3 From 0a91ca29215a41760cca03999498959d0e05d9b3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Jul 2012 21:54:27 +0200 Subject: drm/i915: check connector hw/sw state Atm we can only check the connector state after a dpms call - while doing modeset with the copy&pasted crtc helper code things are too ill-defined for proper checking. But the idea is very much to call this check from the modeset code, too. v2: Fix dpms check and don't presume that if the hw isn't on that it must not be linked up with an encoder (it could simply be switched off with the dpms state). Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 37 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 2 ++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_dvo.c | 2 ++ drivers/gpu/drm/i915/intel_sdvo.c | 2 ++ 6 files changed, 46 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index b0fadd00a4dc..c002d260c1a4 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -176,6 +176,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) intel_crtc_update_dpms(crtc); } + + intel_connector_check_state(to_intel_connector(connector)); } static int intel_crt_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8c8dbc90faf1..15e4a652dee6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3562,6 +3562,41 @@ void intel_encoder_dpms(struct intel_encoder *encoder, int mode) } } +/* Cross check the actual hw state with our own modeset state tracking (and it's + * internal consistency). */ +void intel_connector_check_state(struct intel_connector *connector) +{ + if (connector->get_hw_state(connector)) { + struct intel_encoder *encoder = connector->encoder; + struct drm_crtc *crtc; + bool encoder_enabled; + enum pipe pipe; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.base.id, + drm_get_connector_name(&connector->base)); + + WARN(connector->base.dpms == DRM_MODE_DPMS_OFF, + "wrong connector dpms state\n"); + WARN(connector->base.encoder != &encoder->base, + "active connector not linked to encoder\n"); + WARN(!encoder->connectors_active, + "encoder->connectors_active not set\n"); + + encoder_enabled = encoder->get_hw_state(encoder, &pipe); + WARN(!encoder_enabled, "encoder not enabled\n"); + if (WARN_ON(!encoder->base.crtc)) + return; + + crtc = encoder->base.crtc; + + WARN(!crtc->enabled, "crtc not enabled\n"); + WARN(!to_intel_crtc(crtc)->active, "crtc not active\n"); + WARN(pipe != to_intel_crtc(crtc)->pipe, + "encoder active on the wrong pipe\n"); + } +} + /* Even simpler default implementation, if there's really no special case to * consider. */ void intel_connector_dpms(struct drm_connector *connector, int mode) @@ -3582,6 +3617,8 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) intel_encoder_dpms(encoder, mode); else encoder->connectors_active = false; + + intel_connector_check_state(to_intel_connector(connector)); } /* Simple connector->get_hw_state implementation for encoders that support only diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e3928b922825..96fd1e7ff02e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1367,6 +1367,8 @@ intel_dp_dpms(struct drm_connector *connector, int mode) intel_encoder_dpms(&intel_dp->base, mode); WARN_ON(intel_dp->dpms_mode != DRM_MODE_DPMS_ON); } + + intel_connector_check_state(to_intel_connector(connector)); } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4daa7e65b04a..e2116d96bd6f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -434,6 +434,7 @@ extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); +extern void intel_connector_check_state(struct intel_connector *); static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) { diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index e9397b72b4f3..17dc8bebf8f2 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -188,6 +188,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) intel_crtc_update_dpms(crtc); } + + intel_connector_check_state(to_intel_connector(connector)); } static int intel_dvo_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 4a735a50f471..198bb8965b8d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1274,6 +1274,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) intel_sdvo_set_encoder_power_state(intel_sdvo, mode); intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } + + intel_connector_check_state(to_intel_connector(connector)); } static int intel_sdvo_mode_valid(struct drm_connector *connector, -- cgit v1.2.3 From 84bb65bded92028a6c803fef332586fedbe092b2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 3 Jul 2012 13:19:00 +0200 Subject: drm/i915: rip out intel_crtc->dpms_mode Afaict this has been used for two things: - To prevent the crtc enable code from being run twice. We have now intel_crtc->active to track this in a more precise way. - To ensure the code copes correctly with the unknown hw state after boot and resume. Thanks to the hw state readout and sanitize code we have now a better way to handle this. The only thing it still does is complicate our modeset state space. Having outlived its usefullness, let it just die. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 17 ----------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 18 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 15e4a652dee6..ad03db4b7a5b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3470,18 +3470,10 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) struct intel_encoder *intel_encoder; int pipe = intel_crtc->pipe; bool enabled, enable = false; - int mode; for_each_encoder_on_crtc(dev, crtc, intel_encoder) enable |= intel_encoder->connectors_active; - mode = enable ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF; - - if (intel_crtc->dpms_mode == mode) - return; - - intel_crtc->dpms_mode = mode; - if (enable) dev_priv->display.crtc_enable(crtc); else @@ -5037,11 +5029,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, x, y, old_fb); drm_vblank_post_modeset(dev, pipe); - if (ret) - intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; - else - intel_crtc->dpms_mode = DRM_MODE_DPMS_ON; - return ret; } @@ -7621,10 +7608,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; u32 reg, val; - /* Clear the dpms state for compatibility with code still using that - * deprecated state variable. */ - crtc->dpms_mode = -1; - /* Clear any frame start delays used for debugging left by the BIOS */ reg = PIPECONF(crtc->pipe); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e2116d96bd6f..a7d79dee2be3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -164,7 +164,6 @@ struct intel_crtc { enum pipe pipe; enum plane plane; u8 lut_r[256], lut_g[256], lut_b[256]; - int dpms_mode; /* * Whether the crtc and the connected output pipeline is active. Implies * that crtc->enabled is set, i.e. the current mode configuration has -- cgit v1.2.3 From 7fad798e16fecddd41c6a91728a09f0b9507e40c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Jul 2012 17:51:47 +0200 Subject: drm/i915: ensure the force pipe A quirk is actually followed Many BIOSen forget to turn on the pipe A after resume (because they actually don't turn on anything), so we have to do that ourselves when sanitizing the hw state. I've discovered this due to the recent addition of a pipe WARN that takes the force quirk into account. v2: Actually try to enable the pipe with a proper configuration instead of simpyl switching it on with whatever random state the bios left it in after resume. v3: Fixup rebase conflict - the load_detect functions have lost their encoder argument. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ad03db4b7a5b..090ba2dba696 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7602,6 +7602,33 @@ intel_connector_break_all_links(struct intel_connector *connector) connector->encoder->base.crtc = NULL; } +static void intel_enable_pipe_a(struct drm_device *dev) +{ + struct intel_connector *connector; + struct drm_connector *crt = NULL; + struct intel_load_detect_pipe load_detect_temp; + + /* We can't just switch on the pipe A, we need to set things up with a + * proper mode and output configuration. As a gross hack, enable pipe A + * by enabling the load detect pipe once. */ + list_for_each_entry(connector, + &dev->mode_config.connector_list, + base.head) { + if (connector->encoder->type == INTEL_OUTPUT_ANALOG) { + crt = &connector->base; + break; + } + } + + if (!crt) + return; + + if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp)) + intel_release_load_detect_pipe(crt, &load_detect_temp); + + +} + static void intel_sanitize_crtc(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -7650,6 +7677,15 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) } ok: + if (dev_priv->quirks & QUIRK_PIPEA_FORCE && + crtc->pipe == PIPE_A && !crtc->active) { + /* BIOS forgot to enable pipe A, this mostly happens after + * resume. Force-enable the pipe to fix this, the update_dpms + * call below we restore the pipe to the right state, but leave + * the required bits on. */ + intel_enable_pipe_a(dev); + } + /* Adjust the state of the output pipe according to whether we * have active connectors/encoders. */ intel_crtc_update_dpms(&crtc->base); -- cgit v1.2.3 From d9e55608cdcd875c4c1f319c1a5a438c7cc55f57 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Jul 2012 22:16:09 +0200 Subject: drm/i915: introduce struct intel_set_config intel_crtc_set_config is an unwidly beast and is in serious need of some function extraction. To facilitate that, introduce a struct to keep track of all the state involved. Atm it doesn't do much more than keep track of all the allocated memory. v2: Apply some bikeshed to intel_set_config_free, as suggested by Jesse Barnes. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 74 ++++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 6 +++ 2 files changed, 48 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 090ba2dba696..f77140d161a8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6723,17 +6723,29 @@ done: return ret; } +static void intel_set_config_free(struct intel_set_config *config) +{ + if (!config) + return; + + kfree(config->save_connectors); + kfree(config->save_encoders); + kfree(config->save_crtcs); + kfree(config); +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; - struct drm_crtc *save_crtcs, *new_crtc, *crtc; - struct drm_encoder *save_encoders, *new_encoder, *encoder; + struct drm_crtc *new_crtc, *crtc; + struct drm_encoder *new_encoder, *encoder; struct drm_framebuffer *old_fb = NULL; bool mode_changed = false; /* if true do a full mode set */ bool fb_changed = false; /* if true and !mode_changed just do a flip */ - struct drm_connector *save_connectors, *connector; + struct drm_connector *connector; int count = 0, ro; struct drm_mode_set save_set; + struct intel_set_config *config; int ret; int i; @@ -6762,27 +6774,27 @@ static int intel_crtc_set_config(struct drm_mode_set *set) dev = set->crtc->dev; + ret = -ENOMEM; + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) + goto out_config; + /* Allocate space for the backup of all (non-pointer) crtc, encoder and * connector data. */ - save_crtcs = kzalloc(dev->mode_config.num_crtc * - sizeof(struct drm_crtc), GFP_KERNEL); - if (!save_crtcs) - return -ENOMEM; + config->save_crtcs = kzalloc(dev->mode_config.num_crtc * + sizeof(struct drm_crtc), GFP_KERNEL); + if (!config->save_crtcs) + goto out_config; - save_encoders = kzalloc(dev->mode_config.num_encoder * - sizeof(struct drm_encoder), GFP_KERNEL); - if (!save_encoders) { - kfree(save_crtcs); - return -ENOMEM; - } + config->save_encoders = kzalloc(dev->mode_config.num_encoder * + sizeof(struct drm_encoder), GFP_KERNEL); + if (!config->save_encoders) + goto out_config; - save_connectors = kzalloc(dev->mode_config.num_connector * - sizeof(struct drm_connector), GFP_KERNEL); - if (!save_connectors) { - kfree(save_crtcs); - kfree(save_encoders); - return -ENOMEM; - } + config->save_connectors = kzalloc(dev->mode_config.num_connector * + sizeof(struct drm_connector), GFP_KERNEL); + if (!config->save_connectors) + goto out_config; /* Copy data. Note that driver private data is not affected. * Should anything bad happen only the expected state is @@ -6790,17 +6802,17 @@ static int intel_crtc_set_config(struct drm_mode_set *set) */ count = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - save_crtcs[count++] = *crtc; + config->save_crtcs[count++] = *crtc; } count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - save_encoders[count++] = *encoder; + config->save_encoders[count++] = *encoder; } count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - save_connectors[count++] = *connector; + config->save_connectors[count++] = *connector; } save_set.crtc = set->crtc; @@ -6936,26 +6948,25 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } } - kfree(save_connectors); - kfree(save_encoders); - kfree(save_crtcs); + intel_set_config_free(config); + return 0; fail: /* Restore all previous data. */ count = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - *crtc = save_crtcs[count++]; + *crtc = config->save_crtcs[count++]; } count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - *encoder = save_encoders[count++]; + *encoder = config->save_encoders[count++]; } count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - *connector = save_connectors[count++]; + *connector = config->save_connectors[count++]; } /* Try to restore the config */ @@ -6964,9 +6975,8 @@ fail: save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); - kfree(save_connectors); - kfree(save_encoders); - kfree(save_crtcs); +out_config: + intel_set_config_free(config); return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c080c829cbff..1cb64dd9c7f0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -423,6 +423,12 @@ extern void intel_panel_disable_backlight(struct drm_device *dev); extern void intel_panel_destroy_backlight(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); +struct intel_set_config { + struct drm_connector *save_connectors; + struct drm_encoder *save_encoders; + struct drm_crtc *save_crtcs; +}; + extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); extern void intel_crtc_load_lut(struct drm_crtc *crtc); -- cgit v1.2.3 From 85f9eb71fec3322dc3670207ca5c1706467e701c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Jul 2012 22:24:08 +0200 Subject: drm/i915: extract modeset config save/restore code At the end this won't be of much use to us, but meanwhile just extract it to get a better overview of what exactly set_config does. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 127 +++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 51 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f77140d161a8..b60745d0881e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6734,11 +6734,82 @@ static void intel_set_config_free(struct intel_set_config *config) kfree(config); } +static int intel_set_config_save_state(struct drm_device *dev, + struct intel_set_config *config) +{ + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + int count; + + /* Allocate space for the backup of all (non-pointer) crtc, encoder and + * connector data. */ + config->save_crtcs = kzalloc(dev->mode_config.num_crtc * + sizeof(struct drm_crtc), GFP_KERNEL); + if (!config->save_crtcs) + return -ENOMEM; + + config->save_encoders = kzalloc(dev->mode_config.num_encoder * + sizeof(struct drm_encoder), GFP_KERNEL); + if (!config->save_encoders) + return -ENOMEM; + + config->save_connectors = kzalloc(dev->mode_config.num_connector * + sizeof(struct drm_connector), GFP_KERNEL); + if (!config->save_connectors) + return -ENOMEM; + + /* Copy data. Note that driver private data is not affected. + * Should anything bad happen only the expected state is + * restored, not the drivers personal bookkeeping. + */ + count = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + config->save_crtcs[count++] = *crtc; + } + + count = 0; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + config->save_encoders[count++] = *encoder; + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + config->save_connectors[count++] = *connector; + } + + return 0; +} + +static void intel_set_config_restore_state(struct drm_device *dev, + struct intel_set_config *config) +{ + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + int count; + + count = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + *crtc = config->save_crtcs[count++]; + } + + count = 0; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + *encoder = config->save_encoders[count++]; + } + + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + *connector = config->save_connectors[count++]; + } +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; - struct drm_crtc *new_crtc, *crtc; - struct drm_encoder *new_encoder, *encoder; + struct drm_crtc *new_crtc; + struct drm_encoder *new_encoder; struct drm_framebuffer *old_fb = NULL; bool mode_changed = false; /* if true do a full mode set */ bool fb_changed = false; /* if true and !mode_changed just do a flip */ @@ -6779,42 +6850,10 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (!config) goto out_config; - /* Allocate space for the backup of all (non-pointer) crtc, encoder and - * connector data. */ - config->save_crtcs = kzalloc(dev->mode_config.num_crtc * - sizeof(struct drm_crtc), GFP_KERNEL); - if (!config->save_crtcs) - goto out_config; - - config->save_encoders = kzalloc(dev->mode_config.num_encoder * - sizeof(struct drm_encoder), GFP_KERNEL); - if (!config->save_encoders) - goto out_config; - - config->save_connectors = kzalloc(dev->mode_config.num_connector * - sizeof(struct drm_connector), GFP_KERNEL); - if (!config->save_connectors) + ret = intel_set_config_save_state(dev, config); + if (ret) goto out_config; - /* Copy data. Note that driver private data is not affected. - * Should anything bad happen only the expected state is - * restored, not the drivers personal bookkeeping. - */ - count = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - config->save_crtcs[count++] = *crtc; - } - - count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - config->save_encoders[count++] = *encoder; - } - - count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - config->save_connectors[count++] = *connector; - } - save_set.crtc = set->crtc; save_set.mode = &set->crtc->mode; save_set.x = set->crtc->x; @@ -6953,21 +6992,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) return 0; fail: - /* Restore all previous data. */ - count = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - *crtc = config->save_crtcs[count++]; - } - - count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - *encoder = config->save_encoders[count++]; - } - - count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - *connector = config->save_connectors[count++]; - } + intel_set_config_restore_state(dev, config); /* Try to restore the config */ if (mode_changed && -- cgit v1.2.3 From 5e2b584ed1563c4c5199510710df6eaa1a36f3b1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Jul 2012 22:41:29 +0200 Subject: drm/i915: extract intel_set_config_compute_mode_changes This computes what exactly changed in the modeset configuration, i.e. whether a full modeset is required or only an update of the framebuffer base address or no change at all. In the future we might add more checks for e.g. when only the output mode changed, so that we could do a minimal modeset for outputs that support this. Like the lvds/eDP panels where we only need to update the panel fitter. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 81 ++++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 3 ++ 2 files changed, 48 insertions(+), 36 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b60745d0881e..4ec0ccb64339 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6805,14 +6805,46 @@ static void intel_set_config_restore_state(struct drm_device *dev, } } +static void +intel_set_config_compute_mode_changes(struct drm_mode_set *set, + struct intel_set_config *config) +{ + + /* We should be able to check here if the fb has the same properties + * and then just flip_or_move it */ + if (set->crtc->fb != set->fb) { + /* If we have no fb then treat it as a full mode set */ + if (set->crtc->fb == NULL) { + DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); + config->mode_changed = true; + } else if (set->fb == NULL) { + config->mode_changed = true; + } else if (set->fb->depth != set->crtc->fb->depth) { + config->mode_changed = true; + } else if (set->fb->bits_per_pixel != + set->crtc->fb->bits_per_pixel) { + config->mode_changed = true; + } else + config->fb_changed = true; + } + + if (set->x != set->crtc->x || set->y != set->crtc->y) + config->fb_changed = true; + + if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { + DRM_DEBUG_KMS("modes are different, full mode set\n"); + drm_mode_debug_printmodeline(&set->crtc->mode); + drm_mode_debug_printmodeline(set->mode); + config->mode_changed = true; + } +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_crtc *new_crtc; struct drm_encoder *new_encoder; struct drm_framebuffer *old_fb = NULL; - bool mode_changed = false; /* if true do a full mode set */ - bool fb_changed = false; /* if true and !mode_changed just do a flip */ struct drm_connector *connector; int count = 0, ro; struct drm_mode_set save_set; @@ -6860,33 +6892,11 @@ static int intel_crtc_set_config(struct drm_mode_set *set) save_set.y = set->crtc->y; save_set.fb = set->crtc->fb; - /* We should be able to check here if the fb has the same properties - * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) { - /* If we have no fb then treat it as a full mode set */ - if (set->crtc->fb == NULL) { - DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); - mode_changed = true; - } else if (set->fb == NULL) { - mode_changed = true; - } else if (set->fb->depth != set->crtc->fb->depth) { - mode_changed = true; - } else if (set->fb->bits_per_pixel != - set->crtc->fb->bits_per_pixel) { - mode_changed = true; - } else - fb_changed = true; - } - - if (set->x != set->crtc->x || set->y != set->crtc->y) - fb_changed = true; - - if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { - DRM_DEBUG_KMS("modes are different, full mode set\n"); - drm_mode_debug_printmodeline(&set->crtc->mode); - drm_mode_debug_printmodeline(set->mode); - mode_changed = true; - } + /* Compute whether we need a full modeset, only an fb base update or no + * change at all. In the future we might also check whether only the + * mode changed, e.g. for LVDS where we only change the panel fitter in + * such cases. */ + intel_set_config_compute_mode_changes(set, config); /* a) traverse passed in connector list and get encoders for them */ count = 0; @@ -6902,7 +6912,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (new_encoder != connector->encoder) { DRM_DEBUG_KMS("encoder changed, full mode switch\n"); - mode_changed = true; + config->mode_changed = true; /* If the encoder is reused for another connector, then * the appropriate crtc will be set later. */ @@ -6930,12 +6940,11 @@ static int intel_crtc_set_config(struct drm_mode_set *set) /* Make sure the new CRTC will work with the encoder */ if (new_crtc && !intel_encoder_crtc_ok(connector->encoder, new_crtc)) { - ret = -EINVAL; - goto fail; + return -EINVAL; } if (new_crtc != connector->encoder->crtc) { DRM_DEBUG_KMS("crtc changed, full mode switch\n"); - mode_changed = true; + config->mode_changed = true; connector->encoder->crtc = new_crtc; } if (new_crtc) { @@ -6948,7 +6957,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } } - if (mode_changed) { + if (config->mode_changed) { set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); if (set->crtc->enabled) { DRM_DEBUG_KMS("attempting to set mode from" @@ -6972,7 +6981,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } } drm_helper_disable_unused_functions(dev); - } else if (fb_changed) { + } else if (config->fb_changed) { set->crtc->x = set->x; set->crtc->y = set->y; @@ -6995,7 +7004,7 @@ fail: intel_set_config_restore_state(dev, config); /* Try to restore the config */ - if (mode_changed && + if (config->mode_changed && !intel_set_mode(save_set.crtc, save_set.mode, save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1cb64dd9c7f0..fad11c83ba40 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -427,6 +427,9 @@ struct intel_set_config { struct drm_connector *save_connectors; struct drm_encoder *save_encoders; struct drm_crtc *save_crtcs; + + bool fb_changed; + bool mode_changed; }; extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, -- cgit v1.2.3 From 2e43105183bcecfbe56733785c05bf182df60082 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Jul 2012 22:42:15 +0200 Subject: drm/i915: extract intel_set_config_update_output_state Note that this function already clobbers the mode config state, so we have to clean things up if something fails. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 121 +++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 54 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4ec0ccb64339..c10fb2e57af2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6839,64 +6839,15 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, } } -static int intel_crtc_set_config(struct drm_mode_set *set) +static int +intel_set_config_update_output_state(struct drm_device *dev, + struct drm_mode_set *set, + struct intel_set_config *config) { - struct drm_device *dev; struct drm_crtc *new_crtc; struct drm_encoder *new_encoder; - struct drm_framebuffer *old_fb = NULL; struct drm_connector *connector; - int count = 0, ro; - struct drm_mode_set save_set; - struct intel_set_config *config; - int ret; - int i; - - DRM_DEBUG_KMS("\n"); - - if (!set) - return -EINVAL; - - if (!set->crtc) - return -EINVAL; - - if (!set->crtc->helper_private) - return -EINVAL; - - if (!set->mode) - set->fb = NULL; - - if (set->fb) { - DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", - set->crtc->base.id, set->fb->base.id, - (int)set->num_connectors, set->x, set->y); - } else { - DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); - return intel_crtc_helper_disable(set->crtc); - } - - dev = set->crtc->dev; - - ret = -ENOMEM; - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) - goto out_config; - - ret = intel_set_config_save_state(dev, config); - if (ret) - goto out_config; - - save_set.crtc = set->crtc; - save_set.mode = &set->crtc->mode; - save_set.x = set->crtc->x; - save_set.y = set->crtc->y; - save_set.fb = set->crtc->fb; - - /* Compute whether we need a full modeset, only an fb base update or no - * change at all. In the future we might also check whether only the - * mode changed, e.g. for LVDS where we only change the panel fitter in - * such cases. */ - intel_set_config_compute_mode_changes(set, config); + int count, ro; /* a) traverse passed in connector list and get encoders for them */ count = 0; @@ -6957,6 +6908,68 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } } + return 0; +} + +static int intel_crtc_set_config(struct drm_mode_set *set) +{ + struct drm_device *dev; + struct drm_framebuffer *old_fb = NULL; + struct drm_mode_set save_set; + struct intel_set_config *config; + int ret; + int i; + + DRM_DEBUG_KMS("\n"); + + if (!set) + return -EINVAL; + + if (!set->crtc) + return -EINVAL; + + if (!set->crtc->helper_private) + return -EINVAL; + + if (!set->mode) + set->fb = NULL; + + if (set->fb) { + DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", + set->crtc->base.id, set->fb->base.id, + (int)set->num_connectors, set->x, set->y); + } else { + DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); + return intel_crtc_helper_disable(set->crtc); + } + + dev = set->crtc->dev; + + ret = -ENOMEM; + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) + goto out_config; + + ret = intel_set_config_save_state(dev, config); + if (ret) + goto out_config; + + save_set.crtc = set->crtc; + save_set.mode = &set->crtc->mode; + save_set.x = set->crtc->x; + save_set.y = set->crtc->y; + save_set.fb = set->crtc->fb; + + /* Compute whether we need a full modeset, only an fb base update or no + * change at all. In the future we might also check whether only the + * mode changed, e.g. for LVDS where we only change the panel fitter in + * such cases. */ + intel_set_config_compute_mode_changes(set, config); + + ret = intel_set_config_update_output_state(dev, set, config); + if (ret) + goto fail; + if (config->mode_changed) { set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); if (set->crtc->enabled) { -- cgit v1.2.3 From 431e50f799b356a899a63924883f2b0d1bfaf7b3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Jul 2012 17:53:42 +0200 Subject: drm/i915: implement crtc helper semantics relied upon by the fb helper Yikes! But yeah, we have to do this until someone volunteers to clean up the fb helper and rid it of its incetious relationship with the crtc helper code. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c10fb2e57af2..71cb90d763bd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6934,6 +6934,12 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (!set->mode) set->fb = NULL; + /* The fb helper likes to play gross jokes with ->mode_set_config. + * Unfortunately the crtc helper doesn't do much at all for this case, + * so we have to cope with this madness until the fb helper is fixed up. */ + if (set->fb && set->num_connectors == 0) + return 0; + if (set->fb) { DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", set->crtc->base.id, set->fb->base.id, -- cgit v1.2.3 From 835c5873d6e38cb317091ace7c1f3c40cc0607ce Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Jul 2012 18:11:08 +0200 Subject: drm/i915: don't update the fb base if there is no fb Otherwise we'll set_fb complains pretty loudly if we the crtc is off and userspace moves the NULL fb around a bit. Yeah, this actually happens in the wild ... Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 71cb90d763bd..01d871b16f62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6828,7 +6828,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, config->fb_changed = true; } - if (set->x != set->crtc->x || set->y != set->crtc->y) + if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) config->fb_changed = true; if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { -- cgit v1.2.3 From 8d3e375e77f09174038b9bfb02b8423cbb187959 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Jul 2012 16:09:09 +0200 Subject: drm/i915: convert pointless error checks in set_config to BUGs Because they all are, the ioctl command never calls us with any of these violated. Also drop a equally pointless empty debug message (and also in set_cursor, while we're at it). With all these changes, intel_crtc_set_config is neatly condensed down to it's essence, the actual modeset code (or fb update calling code) v2: The fb helper code is actually stretching ->set_config semantics a bit, it calls it with set->mode == NULL but set->fb != NULL. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 01d871b16f62..9485c5a7f8a5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5462,8 +5462,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, uint32_t addr; int ret; - DRM_DEBUG_KMS("\n"); - /* if we want to turn off the cursor ignore width and height */ if (!handle) { DRM_DEBUG_KMS("cursor off\n"); @@ -6920,16 +6918,9 @@ static int intel_crtc_set_config(struct drm_mode_set *set) int ret; int i; - DRM_DEBUG_KMS("\n"); - - if (!set) - return -EINVAL; - - if (!set->crtc) - return -EINVAL; - - if (!set->crtc->helper_private) - return -EINVAL; + BUG_ON(!set); + BUG_ON(!set->crtc); + BUG_ON(!set->crtc->helper_private); if (!set->mode) set->fb = NULL; -- cgit v1.2.3 From 1aa4b628ee63f55db96c7e820257b6e4948abb74 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Jul 2012 16:20:48 +0200 Subject: drm/i915: don't save all the encoder/crtc state in set_config We actually only touch the connector -> encoder and encoder -> crtc linking. So it's enough to just save/restore that. While at it, also switch to kcalloc to allocate these arrays (omission in the commit message spotted by Jesse Barnes). Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 28 +++++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9485c5a7f8a5..a2ce117aa794 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6726,8 +6726,8 @@ static void intel_set_config_free(struct intel_set_config *config) if (!config) return; - kfree(config->save_connectors); - kfree(config->save_encoders); + kfree(config->save_connector_encoders); + kfree(config->save_encoder_crtcs); kfree(config->save_crtcs); kfree(config); } @@ -6742,19 +6742,21 @@ static int intel_set_config_save_state(struct drm_device *dev, /* Allocate space for the backup of all (non-pointer) crtc, encoder and * connector data. */ - config->save_crtcs = kzalloc(dev->mode_config.num_crtc * + config->save_crtcs = kcalloc(dev->mode_config.num_crtc, sizeof(struct drm_crtc), GFP_KERNEL); if (!config->save_crtcs) return -ENOMEM; - config->save_encoders = kzalloc(dev->mode_config.num_encoder * - sizeof(struct drm_encoder), GFP_KERNEL); - if (!config->save_encoders) + config->save_encoder_crtcs = + kcalloc(dev->mode_config.num_encoder, + sizeof(struct drm_crtc *), GFP_KERNEL); + if (!config->save_encoder_crtcs) return -ENOMEM; - config->save_connectors = kzalloc(dev->mode_config.num_connector * - sizeof(struct drm_connector), GFP_KERNEL); - if (!config->save_connectors) + config->save_connector_encoders = + kcalloc(dev->mode_config.num_connector, + sizeof(struct drm_encoder *), GFP_KERNEL); + if (!config->save_connector_encoders) return -ENOMEM; /* Copy data. Note that driver private data is not affected. @@ -6768,12 +6770,12 @@ static int intel_set_config_save_state(struct drm_device *dev, count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - config->save_encoders[count++] = *encoder; + config->save_encoder_crtcs[count++] = encoder->crtc; } count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - config->save_connectors[count++] = *connector; + config->save_connector_encoders[count++] = connector->encoder; } return 0; @@ -6794,12 +6796,12 @@ static void intel_set_config_restore_state(struct drm_device *dev, count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - *encoder = config->save_encoders[count++]; + encoder->crtc = config->save_encoder_crtcs[count++]; } count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - *connector = config->save_connectors[count++]; + connector->encoder = config->save_connector_encoders[count++]; } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fad11c83ba40..4946282bd324 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -424,8 +424,8 @@ extern void intel_panel_destroy_backlight(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); struct intel_set_config { - struct drm_connector *save_connectors; - struct drm_encoder *save_encoders; + struct drm_encoder **save_connector_encoders; + struct drm_crtc **save_encoder_crtcs; struct drm_crtc *save_crtcs; bool fb_changed; -- cgit v1.2.3 From 9a935856992d68b9194f825ce6e115df7ecc5bca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Jul 2012 22:34:27 +0200 Subject: drm/i915: stage modeset output changes This is the core of the new modeset logic. The current code which is based upon the crtc helper code first updates all the link of the new display pipeline and then calls the lower-level set_mode function to execute the required callbacks to get there. The issue with this approach is that for disabling we need to know the _current_ display pipe state, not the new one. Hence we need to stage the new state of the display pipe and only update it once we have disabled the current configuration and before we start to update the hw registers with the new configuration. This patch here just prepares the ground by switching the new output state computation to these staging pointers. To make it clearer, rename the old update_output_state function to stage_output_state. A few peculiarities: - We're also calling the set_mode function at various places to update properties. Hence after a successfule modeset we need to stage the current configuration (for otherwise we might fall back again). This happens automatically because as part of the (successful) modeset we need to copy the staged state to the real one. But for the hw readout code we need to make sure that this happens, too. - Teach the new staged output state computation code the required smarts to handle the disabling of outputs. The current code handles this in a special case, but to better handle global modeset changes covering more than one crtc, we want to do this all in the same low-level modeset code. - The actual modeset code is still a bit ugly and wants to know the new crtc->enabled state a bit early. Follow-on patches will clean that up, for now we have to apply the staged output configuration early, outside of the set_mode functions. - Improve/add comments in stage_output_state. Essentially all that is left to do now is move the disabling code into set_mode and then move the staged state update code also into set_mode, at the right place between disabling things and calling the mode_set callbacks for the new configuration. v2: Disabling a crtc works by passing in a NULL mode or fb, userspace doesn't hand in the list of connectors. We therefore need to detect this case manually and tear down all the output links. v3: Properly update the output staging pointers after having read out the hw state. v4: Simplify the code, add more DRM_DEBUG_KMS output and check a few assumptions with WARN_ON. Essentially all things that I've noticed while debugging issues in other places of the code. v4: Correctly disable the old set of connectors when enabling an already enabled crtc on a new set of crtc. Reported by Paulo Zanoni. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 174 ++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 16 ++++ 2 files changed, 146 insertions(+), 44 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a2ce117aa794..5031e0c4a02e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6619,6 +6619,51 @@ intel_crtc_prepare_encoders(struct drm_device *dev) } } +/** + * intel_modeset_update_staged_output_state + * + * Updates the staged output configuration state, e.g. after we've read out the + * current hw state. + */ +static void intel_modeset_update_staged_output_state(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + connector->new_encoder = + to_intel_encoder(connector->base.encoder); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + encoder->new_crtc = + to_intel_crtc(encoder->base.crtc); + } +} + +/** + * intel_modeset_commit_output_state + * + * This function copies the stage display pipe configuration to the real one. + */ +static void intel_modeset_commit_output_state(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + connector->base.encoder = &connector->new_encoder->base; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + encoder->base.crtc = &encoder->new_crtc->base; + } +} + bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb) @@ -6785,8 +6830,8 @@ static void intel_set_config_restore_state(struct drm_device *dev, struct intel_set_config *config) { struct drm_crtc *crtc; - struct drm_encoder *encoder; - struct drm_connector *connector; + struct intel_encoder *encoder; + struct intel_connector *connector; int count; count = 0; @@ -6795,13 +6840,15 @@ static void intel_set_config_restore_state(struct drm_device *dev, } count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - encoder->crtc = config->save_encoder_crtcs[count++]; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + encoder->new_crtc = + to_intel_crtc(config->save_encoder_crtcs[count++]); } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->encoder = config->save_connector_encoders[count++]; + list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { + connector->new_encoder = + to_intel_encoder(config->save_connector_encoders[count++]); } } @@ -6840,73 +6887,106 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, } static int -intel_set_config_update_output_state(struct drm_device *dev, - struct drm_mode_set *set, - struct intel_set_config *config) +intel_modeset_stage_output_state(struct drm_device *dev, + struct drm_mode_set *set, + struct intel_set_config *config) { struct drm_crtc *new_crtc; - struct drm_encoder *new_encoder; - struct drm_connector *connector; + struct intel_connector *connector; + struct intel_encoder *encoder; int count, ro; - /* a) traverse passed in connector list and get encoders for them */ + /* The upper layers ensure that we either disabl a crtc or have a list + * of connectors. For paranoia, double-check this. */ + WARN_ON(!set->fb && (set->num_connectors != 0)); + WARN_ON(set->fb && (set->num_connectors == 0)); + count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - new_encoder = connector->encoder; + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + /* Otherwise traverse passed in connector list and get encoders + * for them. */ for (ro = 0; ro < set->num_connectors; ro++) { - if (set->connectors[ro] == connector) { - new_encoder = - &intel_attached_encoder(connector)->base; + if (set->connectors[ro] == &connector->base) { + connector->new_encoder = connector->encoder; break; } } - if (new_encoder != connector->encoder) { + /* If we disable the crtc, disable all its connectors. Also, if + * the connector is on the changing crtc but not on the new + * connector list, disable it. */ + if ((!set->fb || ro == set->num_connectors) && + connector->base.encoder && + connector->base.encoder->crtc == set->crtc) { + connector->new_encoder = NULL; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", + connector->base.base.id, + drm_get_connector_name(&connector->base)); + } + + + if (&connector->new_encoder->base != connector->base.encoder) { DRM_DEBUG_KMS("encoder changed, full mode switch\n"); config->mode_changed = true; - /* If the encoder is reused for another connector, then - * the appropriate crtc will be set later. - */ - if (connector->encoder) - connector->encoder->crtc = NULL; - connector->encoder = new_encoder; } + + /* Disable all disconnected encoders. */ + if (connector->base.status == connector_status_disconnected) + connector->new_encoder = NULL; } + /* connector->new_encoder is now updated for all connectors. */ + /* Update crtc of enabled connectors. */ count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder) + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (!connector->new_encoder) continue; - if (connector->encoder->crtc == set->crtc) - new_crtc = NULL; - else - new_crtc = connector->encoder->crtc; + new_crtc = connector->new_encoder->base.crtc; for (ro = 0; ro < set->num_connectors; ro++) { - if (set->connectors[ro] == connector) + if (set->connectors[ro] == &connector->base) new_crtc = set->crtc; } /* Make sure the new CRTC will work with the encoder */ - if (new_crtc && - !intel_encoder_crtc_ok(connector->encoder, new_crtc)) { + if (!intel_encoder_crtc_ok(&connector->new_encoder->base, + new_crtc)) { return -EINVAL; } - if (new_crtc != connector->encoder->crtc) { + connector->encoder->new_crtc = to_intel_crtc(new_crtc); + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", + connector->base.base.id, + drm_get_connector_name(&connector->base), + new_crtc->base.id); + } + + /* Check for any encoders that needs to be disabled. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + list_for_each_entry(connector, + &dev->mode_config.connector_list, + base.head) { + if (connector->new_encoder == encoder) { + WARN_ON(!connector->new_encoder->new_crtc); + + goto next_encoder; + } + } + encoder->new_crtc = NULL; +next_encoder: + /* Only now check for crtc changes so we don't miss encoders + * that will be disabled. */ + if (&encoder->new_crtc->base != encoder->base.crtc) { DRM_DEBUG_KMS("crtc changed, full mode switch\n"); config->mode_changed = true; - connector->encoder->crtc = new_crtc; - } - if (new_crtc) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", - connector->base.id, drm_get_connector_name(connector), - new_crtc->base.id); - } else { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", - connector->base.id, drm_get_connector_name(connector)); } } + /* Now we've also updated encoder->new_crtc for all encoders. */ return 0; } @@ -6965,11 +7045,13 @@ static int intel_crtc_set_config(struct drm_mode_set *set) * such cases. */ intel_set_config_compute_mode_changes(set, config); - ret = intel_set_config_update_output_state(dev, set, config); + ret = intel_modeset_stage_output_state(dev, set, config); if (ret) goto fail; if (config->mode_changed) { + intel_modeset_commit_output_state(dev); + set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); if (set->crtc->enabled) { DRM_DEBUG_KMS("attempting to set mode from" @@ -7015,6 +7097,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) fail: intel_set_config_restore_state(dev, config); + intel_modeset_commit_output_state(dev); + /* Try to restore the config */ if (config->mode_changed && !intel_set_mode(save_set.crtc, save_set.mode, @@ -7888,6 +7972,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev) crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); intel_sanitize_crtc(crtc); } + + intel_modeset_update_staged_output_state(dev); } void intel_modeset_gem_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4946282bd324..ae807afc5fbf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -133,6 +133,12 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; + /* + * The new crtc this encoder will be driven from. Only differs from + * base->crtc while a modeset is in progress. + */ + struct intel_crtc *new_crtc; + int type; bool needs_tv_clock; /* @@ -153,7 +159,17 @@ struct intel_encoder { struct intel_connector { struct drm_connector base; + /* + * The fixed encoder this connector is connected to. + */ struct intel_encoder *encoder; + + /* + * The new encoder this connector will be driven. Only differs from + * encoder while a modeset is in progress. + */ + struct intel_encoder *new_encoder; + /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); -- cgit v1.2.3 From 94352cf9a5328bb1a44288e6c2c1276695f8a356 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Jul 2012 22:51:56 +0200 Subject: drm/i915: push crtc->fb update into pipe_set_base Passing in the old fb, having overwritten the current fb, leads to some neatly convoluted code. It's much simpler if we defer the crtc->fb update to the place that updates the hw, in pipe_set_base. This way we also don't need to restore anything in case something fails - we only update crtc->fb once things have succeeded. The real reason for this change is that now we keep the old fb assigned to crtc->fb, which allows us to finally move the crtc disable case into the common low-level set_mode function in the next patch. Also don't clobber crtc->x and crtc->y, we neatly pass these down the callchain already. Unfortunately we can't do the same with crtc->mode, because that one is being used in the mode_set callbacks. v2: Don't restore the drm_crtc object any more on failed modesets, since we've lose an fb reference otherwise. Also (and this is the reason this has been found), this totally confused the modeset state tracking, since it clobbers crtc->enabled. Issue reported by Paulo Zanoni. v3: Rip out the entire crtc saving into struct intel_set_config, not just the restoring part. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 104 ++++++++++++----------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 34 insertions(+), 71 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5031e0c4a02e..9ce8c59c6b55 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2201,16 +2201,17 @@ intel_finish_fb(struct drm_framebuffer *old_fb) static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) + struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_framebuffer *old_fb; int ret; /* no fb bound */ - if (!crtc->fb) { + if (!fb) { DRM_ERROR("No FB bound\n"); return 0; } @@ -2224,7 +2225,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, - to_intel_framebuffer(crtc->fb)->obj, + to_intel_framebuffer(fb)->obj, NULL); if (ret != 0) { mutex_unlock(&dev->struct_mutex); @@ -2232,17 +2233,20 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - if (old_fb) - intel_finish_fb(old_fb); + if (crtc->fb) + intel_finish_fb(crtc->fb); - ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y); + ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { - intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); + intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); mutex_unlock(&dev->struct_mutex); DRM_ERROR("failed to update base address\n"); return ret; } + old_fb = crtc->fb; + crtc->fb = fb; + if (old_fb) { intel_wait_for_vblank(dev, intel_crtc->pipe); intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj); @@ -3777,6 +3781,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) * true if they don't match). */ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, + struct drm_framebuffer *fb, unsigned int *pipe_bpp, struct drm_display_mode *mode) { @@ -3846,7 +3851,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, * also stays within the max display bpc discovered above. */ - switch (crtc->fb->depth) { + switch (fb->depth) { case 8: bpc = 8; /* since we go through a colormap */ break; @@ -4265,7 +4270,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb) + struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4455,7 +4460,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - ret = intel_pipe_set_base(crtc, x, y, old_fb); + ret = intel_pipe_set_base(crtc, x, y, fb); intel_update_watermarks(dev); @@ -4613,7 +4618,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb) + struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4733,7 +4738,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* determine panel color depth */ temp = I915_READ(PIPECONF(pipe)); temp &= ~PIPE_BPC_MASK; - dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode); + dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode); switch (pipe_bpp) { case 18: temp |= PIPE_6BPC; @@ -5002,7 +5007,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - ret = intel_pipe_set_base(crtc, x, y, old_fb); + ret = intel_pipe_set_base(crtc, x, y, fb); intel_update_watermarks(dev); @@ -5015,7 +5020,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb) + struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -5026,7 +5031,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, drm_vblank_pre_modeset(dev, pipe); ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, - x, y, old_fb); + x, y, fb); drm_vblank_post_modeset(dev, pipe); return ret; @@ -5718,7 +5723,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_encoder *encoder = &intel_encoder->base; struct drm_crtc *crtc = NULL; struct drm_device *dev = encoder->dev; - struct drm_framebuffer *old_fb; + struct drm_framebuffer *fb; int i = -1; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", @@ -5779,8 +5784,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, if (!mode) mode = &load_detect_mode; - old_fb = crtc->fb; - /* We need a framebuffer large enough to accommodate all accesses * that the plane may generate whilst we perform load detection. * We can not rely on the fbcon either being present (we get called @@ -5788,19 +5791,19 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, * not even exist) or that it is large enough to satisfy the * requested mode. */ - crtc->fb = mode_fits_in_fbdev(dev, mode); - if (crtc->fb == NULL) { + fb = mode_fits_in_fbdev(dev, mode); + if (fb == NULL) { DRM_DEBUG_KMS("creating tmp fb for load-detection\n"); - crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32); - old->release_fb = crtc->fb; + fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32); + old->release_fb = fb; } else DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); - if (IS_ERR(crtc->fb)) { + if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); goto fail; } - if (!intel_set_mode(crtc, mode, 0, 0, old_fb)) { + if (!intel_set_mode(crtc, mode, 0, 0, fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -5814,7 +5817,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, fail: connector->encoder = NULL; encoder->crtc = NULL; - crtc->fb = old_fb; return false; } @@ -6666,13 +6668,12 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *old_fb) + int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; struct drm_encoder_helper_funcs *encoder_funcs; - int saved_x, saved_y; struct drm_encoder *encoder; bool ret = true; @@ -6686,15 +6687,11 @@ bool intel_set_mode(struct drm_crtc *crtc, saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; /* Update crtc values up front so the driver can rely on them for mode * setting. */ crtc->mode = *mode; - crtc->x = x; - crtc->y = y; /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also @@ -6725,7 +6722,7 @@ bool intel_set_mode(struct drm_crtc *crtc, /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ - ret = !intel_crtc_mode_set(crtc, mode, adjusted_mode, x, y, old_fb); + ret = !intel_crtc_mode_set(crtc, mode, adjusted_mode, x, y, fb); if (!ret) goto done; @@ -6741,6 +6738,9 @@ bool intel_set_mode(struct drm_crtc *crtc, encoder_funcs->mode_set(encoder, mode, adjusted_mode); } + crtc->x = x; + crtc->y = y; + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ dev_priv->display.crtc_enable(crtc); @@ -6759,8 +6759,6 @@ done: if (!ret) { crtc->hwmode = saved_hwmode; crtc->mode = saved_mode; - crtc->x = saved_x; - crtc->y = saved_y; } return ret; @@ -6773,25 +6771,16 @@ static void intel_set_config_free(struct intel_set_config *config) kfree(config->save_connector_encoders); kfree(config->save_encoder_crtcs); - kfree(config->save_crtcs); kfree(config); } static int intel_set_config_save_state(struct drm_device *dev, struct intel_set_config *config) { - struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; int count; - /* Allocate space for the backup of all (non-pointer) crtc, encoder and - * connector data. */ - config->save_crtcs = kcalloc(dev->mode_config.num_crtc, - sizeof(struct drm_crtc), GFP_KERNEL); - if (!config->save_crtcs) - return -ENOMEM; - config->save_encoder_crtcs = kcalloc(dev->mode_config.num_encoder, sizeof(struct drm_crtc *), GFP_KERNEL); @@ -6808,11 +6797,6 @@ static int intel_set_config_save_state(struct drm_device *dev, * Should anything bad happen only the expected state is * restored, not the drivers personal bookkeeping. */ - count = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - config->save_crtcs[count++] = *crtc; - } - count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { config->save_encoder_crtcs[count++] = encoder->crtc; @@ -6829,16 +6813,10 @@ static int intel_set_config_save_state(struct drm_device *dev, static void intel_set_config_restore_state(struct drm_device *dev, struct intel_set_config *config) { - struct drm_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; int count; - count = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - *crtc = config->save_crtcs[count++]; - } - count = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { encoder->new_crtc = @@ -6994,7 +6972,6 @@ next_encoder: static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; - struct drm_framebuffer *old_fb = NULL; struct drm_mode_set save_set; struct intel_set_config *config; int ret; @@ -7057,13 +7034,10 @@ static int intel_crtc_set_config(struct drm_mode_set *set) DRM_DEBUG_KMS("attempting to set mode from" " userspace\n"); drm_mode_debug_printmodeline(set->mode); - old_fb = set->crtc->fb; - set->crtc->fb = set->fb; if (!intel_set_mode(set->crtc, set->mode, - set->x, set->y, old_fb)) { + set->x, set->y, set->fb)) { DRM_ERROR("failed to set mode on [CRTC:%d]\n", set->crtc->base.id); - set->crtc->fb = old_fb; ret = -EINVAL; goto fail; } @@ -7076,18 +7050,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } drm_helper_disable_unused_functions(dev); } else if (config->fb_changed) { - set->crtc->x = set->x; - set->crtc->y = set->y; - - old_fb = set->crtc->fb; - if (set->crtc->fb != set->fb) - set->crtc->fb = set->fb; ret = intel_pipe_set_base(set->crtc, - set->x, set->y, old_fb); - if (ret != 0) { - set->crtc->fb = old_fb; - goto fail; - } + set->x, set->y, set->fb); } intel_set_config_free(config); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ae807afc5fbf..1aa0b9c0a4d5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -442,7 +442,6 @@ extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); struct intel_set_config { struct drm_encoder **save_connector_encoders; struct drm_crtc **save_encoder_crtcs; - struct drm_crtc *save_crtcs; bool fb_changed; bool mode_changed; -- cgit v1.2.3 From ba1c28c900f1aeb9a353f230a99c68cd4e550dde Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Jul 2012 23:27:42 +0200 Subject: drm/i915: remove crtc disabling special case Originally this has been introduced in commit 6eebd6bb5f1ea04f04019e5c39f87a0f17ffb472 Author: Chris Wilson Date: Mon Nov 28 21:10:05 2011 +0000 drm: Fix lack of CRTC disable for drm_crtc_helper_set_config(.fb=NULL) With the improvements of the output state staging and no longer overwriting crtc->fb before the hw state is updated we can now handle crtc disabling as part of the normal modeset sequence. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9ce8c59c6b55..0f2c2e1ec6ee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6585,30 +6585,6 @@ static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, return false; } -static int -intel_crtc_helper_disable(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_connector *connector; - struct drm_encoder *encoder; - - /* Decouple all encoders and their attached connectors from this crtc */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder != encoder) - continue; - - connector->encoder = NULL; - } - } - - drm_helper_disable_unused_functions(dev); - return 0; -} - static void intel_crtc_prepare_encoders(struct drm_device *dev) { @@ -6996,7 +6972,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) (int)set->num_connectors, set->x, set->y); } else { DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); - return intel_crtc_helper_disable(set->crtc); } dev = set->crtc->dev; -- cgit v1.2.3 From 87f1faa630b2045ccb6ab29f18c62279ddd7ef17 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Jul 2012 23:36:17 +0200 Subject: drm/i915: move output commit and crtc disabling into set_mode It's rather pointless to compute crtc->enabled twice right away ;-) The only thing we really have to be careful about is that we frob the dpms state only after a successful modeset and when we've actually haven't just disabled the crtc. Hooray for convoluted interfaces ... Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f2c2e1ec6ee..0bfc7993feb5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6653,9 +6653,13 @@ bool intel_set_mode(struct drm_crtc *crtc, struct drm_encoder *encoder; bool ret = true; + intel_modeset_commit_output_state(dev); + crtc->enabled = drm_helper_crtc_in_use(crtc); - if (!crtc->enabled) + if (!crtc->enabled) { + drm_helper_disable_unused_functions(dev); return true; + } adjusted_mode = drm_mode_duplicate(dev, mode); if (!adjusted_mode) @@ -7002,20 +7006,21 @@ static int intel_crtc_set_config(struct drm_mode_set *set) goto fail; if (config->mode_changed) { - intel_modeset_commit_output_state(dev); - - set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); - if (set->crtc->enabled) { + if (set->mode) { DRM_DEBUG_KMS("attempting to set mode from" " userspace\n"); drm_mode_debug_printmodeline(set->mode); - if (!intel_set_mode(set->crtc, set->mode, - set->x, set->y, set->fb)) { - DRM_ERROR("failed to set mode on [CRTC:%d]\n", - set->crtc->base.id); - ret = -EINVAL; - goto fail; - } + } + + if (!intel_set_mode(set->crtc, set->mode, + set->x, set->y, set->fb)) { + DRM_ERROR("failed to set mode on [CRTC:%d]\n", + set->crtc->base.id); + ret = -EINVAL; + goto fail; + } + + if (set->crtc->enabled) { DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); for (i = 0; i < set->num_connectors; i++) { DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, @@ -7023,7 +7028,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); } } - drm_helper_disable_unused_functions(dev); } else if (config->fb_changed) { ret = intel_pipe_set_base(set->crtc, set->x, set->y, set->fb); @@ -7036,8 +7040,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) fail: intel_set_config_restore_state(dev, config); - intel_modeset_commit_output_state(dev); - /* Try to restore the config */ if (config->mode_changed && !intel_set_mode(save_set.crtc, save_set.mode, -- cgit v1.2.3 From 7758a11340cc8845509303b0bee60401738da82e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 8 Jul 2012 19:40:39 +0200 Subject: drm/i915: extract adjusted mode computation While at it, adjust a few things: - Only assigng the new mode to crtc->mode right before calling the mode_set callbacks - none of the previous callbacks depend upon this, they all use the mode argument (as they should). - Check encoder->new_crtc instead of the current crtc to check whether the encoder will be used. This prepares for moving the staged output committing further down in the sequence. Follow-on patches will fix up individual ->mode_fixup callbacks (only tv and lvds are affected though). Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 75 ++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bfc7993feb5..c8fb9268fad7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6642,6 +6642,48 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) } } +static struct drm_display_mode * +intel_modeset_adjusted_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_display_mode *adjusted_mode; + struct drm_encoder_helper_funcs *encoder_funcs; + struct intel_encoder *encoder; + + adjusted_mode = drm_mode_duplicate(dev, mode); + if (!adjusted_mode) + return ERR_PTR(-ENOMEM); + + /* Pass our mode to the connectors and the CRTC to give them a chance to + * adjust it according to limitations or connector properties, and also + * a chance to reject the mode entirely. + */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + + if (&encoder->new_crtc->base != crtc) + continue; + encoder_funcs = encoder->base.helper_private; + if (!(encoder_funcs->mode_fixup(&encoder->base, mode, + adjusted_mode))) { + DRM_DEBUG_KMS("Encoder fixup failed\n"); + goto fail; + } + } + + if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) { + DRM_DEBUG_KMS("CRTC fixup failed\n"); + goto fail; + } + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + + return adjusted_mode; +fail: + drm_mode_destroy(dev, adjusted_mode); + return ERR_PTR(-EINVAL); +} + bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) @@ -6661,44 +6703,21 @@ bool intel_set_mode(struct drm_crtc *crtc, return true; } - adjusted_mode = drm_mode_duplicate(dev, mode); - if (!adjusted_mode) - return false; saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; - /* Update crtc values up front so the driver can rely on them for mode - * setting. - */ - crtc->mode = *mode; - - /* Pass our mode to the connectors and the CRTC to give them a chance to - * adjust it according to limitations or connector properties, and also - * a chance to reject the mode entirely. - */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - - if (encoder->crtc != crtc) - continue; - encoder_funcs = encoder->helper_private; - if (!(ret = encoder_funcs->mode_fixup(encoder, mode, - adjusted_mode))) { - DRM_DEBUG_KMS("Encoder fixup failed\n"); - goto done; - } - } - - if (!(ret = intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) { - DRM_DEBUG_KMS("CRTC fixup failed\n"); - goto done; + adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); + if (IS_ERR(adjusted_mode)) { + return false; } - DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); intel_crtc_prepare_encoders(dev); dev_priv->display.crtc_disable(crtc); + crtc->mode = *mode; + /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ -- cgit v1.2.3 From 6ed0f796c22cd638fac60f29ff72b3a7a03485e6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 8 Jul 2012 19:41:43 +0200 Subject: drm/i915: use staged outuput config in tv->mode_fixup The "is this encoder cloned" check will be reused by the lvds encoder, hence exract it. v2: Be a bit more careful about that we need to check the new, staged ouput configuration in the check_non_cloned helper ... v3: Kill the double negation with s/!non_cloned/is_cloned/, suggested by Jesse Barnes. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_tv.c | 7 ++----- 3 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c8fb9268fad7..3eec29c75d2e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6563,6 +6563,28 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = { .disable = intel_crtc_disable, }; +bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) +{ + struct intel_encoder *other_encoder; + struct drm_crtc *crtc = &encoder->new_crtc->base; + + if (WARN_ON(!crtc)) + return false; + + list_for_each_entry(other_encoder, + &crtc->dev->mode_config.encoder_list, + base.head) { + + if (&other_encoder->new_crtc->base != crtc || + encoder == other_encoder) + continue; + else + return true; + } + + return false; +} + static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, struct drm_crtc *crtc) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1aa0b9c0a4d5..8686f47f6829 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -454,6 +454,7 @@ extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_disable(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); +extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); extern void intel_connector_check_state(struct intel_connector *); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 98ad7fdb3666..003ef9e92804 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -910,17 +910,14 @@ intel_tv_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; struct intel_tv *intel_tv = enc_to_intel_tv(encoder); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); - struct intel_encoder *other_encoder; if (!tv_mode) return false; - for_each_encoder_on_crtc(dev, encoder->crtc, other_encoder) - if (&other_encoder->base != encoder) - return false; + if (intel_encoder_check_is_cloned(&intel_tv->base)) + return false; adjusted_mode->clock = tv_mode->clock; return true; -- cgit v1.2.3 From e2e1ed41ed6e3012464e8a8e7cf7bbcb6d3f7412 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 8 Jul 2012 21:14:38 +0200 Subject: drm/i915: compute masks of crtcs affected in set_mode This is definetely a bit more generic than currently required, but if we keep track of all crtcs that need to be disabled/enable (because they loose an encoder or something similar), crtcs that get completely disabled and those that we need to do an actual mode change nicely prepares us for global modeset operations on multiple crtcs. The only big thing missing here would be a global resource allocation step (for e.g. pch plls), which would equally frob these bitmasks if e.g. a crtc only needs a new pll. Or if we need to enable dithering on an another pipe due to bandwidth constrains somewhere. These masks aren't yet put to use in this patch, this will follow in the next one. v2-v5: Fix up the computations for good (hopefully). v6: Fixup a confusion reported by Damien Lespiau: I've conserved the (imo braindead) behaviour of the crtc helper to disable _any_ disconnected outputs if we do a modeset, even when that newly disabled connector isn't connected to the crtc being changed by the modeset. The effect of that is that we could disable an arbitrary number of unrelated crtcs, which I haven't taken into account when writing this code. Fix this up. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 96 ++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3eec29c75d2e..d354aa0b8eed 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6706,6 +6706,98 @@ fail: return ERR_PTR(-EINVAL); } +/* Computes which crtcs are affected and sets the relevant bits in the mask. For + * simplicity we use the crtc's pipe number (because it's easier to obtain). */ +static void +intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, + unsigned *prepare_pipes, unsigned *disable_pipes) +{ + struct intel_crtc *intel_crtc; + struct drm_device *dev = crtc->dev; + struct intel_encoder *encoder; + struct intel_connector *connector; + struct drm_crtc *tmp_crtc; + + *disable_pipes = *modeset_pipes = *prepare_pipes = 0; + + /* Check which crtcs have changed outputs connected to them, these need + * to be part of the prepare_pipes mask. We don't (yet) support global + * modeset across multiple crtcs, so modeset_pipes will only have one + * bit set at most. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->base.encoder == &connector->new_encoder->base) + continue; + + if (connector->base.encoder) { + tmp_crtc = connector->base.encoder->crtc; + + *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe; + } + + if (connector->new_encoder) + *prepare_pipes |= + 1 << connector->new_encoder->new_crtc->pipe; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->base.crtc == &encoder->new_crtc->base) + continue; + + if (encoder->base.crtc) { + tmp_crtc = encoder->base.crtc; + + *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe; + } + + if (encoder->new_crtc) + *prepare_pipes |= 1 << encoder->new_crtc->pipe; + } + + /* Check for any pipes that will be fully disabled ... */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + bool used = false; + + /* Don't try to disable disabled crtcs. */ + if (!intel_crtc->base.enabled) + continue; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->new_crtc == intel_crtc) + used = true; + } + + if (!used) + *disable_pipes |= 1 << intel_crtc->pipe; + } + + + /* set_mode is also used to update properties on life display pipes. */ + intel_crtc = to_intel_crtc(crtc); + if (crtc->enabled) + *prepare_pipes |= 1 << intel_crtc->pipe; + + /* We only support modeset on one single crtc, hence we need to do that + * only for the passed in crtc iff we change anything else than just + * disable crtcs. + * + * This is actually not true, to be fully compatible with the old crtc + * helper we automatically disable _any_ output (i.e. doesn't need to be + * connected to the crtc we're modesetting on) if it's disconnected. + * Which is a rather nutty api (since changed the output configuration + * without userspace's explicit request can lead to confusion), but + * alas. Hence we currently need to modeset on all pipes we prepare. */ + if (*prepare_pipes) + *modeset_pipes = *prepare_pipes; + + /* ... and mask these out. */ + *modeset_pipes &= ~(*disable_pipes); + *prepare_pipes &= ~(*disable_pipes); +} + bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) @@ -6715,8 +6807,12 @@ bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder *encoder; + unsigned disable_pipe, prepare_pipes, modeset_pipes; bool ret = true; + intel_modeset_affected_pipes(crtc, &modeset_pipes, + &prepare_pipes, &disable_pipe); + intel_modeset_commit_output_state(dev); crtc->enabled = drm_helper_crtc_in_use(crtc); -- cgit v1.2.3 From 25c5b2665fe4cc5a93edd29b62e7c05c15dddd26 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 8 Jul 2012 22:08:04 +0200 Subject: drm/i915: implement new set_mode code flow ... using the pipe masks from the previous patch. Well, not quite: - We still need to call the disable_unused_functions helper, until we've moved the call to commit_output_state further down and adjusted intel_crtc_disable a bit. The next patch will do that. - Because we don't support (yet) mode changes on more than one crtc at a time, some of the modeset_pipes checks are a bit hackish - but that only needs fixing once we incorporate global modeset support. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 99 +++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 36 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d354aa0b8eed..16cbf9554216 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6798,6 +6798,12 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, *prepare_pipes &= ~(*disable_pipes); } +#define for_each_intel_crtc_masked(dev, mask, intel_crtc) \ + list_for_each_entry((intel_crtc), \ + &(dev)->mode_config.crtc_list, \ + base.head) \ + if (mask & (1 <<(intel_crtc)->pipe)) \ + bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) @@ -6807,73 +6813,92 @@ bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder *encoder; - unsigned disable_pipe, prepare_pipes, modeset_pipes; + struct intel_crtc *intel_crtc; + unsigned disable_pipes, prepare_pipes, modeset_pipes; bool ret = true; intel_modeset_affected_pipes(crtc, &modeset_pipes, - &prepare_pipes, &disable_pipe); + &prepare_pipes, &disable_pipes); + + DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", + modeset_pipes, prepare_pipes, disable_pipes); intel_modeset_commit_output_state(dev); crtc->enabled = drm_helper_crtc_in_use(crtc); - if (!crtc->enabled) { - drm_helper_disable_unused_functions(dev); - return true; - } + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) + drm_helper_disable_unused_functions(dev); saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; - adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); - if (IS_ERR(adjusted_mode)) { - return false; - } + /* Hack: Because we don't (yet) support global modeset on multiple + * crtcs, we don't keep track of the new mode for more than one crtc. + * Hence simply check whether any bit is set in modeset_pipes in all the + * pieces of code that are not yet converted to deal with mutliple crtcs + * changing their mode at the same time. */ + adjusted_mode = NULL; + if (modeset_pipes) { + adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); + if (IS_ERR(adjusted_mode)) { + return false; + } - intel_crtc_prepare_encoders(dev); + intel_crtc_prepare_encoders(dev); + } - dev_priv->display.crtc_disable(crtc); + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) + dev_priv->display.crtc_disable(&intel_crtc->base); - crtc->mode = *mode; + if (modeset_pipes) { + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + } /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ - ret = !intel_crtc_mode_set(crtc, mode, adjusted_mode, x, y, fb); - if (!ret) - goto done; + for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { + ret = !intel_crtc_mode_set(&intel_crtc->base, + mode, adjusted_mode, + x, y, fb); + if (!ret) + goto done; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; + if (encoder->crtc != &intel_crtc->base) + continue; - DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", - encoder->base.id, drm_get_encoder_name(encoder), - mode->base.id, mode->name); - encoder_funcs = encoder->helper_private; - encoder_funcs->mode_set(encoder, mode, adjusted_mode); + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", + encoder->base.id, drm_get_encoder_name(encoder), + mode->base.id, mode->name); + encoder_funcs = encoder->helper_private; + encoder_funcs->mode_set(encoder, mode, adjusted_mode); + } } - crtc->x = x; - crtc->y = y; - /* Now enable the clocks, plane, pipe, and connectors that we set up. */ - dev_priv->display.crtc_enable(crtc); + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) + dev_priv->display.crtc_enable(&intel_crtc->base); - /* Store real post-adjustment hardware mode. */ - crtc->hwmode = *adjusted_mode; + if (modeset_pipes) { + /* Store real post-adjustment hardware mode. */ + crtc->hwmode = *adjusted_mode; - /* Calculate and store various constants which - * are later needed by vblank and swap-completion - * timestamping. They are derived from true hwmode. - */ - drm_calc_timestamping_constants(crtc); + /* Calculate and store various constants which + * are later needed by vblank and swap-completion + * timestamping. They are derived from true hwmode. + */ + drm_calc_timestamping_constants(crtc); + } /* FIXME: add subpixel order */ done: drm_mode_destroy(dev, adjusted_mode); - if (!ret) { + if (!ret && crtc->enabled) { crtc->hwmode = saved_hwmode; crtc->mode = saved_mode; } @@ -6881,6 +6906,8 @@ done: return ret; } +#undef for_each_intel_crtc_masked + static void intel_set_config_free(struct intel_set_config *config) { if (!config) -- cgit v1.2.3 From 976f8a20139b1f238ab3676a732acf87fbd38c6a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 8 Jul 2012 22:34:21 +0200 Subject: drm/i915: push commit_output_state past crtc disabling This requires a few changes - We still need a noop function for crtc->disable, becuase the fb helper is a bit too intimate with the crtc helper. - We need to clear crtc->fb ourselves in intel_crtc_disable now that we no longer rely on the helper's disable_unused_functions to do that. - We need to split out the sare update code, becuase the crtc code can't call update_dpms any more, it needs to disable the crtc unconditionally. This is because we now keep onto the encoder -> crtc mapping of the (still) active output pipe configuration. - To check that we really disable a crtc that still has encoders, insert a WARN_ON(!enabled) in the crtc disable function. - Lastly, we need to walk over all crtcs to update their enabled state after having called commit_output_state - for all disabled crtcs the crtc helper code has done that for us previously. v2: Update connector dpms and encoder->connectors_active after disabling the crtc, too. v3: Noop-out intel_encoder_disable. Similarly to the crtc disable callback used by the crtc helper code we can't simply remove all these encoder callbacks: The fb helper (which we still use) has a rather incetious relationship with the crtc helper code ... Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 81 +++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16cbf9554216..b843bc0502c6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3462,26 +3462,13 @@ static void i9xx_crtc_off(struct drm_crtc *crtc) { } -/** - * Sets the power management mode of the pipe and plane. - */ -void intel_crtc_update_dpms(struct drm_crtc *crtc) +static void intel_crtc_update_sarea(struct drm_crtc *crtc, + bool enabled) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder; int pipe = intel_crtc->pipe; - bool enabled, enable = false; - - for_each_encoder_on_crtc(dev, crtc, intel_encoder) - enable |= intel_encoder->connectors_active; - - if (enable) - dev_priv->display.crtc_enable(crtc); - else - dev_priv->display.crtc_disable(crtc); if (!dev->primary->master) return; @@ -3490,8 +3477,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) if (!master_priv->sarea_priv) return; - enabled = crtc->enabled && enable; - switch (pipe) { case 0: master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; @@ -3507,14 +3492,42 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) } } +/** + * Sets the power management mode of the pipe and plane. + */ +void intel_crtc_update_dpms(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + bool enable = false; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) + enable |= intel_encoder->connectors_active; + + if (enable) + dev_priv->display.crtc_enable(crtc); + else + dev_priv->display.crtc_disable(crtc); + + intel_crtc_update_sarea(crtc, enable); +} + +static void intel_crtc_noop(struct drm_crtc *crtc) +{ +} + static void intel_crtc_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + struct drm_connector *connector; struct drm_i915_private *dev_priv = dev->dev_private; - /* crtc->disable is only called when we have no encoders, hence this - * will disable the pipe. */ - intel_crtc_update_dpms(crtc); + /* crtc should still be enabled when we disable it. */ + WARN_ON(!crtc->enabled); + + dev_priv->display.crtc_disable(crtc); + intel_crtc_update_sarea(crtc, false); dev_priv->display.off(crtc); assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); @@ -3524,14 +3537,24 @@ static void intel_crtc_disable(struct drm_crtc *crtc) mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); + crtc->fb = NULL; + } + + /* Update computed state. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->encoder || !connector->encoder->crtc) + continue; + + if (connector->encoder->crtc != crtc) + continue; + + connector->dpms = DRM_MODE_DPMS_OFF; + to_intel_encoder(connector->encoder)->connectors_active = false; } } void intel_encoder_disable(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - - intel_encoder->disable(intel_encoder); } void intel_encoder_destroy(struct drm_encoder *encoder) @@ -6560,7 +6583,7 @@ free_work: static struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, - .disable = intel_crtc_disable, + .disable = intel_crtc_noop, }; bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) @@ -6823,12 +6846,14 @@ bool intel_set_mode(struct drm_crtc *crtc, DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", modeset_pipes, prepare_pipes, disable_pipes); - intel_modeset_commit_output_state(dev); + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) + intel_crtc_disable(&intel_crtc->base); - crtc->enabled = drm_helper_crtc_in_use(crtc); + intel_modeset_commit_output_state(dev); - for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) - drm_helper_disable_unused_functions(dev); + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) + intel_crtc->base.enabled = drm_helper_crtc_in_use(crtc); saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; -- cgit v1.2.3 From 1f70385510991992f3aef339982ca790faa52b06 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Jul 2012 16:51:39 +0200 Subject: drm/i915: s/intel_encoder_disable/intel_encoder_noop Because that's what it is. Unfortunately we can't rip this out because the fb helper has an incetious relationship with the crtc helper - it likes to call disable_unused_functions, among other things. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 4 ++-- drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- drivers/gpu/drm/i915/intel_tv.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c002d260c1a4..cca266f72a4c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -641,7 +641,7 @@ static void intel_crt_reset(struct drm_connector *connector) static const struct drm_encoder_helper_funcs crt_encoder_funcs = { .mode_fixup = intel_crt_mode_fixup, .mode_set = intel_crt_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_crt_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b843bc0502c6..9a0661122da7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3553,7 +3553,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc) } } -void intel_encoder_disable(struct drm_encoder *encoder) +void intel_encoder_noop(struct drm_encoder *encoder) { } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b07d4b4fca6e..3b1c407699c7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2393,7 +2393,7 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder) static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .mode_fixup = intel_dp_mode_fixup, .mode_set = intel_dp_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_dp_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8686f47f6829..5137f9bef13e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -451,7 +451,7 @@ extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); -extern void intel_encoder_disable(struct drm_encoder *encoder); +extern void intel_encoder_noop(struct drm_encoder *encoder); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 17dc8bebf8f2..aa1bf57963b1 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -346,7 +346,7 @@ static void intel_dvo_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { .mode_fixup = intel_dvo_mode_fixup, .mode_set = intel_dvo_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_dvo_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e7d5078e6da7..7acf2d91af35 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -907,13 +907,13 @@ static void intel_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { .mode_fixup = intel_hdmi_mode_fixup, .mode_set = intel_ddi_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { .mode_fixup = intel_hdmi_mode_fixup, .mode_set = intel_hdmi_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_hdmi_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 25b892d907b2..564689554989 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -590,7 +590,7 @@ static int intel_lvds_set_property(struct drm_connector *connector, static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, .mode_set = intel_lvds_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 198bb8965b8d..6f538719b727 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1936,7 +1936,7 @@ done: static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { .mode_fixup = intel_sdvo_mode_fixup, .mode_set = intel_sdvo_mode_set, - .disable = intel_encoder_disable + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_sdvo_connector_funcs = { diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 003ef9e92804..d2c5c8f3baf3 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1492,7 +1492,7 @@ out: static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { .mode_fixup = intel_tv_mode_fixup, .mode_set = intel_tv_mode_set, - .disable = intel_encoder_disable, + .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_tv_connector_funcs = { -- cgit v1.2.3 From 284637d9229dc1115947bb04008730844afbc059 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 9 Jul 2012 09:51:57 +0200 Subject: drm/i915: WARN if the pipe won't turn off This seems to be the symptom of a few neat bugs, hence be more obnoxious when this fails. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9a0661122da7..453bc7cf1841 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1006,7 +1006,7 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) /* Wait for the Pipe State to go off */ if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, 100)) - DRM_DEBUG_KMS("pipe_off wait timed out\n"); + WARN(1, "pipe_off wait timed out\n"); } else { u32 last_line, line_mask; int reg = PIPEDSL(pipe); @@ -1024,7 +1024,7 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) } while (((I915_READ(reg) & line_mask) != last_line) && time_after(timeout, jiffies)); if (time_after(jiffies, timeout)) - DRM_DEBUG_KMS("pipe_off wait timed out\n"); + WARN(1, "pipe_off wait timed out\n"); } } -- cgit v1.2.3 From fc303101dc9bfe2b079798c948f6ad4245c51e57 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 9 Jul 2012 10:40:58 +0200 Subject: drm/i915: switch the load detect code to the staged modeset config Now that set_mode also disables crtcs and expects it's new configuration in the staged output links we need to adjust the load detect code a bit. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 453bc7cf1841..e3d3abff670c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5796,8 +5796,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, return false; } - encoder->crtc = crtc; - connector->encoder = encoder; + intel_encoder->new_crtc = to_intel_crtc(crtc); + to_intel_connector(connector)->new_encoder = intel_encoder; intel_crtc = to_intel_crtc(crtc); old->dpms_mode = connector->dpms; @@ -5849,16 +5849,17 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_encoder *intel_encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = &intel_encoder->base; - struct drm_device *dev = encoder->dev; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, drm_get_connector_name(connector), encoder->base.id, drm_get_encoder_name(encoder)); if (old->load_detect_temp) { - connector->encoder = NULL; - encoder->crtc = NULL; - drm_helper_disable_unused_functions(dev); + struct drm_crtc *crtc = encoder->crtc; + + to_intel_connector(connector)->new_encoder = NULL; + intel_encoder->new_crtc = NULL; + intel_set_mode(crtc, NULL, 0, 0, NULL); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); -- cgit v1.2.3 From ea9d758d6ddb9f4bb9639619100743e8f5fa85a0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Jul 2012 10:42:52 +0200 Subject: drm/i915: push commit_output_state past the crtc/encoder preparing With this change we can (finally!) rip out a few of the temporary hacks and clean up a few other things: - Kill intel_crtc_prepare_encoders, now unused. - Kill the hacks in the crtc_disable/enable functions to always call the encoder callbacks, we now always call the crtc functions with the right encoder -> crtc links. - Also push down the crtc->enable, encoder and connector dpms state updates. Unfortunately we can't add a WARN in the crtc_disable callbacks to ensure that the crtc is always still enabled when disabling an output pipe - the crtc sanitizer of the hw readout path can hit this when it needs to disable an active pipe without any enabled outputs. - Only call crtc->disable if the pipe is already enabled - again avoids running afoul of the new WARN. v2: Copy&paste our own version of crtc_in_use, too. v3: We need to update the dpms an encoder->connectors_active states, too. v4: I've forgotten to kill the unconditional encoder->disable calls in the crtc_disable functions. v5: Rip out leftover debug printk. v6: Properly clear intel_encoder->connectors_active. This wasn't properly cleared when disabling an encoder because it was no longer on the new connector list, but the crtc was still enabled (i.e. switching the encoder of an active crtc). Reported by Jani Nikula. v7: Don't clobber the encoder->connectors_active state of untouched encoders. Since X likes to first disable all outputs with dpms off before setting a new framebuffer, this hit a few warnings. Reported by Paulo Zanoni. v8: Kill the now stale comment warning that intel_crtc->active is not always updated at the right times. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 108 +++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 3 - 2 files changed, 70 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e3d3abff670c..2a393cbe6173 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3221,10 +3221,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) WARN_ON(!crtc->enabled); - /* XXX: For compatability with the crtc helper code, call the encoder's - * enable function unconditionally for now. */ if (intel_crtc->active) - goto encoders; + return; intel_crtc->active = true; intel_update_watermarks(dev); @@ -3272,7 +3270,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc_update_cursor(crtc, true); -encoders: for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); @@ -3290,14 +3287,13 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; - /* XXX: For compatability with the crtc helper code, call the encoder's - * disable function unconditionally for now. */ - for_each_encoder_on_crtc(dev, crtc, encoder) - encoder->disable(encoder); if (!intel_crtc->active) return; + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); + intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); intel_crtc_update_cursor(crtc, false); @@ -3399,10 +3395,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) WARN_ON(!crtc->enabled); - /* XXX: For compatability with the crtc helper code, call the encoder's - * enable function unconditionally for now. */ if (intel_crtc->active) - goto encoders; + return; intel_crtc->active = true; intel_update_watermarks(dev); @@ -3418,7 +3412,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_crtc_dpms_overlay(intel_crtc, true); intel_crtc_update_cursor(crtc, true); -encoders: for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); } @@ -3432,14 +3425,13 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - /* XXX: For compatability with the crtc helper code, call the encoder's - * disable function unconditionally for now. */ - for_each_encoder_on_crtc(dev, crtc, encoder) - encoder->disable(encoder); if (!intel_crtc->active) return; + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); + /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); @@ -6631,18 +6623,6 @@ static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, return false; } -static void -intel_crtc_prepare_encoders(struct drm_device *dev) -{ - struct intel_encoder *encoder; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { - /* Disable unused encoders */ - if (encoder->base.crtc == NULL) - encoder->disable(encoder); - } -} - /** * intel_modeset_update_staged_output_state * @@ -6822,6 +6802,60 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, *prepare_pipes &= ~(*disable_pipes); } +static bool intel_crtc_in_use(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc == crtc) + return true; + + return false; +} + +static void +intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) +{ + struct intel_encoder *intel_encoder; + struct intel_crtc *intel_crtc; + struct drm_connector *connector; + + list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list, + base.head) { + if (!intel_encoder->base.crtc) + continue; + + intel_crtc = to_intel_crtc(intel_encoder->base.crtc); + + if (prepare_pipes & (1 << intel_crtc->pipe)) + intel_encoder->connectors_active = false; + } + + intel_modeset_commit_output_state(dev); + + /* Update computed state. */ + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base); + } + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->encoder || !connector->encoder->crtc) + continue; + + intel_crtc = to_intel_crtc(connector->encoder->crtc); + + if (prepare_pipes & (1 << intel_crtc->pipe)) { + connector->dpms = DRM_MODE_DPMS_ON; + + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } + } + +} + #define for_each_intel_crtc_masked(dev, mask, intel_crtc) \ list_for_each_entry((intel_crtc), \ &(dev)->mode_config.crtc_list, \ @@ -6850,12 +6884,6 @@ bool intel_set_mode(struct drm_crtc *crtc, for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); - intel_modeset_commit_output_state(dev); - - list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, - base.head) - intel_crtc->base.enabled = drm_helper_crtc_in_use(crtc); - saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; @@ -6870,12 +6898,12 @@ bool intel_set_mode(struct drm_crtc *crtc, if (IS_ERR(adjusted_mode)) { return false; } - - intel_crtc_prepare_encoders(dev); } - for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) - dev_priv->display.crtc_disable(&intel_crtc->base); + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { + if (intel_crtc->base.enabled) + dev_priv->display.crtc_disable(&intel_crtc->base); + } if (modeset_pipes) { crtc->mode = *mode; @@ -6883,6 +6911,10 @@ bool intel_set_mode(struct drm_crtc *crtc, crtc->y = y; } + /* Only after disabling all output pipelines that will be changed can we + * update the the output configuration. */ + intel_modeset_update_state(dev, prepare_pipes); + /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5137f9bef13e..d03e77752157 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -184,9 +184,6 @@ struct intel_crtc { * Whether the crtc and the connected output pipeline is active. Implies * that crtc->enabled is set, i.e. the current mode configuration has * some outputs connected to this crtc. - * - * Atm crtc->enabled is unconditionally updated _before_ the hw state is - * changed, hence we can only check this when enabling the crtc. */ bool active; bool primary_disabled; /* is the crtc obscured by a plane? */ -- cgit v1.2.3 From a261b246ebd552fd5d5a8ed84cc931bb821c427f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 26 Jul 2012 19:21:47 +0200 Subject: drm/i915: disable all crtcs at suspend time We need this to avoid confusing the hw state readout code with the cpt pch plls at resume time: We'd read the new pipe state (which is disabled), but still believe that we have a life pll connected to that pipe (from before the suspend). Hence properly disable pipes to clear out all the residual state. This has the neat side-effect that we don't enable ports prematurely by restoring bogus state from the saved register values. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 3 +++ drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 14 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4abac6d6c3e6..fe7512ae3945 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -470,6 +470,9 @@ static int i915_drm_freeze(struct drm_device *dev) "GEM idle failed, resume might fail\n"); return error; } + + intel_modeset_disable(dev); + drm_irq_uninstall(dev); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2a393cbe6173..4c0ec180564f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3545,6 +3545,16 @@ static void intel_crtc_disable(struct drm_crtc *crtc) } } +void intel_modeset_disable(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->enabled) + intel_crtc_disable(crtc); + } +} + void intel_encoder_noop(struct drm_encoder *encoder) { } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d03e77752157..2061399d92c1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -446,6 +446,7 @@ struct intel_set_config { extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); +extern void intel_modeset_disable(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_noop(struct drm_encoder *encoder); -- cgit v1.2.3 From 8af6cf88a5ad7fa41d4eb700cc97f01d0bcd2a69 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Jul 2012 09:50:11 +0200 Subject: drm/i915: add tons of modeset state checks ... let's see whether this catches anything earlier and I can track down a few bugs. v2: Add more checks and also add DRM_DEBUG_KMS output so that it's clear which connector/encoder/crtc is being checked atm. Which proved rather useful for debugging ... v3: Add a WARN in the common encoder dpms function, now that also modeset changes properly update the dpms state ... v4: Properly add a short explanation for each WARN, to avoid the need to correlate dmesg lines with source lines accurately. Suggested by Chris Wilson. v5: Also dump (expected, found) for state checks (or wherever it's not apparent from the test what exactly mismatches with expectations). Again suggested by Chris Wilson. v6: Due to an issue reported by Paulo Zanoni I've noticed that the encoder checking is by far not as strict as it could and should be. Improve this. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 104 ++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4c0ec180564f..d15fa0c6ae88 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3637,7 +3637,7 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) if (encoder->base.crtc) intel_encoder_dpms(encoder, mode); else - encoder->connectors_active = false; + WARN_ON(encoder->connectors_active != false); intel_connector_check_state(to_intel_connector(connector)); } @@ -6872,6 +6872,104 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) \ +static void +intel_modeset_check_state(struct drm_device *dev) +{ + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + /* This also checks the encoder/connector hw state with the + * ->get_hw_state callbacks. */ + intel_connector_check_state(connector); + + WARN(&connector->new_encoder->base != connector->base.encoder, + "connector's staged encoder doesn't match current encoder\n"); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + bool enabled = false; + bool active = false; + enum pipe pipe, tracked_pipe; + + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", + encoder->base.base.id, + drm_get_encoder_name(&encoder->base)); + + WARN(&encoder->new_crtc->base != encoder->base.crtc, + "encoder's stage crtc doesn't match current crtc\n"); + WARN(encoder->connectors_active && !encoder->base.crtc, + "encoder's active_connectors set, but no crtc\n"); + + list_for_each_entry(connector, &dev->mode_config.connector_list, + base.head) { + if (connector->base.encoder != &encoder->base) + continue; + enabled = true; + if (connector->base.dpms != DRM_MODE_DPMS_OFF) + active = true; + } + WARN(!!encoder->base.crtc != enabled, + "encoder's enabled state mismatch " + "(expected %i, found %i)\n", + !!encoder->base.crtc, enabled); + WARN(active && !encoder->base.crtc, + "active encoder with no crtc\n"); + + WARN(encoder->connectors_active != active, + "encoder's computed active state doesn't match tracked active state " + "(expected %i, found %i)\n", active, encoder->connectors_active); + + active = encoder->get_hw_state(encoder, &pipe); + WARN(active != encoder->connectors_active, + "encoder's hw state doesn't match sw tracking " + "(expected %i, found %i)\n", + encoder->connectors_active, active); + + if (!encoder->base.crtc) + continue; + + tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe; + WARN(active && pipe != tracked_pipe, + "active encoder's pipe doesn't match" + "(expected %i, found %i)\n", + tracked_pipe, pipe); + + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + bool enabled = false; + bool active = false; + + DRM_DEBUG_KMS("[CRTC:%d]\n", + crtc->base.base.id); + + WARN(crtc->active && !crtc->base.enabled, + "active crtc, but not enabled in sw tracking\n"); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->base.crtc != &crtc->base) + continue; + enabled = true; + if (encoder->connectors_active) + active = true; + } + WARN(active != crtc->active, + "crtc's computed active state doesn't match tracked active state " + "(expected %i, found %i)\n", active, crtc->active); + WARN(enabled != crtc->base.enabled, + "crtc's computed enabled state doesn't match tracked enabled state " + "(expected %i, found %i)\n", enabled, crtc->base.enabled); + + assert_pipe(dev->dev_private, crtc->pipe, crtc->active); + } +} + bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) @@ -6969,6 +7067,8 @@ done: if (!ret && crtc->enabled) { crtc->hwmode = saved_hwmode; crtc->mode = saved_mode; + } else { + intel_modeset_check_state(dev); } return ret; @@ -8147,6 +8247,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev) } intel_modeset_update_staged_output_state(dev); + + intel_modeset_check_state(dev); } void intel_modeset_gem_init(struct drm_device *dev) -- cgit v1.2.3 From b980514c9adf403e3f43ead08196f5ce0e61fd05 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 31 Aug 2012 17:37:33 +0200 Subject: drm/i915: improve modeset state checking after dpms calls Now that we have solid modeset state tracking and checking code in place, we can do the Full Monty also after dpms calls. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 6 +++--- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_dvo.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index cca266f72a4c..b9f08f66a4a4 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -177,7 +177,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) intel_crtc_update_dpms(crtc); } - intel_connector_check_state(to_intel_connector(connector)); + intel_modeset_check_state(connector->dev); } static int intel_crt_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d15fa0c6ae88..44318bf8e7b9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3585,7 +3585,7 @@ void intel_encoder_dpms(struct intel_encoder *encoder, int mode) /* Cross check the actual hw state with our own modeset state tracking (and it's * internal consistency). */ -void intel_connector_check_state(struct intel_connector *connector) +static void intel_connector_check_state(struct intel_connector *connector) { if (connector->get_hw_state(connector)) { struct intel_encoder *encoder = connector->encoder; @@ -3639,7 +3639,7 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) else WARN_ON(encoder->connectors_active != false); - intel_connector_check_state(to_intel_connector(connector)); + intel_modeset_check_state(connector->dev); } /* Simple connector->get_hw_state implementation for encoders that support only @@ -6872,7 +6872,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) \ -static void +void intel_modeset_check_state(struct drm_device *dev) { struct intel_crtc *crtc; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3b1c407699c7..d391e67231b7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1362,7 +1362,7 @@ intel_dp_dpms(struct drm_connector *connector, int mode) intel_encoder_dpms(&intel_dp->base, mode); } - intel_connector_check_state(to_intel_connector(connector)); + intel_modeset_check_state(connector->dev); } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2061399d92c1..19e69285ba31 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -455,7 +455,8 @@ extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); -extern void intel_connector_check_state(struct intel_connector *); +extern void intel_modeset_check_state(struct drm_device *dev); + static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) { diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index aa1bf57963b1..4f1fdcc44005 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -189,7 +189,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) intel_crtc_update_dpms(crtc); } - intel_connector_check_state(to_intel_connector(connector)); + intel_modeset_check_state(connector->dev); } static int intel_dvo_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 6f538719b727..07d39212dcad 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1275,7 +1275,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } - intel_connector_check_state(to_intel_connector(connector)); + intel_modeset_check_state(connector->dev); } static int intel_sdvo_mode_valid(struct drm_connector *connector, -- cgit v1.2.3 From 6c4c86f51c985a146ff7185abff102fc535f6fa8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 10 Sep 2012 21:58:30 +0200 Subject: drm/i915: correctly update crtc->x/y in set_base While reworking the modeset sequence, this got lost in commit 25c5b2665fe4cc5a93edd29b62e7c05c15dddd26 Author: Daniel Vetter Date: Sun Jul 8 22:08:04 2012 +0200 drm/i915: implement new set_mode code flow I've noticed this because some Xorg versions seem to set up a new mode with every crtc at (0,0) and then pan to the right multi-monitor setup. And since some hacks of mine added more calls to mode_set using the stored crtc->x/y my multi-screen setup blew up. Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e061acdde45d..5576b7c695ed 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2246,6 +2246,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, old_fb = crtc->fb; crtc->fb = fb; + crtc->x = x; + crtc->y = y; if (old_fb) { intel_wait_for_vblank(dev, intel_crtc->pipe); @@ -7020,11 +7022,11 @@ bool intel_set_mode(struct drm_crtc *crtc, dev_priv->display.crtc_disable(&intel_crtc->base); } - if (modeset_pipes) { + /* crtc->mode is already used by the ->mode_set callbacks, hence we need + * to set it here already despite that we pass it down the callchain. + */ + if (modeset_pipes) crtc->mode = *mode; - crtc->x = x; - crtc->y = y; - } /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ -- cgit v1.2.3 From c8203565b098ebb771991a11fce75fed9fe344a0 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Sep 2012 10:06:29 -0300 Subject: drm/i915: extract ironlake_set_pipeconf form ironlake_crtc_mode_set Because ironlake_crtc_mode_set is a giant function that used to have 404 lines. Let's try to make it less complex/confusing. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 88 +++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 36 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5576b7c695ed..84e5ed472394 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4648,6 +4648,50 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) return 120000; } +static void ironlake_set_pipeconf(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + bool dither) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint32_t val; + + val = I915_READ(PIPECONF(pipe)); + + val &= ~PIPE_BPC_MASK; + switch (intel_crtc->bpp) { + case 18: + val |= PIPE_6BPC; + break; + case 24: + val |= PIPE_8BPC; + break; + case 30: + val |= PIPE_10BPC; + break; + case 36: + val |= PIPE_12BPC; + break; + default: + val |= PIPE_8BPC; + break; + } + + val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); + if (dither) + val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); + + val &= ~PIPECONF_INTERLACE_MASK; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + val |= PIPECONF_INTERLACED_ILK; + else + val |= PIPECONF_PROGRESSIVE; + + I915_WRITE(PIPECONF(pipe), val); + POSTING_READ(PIPECONF(pipe)); +} + static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4661,7 +4705,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; + u32 dpll, fp = 0, fp2 = 0, dspcntr; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; struct intel_encoder *encoder, *edp_encoder = NULL; @@ -4770,32 +4814,17 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, target_clock = adjusted_mode->clock; /* determine panel color depth */ - temp = I915_READ(PIPECONF(pipe)); - temp &= ~PIPE_BPC_MASK; dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode); - switch (pipe_bpp) { - case 18: - temp |= PIPE_6BPC; - break; - case 24: - temp |= PIPE_8BPC; - break; - case 30: - temp |= PIPE_10BPC; - break; - case 36: - temp |= PIPE_12BPC; - break; - default: + if (is_lvds && dev_priv->lvds_dither) + dither = true; + + if (pipe_bpp != 18 && pipe_bpp != 24 && pipe_bpp != 30 && + pipe_bpp != 36) { WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n", - pipe_bpp); - temp |= PIPE_8BPC; + pipe_bpp); pipe_bpp = 24; - break; } - intel_crtc->bpp = pipe_bpp; - I915_WRITE(PIPECONF(pipe), temp); if (!lane) { /* @@ -4879,9 +4908,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else dpll |= PLL_REF_INPUT_DREFCLK; - /* setup pipeconf */ - pipeconf = I915_READ(PIPECONF(pipe)); - /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -4944,12 +4970,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(PCH_LVDS, temp); } - pipeconf &= ~PIPECONF_DITHER_EN; - pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; - if ((is_lvds && dev_priv->lvds_dither) || dither) { - pipeconf |= PIPECONF_DITHER_EN; - pipeconf |= PIPECONF_DITHER_TYPE_SP; - } if (is_dp && !is_cpu_edp) { intel_dp_set_m_n(crtc, mode, adjusted_mode); } else { @@ -4985,9 +5005,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } } - pipeconf &= ~PIPECONF_INTERLACE_MASK; if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { - pipeconf |= PIPECONF_INTERLACED_ILK; /* the chip adds 2 halflines automatically */ adjusted_mode->crtc_vtotal -= 1; adjusted_mode->crtc_vblank_end -= 1; @@ -4995,7 +5013,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_htotal/2); } else { - pipeconf |= PIPECONF_PROGRESSIVE; I915_WRITE(VSYNCSHIFT(pipe), 0); } @@ -5033,8 +5050,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (is_cpu_edp) ironlake_set_pll_edp(crtc, adjusted_mode->clock); - I915_WRITE(PIPECONF(pipe), pipeconf); - POSTING_READ(PIPECONF(pipe)); + ironlake_set_pipeconf(crtc, adjusted_mode, dither); intel_wait_for_vblank(dev, pipe); -- cgit v1.2.3 From a1f9e77e1f2f1bf3769798c1596433deff08cd04 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Sep 2012 10:06:32 -0300 Subject: drm/i915: simplify setting DSPCNTR inside ironlake_crtc_mode_set Because declaring a variable in the beginning of the function, then initializing it 100 lines later, then using it 100 lines later does not make our code look good IMHO. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 84e5ed472394..4457fc7a9533 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4705,7 +4705,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll, fp = 0, fp2 = 0, dspcntr; + u32 dpll, fp = 0, fp2 = 0; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; struct intel_encoder *encoder, *edp_encoder = NULL; @@ -4908,9 +4908,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else dpll |= PLL_REF_INPUT_DREFCLK; - /* Set up the display plane register */ - dspcntr = DISPPLANE_GAMMA_ENABLE; - DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); @@ -5054,7 +5051,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_wait_for_vblank(dev, pipe); - I915_WRITE(DSPCNTR(plane), dspcntr); + /* Set up the display plane register */ + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); POSTING_READ(DSPCNTR(plane)); ret = intel_pipe_set_base(crtc, x, y, fb); -- cgit v1.2.3 From 6591c6e4d7d5d0020b91e960e2fe52e0ba6b2a24 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Sep 2012 10:06:34 -0300 Subject: drm/i915: extract compute_clocks from ironlake_crtc_mode_set Signed-off-by: Paulo Zanoni [danvet: resolved conflicts due to missing some earlier patches.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 96 +++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 30 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4457fc7a9533..d771f2f37678 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4692,6 +4692,69 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, POSTING_READ(PIPECONF(pipe)); } +static bool ironlake_compute_clocks(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, + bool *has_reduced_clock, + intel_clock_t *reduced_clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + int refclk; + const intel_limit_t *limit; + bool ret, is_sdvo = false, is_tv = false, is_lvds = false; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + switch (intel_encoder->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + if (intel_encoder->needs_tv_clock) + is_tv = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + } + } + + refclk = ironlake_get_refclk(crtc); + + /* + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ + limit = intel_limit(crtc, refclk); + ret = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL, + clock); + if (!ret) + return false; + + if (is_lvds && dev_priv->lvds_downclock_avail) { + /* + * Ensure we match the reduced clock's P to the target clock. + * If the clocks don't match, we can't switch the display clock + * by using the FP0/FP1. In such case we will disable the LVDS + * downclock feature. + */ + *has_reduced_clock = limit->find_pll(limit, crtc, + dev_priv->lvds_downclock, + refclk, + clock, + reduced_clock); + } + + if (is_sdvo && is_tv) + i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock); + + return true; +} + static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4703,13 +4766,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int refclk, num_connectors = 0; + int num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dpll, fp = 0, fp2 = 0; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; struct intel_encoder *encoder, *edp_encoder = NULL; - const intel_limit_t *limit; int ret; struct fdi_m_n m_n = {0}; u32 temp; @@ -4751,16 +4813,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - refclk = ironlake_get_refclk(crtc); - - /* - * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. - */ - limit = intel_limit(crtc, refclk); - ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL, - &clock); + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, + &has_reduced_clock, &reduced_clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); return -EINVAL; @@ -4769,24 +4823,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - if (is_lvds && dev_priv->lvds_downclock_avail) { - /* - * Ensure we match the reduced clock's P to the target clock. - * If the clocks don't match, we can't switch the display clock - * by using the FP0/FP1. In such case we will disable the LVDS - * downclock feature. - */ - has_reduced_clock = limit->find_pll(limit, crtc, - dev_priv->lvds_downclock, - refclk, - &clock, - &reduced_clock); - } - - if (is_sdvo && is_tv) - i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); - - /* FDI link */ pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); lane = 0; -- cgit v1.2.3 From bf49ec8c5241ca1985269ce77df08021a5dd1589 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Sep 2012 22:15:40 +0200 Subject: drm/i915: add encoder->pre_enable/post_disable The cpu eDP encoder has some horrible hacks to set up the DP pll at the right time. To be able to move them to the right place, add some more encoder callbacks so that this can happen at the right time. LVDS has some similar funky hacks, but that would require more work (we need to move around the pll setup a bit). Hence for now only wire these new callbacks up for ilk+ - we only have cpu eDP on these platforms. v2: Bikeshed the vtable ordering, requested by Chris Wilson. Reviewed-by: Paulo Zanoni Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ 2 files changed, 10 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d771f2f37678..ea707fcbc40a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3242,6 +3242,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) else ironlake_fdi_disable(crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + /* Enable panel fitting for LVDS */ if (dev_priv->pch_pf_size && (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) { @@ -3311,6 +3315,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) I915_WRITE(PF_CTL(pipe), 0); I915_WRITE(PF_WIN_SZ(pipe), 0); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->post_disable) + encoder->post_disable(encoder); + ironlake_fdi_disable(crtc); /* This is a horrible layering violation; we should be doing this in diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4f2b2d6a2489..351fd7179cd7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -152,8 +152,10 @@ struct intel_encoder { bool cloneable; bool connectors_active; void (*hot_plug)(struct intel_encoder *); + void (*pre_enable)(struct intel_encoder *); void (*enable)(struct intel_encoder *); void (*disable)(struct intel_encoder *); + void (*post_disable)(struct intel_encoder *); /* Read out the current hw state of this connector, returning true if * the encoder is active. If the encoder is enabled it also set the pipe * it is connected to in the pipe parameter. */ -- cgit v1.2.3 From a14d33592061032be0f8373627eb13882c857742 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Sep 2012 22:08:32 +0200 Subject: drm/i915: rip out intel_disable_pch_ports Even with the old crtc helper code we should have disabled all encoders on that pipe by now, and with the new code this would definitely paper over a bug. We already have the necessary checks in place in intel_disable_transcoder, so if we accidentally leave a pch port on, this will be caught. Hence just rip this all out. Note that up to the patch in this giant modeset series that removes the LVDS special case to avoid disabling LVDS in the encoder->prepare callback ("drm/i915/lvds: ditch ->prepare special case"), this was not the case for all outputs. Also note that in commit 1b3c7a47f993bf9ab6c4c7cc3bbf5588052b58f4 Author: Zhenyu Wang Date: Wed Nov 25 13:09:38 2009 +0800 drm/i915: Fix LVDS stability issue on Ironlake this was already discovered independently and worked around. How I bloody hate this entire mess of cludges piled on top of other cludges. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 60 ------------------------------------ 1 file changed, 60 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ea707fcbc40a..b20fad3d9f04 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1860,59 +1860,6 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, intel_wait_for_vblank(dev_priv->dev, pipe); } -static void disable_pch_dp(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg, u32 port_sel) -{ - u32 val = I915_READ(reg); - if (dp_pipe_enabled(dev_priv, pipe, 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(dev_priv, pipe, val)) { - 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 */ -static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, - enum pipe pipe) -{ - u32 reg, val; - - val = I915_READ(PCH_PP_CONTROL); - I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS); - - 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); - if (adpa_pipe_enabled(dev_priv, pipe, val)) - I915_WRITE(reg, val & ~ADPA_DAC_ENABLE); - - reg = PCH_LVDS; - val = I915_READ(reg); - if (lvds_pipe_enabled(dev_priv, pipe, val)) { - DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val); - I915_WRITE(reg, val & ~LVDS_PORT_EN); - POSTING_READ(reg); - udelay(100); - } - - disable_pch_hdmi(dev_priv, pipe, HDMIB); - disable_pch_hdmi(dev_priv, pipe, HDMIC); - disable_pch_hdmi(dev_priv, pipe, HDMID); -} - int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, @@ -3321,13 +3268,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_disable(crtc); - /* This is a horrible layering violation; we should be doing this in - * the connector/encoder ->prepare instead, but we don't always have - * enough information there about the config to know whether it will - * actually be necessary or just cause undesired flicker. - */ - intel_disable_pch_ports(dev_priv, pipe); - intel_disable_transcoder(dev_priv, pipe); if (HAS_PCH_CPT(dev)) { -- cgit v1.2.3 From 46b6f8149a7a631ae8789f4eaebf8c27c1279b5a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Sep 2012 22:08:33 +0200 Subject: drm/i915: don't disable fdi links harder in ilk_crtc_enable Because they should have been disabled when shutting down the display pipe previously. To ensure that this is the case, add a few assserts instead of unconditionally disabling the fdi link. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b20fad3d9f04..5e42a03f2685 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3184,10 +3184,12 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) is_pch_port = intel_crtc_driving_pch(crtc); - if (is_pch_port) + if (is_pch_port) { ironlake_fdi_pll_enable(intel_crtc); - else - ironlake_fdi_disable(crtc); + } else { + assert_fdi_tx_disabled(dev_priv, pipe); + assert_fdi_rx_disabled(dev_priv, pipe); + } for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) -- cgit v1.2.3 From 172a1ae141a20f8279dfa285d99ff0541b7eb044 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Sep 2012 22:08:34 +0200 Subject: drm/i915: don't call dpms funcs after set_mode ... because our current set_mode implementation doesn't bother to adjust for the dpms state, we just forcefully update it. So stop pretending that we're better than we are and rip out this extranous call. Note that this totally confuses userspace, because the exposed connector property isn't actually updated ... Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5e42a03f2685..00e8541f81ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7296,7 +7296,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) struct drm_mode_set save_set; struct intel_set_config *config; int ret; - int i; BUG_ON(!set); BUG_ON(!set->crtc); @@ -7360,15 +7359,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail; } - - if (set->crtc->enabled) { - DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); - for (i = 0; i < set->num_connectors; i++) { - DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, - drm_get_connector_name(set->connectors[i])); - set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); - } - } } else if (config->fb_changed) { ret = intel_pipe_set_base(set->crtc, set->x, set->y, set->fb); -- cgit v1.2.3 From 68d3472047a572936551f8ff0b6f4016c5a1fdef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Sep 2012 22:08:35 +0200 Subject: drm/i915: update dpms property in set_mode Hopefully this makes userspace slightly less confused about us frobbing the dpms state behind its back. Yeah, it would be better to be more careful with not changing the dpms state, but that is quite more invasive. Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 00e8541f81ca..947c97d427cc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6866,7 +6866,13 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) intel_crtc = to_intel_crtc(connector->encoder->crtc); if (prepare_pipes & (1 << intel_crtc->pipe)) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; + connector->dpms = DRM_MODE_DPMS_ON; + drm_connector_property_set_value(connector, + dpms_property, + DRM_MODE_DPMS_ON); intel_encoder = to_intel_encoder(connector->encoder); intel_encoder->connectors_active = true; -- cgit v1.2.3 From 0c96c65b48fba3ffe9822a554cbc0cd610765cd5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 26 Sep 2012 18:43:10 +0300 Subject: drm/i915: use adjusted_mode instead of mode for checking the 6bpc force flag The dithering introduced in commit 3b5c78a35cf7511c15e09a9b0ffab290a42d9bcf Author: Adam Jackson Date: Tue Dec 13 15:41:00 2011 -0800 drm/i915/dp: Dither down to 6bpc if it makes the mode fit stores the INTEL_MODE_DP_FORCE_6BPC flag in the private_flags of the adjusted mode, while i9xx_crtc_mode_set() and ironlake_crtc_mode_set() use the original mode, without the flag, so it would never have any effect. However, the BPC was clamped by VBT settings, making things work by coincidence, until that part was removed in commit 4344b813f105a19f793f1fd93ad775b784648b95 Author: Daniel Vetter Date: Fri Aug 10 11:10:20 2012 +0200 Use adjusted_mode instead of mode when checking for INTEL_MODE_DP_FORCE_6BPC to make the flag have effect. v2: Don't forget to fix this in i9xx_crtc_mode_set() also, pointed out by Daniel both before and after sending the first patch. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=47621 CC: Adam Jackson CC: stable@vger.kernel.org Signed-off-by: Jani Nikula Reviewed-by: Adam Jackson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6f5aafa1b633..f6e274c5db62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4370,7 +4370,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, /* default to 8bpc */ pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN); if (is_dp) { - if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { + if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { pipeconf |= PIPECONF_BPP_6 | PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP; @@ -4802,7 +4802,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, target_clock = adjusted_mode->clock; /* determine panel color depth */ - dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, mode); + dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, + adjusted_mode); if (is_lvds && dev_priv->lvds_dither) dither = true; -- cgit v1.2.3 From 5bb61643f6a70d48de9cfe91ad0fee0d618b6816 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 Sep 2012 21:25:58 +0100 Subject: drm/i915: Flush the pending flips on the CRTC before modification This was meant to be the purpose of the intel_crtc_wait_for_pending_flips() function which is called whilst preparing the CRTC for a modeset or before disabling. However, as Ville Syrjala pointed out, we set the pending flip notification on the old framebuffer that is no longer attached to the CRTC by the time we come to flush the pending operations. Instead, we can simply wait on the pending unpin work to be finished on this CRTC, knowning that the hardware has therefore finished modifying the registers, before proceeding with our direct access. Fixes i-g-t/flip_test on non-pch platforms. pch platforms simply schedule the flip immediately when the pipe is disabled, leading to other funny issues. Signed-off-by: Chris Wilson Cc: stable@vger.kernel.org [danvet: Added i-g-t note and cc: stable] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f6e274c5db62..57c1309733f6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2806,13 +2806,34 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) udelay(100); } +static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + bool pending; + + if (atomic_read(&dev_priv->mm.wedged)) + return false; + + spin_lock_irqsave(&dev->event_lock, flags); + pending = to_intel_crtc(crtc)->unpin_work != NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + return pending; +} + static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; if (crtc->fb == NULL) return; + wait_event(dev_priv->pending_flip_queue, + !intel_crtc_has_pending_flip(crtc)); + mutex_lock(&dev->struct_mutex); intel_finish_fb(crtc->fb); mutex_unlock(&dev->struct_mutex); @@ -6217,9 +6238,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev, atomic_clear_mask(1 << intel_crtc->plane, &obj->pending_flip.counter); - if (atomic_read(&obj->pending_flip) == 0) - wake_up(&dev_priv->pending_flip_queue); + wake_up(&dev_priv->pending_flip_queue); schedule_work(&work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); -- cgit v1.2.3 From 760285e7e7ab282c25b5e90816f7c47000557f4f Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 2 Oct 2012 18:01:07 +0100 Subject: UAPI: (Scripted) Convert #include "..." to #include in drivers/gpu/ Convert #include "..." to #include in drivers/gpu/. Signed-off-by: David Howells Acked-by: Dave Airlie Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Paul E. McKenney Acked-by: Dave Jones --- drivers/gpu/drm/ast/ast_drv.c | 4 ++-- drivers/gpu/drm/ast/ast_drv.h | 12 ++++++------ drivers/gpu/drm/ast/ast_fb.c | 6 +++--- drivers/gpu/drm/ast/ast_main.c | 6 +++--- drivers/gpu/drm/ast/ast_mode.c | 6 +++--- drivers/gpu/drm/ast/ast_post.c | 2 +- drivers/gpu/drm/ast/ast_ttm.c | 2 +- drivers/gpu/drm/ati_pcigart.c | 2 +- drivers/gpu/drm/cirrus/cirrus_drv.c | 2 +- drivers/gpu/drm/cirrus/cirrus_drv.h | 10 +++++----- drivers/gpu/drm/cirrus/cirrus_fbdev.c | 4 ++-- drivers/gpu/drm/cirrus/cirrus_main.c | 4 ++-- drivers/gpu/drm/cirrus/cirrus_mode.c | 4 ++-- drivers/gpu/drm/cirrus/cirrus_ttm.c | 2 +- drivers/gpu/drm/drm_agpsupport.c | 2 +- drivers/gpu/drm/drm_auth.c | 2 +- drivers/gpu/drm/drm_buffer.c | 2 +- drivers/gpu/drm/drm_bufs.c | 2 +- drivers/gpu/drm/drm_cache.c | 2 +- drivers/gpu/drm/drm_context.c | 2 +- drivers/gpu/drm/drm_crtc.c | 8 ++++---- drivers/gpu/drm/drm_crtc_helper.c | 12 ++++++------ drivers/gpu/drm/drm_debugfs.c | 2 +- drivers/gpu/drm/drm_dma.c | 2 +- drivers/gpu/drm/drm_dp_i2c_helper.c | 4 ++-- drivers/gpu/drm/drm_drv.c | 4 ++-- drivers/gpu/drm/drm_edid.c | 4 ++-- drivers/gpu/drm/drm_edid_load.c | 8 ++++---- drivers/gpu/drm/drm_edid_modes.h | 4 ++-- drivers/gpu/drm/drm_encoder_slave.c | 2 +- drivers/gpu/drm/drm_fb_helper.c | 8 ++++---- drivers/gpu/drm/drm_fops.c | 2 +- drivers/gpu/drm/drm_gem.c | 2 +- drivers/gpu/drm/drm_global.c | 2 +- drivers/gpu/drm/drm_hashtab.c | 4 ++-- drivers/gpu/drm/drm_info.c | 2 +- drivers/gpu/drm/drm_ioc32.c | 4 ++-- drivers/gpu/drm/drm_ioctl.c | 8 ++++---- drivers/gpu/drm/drm_irq.c | 2 +- drivers/gpu/drm/drm_lock.c | 2 +- drivers/gpu/drm/drm_memory.c | 2 +- drivers/gpu/drm/drm_mm.c | 4 ++-- drivers/gpu/drm/drm_modes.c | 4 ++-- drivers/gpu/drm/drm_pci.c | 2 +- drivers/gpu/drm/drm_platform.c | 2 +- drivers/gpu/drm/drm_prime.c | 2 +- drivers/gpu/drm/drm_proc.c | 2 +- drivers/gpu/drm/drm_scatter.c | 2 +- drivers/gpu/drm/drm_stub.c | 4 ++-- drivers/gpu/drm/drm_sysfs.c | 6 +++--- drivers/gpu/drm/drm_trace_points.c | 2 +- drivers/gpu/drm/drm_usb.c | 2 +- drivers/gpu/drm/drm_vm.c | 2 +- drivers/gpu/drm/exynos/exynos_ddc.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_buf.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_connector.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_core.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_drv.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_encoder.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_fb.c | 8 ++++---- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 8 ++++---- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_gem.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_plane.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 6 +++--- drivers/gpu/drm/exynos/exynos_hdmi.c | 6 +++--- drivers/gpu/drm/exynos/exynos_hdmiphy.c | 2 +- drivers/gpu/drm/exynos/exynos_mixer.c | 2 +- drivers/gpu/drm/gma500/cdv_device.c | 2 +- drivers/gpu/drm/gma500/gem.c | 2 +- drivers/gpu/drm/gma500/intel_bios.c | 2 +- drivers/gpu/drm/gma500/intel_gmbus.c | 4 ++-- drivers/gpu/drm/gma500/mid_bios.c | 2 +- drivers/gpu/drm/gma500/oaktrail_device.c | 2 +- drivers/gpu/drm/gma500/psb_device.c | 2 +- drivers/gpu/drm/gma500/psb_drv.c | 2 +- drivers/gpu/drm/gma500/psb_drv.h | 4 ++-- drivers/gpu/drm/gma500/psb_intel_sdvo.c | 8 ++++---- drivers/gpu/drm/i2c/ch7006_priv.h | 8 ++++---- drivers/gpu/drm/i2c/sil164_drv.c | 8 ++++---- drivers/gpu/drm/i810/i810_dma.c | 4 ++-- drivers/gpu/drm/i810/i810_drv.c | 6 +++--- drivers/gpu/drm/i915/dvo.h | 4 ++-- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/i915_dma.c | 8 ++++---- drivers/gpu/drm/i915/i915_drv.c | 6 +++--- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_debug.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_dmabuf.c | 2 +- drivers/gpu/drm/i915/i915_gem_evict.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_stolen.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_tiling.c | 8 ++++---- drivers/gpu/drm/i915/i915_ioc32.c | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- drivers/gpu/drm/i915/i915_suspend.c | 4 ++-- drivers/gpu/drm/i915/intel_acpi.c | 2 +- drivers/gpu/drm/i915/intel_bios.c | 4 ++-- drivers/gpu/drm/i915/intel_bios.h | 2 +- drivers/gpu/drm/i915/intel_crt.c | 10 +++++----- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_dp.c | 12 ++++++------ drivers/gpu/drm/i915/intel_drv.h | 8 ++++---- drivers/gpu/drm/i915/intel_dvo.c | 6 +++--- drivers/gpu/drm/i915/intel_fb.c | 8 ++++---- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++---- drivers/gpu/drm/i915/intel_i2c.c | 4 ++-- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++---- drivers/gpu/drm/i915/intel_modes.c | 4 ++-- drivers/gpu/drm/i915/intel_opregion.c | 4 ++-- drivers/gpu/drm/i915/intel_overlay.c | 4 ++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++-- drivers/gpu/drm/i915/intel_sdvo.c | 8 ++++---- drivers/gpu/drm/i915/intel_sprite.c | 8 ++++---- drivers/gpu/drm/i915/intel_tv.c | 8 ++++---- drivers/gpu/drm/mga/mga_dma.c | 4 ++-- drivers/gpu/drm/mga/mga_drv.c | 6 +++--- drivers/gpu/drm/mga/mga_ioc32.c | 4 ++-- drivers/gpu/drm/mga/mga_irq.c | 4 ++-- drivers/gpu/drm/mga/mga_state.c | 4 ++-- drivers/gpu/drm/mga/mga_warp.c | 4 ++-- drivers/gpu/drm/mgag200/mgag200_drv.c | 4 ++-- drivers/gpu/drm/mgag200/mgag200_drv.h | 12 ++++++------ drivers/gpu/drm/mgag200/mgag200_fb.c | 4 ++-- drivers/gpu/drm/mgag200/mgag200_i2c.c | 2 +- drivers/gpu/drm/mgag200/mgag200_main.c | 4 ++-- drivers/gpu/drm/mgag200/mgag200_mode.c | 4 ++-- drivers/gpu/drm/mgag200/mgag200_ttm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- drivers/gpu/drm/nouveau/nouveau_acpi.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_backlight.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_calc.c | 2 +- drivers/gpu/drm/nouveau/nouveau_channel.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_connector.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_connector.h | 2 +- drivers/gpu/drm/nouveau/nouveau_debugfs.c | 2 +- drivers/gpu/drm/nouveau/nouveau_display.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_dma.c | 2 +- drivers/gpu/drm/nouveau/nouveau_dp.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_drv.h | 12 ++++++------ drivers/gpu/drm/nouveau/nouveau_encoder.h | 2 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 10 +++++----- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 +- drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_gpio.c | 2 +- drivers/gpu/drm/nouveau/nouveau_gpuobj.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_hdmi.c | 2 +- drivers/gpu/drm/nouveau/nouveau_hw.c | 2 +- drivers/gpu/drm/nouveau/nouveau_hw.h | 2 +- drivers/gpu/drm/nouveau/nouveau_i2c.c | 2 +- drivers/gpu/drm/nouveau/nouveau_i2c.h | 2 +- drivers/gpu/drm/nouveau/nouveau_ioc32.c | 2 +- drivers/gpu/drm/nouveau/nouveau_irq.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_mem.c | 2 +- drivers/gpu/drm/nouveau/nouveau_mm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_mxm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_notifier.c | 2 +- drivers/gpu/drm/nouveau/nouveau_perf.c | 2 +- drivers/gpu/drm/nouveau/nouveau_pm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_prime.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_ramht.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 2 +- drivers/gpu/drm/nouveau/nouveau_state.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_temp.c | 2 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_vm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_vm.h | 2 +- drivers/gpu/drm/nouveau/nouveau_volt.c | 2 +- drivers/gpu/drm/nouveau/nv04_crtc.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_cursor.c | 2 +- drivers/gpu/drm/nouveau/nv04_dac.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_dfp.c | 6 +++--- drivers/gpu/drm/nouveau/nv04_display.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nv04_fence.c | 2 +- drivers/gpu/drm/nouveau/nv04_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv04_graph.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_instmem.c | 2 +- drivers/gpu/drm/nouveau/nv04_mc.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_pm.c | 2 +- drivers/gpu/drm/nouveau/nv04_software.c | 2 +- drivers/gpu/drm/nouveau/nv04_timer.c | 4 ++-- drivers/gpu/drm/nouveau/nv04_tv.c | 6 +++--- drivers/gpu/drm/nouveau/nv10_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nv10_fence.c | 2 +- drivers/gpu/drm/nouveau/nv10_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv10_gpio.c | 2 +- drivers/gpu/drm/nouveau/nv10_graph.c | 4 ++-- drivers/gpu/drm/nouveau/nv17_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv17_tv.c | 4 ++-- drivers/gpu/drm/nouveau/nv17_tv_modes.c | 4 ++-- drivers/gpu/drm/nouveau/nv20_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nv20_graph.c | 4 ++-- drivers/gpu/drm/nouveau/nv30_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nv31_mpeg.c | 2 +- drivers/gpu/drm/nouveau/nv40_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nv40_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv40_graph.c | 2 +- drivers/gpu/drm/nouveau/nv40_grctx.c | 2 +- drivers/gpu/drm/nouveau/nv40_mc.c | 4 ++-- drivers/gpu/drm/nouveau/nv40_pm.c | 2 +- drivers/gpu/drm/nouveau/nv50_calc.c | 2 +- drivers/gpu/drm/nouveau/nv50_crtc.c | 4 ++-- drivers/gpu/drm/nouveau/nv50_cursor.c | 2 +- drivers/gpu/drm/nouveau/nv50_dac.c | 4 ++-- drivers/gpu/drm/nouveau/nv50_display.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.h | 2 +- drivers/gpu/drm/nouveau/nv50_evo.c | 2 +- drivers/gpu/drm/nouveau/nv50_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nv50_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nv50_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv50_gpio.c | 2 +- drivers/gpu/drm/nouveau/nv50_graph.c | 2 +- drivers/gpu/drm/nouveau/nv50_grctx.c | 2 +- drivers/gpu/drm/nouveau/nv50_instmem.c | 2 +- drivers/gpu/drm/nouveau/nv50_mc.c | 2 +- drivers/gpu/drm/nouveau/nv50_mpeg.c | 2 +- drivers/gpu/drm/nouveau/nv50_pm.c | 2 +- drivers/gpu/drm/nouveau/nv50_software.c | 2 +- drivers/gpu/drm/nouveau/nv50_sor.c | 4 ++-- drivers/gpu/drm/nouveau/nv50_vm.c | 2 +- drivers/gpu/drm/nouveau/nv50_vram.c | 2 +- drivers/gpu/drm/nouveau/nv84_bsp.c | 2 +- drivers/gpu/drm/nouveau/nv84_crypt.c | 2 +- drivers/gpu/drm/nouveau/nv84_fence.c | 2 +- drivers/gpu/drm/nouveau/nv84_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv84_vp.c | 2 +- drivers/gpu/drm/nouveau/nv98_crypt.c | 2 +- drivers/gpu/drm/nouveau/nv98_ppp.c | 2 +- drivers/gpu/drm/nouveau/nva3_copy.c | 2 +- drivers/gpu/drm/nouveau/nva3_pm.c | 2 +- drivers/gpu/drm/nouveau/nvc0_copy.c | 2 +- drivers/gpu/drm/nouveau/nvc0_fb.c | 4 ++-- drivers/gpu/drm/nouveau/nvc0_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nvc0_fence.c | 2 +- drivers/gpu/drm/nouveau/nvc0_fifo.c | 2 +- drivers/gpu/drm/nouveau/nvc0_graph.c | 2 +- drivers/gpu/drm/nouveau/nvc0_grctx.c | 2 +- drivers/gpu/drm/nouveau/nvc0_instmem.c | 2 +- drivers/gpu/drm/nouveau/nvc0_pm.c | 2 +- drivers/gpu/drm/nouveau/nvc0_software.c | 2 +- drivers/gpu/drm/nouveau/nvc0_vm.c | 2 +- drivers/gpu/drm/nouveau/nvc0_vram.c | 2 +- drivers/gpu/drm/nouveau/nvd0_display.c | 4 ++-- drivers/gpu/drm/nouveau/nve0_fifo.c | 2 +- drivers/gpu/drm/nouveau/nve0_graph.c | 2 +- drivers/gpu/drm/nouveau/nve0_grctx.c | 2 +- drivers/gpu/drm/r128/r128_cce.c | 4 ++-- drivers/gpu/drm/r128/r128_drv.c | 6 +++--- drivers/gpu/drm/r128/r128_ioc32.c | 4 ++-- drivers/gpu/drm/r128/r128_irq.c | 4 ++-- drivers/gpu/drm/r128/r128_state.c | 4 ++-- drivers/gpu/drm/radeon/atom.h | 2 +- drivers/gpu/drm/radeon/atombios_dp.c | 6 +++--- drivers/gpu/drm/radeon/atombios_encoders.c | 6 +++--- drivers/gpu/drm/radeon/atombios_i2c.c | 4 ++-- drivers/gpu/drm/radeon/evergreen.c | 4 ++-- drivers/gpu/drm/radeon/evergreen_blit_kms.c | 4 ++-- drivers/gpu/drm/radeon/evergreen_cs.c | 2 +- drivers/gpu/drm/radeon/evergreen_hdmi.c | 4 ++-- drivers/gpu/drm/radeon/ni.c | 4 ++-- drivers/gpu/drm/radeon/r100.c | 4 ++-- drivers/gpu/drm/radeon/r200.c | 4 ++-- drivers/gpu/drm/radeon/r300.c | 2 +- drivers/gpu/drm/radeon/r300_cmdbuf.c | 6 +++--- drivers/gpu/drm/radeon/r420.c | 2 +- drivers/gpu/drm/radeon/r520.c | 2 +- drivers/gpu/drm/radeon/r600.c | 4 ++-- drivers/gpu/drm/radeon/r600_audio.c | 2 +- drivers/gpu/drm/radeon/r600_blit.c | 4 ++-- drivers/gpu/drm/radeon/r600_blit_kms.c | 4 ++-- drivers/gpu/drm/radeon/r600_cp.c | 4 ++-- drivers/gpu/drm/radeon/r600_cs.c | 2 +- drivers/gpu/drm/radeon/r600_hdmi.c | 4 ++-- drivers/gpu/drm/radeon/radeon_acpi.c | 4 ++-- drivers/gpu/drm/radeon/radeon_agp.c | 4 ++-- drivers/gpu/drm/radeon/radeon_atombios.c | 4 ++-- drivers/gpu/drm/radeon/radeon_bios.c | 2 +- drivers/gpu/drm/radeon/radeon_clocks.c | 4 ++-- drivers/gpu/drm/radeon/radeon_combios.c | 4 ++-- drivers/gpu/drm/radeon/radeon_connectors.c | 10 +++++----- drivers/gpu/drm/radeon/radeon_cp.c | 4 ++-- drivers/gpu/drm/radeon/radeon_cs.c | 4 ++-- drivers/gpu/drm/radeon/radeon_cursor.c | 4 ++-- drivers/gpu/drm/radeon/radeon_display.c | 8 ++++---- drivers/gpu/drm/radeon/radeon_drv.c | 6 +++--- drivers/gpu/drm/radeon/radeon_encoders.c | 6 +++--- drivers/gpu/drm/radeon/radeon_fb.c | 10 +++++----- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- drivers/gpu/drm/radeon/radeon_gart.c | 4 ++-- drivers/gpu/drm/radeon/radeon_gem.c | 4 ++-- drivers/gpu/drm/radeon/radeon_i2c.c | 6 +++--- drivers/gpu/drm/radeon/radeon_ioc32.c | 4 ++-- drivers/gpu/drm/radeon/radeon_irq.c | 4 ++-- drivers/gpu/drm/radeon/radeon_irq_kms.c | 6 +++--- drivers/gpu/drm/radeon/radeon_kms.c | 4 ++-- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 6 +++--- drivers/gpu/drm/radeon/radeon_legacy_tv.c | 4 ++-- drivers/gpu/drm/radeon/radeon_mem.c | 4 ++-- drivers/gpu/drm/radeon/radeon_mode.h | 10 +++++----- drivers/gpu/drm/radeon/radeon_object.c | 2 +- drivers/gpu/drm/radeon/radeon_pm.c | 2 +- drivers/gpu/drm/radeon/radeon_prime.c | 4 ++-- drivers/gpu/drm/radeon/radeon_ring.c | 4 ++-- drivers/gpu/drm/radeon/radeon_sa.c | 2 +- drivers/gpu/drm/radeon/radeon_semaphore.c | 2 +- drivers/gpu/drm/radeon/radeon_state.c | 6 +++--- drivers/gpu/drm/radeon/radeon_trace_points.c | 2 +- drivers/gpu/drm/radeon/rs600.c | 2 +- drivers/gpu/drm/radeon/rs690.c | 2 +- drivers/gpu/drm/radeon/rv515.c | 2 +- drivers/gpu/drm/radeon/rv770.c | 4 ++-- drivers/gpu/drm/radeon/si.c | 4 ++-- drivers/gpu/drm/savage/savage_bci.c | 4 ++-- drivers/gpu/drm/savage/savage_drv.c | 6 +++--- drivers/gpu/drm/savage/savage_state.c | 4 ++-- drivers/gpu/drm/sis/sis_drv.c | 6 +++--- drivers/gpu/drm/sis/sis_drv.h | 2 +- drivers/gpu/drm/sis/sis_mm.c | 4 ++-- drivers/gpu/drm/tdfx/tdfx_drv.c | 4 ++-- drivers/gpu/drm/ttm/ttm_agp_backend.c | 8 ++++---- drivers/gpu/drm/ttm/ttm_bo.c | 6 +++--- drivers/gpu/drm/ttm/ttm_bo_manager.c | 8 ++++---- drivers/gpu/drm/ttm/ttm_bo_util.c | 4 ++-- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 6 +++--- drivers/gpu/drm/ttm/ttm_lock.c | 4 ++-- drivers/gpu/drm/ttm/ttm_memory.c | 6 +++--- drivers/gpu/drm/ttm/ttm_module.c | 4 ++-- drivers/gpu/drm/ttm/ttm_object.c | 4 ++-- drivers/gpu/drm/ttm/ttm_page_alloc.c | 4 ++-- drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 4 ++-- drivers/gpu/drm/ttm/ttm_tt.c | 12 ++++++------ drivers/gpu/drm/udl/udl_connector.c | 8 ++++---- drivers/gpu/drm/udl/udl_drv.c | 4 ++-- drivers/gpu/drm/udl/udl_encoder.c | 6 +++--- drivers/gpu/drm/udl/udl_fb.c | 8 ++++---- drivers/gpu/drm/udl/udl_gem.c | 2 +- drivers/gpu/drm/udl/udl_main.c | 2 +- drivers/gpu/drm/udl/udl_modeset.c | 6 +++--- drivers/gpu/drm/udl/udl_transfer.c | 2 +- drivers/gpu/drm/via/via_dma.c | 4 ++-- drivers/gpu/drm/via/via_dmablit.c | 4 ++-- drivers/gpu/drm/via/via_drv.c | 6 +++--- drivers/gpu/drm/via/via_drv.h | 2 +- drivers/gpu/drm/via/via_irq.c | 4 ++-- drivers/gpu/drm/via/via_map.c | 4 ++-- drivers/gpu/drm/via/via_mm.c | 4 ++-- drivers/gpu/drm/via/via_verifier.c | 4 ++-- drivers/gpu/drm/via/via_video.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 10 +++++----- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 18 +++++++++--------- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 8 ++++---- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 2 +- 376 files changed, 731 insertions(+), 731 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index d5749b86caec..31123b6a0be5 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -28,8 +28,8 @@ #include #include -#include "drmP.h" -#include "drm_crtc_helper.h" +#include +#include #include "ast_drv.h" diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index d4af9edcbb97..aea439760b60 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -28,13 +28,13 @@ #ifndef __AST_DRV_H__ #define __AST_DRV_H__ -#include "drm_fb_helper.h" +#include -#include "ttm/ttm_bo_api.h" -#include "ttm/ttm_bo_driver.h" -#include "ttm/ttm_placement.h" -#include "ttm/ttm_memory.h" -#include "ttm/ttm_module.h" +#include +#include +#include +#include +#include #include #include diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index d0d279233101..d9ec77959dff 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -37,9 +37,9 @@ #include -#include "drmP.h" -#include "drm_crtc.h" -#include "drm_fb_helper.h" +#include +#include +#include #include "ast_drv.h" static void ast_dirty_update(struct ast_fbdev *afbdev, diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 95ae55b8214b..f668e6cc0f7a 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -25,12 +25,12 @@ /* * Authors: Dave Airlie */ -#include "drmP.h" +#include #include "ast_drv.h" -#include "drm_fb_helper.h" -#include "drm_crtc_helper.h" +#include +#include #include "ast_dram_tables.h" diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index a712cafcfa1d..a6982b86df9b 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -28,9 +28,9 @@ * Authors: Dave Airlie */ #include -#include "drmP.h" -#include "drm_crtc.h" -#include "drm_crtc_helper.h" +#include +#include +#include #include "ast_drv.h" #include "ast_tables.h" diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 6edbee63b0cb..977cfb35837a 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -26,7 +26,7 @@ * Authors: Dave Airlie */ -#include "drmP.h" +#include #include "ast_drv.h" #include "ast_dram_tables.h" diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 6cf2adea66bc..1a026ac2dfb4 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -25,7 +25,7 @@ /* * Authors: Dave Airlie */ -#include "drmP.h" +#include #include "ast_drv.h" #include diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 9afe495c12c7..c399dea27a3b 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -32,7 +32,7 @@ */ #include -#include "drmP.h" +#include # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index 781b90c5a3ca..101e423c8991 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -10,7 +10,7 @@ */ #include #include -#include "drmP.h" +#include #include "cirrus_drv.h" diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 64ea597cb6d3..7f0d71ffba3f 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -15,11 +15,11 @@ #include -#include "ttm/ttm_bo_api.h" -#include "ttm/ttm_bo_driver.h" -#include "ttm/ttm_placement.h" -#include "ttm/ttm_memory.h" -#include "ttm/ttm_module.h" +#include +#include +#include +#include +#include #define DRIVER_AUTHOR "Matthew Garrett" diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 6aaada5d2b61..6c6b4c87d309 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -9,8 +9,8 @@ * Dave Airlie */ #include -#include "drmP.h" -#include "drm_fb_helper.h" +#include +#include #include diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 5690d2412607..6a9b12e88d46 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -8,8 +8,8 @@ * Authors: Matthew Garrett * Dave Airlie */ -#include "drmP.h" -#include "drm_crtc_helper.h" +#include +#include #include "cirrus_drv.h" diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index e70f782a4f29..60685b21cc36 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -14,8 +14,8 @@ * * Copyright 1999-2001 Jeff Garzik */ -#include "drmP.h" -#include "drm_crtc_helper.h" +#include +#include #include