Merge tag 'drm-intel-next-2019-05-24' of git://anongit.freedesktop.org/drm/drm-intel...
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / intel_dp.c
index 560274d..24b56b2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+
 #include <asm/byteorder.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/i915_drm.h>
 
+#include "i915_debugfs.h"
 #include "i915_drv.h"
+#include "intel_atomic.h"
 #include "intel_audio.h"
 #include "intel_connector.h"
 #include "intel_ddi.h"
 #include "intel_dp.h"
+#include "intel_dp_link_training.h"
+#include "intel_dp_mst.h"
+#include "intel_dpio_phy.h"
 #include "intel_drv.h"
+#include "intel_fifo_underrun.h"
 #include "intel_hdcp.h"
 #include "intel_hdmi.h"
+#include "intel_hotplug.h"
 #include "intel_lspcon.h"
 #include "intel_lvds.h"
 #include "intel_panel.h"
 #include "intel_psr.h"
+#include "intel_sideband.h"
+#include "intel_vdsc.h"
 
 #define DP_DPRX_ESI_LEN 14
 
@@ -206,14 +216,17 @@ static int intel_dp_get_fia_supported_lane_count(struct intel_dp *intel_dp)
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
        enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port);
+       intel_wakeref_t wakeref;
        u32 lane_info;
 
        if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC)
                return 4;
 
-       lane_info = (I915_READ(PORT_TX_DFLEXDPSP) &
-                    DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
-                   DP_LANE_ASSIGNMENT_SHIFT(tc_port);
+       lane_info = 0;
+       with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref)
+               lane_info = (I915_READ(PORT_TX_DFLEXDPSP) &
+                            DP_LANE_ASSIGNMENT_MASK(tc_port)) >>
+                               DP_LANE_ASSIGNMENT_SHIFT(tc_port);
 
        switch (lane_info) {
        default:
@@ -1211,7 +1224,10 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
                        to_i915(intel_dig_port->base.base.dev);
        i915_reg_t ch_ctl, ch_data[5];
        u32 aux_clock_divider;
-       intel_wakeref_t wakeref;
+       enum intel_display_power_domain aux_domain =
+               intel_aux_power_domain(intel_dig_port);
+       intel_wakeref_t aux_wakeref;
+       intel_wakeref_t pps_wakeref;
        int i, ret, recv_bytes;
        int try, clock = 0;
        u32 status;
@@ -1221,7 +1237,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
        for (i = 0; i < ARRAY_SIZE(ch_data); i++)
                ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
 
-       wakeref = pps_lock(intel_dp);
+       aux_wakeref = intel_display_power_get(dev_priv, aux_domain);
+       pps_wakeref = pps_lock(intel_dp);
 
        /*
         * We will be called with VDD already enabled for dpcd/edid/oui reads.
@@ -1367,7 +1384,8 @@ out:
        if (vdd)
                edp_panel_vdd_off(intel_dp, false);
 
-       pps_unlock(intel_dp, wakeref);
+       pps_unlock(intel_dp, pps_wakeref);
+       intel_display_power_put_async(dev_priv, aux_domain, aux_wakeref);
 
        return ret;
 }
@@ -1832,6 +1850,19 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
        }
 }
 
+static int intel_dp_output_bpp(const struct intel_crtc_state *crtc_state, int bpp)
+{
+       /*
+        * bpp value was assumed to RGB format. And YCbCr 4:2:0 output
+        * format of the number of bytes per pixel will be half the number
+        * of bytes of RGB pixel.
+        */
+       if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+               bpp /= 2;
+
+       return bpp;
+}
+
 /* Optimize link config in order: max bpp, min clock, min lanes */
 static int
 intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
@@ -2075,6 +2106,36 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
        return 0;
 }
 
