[Intel-gfx] [PATCH 5/6] drm/i915/dp: push eDP caching out into a work queue

Jesse Barnes jbarnes at virtuousgeek.org
Wed Mar 5 23:48:30 CET 2014


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 <jbarnes at 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




More information about the Intel-gfx mailing list