Commit 89b667f8 authored by Jesse Barnes's avatar Jesse Barnes Committed by Daniel Vetter

drm/i915: update VLV PLL and DPIO code v11

In Valleyview voltage swing, pre-emphasis and lane control registers can
be programmed only through the h/w side band fabric.  Update
vlv_update_pll, i9xx_crtc_enable, and intel_enable_pll with the
appropriate programming.

We need to make sure that the tx lane reset occurs in both the full mode
set and DPMS paths, so factor things out to allow that.

v2: use different DPIO_DIVISOR values for VGA and DisplayPort
v3: Fix update pll logic to use same DPIO_DIVISOR & DPIO_REFSFR values
        for all display interfaces
v4: collapse with various updates
v5: squash with crtc enable/pll enable bits
v6: split out DP code (jbarnes)
    put phyready check under IS_VALLEYVIEW (jbarnes)
    remove unneeded check in 9xx pll div update (Jani)
    wrap VLV pll update call in IS_VALLEYVIEW (Jani)
    move port enable back to end of crtc enable (jbarnes)
    put phyready check under IS_VALLEYVIEW (jbarnes)
v7: fix up conflicts against latest drm-intel-next-queued
v8: use DPIO reg names, fix pipes (Jani)
    from mPhy_registers_VLV2_ww20p5 doc
v9: update to latest info from driver enabling notes doc
    driver_vbios_notes_9
v10: fixup a bit of pipe/port confusion to allow eDP and HDMI to work
     simultaneously (Jesse)
v11: use pll/port callbacks for DPIO port activity (Daniel)
     use separate VLV CRTC enable function (Daniel)
     move around port ready checks (Jesse)
