summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_ddi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_ddi.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c137
1 files changed, 82 insertions, 55 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 69ecf2a3d6c6..0f1ec2a98cc8 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -31,6 +31,7 @@
#include <drm/drm_privacy_screen_consumer.h>
#include "i915_drv.h"
+#include "i915_reg.h"
#include "intel_audio.h"
#include "intel_audio_regs.h"
#include "intel_backlight.h"
@@ -44,6 +45,7 @@
#include "intel_display_power.h"
#include "intel_display_types.h"
#include "intel_dkl_phy.h"
+#include "intel_dkl_phy_regs.h"
#include "intel_dp.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
@@ -55,14 +57,15 @@
#include "intel_hdcp.h"
#include "intel_hdmi.h"
#include "intel_hotplug.h"
+#include "intel_hti.h"
#include "intel_lspcon.h"
+#include "intel_mg_phy_regs.h"
#include "intel_pps.h"
#include "intel_psr.h"
#include "intel_quirks.h"
#include "intel_snps_phy.h"
#include "intel_sprite.h"
#include "intel_tc.h"
-#include "intel_tc_phy_regs.h"
#include "intel_vdsc.h"
#include "intel_vrr.h"
#include "skl_scaler.h"
@@ -845,22 +848,65 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
}
static enum intel_display_power_domain
-intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port)
+intel_ddi_main_link_aux_domain(struct intel_digital_port *dig_port,
+ const struct intel_crtc_state *crtc_state)
{
- /* ICL+ HW requires corresponding AUX IOs to be powered up for PSR with
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
+
+ /*
+ * ICL+ HW requires corresponding AUX IOs to be powered up for PSR with
* DC states enabled at the same time, while for driver initiated AUX
* transfers we need the same AUX IOs to be powered but with DC states
- * disabled. Accordingly use the AUX power domain here which leaves DC
- * states enabled.
- * However, for non-A AUX ports the corresponding non-EDP transcoders
- * would have already enabled power well 2 and DC_OFF. This means we can
- * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a
- * specific AUX_IO reference without powering up any extra wells.
- * Note that PSR is enabled only on Port A even though this function
- * returns the correct domain for other ports too.
+ * disabled. Accordingly use the AUX_IO_<port> power domain here which
+ * leaves DC states enabled.
+ *
+ * Before MTL TypeC PHYs (in all TypeC modes and both DP/HDMI) also require
+ * AUX IO to be enabled, but all these require DC_OFF to be enabled as
+ * well, so we can acquire a wider AUX_<port> power domain reference
+ * instead of a specific AUX_IO_<port> reference without powering up any
+ * extra wells.
*/
- return dig_port->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
- intel_aux_power_domain(dig_port);
+ if (intel_encoder_can_psr(&dig_port->base))
+ return intel_display_power_aux_io_domain(i915, dig_port->aux_ch);
+ else if (DISPLAY_VER(i915) < 14 &&
+ (intel_crtc_has_dp_encoder(crtc_state) ||
+ intel_phy_is_tc(i915, phy)))
+ return intel_aux_power_domain(dig_port);
+ else
+ return POWER_DOMAIN_INVALID;
+}
+
+static void
+main_link_aux_power_domain_get(struct intel_digital_port *dig_port,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum intel_display_power_domain domain =
+ intel_ddi_main_link_aux_domain(dig_port, crtc_state);
+
+ drm_WARN_ON(&i915->drm, dig_port->aux_wakeref);
+
+ if (domain == POWER_DOMAIN_INVALID)
+ return;
+
+ dig_port->aux_wakeref = intel_display_power_get(i915, domain);
+}
+
+static void
+main_link_aux_power_domain_put(struct intel_digital_port *dig_port,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ enum intel_display_power_domain domain =
+ intel_ddi_main_link_aux_domain(dig_port, crtc_state);
+ intel_wakeref_t wf;
+
+ wf = fetch_and_zero(&dig_port->aux_wakeref);
+ if (!wf)
+ return;
+
+ intel_display_power_put(i915, domain, wf);
}
static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
@@ -868,7 +914,6 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_digital_port *dig_port;
- enum phy phy = intel_port_to_phy(dev_priv, encoder->port);
/*
* TODO: Add support for MST encoders. Atm, the following should never
@@ -887,17 +932,7 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
dig_port->ddi_io_power_domain);
}
- /*
- * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
- * ports.
- */
- if (intel_crtc_has_dp_encoder(crtc_state) ||
- intel_phy_is_tc(dev_priv, phy)) {
- drm_WARN_ON(&dev_priv->drm, dig_port->aux_wakeref);
- dig_port->aux_wakeref =
- intel_display_power_get(dev_priv,
- intel_ddi_main_link_aux_domain(dig_port));
- }
+ main_link_aux_power_domain_get(dig_port, crtc_state);
}
void intel_ddi_enable_pipe_clock(struct intel_encoder *encoder,
@@ -1263,11 +1298,11 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
for (ln = 0; ln < 2; ln++) {
int level;
- intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port), ln, 0);
+ intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port, ln), 0);
level = intel_ddi_level(encoder, crtc_state, 2*ln+0);
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port, ln),
DKL_TX_PRESHOOT_COEFF_MASK |
DKL_TX_DE_EMPAHSIS_COEFF_MASK |
DKL_TX_VSWING_CONTROL_MASK,
@@ -1277,7 +1312,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
level = intel_ddi_level(encoder, crtc_state, 2*ln+1);
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port, ln),
DKL_TX_PRESHOOT_COEFF_MASK |
DKL_TX_DE_EMPAHSIS_COEFF_MASK |
DKL_TX_VSWING_CONTROL_MASK,
@@ -1285,7 +1320,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) |
DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing));
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port, ln),
DKL_TX_DP20BITMODE, 0);
if (IS_ALDERLAKE_P(dev_priv)) {
@@ -1304,7 +1339,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder,
val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(0);
}
- intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln,
+ intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port, ln),
DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK |
DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK,
val);
@@ -2017,8 +2052,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port,
return;
if (DISPLAY_VER(dev_priv) >= 12) {
- ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 0);
- ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 1);
+ ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port, 0));
+ ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port, 1));
} else {
ln0 = intel_de_read(dev_priv, MG_DP_MODE(0, tc_port));
ln1 = intel_de_read(dev_priv, MG_DP_MODE(1, tc_port));
@@ -2079,8 +2114,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port,
}
if (DISPLAY_VER(dev_priv) >= 12) {
- intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 0, ln0);
- intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 1, ln1);
+ intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port, 0), ln0);
+ intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port, 1), ln1);
} else {
intel_de_write(dev_priv, MG_DP_MODE(0, tc_port), ln0);
intel_de_write(dev_priv, MG_DP_MODE(1, tc_port), ln1);
@@ -2736,10 +2771,7 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
intel_ddi_post_disable_dp(state, encoder, old_crtc_state,
old_conn_state);
- if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port)
- intel_display_power_put(dev_priv,
- intel_ddi_main_link_aux_domain(dig_port),
- fetch_and_zero(&dig_port->aux_wakeref));
+ main_link_aux_power_domain_put(dig_port, old_crtc_state);
if (is_tc_port)
intel_tc_port_put_link(dig_port);
@@ -3060,12 +3092,7 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state,
if (is_tc_port)
intel_tc_port_get_link(dig_port, crtc_state->lane_count);
- if (intel_crtc_has_dp_encoder(crtc_state) || is_tc_port) {
- drm_WARN_ON(&dev_priv->drm, dig_port->aux_wakeref);
- dig_port->aux_wakeref =
- intel_display_power_get(dev_priv,
- intel_ddi_main_link_aux_domain(dig_port));
- }
+ main_link_aux_power_domain_get(dig_port, crtc_state);
if (is_tc_port && !intel_tc_port_in_tbt_alt_mode(dig_port))
/*
@@ -3085,7 +3112,7 @@ static void adlp_tbt_to_dp_alt_switch_wa(struct intel_encoder *encoder)
int ln;
for (ln = 0; ln < 2; ln++)
- intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port), ln, DKL_PCS_DW5_CORE_SOFTRESET, 0);
+ intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port, ln), DKL_PCS_DW5_CORE_SOFTRESET, 0);
}
static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp,
@@ -3524,7 +3551,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
if (drm_WARN_ON(&i915->drm, !pll))
return;
- if (intel_get_shared_dpll_id(i915, pll) == DPLL_ID_ICL_TBTPLL)
+ if (pll->info->id == DPLL_ID_ICL_TBTPLL)
port_dpll_id = ICL_PORT_DPLL_DEFAULT;
else
port_dpll_id = ICL_PORT_DPLL_MG_PHY;
@@ -3537,7 +3564,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder,
icl_set_active_port_dpll(crtc_state, port_dpll_id);
- if (intel_get_shared_dpll_id(i915, crtc_state->shared_dpll) == DPLL_ID_ICL_TBTPLL)
+ if (crtc_state->shared_dpll->info->id == DPLL_ID_ICL_TBTPLL)
crtc_state->port_clock = icl_calc_tbt_pll_link(i915, encoder->port);
else
crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll,
@@ -3579,7 +3606,7 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder,
enum phy phy = intel_port_to_phy(i915, encoder->port);
if (intel_phy_is_tc(i915, phy))
- intel_tc_port_sanitize(enc_to_dig_port(encoder));
+ intel_tc_port_sanitize_mode(enc_to_dig_port(encoder));
if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))
intel_dp_sync_state(encoder, crtc_state);
@@ -3789,11 +3816,17 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
static void intel_ddi_encoder_reset(struct drm_encoder *encoder)
{
+ struct drm_i915_private *i915 = to_i915(encoder->dev);
struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder));
+ struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+ enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
intel_dp->reset_link_params = true;
intel_pps_encoder_reset(intel_dp);
+
+ if (intel_phy_is_tc(i915, phy))
+ intel_tc_port_init_mode(dig_port);
}
static const struct drm_encoder_funcs intel_ddi_funcs = {
@@ -4106,12 +4139,6 @@ intel_ddi_max_lanes(struct intel_digital_port *dig_port)
return max_lanes;
}
-static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
-{
- return i915->hti_state & HDPORT_ENABLED &&
- i915->hti_state & HDPORT_DDI_USED(phy);
-}
-
static enum hpd_pin xelpd_hpd_pin(struct drm_i915_private *dev_priv,
enum port port)
{
@@ -4240,7 +4267,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
* driver. In that case we should skip initializing the corresponding
* outputs.
*/
- if (hti_uses_phy(dev_priv, phy)) {
+ if (intel_hti_uses_phy(dev_priv, phy)) {
drm_dbg_kms(&dev_priv->drm, "PORT %c / PHY %c reserved by HTI\n",
port_name(port), phy_name(phy));
return;