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@xxxxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx