Unfortunately this requires a bunch of exports for pch handling functions, but there's been various plans floating around to extract them all into an intel_pch.c helper library anyway. In any case haswell_crtc_enable is now pch encoder free. Signed-off-by: Daniel Vetter <daniel.vetter@xxxxxxxx> --- drivers/gpu/drm/i915/intel_crt.c | 147 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_display.c | 160 ++--------------------------------- drivers/gpu/drm/i915/intel_drv.h | 14 +++ 3 files changed, 168 insertions(+), 153 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ec806e432545..9d7135b878c0 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -354,6 +354,150 @@ static void intel_enable_crt(struct intel_encoder *encoder) intel_crt_set_dpms(encoder, crt->connector->base.dpms); } +/* Program iCLKIP clock to the desired frequency */ +static void lpt_program_iclkip(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; + u32 divsel, phaseinc, auxdiv, phasedir = 0; + u32 temp; + + mutex_lock(&dev_priv->dpio_lock); + + /* It is necessary to ungate the pixclk gate prior to programming + * the divisors, and gate it back when it is done. + */ + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE); + + /* Disable SSCCTL */ + intel_sbi_write(dev_priv, SBI_SSCCTL6, + intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK) | + SBI_SSCCTL_DISABLE, + SBI_ICLK); + + /* 20MHz is a corner case which is out of range for the 7-bit divisor */ + if (clock == 20000) { + auxdiv = 1; + divsel = 0x41; + phaseinc = 0x20; + } else { + /* The iCLK virtual clock root frequency is in MHz, + * but the adjusted_mode->crtc_clock in in KHz. To get the + * divisors, it is necessary to divide one by another, so we + * convert the virtual clock precision to KHz here for higher + * precision. + */ + u32 iclk_virtual_root_freq = 172800 * 1000; + u32 iclk_pi_range = 64; + u32 desired_divisor, msb_divisor_value, pi_value; + + desired_divisor = (iclk_virtual_root_freq / clock); + msb_divisor_value = desired_divisor / iclk_pi_range; + pi_value = desired_divisor % iclk_pi_range; + + auxdiv = 0; + divsel = msb_divisor_value - 2; + phaseinc = pi_value; + } + + /* This should not happen with any sane values */ + WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) & + ~SBI_SSCDIVINTPHASE_DIVSEL_MASK); + WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) & + ~SBI_SSCDIVINTPHASE_INCVAL_MASK); + + DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n", + clock, + auxdiv, + divsel, + phasedir, + phaseinc); + + /* Program SSCDIVINTPHASE6 */ + temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK); + temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; + temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); + temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; + temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); + temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); + temp |= SBI_SSCDIVINTPHASE_PROPAGATE; + intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK); + + /* Program SSCAUXDIV */ + temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK); + temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1); + temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv); + intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK); + + /* Enable modulator and associated divider */ + temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK); + temp &= ~SBI_SSCCTL_DISABLE; + intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK); + + /* Wait for initialization time */ + udelay(24); + + I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); + + mutex_unlock(&dev_priv->dpio_lock); +} + +static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) +{ + u32 val, pipeconf_val; + + /* PCH only available on ILK+ */ + BUG_ON(INTEL_INFO(dev_priv->dev)->gen < 5); + + /* FDI must be feeding us bits for PCH ports */ + assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); + assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); + + /* Workaround: set timing override bit. */ + val = I915_READ(_TRANSA_CHICKEN2); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(_TRANSA_CHICKEN2, val); + + val = TRANS_ENABLE; + pipeconf_val = I915_READ(PIPECONF(cpu_transcoder)); + + if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == + PIPECONF_INTERLACED_ILK) + val |= TRANS_INTERLACED; + else + val |= TRANS_PROGRESSIVE; + + I915_WRITE(LPT_TRANSCONF, val); + if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("Failed to enable PCH transcoder\n"); +} + +static void lpt_pch_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); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + + assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A); + + lpt_program_iclkip(crtc); + + /* Set transcoder timing. */ + ironlake_pch_transcoder_set_timings(intel_crtc, PIPE_A); + + lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); +} + +static void hsw_crt_enable(struct intel_encoder *encoder) +{ + lpt_pch_enable(encoder->base.crtc); + + intel_enable_crt(encoder); +} + /* Special dpms function to support cloning between dvo/sdvo/crt. */ static void intel_crt_dpms(struct drm_connector *connector, int mode) { @@ -1006,16 +1150,17 @@ void intel_crt_init(struct drm_device *dev) crt->base.compute_config = intel_crt_compute_config; crt->base.disable = intel_disable_crt; - crt->base.enable = intel_enable_crt; if (I915_HAS_HOTPLUG(dev)) crt->base.hpd_pin = HPD_CRT; if (HAS_DDI(dev)) { crt->base.get_config = hsw_crt_get_config; crt->base.get_hw_state = hsw_crt_get_hw_state; crt->base.pre_enable = hsw_crt_pre_enable; + crt->base.enable = hsw_crt_enable; } else { crt->base.get_config = intel_crt_get_config; crt->base.get_hw_state = intel_crt_get_hw_state; + crt->base.enable = intel_enable_crt; } intel_connector->get_hw_state = intel_connector_get_hw_state; intel_connector->unregister = intel_connector_unregister; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 43a40594841f..26b2eceb0d63 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -992,8 +992,8 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, pll->name, state_string(state), state_string(cur_state)); } -static void assert_fdi_tx(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) +void assert_fdi_tx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) { int reg; u32 val; @@ -1015,11 +1015,9 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, "FDI TX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } -#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true) -#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false) -static void assert_fdi_rx(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) +void assert_fdi_rx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) { int reg; u32 val; @@ -1032,8 +1030,6 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv, "FDI RX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } -#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true) -#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false) static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, enum pipe pipe) @@ -1236,8 +1232,8 @@ static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); } -static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe) +void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) { int reg; u32 val; @@ -1692,37 +1688,6 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, DRM_ERROR("failed to enable transcoder %c\n", pipe_name(pipe)); } -static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder) -{ - u32 val, pipeconf_val; - - /* PCH only available on ILK+ */ - BUG_ON(INTEL_INFO(dev_priv->dev)->gen < 5); - - /* FDI must be feeding us bits for PCH ports */ - assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); - assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); - - /* Workaround: set timing override bit. */ - val = I915_READ(_TRANSA_CHICKEN2); - val |= TRANS_CHICKEN2_TIMING_OVERRIDE; - I915_WRITE(_TRANSA_CHICKEN2, val); - - val = TRANS_ENABLE; - pipeconf_val = I915_READ(PIPECONF(cpu_transcoder)); - - if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == - PIPECONF_INTERLACED_ILK) - val |= TRANS_INTERLACED; - else - val |= TRANS_PROGRESSIVE; - - I915_WRITE(LPT_TRANSCONF, val); - if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100)) - DRM_ERROR("Failed to enable PCH transcoder\n"); -} - static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, enum pipe pipe) { @@ -3120,97 +3085,8 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -/* Program iCLKIP clock to the desired frequency */ -static void lpt_program_iclkip(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - u32 divsel, phaseinc, auxdiv, phasedir = 0; - u32 temp; - - mutex_lock(&dev_priv->dpio_lock); - - /* It is necessary to ungate the pixclk gate prior to programming - * the divisors, and gate it back when it is done. - */ - I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE); - - /* Disable SSCCTL */ - intel_sbi_write(dev_priv, SBI_SSCCTL6, - intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK) | - SBI_SSCCTL_DISABLE, - SBI_ICLK); - - /* 20MHz is a corner case which is out of range for the 7-bit divisor */ - if (clock == 20000) { - auxdiv = 1; - divsel = 0x41; - phaseinc = 0x20; - } else { - /* The iCLK virtual clock root frequency is in MHz, - * but the adjusted_mode->crtc_clock in in KHz. To get the - * divisors, it is necessary to divide one by another, so we - * convert the virtual clock precision to KHz here for higher - * precision. - */ - u32 iclk_virtual_root_freq = 172800 * 1000; - u32 iclk_pi_range = 64; - u32 desired_divisor, msb_divisor_value, pi_value; - - desired_divisor = (iclk_virtual_root_freq / clock); - msb_divisor_value = desired_divisor / iclk_pi_range; - pi_value = desired_divisor % iclk_pi_range; - - auxdiv = 0; - divsel = msb_divisor_value - 2; - phaseinc = pi_value; - } - - /* This should not happen with any sane values */ - WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) & - ~SBI_SSCDIVINTPHASE_DIVSEL_MASK); - WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) & - ~SBI_SSCDIVINTPHASE_INCVAL_MASK); - - DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n", - clock, - auxdiv, - divsel, - phasedir, - phaseinc); - - /* Program SSCDIVINTPHASE6 */ - temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK); - temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; - temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); - temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; - temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); - temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); - temp |= SBI_SSCDIVINTPHASE_PROPAGATE; - intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK); - - /* Program SSCAUXDIV */ - temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK); - temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1); - temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv); - intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK); - - /* Enable modulator and associated divider */ - temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK); - temp &= ~SBI_SSCCTL_DISABLE; - intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK); - - /* Wait for initialization time */ - udelay(24); - - I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); - - mutex_unlock(&dev_priv->dpio_lock); -} - -static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc, - enum pipe pch_transcoder) +void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc, + enum pipe pch_transcoder) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -3373,23 +3249,6 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) ironlake_enable_pch_transcoder(dev_priv, pipe); } -static void lpt_pch_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); - enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; - - assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A); - - lpt_program_iclkip(crtc); - - /* Set transcoder timing. */ - ironlake_pch_transcoder_set_timings(intel_crtc, PIPE_A); - - lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); -} - static void intel_put_shared_dpll(struct intel_crtc *crtc) { struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); @@ -3876,9 +3735,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); - if (intel_crtc->config.has_pch_encoder) - lpt_pch_enable(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) { encoder->enable(encoder); intel_opregion_notify_encoder(encoder, true); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7f1d7f675953..5b8e34c6907e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -782,6 +782,20 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_config *pipe_config); int intel_format_to_fourcc(int format); +/* pch handling code shared with intel_crt on hsw/lpt */ +void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc, + enum pipe pch_transcoder); +void assert_fdi_tx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state); +#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true) +#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false) +void assert_fdi_rx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state); +#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true) +#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false) +void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe); + /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, -- 1.8.1.4 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx