@@ -463,6 +463,8 @@ struct intel_hdmi {
bool has_audio;
enum hdmi_force_audio force_audio;
bool rgb_quant_range_selectable;
+ struct edid *edid;
+ uint32_t edid_mode_count;
void (*write_infoframe)(struct drm_encoder *encoder,
enum hdmi_infoframe_type type,
const void *frame, ssize_t len);
@@ -994,7 +994,14 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, drm_get_connector_name(connector));
+ /* If its forced detect call, dont read EDID again */
+ if (force && intel_hdmi->edid)
+ return connector->status;
+
status = get_hdmi_hotplug_live_status(dev, intel_hdmi);
+ /* Suppress spurious IRQ, if current status is same as live status*/
+ if (connector->status == status)
+ return connector->status;
intel_hdmi->has_hdmi_sink = false;
intel_hdmi->has_audio = false;
@@ -1015,11 +1022,22 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
drm_detect_monitor_audio(edid);
intel_hdmi->rgb_quant_range_selectable =
drm_rgb_quant_range_selectable(edid);
+
+ /* Free previously saved EDID and save new one
+ for read modes. */
+ kfree(intel_hdmi->edid);
+ intel_hdmi->edid = edid;
+ } else {
+ kfree(edid);
+ DRM_ERROR("EDID is not in digital form ?\n");
}
- kfree(edid);
} else {
- status = connector_status_disconnected;
+ DRM_DEBUG_KMS("EDID read failed\n");
}
+
+ if (intel_hdmi->edid == NULL)
+ status = connector_status_disconnected;
+
}
if (status == connector_status_connected) {
@@ -1027,6 +1045,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
intel_hdmi->has_audio =
(intel_hdmi->force_audio == HDMI_AUDIO_ON);
intel_encoder->type = INTEL_OUTPUT_HDMI;
+ } else {
+ kfree(intel_hdmi->edid);
+ intel_hdmi->edid = NULL;
}
return status;
@@ -1036,14 +1057,44 @@ static int intel_hdmi_get_modes(struct drm_connector *connector)
{
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
+ struct edid *edid = intel_hdmi->edid;
+ struct drm_display_mode *mode = NULL;
+ int count = 0;
- /* We should parse the EDID data and find out if it's an HDMI sink so
- * we can send audio to it.
- */
+ /* No need to read modes if panel is not connected */
+ if (connector->status != connector_status_connected)
+ return 0;
- return intel_ddc_get_modes(connector,
+ /* Need not read modes again if previously read modes are
+ available and display is consistent */
+ if (intel_hdmi->edid) {
+ list_for_each_entry(mode, &connector->modes, head) {
+ if (mode) {
+ /* Setting the MODE_OK for all sanitized modes*/
+ mode->status = MODE_OK;
+ count++;
+ }
+ }
+ /* If modes are availlable, no need to read again */
+ if (count)
+ goto out;
+ }
+
+ /* EDID was saved in detect, re-use that if available, avoid
+ reading EDID everytime */
+ if (edid) {
+ drm_mode_connector_update_edid_property(connector, edid);
+ count = drm_add_edid_modes(connector, edid);
+ drm_edid_to_eld(connector, edid);
+ } else {
+ count = intel_ddc_get_modes(connector,
intel_gmbus_get_adapter(dev_priv,
- intel_hdmi->ddc_bus));
+ intel_hdmi->ddc_bus));
+ }
+
+out:
+ intel_hdmi->edid_mode_count = count;
+ return count;
}
static bool
@@ -1381,6 +1432,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
intel_dig_port->port = port;
intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
+ intel_dig_port->hdmi.edid = NULL;
intel_dig_port->dp.output_reg = 0;
intel_hdmi_init_connector(intel_dig_port, intel_connector);