It takes awhile to fetch the DPCD and EDID for caching, so take it out
of the critical path to improve init time.

Signed-off-by: Jesse Barnes <jbar...@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_dp.c | 113 +++++++++++++++++++++++++++++-----------
 1 file changed, 82 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 738c4e6..763f235 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3001,6 +3001,20 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp)
        intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_NAK);
 }
 
+static void intel_flush_edp_cache_work(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp->attached_connector->base.dev;
+
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+
+       if (!is_edp(intel_dp))
+               return;
+
+       mutex_unlock(&dev->mode_config.mutex);
+       flush_work(&intel_dp->edp_cache_work);
+       mutex_lock(&dev->mode_config.mutex);
+}
+
 /*
  * According to DP spec
  * 5.1.2:
@@ -3028,6 +3042,8 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
                return;
        }
 
+       intel_flush_edp_cache_work(intel_dp);
+
        /* Now read the DPCD to see if it's actually running */
        if (!intel_dp_get_dpcd(intel_dp)) {
                return;
@@ -3063,6 +3079,8 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
        uint8_t *dpcd = intel_dp->dpcd;
        uint8_t type;
 
+       intel_flush_edp_cache_work(intel_dp);
+
        if (!intel_dp_get_dpcd(intel_dp))
                return connector_status_disconnected;
 
@@ -3180,13 +3198,23 @@ g4x_dp_detect(struct intel_dp *intel_dp)
        return intel_dp_detect_dpcd(intel_dp);
 }
 
+static bool intel_connector_has_edid(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+
+       intel_flush_edp_cache_work(intel_dp);
+
+       return intel_connector->edid != NULL;
+}
+
 static struct edid *
 intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
 
        /* use cached edid if we have one */
-       if (intel_connector->edid) {
+       if (intel_connector_has_edid(connector)) {
                /* invalid edid */
                if (IS_ERR(intel_connector->edid))
                        return NULL;
@@ -3203,7 +3231,7 @@ intel_dp_get_edid_modes(struct drm_connector *connector, 
struct i2c_adapter *ada
        struct intel_connector *intel_connector = to_intel_connector(connector);
 
        /* use cached edid if we have one */
-       if (intel_connector->edid) {
+       if (intel_connector_has_edid(connector)) {
                /* invalid edid */
                if (IS_ERR(intel_connector->edid))
                        return 0;
@@ -3226,6 +3254,8 @@ intel_dp_detect(struct drm_connector *connector, bool 
force)
        enum drm_connector_status status;
        struct edid *edid = NULL;
 
+       intel_flush_edp_cache_work(intel_dp);
+
        intel_runtime_pm_get(dev_priv);
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
@@ -3420,6 +3450,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
        drm_encoder_cleanup(encoder);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               cancel_work_sync(&intel_dp->edp_cache_work);
                mutex_lock(&dev->mode_config.mutex);
                edp_panel_vdd_off_sync(intel_dp);
                mutex_unlock(&dev->mode_config.mutex);
@@ -3693,21 +3724,30 @@ intel_dp_init_panel_power_sequencer_registers(struct 
drm_device *dev,
                      I915_READ(pp_div_reg));
 }
 
-static bool intel_edp_init_connector(struct intel_dp *intel_dp,
-                                    struct intel_connector *intel_connector,
-                                    struct edp_power_seq *power_seq)
+static void intel_edp_cache_work(struct work_struct *work)
 {
+       struct intel_dp *intel_dp = container_of(work, struct intel_dp,
+                                                edp_cache_work);
+       struct intel_connector *intel_connector = intel_dp->attached_connector;
        struct drm_connector *connector = &intel_connector->base;
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *fixed_mode = NULL;
+       enum port port = intel_dig_port->port;
        bool has_dpcd;
        struct drm_display_mode *scan;
        struct edid *edid;
+       int error;
 
-       if (!is_edp(intel_dp))
-               return true;
+       mutex_lock(&dev->mode_config.mutex);
+
+       error = intel_dp_i2c_init(intel_dp, intel_connector,
+                                 intel_dp->i2c_name);
+       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
+            error, port_name(port));
+
+       intel_dp->psr_setup_done = false;
 
        /* Cache DPCD and EDID for edp. */
        edp_panel_vdd_on(intel_dp);
@@ -3719,10 +3759,15 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
                        dev_priv->no_aux_handshake =
                                intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
                                DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+               intel_dp->dpcd_valid = true;
        } else {
-               /* if this fails, presume the device is a ghost */
-               DRM_INFO("failed to retrieve link info, disabling eDP\n");
-               return false;
+               i2c_del_adapter(&intel_dp->adapter);
+               cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               edp_panel_vdd_off_sync(intel_dp);
+               drm_sysfs_connector_remove(connector);
+               drm_connector_cleanup(connector);
+               mutex_unlock(&dev->mode_config.mutex);
+               return;
        }
 
        /* We now know it's not a ghost, init power sequence regs. */
@@ -3750,7 +3795,6 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
                        break;
                }
        }
-
        /* fallback to VBT if available for eDP */
        if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
                fixed_mode = drm_mode_duplicate(dev,
@@ -3760,9 +3804,23 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
        }
 
        intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
-       intel_panel_setup_backlight(connector);
 
-       return true;
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void intel_edp_init_connector(struct intel_dp *intel_dp,
+                                    struct intel_connector *intel_connector)
+{
+       struct drm_connector *connector = &intel_connector->base;
+
+       if (!is_edp(intel_dp))
+               return;
+
+       INIT_WORK(&intel_dp->edp_cache_work, intel_edp_cache_work);
+
+       schedule_work(&intel_dp->edp_cache_work);
+
+       intel_panel_setup_backlight(connector);
 }
 
 bool
@@ -3817,8 +3875,7 @@ intel_dp_init_connector(struct intel_digital_port 
*intel_dig_port,
        connector->interlace_allowed = true;
        connector->doublescan_allowed = 0;
 
-       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
-                         edp_panel_vdd_work);
+       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, edp_panel_vdd_work);
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
@@ -3873,27 +3930,21 @@ intel_dp_init_connector(struct intel_digital_port 
*intel_dig_port,
 
        if (is_edp(intel_dp)) {
                intel_dp_init_panel_power_timestamps(intel_dp);
-               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+               intel_dp_init_panel_power_sequencer(dev, intel_dp);
        }
 
-       error = intel_dp_i2c_init(intel_dp, intel_connector, name);
-       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
-            error, port_name(port));
+       intel_dp->i2c_name = name;
+
+       if (!is_edp(intel_dp)) {
+               error = intel_dp_i2c_init(intel_dp, intel_connector, name);
+               WARN(error,
+                    "intel_dp_i2c_init failed with error %d for port %c\n",
+                    error, port_name(port));
+       }
 
        intel_dp->psr_setup_done = false;
 
-       if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
-               i2c_del_adapter(&intel_dp->adapter);
-               if (is_edp(intel_dp)) {
-                       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-                       mutex_lock(&dev->mode_config.mutex);
-                       edp_panel_vdd_off_sync(intel_dp);
-                       mutex_unlock(&dev->mode_config.mutex);
-               }
-               drm_sysfs_connector_remove(connector);
-               drm_connector_cleanup(connector);
-               return false;
-       }
+       intel_edp_init_connector(intel_dp, intel_connector);
 
        intel_dp_add_properties(intel_dp, connector);
 
-- 
1.8.4.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to