drm/i915/skl: Program the DDB allocation
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_dp.c
index cad4e112cfaa4948f1e19b38ca274c32b2874eb0..5f2c206aef130bfb681879c07d5d26534197f8d8 100644 (file)
@@ -114,6 +114,8 @@ static void intel_dp_link_down(struct intel_dp *intel_dp);
 static bool edp_panel_vdd_on(struct intel_dp *intel_dp);
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp);
+static void vlv_steal_power_sequencer(struct drm_device *dev,
+                                     enum pipe pipe);
 
 int
 intel_dp_max_link_bw(struct intel_dp *intel_dp)
@@ -321,6 +323,66 @@ static void pps_unlock(struct intel_dp *intel_dp)
        intel_display_power_put(dev_priv, power_domain);
 }
 
+static void
+vlv_power_sequencer_kick(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_dp->pps_pipe;
+       bool pll_enabled;
+       uint32_t DP;
+
+       if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
+                "skipping pipe %c power seqeuncer kick due to port %c being active\n",
+                pipe_name(pipe), port_name(intel_dig_port->port)))
+               return;
+
+       DRM_DEBUG_KMS("kicking pipe %c power sequencer for port %c\n",
+                     pipe_name(pipe), port_name(intel_dig_port->port));
+
+       /* Preserve the BIOS-computed detected bit. This is
+        * supposed to be read-only.
+        */
+       DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
+       DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
+       DP |= DP_PORT_WIDTH(1);
+       DP |= DP_LINK_TRAIN_PAT_1;
+
+       if (IS_CHERRYVIEW(dev))
+               DP |= DP_PIPE_SELECT_CHV(pipe);
+       else if (pipe == PIPE_B)
+               DP |= DP_PIPEB_SELECT;
+
+       pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE;
+
+       /*
+        * The DPLL for the pipe must be enabled for this to work.
+        * So enable temporarily it if it's not already enabled.
+        */
+       if (!pll_enabled)
+               vlv_force_pll_on(dev, pipe, IS_CHERRYVIEW(dev) ?
+                                &chv_dpll[0].dpll : &vlv_dpll[0].dpll);
+
+       /*
+        * Similar magic as in intel_dp_enable_port().
+        * We _must_ do this port enable + disable trick
+        * to make this power seqeuencer lock onto the port.
+        * Otherwise even VDD force bit won't work.
+        */
+       I915_WRITE(intel_dp->output_reg, DP);
+       POSTING_READ(intel_dp->output_reg);
+
+       I915_WRITE(intel_dp->output_reg, DP | DP_PORT_EN);
+       POSTING_READ(intel_dp->output_reg);
+
+       I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
+       POSTING_READ(intel_dp->output_reg);
+
+       if (!pll_enabled)
+               vlv_force_pll_off(dev, pipe);
+}
+
 static enum pipe
 vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
 {
@@ -329,9 +391,13 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *encoder;
        unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
+       enum pipe pipe;
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
+       /* We should never land here with regular DP ports */
+       WARN_ON(!is_edp(intel_dp));
+
        if (intel_dp->pps_pipe != INVALID_PIPE)
                return intel_dp->pps_pipe;
 
@@ -357,9 +423,12 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
         * are two power sequencers and up to two eDP ports.
         */
        if (WARN_ON(pipes == 0))
-               return PIPE_A;
+               pipe = PIPE_A;
+       else
+               pipe = ffs(pipes) - 1;
 
-       intel_dp->pps_pipe = ffs(pipes) - 1;
+       vlv_steal_power_sequencer(dev, pipe);
+       intel_dp->pps_pipe = pipe;
 
        DRM_DEBUG_KMS("picked pipe %c power sequencer for port %c\n",
                      pipe_name(intel_dp->pps_pipe),
@@ -369,6 +438,12 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
        intel_dp_init_panel_power_sequencer(dev, intel_dp);
        intel_dp_init_panel_power_sequencer_registers(dev, intel_dp);
 
+       /*
+        * Even vdd force doesn't work until we've made
+        * the power sequencer lock in on the port.
+        */
+       vlv_power_sequencer_kick(intel_dp);
+
        return intel_dp->pps_pipe;
 }
 
@@ -545,6 +620,10 @@ static bool edp_have_panel_power(struct intel_dp *intel_dp)
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
+       if (IS_VALLEYVIEW(dev) &&
+           intel_dp->pps_pipe == INVALID_PIPE)
+               return false;
+
        return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
 }
 
