This helps speed up driver init time, and puts off the eDP stuff until
we actually need it.

Signed-off-by: Jesse Barnes <jbar...@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_dp.c  | 103 ++++++++++++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_drv.h |   3 ++
 2 files changed, 73 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5256c06..2abd339 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3768,6 +3768,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("DPCD: %*ph\n", (int) sizeof(intel_dp->dpcd), 
intel_dp->dpcd);
 
+       if (intel_dp->dpcd_valid)
+               return true;
+
        if (intel_dp->dpcd[DP_DPCD_REV] == 0)
                return false; /* DPCD not present */
 
@@ -4012,6 +4015,25 @@ go_again:
        return -EINVAL;
 }
 
+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;
+
+       /*
+        * FIXME: we need to synchronize this at a higher level, like the
+        * first mode set or other display I/O activity.  Maybe re-use
+        * async mode setting entry points?
+        */
+       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:
@@ -4044,6 +4066,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;
@@ -4079,6 +4103,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;
 
@@ -4215,13 +4241,23 @@ g4x_dp_detect(struct intel_dp *intel_dp)
        return intel_dp_detect_dpcd(intel_dp);
 }
 
+static bool intel_connector_has_edid(struct intel_connector *intel_connector)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+
+       intel_flush_edp_cache_work(intel_dp);
+
+       return intel_connector->edid != NULL;
+}
+
 static struct edid *
 intel_dp_get_edid(struct intel_dp *intel_dp)
 {
        struct intel_connector *intel_connector = intel_dp->attached_connector;
 
        /* use cached edid if we have one */
-       if (intel_connector->edid) {
+       if (intel_connector_has_edid(intel_connector)) {
                /* invalid edid */
                if (IS_ERR(intel_connector->edid))
                        return NULL;
@@ -4516,6 +4552,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
        intel_dp_mst_encoder_cleanup(intel_dig_port);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               cancel_work_sync(&intel_dp->edp_cache_work);
                /*
                 * vdd might still be enabled do to the delayed vdd off.
                 * Make sure vdd is actually turned off here.
@@ -5316,9 +5353,11 @@ intel_dp_drrs_init(struct intel_connector 
*intel_connector,
        return downclock_mode;
 }
 
-static bool intel_edp_init_connector(struct intel_dp *intel_dp,
-                                    struct intel_connector *intel_connector)
+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 intel_encoder *intel_encoder = &intel_dig_port->base;
@@ -5329,12 +5368,10 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
        bool has_dpcd;
        struct drm_display_mode *scan;
        struct edid *edid;
-       enum pipe pipe = INVALID_PIPE;
 
        dev_priv->drrs.type = DRRS_NOT_SUPPORTED;
 
-       if (!is_edp(intel_dp))
-               return true;
+       mutex_lock(&dev->mode_config.mutex);
 
        pps_lock(intel_dp);
        intel_edp_panel_vdd_sanitize(intel_dp);
@@ -5348,10 +5385,13 @@ 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;
+               cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               edp_panel_vdd_off_sync(intel_dp);
+               drm_connector_cleanup(connector);
+               mutex_unlock(&dev->mode_config.mutex);
+               return;
        }
 
        /* We now know it's not a ghost, init power sequence regs. */
@@ -5359,7 +5399,6 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
        intel_dp_init_panel_power_sequencer_registers(dev, intel_dp);
        pps_unlock(intel_dp);
 
-       mutex_lock(&dev->mode_config.mutex);
        edid = drm_get_edid(connector, &intel_dp->aux.ddc);
        if (edid) {
                if (drm_add_edid_modes(connector, edid)) {
@@ -5384,7 +5423,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,
@@ -5392,7 +5430,26 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
                if (fixed_mode)
                        fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
        }
+
+       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_connector->panel.backlight_power = intel_edp_backlight_power;
+
        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;
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       enum pipe pipe = INVALID_PIPE;
+
+       if (!is_edp(intel_dp))
+               return;
+
+       INIT_WORK(&intel_dp->edp_cache_work, intel_edp_cache_work);
+
+       schedule_work(&intel_dp->edp_cache_work);
 
        if (IS_VALLEYVIEW(dev)) {
                intel_dp->edp_notifier.notifier_call = edp_notify_handler;
@@ -5418,11 +5475,7 @@ static bool intel_edp_init_connector(struct intel_dp 
*intel_dp,
                              pipe_name(pipe));
        }
 
-       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
-       intel_connector->panel.backlight_power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector, pipe);
-
-       return true;
 }
 
 bool
@@ -5488,8 +5541,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_connector_register(connector);
@@ -5538,22 +5590,7 @@ intel_dp_init_connector(struct intel_digital_port 
*intel_dig_port,
                }
        }
 
-       if (!intel_edp_init_connector(intel_dp, intel_connector)) {
-               drm_dp_aux_unregister(&intel_dp->aux);
-               if (is_edp(intel_dp)) {
-                       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-                       /*
-                        * vdd might still be enabled do to the delayed vdd off.
-                        * Make sure vdd is actually turned off here.
-                        */
-                       pps_lock(intel_dp);
-                       edp_panel_vdd_off_sync(intel_dp);
-                       pps_unlock(intel_dp);
-               }
-               drm_connector_unregister(connector);
-               drm_connector_cleanup(connector);
-               return false;
-       }
+       intel_edp_init_connector(intel_dp, intel_connector);
 
        intel_dp_add_properties(intel_dp, connector);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a1baaa1..8cee4a2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -656,12 +656,15 @@ struct intel_dp {
        bool can_mst; /* this port supports mst */
        bool is_mst;
        int active_mst_links;
+       bool dpcd_valid; /* for eDP DPCD caching */
        /* connector directly attached - won't be use for modeset in mst world 
*/
        struct intel_connector *attached_connector;
 
        /* mst connector list */
        struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES];
        struct drm_dp_mst_topology_mgr mst_mgr;
+       struct work_struct edp_cache_work;
+       const char *i2c_name;
 
        uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index);
        /*
-- 
1.9.1

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

Reply via email to