This helps speed up driver init time, and puts off the eDP stuff until we actually need it. Signed-off-by: Jesse Barnes <jbarnes@xxxxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx