diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hotplug.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_hotplug.c | 203 |
1 files changed, 99 insertions, 104 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 99d3a3c7989e..a091442efba4 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -23,8 +23,6 @@ #include <linux/kernel.h> -#include <drm/i915_drm.h> - #include "i915_drv.h" #include "intel_display_types.h" #include "intel_hotplug.h" @@ -89,29 +87,16 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, enum port port) { - switch (port) { - case PORT_A: - return HPD_PORT_A; - case PORT_B: - return HPD_PORT_B; - case PORT_C: - return HPD_PORT_C; - case PORT_D: - return HPD_PORT_D; - case PORT_E: - return HPD_PORT_E; - case PORT_F: - if (IS_CNL_WITH_PORT_F(dev_priv)) - return HPD_PORT_E; - return HPD_PORT_F; - case PORT_G: - return HPD_PORT_G; - case PORT_H: - return HPD_PORT_H; - case PORT_I: - return HPD_PORT_I; + enum phy phy = intel_port_to_phy(dev_priv, port); + + switch (phy) { + case PHY_F: + return IS_CNL_WITH_PORT_F(dev_priv) ? HPD_PORT_E : HPD_PORT_F; + case PHY_A ... PHY_E: + case PHY_G ... PHY_I: + return HPD_PORT_A + phy - PHY_A; default: - MISSING_CASE(port); + MISSING_CASE(phy); return HPD_NONE; } } @@ -120,6 +105,20 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, #define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) #define HPD_RETRY_DELAY 1000 +static enum hpd_pin +intel_connector_hpd_pin(struct intel_connector *connector) +{ + struct intel_encoder *encoder = intel_attached_encoder(connector); + + /* + * MST connectors get their encoder attached dynamically + * so need to make sure we have an encoder here. But since + * MST encoders have their hpd_pin set to HPD_NONE we don't + * have to special case them beyond that. + */ + return encoder ? encoder->hpd_pin : HPD_NONE; +} + /** * intel_hpd_irq_storm_detect - gather stats and detect HPD IRQ storm on a pin * @dev_priv: private driver data pointer @@ -171,10 +170,13 @@ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, hpd->stats[pin].count += increment; if (hpd->stats[pin].count > threshold) { hpd->stats[pin].state = HPD_MARK_DISABLED; - DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); + drm_dbg_kms(&dev_priv->drm, + "HPD interrupt storm detected on PIN %d\n", pin); storm = true; } else { - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, + drm_dbg_kms(&dev_priv->drm, + "Received HPD interrupt on PIN %d - cnt: %d\n", + pin, hpd->stats[pin].count); } @@ -185,37 +187,32 @@ static void intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; - struct intel_connector *intel_connector; - struct intel_encoder *intel_encoder; - struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - enum hpd_pin pin; + struct intel_connector *connector; bool hpd_disabled = false; lockdep_assert_held(&dev_priv->irq_lock); drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->polled != DRM_CONNECTOR_POLL_HPD) - continue; + for_each_intel_connector_iter(connector, &conn_iter) { + enum hpd_pin pin; - intel_connector = to_intel_connector(connector); - intel_encoder = intel_connector->encoder; - if (!intel_encoder) + if (connector->base.polled != DRM_CONNECTOR_POLL_HPD) continue; - pin = intel_encoder->hpd_pin; + pin = intel_connector_hpd_pin(connector); if (pin == HPD_NONE || dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) continue; - DRM_INFO("HPD interrupt storm detected on connector %s: " + drm_info(&dev_priv->drm, + "HPD interrupt storm detected on connector %s: " "switching from hotplug detection to polling\n", - connector->name); + connector->base.name); dev_priv->hotplug.stats[pin].state = HPD_DISABLED; - connector->polled = DRM_CONNECTOR_POLL_CONNECT - | DRM_CONNECTOR_POLL_DISCONNECT; + connector->base.polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; hpd_disabled = true; } drm_connector_list_iter_end(&conn_iter); @@ -234,40 +231,38 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) container_of(work, typeof(*dev_priv), hotplug.reenable_work.work); struct drm_device *dev = &dev_priv->drm; + struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; intel_wakeref_t wakeref; enum hpd_pin pin; wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); spin_lock_irq(&dev_priv->irq_lock); - for_each_hpd_pin(pin) { - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; - if (dev_priv->hotplug.stats[pin].state != HPD_DISABLED) + drm_connector_list_iter_begin(dev, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + pin = intel_connector_hpd_pin(connector); + if (pin == HPD_NONE || + dev_priv->hotplug.stats[pin].state != HPD_DISABLED) continue; - dev_priv->hotplug.stats[pin].state = HPD_ENABLED; - - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - struct intel_connector *intel_connector = to_intel_connector(connector); - - /* Don't check MST ports, they don't have pins */ - if (!intel_connector->mst_port && - intel_connector->encoder->hpd_pin == pin) { - if (connector->polled != intel_connector->polled) - DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", - connector->name); - connector->polled = intel_connector->polled; - if (!connector->polled) - connector->polled = DRM_CONNECTOR_POLL_HPD; - } - } - drm_connector_list_iter_end(&conn_iter); + if (connector->base.polled != connector->polled) + drm_dbg(&dev_priv->drm, + "Reenabling HPD on connector %s\n", + connector->base.name); + connector->base.polled = connector->polled; } + drm_connector_list_iter_end(&conn_iter); + + for_each_hpd_pin(pin) { + if (dev_priv->hotplug.stats[pin].state == HPD_DISABLED) + dev_priv->hotplug.stats[pin].state = HPD_ENABLED; + } + if (dev_priv->display_irqs_enabled && dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); @@ -281,7 +276,7 @@ intel_encoder_hotplug(struct intel_encoder *encoder, struct drm_device *dev = connector->base.dev; enum drm_connector_status old_status; - WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex)); old_status = connector->base.status; connector->base.status = @@ -290,11 +285,12 @@ intel_encoder_hotplug(struct intel_encoder *encoder, if (old_status == connector->base.status) return INTEL_HOTPLUG_UNCHANGED; - DRM_DEBUG_KMS("[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)); + 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)); return INTEL_HOTPLUG_CHANGED; } @@ -361,16 +357,14 @@ static void i915_hotplug_work_func(struct work_struct *work) container_of(work, struct drm_i915_private, hotplug.hotplug_work.work); struct drm_device *dev = &dev_priv->drm; - struct intel_connector *intel_connector; - struct intel_encoder *intel_encoder; - struct drm_connector *connector; struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; u32 changed = 0, retry = 0; u32 hpd_event_bits; u32 hpd_retry_bits; mutex_lock(&dev->mode_config.mutex); - DRM_DEBUG_KMS("running encoder hotplug functions\n"); + drm_dbg_kms(&dev_priv->drm, "running encoder hotplug functions\n"); spin_lock_irq(&dev_priv->irq_lock); @@ -385,21 +379,25 @@ static void i915_hotplug_work_func(struct work_struct *work) spin_unlock_irq(&dev_priv->irq_lock); drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { + for_each_intel_connector_iter(connector, &conn_iter) { + enum hpd_pin pin; u32 hpd_bit; - intel_connector = to_intel_connector(connector); - if (!intel_connector->encoder) + pin = intel_connector_hpd_pin(connector); + if (pin == HPD_NONE) continue; - intel_encoder = intel_connector->encoder; - hpd_bit = BIT(intel_encoder->hpd_pin); + + hpd_bit = BIT(pin); if ((hpd_event_bits | hpd_retry_bits) & hpd_bit) { - DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", - connector->name, intel_encoder->hpd_pin); + struct intel_encoder *encoder = + intel_attached_encoder(connector); + + drm_dbg_kms(&dev_priv->drm, + "Connector %s (pin %i) received hotplug event.\n", + connector->base.name, pin); - switch (intel_encoder->hotplug(intel_encoder, - intel_connector, - hpd_event_bits & hpd_bit)) { + switch (encoder->hotplug(encoder, connector, + hpd_event_bits & hpd_bit)) { case INTEL_HOTPLUG_UNCHANGED: break; case INTEL_HOTPLUG_CHANGED: @@ -481,9 +479,10 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, long_hpd = long_mask & BIT(pin); - DRM_DEBUG_DRIVER("digital hpd on [ENCODER:%d:%s] - %s\n", - encoder->base.base.id, encoder->base.name, - long_hpd ? "long" : "short"); + drm_dbg(&dev_priv->drm, + "digital hpd on [ENCODER:%d:%s] - %s\n", + encoder->base.base.id, encoder->base.name, + long_hpd ? "long" : "short"); queue_dig = true; if (long_hpd) { @@ -509,8 +508,9 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, * hotplug bits itself. So only WARN about unexpected * interrupts on saner platforms. */ - WARN_ONCE(!HAS_GMCH(dev_priv), - "Received HPD interrupt on pin %d although disabled\n", pin); + drm_WARN_ONCE(&dev_priv->drm, !HAS_GMCH(dev_priv), + "Received HPD interrupt on pin %d although disabled\n", + pin); continue; } @@ -601,8 +601,8 @@ static void i915_hpd_poll_init_work(struct work_struct *work) container_of(work, struct drm_i915_private, hotplug.poll_init_work); struct drm_device *dev = &dev_priv->drm; - struct drm_connector *connector; struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; bool enabled; mutex_lock(&dev->mode_config.mutex); @@ -610,23 +610,18 @@ static void i915_hpd_poll_init_work(struct work_struct *work) enabled = READ_ONCE(dev_priv->hotplug.poll_enabled); drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - struct intel_connector *intel_connector = - to_intel_connector(connector); - connector->polled = intel_connector->polled; - - /* MST has a dynamic intel_connector->encoder and it's reprobing - * is all handled by the MST helpers. */ - if (intel_connector->mst_port) + for_each_intel_connector_iter(connector, &conn_iter) { + enum hpd_pin pin; + + pin = intel_connector_hpd_pin(connector); + if (pin == HPD_NONE) continue; - if (!connector->polled && I915_HAS_HOTPLUG(dev_priv) && - intel_connector->encoder->hpd_pin > HPD_NONE) { - connector->polled = enabled ? - DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT : - DRM_CONNECTOR_POLL_HPD; - } + connector->base.polled = connector->polled; + + if (enabled && connector->base.polled == DRM_CONNECTOR_POLL_HPD) + connector->base.polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; } drm_connector_list_iter_end(&conn_iter); |