aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/intel_ddi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ddi.c')
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c123
1 files changed, 89 insertions, 34 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index f4a8598a2d39..044fe1fb9872 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -915,7 +915,14 @@ static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port por
level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
- if (IS_CANNONLAKE(dev_priv)) {
+ if (IS_ICELAKE(dev_priv)) {
+ if (port == PORT_A || port == PORT_B)
+ icl_get_combo_buf_trans(dev_priv, port,
+ INTEL_OUTPUT_HDMI, &n_entries);
+ else
+ n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations);
+ default_entry = n_entries - 1;
+ } else if (IS_CANNONLAKE(dev_priv)) {
cnl_get_buf_trans_hdmi(dev_priv, &n_entries);
default_entry = n_entries - 1;
} else if (IS_GEN9_LP(dev_priv)) {
@@ -1055,6 +1062,8 @@ static uint32_t hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll)
static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder,
const struct intel_shared_dpll *pll)
{
+ struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+ int clock = crtc->config->port_clock;
const enum intel_dpll_id id = pll->info->id;
switch (id) {
@@ -1063,6 +1072,20 @@ static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder,
case DPLL_ID_ICL_DPLL0:
case DPLL_ID_ICL_DPLL1:
return DDI_CLK_SEL_NONE;
+ case DPLL_ID_ICL_TBTPLL:
+ switch (clock) {
+ case 162000:
+ return DDI_CLK_SEL_TBT_162;
+ case 270000:
+ return DDI_CLK_SEL_TBT_270;
+ case 540000:
+ return DDI_CLK_SEL_TBT_540;
+ case 810000:
+ return DDI_CLK_SEL_TBT_810;
+ default:
+ MISSING_CASE(clock);
+ break;
+ }
case DPLL_ID_ICL_MGPLL1:
case DPLL_ID_ICL_MGPLL2:
case DPLL_ID_ICL_MGPLL3:
@@ -1243,35 +1266,6 @@ intel_ddi_get_crtc_encoder(struct intel_crtc *crtc)
return ret;
}
-/* Finds the only possible encoder associated with the given CRTC. */
-struct intel_encoder *
-intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
-{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
- struct intel_encoder *ret = NULL;
- struct drm_atomic_state *state;
- struct drm_connector *connector;
- struct drm_connector_state *connector_state;
- int num_encoders = 0;
- int i;
-
- state = crtc_state->base.state;
-
- for_each_new_connector_in_state(state, connector, connector_state, i) {
- if (connector_state->crtc != crtc_state->base.crtc)
- continue;
-
- ret = to_intel_encoder(connector_state->best_encoder);
- num_encoders++;
- }
-
- WARN(num_encoders != 1, "%d encoders on crtc for pipe %c\n", num_encoders,
- pipe_name(crtc->pipe));
-
- BUG_ON(ret == NULL);
- return ret;
-}
-
#define LC_FREQ 2700
static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
@@ -1374,8 +1368,13 @@ static int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv,
uint32_t cfgcr0, cfgcr1;
uint32_t p0, p1, p2, dco_freq, ref_clock;
- cfgcr0 = I915_READ(CNL_DPLL_CFGCR0(pll_id));
- cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(pll_id));
+ if (INTEL_GEN(dev_priv) >= 11) {
+ cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(pll_id));
+ cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(pll_id));
+ } else {
+ cfgcr0 = I915_READ(CNL_DPLL_CFGCR0(pll_id));
+ cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(pll_id));
+ }
p0 = cfgcr1 & DPLL_CFGCR1_PDIV_MASK;
p2 = cfgcr1 & DPLL_CFGCR1_KDIV_MASK;
@@ -1451,6 +1450,30 @@ static void ddi_dotclock_get(struct intel_crtc_state *pipe_config)
pipe_config->base.adjusted_mode.crtc_clock = dotclock;
}
+static void icl_ddi_clock_get(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum port port = encoder->port;
+ int link_clock = 0;
+ uint32_t pll_id;
+
+ pll_id = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll);
+ if (port == PORT_A || port == PORT_B) {
+ if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI))
+ link_clock = cnl_calc_wrpll_link(dev_priv, pll_id);
+ else
+ link_clock = icl_calc_dp_combo_pll_link(dev_priv,
+ pll_id);
+ } else {
+ /* FIXME - Add for MG PLL */
+ WARN(1, "MG PLL clock_get code not implemented yet\n");
+ }
+
+ pipe_config->port_clock = link_clock;
+ ddi_dotclock_get(pipe_config);
+}
+
static void cnl_ddi_clock_get(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
@@ -1644,6 +1667,8 @@ static void intel_ddi_clock_get(struct intel_encoder *encoder,
bxt_ddi_clock_get(encoder, pipe_config);
else if (IS_CANNONLAKE(dev_priv))
cnl_ddi_clock_get(encoder, pipe_config);
+ else if (IS_ICELAKE(dev_priv))
+ icl_ddi_clock_get(encoder, pipe_config);
}
void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state)
@@ -2115,6 +2140,26 @@ u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder)
DP_TRAIN_VOLTAGE_SWING_MASK;
}
+/*
+ * We assume that the full set of pre-emphasis values can be
+ * used on all DDI platforms. Should that change we need to
+ * rethink this code.
+ */
+u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder, u8 voltage_swing)
+{
+ switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
+ return DP_TRAIN_PRE_EMPH_LEVEL_3;
+ case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
+ return DP_TRAIN_PRE_EMPH_LEVEL_2;
+ case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
+ return DP_TRAIN_PRE_EMPH_LEVEL_1;
+ case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
+ default:
+ return DP_TRAIN_PRE_EMPH_LEVEL_0;
+ }
+}
+
static void cnl_ddi_vswing_program(struct intel_encoder *encoder,
int level, enum intel_output_type type)
{
@@ -2610,6 +2655,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
intel_dp_start_link_train(intel_dp);
if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
intel_dp_stop_link_train(intel_dp);
+
+ intel_ddi_enable_pipe_clock(crtc_state);
}
static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
@@ -2640,6 +2687,8 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
if (IS_GEN9_BC(dev_priv))
skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI);
+ intel_ddi_enable_pipe_clock(crtc_state);
+
intel_dig_port->set_infoframes(&encoder->base,
crtc_state->has_infoframe,
crtc_state, conn_state);
@@ -2709,6 +2758,8 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
bool is_mst = intel_crtc_has_type(old_crtc_state,
INTEL_OUTPUT_DP_MST);
+ intel_ddi_disable_pipe_clock(old_crtc_state);
+
/*
* Power down sink before disabling the port, otherwise we end
* up getting interrupts from the sink on detecting link loss.
@@ -2734,11 +2785,13 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
- intel_disable_ddi_buf(encoder);
-
dig_port->set_infoframes(&encoder->base, false,
old_crtc_state, old_conn_state);
+ intel_ddi_disable_pipe_clock(old_crtc_state);
+
+ intel_disable_ddi_buf(encoder);
+
intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
intel_ddi_clk_disable(encoder);
@@ -3025,6 +3078,8 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
{
if (IS_CANNONLAKE(dev_priv) && crtc_state->port_clock > 594000)
crtc_state->min_voltage_level = 2;
+ else if (IS_ICELAKE(dev_priv) && crtc_state->port_clock > 594000)
+ crtc_state->min_voltage_level = 1;
}
void intel_ddi_get_config(struct intel_encoder *encoder,