diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ddi.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 228 |
1 files changed, 155 insertions, 73 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ad11540ac436..f3e1d6a0b7dd 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -28,6 +28,7 @@ #include <drm/drm_scdc_helper.h> #include "i915_drv.h" #include "intel_drv.h" +#include "intel_dsi.h" struct ddi_buf_trans { u32 trans1; /* balance leg enable, de-emph level */ @@ -1363,8 +1364,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, return dco_freq / (p0 * p1 * p2 * 5); } -static int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv, - enum intel_dpll_id pll_id) +int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv, + enum intel_dpll_id pll_id) { uint32_t cfgcr0, cfgcr1; uint32_t p0, p1, p2, dco_freq, ref_clock; @@ -2154,6 +2155,12 @@ static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder, intel_port_is_tc(dev_priv, encoder->port)) domains |= BIT_ULL(intel_ddi_main_link_aux_domain(dig_port)); + /* + * VDSC power is needed when DSC is enabled + */ + if (crtc_state->dsc_params.compression_enable) + domains |= BIT_ULL(intel_dsc_power_domain(crtc_state)); + return domains; } @@ -2785,77 +2792,54 @@ uint32_t icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, return 0; } -void icl_map_plls_to_ports(struct drm_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct drm_atomic_state *old_state) +static void icl_map_plls_to_ports(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct drm_connector_state *conn_state; - struct drm_connector *conn; - int i; - - for_each_new_connector_in_state(old_state, conn, conn_state, i) { - struct intel_encoder *encoder = - to_intel_encoder(conn_state->best_encoder); - enum port port; - uint32_t val; - - if (conn_state->crtc != crtc) - continue; - - port = encoder->port; - mutex_lock(&dev_priv->dpll_lock); + enum port port = encoder->port; + u32 val; - val = I915_READ(DPCLKA_CFGCR0_ICL); - WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0); + mutex_lock(&dev_priv->dpll_lock); - if (intel_port_is_combophy(dev_priv, port)) { - val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); - val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); - I915_WRITE(DPCLKA_CFGCR0_ICL, val); - POSTING_READ(DPCLKA_CFGCR0_ICL); - } + val = I915_READ(DPCLKA_CFGCR0_ICL); + WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0); - val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port); + if (intel_port_is_combophy(dev_priv, port)) { + val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); + val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); I915_WRITE(DPCLKA_CFGCR0_ICL, val); - - mutex_unlock(&dev_priv->dpll_lock); + POSTING_READ(DPCLKA_CFGCR0_ICL); } + + val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port); + I915_WRITE(DPCLKA_CFGCR0_ICL, val); + + mutex_unlock(&dev_priv->dpll_lock); } -void icl_unmap_plls_to_ports(struct drm_crtc *crtc, - struct intel_crtc_state *crtc_state, - struct drm_atomic_state *old_state) +static void icl_unmap_plls_to_ports(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct drm_connector_state *old_conn_state; - struct drm_connector *conn; - int i; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum port port = encoder->port; + u32 val; - for_each_old_connector_in_state(old_state, conn, old_conn_state, i) { - struct intel_encoder *encoder = - to_intel_encoder(old_conn_state->best_encoder); - enum port port; + mutex_lock(&dev_priv->dpll_lock); - if (old_conn_state->crtc != crtc) - continue; + val = I915_READ(DPCLKA_CFGCR0_ICL); + val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port); + I915_WRITE(DPCLKA_CFGCR0_ICL, val); - port = encoder->port; - mutex_lock(&dev_priv->dpll_lock); - I915_WRITE(DPCLKA_CFGCR0_ICL, - I915_READ(DPCLKA_CFGCR0_ICL) | - icl_dpclka_cfgcr0_clk_off(dev_priv, port)); - mutex_unlock(&dev_priv->dpll_lock); - } + mutex_unlock(&dev_priv->dpll_lock); } void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 val; - enum port port = encoder->port; - bool clk_enabled; + enum port port; + u32 port_mask; + bool ddi_clk_needed; /* * In case of DP MST, we sanitize the primary encoder only, not the @@ -2864,9 +2848,6 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) if (encoder->type == INTEL_OUTPUT_DP_MST) return; - val = I915_READ(DPCLKA_CFGCR0_ICL); - clk_enabled = !(val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)); - if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) { u8 pipe_mask; bool is_mst; @@ -2880,20 +2861,52 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) return; } - if (clk_enabled == !!encoder->base.crtc) - return; + port_mask = BIT(encoder->port); + ddi_clk_needed = encoder->base.crtc; - /* - * Punt on the case now where clock is disabled, but the encoder is - * enabled, something else is really broken then. - */ - if (WARN_ON(!clk_enabled)) - return; + if (encoder->type == INTEL_OUTPUT_DSI) { + struct intel_encoder *other_encoder; - DRM_NOTE("Port %c is disabled but it has a mapped PLL, unmap it\n", - port_name(port)); - val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port); - I915_WRITE(DPCLKA_CFGCR0_ICL, val); + port_mask = intel_dsi_encoder_ports(encoder); + /* + * Sanity check that we haven't incorrectly registered another + * encoder using any of the ports of this DSI encoder. + */ + for_each_intel_encoder(&dev_priv->drm, other_encoder) { + if (other_encoder == encoder) + continue; + + if (WARN_ON(port_mask & BIT(other_encoder->port))) + return; + } + /* + * DSI ports should have their DDI clock ungated when disabled + * and gated when enabled. + */ + ddi_clk_needed = !encoder->base.crtc; + } + + val = I915_READ(DPCLKA_CFGCR0_ICL); + for_each_port_masked(port, port_mask) { + bool ddi_clk_ungated = !(val & + icl_dpclka_cfgcr0_clk_off(dev_priv, + port)); + + if (ddi_clk_needed == ddi_clk_ungated) + continue; + + /* + * Punt on the case now where clock is gated, but it would + * be needed by the port. Something else is really broken then. + */ + if (WARN_ON(ddi_clk_needed)) + continue; + + DRM_NOTE("Port %c is disabled/in DSI mode with an ungated DDI clock, gate it\n", + port_name(port)); + val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port); + I915_WRITE(DPCLKA_CFGCR0_ICL, val); + } } static void intel_ddi_clk_select(struct intel_encoder *encoder, @@ -3096,6 +3109,53 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) I915_WRITE(MG_DP_MODE(port, 1), ln1); } +static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + if (!crtc_state->fec_enable) + return; + + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) + DRM_DEBUG_KMS("Failed to set FEC_READY in the sink\n"); +} + +static void intel_ddi_enable_fec(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum port port = encoder->port; + u32 val; + + if (!crtc_state->fec_enable) + return; + + val = I915_READ(DP_TP_CTL(port)); + val |= DP_TP_CTL_FEC_ENABLE; + I915_WRITE(DP_TP_CTL(port), val); + + if (intel_wait_for_register(dev_priv, DP_TP_STATUS(port), + DP_TP_STATUS_FEC_ENABLE_LIVE, + DP_TP_STATUS_FEC_ENABLE_LIVE, + 1)) + DRM_ERROR("Timed out waiting for FEC Enable Status\n"); +} + +static void intel_ddi_disable_fec_state(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum port port = encoder->port; + u32 val; + + if (!crtc_state->fec_enable) + return; + + val = I915_READ(DP_TP_CTL(port)); + val &= ~DP_TP_CTL_FEC_ENABLE; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); +} + static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) @@ -3134,14 +3194,21 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, intel_ddi_init_dp_buf_reg(encoder); if (!is_mst) intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_sink_set_decompression_state(intel_dp, crtc_state, + true); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state); intel_dp_start_link_train(intel_dp); if (port != PORT_A || INTEL_GEN(dev_priv) >= 9) intel_dp_stop_link_train(intel_dp); + intel_ddi_enable_fec(encoder, crtc_state); + icl_enable_phy_clock_gating(dig_port); if (!is_mst) intel_ddi_enable_pipe_clock(crtc_state); + + intel_dsc_enable(encoder, crtc_state); } static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, @@ -3208,6 +3275,9 @@ static void intel_ddi_pre_enable(struct intel_encoder *encoder, WARN_ON(crtc_state->has_pch_encoder); + if (INTEL_GEN(dev_priv) >= 11) + icl_map_plls_to_ports(encoder, crtc_state); + intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { @@ -3228,7 +3298,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *encoder, } } -static void intel_disable_ddi_buf(struct intel_encoder *encoder) +static void intel_disable_ddi_buf(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; @@ -3247,6 +3318,9 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder) val |= DP_TP_CTL_LINK_TRAIN_PAT1; I915_WRITE(DP_TP_CTL(port), val); + /* Disable FEC in DP Sink */ + intel_ddi_disable_fec_state(encoder, crtc_state); + if (wait) intel_wait_ddi_buf_idle(dev_priv, port); } @@ -3270,7 +3344,7 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder, intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); } - intel_disable_ddi_buf(encoder); + intel_disable_ddi_buf(encoder, old_crtc_state); intel_edp_panel_vdd_on(intel_dp); intel_edp_panel_off(intel_dp); @@ -3293,7 +3367,7 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder, intel_ddi_disable_pipe_clock(old_crtc_state); - intel_disable_ddi_buf(encoder); + intel_disable_ddi_buf(encoder, old_crtc_state); intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain); @@ -3306,6 +3380,8 @@ static void intel_ddi_post_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + /* * When called from DP MST code: * - old_conn_state will be NULL @@ -3325,6 +3401,9 @@ static void intel_ddi_post_disable(struct intel_encoder *encoder, else intel_ddi_post_disable_dp(encoder, old_crtc_state, old_conn_state); + + if (INTEL_GEN(dev_priv) >= 11) + icl_unmap_plls_to_ports(encoder); } void intel_ddi_fdi_post_disable(struct intel_encoder *encoder, @@ -3344,7 +3423,7 @@ void intel_ddi_fdi_post_disable(struct intel_encoder *encoder, val &= ~FDI_RX_ENABLE; I915_WRITE(FDI_RX_CTL(PIPE_A), val); - intel_disable_ddi_buf(encoder); + intel_disable_ddi_buf(encoder, old_crtc_state); intel_ddi_clk_disable(encoder); val = I915_READ(FDI_RX_MISC(PIPE_A)); @@ -3491,6 +3570,9 @@ static void intel_disable_ddi_dp(struct intel_encoder *encoder, intel_edp_drrs_disable(intel_dp, old_crtc_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); } static void intel_disable_ddi_hdmi(struct intel_encoder *encoder, |