From: Ville Syrjälä <ville.syrj...@linux.intel.com>

Eliminate the troublesome role switching DDI encoder, and just register
a separate encoder for each role (DP and HDMI).

Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c      | 232 +++++++++++++++++++++++++---------
 drivers/gpu/drm/i915/intel_display.c  |  18 ---
 drivers/gpu/drm/i915/intel_dp.c       |  23 +---
 drivers/gpu/drm/i915/intel_drv.h      |   3 +-
 drivers/gpu/drm/i915/intel_hdmi.c     |   3 +
 drivers/gpu/drm/i915/intel_opregion.c |   1 -
 6 files changed, 180 insertions(+), 100 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 074121efb265..5f008f0fdc13 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -318,7 +318,6 @@ static void ddi_get_encoder_port(struct intel_encoder 
*intel_encoder,
        case INTEL_OUTPUT_DISPLAYPORT:
        case INTEL_OUTPUT_EDP:
        case INTEL_OUTPUT_HDMI:
-       case INTEL_OUTPUT_UNKNOWN:
                *dig_port = enc_to_dig_port(encoder);
                *port = (*dig_port)->port;
                break;
@@ -1942,19 +1941,19 @@ bool intel_ddi_connector_get_hw_state(struct 
intel_connector *intel_connector)
        switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
        case TRANS_DDI_MODE_SELECT_HDMI:
        case TRANS_DDI_MODE_SELECT_DVI:
-               return (type == DRM_MODE_CONNECTOR_HDMIA);
+               return type == DRM_MODE_CONNECTOR_HDMIA;
 
        case TRANS_DDI_MODE_SELECT_DP_SST:
-               if (type == DRM_MODE_CONNECTOR_eDP)
-                       return true;
-               return (type == DRM_MODE_CONNECTOR_DisplayPort);
+               return type == DRM_MODE_CONNECTOR_DisplayPort ||
+                       type == DRM_MODE_CONNECTOR_eDP;
+
        case TRANS_DDI_MODE_SELECT_DP_MST:
                /* if the transcoder is in MST state then
                 * connector isn't connected */
                return false;
 
        case TRANS_DDI_MODE_SELECT_FDI:
-               return (type == DRM_MODE_CONNECTOR_VGA);
+               return type == DRM_MODE_CONNECTOR_VGA;
 
        default:
                return false;
@@ -1981,8 +1980,23 @@ bool intel_ddi_get_hw_state(struct intel_encoder 
*encoder,
                return false;
 
        if (port == PORT_A) {
+               WARN_ON(encoder->type != INTEL_OUTPUT_EDP);
+
                tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
 
+               if ((tmp & TRANS_DDI_FUNC_ENABLE) == 0)
+                       goto out;
+
+               switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
+               case TRANS_DDI_MODE_SELECT_DP_SST:
+                       break;
+               default:
+                       WARN(1,
+                            "Bad transcoder EDP DDI mode 0x%08x for port %c\n",
+                            tmp, port_name(port));
+                       return false;
+               }
+
                switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
                case TRANS_DDI_EDP_INPUT_A_ON:
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
@@ -1994,25 +2008,98 @@ bool intel_ddi_get_hw_state(struct intel_encoder 
*encoder,
                case TRANS_DDI_EDP_INPUT_C_ONOFF:
                        *pipe = PIPE_C;
                        break;
+               default:
+                       WARN(1,
+                            "Bad transcoder EDP input select 0x%08x for port 
%c\n",
+                            tmp, port_name(port));
+                       return false;
                }
 
                return true;
        } else {
+               int num_mst_transcoders = 0;
+               int num_sst_transcoders = 0;
+               int num_fdi_transcoders = 0;
+               int num_hdmi_transcoders = 0;
+               int num_transcoders = 0;
+               bool enabled = false;
+
                for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
                        tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));
 
-                       if ((tmp & TRANS_DDI_PORT_MASK)
-                           == TRANS_DDI_SELECT_PORT(port)) {
-                               if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == 
TRANS_DDI_MODE_SELECT_DP_MST)
-                                       return false;
+                       if ((tmp & TRANS_DDI_FUNC_ENABLE) == 0)
+                               continue;
+
+                       if ((tmp & TRANS_DDI_PORT_MASK) != 
TRANS_DDI_SELECT_PORT(port))
+                               continue;
+
+                       if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == 
TRANS_DDI_MODE_SELECT_DP_MST) {
+                               num_mst_transcoders++;
+                               WARN_ON(port == PORT_E);
+                               continue;
+                       }
+
+
+                       switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
+                       case TRANS_DDI_MODE_SELECT_DP_SST:
+                               WARN_ON(port == PORT_E && 
INTEL_INFO(dev_priv)->gen < 9);
+
+                               num_sst_transcoders++;
+                               if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+                                   encoder->type == INTEL_OUTPUT_EDP) {
+                                       enabled = true;
+                                       *pipe = i;
+                               }
+                               break;
+                       case TRANS_DDI_MODE_SELECT_HDMI:
+                       case TRANS_DDI_MODE_SELECT_DVI:
+                               WARN_ON(port == PORT_E);
+
+                               num_hdmi_transcoders++;
+                               if (encoder->type == INTEL_OUTPUT_HDMI) {
+                                       enabled = true;
+                                       *pipe = i;
+                               }
+                               break;
+
+                       case TRANS_DDI_MODE_SELECT_FDI:
+                               WARN_ON(port != PORT_E || 
INTEL_INFO(dev_priv)->gen >= 9);
+
+                               num_fdi_transcoders++;
+                               if (encoder->type == INTEL_OUTPUT_ANALOG) {
+                                       enabled = true;
+                                       *pipe = i;
+                               }
+                               break;
 
-                               *pipe = i;
-                               return true;
+                       default:
+                               WARN(1, "Bad transcoder %c DDI mode 0x%08x for 
port %c\n",
+                                    transcoder_name(i), tmp, port_name(port));
+                               return false;
                        }
                }
+
+               num_transcoders = num_sst_transcoders +
+                       num_fdi_transcoders + num_hdmi_transcoders;
+
+               if (WARN(num_transcoders && num_mst_transcoders,
+                        "MST and non-MST transcoders enabled for port %c (%d 
sst, %d mst, %d fdi, %d hdmi)\n",
+                        port_name(port), num_sst_transcoders, 
num_mst_transcoders,
+                        num_fdi_transcoders, num_hdmi_transcoders))
+                       return false;
+
+               if (WARN(num_transcoders > 1,
+                        "Multiple transcoders enabled for port %c (%d sst, %d 
mst, %d fdi, %d hdmi)\n",
+                        port_name(port), num_sst_transcoders, 
num_mst_transcoders,
+                        num_fdi_transcoders, num_hdmi_transcoders))
+                       return false;
+
+               if (enabled)
+                       return true;
        }
 
-       DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
+out:
+       DRM_DEBUG_KMS("No pipe for DDI port %c found\n", port_name(port));
 
        return false;
 }
@@ -3174,8 +3261,6 @@ static bool intel_ddi_compute_config(struct intel_encoder 
*encoder,
        int type = encoder->type;
        int port = intel_ddi_get_encoder_port(encoder);
 
-       WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown 
output!\n");
-
        if (port == PORT_A)
                pipe_config->cpu_transcoder = TRANSCODER_EDP;
 
@@ -3224,53 +3309,18 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port 
*intel_dig_port)
        return connector;
 }
 
-void intel_ddi_init(struct drm_device *dev, enum port port)
+static int intel_ddi_init_role(struct drm_device *dev, enum port port,
+                              int encoder_type, uint32_t saved_port_bits,
+                              int max_lanes)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_digital_port *intel_dig_port;
        struct intel_encoder *intel_encoder;
        struct drm_encoder *encoder;
-       bool init_hdmi, init_dp;
-       int max_lanes;
-
-       if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES) {
-               switch (port) {
-               case PORT_A:
-                       max_lanes = 4;
-                       break;
-               case PORT_E:
-                       max_lanes = 0;
-                       break;
-               default:
-                       max_lanes = 4;
-                       break;
-               }
-       } else {
-               switch (port) {
-               case PORT_A:
-                       max_lanes = 2;
-                       break;
-               case PORT_E:
-                       max_lanes = 2;
-                       break;
-               default:
-                       max_lanes = 4;
-                       break;
-               }
-       }
-
-       init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi ||
-                    dev_priv->vbt.ddi_port_info[port].supports_hdmi);
-       init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp;
-       if (!init_dp && !init_hdmi) {
-               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, 
respect it\n",
-                             port_name(port));
-               return;
-       }
 
        intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
        if (!intel_dig_port)
-               return;
+               return -ENOMEM;
 
        intel_encoder = &intel_dig_port->base;
        encoder = &intel_encoder->base;
@@ -3287,9 +3337,7 @@ void intel_ddi_init(struct drm_device *dev, enum port 
port)
        intel_encoder->get_config = intel_ddi_get_config;
 
        intel_dig_port->port = port;
-       intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
-                                         (DDI_BUF_PORT_REVERSAL |
-                                          DDI_A_4_LANES);
+       intel_dig_port->saved_port_bits = saved_port_bits;
        intel_dig_port->max_lanes = max_lanes;
 
        /*
@@ -3306,11 +3354,11 @@ void intel_ddi_init(struct drm_device *dev, enum port 
port)
                }
        }
 
-       intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
+       intel_encoder->type = encoder_type;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        intel_encoder->cloneable = 0;
 
-       if (init_dp) {
+       if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
                if (!intel_ddi_init_dp_connector(intel_dig_port))
                        goto err;
 
@@ -3327,14 +3375,74 @@ void intel_ddi_init(struct drm_device *dev, enum port 
port)
 
        /* In theory we don't need the encoder->type check, but leave it just in
         * case we have some really bad VBTs... */
