diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hdmi.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_hdmi.c | 105 |
1 files changed, 56 insertions, 49 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 7816b2a33fee..c0ce6d3dc505 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -42,7 +42,9 @@ #include "i915_debugfs.h" #include "i915_drv.h" +#include "i915_reg.h" #include "intel_atomic.h" +#include "intel_audio.h" #include "intel_connector.h" #include "intel_ddi.h" #include "intel_de.h" @@ -536,8 +538,7 @@ void hsw_write_infoframe(struct intel_encoder *encoder, 0); /* Wa_14013475917 */ - if (DISPLAY_VER(dev_priv) == 13 && crtc_state->has_psr && - type == DP_SDP_VSC) + if (IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC) return; val |= hsw_infoframe_enable(type); @@ -766,6 +767,7 @@ intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd; int ret; @@ -775,7 +777,11 @@ intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder, crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD); - ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx"); + if (IS_DGFX(i915)) + ret = hdmi_spd_infoframe_init(frame, "Intel", "Discrete gfx"); + else + ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx"); + if (drm_WARN_ON(encoder->base.dev, ret)) return false; @@ -1987,9 +1993,6 @@ intel_hdmi_mode_valid(struct drm_connector *connector, bool has_hdmi_sink = intel_has_hdmi_sink(hdmi, connector->state); bool ycbcr_420_only; - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - return MODE_NO_DBLESCAN; - if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) clock *= 2; @@ -2057,13 +2060,6 @@ static bool hdmi_bpc_possible(const struct intel_crtc_state *crtc_state, int bpc if (!intel_hdmi_source_bpc_possible(dev_priv, bpc)) return false; - /* - * HDMI deep color affects the clocks, so it's only possible - * when not cloning with other encoder types. - */ - if (bpc > 8 && crtc_state->output_types != BIT(INTEL_OUTPUT_HDMI)) - return false; - /* Display Wa_1405510057:icl,ehl */ if (intel_hdmi_is_ycbcr420(crtc_state) && bpc == 10 && DISPLAY_VER(dev_priv) == 11 && @@ -2190,9 +2186,13 @@ static bool intel_hdmi_has_audio(struct intel_encoder *encoder, } static enum intel_output_format -intel_hdmi_output_format(struct intel_connector *connector, +intel_hdmi_output_format(const struct intel_crtc_state *crtc_state, + struct intel_connector *connector, bool ycbcr_420_output) { + if (!crtc_state->has_hdmi_sink) + return INTEL_OUTPUT_FORMAT_RGB; + if (connector->base.ycbcr_420_allowed && ycbcr_420_output) return INTEL_OUTPUT_FORMAT_YCBCR420; else @@ -2211,7 +2211,8 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, bool ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode); int ret; - crtc_state->output_format = intel_hdmi_output_format(connector, ycbcr_420_only); + crtc_state->output_format = + intel_hdmi_output_format(crtc_state, connector, ycbcr_420_only); if (ycbcr_420_only && !intel_hdmi_is_ycbcr420(crtc_state)) { drm_dbg_kms(&i915->drm, @@ -2226,13 +2227,19 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, !drm_mode_is_420_also(info, adjusted_mode)) return ret; - crtc_state->output_format = intel_hdmi_output_format(connector, true); + crtc_state->output_format = intel_hdmi_output_format(crtc_state, connector, true); ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits); } return ret; } +static bool intel_hdmi_is_cloned(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->uapi.encoder_mask && + !is_power_of_2(crtc_state->uapi.encoder_mask); +} + int intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -2247,9 +2254,14 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; + if (!connector->interlace_allowed && + adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + return -EINVAL; + pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - pipe_config->has_hdmi_sink = intel_has_hdmi_sink(intel_hdmi, - conn_state); + pipe_config->has_hdmi_sink = + intel_has_hdmi_sink(intel_hdmi, conn_state) && + !intel_hdmi_is_cloned(pipe_config); if (pipe_config->has_hdmi_sink) pipe_config->has_infoframe = true; @@ -2257,11 +2269,9 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) pipe_config->pixel_multiplier = 2; - if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv)) - pipe_config->has_pch_encoder = true; - pipe_config->has_audio = - intel_hdmi_has_audio(encoder, pipe_config, conn_state); + intel_hdmi_has_audio(encoder, pipe_config, conn_state) && + intel_audio_compute_config(encoder, pipe_config, conn_state); /* * Try to respect downstream TMDS clock limits first, if @@ -2350,12 +2360,12 @@ intel_hdmi_unset_edid(struct drm_connector *connector) intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE; intel_hdmi->dp_dual_mode.max_tmds_clock = 0; - kfree(to_intel_connector(connector)->detect_edid); + drm_edid_free(to_intel_connector(connector)->detect_edid); to_intel_connector(connector)->detect_edid = NULL; } static void -intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) +intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); @@ -2371,16 +2381,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) * CONFIG1 pin, but no such luck on our hardware. * * The only method left to us is to check the VBT to see - * if the port is a dual mode capable DP port. But let's - * only do that when we sucesfully read the EDID, to avoid - * confusing log messages about DP dual mode adaptors when - * there's nothing connected to the port. + * if the port is a dual mode capable DP port. */ if (type == DRM_DP_DUAL_MODE_UNKNOWN) { - /* An overridden EDID imply that we want this port for testing. - * Make sure not to set limits for that port. - */ - if (has_edid && !connector->override_edid && + if (!connector->force && intel_bios_is_port_dp_dual_mode(dev_priv, port)) { drm_dbg_kms(&dev_priv->drm, "Assuming DP dual mode adaptor presence based on VBT\n"); @@ -2417,7 +2421,8 @@ intel_hdmi_set_edid(struct drm_connector *connector) struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector)); intel_wakeref_t wakeref; - struct edid *edid; + const struct drm_edid *drm_edid; + const struct edid *edid; bool connected = false; struct i2c_adapter *i2c; @@ -2425,28 +2430,34 @@ intel_hdmi_set_edid(struct drm_connector *connector) i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); - edid = drm_get_edid(connector, i2c); + drm_edid = drm_edid_read_ddc(connector, i2c); - if (!edid && !intel_gmbus_is_forced_bit(i2c)) { + if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) { drm_dbg_kms(&dev_priv->drm, "HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n"); intel_gmbus_force_bit(i2c, true); - edid = drm_get_edid(connector, i2c); + drm_edid = drm_edid_read_ddc(connector, i2c); intel_gmbus_force_bit(i2c, false); } - intel_hdmi_dp_dual_mode_detect(connector, edid != NULL); + /* Below we depend on display info having been updated */ + drm_edid_connector_update(connector, drm_edid); - intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); + to_intel_connector(connector)->detect_edid = drm_edid; - to_intel_connector(connector)->detect_edid = edid; + /* FIXME: Get rid of drm_edid_raw() */ + edid = drm_edid_raw(drm_edid); if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { intel_hdmi->has_audio = drm_detect_monitor_audio(edid); intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); + intel_hdmi_dp_dual_mode_detect(connector); + connected = true; } + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); + cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); return connected; @@ -2511,13 +2522,8 @@ intel_hdmi_force(struct drm_connector *connector) static int intel_hdmi_get_modes(struct drm_connector *connector) { - struct edid *edid; - - edid = to_intel_connector(connector)->detect_edid; - if (edid == NULL) - return 0; - - return intel_connector_update_modes(connector, edid); + /* drm_edid_connector_update() done in ->detect() or ->force() */ + return drm_edid_connector_add_modes(connector); } static struct i2c_adapter * @@ -2956,9 +2962,10 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, ddc); drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); - connector->interlace_allowed = 1; - connector->doublescan_allowed = 0; - connector->stereo_allowed = 1; + if (DISPLAY_VER(dev_priv) < 12) + connector->interlace_allowed = true; + + connector->stereo_allowed = true; if (DISPLAY_VER(dev_priv) >= 10) connector->ycbcr_420_allowed = true; |