drm/i915: Reject unusable power sequencers

On ICP-ADP the pins used by the second PPS can be alternatively
muxed to some other function. In that case the second power
sequencer is unusable.

Unfortunately (on my ADL Thinkpad T14 gen3 at least) the
BIOS still likes to enable the VDD on the second PPS (due
to the VBT declaring the second bogus eDP panel) even when
not correctly muxed, so we need to deal with it somehow.
For now let's just initialize the PPS as normal, and then
use the normal eDP probe failure VDD off path to turn it off
(and release the wakeref the PPS init grabbed). The
alternative of just declaring that the platform has a single
PPS doesn't really work since it would cause the second eDP
probe to also try to use the first PPS and thus clobber the
state for the first (real) eDP panel.

Cc: Animesh Manna <animesh.manna@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221125173156.31689-7-ville.syrjala@linux.intel.com
Reviewed-by: Animesh Manna <animesh.manna@intel.com>
This commit is contained in:
Ville Syrjälä 2022-11-25 19:31:53 +02:00
parent d83804f22d
commit ba21bb2481
4 changed files with 38 additions and 11 deletions

View File

@ -5224,7 +5224,17 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
intel_bios_init_panel_early(dev_priv, &intel_connector->panel,
encoder->devdata);
intel_pps_init(intel_dp);
if (!intel_pps_init(intel_dp)) {
drm_info(&dev_priv->drm,
"[ENCODER:%d:%s] unusable PPS, disabling eDP\n",
encoder->base.base.id, encoder->base.name);
/*
* The BIOS may have still enabled VDD on the PPS even
* though it's unusable. Make sure we turn it back off
* and to release the power domain references/etc.
*/
goto out_vdd_off;
}
/* Cache DPCD and EDID for edp. */
has_dpcd = intel_edp_init_dpcd(intel_dp);

View File

@ -327,6 +327,18 @@ static int intel_num_pps(struct drm_i915_private *i915)
return 1;
}
static bool intel_pps_is_valid(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
if (intel_dp->pps.pps_idx == 1 &&
INTEL_PCH_TYPE(i915) >= PCH_ICP &&
INTEL_PCH_TYPE(i915) < PCH_MTP)
return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT;
return true;
}
static int
bxt_initial_pps_idx(struct drm_i915_private *i915, pps_check check)
{
@ -340,7 +352,7 @@ bxt_initial_pps_idx(struct drm_i915_private *i915, pps_check check)
return -1;
}
static void
static bool
pps_initial_setup(struct intel_dp *intel_dp)
{
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
@ -351,7 +363,7 @@ pps_initial_setup(struct intel_dp *intel_dp)
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
vlv_initial_power_sequencer_setup(intel_dp);
return;
return true;
}
/* first ask the VBT */
@ -377,13 +389,14 @@ pps_initial_setup(struct intel_dp *intel_dp)
"[ENCODER:%d:%s] no initial power sequencer, assuming %d\n",
encoder->base.base.id, encoder->base.name,
intel_dp->pps.pps_idx);
return;
} else {
drm_dbg_kms(&i915->drm,
"[ENCODER:%d:%s] initial power sequencer: %d\n",
encoder->base.base.id, encoder->base.name,
intel_dp->pps.pps_idx);
}
drm_dbg_kms(&i915->drm,
"[ENCODER:%d:%s] initial power sequencer: %d\n",
encoder->base.base.id, encoder->base.name,
intel_dp->pps.pps_idx);
return intel_pps_is_valid(intel_dp);
}
void intel_pps_reset_all(struct drm_i915_private *dev_priv)
@ -1504,9 +1517,10 @@ void intel_pps_encoder_reset(struct intel_dp *intel_dp)
}
}
void intel_pps_init(struct intel_dp *intel_dp)
bool intel_pps_init(struct intel_dp *intel_dp)
{
intel_wakeref_t wakeref;
bool ret;
intel_dp->pps.initializing = true;
INIT_DELAYED_WORK(&intel_dp->pps.panel_vdd_work, edp_panel_vdd_work);
@ -1514,12 +1528,14 @@ void intel_pps_init(struct intel_dp *intel_dp)
pps_init_timestamps(intel_dp);
with_intel_pps_lock(intel_dp, wakeref) {
pps_initial_setup(intel_dp);
ret = pps_initial_setup(intel_dp);
pps_init_delays(intel_dp);
pps_init_registers(intel_dp, false);
pps_vdd_init(intel_dp);
}
return ret;
}
static void pps_init_late(struct intel_dp *intel_dp)

View File

@ -40,7 +40,7 @@ void intel_pps_vdd_off_sync(struct intel_dp *intel_dp);
bool intel_pps_have_panel_power_or_vdd(struct intel_dp *intel_dp);
void intel_pps_wait_power_cycle(struct intel_dp *intel_dp);
void intel_pps_init(struct intel_dp *intel_dp);
bool intel_pps_init(struct intel_dp *intel_dp);
void intel_pps_init_late(struct intel_dp *intel_dp);
void intel_pps_encoder_reset(struct intel_dp *intel_dp);
void intel_pps_reset_all(struct drm_i915_private *i915);

View File

@ -6241,6 +6241,7 @@
#define CHASSIS_CLK_REQ_DURATION_MASK (0xf << 8)
#define CHASSIS_CLK_REQ_DURATION(x) ((x) << 8)
#define SBCLK_RUN_REFCLK_DIS (1 << 7)
#define ICP_SECOND_PPS_IO_SELECT REG_BIT(2)
#define SPT_PWM_GRANULARITY (1 << 0)
#define SOUTH_CHICKEN2 _MMIO(0xc2004)
#define FDI_MPHY_IOSFSB_RESET_STATUS (1 << 13)