diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_ddi.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_ddi.c | 230 |
1 files changed, 176 insertions, 54 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 9151d5add9..31aa5d54fd 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -25,6 +25,7 @@ * */ +#include <linux/iopoll.h> #include <linux/string_helpers.h> #include <drm/display/drm_scdc_helper.h> @@ -2210,16 +2211,87 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel } static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + bool enable) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); if (!crtc_state->fec_enable) return; - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) - drm_dbg_kms(&i915->drm, - "Failed to set FEC_READY in the sink\n"); + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, + enable ? DP_FEC_READY : 0) <= 0) + drm_dbg_kms(&i915->drm, "Failed to set FEC_READY to %s in the sink\n", + enable ? "enabled" : "disabled"); + + if (enable && + drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS, + DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0) + drm_dbg_kms(&i915->drm, "Failed to clear FEC detected flags\n"); +} + +static int read_fec_detected_status(struct drm_dp_aux *aux) +{ + int ret; + u8 status; + + ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status); + if (ret < 0) + return ret; + + return status; +} + +static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled) +{ + struct drm_i915_private *i915 = to_i915(aux->drm_dev); + int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED; + int status; + int err; + + err = readx_poll_timeout(read_fec_detected_status, aux, status, + status & mask || status < 0, + 10000, 200000); + + if (!err && status >= 0) + return; + + if (err == -ETIMEDOUT) + drm_dbg_kms(&i915->drm, "Timeout waiting for FEC %s to get detected\n", + str_enabled_disabled(enabled)); + else + drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status); +} + +void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool enabled) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int ret; + + if (!crtc_state->fec_enable) + return; + + if (enabled) + ret = intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state), + DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + else + ret = intel_de_wait_for_clear(i915, dp_tp_status_reg(encoder, crtc_state), + DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + + if (ret) + drm_err(&i915->drm, + "Timeout waiting for FEC live state to get %s\n", + str_enabled_disabled(enabled)); + + /* + * At least the Synoptics MST hub doesn't set the detected flag for + * FEC decoding disabling so skip waiting for that. + */ + if (enabled) + wait_for_fec_detected(&intel_dp->aux, enabled); } static void intel_ddi_enable_fec(struct intel_encoder *encoder, @@ -2234,8 +2306,8 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder, 0, DP_TP_CTL_FEC_ENABLE); } -static void intel_ddi_disable_fec_state(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void intel_ddi_disable_fec(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -2466,13 +2538,17 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + if (!is_mst) + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); + /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link * training */ - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_check_frl_training(intel_dp); intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2505,7 +2581,8 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 6.o Configure and enable FEC if needed */ intel_ddi_enable_fec(encoder, crtc_state); - intel_dsc_dp_pps_write(encoder, crtc_state); + if (!is_mst) + intel_dsc_dp_pps_write(encoder, crtc_state); } static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2616,13 +2693,16 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + if (!is_mst) + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link * training */ - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_check_frl_training(intel_dp); intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2643,7 +2723,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 7.l Configure and enable FEC if needed */ intel_ddi_enable_fec(encoder, crtc_state); - intel_dsc_dp_pps_write(encoder, crtc_state); + if (!is_mst) + intel_dsc_dp_pps_write(encoder, crtc_state); } static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2695,9 +2776,11 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, - true); - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + if (!is_mst) + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_start_link_train(intel_dp, crtc_state); if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) && !is_trans_port_sync_mode(crtc_state)) @@ -2705,10 +2788,10 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_fec(encoder, crtc_state); - if (!is_mst) + if (!is_mst) { intel_ddi_enable_transcoder_clock(encoder, crtc_state); - - intel_dsc_dp_pps_write(encoder, crtc_state); + intel_dsc_dp_pps_write(encoder, crtc_state); + } } static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2717,10 +2800,15 @@ static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - if (HAS_DP20(dev_priv)) + if (HAS_DP20(dev_priv)) { intel_dp_128b132b_sdp_crc16(enc_to_intel_dp(encoder), crtc_state); + if (crtc_state->has_panel_replay) + drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG, + DP_PANEL_REPLAY_ENABLE); + } if (DISPLAY_VER(dev_priv) >= 14) mtl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state); @@ -2866,8 +2954,7 @@ static void disable_ddi_buf(struct intel_encoder *encoder, intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), DP_TP_CTL_ENABLE, 0); - /* Disable FEC in DP Sink */ - intel_ddi_disable_fec_state(encoder, crtc_state); + intel_ddi_disable_fec(encoder, crtc_state); if (wait) intel_wait_ddi_buf_idle(dev_priv, port); @@ -2882,10 +2969,12 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder, mtl_disable_ddi_buf(encoder, crtc_state); /* 3.f Disable DP_TP_CTL FEC Enable if it is needed */ - intel_ddi_disable_fec_state(encoder, crtc_state); + intel_ddi_disable_fec(encoder, crtc_state); } else { disable_ddi_buf(encoder, crtc_state); } + + intel_ddi_wait_for_fec_status(encoder, crtc_state, false); } static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, @@ -2925,6 +3014,8 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, intel_disable_ddi_buf(encoder, old_crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, old_crtc_state, false); + /* * From TGL spec: "If single stream or multi-stream master transcoder: * Configure Transcoder Clock select to direct no clock to the @@ -3110,11 +3201,18 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, if (!dig_port->lspcon.active || intel_dp_has_hdmi_sink(&dig_port->dp)) intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); - intel_audio_codec_enable(encoder, crtc_state, conn_state); - trans_port_sync_stop_link_train(state, encoder, crtc_state); } +/* FIXME bad home for this function */ +i915_reg_t hsw_chicken_trans_reg(struct drm_i915_private *i915, + enum transcoder cpu_transcoder) +{ + return DISPLAY_VER(i915) >= 14 ? + MTL_CHICKEN_TRANS(cpu_transcoder) : + CHICKEN_TRANS(cpu_transcoder); +} + static i915_reg_t gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv, enum port port) @@ -3233,8 +3331,6 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, DDI_BUF_CTL(port), buf_ctl); intel_wait_ddi_buf_active(dev_priv, port); - - intel_audio_codec_enable(encoder, crtc_state, conn_state); } static void intel_enable_ddi(struct intel_atomic_state *state, @@ -3252,6 +3348,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_enable_transcoder(crtc_state); + intel_ddi_wait_for_fec_status(encoder, crtc_state, true); + intel_crtc_vblank_on(crtc_state); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) @@ -3259,10 +3357,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, else intel_enable_ddi_dp(state, encoder, crtc_state, conn_state); - /* Enable hdcp if it's desired */ - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) - intel_hdcp_enable(state, encoder, crtc_state, conn_state); + intel_hdcp_enable(state, encoder, crtc_state, conn_state); + } static void intel_disable_ddi_dp(struct intel_atomic_state *state, @@ -3271,16 +3367,16 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state, const struct drm_connector_state *old_conn_state) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_connector *connector = + to_intel_connector(old_conn_state->connector); intel_dp->link_trained = false; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - intel_psr_disable(intel_dp, old_crtc_state); intel_edp_backlight_off(old_conn_state); /* Disable the decompression in DP Sink */ - intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, - false); + intel_dp_sink_disable_decompression(state, + connector, old_crtc_state); /* Disable Ignore_MSA bit in DP Sink */ intel_dp_sink_set_msa_timing_par_ignore_state(intel_dp, old_crtc_state, false); @@ -3294,8 +3390,6 @@ static void intel_disable_ddi_hdmi(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = old_conn_state->connector; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - if (!intel_hdmi_handle_sink_scrambling(encoder, connector, false, false)) drm_dbg_kms(&i915->drm, @@ -3578,16 +3672,42 @@ static bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv, AUDIO_OUTPUT_ENABLE(cpu_transcoder); } -void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, - struct intel_crtc_state *crtc_state) +static int tgl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) { - if (DISPLAY_VER(dev_priv) >= 12 && crtc_state->port_clock > 594000) - crtc_state->min_voltage_level = 2; - else if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && - crtc_state->port_clock > 594000) - crtc_state->min_voltage_level = 3; - else if (DISPLAY_VER(dev_priv) >= 11 && crtc_state->port_clock > 594000) - crtc_state->min_voltage_level = 1; + if (crtc_state->port_clock > 594000) + return 2; + else + return 0; +} + +static int jsl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->port_clock > 594000) + return 3; + else + return 0; +} + +static int icl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->port_clock > 594000) + return 1; + else + return 0; +} + +void intel_ddi_compute_min_voltage_level(struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + + if (DISPLAY_VER(dev_priv) >= 14) + crtc_state->min_voltage_level = icl_ddi_min_voltage_level(crtc_state); + else if (DISPLAY_VER(dev_priv) >= 12) + crtc_state->min_voltage_level = tgl_ddi_min_voltage_level(crtc_state); + else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) + crtc_state->min_voltage_level = jsl_ddi_min_voltage_level(crtc_state); + else if (DISPLAY_VER(dev_priv) >= 11) + crtc_state->min_voltage_level = icl_ddi_min_voltage_level(crtc_state); } static enum transcoder bdw_transcoder_master_readout(struct drm_i915_private *dev_priv, @@ -3801,7 +3921,7 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, pipe_config->lane_lat_optim_mask = bxt_ddi_phy_get_lane_lat_optim_mask(encoder); - intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + intel_ddi_compute_min_voltage_level(pipe_config); intel_hdmi_read_gcp_infoframe(encoder, pipe_config); @@ -3854,18 +3974,13 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, static void mtl_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(i915, encoder->port); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); if (intel_tc_port_in_tbt_alt_mode(dig_port)) { crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); - } else if (intel_is_c10phy(i915, phy)) { - intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10); - crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); } else { - intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20); - crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); + intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->cx0pll_state); } intel_ddi_get_config(encoder, crtc_state); @@ -4086,7 +4201,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, pipe_config->lane_lat_optim_mask = bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); - intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + intel_ddi_compute_min_voltage_level(pipe_config); return 0; } @@ -4114,7 +4229,12 @@ static bool m_n_equal(const struct intel_link_m_n *m_n_1, static bool crtcs_port_sync_compatible(const struct intel_crtc_state *crtc_state1, const struct intel_crtc_state *crtc_state2) { + /* + * FIXME the modeset sequence is currently wrong and + * can't deal with bigjoiner + port sync at the same time. + */ return crtc_state1->hw.active && crtc_state2->hw.active && + !crtc_state1->bigjoiner_pipes && !crtc_state2->bigjoiner_pipes && crtc_state1->output_types == crtc_state2->output_types && crtc_state1->output_format == crtc_state2->output_format && crtc_state1->lane_count == crtc_state2->lane_count && @@ -4844,6 +4964,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, encoder->post_pll_disable = intel_ddi_post_pll_disable; encoder->post_disable = intel_ddi_post_disable; encoder->update_pipe = intel_ddi_update_pipe; + encoder->audio_enable = intel_audio_codec_enable; + encoder->audio_disable = intel_audio_codec_disable; encoder->get_hw_state = intel_ddi_get_hw_state; encoder->sync_state = intel_ddi_sync_state; encoder->initial_fastset_check = intel_ddi_initial_fastset_check; |