drm/i915: Make encoder cloning more flexible
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Mon, 3 Mar 2014 14:15:28 +0000 (16:15 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 10 Mar 2014 20:33:26 +0000 (21:33 +0100)
Currently we allow encoders to indicate whether they can be part of a
cloned set with just one flag. That's not flexible enough to describe
the actual hardware capabilities. Instead make it a bitmask of encoder
types with which the current encoder can be cloned.

For now we set the bitmask to allow DVO+DVO and DVO+VGA, which should
match what the old boolean flag allowed. We will add some more cloning
options in the future.

Note that this patch also removes the encoder.possible_clones setting
from encoder setup code - we compute this dynamically.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
[danvet: Add Ville's explanation why removing the encoder
possible_clones is save.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c

index 4ef6d69c078d38a059957fe8a61b7a0309122b98..32b7d49306f8c74e0944f9c3d1b74a4699faffeb 100644 (file)
@@ -839,7 +839,7 @@ void intel_crt_init(struct drm_device *dev)
        intel_connector_attach_encoder(intel_connector, &crt->base);
 
        crt->base.type = INTEL_OUTPUT_ANALOG;
-       crt->base.cloneable = true;
+       crt->base.cloneable = 1 << INTEL_OUTPUT_DVO;
        if (IS_I830(dev))
                crt->base.crtc_mask = (1 << 0);
        else
index e2665e09d5dff3a3ab5699505644dbf3ae5bc099..3565d61531f0281cf4e32a0f5e02a90b07e6f13a 100644 (file)
@@ -1717,7 +1717,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
 
        intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
        intel_encoder->crtc_mask =  (1 << 0) | (1 << 1) | (1 << 2);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        intel_encoder->hot_plug = intel_ddi_hot_plug;
 
        if (init_dp)
index 500435fd2aea7957b633f1998ac3b23c8e9e28a5..307ce4401faa7b89d8a523981d8e93f36e5fdd4a 100644 (file)
@@ -9221,23 +9221,47 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
 }
 
-static bool check_encoder_cloning(struct drm_crtc *crtc)
+static bool encoders_cloneable(const struct intel_encoder *a,
+                              const struct intel_encoder *b)
 {
-       int num_encoders = 0;
-       bool uncloneable_encoders = false;
+       /* masks could be asymmetric, so check both ways */
+       return a == b || (a->cloneable & (1 << b->type) &&
+                         b->cloneable & (1 << a->type));
+}
+
+static bool check_single_encoder_cloning(struct intel_crtc *crtc,
+                                        struct intel_encoder *encoder)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_encoder *source_encoder;
+
+       list_for_each_entry(source_encoder,
+                           &dev->mode_config.encoder_list, base.head) {
+               if (source_encoder->new_crtc != crtc)
+                       continue;
+
+               if (!encoders_cloneable(encoder, source_encoder))
+                       return false;
+       }
+
+       return true;
+}
+
+static bool check_encoder_cloning(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
        struct intel_encoder *encoder;
 
-       list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list,
-                           base.head) {
-               if (&encoder->new_crtc->base != crtc)
+       list_for_each_entry(encoder,
+                           &dev->mode_config.encoder_list, base.head) {
+               if (encoder->new_crtc != crtc)
                        continue;
 
-               num_encoders++;
-               if (!encoder->cloneable)
-                       uncloneable_encoders = true;
+               if (!check_single_encoder_cloning(crtc, encoder))
+                       return false;
        }
 
-       return !(num_encoders > 1 && uncloneable_encoders);
+       return true;
 }
 
 static struct intel_crtc_config *
@@ -9251,7 +9275,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
        int plane_bpp, ret = -EINVAL;
        bool retry = true;
 
-       if (!check_encoder_cloning(crtc)) {
+       if (!check_encoder_cloning(to_intel_crtc(crtc))) {
                DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
                return ERR_PTR(-EINVAL);
        }
@@ -10614,12 +10638,7 @@ static int intel_encoder_clones(struct intel_encoder *encoder)
 
        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)
