aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2014-12-02 07:10:46 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-12-03 03:31:53 -0500
commit00f0b3781028605910cb4662a0f8a4849b445fc2 (patch)
tree1e754a0524bda40b30a12cfdaf367ff43d815ee3 /drivers/gpu
parent9939fba226649c62630a74d36ee45c5d5402b460 (diff)
drm/i915: Reject modeset when the same digital port is used more than once
On pre-HSW we have two encoders per digital port: one HDMI, one DP. However they are the same physical port in hardware and we can't enable both at the same time. Reject the modeset if the user attempts this. So far we've been saved by the fact that we never see both HDMI and DP connectors as connected. But if the user decides to force a mode anyway, all kinds of funny stuff might happen. Unfortunately we don't seem to have any way to inform userspace that such configurations are invalid except by returning an error from setcrtc. possible_clones only covers real cloning situations, and looking at the connector names doesn't work either since we don't always register both connectors for the same port. I suppose the only way to fix that would be to expose only a single encoder per digital port like we do on HSW+ but that would be a fairly large undertaking for little gain. kms_setmode hits this since it forces modes on non-connected VGA and HDMI connectors. Previosuly it just resulted in weirdness such as failed link training. With this patch it will now get an error back from the kernel and will die with an assert since it thinks that the configuration should be fine. v2: Deal with INTEL_OUTPUT_UNKNOWN (Paulo) Cc: Paulo Zanoni <przanoni@gmail.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 910df02840d6..6289babd03b0 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10153,6 +10153,48 @@ static bool check_encoder_cloning(struct intel_crtc *crtc)
10153 return true; 10153 return true;
10154} 10154}
10155 10155
10156static bool check_digital_port_conflicts(struct drm_device *dev)
10157{
10158 struct intel_connector *connector;
10159 unsigned int used_ports = 0;
10160
10161 /*
10162 * Walk the connector list instead of the encoder
10163 * list to detect the problem on ddi platforms
10164 * where there's just one encoder per digital port.
10165 */
10166 list_for_each_entry(connector,
10167 &dev->mode_config.connector_list, base.head) {
10168 struct intel_encoder *encoder = connector->new_encoder;
10169
10170 if (!encoder)
10171 continue;
10172
10173 WARN_ON(!encoder->new_crtc);
10174
10175 switch (encoder->type) {
10176 unsigned int port_mask;
10177 case INTEL_OUTPUT_UNKNOWN:
10178 if (WARN_ON(!HAS_DDI(dev)))
10179 break;
10180 case INTEL_OUTPUT_DISPLAYPORT:
10181 case INTEL_OUTPUT_HDMI:
10182 case INTEL_OUTPUT_EDP:
10183 port_mask = 1 << enc_to_dig_port(&encoder->base)->port;
10184
10185 /* the same port mustn't appear more than once */
10186 if (used_ports & port_mask)
10187 return false;
10188
10189 used_ports |= port_mask;
10190 default:
10191 break;
10192 }
10193 }
10194
10195 return true;
10196}
10197
10156static struct intel_crtc_config * 10198static struct intel_crtc_config *
10157intel_modeset_pipe_config(struct drm_crtc *crtc, 10199intel_modeset_pipe_config(struct drm_crtc *crtc,
10158 struct drm_framebuffer *fb, 10200 struct drm_framebuffer *fb,
@@ -10169,6 +10211,11 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
10169 return ERR_PTR(-EINVAL); 10211 return ERR_PTR(-EINVAL);
10170 } 10212 }
10171 10213
10214 if (!check_digital_port_conflicts(dev)) {
10215 DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
10216 return ERR_PTR(-EINVAL);
10217 }
10218
10172 pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); 10219 pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
10173 if (!pipe_config) 10220 if (!pipe_config)
10174 return ERR_PTR(-ENOMEM); 10221 return ERR_PTR(-ENOMEM);