mirror of https://gitee.com/openkylin/linux.git
drm/i915: Read out the power sequencer port assignment on resume on vlv/chv
When we suspend we turn everything off so the pps should be idle, and we also (or at least should) disable all power wells which will reset the power sequencer port assignment. So when we resume all power sequencers should be in their reset state. However it's at least theoretically possible that the BIOS would touch the power seuqencer(s), so to be safe we ought to read out the current port assignment like we do at driver init time. To do that we can simply call vlv_initial_power_sequencer_setup() from the encoder ->reset() hook before calling intel_edp_panel_vdd_sanitize(). There's no danger or clobbering the pps delays since we now have those stored within intel_dp and we don't change them once initialized. This will make sure that the vdd state gets correctly tracked post-resume in case the BIOS enabled it. We need to shuffle things around a bit to get the locking right, and while at it, make intel_edp_panel_vdd_sanitize() static and move it around a bit to avoid a forward declaration. Cc: Imre Deak <imre.deak@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
1e74a32446
commit
49e6bc51bc
|
@ -4677,9 +4677,52 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
|
||||||
pps_unlock(intel_dp);
|
pps_unlock(intel_dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
enum intel_display_power_domain power_domain;
|
||||||
|
|
||||||
|
lockdep_assert_held(&dev_priv->pps_mutex);
|
||||||
|
|
||||||
|
if (!edp_have_panel_vdd(intel_dp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The VDD bit needs a power domain reference, so if the bit is
|
||||||
|
* already enabled when we boot or resume, grab this reference and
|
||||||
|
* schedule a vdd off, so we don't hold on to the reference
|
||||||
|
* indefinitely.
|
||||||
|
*/
|
||||||
|
DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
|
||||||
|
power_domain = intel_display_port_power_domain(&intel_dig_port->base);
|
||||||
|
intel_display_power_get(dev_priv, power_domain);
|
||||||
|
|
||||||
|
edp_panel_vdd_schedule_off(intel_dp);
|
||||||
|
}
|
||||||
|
|
||||||
static void intel_dp_encoder_reset(struct drm_encoder *encoder)
|
static void intel_dp_encoder_reset(struct drm_encoder *encoder)
|
||||||
{
|
{
|
||||||
intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder));
|
struct intel_dp *intel_dp;
|
||||||
|
|
||||||
|
if (to_intel_encoder(encoder)->type != INTEL_OUTPUT_EDP)
|
||||||
|
return;
|
||||||
|
|
||||||
|
intel_dp = enc_to_intel_dp(encoder);
|
||||||
|
|
||||||
|
pps_lock(intel_dp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read out the current power sequencer assignment,
|
||||||
|
* in case the BIOS did something with it.
|
||||||
|
*/
|
||||||
|
if (IS_VALLEYVIEW(encoder->dev))
|
||||||
|
vlv_initial_power_sequencer_setup(intel_dp);
|
||||||
|
|
||||||
|
intel_edp_panel_vdd_sanitize(intel_dp);
|
||||||
|
|
||||||
|
pps_unlock(intel_dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct drm_connector_funcs intel_dp_connector_funcs = {
|
static const struct drm_connector_funcs intel_dp_connector_funcs = {
|
||||||
|
@ -5150,37 +5193,6 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
|
||||||
return downclock_mode;
|
return downclock_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder)
|
|
||||||
{
|
|
||||||
struct drm_device *dev = intel_encoder->base.dev;
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
struct intel_dp *intel_dp;
|
|
||||||
enum intel_display_power_domain power_domain;
|
|
||||||
|
|
||||||
if (intel_encoder->type != INTEL_OUTPUT_EDP)
|
|
||||||
return;
|
|
||||||
|
|
||||||
intel_dp = enc_to_intel_dp(&intel_encoder->base);
|
|
||||||
|
|
||||||
pps_lock(intel_dp);
|
|
||||||
|
|
||||||
if (!edp_have_panel_vdd(intel_dp))
|
|
||||||
goto out;
|
|
||||||
/*
|
|
||||||
* The VDD bit needs a power domain reference, so if the bit is
|
|
||||||
* already enabled when we boot or resume, grab this reference and
|
|
||||||
* schedule a vdd off, so we don't hold on to the reference
|
|
||||||
* indefinitely.
|
|
||||||
*/
|
|
||||||
DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
|
|
||||||
power_domain = intel_display_port_power_domain(intel_encoder);
|
|
||||||
intel_display_power_get(dev_priv, power_domain);
|
|
||||||
|
|
||||||
edp_panel_vdd_schedule_off(intel_dp);
|
|
||||||
out:
|
|
||||||
pps_unlock(intel_dp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool intel_edp_init_connector(struct intel_dp *intel_dp,
|
static bool intel_edp_init_connector(struct intel_dp *intel_dp,
|
||||||
struct intel_connector *intel_connector)
|
struct intel_connector *intel_connector)
|
||||||
{
|
{
|
||||||
|
@ -5200,7 +5212,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
|
||||||
if (!is_edp(intel_dp))
|
if (!is_edp(intel_dp))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
intel_edp_panel_vdd_sanitize(intel_encoder);
|
pps_lock(intel_dp);
|
||||||
|
intel_edp_panel_vdd_sanitize(intel_dp);
|
||||||
|
pps_unlock(intel_dp);
|
||||||
|
|
||||||
/* Cache DPCD and EDID for edp. */
|
/* Cache DPCD and EDID for edp. */
|
||||||
has_dpcd = intel_dp_get_dpcd(intel_dp);
|
has_dpcd = intel_dp_get_dpcd(intel_dp);
|
||||||
|
|
|
@ -981,7 +981,6 @@ bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
|
||||||
void intel_edp_backlight_on(struct intel_dp *intel_dp);
|
void intel_edp_backlight_on(struct intel_dp *intel_dp);
|
||||||
void intel_edp_backlight_off(struct intel_dp *intel_dp);
|
void intel_edp_backlight_off(struct intel_dp *intel_dp);
|
||||||
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
|
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
|
||||||
void intel_edp_panel_vdd_sanitize(struct intel_encoder *intel_encoder);
|
|
||||||
void intel_edp_panel_on(struct intel_dp *intel_dp);
|
void intel_edp_panel_on(struct intel_dp *intel_dp);
|
||||||
void intel_edp_panel_off(struct intel_dp *intel_dp);
|
void intel_edp_panel_off(struct intel_dp *intel_dp);
|
||||||
void intel_edp_psr_enable(struct intel_dp *intel_dp);
|
void intel_edp_psr_enable(struct intel_dp *intel_dp);
|
||||||
|
|
Loading…
Reference in New Issue