-       if (intel_encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
+       if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
                if (!intel_ddi_init_hdmi_connector(intel_dig_port))
                        goto err;
        }
 
-       return;
+       return intel_encoder->type;
 
 err:
        drm_encoder_cleanup(encoder);
        kfree(intel_dig_port);
+
+       return -ENODEV;
+}
+
+void intel_ddi_init(struct drm_device *dev, enum port port)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       uint32_t saved_port_bits;
+       bool init_hdmi, init_dp;
+       int max_lanes;
+
+       if (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES) {
+               switch (port) {
+               case PORT_A:
+                       max_lanes = 4;
+                       break;
+               case PORT_E:
+                       max_lanes = 0;
+                       break;
+               default:
+                       max_lanes = 4;
+                       break;
+               }
+       } else {
+               switch (port) {
+               case PORT_A:
+                       max_lanes = 2;
+                       break;
+               case PORT_E:
+                       max_lanes = 2;
+                       break;
+               default:
+                       max_lanes = 4;
+                       break;
+               }
+       }
+
+       init_hdmi = (dev_priv->vbt.ddi_port_info[port].supports_dvi ||
+                    dev_priv->vbt.ddi_port_info[port].supports_hdmi);
+       init_dp = dev_priv->vbt.ddi_port_info[port].supports_dp;
+       if (!init_dp && !init_hdmi) {
+               DRM_DEBUG_KMS("VBT says port %c is not DVI/HDMI/DP compatible, 
respect it\n",
+                             port_name(port));
+               return;
+       }
+
+       saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
+               (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES);
+
+       if (init_dp) {
+               int ret = intel_ddi_init_role(dev, port, 
INTEL_OUTPUT_DISPLAYPORT,
+                                             saved_port_bits, max_lanes);
+               /* Don't register the HDMI connector/encoder when we have eDP */
+               if (ret == INTEL_OUTPUT_EDP)
+                       init_hdmi = false;
+       }
+
+       if (init_hdmi)
+               intel_ddi_init_role(dev, port, INTEL_OUTPUT_HDMI,
+                                   saved_port_bits, max_lanes);
 }
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index bc7aaa3c431e..fc1d7387eb12 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5252,13 +5252,9 @@ static enum intel_display_power_domain 
port_to_aux_power_domain(enum port port)
 enum intel_display_power_domain
 intel_display_port_power_domain(struct intel_encoder *intel_encoder)
 {
-       struct drm_device *dev = intel_encoder->base.dev;
        struct intel_digital_port *intel_dig_port;
 
        switch (intel_encoder->type) {
-       case INTEL_OUTPUT_UNKNOWN:
-               /* Only DDI platforms should ever use this output type */
-               WARN_ON_ONCE(!HAS_DDI(dev));
        case INTEL_OUTPUT_DISPLAYPORT:
        case INTEL_OUTPUT_HDMI:
        case INTEL_OUTPUT_EDP:
@@ -5279,20 +5275,9 @@ intel_display_port_power_domain(struct intel_encoder 
*intel_encoder)
 enum intel_display_power_domain
 intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder)
 {
-       struct drm_device *dev = intel_encoder->base.dev;
        struct intel_digital_port *intel_dig_port;
 
        switch (intel_encoder->type) {
-       case INTEL_OUTPUT_UNKNOWN:
-       case INTEL_OUTPUT_HDMI:
-               /*
-                * Only DDI platforms should ever use these output types.
-                * We can get here after the HDMI detect code has already set
-                * the type of the shared encoder. Since we can't be sure
-                * what's the status of the given connectors, play safe and
-                * run the DP detection too.
-                */
-               WARN_ON_ONCE(!HAS_DDI(dev));
        case INTEL_OUTPUT_DISPLAYPORT:
        case INTEL_OUTPUT_EDP:
                intel_dig_port = enc_to_dig_port(&intel_encoder->base);
@@ -12283,9 +12268,6 @@ static bool check_digital_port_conflicts(struct 
drm_atomic_state *state)
 
                switch (encoder->type) {
                        unsigned int port_mask;
-               case INTEL_OUTPUT_UNKNOWN:
-                       if (WARN_ON(!HAS_DDI(dev)))
-                               break;
                case INTEL_OUTPUT_DISPLAYPORT:
                case INTEL_OUTPUT_HDMI:
                case INTEL_OUTPUT_EDP:
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 7d354b1e5e5f..1d31aa296aaa 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -4601,8 +4601,6 @@ intel_dp_detect(struct drm_connector *connector, bool 
force)
 
        if (intel_dp->is_mst) {
                /* MST devices are disconnected from a monitor POV */
-               if (intel_encoder->type != INTEL_OUTPUT_EDP)
-                       intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
                return connector_status_disconnected;
        }
 
@@ -4632,8 +4630,6 @@ intel_dp_detect(struct drm_connector *connector, bool 
force)
        if (ret) {
                /* if we are in MST mode then this connector
                   won't appear connected or have anything with EDID on it */
-               if (intel_encoder->type != INTEL_OUTPUT_EDP)
-                       intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
                status = connector_status_disconnected;
                goto out;
        }
@@ -4648,8 +4644,6 @@ intel_dp_detect(struct drm_connector *connector, bool 
force)
 
        intel_dp_set_edid(intel_dp);
 
-       if (intel_encoder->type != INTEL_OUTPUT_EDP)
-               intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
        status = connector_status_connected;
 
        /* Try to read the source of the interrupt */
@@ -4692,9 +4686,6 @@ intel_dp_force(struct drm_connector *connector)
        intel_dp_set_edid(intel_dp);
 
        intel_display_power_put(dev_priv, power_domain);
-
-       if (intel_encoder->type != INTEL_OUTPUT_EDP)
-               intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
@@ -4969,9 +4960,9 @@ intel_dp_hpd_pulse(struct intel_digital_port 
*intel_dig_port, bool long_hpd)
        enum intel_display_power_domain power_domain;
        enum irqreturn ret = IRQ_NONE;
 
-       if (intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
-           intel_dig_port->base.type != INTEL_OUTPUT_HDMI)
-               intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
+       if (WARN_ON_ONCE(intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
+                        intel_dig_port->base.type != INTEL_OUTPUT_DISPLAYPORT))
+               return IRQ_HANDLED;
 
        if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
                /*
@@ -5815,6 +5806,9 @@ intel_dp_init_connector(struct intel_digital_port 
*intel_dig_port,
        enum port port = intel_dig_port->port;
        int type, ret;
 
+       if (WARN_ON(intel_encoder->type != INTEL_OUTPUT_DISPLAYPORT))
+               return false;
+
        if (WARN(intel_dig_port->max_lanes < 1,
                 "Not enough lanes (%d) for DP on port %c\n",
                 intel_dig_port->max_lanes, port_name(port)))
@@ -5851,11 +5845,6 @@ intel_dp_init_connector(struct intel_digital_port 
*intel_dig_port,
        else
                type = DRM_MODE_CONNECTOR_DisplayPort;
 
-       /*
-        * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
-        * for DP the encoder type can be set by the caller to
-        * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
-        */
        if (type == DRM_MODE_CONNECTOR_eDP)
                intel_encoder->type = INTEL_OUTPUT_EDP;
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a8a84b8c2bac..9e5db3d71e12 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -103,8 +103,7 @@ enum intel_output_type {
        INTEL_OUTPUT_DISPLAYPORT = 7,
        INTEL_OUTPUT_EDP = 8,
        INTEL_OUTPUT_DSI = 9,
-       INTEL_OUTPUT_UNKNOWN = 10,
-       INTEL_OUTPUT_DP_MST = 11,
+       INTEL_OUTPUT_DP_MST = 10,
 };
 
 #define INTEL_DVO_CHIP_NONE 0
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c 
b/drivers/gpu/drm/i915/intel_hdmi.c
index 895189abfd56..75ea9515a9ce 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -2034,6 +2034,9 @@ void intel_hdmi_init_connector(struct intel_digital_port 
*intel_dig_port,
        enum port port = intel_dig_port->port;
        uint8_t alternate_ddc_pin;
 
+       if (WARN_ON(intel_encoder->type != INTEL_OUTPUT_HDMI))
+               return;
+
        if (WARN(intel_dig_port->max_lanes < 4,
                 "Not enough lanes (%d) for HDMI on port %c\n",
                 intel_dig_port->max_lanes, port_name(port)))
diff --git a/drivers/gpu/drm/i915/intel_opregion.c 
b/drivers/gpu/drm/i915/intel_opregion.c
index e362a30776fa..a15459a451c2 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -360,7 +360,6 @@ int intel_opregion_notify_encoder(struct intel_encoder 
*intel_encoder,
        case INTEL_OUTPUT_ANALOG:
                type = DISPLAY_TYPE_CRT;
                break;
-       case INTEL_OUTPUT_UNKNOWN:
        case INTEL_OUTPUT_DISPLAYPORT:
        case INTEL_OUTPUT_HDMI:
        case INTEL_OUTPUT_DP_MST:
-- 
2.4.10

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to