diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ddi.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 912 |
1 files changed, 732 insertions, 180 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3eb0efc2dd0d..cacb07b7a8f1 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -155,33 +155,100 @@ static const struct ddi_buf_trans skl_ddi_translations_edp[] = { static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { - /* Idx NT mV T mV db */ - { 0x00004014, 0x00000087 }, /* 0: 800 1000 2 */ + { 0x00000018, 0x000000ac }, + { 0x00005012, 0x0000009d }, + { 0x00007011, 0x00000088 }, + { 0x00000018, 0x000000a1 }, + { 0x00000018, 0x00000098 }, + { 0x00004013, 0x00000088 }, + { 0x00006012, 0x00000087 }, + { 0x00000018, 0x000000df }, + { 0x00003015, 0x00000087 }, + { 0x00003015, 0x000000c7 }, + { 0x00000018, 0x000000c7 }, }; -enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) +struct bxt_ddi_buf_trans { + u32 margin; /* swing value */ + u32 scale; /* scale value */ + u32 enable; /* scale enable */ + u32 deemphasis; + bool default_index; /* true if the entry represents default value */ +}; + +/* BSpec does not define separate vswing/pre-emphasis values for eDP. + * Using DP values for eDP as well. + */ +static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { + /* Idx NT mV diff db */ + { 52, 0, 0, 128, true }, /* 0: 400 0 */ + { 78, 0, 0, 85, false }, /* 1: 400 3.5 */ + { 104, 0, 0, 64, false }, /* 2: 400 6 */ + { 154, 0, 0, 43, false }, /* 3: 400 9.5 */ + { 77, 0, 0, 128, false }, /* 4: 600 0 */ + { 116, 0, 0, 85, false }, /* 5: 600 3.5 */ + { 154, 0, 0, 64, false }, /* 6: 600 6 */ + { 102, 0, 0, 128, false }, /* 7: 800 0 */ + { 154, 0, 0, 85, false }, /* 8: 800 3.5 */ + { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ +}; + +/* BSpec has 2 recommended values - entries 0 and 8. + * Using the entry with higher vswing. + */ +static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { + /* Idx NT mV diff db */ + { 52, 0, 0, 128, false }, /* 0: 400 0 */ + { 52, 0, 0, 85, false }, /* 1: 400 3.5 */ + { 52, 0, 0, 64, false }, /* 2: 400 6 */ + { 42, 0, 0, 43, false }, /* 3: 400 9.5 */ + { 77, 0, 0, 128, false }, /* 4: 600 0 */ + { 77, 0, 0, 85, false }, /* 5: 600 3.5 */ + { 77, 0, 0, 64, false }, /* 6: 600 6 */ + { 102, 0, 0, 128, false }, /* 7: 800 0 */ + { 102, 0, 0, 85, false }, /* 8: 800 3.5 */ + { 154, 0x9A, 1, 128, true }, /* 9: 1200 0 */ +}; + +static void ddi_get_encoder_port(struct intel_encoder *intel_encoder, + struct intel_digital_port **dig_port, + enum port *port) { struct drm_encoder *encoder = &intel_encoder->base; int type = intel_encoder->type; if (type == INTEL_OUTPUT_DP_MST) { - struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary; - return intel_dig_port->port; + *dig_port = enc_to_mst(encoder)->primary; + *port = (*dig_port)->port; } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { - struct intel_digital_port *intel_dig_port = - enc_to_dig_port(encoder); - return intel_dig_port->port; - + *dig_port = enc_to_dig_port(encoder); + *port = (*dig_port)->port; } else if (type == INTEL_OUTPUT_ANALOG) { - return PORT_E; - + *dig_port = NULL; + *port = PORT_E; } else { DRM_ERROR("Invalid DDI encoder type %d\n", type); BUG(); } } +enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) +{ + struct intel_digital_port *dig_port; + enum port port; + + ddi_get_encoder_port(intel_encoder, &dig_port, &port); + + return port; +} + +static bool +intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port) +{ + return intel_dig_port->hdmi.hdmi_reg; +} + /* * Starting with Haswell, DDI port buffers must be programmed with correct * values in advance. The buffer values are different for FDI and DP modes, @@ -189,7 +256,8 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) * in either FDI or DP modes only, as HDMI connections will work with both * of those */ -static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) +static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, + bool supports_hdmi) { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg; @@ -202,11 +270,19 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) const struct ddi_buf_trans *ddi_translations_hdmi; const struct ddi_buf_trans *ddi_translations; - if (IS_SKYLAKE(dev)) { + if (IS_BROXTON(dev)) { + if (!supports_hdmi) + return; + + /* Vswing programming for HDMI */ + bxt_ddi_vswing_sequence(dev, hdmi_level, port, + INTEL_OUTPUT_HDMI); + return; + } else if (IS_SKYLAKE(dev)) { ddi_translations_fdi = NULL; ddi_translations_dp = skl_ddi_translations_dp; n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp); - if (dev_priv->vbt.edp_low_vswing) { + if (dev_priv->edp_low_vswing) { ddi_translations_edp = skl_ddi_translations_edp; n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp); } else { @@ -214,16 +290,9 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) n_edp_entries = ARRAY_SIZE(skl_ddi_translations_dp); } - /* - * On SKL, the recommendation from the hw team is to always use - * a certain type of level shifter (and thus the corresponding - * 800mV+2dB entry). Given that's the only validated entry, we - * override what is in the VBT, at least until further notice. - */ - hdmi_level = 0; ddi_translations_hdmi = skl_ddi_translations_hdmi; n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); - hdmi_default_entry = 0; + hdmi_default_entry = 7; } else if (IS_BROADWELL(dev)) { ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; @@ -290,6 +359,9 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) reg += 4; } + if (!supports_hdmi) + return; + /* Choose a good default if VBT is badly populated */ if (hdmi_level == HDMI_LEVEL_SHIFT_UNKNOWN || hdmi_level >= n_hdmi_entries) @@ -307,13 +379,28 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) */ void intel_prepare_ddi(struct drm_device *dev) { - int port; + struct intel_encoder *intel_encoder; + bool visited[I915_MAX_PORTS] = { 0, }; if (!HAS_DDI(dev)) return; - for (port = PORT_A; port <= PORT_E; port++) - intel_prepare_ddi_buffers(dev, port); + for_each_intel_encoder(dev, intel_encoder) { + struct intel_digital_port *intel_dig_port; + enum port port; + bool supports_hdmi; + + ddi_get_encoder_port(intel_encoder, &intel_dig_port, &port); + + if (visited[port]) + continue; + + supports_hdmi = intel_dig_port && + intel_dig_port_supports_hdmi(intel_dig_port); + + intel_prepare_ddi_buffers(dev, port, supports_hdmi); + visited[port] = true; + } } static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, @@ -322,7 +409,7 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, uint32_t reg = DDI_BUF_CTL(port); int i; - for (i = 0; i < 8; i++) { + for (i = 0; i < 16; i++) { udelay(1); if (I915_READ(reg) & DDI_BUF_IS_IDLE) return; @@ -491,23 +578,24 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) return ret; } -static struct intel_encoder * +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 (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i] || - state->connector_states[i]->crtc != crtc_state->base.crtc) + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != crtc_state->base.crtc) continue; - ret = to_intel_encoder(state->connector_states[i]->best_encoder); + ret = to_intel_encoder(connector_state->best_encoder); num_encoders++; } @@ -783,26 +871,26 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder, if (dpll_ctl1 & DPLL_CTRL1_HDMI_MODE(dpll)) { link_clock = skl_calc_wrpll_link(dev_priv, dpll); } else { - link_clock = dpll_ctl1 & DPLL_CRTL1_LINK_RATE_MASK(dpll); - link_clock >>= DPLL_CRTL1_LINK_RATE_SHIFT(dpll); + link_clock = dpll_ctl1 & DPLL_CTRL1_LINK_RATE_MASK(dpll); + link_clock >>= DPLL_CTRL1_LINK_RATE_SHIFT(dpll); switch (link_clock) { - case DPLL_CRTL1_LINK_RATE_810: + case DPLL_CTRL1_LINK_RATE_810: link_clock = 81000; break; - case DPLL_CRTL1_LINK_RATE_1080: + case DPLL_CTRL1_LINK_RATE_1080: link_clock = 108000; break; - case DPLL_CRTL1_LINK_RATE_1350: + case DPLL_CTRL1_LINK_RATE_1350: link_clock = 135000; break; - case DPLL_CRTL1_LINK_RATE_1620: + case DPLL_CTRL1_LINK_RATE_1620: link_clock = 162000; break; - case DPLL_CRTL1_LINK_RATE_2160: + case DPLL_CTRL1_LINK_RATE_2160: link_clock = 216000; break; - case DPLL_CRTL1_LINK_RATE_2700: + case DPLL_CTRL1_LINK_RATE_2700: link_clock = 270000; break; default: @@ -878,6 +966,32 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; } +static int bxt_calc_pll_link(struct drm_i915_private *dev_priv, + enum intel_dpll_id dpll) +{ + /* FIXME formula not available in bspec */ + return 0; +} + +static void bxt_ddi_clock_get(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + enum port port = intel_ddi_get_encoder_port(encoder); + uint32_t dpll = port; + + pipe_config->port_clock = + bxt_calc_pll_link(dev_priv, dpll); + + if (pipe_config->has_dp_encoder) + pipe_config->base.adjusted_mode.crtc_clock = + intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->dp_m_n); + else + pipe_config->base.adjusted_mode.crtc_clock = + pipe_config->port_clock; +} + void intel_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { @@ -885,8 +999,10 @@ void intel_ddi_clock_get(struct intel_encoder *encoder, if (INTEL_INFO(dev)->gen <= 8) hsw_ddi_clock_get(encoder, pipe_config); - else + else if (IS_SKYLAKE(dev)) skl_ddi_clock_get(encoder, pipe_config); + else if (IS_BROXTON(dev)) + bxt_ddi_clock_get(encoder, pipe_config); } static void @@ -971,6 +1087,9 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); + memset(&crtc_state->dpll_hw_state, 0, + sizeof(crtc_state->dpll_hw_state)); + crtc_state->dpll_hw_state.wrpll = val; pll = intel_get_shared_dpll(intel_crtc, crtc_state); @@ -1073,69 +1192,69 @@ found: if (min_dco_index > 2) { WARN(1, "No valid values found for the given pixel clock\n"); } else { - wrpll_params->central_freq = dco_central_freq[min_dco_index]; + wrpll_params->central_freq = dco_central_freq[min_dco_index]; - switch (dco_central_freq[min_dco_index]) { - case 9600000000ULL: + switch (dco_central_freq[min_dco_index]) { + case 9600000000ULL: wrpll_params->central_freq = 0; break; - case 9000000000ULL: + case 9000000000ULL: wrpll_params->central_freq = 1; break; - case 8400000000ULL: + case 8400000000ULL: wrpll_params->central_freq = 3; - } + } - switch (candidate_p0[min_dco_index]) { - case 1: + switch (candidate_p0[min_dco_index]) { + case 1: wrpll_params->pdiv = 0; break; - case 2: + case 2: wrpll_params->pdiv = 1; break; - case 3: + case 3: wrpll_params->pdiv = 2; break; - case 7: + case 7: wrpll_params->pdiv = 4; break; - default: + default: WARN(1, "Incorrect PDiv\n"); - } + } - switch (candidate_p2[min_dco_index]) { - case 5: + switch (candidate_p2[min_dco_index]) { + case 5: wrpll_params->kdiv = 0; break; - case 2: + case 2: wrpll_params->kdiv = 1; break; - case 3: + case 3: wrpll_params->kdiv = 2; break; - case 1: + case 1: wrpll_params->kdiv = 3; break; - default: + default: WARN(1, "Incorrect KDiv\n"); - } + } - wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; - wrpll_params->qdiv_mode = + wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; + wrpll_params->qdiv_mode = (wrpll_params->qdiv_ratio == 1) ? 0 : 1; - dco_freq = candidate_p0[min_dco_index] * - candidate_p1[min_dco_index] * - candidate_p2[min_dco_index] * afe_clock; + dco_freq = candidate_p0[min_dco_index] * + candidate_p1[min_dco_index] * + candidate_p2[min_dco_index] * afe_clock; /* - * Intermediate values are in Hz. - * Divide by MHz to match bsepc - */ - wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); - wrpll_params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + * Intermediate values are in Hz. + * Divide by MHz to match bsepc + */ + wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + wrpll_params->dco_fraction = + div_u64(((div_u64(dco_freq, 24) - + wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); } } @@ -1179,13 +1298,13 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, switch (intel_dp->link_bw) { case DP_LINK_BW_1_62: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, 0); + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); break; case DP_LINK_BW_2_7: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, 0); + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); break; case DP_LINK_BW_5_4: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, 0); + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); break; } @@ -1193,6 +1312,9 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, } else /* eDP */ return true; + memset(&crtc_state->dpll_hw_state, 0, + sizeof(crtc_state->dpll_hw_state)); + crtc_state->dpll_hw_state.ctrl1 = ctrl1; crtc_state->dpll_hw_state.cfgcr1 = cfgcr1; crtc_state->dpll_hw_state.cfgcr2 = cfgcr2; @@ -1210,6 +1332,161 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, return true; } +/* bxt clock parameters */ +struct bxt_clk_div { + uint32_t p1; + uint32_t p2; + uint32_t m2_int; + uint32_t m2_frac; + bool m2_frac_en; + uint32_t n; +}; + +/* pre-calculated values for DP linkrates */ +static struct bxt_clk_div bxt_dp_clk_val[7] = { + /* 162 */ {4, 2, 32, 1677722, 1, 1}, + /* 270 */ {4, 1, 27, 0, 0, 1}, + /* 540 */ {2, 1, 27, 0, 0, 1}, + /* 216 */ {3, 2, 32, 1677722, 1, 1}, + /* 243 */ {4, 1, 24, 1258291, 1, 1}, + /* 324 */ {4, 1, 32, 1677722, 1, 1}, + /* 432 */ {3, 1, 32, 1677722, 1, 1} +}; + +static bool +bxt_ddi_pll_select(struct intel_crtc *intel_crtc, + struct intel_crtc_state *crtc_state, + struct intel_encoder *intel_encoder, + int clock) +{ + struct intel_shared_dpll *pll; + struct bxt_clk_div clk_div = {0}; + int vco = 0; + uint32_t prop_coef, int_coef, gain_ctl, targ_cnt; + uint32_t dcoampovr_en_h, dco_amp, lanestagger; + + if (intel_encoder->type == INTEL_OUTPUT_HDMI) { + intel_clock_t best_clock; + + /* Calculate HDMI div */ + /* + * FIXME: tie the following calculation into + * i9xx_crtc_compute_clock + */ + if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) { + DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n", + clock, pipe_name(intel_crtc->pipe)); + return false; + } + + clk_div.p1 = best_clock.p1; + clk_div.p2 = best_clock.p2; + WARN_ON(best_clock.m1 != 2); + clk_div.n = best_clock.n; + clk_div.m2_int = best_clock.m2 >> 22; + clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1); + clk_div.m2_frac_en = clk_div.m2_frac != 0; + + vco = best_clock.vco; + } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || + intel_encoder->type == INTEL_OUTPUT_EDP) { + struct drm_encoder *encoder = &intel_encoder->base; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + switch (intel_dp->link_bw) { + case DP_LINK_BW_1_62: + clk_div = bxt_dp_clk_val[0]; + break; + case DP_LINK_BW_2_7: + clk_div = bxt_dp_clk_val[1]; + break; + case DP_LINK_BW_5_4: + clk_div = bxt_dp_clk_val[2]; + break; + default: + clk_div = bxt_dp_clk_val[0]; + DRM_ERROR("Unknown link rate\n"); + } + vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2; + } + + dco_amp = 15; + dcoampovr_en_h = 0; + if (vco >= 6200000 && vco <= 6480000) { + prop_coef = 4; + int_coef = 9; + gain_ctl = 3; + targ_cnt = 8; + } else if ((vco > 5400000 && vco < 6200000) || + (vco >= 4800000 && vco < 5400000)) { + prop_coef = 5; + int_coef = 11; + gain_ctl = 3; + targ_cnt = 9; + if (vco >= 4800000 && vco < 5400000) + dcoampovr_en_h = 1; + } else if (vco == 5400000) { + prop_coef = 3; + int_coef = 8; + gain_ctl = 1; + targ_cnt = 9; + } else { + DRM_ERROR("Invalid VCO\n"); + return false; + } + + memset(&crtc_state->dpll_hw_state, 0, + sizeof(crtc_state->dpll_hw_state)); + + if (clock > 270000) + lanestagger = 0x18; + else if (clock > 135000) + lanestagger = 0x0d; + else if (clock > 67000) + lanestagger = 0x07; + else if (clock > 33000) + lanestagger = 0x04; + else + lanestagger = 0x02; + + crtc_state->dpll_hw_state.ebb0 = + PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2); + crtc_state->dpll_hw_state.pll0 = clk_div.m2_int; + crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n); + crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac; + + if (clk_div.m2_frac_en) + crtc_state->dpll_hw_state.pll3 = + PORT_PLL_M2_FRAC_ENABLE; + + crtc_state->dpll_hw_state.pll6 = + prop_coef | PORT_PLL_INT_COEFF(int_coef); + crtc_state->dpll_hw_state.pll6 |= + PORT_PLL_GAIN_CTL(gain_ctl); + + crtc_state->dpll_hw_state.pll8 = targ_cnt; + + if (dcoampovr_en_h) + crtc_state->dpll_hw_state.pll10 = PORT_PLL_DCO_AMP_OVR_EN_H; + + crtc_state->dpll_hw_state.pll10 |= PORT_PLL_DCO_AMP(dco_amp); + + crtc_state->dpll_hw_state.pcsdw12 = + LANESTAGGER_STRAP_OVRD | lanestagger; + + pll = intel_get_shared_dpll(intel_crtc, crtc_state); + if (pll == NULL) { + DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", + pipe_name(intel_crtc->pipe)); + return false; + } + + /* shared DPLL id 0 is DPLL A */ + crtc_state->ddi_pll_sel = pll->id; + + return true; +} + /* * Tries to find a *shared* PLL for the CRTC and store it in * intel_crtc->ddi_pll_sel. @@ -1228,6 +1505,9 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc, if (IS_SKYLAKE(dev)) return skl_ddi_pll_select(intel_crtc, crtc_state, intel_encoder, clock); + else if (IS_BROXTON(dev)) + return bxt_ddi_pll_select(intel_crtc, crtc_state, + intel_encoder, clock); else return hsw_ddi_pll_select(intel_crtc, crtc_state, intel_encoder, clock); @@ -1519,6 +1799,67 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) TRANS_CLK_SEL_DISABLED); } +void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, + enum port port, int type) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct bxt_ddi_buf_trans *ddi_translations; + u32 n_entries, i; + uint32_t val; + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + n_entries = ARRAY_SIZE(bxt_ddi_translations_dp); + ddi_translations = bxt_ddi_translations_dp; + } else if (type == INTEL_OUTPUT_HDMI) { + n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi); + ddi_translations = bxt_ddi_translations_hdmi; + } else { + DRM_DEBUG_KMS("Vswing programming not done for encoder %d\n", + type); + return; + } + + /* Check if default value has to be used */ + if (level >= n_entries || + (type == INTEL_OUTPUT_HDMI && level == HDMI_LEVEL_SHIFT_UNKNOWN)) { + for (i = 0; i < n_entries; i++) { + if (ddi_translations[i].default_index) { + level = i; + break; + } + } + } + + /* + * While we write to the group register to program all lanes at once we + * can read only lane registers and we pick lanes 0/1 for that. + */ + val = I915_READ(BXT_PORT_PCS_DW10_LN01(port)); + val &= ~(TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT); + I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val); + + val = I915_READ(BXT_PORT_TX_DW2_LN0(port)); + val &= ~(MARGIN_000 | UNIQ_TRANS_SCALE); + val |= ddi_translations[level].margin << MARGIN_000_SHIFT | + ddi_translations[level].scale << UNIQ_TRANS_SCALE_SHIFT; + I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val); + + val = I915_READ(BXT_PORT_TX_DW3_LN0(port)); + val &= ~UNIQE_TRANGE_EN_METHOD; + if (ddi_translations[level].enable) + val |= UNIQE_TRANGE_EN_METHOD; + I915_WRITE(BXT_PORT_TX_DW3_GRP(port), val); + + val = I915_READ(BXT_PORT_TX_DW4_LN0(port)); + val &= ~DE_EMPHASIS; + val |= ddi_translations[level].deemphasis << DEEMPH_SHIFT; + I915_WRITE(BXT_PORT_TX_DW4_GRP(port), val); + + val = I915_READ(BXT_PORT_PCS_DW10_LN01(port)); + val |= TX2_SWING_CALC_INIT | TX1_SWING_CALC_INIT; + I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val); +} + static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; @@ -1527,6 +1868,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; + int hdmi_level; if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -1548,7 +1890,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | - DPLL_CRTL1_LINK_RATE_MASK(dpll)); + DPLL_CTRL1_LINK_RATE_MASK(dpll)); val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6); I915_WRITE(DPLL_CTRL1, val); @@ -1565,7 +1907,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) I915_WRITE(DPLL_CTRL2, val); - } else { + } else if (INTEL_INFO(dev)->gen < 9) { WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE); I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel); } @@ -1583,6 +1925,12 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) } else if (type == INTEL_OUTPUT_HDMI) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + if (IS_BROXTON(dev)) { + hdmi_level = dev_priv->vbt. + ddi_port_info[port].hdmi_level_shift; + bxt_ddi_vswing_sequence(dev, hdmi_level, port, + INTEL_OUTPUT_HDMI); + } intel_hdmi->set_infoframes(encoder, crtc->config->has_hdmi_sink, &crtc->config->base.adjusted_mode); @@ -1624,7 +1972,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (IS_SKYLAKE(dev)) I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) | DPLL_CTRL2_DDI_CLK_OFF(port))); - else + else if (INTEL_INFO(dev)->gen < 9) I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); } @@ -1689,105 +2037,6 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) } } -static int skl_get_cdclk_freq(struct drm_i915_private *dev_priv) -{ - uint32_t lcpll1 = I915_READ(LCPLL1_CTL); - uint32_t cdctl = I915_READ(CDCLK_CTL); - uint32_t linkrate; - - if (!(lcpll1 & LCPLL_PLL_ENABLE)) { - WARN(1, "LCPLL1 not enabled\n"); - return 24000; /* 24MHz is the cd freq with NSSC ref */ - } - - if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540) - return 540000; - - linkrate = (I915_READ(DPLL_CTRL1) & - DPLL_CRTL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1; - - if (linkrate == DPLL_CRTL1_LINK_RATE_2160 || - linkrate == DPLL_CRTL1_LINK_RATE_1080) { - /* vco 8640 */ - switch (cdctl & CDCLK_FREQ_SEL_MASK) { - case CDCLK_FREQ_450_432: - return 432000; - case CDCLK_FREQ_337_308: - return 308570; - case CDCLK_FREQ_675_617: - return 617140; - default: - WARN(1, "Unknown cd freq selection\n"); - } - } else { - /* vco 8100 */ - switch (cdctl & CDCLK_FREQ_SEL_MASK) { - case CDCLK_FREQ_450_432: - return 450000; - case CDCLK_FREQ_337_308: - return 337500; - case CDCLK_FREQ_675_617: - return 675000; - default: - WARN(1, "Unknown cd freq selection\n"); - } - } - - /* error case, do as if DPLL0 isn't enabled */ - return 24000; -} - -static int bdw_get_cdclk_freq(struct drm_i915_private *dev_priv) -{ - uint32_t lcpll = I915_READ(LCPLL_CTL); - uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; - - if (lcpll & LCPLL_CD_SOURCE_FCLK) - return 800000; - else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) - return 450000; - else if (freq == LCPLL_CLK_FREQ_450) - return 450000; - else if (freq == LCPLL_CLK_FREQ_54O_BDW) - return 540000; - else if (freq == LCPLL_CLK_FREQ_337_5_BDW) - return 337500; - else - return 675000; -} - -static int hsw_get_cdclk_freq(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - uint32_t lcpll = I915_READ(LCPLL_CTL); - uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; - - if (lcpll & LCPLL_CD_SOURCE_FCLK) - return 800000; - else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) - return 450000; - else if (freq == LCPLL_CLK_FREQ_450) - return 450000; - else if (IS_HSW_ULT(dev)) - return 337500; - else - return 540000; -} - -int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - - if (IS_SKYLAKE(dev)) - return skl_get_cdclk_freq(dev_priv); - - if (IS_BROADWELL(dev)) - return bdw_get_cdclk_freq(dev_priv); - - /* Haswell */ - return hsw_get_cdclk_freq(dev_priv); -} - static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { @@ -1887,7 +2136,7 @@ static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, val = I915_READ(DPLL_CTRL1); val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | - DPLL_CRTL1_LINK_RATE_MASK(dpll)); + DPLL_CTRL1_LINK_RATE_MASK(dpll)); val |= pll->config.hw_state.ctrl1 << (dpll * 6); I915_WRITE(DPLL_CTRL1, val); @@ -1963,22 +2212,325 @@ static void skl_shared_dplls_init(struct drm_i915_private *dev_priv) } } +static void broxton_phy_init(struct drm_i915_private *dev_priv, + enum dpio_phy phy) +{ + enum port port; + uint32_t val; + + val = I915_READ(BXT_P_CR_GT_DISP_PWRON); + val |= GT_DISPLAY_POWER_ON(phy); + I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val); + + /* Considering 10ms timeout until BSpec is updated */ + if (wait_for(I915_READ(BXT_PORT_CL1CM_DW0(phy)) & PHY_POWER_GOOD, 10)) + DRM_ERROR("timeout during PHY%d power on\n", phy); + + for (port = (phy == DPIO_PHY0 ? PORT_B : PORT_A); + port <= (phy == DPIO_PHY0 ? PORT_C : PORT_A); port++) { + int lane; + + for (lane = 0; lane < 4; lane++) { + val = I915_READ(BXT_PORT_TX_DW14_LN(port, lane)); + /* + * Note that on CHV this flag is called UPAR, but has + * the same function. + */ + val &= ~LATENCY_OPTIM; + if (lane != 1) + val |= LATENCY_OPTIM; + + I915_WRITE(BXT_PORT_TX_DW14_LN(port, lane), val); + } + } + + /* Program PLL Rcomp code offset */ + val = I915_READ(BXT_PORT_CL1CM_DW9(phy)); + val &= ~IREF0RC_OFFSET_MASK; + val |= 0xE4 << IREF0RC_OFFSET_SHIFT; + I915_WRITE(BXT_PORT_CL1CM_DW9(phy), val); + + val = I915_READ(BXT_PORT_CL1CM_DW10(phy)); + val &= ~IREF1RC_OFFSET_MASK; + val |= 0xE4 << IREF1RC_OFFSET_SHIFT; + I915_WRITE(BXT_PORT_CL1CM_DW10(phy), val); + + /* Program power gating */ + val = I915_READ(BXT_PORT_CL1CM_DW28(phy)); + val |= OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | + SUS_CLK_CONFIG; + I915_WRITE(BXT_PORT_CL1CM_DW28(phy), val); + + if (phy == DPIO_PHY0) { + val = I915_READ(BXT_PORT_CL2CM_DW6_BC); + val |= DW6_OLDO_DYN_PWR_DOWN_EN; + I915_WRITE(BXT_PORT_CL2CM_DW6_BC, val); + } + + val = I915_READ(BXT_PORT_CL1CM_DW30(phy)); + val &= ~OCL2_LDOFUSE_PWR_DIS; + /* + * On PHY1 disable power on the second channel, since no port is + * connected there. On PHY0 both channels have a port, so leave it + * enabled. + * TODO: port C is only connected on BXT-P, so on BXT0/1 we should + * power down the second channel on PHY0 as well. + */ + if (phy == DPIO_PHY1) + val |= OCL2_LDOFUSE_PWR_DIS; + I915_WRITE(BXT_PORT_CL1CM_DW30(phy), val); + + if (phy == DPIO_PHY0) { + uint32_t grc_code; + /* + * PHY0 isn't connected to an RCOMP resistor so copy over + * the corresponding calibrated value from PHY1, and disable + * the automatic calibration on PHY0. + */ + if (wait_for(I915_READ(BXT_PORT_REF_DW3(DPIO_PHY1)) & GRC_DONE, + 10)) + DRM_ERROR("timeout waiting for PHY1 GRC\n"); + + val = I915_READ(BXT_PORT_REF_DW6(DPIO_PHY1)); + val = (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT; + grc_code = val << GRC_CODE_FAST_SHIFT | + val << GRC_CODE_SLOW_SHIFT | + val; + I915_WRITE(BXT_PORT_REF_DW6(DPIO_PHY0), grc_code); + + val = I915_READ(BXT_PORT_REF_DW8(DPIO_PHY0)); + val |= GRC_DIS | GRC_RDY_OVRD; + I915_WRITE(BXT_PORT_REF_DW8(DPIO_PHY0), val); + } + + val = I915_READ(BXT_PHY_CTL_FAMILY(phy)); + val |= COMMON_RESET_DIS; + I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val); +} + +void broxton_ddi_phy_init(struct drm_device *dev) +{ + /* Enable PHY1 first since it provides Rcomp for PHY0 */ + broxton_phy_init(dev->dev_private, DPIO_PHY1); + broxton_phy_init(dev->dev_private, DPIO_PHY0); +} + +static void broxton_phy_uninit(struct drm_i915_private *dev_priv, + enum dpio_phy phy) +{ + uint32_t val; + + val = I915_READ(BXT_PHY_CTL_FAMILY(phy)); + val &= ~COMMON_RESET_DIS; + I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val); +} + +void broxton_ddi_phy_uninit(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + broxton_phy_uninit(dev_priv, DPIO_PHY1); + broxton_phy_uninit(dev_priv, DPIO_PHY0); + + /* FIXME: do this in broxton_phy_uninit per phy */ + I915_WRITE(BXT_P_CR_GT_DISP_PWRON, 0); +} + +static const char * const bxt_ddi_pll_names[] = { + "PORT PLL A", + "PORT PLL B", + "PORT PLL C", +}; + +static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + uint32_t temp; + enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + + temp = I915_READ(BXT_PORT_PLL_ENABLE(port)); + temp &= ~PORT_PLL_REF_SEL; + /* Non-SSC reference */ + I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp); + + /* Disable 10 bit clock */ + temp = I915_READ(BXT_PORT_PLL_EBB_4(port)); + temp &= ~PORT_PLL_10BIT_CLK_ENABLE; + I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); + + /* Write P1 & P2 */ + temp = I915_READ(BXT_PORT_PLL_EBB_0(port)); + temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK); + temp |= pll->config.hw_state.ebb0; + I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp); + + /* Write M2 integer */ + temp = I915_READ(BXT_PORT_PLL(port, 0)); + temp &= ~PORT_PLL_M2_MASK; + temp |= pll->config.hw_state.pll0; + I915_WRITE(BXT_PORT_PLL(port, 0), temp); + + /* Write N */ + temp = I915_READ(BXT_PORT_PLL(port, 1)); + temp &= ~PORT_PLL_N_MASK; + temp |= pll->config.hw_state.pll1; + I915_WRITE(BXT_PORT_PLL(port, 1), temp); + + /* Write M2 fraction */ + temp = I915_READ(BXT_PORT_PLL(port, 2)); + temp &= ~PORT_PLL_M2_FRAC_MASK; + temp |= pll->config.hw_state.pll2; + I915_WRITE(BXT_PORT_PLL(port, 2), temp); + + /* Write M2 fraction enable */ + temp = I915_READ(BXT_PORT_PLL(port, 3)); + temp &= ~PORT_PLL_M2_FRAC_ENABLE; + temp |= pll->config.hw_state.pll3; + I915_WRITE(BXT_PORT_PLL(port, 3), temp); + + /* Write coeff */ + temp = I915_READ(BXT_PORT_PLL(port, 6)); + temp &= ~PORT_PLL_PROP_COEFF_MASK; + temp &= ~PORT_PLL_INT_COEFF_MASK; + temp &= ~PORT_PLL_GAIN_CTL_MASK; + temp |= pll->config.hw_state.pll6; + I915_WRITE(BXT_PORT_PLL(port, 6), temp); + + /* Write calibration val */ + temp = I915_READ(BXT_PORT_PLL(port, 8)); + temp &= ~PORT_PLL_TARGET_CNT_MASK; + temp |= pll->config.hw_state.pll8; + I915_WRITE(BXT_PORT_PLL(port, 8), temp); + + temp = I915_READ(BXT_PORT_PLL(port, 9)); + temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK; + temp |= (5 << 1); + I915_WRITE(BXT_PORT_PLL(port, 9), temp); + + temp = I915_READ(BXT_PORT_PLL(port, 10)); + temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H; + temp &= ~PORT_PLL_DCO_AMP_MASK; + temp |= pll->config.hw_state.pll10; + I915_WRITE(BXT_PORT_PLL(port, 10), temp); + + /* Recalibrate with new settings */ + temp = I915_READ(BXT_PORT_PLL_EBB_4(port)); + temp |= PORT_PLL_RECALIBRATE; + I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); + /* Enable 10 bit clock */ + temp |= PORT_PLL_10BIT_CLK_ENABLE; + I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); + + /* Enable PLL */ + temp = I915_READ(BXT_PORT_PLL_ENABLE(port)); + temp |= PORT_PLL_ENABLE; + I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp); + POSTING_READ(BXT_PORT_PLL_ENABLE(port)); + + if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) & + PORT_PLL_LOCK), 200)) + DRM_ERROR("PLL %d not locked\n", port); + + /* + * While we write to the group register to program all lanes at once we + * can read only lane registers and we pick lanes 0/1 for that. + */ + temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port)); + temp &= ~LANE_STAGGER_MASK; + temp &= ~LANESTAGGER_STRAP_OVRD; + temp |= pll->config.hw_state.pcsdw12; + I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp); +} + +static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + uint32_t temp; + + temp = I915_READ(BXT_PORT_PLL_ENABLE(port)); + temp &= ~PORT_PLL_ENABLE; + I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp); + POSTING_READ(BXT_PORT_PLL_ENABLE(port)); +} + +static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) +{ + enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + uint32_t val; + + if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS)) + return false; + + val = I915_READ(BXT_PORT_PLL_ENABLE(port)); + if (!(val & PORT_PLL_ENABLE)) + return false; + + hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); + hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0)); + hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1)); + hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2)); + hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3)); + hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6)); + hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8)); + hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10)); + /* + * While we write to the group register to program all lanes at once we + * can read only lane registers. We configure all lanes the same way, so + * here just read out lanes 0/1 and output a note if lanes 2/3 differ. + */ + hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port)); + if (I915_READ(BXT_PORT_PCS_DW12_LN23(port) != hw_state->pcsdw12)) + DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n", + hw_state->pcsdw12, + I915_READ(BXT_PORT_PCS_DW12_LN23(port))); + + return true; +} + +static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv) +{ + int i; + + dev_priv->num_shared_dpll = 3; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + dev_priv->shared_dplls[i].id = i; + dev_priv->shared_dplls[i].name = bxt_ddi_pll_names[i]; + dev_priv->shared_dplls[i].disable = bxt_ddi_pll_disable; + dev_priv->shared_dplls[i].enable = bxt_ddi_pll_enable; + dev_priv->shared_dplls[i].get_hw_state = + bxt_ddi_pll_get_hw_state; + } +} + void intel_ddi_pll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t val = I915_READ(LCPLL_CTL); + int cdclk_freq; if (IS_SKYLAKE(dev)) skl_shared_dplls_init(dev_priv); + else if (IS_BROXTON(dev)) + bxt_shared_dplls_init(dev_priv); else hsw_shared_dplls_init(dev_priv); - DRM_DEBUG_KMS("CDCLK running at %dKHz\n", - intel_ddi_get_cdclk_freq(dev_priv)); + cdclk_freq = dev_priv->display.get_display_clock_speed(dev); + DRM_DEBUG_KMS("CDCLK running at %dKHz\n", cdclk_freq); if (IS_SKYLAKE(dev)) { + dev_priv->skl_boot_cdclk = cdclk_freq; if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) DRM_ERROR("LCPLL1 is disabled\n"); + else + intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); + } else if (IS_BROXTON(dev)) { + broxton_init_cdclk(dev); + broxton_ddi_phy_init(dev); } else { /* * The LCPLL register should be turned on by the BIOS. For now |