@ -911,26 +911,28 @@ static void assert_pll(struct drm_i915_private *dev_priv,
/* For ILK+ */
static void assert_pch_pll ( struct drm_i915_private * dev_priv ,
enum pipe pipe , bool state )
struct intel_crtc * intel_crtc , bool state )
{
int reg ;
u32 val ;
bool cur_state ;
if ( ! intel_crtc - > pch_pll ) {
WARN ( 1 , " asserting PCH PLL enabled with no PLL \n " ) ;
return ;
}
if ( HAS_PCH_CPT ( dev_priv - > dev ) ) {
u32 pch_dpll ;
pch_dpll = I915_READ ( PCH_DPLL_SEL ) ;
/* Make sure the selected PLL is enabled to the transcoder */
WARN ( ! ( ( pch_dpll > > ( 4 * pipe ) ) & 8 ) ,
" transcoder %d PLL not enabled \n " , pipe ) ;
/* Convert the transcoder pipe number to a pll pipe number */
pipe = ( pch_dpll > > ( 4 * pipe ) ) & 1 ;
WARN ( ! ( ( pch_dpll > > ( 4 * intel_crtc - > pipe ) ) & 8 ) ,
" transcoder %d PLL not enabled \n " , intel_crtc - > pipe ) ;
}
reg = PCH_DPLL ( pipe ) ;
reg = intel_crtc - > pch_pll - > pll_reg ;
val = I915_READ ( reg ) ;
cur_state = ! ! ( val & DPLL_VCO_ENABLE ) ;
WARN ( cur_state ! = state ,
@ -1306,60 +1308,79 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
* The PCH PLL needs to be enabled before the PCH transcoder , since it
* drives the transcoder clock .
*/
static void intel_enable_pch_pll ( struct drm_i915_private * dev_priv ,
enum pipe pipe )
static void intel_enable_pch_pll ( struct intel_crtc * intel_crtc )
{
struct drm_i915_private * dev_priv = intel_crtc - > base . dev - > dev_private ;
struct intel_pch_pll * pll = intel_crtc - > pch_pll ;
int reg ;
u32 val ;
if ( pipe > 1 )
return ;
/* PCH only available on ILK+ */
BUG_ON ( dev_priv - > info - > gen < 5 ) ;
BUG_ON ( pll = = NULL ) ;
BUG_ON ( pll - > refcount = = 0 ) ;
DRM_DEBUG_KMS ( " enable PCH PLL %x (active %d, on? %d)for crtc %d \n " ,
pll - > pll_reg , pll - > active , pll - > on ,
intel_crtc - > base . base . id ) ;
/* PCH refclock must be enabled first */
assert_pch_refclk_enabled ( dev_priv ) ;
reg = PCH_DPLL ( pipe ) ;
if ( pll - > active + + & & pll - > on ) {
assert_pch_pll_enabled ( dev_priv , intel_crtc ) ;
return ;
}
DRM_DEBUG_KMS ( " enabling PCH PLL %x \n " , pll - > pll_reg ) ;
reg = pll - > pll_reg ;
val = I915_READ ( reg ) ;
val | = DPLL_VCO_ENABLE ;
I915_WRITE ( reg , val ) ;
POSTING_READ ( reg ) ;
udelay ( 200 ) ;
pll - > on = true ;
}
static void intel_disable_pch_pll ( struct drm_i915_private * dev_priv ,
enum pipe pipe )
static void intel_disable_pch_pll ( struct intel_crtc * intel_crtc )
{
struct drm_i915_private * dev_priv = intel_crtc - > base . dev - > dev_private ;
struct intel_pch_pll * pll = intel_crtc - > pch_pll ;
int reg ;
u32 val , pll_mask = TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL ,
pll_sel = TRANSC_DPLL_ENABLE ;
if ( pipe > 1 )
return ;
u32 val ;
/* PCH only available on ILK+ */
BUG_ON ( dev_priv - > info - > gen < 5 ) ;
if ( pll = = NULL )
return ;
/* Make sure transcoder isn't still depending on us */
assert_transcoder_disabled ( dev_priv , pipe ) ;
if ( pipe = = 0 )
pll_sel | = TRANSC_DPLLA_SEL ;
else if ( pipe = = 1 )
pll_sel | = TRANSC_DPLLB_SEL ;
BUG_ON ( pll - > refcount = = 0 ) ;
DRM_DEBUG_KMS ( " disable PCH PLL %x (active %d, on? %d) for crtc %d \n " ,
pll - > pll_reg , pll - > active , pll - > on ,
intel_crtc - > base . base . id ) ;
if ( ( I915_READ ( PCH_DPLL_SEL ) & pll_mask ) = = pll_sel )
BUG_ON ( pll - > active = = 0 ) ;
if ( - - pll - > active ) {
assert_pch_pll_enabled ( dev_priv , intel_crtc ) ;
return ;
}
DRM_DEBUG_KMS ( " disabling PCH PLL %x \n " , pll - > pll_reg ) ;
/* Make sure transcoder isn't still depending on us */
assert_transcoder_disabled ( dev_priv , intel_crtc - > pipe ) ;
reg = PCH_DPLL ( pipe ) ;
reg = pll - > pll_reg ;
val = I915_READ ( reg ) ;
val & = ~ DPLL_VCO_ENABLE ;
I915_WRITE ( reg , val ) ;
POSTING_READ ( reg ) ;
udelay ( 200 ) ;
pll - > on = false ;
}
static void intel_enable_transcoder ( struct drm_i915_private * dev_priv ,
@ -1373,7 +1394,7 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
BUG_ON ( dev_priv - > info - > gen < 5 ) ;
/* Make sure PCH DPLL is enabled */
assert_pch_pll_enabled ( dev_priv , pipe ) ;
assert_pch_pll_enabled ( dev_priv , to_intel_crtc ( crtc ) ) ;
/* FDI must be feeding us bits for PCH ports */
assert_fdi_tx_enabled ( dev_priv , pipe ) ;
@ -2578,29 +2599,36 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
int pipe = intel_crtc - > pipe ;
u32 reg , temp , transc_sel ;
u32 reg , temp ;
/* For PCH output, training FDI link */
dev_priv - > display . fdi_link_train ( crtc ) ;
intel_enable_pch_pll ( dev_priv , pipe ) ;
intel_enable_pch_pll ( intel_crtc ) ;
if ( HAS_PCH_CPT ( dev ) ) {
transc_sel = intel_crtc - > use_pll_a ? TRANSC_DPLLA_SEL :
TRANSC_DPLLB_SEL ;
u32 sel ;
/* Be sure PCH DPLL SEL is set */
temp = I915_READ ( PCH_DPLL_SEL ) ;
if ( pipe = = 0 ) {
temp & = ~ ( TRANSA_DPLLB_SEL ) ;
temp | = ( TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL ) ;
} else if ( pipe = = 1 ) {
temp & = ~ ( TRANSB_DPLLB_SEL ) ;
temp | = ( TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL ) ;
} else if ( pipe = = 2 ) {
temp & = ~ ( TRANSC_DPLLB_SEL ) ;
temp | = ( TRANSC_DPLL_ENABLE | transc_sel ) ;
switch ( pipe ) {
default :
case 0 :
temp | = TRANSA_DPLL_ENABLE ;
sel = TRANSA_DPLLB_SEL ;
break ;
case 1 :
temp | = TRANSB_DPLL_ENABLE ;
sel = TRANSB_DPLLB_SEL ;
break ;
case 2 :
temp | = TRANSC_DPLL_ENABLE ;
sel = TRANSC_DPLLB_SEL ;
break ;
}
if ( intel_crtc - > pch_pll - > pll_reg = = _PCH_DPLL_B )
temp | = sel ;
else
temp & = ~ sel ;
I915_WRITE ( PCH_DPLL_SEL , temp ) ;
}
@ -2658,6 +2686,79 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
intel_enable_transcoder ( dev_priv , pipe ) ;
}
static void intel_put_pch_pll ( struct intel_crtc * intel_crtc )
{
struct intel_pch_pll * pll = intel_crtc - > pch_pll ;
if ( pll = = NULL )
return ;
if ( pll - > refcount = = 0 ) {
WARN ( 1 , " bad PCH PLL refcount \n " ) ;
return ;
}
- - pll - > refcount ;
intel_crtc - > pch_pll = NULL ;
}
static struct intel_pch_pll * intel_get_pch_pll ( struct intel_crtc * intel_crtc , u32 dpll , u32 fp )
{
struct drm_i915_private * dev_priv = intel_crtc - > base . dev - > dev_private ;
struct intel_pch_pll * pll ;
int i ;
pll = intel_crtc - > pch_pll ;
if ( pll ) {
DRM_DEBUG_KMS ( " CRTC:%d reusing existing PCH PLL %x \n " ,
intel_crtc - > base . base . id , pll - > pll_reg ) ;
goto prepare ;
}
for ( i = 0 ; i < dev_priv - > num_pch_pll ; i + + ) {
pll = & dev_priv - > pch_plls [ i ] ;
/* Only want to check enabled timings first */
if ( pll - > refcount = = 0 )
continue ;
if ( dpll = = ( I915_READ ( pll - > pll_reg ) & 0x7fffffff ) & &
fp = = I915_READ ( pll - > fp0_reg ) ) {
DRM_DEBUG_KMS ( " CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d) \n " ,
intel_crtc - > base . base . id ,
pll - > pll_reg , pll - > refcount , pll - > active ) ;
goto found ;
}
}
/* Ok no matching timings, maybe there's a free one? */
for ( i = 0 ; i < dev_priv - > num_pch_pll ; i + + ) {
pll = & dev_priv - > pch_plls [ i ] ;
if ( pll - > refcount = = 0 ) {
DRM_DEBUG_KMS ( " CRTC:%d allocated PCH PLL %x \n " ,
intel_crtc - > base . base . id , pll - > pll_reg ) ;
goto found ;
}
}
return NULL ;
found :
intel_crtc - > pch_pll = pll ;
pll - > refcount + + ;
DRM_DEBUG_DRIVER ( " using pll %d for pipe %d \n " , i , intel_crtc - > pipe ) ;
prepare : /* separate function? */
DRM_DEBUG_DRIVER ( " switching PLL %x off \n " , pll - > pll_reg ) ;
I915_WRITE ( pll - > fp0_reg , fp ) ;
I915_WRITE ( pll - > pll_reg , dpll & ~ DPLL_VCO_ENABLE ) ;
POSTING_READ ( pll - > pll_reg ) ;
udelay ( 150 ) ;
pll - > on = false ;
return pll ;
}
void intel_cpt_verify_modeset ( struct drm_device * dev , int pipe )
{
struct drm_i915_private * dev_priv = dev - > dev_private ;
@ -2802,8 +2903,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
}
/* disable PCH DPLL */
if ( ! intel_crtc - > no_pll )
intel_disable_pch_pll ( dev_priv , pipe ) ;
intel_disable_pch_pll ( intel_crtc ) ;
/* Switch from PCDclk to Rawclk */
reg = FDI_RX_CTL ( pipe ) ;
@ -2859,6 +2959,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
static void ironlake_crtc_off ( struct drm_crtc * crtc )
{
struct intel_crtc * intel_crtc = to_intel_crtc ( crtc ) ;
intel_put_pch_pll ( intel_crtc ) ;
}
static void intel_crtc_dpms_overlay ( struct intel_crtc * intel_crtc , bool enable )
{
if ( ! enable & & intel_crtc - > overlay ) {
@ -2950,6 +3056,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
static void i9xx_crtc_off ( struct drm_crtc * crtc )
{
}
/**
* Sets the power management mode of the pipe and plane .
*/
@ -2997,8 +3107,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
{
struct drm_crtc_helper_funcs * crtc_funcs = crtc - > helper_private ;
struct drm_device * dev = crtc - > dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
crtc_funcs - > dpms ( crtc , DRM_MODE_DPMS_OFF ) ;
dev_priv - > display . off ( crtc ) ;
assert_plane_disabled ( dev - > dev_private , to_intel_crtc ( crtc ) - > plane ) ;
assert_pipe_disabled ( dev - > dev_private , to_intel_crtc ( crtc ) - > pipe ) ;
@ -4238,29 +4351,18 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
DRM_DEBUG_KMS ( " Mode for pipe %d: \n " , pipe ) ;
drm_mode_debug_printmodeline ( mode ) ;
/* PCH eDP needs FDI, but CPU eDP does not */
if ( ! intel_crtc - > no_pll ) {
if ( ! is_cpu_edp ) {
I915_WRITE ( PCH_FP0 ( pipe ) , fp ) ;
I915_WRITE ( PCH_DPLL ( pipe ) , dpll & ~ DPLL_VCO_ENABLE ) ;
/* CPU eDP is the only output that doesn't need a PCH PLL of its own */
if ( ! is_cpu_edp ) {
struct intel_pch_pll * pll ;
POSTING_READ ( PCH_DPLL ( pipe ) ) ;
udelay ( 150 ) ;
}
} else {
if ( dpll = = ( I915_READ ( PCH_DPLL ( 0 ) ) & 0x7fffffff ) & &
fp = = I915_READ ( PCH_FP0 ( 0 ) ) ) {
intel_crtc - > use_pll_a = true ;
DRM_DEBUG_KMS ( " using pipe a dpll \n " ) ;
} else if ( dpll = = ( I915_READ ( PCH_DPLL ( 1 ) ) & 0x7fffffff ) & &
fp = = I915_READ ( PCH_FP0 ( 1 ) ) ) {
intel_crtc - > use_pll_a = false ;
DRM_DEBUG_KMS ( " using pipe b dpll \n " ) ;
} else {
DRM_DEBUG_KMS ( " no matching PLL configuration for pipe 2 \n " ) ;
pll = intel_get_pch_pll ( intel_crtc , dpll , fp ) ;
if ( pll = = NULL ) {
DRM_DEBUG_DRIVER ( " failed to find PLL for pipe %d \n " ,
pipe ) ;
return - EINVAL ;
}
}
} else
intel_put_pch_pll ( intel_crtc ) ;
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn ' t turn
@ -4317,11 +4419,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE ( TRANSDPLINK_N1 ( pipe ) , 0 ) ;
}
if ( ! intel_crtc - > no_pll & & ( ! edp_encoder | | is_pch_edp ) ) {
I915_WRITE ( PCH_DPLL ( pipe ) , dpll ) ;
if ( intel_crtc - > pch_pll ) {
I915_WRITE ( intel_crtc - > pch_pll - > pll_reg , dpll ) ;
/* Wait for the clocks to stabilize. */
POSTING_READ ( PCH_DPLL ( pipe ) ) ;
POSTING_READ ( intel_crtc - > pch_pll - > pll_reg ) ;
udelay ( 150 ) ;
/* The pixel multiplier can only be updated once the
@ -4329,20 +4431,20 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
*
* So write it again .
*/
I915_WRITE ( PCH_DPLL ( pipe ) , dpll ) ;
I915_WRITE ( intel_crtc - > pch_pll - > pll_reg , dpll ) ;
}
intel_crtc - > lowfreq_avail = false ;
if ( ! intel_crtc - > no _pll) {
if ( intel_crtc - > pch _pll) {
if ( is_lvds & & has_reduced_clock & & i915_powersave ) {
I915_WRITE ( PCH_FP1 ( pipe ) , fp2 ) ;
I915_WRITE ( intel_crtc - > pch_pll - > fp1_reg , fp2 ) ;
intel_crtc - > lowfreq_avail = true ;
if ( HAS_PIPE_CXSR ( dev ) ) {
DRM_DEBUG_KMS ( " enabling CxSR downclocking \n " ) ;
pipeconf | = PIPECONF_CXSR_DOWNCLOCK ;
}
} else {
I915_WRITE ( PCH_FP1 ( pipe ) , fp ) ;
I915_WRITE ( intel_crtc - > pch_pll - > fp1_reg , fp ) ;
if ( HAS_PIPE_CXSR ( dev ) ) {
DRM_DEBUG_KMS ( " disabling CxSR downclocking \n " ) ;
pipeconf & = ~ PIPECONF_CXSR_DOWNCLOCK ;
@ -6016,6 +6118,23 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
. page_flip = intel_crtc_page_flip ,
} ;
static void intel_pch_pll_init ( struct drm_device * dev )
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
int i ;
if ( dev_priv - > num_pch_pll = = 0 ) {
DRM_DEBUG_KMS ( " No PCH PLLs on this hardware, skipping initialisation \n " ) ;
return ;
}
for ( i = 0 ; i < dev_priv - > num_pch_pll ; i + + ) {
dev_priv - > pch_plls [ i ] . pll_reg = _PCH_DPLL ( i ) ;
dev_priv - > pch_plls [ i ] . fp0_reg = _PCH_FP0 ( i ) ;
dev_priv - > pch_plls [ i ] . fp1_reg = _PCH_FP1 ( i ) ;
}
}
static void intel_crtc_init ( struct drm_device * dev , int pipe )
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
@ -6053,8 +6172,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc - > bpp = 24 ; /* default for pre-Ironlake */
if ( HAS_PCH_SPLIT ( dev ) ) {
if ( pipe = = 2 & & IS_IVYBRIDGE ( dev ) )
intel_crtc - > no_pll = true ;
intel_helper_funcs . prepare = ironlake_crtc_prepare ;
intel_helper_funcs . commit = ironlake_crtc_commit ;
} else {
@ -6337,10 +6454,12 @@ static void intel_init_display(struct drm_device *dev)
if ( HAS_PCH_SPLIT ( dev ) ) {
dev_priv - > display . dpms = ironlake_crtc_dpms ;
dev_priv - > display . crtc_mode_set = ironlake_crtc_mode_set ;
dev_priv - > display . off = ironlake_crtc_off ;
dev_priv - > display . update_plane = ironlake_update_plane ;
} else {
dev_priv - > display . dpms = i9xx_crtc_dpms ;
dev_priv - > display . crtc_mode_set = i9xx_crtc_mode_set ;
dev_priv - > display . off = i9xx_crtc_off ;
dev_priv - > display . update_plane = i9xx_update_plane ;
}
@ -6603,6 +6722,8 @@ void intel_modeset_init(struct drm_device *dev)
DRM_DEBUG_KMS ( " plane %d init failed: %d \n " , i , ret ) ;
}
intel_pch_pll_init ( dev ) ;
/* Just disable it once at startup */
i915_disable_vga ( dev ) ;
intel_setup_outputs ( dev ) ;