+               if (encoders_cloneable(encoder, source_encoder))
                        index_mask |= (1 << entry);
 
                entry++;
index 7584348b7e8982b639d20f82c121e21e3c0b1e20..ee96bf8c91306134f722a922d4a030fb86ad0d27 100644 (file)
@@ -3980,7 +3980,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 
        intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        intel_encoder->hot_plug = intel_dp_hot_plug;
 
        if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
index 5360d1628263e62de84f1fcef12f443735c075e8..2546cae0b4f03dc7dfae4e5a0d5d19f92dd8b6b9 100644 (file)
@@ -125,11 +125,7 @@ struct intel_encoder {
        struct intel_crtc *new_crtc;
 
        int type;
-       /*
-        * Intel hw has only one MUX where encoders could be clone, hence a
-        * simple flag is enough to compute the possible_clones mask.
-        */
-       bool cloneable;
+       unsigned int cloneable;
        bool connectors_active;
        void (*hot_plug)(struct intel_encoder *);
        bool (*compute_config)(struct intel_encoder *,
index cf7322e95278a383967ef8348716ea1f2a4739a5..33656647f8bcf566ea8fba54f898ec6fc71b2b5b 100644 (file)
@@ -620,7 +620,7 @@ bool intel_dsi_init(struct drm_device *dev)
        intel_encoder->type = INTEL_OUTPUT_DSI;
        intel_encoder->crtc_mask = (1 << 0); /* XXX */
 
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
                           DRM_MODE_CONNECTOR_DSI);
 
index 86eeb8b7d435835e722afe86867c8a80890cad9e..7fe3feedfe039cda453851f1338fd56b100945cb 100644 (file)
@@ -522,14 +522,15 @@ void intel_dvo_init(struct drm_device *dev)
                intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
                switch (dvo->type) {
                case INTEL_DVO_CHIP_TMDS:
-                       intel_encoder->cloneable = true;
+                       intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
+                               (1 << INTEL_OUTPUT_DVO);
                        drm_connector_init(dev, connector,
                                           &intel_dvo_connector_funcs,
                                           DRM_MODE_CONNECTOR_DVII);
                        encoder_type = DRM_MODE_ENCODER_TMDS;
                        break;
                case INTEL_DVO_CHIP_LVDS:
-                       intel_encoder->cloneable = false;
+                       intel_encoder->cloneable = 0;
                        drm_connector_init(dev, connector,
                                           &intel_dvo_connector_funcs,
                                           DRM_MODE_CONNECTOR_LVDS);
index f410cc03e08a03ff6cbba25c42865a4ccc1ce5fc..4575a91d035b8458a2fa8774a27ef01d3054f353 100644 (file)
@@ -1318,7 +1318,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
 
        intel_encoder->type = INTEL_OUTPUT_HDMI;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
 
        intel_dig_port->port = port;
        intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
index fecff3c2b9e18aecc13435262def62312cb60037..ef5e5661efb21f3ade3da94e52ac47f1c86af5fc 100644 (file)
@@ -963,7 +963,7 @@ void intel_lvds_init(struct drm_device *dev)
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_LVDS;
 
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        if (HAS_PCH_SPLIT(dev))
                intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        else if (IS_GEN4(dev))
index 825853d82a4d5e579f729cbe3a069e9c7b7618c3..9a0b71f6aed6e9f32bfcf8881392dc360e3726eb 100644 (file)
@@ -3032,7 +3032,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
         * simplistic anyway to express such constraints, so just give up on
         * cloning for SDVO encoders.
         */
-       intel_sdvo->base.cloneable = false;
+       intel_sdvo->base.cloneable = 0;
 
        intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
 
index b64fc1c6ff3f65287258e883ff8a420f931cd9f4..5be4ab218054dedc2af9d5367ca829dda568da5d 100644 (file)
@@ -1639,9 +1639,8 @@ intel_tv_init(struct drm_device *dev)
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_TVOUT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
-       intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
        intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
 
        /* BIOS margin values */