aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hdmi.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c105
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;