From patchwork Fri Aug 16 08:04:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Lucas De Marchi X-Patchwork-Id: 11097129 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B964D56FE for ; Fri, 16 Aug 2019 08:06:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AA6E122362 for ; Fri, 16 Aug 2019 08:06:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9EDC128741; Fri, 16 Aug 2019 08:06:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CB6E82871A for ; Fri, 16 Aug 2019 08:06:03 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0E1A96EB20; Fri, 16 Aug 2019 08:06:02 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 518F16EB1C for ; Fri, 16 Aug 2019 08:05:50 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Aug 2019 01:05:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,391,1559545200"; d="scan'208";a="184851512" Received: from miyoungj-mobl1.amr.corp.intel.com (HELO ldmartin-desk1.intel.com) ([10.254.105.68]) by FMSMGA003.fm.intel.com with ESMTP; 16 Aug 2019 01:05:48 -0700 From: Lucas De Marchi To: intel-gfx@lists.freedesktop.org Date: Fri, 16 Aug 2019 01:04:41 -0700 Message-Id: <20190816080503.28594-18-lucas.demarchi@intel.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190816080503.28594-1-lucas.demarchi@intel.com> References: <20190816080503.28594-1-lucas.demarchi@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 17/39] drm/i915/tgl: Select master transcoder in DP MST X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP From: José Roberto de Souza On TGL the blending of all the streams have moved from DDI to transcoder, so now every transcoder working over the same MST port must send its stream to a master transcoder and master will send to DDI respecting the time slots. So here it is picking the lowest pipe/transcoder as it will be enabled first and disabled last. BSpec: 50493 BSpec: 49190 Cc: Ville Syrjälä Cc: Manasi Navare Cc: Rodrigo Vivi Signed-off-by: José Roberto de Souza Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/i915/display/intel_ddi.c | 17 ++ drivers/gpu/drm/i915/display/intel_display.c | 15 ++ drivers/gpu/drm/i915/display/intel_display.h | 3 + .../drm/i915/display/intel_display_types.h | 3 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 159 +++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp_mst.h | 2 + drivers/gpu/drm/i915/i915_reg.h | 3 + 7 files changed, 199 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 647ba5140656..c26dee8521f6 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1840,6 +1840,12 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state) } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) { temp |= TRANS_DDI_MODE_SELECT_DP_MST; temp |= DDI_PORT_WIDTH(crtc_state->lane_count); + + if (INTEL_GEN(dev_priv) >= 12) { + enum transcoder master = crtc_state->mst_master_trans; + + temp |= TRANS_DDI_MST_TRANSPORT_SELECT_DPTP(master); + } } else { temp |= TRANS_DDI_MODE_SELECT_DP_SST; temp |= DDI_PORT_WIDTH(crtc_state->lane_count); @@ -3863,6 +3869,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder, break; } + pipe_config->mst_master_trans = TRANSCODER_INVALID; + switch (temp & TRANS_DDI_MODE_SELECT_MASK) { case TRANS_DDI_MODE_SELECT_HDMI: pipe_config->has_hdmi_sink = true; @@ -3898,6 +3906,13 @@ void intel_ddi_get_config(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_DP_MST); pipe_config->lane_count = ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1; + + if (INTEL_GEN(dev_priv) >= 12) { + temp = temp & TRANS_DDI_MST_TRANSPORT_SELECT_MASK; + temp = temp >> TRANS_DDI_MST_TRANSPORT_SELECT_SHIFT; + pipe_config->mst_master_trans = temp; + } + intel_dp_get_m_n(intel_crtc, pipe_config); break; default: @@ -4000,6 +4015,8 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + pipe_config->mst_master_trans = TRANSCODER_INVALID; + return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 72c41d3affb1..81c1d359edb2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -47,6 +47,7 @@ #include "display/intel_crt.h" #include "display/intel_ddi.h" #include "display/intel_dp.h" +#include "display/intel_dp_mst.h" #include "display/intel_dsi.h" #include "display/intel_dvo.h" #include "display/intel_gmbus.h" @@ -12154,6 +12155,14 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, intel_dpll_dump_hw_state(dev_priv, &pipe_config->dpll_hw_state); + if (INTEL_GEN(dev_priv) >= 12 && + intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) { + enum transcoder master = pipe_config->mst_master_trans; + + DRM_DEBUG_KMS("master mst cpu_transcoder: %s\n", + transcoder_name(master)); + } + dump_planes: if (!state) return; @@ -12837,6 +12846,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_INFOFRAME(hdmi); PIPE_CONF_CHECK_INFOFRAME(drm); + PIPE_CONF_CHECK_I(mst_master_trans); + #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_BOOL @@ -13613,6 +13624,10 @@ static int intel_atomic_check(struct drm_device *dev, int ret, i; bool any_ms = state->cdclk.force_min_cdclk_changed; + ret = intel_dp_mst_atomic_add_affected_crtcs(state); + if (ret) + return ret; + /* Catch I915_MODE_FLAG_INHERITED */ for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index c0197380a871..459b341796bd 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -91,6 +91,8 @@ enum pipe { #define pipe_name(p) ((p) + 'A') enum transcoder { + TRANSCODER_INVALID = -1, + /* * The following transcoders have a 1:1 transcoder -> pipe mapping, * keep their values fixed: the code assumes that TRANSCODER_A=0, the @@ -132,6 +134,7 @@ static inline const char *transcoder_name(enum transcoder transcoder) return "DSI A"; case TRANSCODER_DSI_C: return "DSI C"; + case TRANSCODER_INVALID: default: return ""; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index a88ec9aa9ca0..54d1053ff6d0 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -983,6 +983,9 @@ struct intel_crtc_state { /* Forward Error correction State */ bool fec_enable; + + /* Master transcoder for all streams, only used on TGL+ */ + enum transcoder mst_master_trans; }; struct intel_crtc { diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 7138785daf15..75c9db85f2b0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -87,6 +87,50 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, return 0; } +/* + * Iterate over all the CRTCs and return the transcoder of the lowest CRTC that + * share the same MST connector. + */ +static enum transcoder +mst_compute_master_trans(struct drm_atomic_state *state, + struct drm_connector *mst_conn) +{ + struct intel_connector *intel_mst_conn = to_intel_connector(mst_conn); + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_crtc_state *intel_crtc_state; + struct intel_crtc *intel_crtc; + int i; + + if (INTEL_GEN(dev_priv) < 12) + return TRANSCODER_INVALID; + + /* Iterate from the lowest to the highest pipe */ + for_each_new_intel_crtc_in_state(intel_state, intel_crtc, intel_crtc_state, i) { + struct intel_digital_connector_state *intel_conn_state; + struct intel_connector *intel_conn; + int j; + + if (!intel_crtc_state->base.active) + continue; + + for_each_new_intel_connector_in_state(intel_state, intel_conn, + intel_conn_state, j) { + /* Only care about connectors of this CRTC */ + if (intel_conn_state->base.crtc != + intel_crtc_state->base.crtc) + continue; + + if (intel_conn->mst_port != intel_mst_conn->mst_port) + continue; + + return intel_crtc_state->cpu_transcoder; + } + } + + return TRANSCODER_INVALID; +} + static int intel_dp_mst_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -94,14 +138,15 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_dp *intel_dp = &intel_mst->primary->dp; - struct intel_connector *connector = - to_intel_connector(conn_state->connector); + struct drm_connector *connector = conn_state->connector; + struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(conn_state); const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - void *port = connector->port; + void *port = intel_connector->port; struct link_config_limits limits; + enum transcoder master; int ret; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -146,6 +191,51 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + master = mst_compute_master_trans(conn_state->state, connector); + pipe_config->mst_master_trans = master; + + return 0; +} + +static int +intel_dp_mst_master_trans_check(struct drm_connector *conn, + struct drm_connector_state *new_conn_state) +{ + struct drm_i915_private *dev_priv = to_i915(conn->dev); + struct drm_atomic_state *state = new_conn_state->state; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, conn); + struct drm_crtc *new_crtc = new_conn_state->crtc; + struct drm_crtc *old_crtc = old_conn_state->crtc; + enum transcoder old_master_trans = TRANSCODER_INVALID; + enum transcoder new_master_trans = TRANSCODER_INVALID; + struct drm_crtc_state *new_crtc_state, *old_crtc_state; + + if (INTEL_GEN(dev_priv) < 12) + return 0; + + if (old_crtc) { + struct intel_crtc_state *intel_crtc_state; + + old_crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); + intel_crtc_state = to_intel_crtc_state(old_crtc_state); + old_master_trans = intel_crtc_state->mst_master_trans; + } + + if (new_crtc) { + struct intel_crtc_state *intel_crtc_state; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + intel_crtc_state = to_intel_crtc_state(new_crtc_state); + new_master_trans = mst_compute_master_trans(state, conn); + } + + if (old_crtc && old_master_trans != new_master_trans) + old_crtc_state->mode_changed = true; + + if (new_crtc && old_master_trans != new_master_trans) + new_crtc_state->mode_changed = true; + return 0; } @@ -168,6 +258,10 @@ intel_dp_mst_atomic_check(struct drm_connector *connector, if (ret) return ret; + ret = intel_dp_mst_master_trans_check(connector, new_conn_state); + if (ret) + return ret; + if (!old_conn_state->crtc) return 0; @@ -672,3 +766,62 @@ intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port) drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr); /* encoders will get killed by normal cleanup */ } + +/** + * intel_dp_mst_atomic_add_affected_crtcs - Add all CRTCs that share the MST + * stream with the CRTCs in the current atomic state. + * @state: state to add CRTCs + * + * It is needed add the CRTCs trigger a call to atomic_check() to + * every connector attached to the CRTC in case a new master transcoder will + * be needed. + */ +int intel_dp_mst_atomic_add_affected_crtcs(struct intel_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_digital_connector_state *intel_conn_state; + struct drm_device *dev = state->base.dev; + struct intel_connector *intel_conn; + int i; + + if (INTEL_GEN(dev_priv) < 12) + return 0; + + for_each_new_intel_connector_in_state(state, intel_conn, intel_conn_state, i) { + struct drm_connector_list_iter conn_list_iter; + struct drm_connector *conn_iter; + + if (!intel_conn->mst_port) + continue; + + drm_connector_list_iter_begin(dev, &conn_list_iter); + drm_for_each_connector_iter(conn_iter, &conn_list_iter) { + struct drm_connector_state *conn_iter_state; + struct intel_connector *intel_conn_iter; + struct drm_crtc_state *crtc_state; + + intel_conn_iter = to_intel_connector(conn_iter); + + if (intel_conn_iter->mst_port != intel_conn->mst_port) + continue; + + conn_iter_state = drm_atomic_get_connector_state(&state->base, conn_iter); + if (IS_ERR(conn_iter_state)) { + drm_connector_list_iter_end(&conn_list_iter); + return PTR_ERR(conn_iter_state); + } + if (!conn_iter_state->crtc) + continue; + + crtc_state = drm_atomic_get_crtc_state(&state->base, + conn_iter_state->crtc); + if (IS_ERR(crtc_state)) { + drm_connector_list_iter_end(&conn_list_iter); + return PTR_ERR(crtc_state); + } + } + drm_connector_list_iter_end(&conn_list_iter); + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h index f660ad80db04..173598aa81d2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h @@ -6,10 +6,12 @@ #ifndef __INTEL_DP_MST_H__ #define __INTEL_DP_MST_H__ +struct intel_atomic_state; struct intel_digital_port; int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port); +int intel_dp_mst_atomic_add_affected_crtcs(struct intel_atomic_state *state); int intel_dp_mst_encoder_active_links(struct intel_digital_port *intel_dig_port); #endif /* __INTEL_DP_MST_H__ */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 095dd27044c0..c836af0b8231 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9480,6 +9480,9 @@ enum skl_power_gate { #define TRANS_DDI_EDP_INPUT_A_ONOFF (4 << 12) #define TRANS_DDI_EDP_INPUT_B_ONOFF (5 << 12) #define TRANS_DDI_EDP_INPUT_C_ONOFF (6 << 12) +#define TRANS_DDI_MST_TRANSPORT_SELECT_SHIFT 10 /* TGL+ */ +#define TRANS_DDI_MST_TRANSPORT_SELECT_MASK (0x3 << 10) +#define TRANS_DDI_MST_TRANSPORT_SELECT_DPTP(trans) ((trans) << 10) #define TRANS_DDI_HDCP_SIGNALLING (1 << 9) #define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1 << 8) #define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1 << 7)