[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