Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 953ece69 authored by Chris Wilson's avatar Chris Wilson Committed by Daniel Vetter
Browse files

drm/i915/hdmi: Cache EDID for a detection cycle



As we may query the edid multiple times following a detect, record the
EDID found during output discovery and reuse it. This is a separate
issue from caching the output EDID across detection cycles.

v2: Also hookup the force() callback for audio detection when the user
forces the connection status.
v3: Ville spots a typo, s/==/!=/

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent beb60608
Loading
Loading
Loading
Loading
+80 −65
Original line number Original line Diff line number Diff line
@@ -962,104 +962,117 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
	return true;
	return true;
}
}


static enum drm_connector_status
static void
intel_hdmi_detect(struct drm_connector *connector, bool force)
intel_hdmi_unset_edid(struct drm_connector *connector)
{
{
	struct drm_device *dev = connector->dev;
	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
	struct intel_digital_port *intel_dig_port =
		hdmi_to_dig_port(intel_hdmi);
	struct intel_encoder *intel_encoder = &intel_dig_port->base;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct edid *edid;
	enum intel_display_power_domain power_domain;
	enum drm_connector_status status = connector_status_disconnected;


	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
	intel_hdmi->has_hdmi_sink = false;
		      connector->base.id, connector->name);
	intel_hdmi->has_audio = false;
	intel_hdmi->rgb_quant_range_selectable = false;

	kfree(to_intel_connector(connector)->detect_edid);
	to_intel_connector(connector)->detect_edid = NULL;
}

static bool
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(connector);
	struct intel_encoder *intel_encoder =
		&hdmi_to_dig_port(intel_hdmi)->base;
	enum intel_display_power_domain power_domain;
	struct edid *edid;
	bool connected = false;


	power_domain = intel_display_port_power_domain(intel_encoder);
	power_domain = intel_display_port_power_domain(intel_encoder);
	intel_display_power_get(dev_priv, power_domain);
	intel_display_power_get(dev_priv, power_domain);


	intel_hdmi->has_hdmi_sink = false;
	intel_hdmi->has_audio = false;
	intel_hdmi->rgb_quant_range_selectable = false;
	edid = drm_get_edid(connector,
	edid = drm_get_edid(connector,
			    intel_gmbus_get_adapter(dev_priv,
			    intel_gmbus_get_adapter(dev_priv,
						    intel_hdmi->ddc_bus));
						    intel_hdmi->ddc_bus));


	if (edid) {
	intel_display_power_put(dev_priv, power_domain);
		if (edid->input & DRM_EDID_INPUT_DIGITAL) {

			status = connector_status_connected;
	to_intel_connector(connector)->detect_edid = edid;
			if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
				intel_hdmi->has_hdmi_sink =
						drm_detect_hdmi_monitor(edid);
			intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
		intel_hdmi->rgb_quant_range_selectable =
		intel_hdmi->rgb_quant_range_selectable =
			drm_rgb_quant_range_selectable(edid);
			drm_rgb_quant_range_selectable(edid);
		}
		kfree(edid);
	}


	if (status == connector_status_connected) {
		intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
			intel_hdmi->has_audio =
			intel_hdmi->has_audio =
				(intel_hdmi->force_audio == HDMI_AUDIO_ON);
				intel_hdmi->force_audio == HDMI_AUDIO_ON;
		intel_encoder->type = INTEL_OUTPUT_HDMI;

		if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
			intel_hdmi->has_hdmi_sink =
				drm_detect_hdmi_monitor(edid);

		connected = true;
	}
	}


	intel_display_power_put(dev_priv, power_domain);
	return connected;
}

static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector, bool force)
{
	enum drm_connector_status status;

	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
		      connector->base.id, connector->name);

	intel_hdmi_unset_edid(connector);

	if (intel_hdmi_set_edid(connector)) {
		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);

		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
		status = connector_status_connected;
	} else
		status = connector_status_disconnected;


	return status;
	return status;
}
}


static int intel_hdmi_get_modes(struct drm_connector *connector)
static void
intel_hdmi_force(struct drm_connector *connector)
{
{
	struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
	struct drm_i915_private *dev_priv = connector->dev->dev_private;
	enum intel_display_power_domain power_domain;
	int ret;


	/* We should parse the EDID data and find out if it's an HDMI sink so
	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
	 * we can send audio to it.
		      connector->base.id, connector->name);
	 */


	power_domain = intel_display_port_power_domain(intel_encoder);
	intel_hdmi_unset_edid(connector);
	intel_display_power_get(dev_priv, power_domain);


	ret = intel_ddc_get_modes(connector,
	if (connector->status != connector_status_connected)
				   intel_gmbus_get_adapter(dev_priv,
		return;
							   intel_hdmi->ddc_bus));


	intel_display_power_put(dev_priv, power_domain);
	intel_hdmi_set_edid(connector);
	hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
}


	return ret;
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);
}
}


static bool
static bool
intel_hdmi_detect_audio(struct drm_connector *connector)
intel_hdmi_detect_audio(struct drm_connector *connector)
{
{
	struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
	struct drm_i915_private *dev_priv = connector->dev->dev_private;
	enum intel_display_power_domain power_domain;
	struct edid *edid;
	bool has_audio = false;
	bool has_audio = false;
	struct edid *edid;


	power_domain = intel_display_port_power_domain(intel_encoder);
	edid = to_intel_connector(connector)->detect_edid;
	intel_display_power_get(dev_priv, power_domain);
	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL)

	edid = drm_get_edid(connector,
			    intel_gmbus_get_adapter(dev_priv,
						    intel_hdmi->ddc_bus));
	if (edid) {
		if (edid->input & DRM_EDID_INPUT_DIGITAL)
		has_audio = drm_detect_monitor_audio(edid);
		has_audio = drm_detect_monitor_audio(edid);
		kfree(edid);
	}

	intel_display_power_put(dev_priv, power_domain);


	return has_audio;
	return has_audio;
}
}
@@ -1479,6 +1492,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)


static void intel_hdmi_destroy(struct drm_connector *connector)
static void intel_hdmi_destroy(struct drm_connector *connector)
{
{
	intel_hdmi_unset_edid(connector);
	drm_connector_cleanup(connector);
	drm_connector_cleanup(connector);
	kfree(connector);
	kfree(connector);
}
}
@@ -1486,6 +1500,7 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
	.dpms = intel_connector_dpms,
	.dpms = intel_connector_dpms,
	.detect = intel_hdmi_detect,
	.detect = intel_hdmi_detect,
	.force = intel_hdmi_force,
	.fill_modes = drm_helper_probe_single_connector_modes,
	.fill_modes = drm_helper_probe_single_connector_modes,
	.set_property = intel_hdmi_set_property,
	.set_property = intel_hdmi_set_property,
	.destroy = intel_hdmi_destroy,
	.destroy = intel_hdmi_destroy,