summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_hotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hotplug.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_hotplug.c53
1 files changed, 43 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c
index 4f6f560e093e..3f1d7b804a66 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug.c
@@ -89,6 +89,15 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
{
enum phy phy = intel_port_to_phy(dev_priv, port);
+ /*
+ * RKL + TGP PCH is a special case; we effectively choose the hpd_pin
+ * based on the DDI rather than the PHY (i.e., the last two outputs
+ * shold be HPD_PORT_{D,E} rather than {C,D}. Note that this differs
+ * from the behavior of both TGL+TGP and RKL+CMP.
+ */
+ if (IS_ROCKETLAKE(dev_priv) && HAS_PCH_TGP(dev_priv))
+ return HPD_PORT_A + port - PORT_A;
+
switch (phy) {
case PHY_F:
return IS_CNL_WITH_PORT_F(dev_priv) ? HPD_PORT_E : HPD_PORT_F;
@@ -274,24 +283,30 @@ intel_encoder_hotplug(struct intel_encoder *encoder,
{
struct drm_device *dev = connector->base.dev;
enum drm_connector_status old_status;
+ u64 old_epoch_counter;
+ bool ret = false;
drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex));
old_status = connector->base.status;
+ old_epoch_counter = connector->base.epoch_counter;
connector->base.status =
drm_helper_probe_detect(&connector->base, NULL, false);
- if (old_status == connector->base.status)
- return INTEL_HOTPLUG_UNCHANGED;
-
- drm_dbg_kms(&to_i915(dev)->drm,
- "[CONNECTOR:%d:%s] status updated from %s to %s\n",
- connector->base.base.id,
- connector->base.name,
- drm_get_connector_status_name(old_status),
- drm_get_connector_status_name(connector->base.status));
+ if (old_epoch_counter != connector->base.epoch_counter)
+ ret = true;
- return INTEL_HOTPLUG_CHANGED;
+ if (ret) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s (epoch counter %llu->%llu)\n",
+ connector->base.base.id,
+ connector->base.name,
+ drm_get_connector_status_name(old_status),
+ drm_get_connector_status_name(connector->base.status),
+ old_epoch_counter,
+ connector->base.epoch_counter);
+ return INTEL_HOTPLUG_CHANGED;
+ }
+ return INTEL_HOTPLUG_UNCHANGED;
}
static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder)
@@ -347,6 +362,24 @@ static void i915_digport_work_func(struct work_struct *work)
}
}
+/**
+ * intel_hpd_trigger_irq - trigger an hpd irq event for a port
+ * @dig_port: digital port
+ *
+ * Trigger an HPD interrupt event for the given port, emulating a short pulse
+ * generated by the sink, and schedule the dig port work to handle it.
+ */
+void intel_hpd_trigger_irq(struct intel_digital_port *dig_port)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+
+ spin_lock_irq(&i915->irq_lock);
+ i915->hotplug.short_port_mask |= BIT(dig_port->base.port);
+ spin_unlock_irq(&i915->irq_lock);
+
+ queue_work(i915->hotplug.dp_wq, &i915->hotplug.dig_port_work);
+}
+
/*
* Handle hotplug events outside the interrupt handler proper.
*/