@@ -555,6 +634,10 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
+       if (IS_VALLEYVIEW(dev) &&
+           intel_dp->pps_pipe == INVALID_PIPE)
+               return false;
+
        return I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD;
 }
 
@@ -1245,7 +1328,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
                DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
                                 pipe_name(crtc->pipe));
                intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
-               intel_write_eld(encoder);
+               intel_audio_codec_enable(encoder);
        }
 
        /* Split out the IBX/CPU vs CPT settings */
@@ -1404,7 +1487,8 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
        power_domain = intel_display_port_power_domain(intel_encoder);
        intel_display_power_get(dev_priv, power_domain);
 
-       DRM_DEBUG_KMS("Turning eDP VDD on\n");
+       DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
+                     port_name(intel_dig_port->port));
 
        if (!edp_have_panel_power(intel_dp))
                wait_panel_power_cycle(intel_dp);
@@ -1423,7 +1507,8 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
         * If the panel wasn't on, delay before accessing aux channel
         */
        if (!edp_have_panel_power(intel_dp)) {
-               DRM_DEBUG_KMS("eDP was not running\n");
+               DRM_DEBUG_KMS("eDP port %c panel power wasn't enabled\n",
+                             port_name(intel_dig_port->port));
                msleep(intel_dp->panel_power_up_delay);
        }
 
@@ -1448,7 +1533,8 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
        vdd = edp_panel_vdd_on(intel_dp);
        pps_unlock(intel_dp);
 
-       WARN(!vdd, "eDP VDD already requested on\n");
+       WARN(!vdd, "eDP port %c VDD already requested on\n",
+            port_name(dp_to_dig_port(intel_dp)->port));
 }
 
 static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
@@ -1469,7 +1555,8 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
        if (!edp_have_panel_vdd(intel_dp))
                return;
 
-       DRM_DEBUG_KMS("Turning eDP VDD off\n");
+       DRM_DEBUG_KMS("Turning eDP port %c VDD off\n",
+                     port_name(intel_dig_port->port));
 
        pp = ironlake_get_pp_control(intel_dp);
        pp &= ~EDP_FORCE_VDD;
@@ -1530,7 +1617,8 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
        if (!is_edp(intel_dp))
                return;
 
-       WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on");
+       WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
+            port_name(dp_to_dig_port(intel_dp)->port));
 
        intel_dp->want_panel_vdd = false;
 
@@ -1552,12 +1640,13 @@ static void edp_panel_on(struct intel_dp *intel_dp)
        if (!is_edp(intel_dp))
                return;
 
-       DRM_DEBUG_KMS("Turn eDP power on\n");
+       DRM_DEBUG_KMS("Turn eDP port %c panel power on\n",
+                     port_name(dp_to_dig_port(intel_dp)->port));
 
-       if (edp_have_panel_power(intel_dp)) {
-               DRM_DEBUG_KMS("eDP power already on\n");
+       if (WARN(edp_have_panel_power(intel_dp),
+                "eDP port %c panel power already on\n",
+                port_name(dp_to_dig_port(intel_dp)->port)))
                return;
-       }
 
        wait_panel_power_cycle(intel_dp);
 
@@ -1613,9 +1702,11 @@ static void edp_panel_off(struct intel_dp *intel_dp)
        if (!is_edp(intel_dp))
                return;
 
-       DRM_DEBUG_KMS("Turn eDP power off\n");
+       DRM_DEBUG_KMS("Turn eDP port %c panel power off\n",
+                     port_name(dp_to_dig_port(intel_dp)->port));
 
-       WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
+       WARN(!intel_dp->want_panel_vdd, "Need eDP port %c VDD to turn off panel\n",
+            port_name(dp_to_dig_port(intel_dp)->port));
 
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
@@ -2517,14 +2608,23 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp)
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       intel_dp->DP |= DP_PORT_EN;
-
        /* enable with pattern 1 (as per spec) */
        _intel_dp_set_link_train(intel_dp, &intel_dp->DP,
                                 DP_TRAINING_PATTERN_1);
 
        I915_WRITE(intel_dp->output_reg, intel_dp->DP);
        POSTING_READ(intel_dp->output_reg);
+
+       /*
+        * Magic for VLV/CHV. We _must_ first set up the register
+        * without actually enabling the port, and then do another
+        * write to enable the port. Otherwise link training will
+        * fail when the power sequencer is freshly used for this port.
+        */
+       intel_dp->DP |= DP_PORT_EN;
+
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
 }
 
 static void intel_enable_dp(struct intel_encoder *encoder)
@@ -2550,6 +2650,9 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 
        pps_unlock(intel_dp);
 
+       if (IS_VALLEYVIEW(dev))
+               vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp));
+
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
        intel_dp_complete_link_train(intel_dp);
@@ -2585,6 +2688,32 @@ static void g4x_pre_enable_dp(struct intel_encoder *encoder)
        }
 }
 
+static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_i915_private *dev_priv = intel_dig_port->base.base.dev->dev_private;
+       enum pipe pipe = intel_dp->pps_pipe;
+       int pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
+
+       edp_panel_vdd_off_sync(intel_dp);
+
+       /*
+        * VLV seems to get confused when multiple power seqeuencers
+        * have the same port selected (even if only one has power/vdd
+        * enabled). The failure manifests as vlv_wait_port_ready() failing
+        * CHV on the other hand doesn't seem to mind having the same port
+        * selected in multiple power seqeuencers, but let's clear the
+        * port select always when logically disconnecting a power sequencer
+        * from a port.
+        */
+       DRM_DEBUG_KMS("detaching pipe %c power sequencer from port %c\n",
+                     pipe_name(pipe), port_name(intel_dig_port->port));
+       I915_WRITE(pp_on_reg, 0);
+       POSTING_READ(pp_on_reg);
+
+       intel_dp->pps_pipe = INVALID_PIPE;
+}
+
 static void vlv_steal_power_sequencer(struct drm_device *dev,
                                      enum pipe pipe)
 {
@@ -2593,6 +2722,9 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
+       if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
+               return;
+
        list_for_each_entry(encoder, &dev->mode_config.encoder_list,
                            base.head) {
                struct intel_dp *intel_dp;
@@ -2610,10 +2742,12 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
                DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
                              pipe_name(pipe), port_name(port));
 
-               /* make sure vdd is off before we steal it */
-               edp_panel_vdd_off_sync(intel_dp);
+               WARN(encoder->connectors_active,
+                    "stealing pipe %c power sequencer from active eDP port %c\n",
+                    pipe_name(pipe), port_name(port));
 
-               intel_dp->pps_pipe = INVALID_PIPE;
+               /* make sure vdd is off before we steal it */
+               vlv_detach_power_sequencer(intel_dp);
        }
 }
 
@@ -2639,7 +2773,7 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
         * we still have control of it.
         */
        if (intel_dp->pps_pipe != INVALID_PIPE)
