drm/i915/icl: fix transcoder state readout
authorJani Nikula <jani.nikula@intel.com>
Tue, 4 Dec 2018 10:19:26 +0000 (12:19 +0200)
committerJani Nikula <jani.nikula@intel.com>
Tue, 4 Dec 2018 17:05:51 +0000 (19:05 +0200)
Commit 2ca711caeca2 ("drm/i915/icl: Consider DSI for getting transcoder
state") clobbers the previously read TRANS_DDI_FUNC_CTL_EDP register
contents with TRANS_DDI_FUNC_CTL_DSI0 contents. Fix the state readout,
and handle DSI 1 while at it.

Use a bitmask for iterating and logging transcoders, because the allowed
combinations are a bit funky.

Fixes: 2ca711caeca2 ("drm/i915/icl: Consider DSI for getting transcoder state")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=108928
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Madhav Chauhan <madhav.chauhan@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181204101926.17174-1-jani.nikula@intel.com
drivers/gpu/drm/i915/intel_display.c

index a2584f977ab1f5af1685d2f5150aa386db49d580..07c861884c7068124f3c7835a9f46ff23f0da10f 100644 (file)
@@ -9476,13 +9476,18 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        enum intel_display_power_domain power_domain;
+       unsigned long panel_transcoder_mask = BIT(TRANSCODER_EDP);
+       unsigned long enabled_panel_transcoders = 0;
+       enum transcoder panel_transcoder;
        u32 tmp;
-       bool is_dsi = false;
-       bool is_edp = false;
+
+       if (IS_ICELAKE(dev_priv))
+               panel_transcoder_mask |=
+                       BIT(TRANSCODER_DSI_0) | BIT(TRANSCODER_DSI_1);
 
        /*
         * The pipe->transcoder mapping is fixed with the exception of the eDP
-        * transcoder handled below.
+        * and DSI transcoders handled below.
         */
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
 
@@ -9490,23 +9495,26 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
         * XXX: Do intel_display_power_get_if_enabled before reading this (for
         * consistency and less surprising code; it's in always on power).
         */
-       tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
-       if (tmp & TRANS_DDI_FUNC_ENABLE)
-               is_edp = true;
+       for_each_set_bit(panel_transcoder, &panel_transcoder_mask, 32) {
+               enum pipe trans_pipe;
 
-       if (IS_ICELAKE(dev_priv)) {
-               tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_DSI_0));
-               if (tmp & TRANS_DDI_FUNC_ENABLE)
-                       is_dsi = true;
-       }
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(panel_transcoder));
+               if (!(tmp & TRANS_DDI_FUNC_ENABLE))
+                       continue;
 
-       WARN_ON(is_edp && is_dsi);
+               /*
+                * Log all enabled ones, only use the first one.
+                *
+                * FIXME: This won't work for two separate DSI displays.
+                */
+               enabled_panel_transcoders |= BIT(panel_transcoder);
+               if (enabled_panel_transcoders != BIT(panel_transcoder))
+                       continue;
 
-       if (is_edp || is_dsi) {
-               enum pipe trans_pipe;
                switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
                default:
-                       WARN(1, "unknown pipe linked to edp transcoder\n");
+                       WARN(1, "unknown pipe linked to transcoder %s\n",
+                            transcoder_name(panel_transcoder));
                        /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
                case TRANS_DDI_EDP_INPUT_A_ON:
@@ -9520,14 +9528,16 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
                        break;
                }
 
-               if (trans_pipe == crtc->pipe) {
-                       if (is_edp)
-                               pipe_config->cpu_transcoder = TRANSCODER_EDP;
-                       else if (is_dsi)
-                               pipe_config->cpu_transcoder = TRANSCODER_DSI_0;
-               }
+               if (trans_pipe == crtc->pipe)
+                       pipe_config->cpu_transcoder = panel_transcoder;
        }
 
+       /*
+        * Valid combos: none, eDP, DSI0, DSI1, DSI0+DSI1
+        */
+       WARN_ON((enabled_panel_transcoders & BIT(TRANSCODER_EDP)) &&
+               enabled_panel_transcoders != BIT(TRANSCODER_EDP));
+
        power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
        if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;