+static int
+intel_dp_ycbcr420_config(struct intel_dp *intel_dp,
+                        struct drm_connector *connector,
+                        struct intel_crtc_state *crtc_state)
+{
+       const struct drm_display_info *info = &connector->display_info;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc_state->base.adjusted_mode;
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       int ret;
+
+       if (!drm_mode_is_420_only(info, adjusted_mode) ||
+           !intel_dp_get_colorimetry_status(intel_dp) ||
+           !connector->ycbcr_420_allowed)
+               return 0;
+
+       crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR420;
+
+       /* YCBCR 420 output conversion needs a scaler */
+       ret = skl_update_scaler_crtc(crtc_state);
+       if (ret) {
+               DRM_DEBUG_KMS("Scaler allocation for output failed\n");
+               return ret;
+       }
+
+       intel_pch_panel_fitting(crtc, crtc_state, DRM_MODE_SCALE_FULLSCREEN);
+
+       return 0;
+}
+
 bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
                                  const struct drm_connector_state *conn_state)
 {
@@ -2114,7 +2175,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                to_intel_digital_connector_state(conn_state);
        bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
                                           DP_DPCD_QUIRK_CONSTANT_N);
-       int ret, output_bpp;
+       int ret = 0, output_bpp;
 
        if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
                pipe_config->has_pch_encoder = true;
@@ -2122,6 +2183,12 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
        if (lspcon->active)
                lspcon_ycbcr420_config(&intel_connector->base, pipe_config);
+       else
+               ret = intel_dp_ycbcr420_config(intel_dp, &intel_connector->base,
+                                              pipe_config);
+
+       if (ret)
+               return ret;
 
        pipe_config->has_drrs = false;
        if (IS_G4X(dev_priv) || port == PORT_A)
@@ -2169,7 +2236,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        if (pipe_config->dsc_params.compression_enable)
                output_bpp = pipe_config->dsc_params.compressed_bpp;
        else
-               output_bpp = pipe_config->pipe_bpp;
+               output_bpp = intel_dp_output_bpp(pipe_config, pipe_config->pipe_bpp);
 
        intel_link_compute_m_n(output_bpp,
                               pipe_config->lane_count,
@@ -3148,12 +3215,12 @@ static void chv_post_disable_dp(struct intel_encoder *encoder,
 
        intel_dp_link_down(encoder, old_crtc_state);
 
-       mutex_lock(&dev_priv->sb_lock);
+       vlv_dpio_get(dev_priv);
 
        /* Assert data lane reset */
        chv_data_lane_soft_reset(encoder, old_crtc_state, true);
 
-       mutex_unlock(&dev_priv->sb_lock);
+       vlv_dpio_put(dev_priv);
 }
 
 static void
@@ -4041,6 +4108,16 @@ intel_dp_read_dpcd(struct intel_dp *intel_dp)
        return intel_dp->dpcd[DP_DPCD_REV] != 0;
 }
 
+bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
+{
+       u8 dprx = 0;
+
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
+                             &dprx) != 1)
+               return false;
+       return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
+}
+
 static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp)
 {
        /*
@@ -4351,6 +4428,96 @@ u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
        return 0;
 }
 
+static void
+intel_pixel_encoding_setup_vsc(struct intel_dp *intel_dp,
+                              const struct intel_crtc_state *crtc_state)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct dp_sdp vsc_sdp = {};
+
+       /* Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119 */
+       vsc_sdp.sdp_header.HB0 = 0;
+       vsc_sdp.sdp_header.HB1 = 0x7;
+
+       /*
+        * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
+        * Colorimetry Format indication.
+        */
+       vsc_sdp.sdp_header.HB2 = 0x5;
+
+       /*
+        * VSC SDP supporting 3D stereo, + PSR2, + Pixel Encoding/
+        * Colorimetry Format indication (HB2 = 05h).
+        */
+       vsc_sdp.sdp_header.HB3 = 0x13;
+
+       /*
+        * YCbCr 420 = 3h DB16[7:4] ITU-R BT.601 = 0h, ITU-R BT.709 = 1h
+        * DB16[3:0] DP 1.4a spec, Table 2-120
+        */
+       vsc_sdp.db[16] = 0x3 << 4; /* 0x3 << 4 , YCbCr 420*/
+       /* RGB->YCBCR color conversion uses the BT.709 color space. */
+       vsc_sdp.db[16] |= 0x1; /* 0x1, ITU-R BT.709 */
+
+       /*
+        * For pixel encoding formats YCbCr444, YCbCr422, YCbCr420, and Y Only,
+        * the following Component Bit Depth values are defined:
+        * 001b = 8bpc.
+        * 010b = 10bpc.
+        * 011b = 12bpc.
+        * 100b = 16bpc.
+        */
+       switch (crtc_state->pipe_bpp) {
+       case 24: /* 8bpc */
+               vsc_sdp.db[17] = 0x1;
+               break;
+       case 30: /* 10bpc */
+               vsc_sdp.db[17] = 0x2;
+               break;
+       case 36: /* 12bpc */
+               vsc_sdp.db[17] = 0x3;
+               break;
+       case 48: /* 16bpc */
+               vsc_sdp.db[17] = 0x4;
+               break;
+       default:
+               MISSING_CASE(crtc_state->pipe_bpp);
+               break;
+       }
+
+       /*
+        * Dynamic Range (Bit 7)
+        * 0 = VESA range, 1 = CTA range.
+        * all YCbCr are always limited range
+        */
+       vsc_sdp.db[17] |= 0x80;
+
+       /*
+        * Content Type (Bits 2:0)
+        * 000b = Not defined.
+        * 001b = Graphics.
+        * 010b = Photo.
+        * 011b = Video.
+        * 100b = Game
+        * All other values are RESERVED.
+        * Note: See CTA-861-G for the definition and expected
+        * processing by a stream sink for the above contect types.
+        */
+       vsc_sdp.db[18] = 0;
+
+       intel_dig_port->write_infoframe(&intel_dig_port->base,
+                       crtc_state, DP_SDP_VSC, &vsc_sdp, sizeof(vsc_sdp));
+}
+
+void intel_dp_ycbcr_420_enable(struct intel_dp *intel_dp,
+                              const struct intel_crtc_state *crtc_state)
+{
+       if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420)
+               return;
+
+       intel_pixel_encoding_setup_vsc(intel_dp, crtc_state);
+}
+
 static u8 intel_dp_autotest_link_training(struct intel_dp *intel_dp)
 {
        int status = 0;
@@ -4829,15 +4996,15 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
        u8 *dpcd = intel_dp->dpcd;
        u8 type;
 
+       if (WARN_ON(intel_dp_is_edp(intel_dp)))
+               return connector_status_connected;
+
        if (lspcon->active)
                lspcon_resume(lspcon);
 
        if (!intel_dp_get_dpcd(intel_dp))
                return connector_status_disconnected;
 
-       if (intel_dp_is_edp(intel_dp))
-               return connector_status_connected;
-
        /* if there's no downstream port, we're done */
        if (!drm_dp_is_branch(dpcd))
                return connector_status_connected;
@@ -5219,12 +5386,15 @@ static bool icl_tc_port_connected(struct drm_i915_private *dev_priv,
        u32 dpsp;
 
        /*
-        * WARN if we got a legacy port HPD, but VBT didn't mark the port as
+        * Complain if we got a legacy port HPD, but VBT didn't mark the port as
         * legacy. Treat the port as legacy from now on.
         */
-       if (WARN_ON(!intel_dig_port->tc_legacy_port &&
-                   I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)))
+       if (!intel_dig_port->tc_legacy_port &&
+           I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) {
+               DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n",
+                         port_name(port));
                intel_dig_port->tc_legacy_port = true;
+       }
        is_legacy = intel_dig_port->tc_legacy_port;
 
        /*
@@ -5276,7 +5446,7 @@ static bool icl_digital_port_connected(struct intel_encoder *encoder)
  *
  * Return %true if port is connected, %false otherwise.
  */
-bool intel_digital_port_connected(struct intel_encoder *encoder)
+static bool __intel_digital_port_connected(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 
@@ -5306,6 +5476,18 @@ bool intel_digital_port_connected(struct intel_encoder *encoder)
        return false;
 }
 
+bool intel_digital_port_connected(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       bool is_connected = false;
+       intel_wakeref_t wakeref;
+
+       with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref)
+               is_connected = __intel_digital_port_connected(encoder);
+
+       return is_connected;
+}
+
 static struct edid *
 intel_dp_get_edid(struct intel_dp *intel_dp)
 {
@@ -5359,16 +5541,11 @@ intel_dp_detect(struct drm_connector *connector,
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct intel_encoder *encoder = &dig_port->base;
        enum drm_connector_status status;
-       enum intel_display_power_domain aux_domain =
-               intel_aux_power_domain(dig_port);
-       intel_wakeref_t wakeref;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
        WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
 
-       wakeref = intel_display_power_get(dev_priv, aux_domain);
-
        /* Can't disconnect eDP */
        if (intel_dp_is_edp(intel_dp))
                status = edp_detect(intel_dp);
@@ -5432,10 +5609,8 @@ intel_dp_detect(struct drm_connector *connector,
                int ret;
 
                ret = intel_dp_retrain_link(encoder, ctx);
-               if (ret) {
-                       intel_display_power_put(dev_priv, aux_domain, wakeref);
+               if (ret)
                        return ret;
-               }
        }
 
        /*
@@ -5457,7 +5632,6 @@ out:
        if (status != connector_status_connected && !intel_dp->is_mst)
                intel_dp_unset_edid(intel_dp);
 
-       intel_display_power_put(dev_priv, aux_domain, wakeref);
        return status;
 }
 
@@ -6235,6 +6409,10 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
 
        intel_dp->reset_link_params = true;
 
+       if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
+           !intel_dp_is_edp(intel_dp))
+               return;
+
        with_pps_lock(intel_dp, wakeref) {
                if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                        intel_dp->active_pipe = vlv_active_pipe(intel_dp);
@@ -6278,9 +6456,6 @@ enum irqreturn
 intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 {
        struct intel_dp *intel_dp = &intel_dig_port->dp;
-       struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-       enum irqreturn ret = IRQ_NONE;
-       intel_wakeref_t wakeref;
 
        if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
                /*
@@ -6303,9 +6478,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                return IRQ_NONE;
        }
 
-       wakeref = intel_display_power_get(dev_priv,
-                                         intel_aux_power_domain(intel_dig_port));
-
        if (intel_dp->is_mst) {
                if (intel_dp_check_mst_status(intel_dp) == -EINVAL) {
                        /*
@@ -6317,7 +6489,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                        intel_dp->is_mst = false;
                        drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
                                                        intel_dp->is_mst);
-                       goto put_power;
+
+                       return IRQ_NONE;
                }
        }
 
@@ -6327,17 +6500,10 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                handled = intel_dp_short_pulse(intel_dp);
 
                if (!handled)
-                       goto put_power;
+                       return IRQ_NONE;
        }
 
-       ret = IRQ_HANDLED;
-
-put_power:
-       intel_display_power_put(dev_priv,
-                               intel_aux_power_domain(intel_dig_port),
-                               wakeref);
-
-       return ret;
+       return IRQ_HANDLED;
 }
 
 /* check the VBT to see whether the eDP is on another port */
@@ -7190,10 +7356,16 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        intel_dp->DP = I915_READ(intel_dp->output_reg);
        intel_dp->attached_connector = intel_connector;
 
-       if (intel_dp_is_port_edp(dev_priv, port))
+       if (intel_dp_is_port_edp(dev_priv, port)) {
+               /*
+                * Currently we don't support eDP on TypeC ports, although in
+                * theory it could work on TypeC legacy ports.
+                */
+               WARN_ON(intel_port_is_tc(dev_priv, port));
                type = DRM_MODE_CONNECTOR_eDP;
-       else
+       } else {
                type = DRM_MODE_CONNECTOR_DisplayPort;
+       }
 
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                intel_dp->active_pipe = vlv_active_pipe(intel_dp);
@@ -7223,6 +7395,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                connector->interlace_allowed = true;
        connector->doublescan_allowed = 0;
 
+       if (INTEL_GEN(dev_priv) >= 11)
+               connector->ycbcr_420_allowed = true;
+
        intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
 
        intel_dp_aux_init(intel_dp);