-               edp_panel_vdd_off_sync(intel_dp);
+               vlv_detach_power_sequencer(intel_dp);
 
        /*
         * We may be stealing the power
@@ -2685,8 +2819,6 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 
        intel_enable_dp(encoder);
-
-       vlv_wait_port_ready(dev_priv, dport);
 }
 
 static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
@@ -2779,8 +2911,6 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
        mutex_unlock(&dev_priv->dpio_lock);
 
        intel_enable_dp(encoder);
-
-       vlv_wait_port_ready(dev_priv, dport);
 }
 
 static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
@@ -3682,7 +3812,6 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
 
                /* Try 5 times, then try clock recovery if that fails */
                if (tries > 5) {
-                       intel_dp_link_down(intel_dp);
                        intel_dp_start_link_train(intel_dp);
                        intel_dp_set_link_train(intel_dp, &DP,
                                                training_pattern |
@@ -4547,9 +4676,52 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
        pps_unlock(intel_dp);
 }
 
+static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
+
+       lockdep_assert_held(&dev_priv->pps_mutex);
+
+       if (!edp_have_panel_vdd(intel_dp))
+               return;
+
+       /*
+        * The VDD bit needs a power domain reference, so if the bit is
+        * already enabled when we boot or resume, grab this reference and
+        * schedule a vdd off, so we don't hold on to the reference
+        * indefinitely.
+        */
+       DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
+       power_domain = intel_display_port_power_domain(&intel_dig_port->base);
+       intel_display_power_get(dev_priv, power_domain);
+
+       edp_panel_vdd_schedule_off(intel_dp);
+}
+
 static void intel_dp_encoder_reset(struct drm_encoder *encoder)
 {
-       intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder));
+       struct intel_dp *intel_dp;
+
+       if (to_intel_encoder(encoder)->type != INTEL_OUTPUT_EDP)
+               return;
+
+       intel_dp = enc_to_intel_dp(encoder);
+
+       pps_lock(intel_dp);
+
+       /*
+        * Read out the current power sequencer assignment,
+        * in case the BIOS did something with it.
+        */
+       if (IS_VALLEYVIEW(encoder->dev))
+               vlv_initial_power_sequencer_setup(intel_dp);
+
+       intel_edp_panel_vdd_sanitize(intel_dp);
+
+       pps_unlock(intel_dp);
 }
 
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
@@ -5020,37 +5192,6 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
        return downclock_mode;
 }
 
-void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder)
-{
-       struct drm_device *dev = intel_encoder->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_dp *intel_dp;
-       enum intel_display_power_domain power_domain;
-
-       if (intel_encoder->type != INTEL_OUTPUT_EDP)
-               return;
-
-       intel_dp = enc_to_intel_dp(&intel_encoder->base);
-
-       pps_lock(intel_dp);
-
-       if (!edp_have_panel_vdd(intel_dp))
-               goto out;
-       /*
-        * The VDD bit needs a power domain reference, so if the bit is
-        * already enabled when we boot or resume, grab this reference and
-        * schedule a vdd off, so we don't hold on to the reference
-        * indefinitely.
-        */
-       DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
-       power_domain = intel_display_port_power_domain(intel_encoder);
-       intel_display_power_get(dev_priv, power_domain);
-
-       edp_panel_vdd_schedule_off(intel_dp);
- out:
-       pps_unlock(intel_dp);
-}
-
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                                     struct intel_connector *intel_connector)
 {
@@ -5070,7 +5211,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        if (!is_edp(intel_dp))
                return true;
 
-       intel_edp_panel_vdd_sanitize(intel_encoder);
+       pps_lock(intel_dp);
+       intel_edp_panel_vdd_sanitize(intel_dp);
+       pps_unlock(intel_dp);
 
        /* Cache DPCD and EDID for edp. */
        has_dpcd = intel_dp_get_dpcd(intel_dp);
@@ -5234,12 +5377,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 
        if (is_edp(intel_dp)) {
                pps_lock(intel_dp);
-               if (IS_VALLEYVIEW(dev)) {
+               intel_dp_init_panel_power_timestamps(intel_dp);
+               if (IS_VALLEYVIEW(dev))
                        vlv_initial_power_sequencer_setup(intel_dp);
-               } else {
-                       intel_dp_init_panel_power_timestamps(intel_dp);
+               else
                        intel_dp_init_panel_power_sequencer(dev, intel_dp);
-               }
                pps_unlock(intel_dp);
        }
 
This page took 0.125387 seconds and 5 git commands to generate.