Signed-off-by: default avatarPallavi G <pallavi.g@intel.com>
Signed-off-by: default avatarVijay Purushothaman <vijay.a.purushothaman@intel.com>
Signed-off-by: default avatarGajanan Bhat <gajanan.bhat@intel.com>
Signed-off-by: default avatarBen Widawsky <benjamin.widawsky@intel.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
[danvet: Drop pfit changes and add a little comment explaining that
vlv has a different enable sequence and so needs it's own crtc_enable
callback. Also apply a fixup patch from Wu Fengguang to shut up some
compiler warnings.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 78c9b7e7
...@@ -1576,6 +1576,20 @@ intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, ...@@ -1576,6 +1576,20 @@ intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
return I915_READ(SBI_DATA); return I915_READ(SBI_DATA);
} }
void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port)
{
u32 port_mask;
if (!port)
port_mask = DPLL_PORTB_READY_MASK;
else
port_mask = DPLL_PORTC_READY_MASK;
if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000))
WARN(1, "timed out waiting for port %c ready: 0x%08x\n",
'B' + port, I915_READ(DPLL(0)));
}
/** /**
* ironlake_enable_pch_pll - enable PCH PLL * ironlake_enable_pch_pll - enable PCH PLL
* @dev_priv: i915 private structure * @dev_priv: i915 private structure
...@@ -3678,6 +3692,52 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) ...@@ -3678,6 +3692,52 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe)
} }
} }
static void valleyview_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
WARN_ON(!crtc->enabled);
if (intel_crtc->active)
return;
intel_crtc->active = true;
intel_update_watermarks(dev);
mutex_lock(&dev_priv->dpio_lock);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_pll_enable)
encoder->pre_pll_enable(encoder);
intel_enable_pll(dev_priv, pipe);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_enable)
encoder->pre_enable(encoder);
/* VLV wants encoder enabling _before_ the pipe is up. */
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
intel_enable_pipe(dev_priv, pipe, false);
intel_enable_plane(dev_priv, plane, pipe);
intel_crtc_load_lut(crtc);
intel_update_fbc(dev);
/* Give the overlay scaler a chance to enable if it's on this pipe */
intel_crtc_dpms_overlay(intel_crtc, true);
intel_crtc_update_cursor(crtc, true);
mutex_unlock(&dev_priv->dpio_lock);
}
static void i9xx_crtc_enable(struct drm_crtc *crtc) static void i9xx_crtc_enable(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
...@@ -3766,6 +3826,10 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) ...@@ -3766,6 +3826,10 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
i9xx_pfit_disable(intel_crtc); i9xx_pfit_disable(intel_crtc);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->post_disable)
encoder->post_disable(encoder);
intel_disable_pll(dev_priv, pipe); intel_disable_pll(dev_priv, pipe);
intel_crtc->active = false; intel_crtc->active = false;
...@@ -4208,6 +4272,34 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc, ...@@ -4208,6 +4272,34 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
} }
} }
static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv)
{
u32 reg_val;
/*
* PLLB opamp always calibrates to max value of 0x3f, force enable it
* and set it to a reasonable value instead.
*/
reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1));
reg_val &= 0xffffff00;
reg_val |= 0x00000030;
intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION);
reg_val &= 0x8cffffff;
reg_val = 0x8c000000;
intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1));
reg_val &= 0xffffff00;
intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION);
reg_val &= 0x00ffffff;
reg_val |= 0xb0000000;
intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
}
static void intel_dp_set_m_n(struct intel_crtc *crtc) static void intel_dp_set_m_n(struct intel_crtc *crtc)
{ {
if (crtc->config.has_pch_encoder) if (crtc->config.has_pch_encoder)
...@@ -4220,24 +4312,18 @@ static void vlv_update_pll(struct intel_crtc *crtc) ...@@ -4220,24 +4312,18 @@ static void vlv_update_pll(struct intel_crtc *crtc)
{ {
struct drm_device *dev = crtc->base.dev; struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *adjusted_mode =
&crtc->config.adjusted_mode;
struct intel_encoder *encoder;
int pipe = crtc->pipe; int pipe = crtc->pipe;
u32 dpll, mdiv, pdiv; u32 dpll, mdiv;
u32 bestn, bestm1, bestm2, bestp1, bestp2; u32 bestn, bestm1, bestm2, bestp1, bestp2;
bool is_sdvo; bool is_hdmi;
u32 temp; u32 coreclk, reg_val, temp;
mutex_lock(&dev_priv->dpio_lock); mutex_lock(&dev_priv->dpio_lock);
is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || is_hdmi = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
dpll = DPLL_VGA_MODE_DIS;
dpll |= DPLL_EXT_BUFFER_ENABLE_VLV;
dpll |= DPLL_REFA_CLK_ENABLE_VLV;
dpll |= DPLL_INTEGRATED_CLOCK_VLV;
I915_WRITE(DPLL(pipe), dpll);
POSTING_READ(DPLL(pipe));
bestn = crtc->config.dpll.n; bestn = crtc->config.dpll.n;
bestm1 = crtc->config.dpll.m1; bestm1 = crtc->config.dpll.m1;
...@@ -4245,71 +4331,105 @@ static void vlv_update_pll(struct intel_crtc *crtc) ...@@ -4245,71 +4331,105 @@ static void vlv_update_pll(struct intel_crtc *crtc)
bestp1 = crtc->config.dpll.p1; bestp1 = crtc->config.dpll.p1;
bestp2 = crtc->config.dpll.p2; bestp2 = crtc->config.dpll.p2;
/* /* See eDP HDMI DPIO driver vbios notes doc */
* In Valleyview PLL and program lane counter registers are exposed
* through DPIO interface /* PLL B needs special handling */
*/ if (pipe)
vlv_pllb_recal_opamp(dev_priv);
/* Set up Tx target for periodic Rcomp update */
intel_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f);
/* Disable target IRef on PLL */
reg_val = intel_dpio_read(dev_priv, DPIO_IREF_CTL(pipe));
reg_val &= 0x00ffffff;
intel_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val);
/* Disable fast lock */
intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610);
/* Set idtafcrecal before PLL is enabled */
mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT));
mdiv |= ((bestn << DPIO_N_SHIFT)); mdiv |= ((bestn << DPIO_N_SHIFT));
mdiv |= (1 << DPIO_POST_DIV_SHIFT);
mdiv |= (1 << DPIO_K_SHIFT); mdiv |= (1 << DPIO_K_SHIFT);
mdiv |= DPIO_ENABLE_CALIBRATION; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI) ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT))
mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT);
intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000); mdiv |= DPIO_ENABLE_CALIBRATION;
intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
pdiv = (1 << DPIO_REFSEL_OVERRIDE) | (5 << DPIO_PLL_MODESEL_SHIFT) | /* Set HBR and RBR LPF coefficients */
(3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) | if (adjusted_mode->clock == 162000 ||
(7 << DPIO_PLL_REFCLK_SEL_SHIFT) | (8 << DPIO_DRIVER_CTL_SHIFT) | intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
(5 << DPIO_CLK_BIAS_CTL_SHIFT); intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe),
intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv); 0x005f0021);
else
intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe),
0x00d0000f);
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) {
/* Use SSC source */
if (!pipe)
intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
0x0df40000);
else
intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
0x0df70000);
} else { /* HDMI or VGA */
/* Use bend source */
if (!pipe)
intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
0x0df70000);
else
intel_dpio_write(dev_priv, DPIO_REFSFR(pipe),
0x0df40000);
}
intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f003b); coreclk = intel_dpio_read(dev_priv, DPIO_CORE_CLK(pipe));
coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP))
coreclk |= 0x01000000;
intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk);
dpll |= DPLL_VCO_ENABLE; intel_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
I915_WRITE(DPLL(pipe), dpll);
POSTING_READ(DPLL(pipe));
if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
DRM_ERROR("DPLL %d failed to lock\n", pipe);
intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620); for_each_encoder_on_crtc(dev, &crtc->base, encoder)
if (encoder->pre_pll_enable)
encoder->pre_pll_enable(encoder);
if (crtc->config.has_dp_encoder) /* Enable DPIO clock input */
intel_dp_set_m_n(crtc); dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV;
if (pipe)
dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
dpll |= DPLL_VCO_ENABLE;
I915_WRITE(DPLL(pipe), dpll); I915_WRITE(DPLL(pipe), dpll);
/* Wait for the clocks to stabilize. */
POSTING_READ(DPLL(pipe)); POSTING_READ(DPLL(pipe));
udelay(150); udelay(150);
temp = 0; if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
if (is_sdvo) { DRM_ERROR("DPLL %d failed to lock\n", pipe);
if (is_hdmi) {
temp = 0; temp = 0;
if (crtc->config.pixel_multiplier > 1) { if (crtc->config.pixel_multiplier > 1) {
temp = (crtc->config.pixel_multiplier - 1) temp = (crtc->config.pixel_multiplier - 1)
<< DPLL_MD_UDI_MULTIPLIER_SHIFT; << DPLL_MD_UDI_MULTIPLIER_SHIFT;
} }
}
I915_WRITE(DPLL_MD(pipe), temp);
POSTING_READ(DPLL_MD(pipe));
/* Now program lane control registers */ I915_WRITE(DPLL_MD(pipe), temp);
if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) POSTING_READ(DPLL_MD(pipe));
|| intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) {
temp = 0x1000C4;
if(pipe == 1)
temp |= (1 << 21);
intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp);
} }
if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { if (crtc->config.has_dp_encoder)
temp = 0x1000C4; intel_dp_set_m_n(crtc);
if(pipe == 1)
temp |= (1 << 21);
intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp);
}
mutex_unlock(&dev_priv->dpio_lock); mutex_unlock(&dev_priv->dpio_lock);
} }
...@@ -4699,7 +4819,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, ...@@ -4699,7 +4819,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
else else
i9xx_update_pll(intel_crtc, i9xx_update_pll(intel_crtc,
has_reduced_clock ? &reduced_clock : NULL, has_reduced_clock ? &reduced_clock : NULL,
num_connectors); num_connectors);
/* Set up the display plane register */ /* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE; dspcntr = DISPPLANE_GAMMA_ENABLE;
...@@ -8753,6 +8873,13 @@ static void intel_init_display(struct drm_device *dev) ...@@ -8753,6 +8873,13 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.crtc_disable = ironlake_crtc_disable; dev_priv->display.crtc_disable = ironlake_crtc_disable;
dev_priv->display.off = ironlake_crtc_off; dev_priv->display.off = ironlake_crtc_off;
dev_priv->display.update_plane = ironlake_update_plane; dev_priv->display.update_plane = ironlake_update_plane;
} else if (IS_VALLEYVIEW(dev)) {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
dev_priv->display.crtc_enable = valleyview_crtc_enable;
dev_priv->display.crtc_disable = i9xx_crtc_disable;
dev_priv->display.off = i9xx_crtc_off;
dev_priv->display.update_plane = i9xx_update_plane;
} else { } else {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
......
...@@ -1390,15 +1390,77 @@ static void intel_enable_dp(struct intel_encoder *encoder) ...@@ -1390,15 +1390,77 @@ static void intel_enable_dp(struct intel_encoder *encoder)
ironlake_edp_panel_vdd_off(intel_dp, true); ironlake_edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp); intel_dp_complete_link_train(intel_dp);
ironlake_edp_backlight_on(intel_dp); ironlake_edp_backlight_on(intel_dp);
if (IS_VALLEYVIEW(dev)) {
struct intel_digital_port *dport =
enc_to_dig_port(&encoder->base);
int channel = vlv_dport_to_channel(dport);
vlv_wait_port_ready(dev_priv, channel);
}
} }
static void intel_pre_enable_dp(struct intel_encoder *encoder) static void intel_pre_enable_dp(struct intel_encoder *encoder)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
ironlake_edp_pll_on(intel_dp); ironlake_edp_pll_on(intel_dp);
if (IS_VALLEYVIEW(dev)) {
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
struct intel_crtc *intel_crtc =
to_intel_crtc(encoder->base.crtc);
int port = vlv_dport_to_channel(dport);
int pipe = intel_crtc->pipe;
u32 val;
WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
val = 0;
if (pipe)
val |= (1<<21);
else
val &= ~(1<<21);
val |= 0x001000c4;
intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
0x00760018);
intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
0x00400888);
}
}
static void intel_dp_pre_pll_enable(struct intel_encoder *encoder)
{
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int port = vlv_dport_to_channel(dport);
if (!IS_VALLEYVIEW(dev))
return;
WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
/* Program Tx lane resets to default */
intel_dpio_write(dev_priv, DPIO_PCS_TX(port),
DPIO_PCS_TX_LANE2_RESET |
DPIO_PCS_TX_LANE1_RESET);
intel_dpio_write(dev_priv, DPIO_PCS_CLK(port),
DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
(1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
DPIO_PCS_CLK_SOFT_RESET);
/* Fix up inter-pair skew failure */
intel_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
intel_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
intel_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
} }
/* /*
...@@ -1542,6 +1604,8 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) ...@@ -1542,6 +1604,8 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
else else
BUG(); BUG();
WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
case DP_TRAIN_PRE_EMPHASIS_0: case DP_TRAIN_PRE_EMPHASIS_0:
preemph_reg_value = 0x0004000; preemph_reg_value = 0x0004000;
...@@ -1615,8 +1679,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) ...@@ -1615,8 +1679,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
return 0; return 0;
} }
/* eDP is only on port C */
mutex_lock(&dev_priv->dpio_lock);
intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000); intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000);
intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value); intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value);
intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port), intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
...@@ -1625,7 +1687,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) ...@@ -1625,7 +1687,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000); intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value); intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value);
intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000); intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000);
mutex_unlock(&dev_priv->dpio_lock);
return 0; return 0;
} }
...@@ -3078,6 +3139,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) ...@@ -3078,6 +3139,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_encoder->disable = intel_disable_dp; intel_encoder->disable = intel_disable_dp;
intel_encoder->post_disable = intel_post_disable_dp; intel_encoder->post_disable = intel_post_disable_dp;
intel_encoder->get_hw_state = intel_dp_get_hw_state; intel_encoder->get_hw_state = intel_dp_get_hw_state;
if (IS_VALLEYVIEW(dev))
intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable;
intel_dig_port->port = port; intel_dig_port->port = port;
intel_dig_port->dp.output_reg = output_reg; intel_dig_port->dp.output_reg = output_reg;
......
...@@ -431,6 +431,19 @@ struct intel_digital_port { ...@@ -431,6 +431,19 @@ struct intel_digital_port {
struct intel_hdmi hdmi; struct intel_hdmi hdmi;
}; };
static inline int
vlv_dport_to_channel(struct intel_digital_port *dport)
{
switch (dport->port) {
case PORT_B:
return 0;
case PORT_C:
return 1;
default:
BUG();
}
}
static inline struct drm_crtc * static inline struct drm_crtc *
intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
{ {
...@@ -606,6 +619,7 @@ intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, ...@@ -606,6 +619,7 @@ intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
extern int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); extern int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
extern void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port);
struct intel_load_detect_pipe { struct intel_load_detect_pipe {
struct drm_framebuffer *release_fb; struct drm_framebuffer *release_fb;
......
...@@ -697,6 +697,14 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) ...@@ -697,6 +697,14 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
I915_WRITE(intel_hdmi->hdmi_reg, temp); I915_WRITE(intel_hdmi->hdmi_reg, temp);
POSTING_READ(intel_hdmi->hdmi_reg); POSTING_READ(intel_hdmi->hdmi_reg);
} }
if (IS_VALLEYVIEW(dev)) {
struct intel_digital_port *dport =
enc_to_dig_port(&encoder->base);
int channel = vlv_dport_to_channel(dport);
vlv_wait_port_ready(dev_priv, channel);
}
} }
static void intel_disable_hdmi(struct intel_encoder *encoder) static void intel_disable_hdmi(struct intel_encoder *encoder)
...@@ -947,6 +955,101 @@ intel_hdmi_set_property(struct drm_connector *connector, ...@@ -947,6 +955,101 @@ intel_hdmi_set_property(struct drm_connector *connector,
return 0; return 0;
} }
static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
{
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc =
to_intel_crtc(encoder->base.crtc);
int port = vlv_dport_to_channel(dport);
int pipe = intel_crtc->pipe;
u32 val;
if (!IS_VALLEYVIEW(dev))
return;
WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
/* Enable clock channels for this port */
val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
val = 0;
if (pipe)
val |= (1<<21);
else
val &= ~(1<<21);
val |= 0x001000c4;
intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
/* HDMI 1.0V-2dB */
intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0);
intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port),
0x2b245f5f);
intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
0x5578b83a);
intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port),
0x0c782040);
intel_dpio_write(dev_priv, DPIO_TX3_SWING_CTL4(port),
0x2b247878);
intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
0x00002000);
intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
DPIO_TX_OCALINIT_EN);
/* Program lane clock */
intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
0x00760018);
intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
0x00400888);
}
static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder)
{
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int port = vlv_dport_to_channel(dport);
if (!IS_VALLEYVIEW(dev))
return;
WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
/* Program Tx lane resets to default */
intel_dpio_write(dev_priv, DPIO_PCS_TX(port),
DPIO_PCS_TX_LANE2_RESET |
DPIO_PCS_TX_LANE1_RESET);
intel_dpio_write(dev_priv, DPIO_PCS_CLK(port),
DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
(1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
DPIO_PCS_CLK_SOFT_RESET);
/* Fix up inter-pair skew failure */
intel_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
intel_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
intel_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
0x00002000);
intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
DPIO_TX_OCALINIT_EN);
}
static void intel_hdmi_post_disable(struct intel_encoder *encoder)
{
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
int port = vlv_dport_to_channel(dport);
/* Reset lanes to avoid HDMI flicker (VLV w/a) */
mutex_lock(&dev_priv->dpio_lock);
intel_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000);
intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060);
mutex_unlock(&dev_priv->dpio_lock);
}
static void intel_hdmi_destroy(struct drm_connector *connector) static void intel_hdmi_destroy(struct drm_connector *connector)
{ {
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
...@@ -1086,6 +1189,11 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) ...@@ -1086,6 +1189,11 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
intel_encoder->enable = intel_enable_hdmi; intel_encoder->enable = intel_enable_hdmi;
intel_encoder->disable = intel_disable_hdmi; intel_encoder->disable = intel_disable_hdmi;
intel_encoder->get_hw_state = intel_hdmi_get_hw_state; intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
if (IS_VALLEYVIEW(dev)) {
intel_encoder->pre_enable = intel_hdmi_pre_enable;
intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable;
intel_encoder->post_disable = intel_hdmi_post_disable;
}
intel_encoder->type = INTEL_OUTPUT_HDMI; intel_encoder->type = INTEL_OUTPUT_HDMI;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment