@@ -444,6 +444,16 @@ struct cxsr_latency {
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
#define to_intel_plane(x) container_of(x, struct intel_plane, base)
+/* DisplayPort/HDMI Hotplug line status bit mask */
+#define VLV_HDMIB_HOTPLUG_LIVE_STATUS (1 << 29)
+#define VLV_HDMIC_HOTPLUG_LIVE_STATUS (1 << 28)
+#define VLV_HDMID_HOTPLUG_LIVE_STATUS (1 << 27)
+
+/* DisplayPort/HDMI/DVI Hotplug line status bit mask */
+#define CORE_HDMIB_HOTPLUG_LIVE_STATUS (1 << 21)
+#define CORE_HDMIC_HOTPLUG_LIVE_STATUS (1 << 22)
+#define CORE_HDMID_HOTPLUG_LIVE_STATUS (1 << 23)
+
struct intel_hdmi {
u32 hdmi_reg;
int ddc_bus;
@@ -924,6 +924,61 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
return true;
}
+static int get_hdmi_hotplug_live_status(struct drm_device *dev,
+ struct intel_hdmi *intel_hdmi)
+{
+ uint32_t bit, reg;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_digital_port *intel_dig_port =
+ hdmi_to_dig_port(intel_hdmi);
+
+ DRM_DEBUG_KMS("Reading Live status");
+
+ /* Live status is available from Gen 6 onwards */
+ if (INTEL_INFO(dev)->gen < 6)
+ return connector_status_connected;
+
+ if (IS_VALLEYVIEW(dev)) {
+ switch (intel_dig_port->port) {
+ case PORT_B:
+ bit = VLV_HDMIB_HOTPLUG_LIVE_STATUS;
+ break;
+ case PORT_C:
+ bit = VLV_HDMIC_HOTPLUG_LIVE_STATUS;
+ break;
+ case PORT_D:
+ bit = VLV_HDMID_HOTPLUG_LIVE_STATUS;
+ break;
+ default:
+ DRM_ERROR("Unrecognized port is encountered\n");
+ return connector_status_unknown;
+ }
+ reg = I915_READ(PORT_HOTPLUG_STAT);
+
+ } else {
+ switch (intel_dig_port->port) {
+ case PORT_B:
+ bit = CORE_HDMIB_HOTPLUG_LIVE_STATUS;
+ break;
+ case PORT_C:
+ bit = CORE_HDMIC_HOTPLUG_LIVE_STATUS;
+ break;
+ case PORT_D:
+ bit = CORE_HDMID_HOTPLUG_LIVE_STATUS;
+ break;
+ default:
+ DRM_ERROR("Unrecognized port is encountered\n");
+ return connector_status_unknown;
+ }
+
+ reg = I915_READ(SDEISR);
+ }
+
+ /* Return connector status */
+ return ((reg & bit) ?
+ connector_status_connected : connector_status_disconnected);
+}
+
static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector, bool force)
{
@@ -939,24 +994,32 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, drm_get_connector_name(connector));
+ status = get_hdmi_hotplug_live_status(dev, intel_hdmi);
+
intel_hdmi->has_hdmi_sink = false;
intel_hdmi->has_audio = false;
intel_hdmi->rgb_quant_range_selectable = false;
- edid = drm_get_edid(connector,
- intel_gmbus_get_adapter(dev_priv,
- intel_hdmi->ddc_bus));
- if (edid) {
- if (edid->input & DRM_EDID_INPUT_DIGITAL) {
- status = connector_status_connected;
- if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
- intel_hdmi->has_hdmi_sink =
+ if (status == connector_status_connected) {
+ edid = drm_get_edid(connector,
+ intel_gmbus_get_adapter(dev_priv,
+ intel_hdmi->ddc_bus));
+ if (edid) {
+ if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+ status = connector_status_connected;
+ if (intel_hdmi->force_audio !=
+ HDMI_AUDIO_OFF_DVI)
+ 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 =
- drm_rgb_quant_range_selectable(edid);
+ intel_hdmi->has_audio =
+ drm_detect_monitor_audio(edid);
+ intel_hdmi->rgb_quant_range_selectable =
+ drm_rgb_quant_range_selectable(edid);
+ }
+ kfree(edid);
+ } else {
+ status = connector_status_disconnected;
}
- kfree(edid);
}
if (status == connector_status_connected) {