[Intel-gfx] [PATCH] drm/i915/dp: move edp init to work queue

Jesse Barnes jbarnes at virtuousgeek.org
Wed Mar 18 11:41:49 PDT 2015


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

Signed-off-by: Jesse Barnes <jbarnes at 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



More information about the Intel-gfx mailing list