2016-07-05 10:40:20 +01:00
/*
* Copyright © 2016 Intel Corporation
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE .
*
*/
# include "i915_drv.h"
2016-12-01 14:49:55 +02:00
# define PLATFORM_NAME(x) [INTEL_##x] = #x
static const char * const platform_names [ ] = {
PLATFORM_NAME ( I830 ) ,
PLATFORM_NAME ( I845G ) ,
PLATFORM_NAME ( I85X ) ,
PLATFORM_NAME ( I865G ) ,
PLATFORM_NAME ( I915G ) ,
PLATFORM_NAME ( I915GM ) ,
PLATFORM_NAME ( I945G ) ,
PLATFORM_NAME ( I945GM ) ,
PLATFORM_NAME ( G33 ) ,
PLATFORM_NAME ( PINEVIEW ) ,
2016-12-07 12:13:04 +02:00
PLATFORM_NAME ( I965G ) ,
PLATFORM_NAME ( I965GM ) ,
2016-11-30 17:43:05 +02:00
PLATFORM_NAME ( G45 ) ,
PLATFORM_NAME ( GM45 ) ,
2016-12-01 14:49:55 +02:00
PLATFORM_NAME ( IRONLAKE ) ,
PLATFORM_NAME ( SANDYBRIDGE ) ,
PLATFORM_NAME ( IVYBRIDGE ) ,
PLATFORM_NAME ( VALLEYVIEW ) ,
PLATFORM_NAME ( HASWELL ) ,
PLATFORM_NAME ( BROADWELL ) ,
PLATFORM_NAME ( CHERRYVIEW ) ,
PLATFORM_NAME ( SKYLAKE ) ,
PLATFORM_NAME ( BROXTON ) ,
PLATFORM_NAME ( KABYLAKE ) ,
PLATFORM_NAME ( GEMINILAKE ) ,
} ;
# undef PLATFORM_NAME
const char * intel_platform_name ( enum intel_platform platform )
{
if ( WARN_ON_ONCE ( platform > = ARRAY_SIZE ( platform_names ) | |
platform_names [ platform ] = = NULL ) )
return " <unknown> " ;
return platform_names [ platform ] ;
}
2016-07-05 10:40:20 +01:00
void intel_device_info_dump ( struct drm_i915_private * dev_priv )
{
const struct intel_device_info * info = & dev_priv - > info ;
2016-12-01 14:49:55 +02:00
DRM_DEBUG_DRIVER ( " i915 device info: platform=%s gen=%i pciid=0x%04x rev=0x%02x " ,
intel_platform_name ( info - > platform ) ,
2016-07-05 10:40:20 +01:00
info - > gen ,
dev_priv - > drm . pdev - > device ,
2016-10-05 13:50:16 +03:00
dev_priv - > drm . pdev - > revision ) ;
# define PRINT_FLAG(name) \
DRM_DEBUG_DRIVER ( " i915 device info: " # name " : %s " , yesno ( info - > name ) )
DEV_INFO_FOR_EACH_FLAG ( PRINT_FLAG ) ;
2016-07-05 10:40:20 +01:00
# undef PRINT_FLAG
}
static void cherryview_sseu_info_init ( struct drm_i915_private * dev_priv )
{
2016-08-31 19:13:02 +03:00
struct sseu_dev_info * sseu = & mkwrite_device_info ( dev_priv ) - > sseu ;
2016-07-05 10:40:20 +01:00
u32 fuse , eu_dis ;
fuse = I915_READ ( CHV_FUSE_GT ) ;
2016-08-31 19:13:04 +03:00
sseu - > slice_mask = BIT ( 0 ) ;
2016-07-05 10:40:20 +01:00
if ( ! ( fuse & CHV_FGT_DISABLE_SS0 ) ) {
2016-08-31 19:13:05 +03:00
sseu - > subslice_mask | = BIT ( 0 ) ;
2016-07-05 10:40:20 +01:00
eu_dis = fuse & ( CHV_FGT_EU_DIS_SS0_R0_MASK |
CHV_FGT_EU_DIS_SS0_R1_MASK ) ;
2016-08-31 19:13:02 +03:00
sseu - > eu_total + = 8 - hweight32 ( eu_dis ) ;
2016-07-05 10:40:20 +01:00
}
if ( ! ( fuse & CHV_FGT_DISABLE_SS1 ) ) {
2016-08-31 19:13:05 +03:00
sseu - > subslice_mask | = BIT ( 1 ) ;
2016-07-05 10:40:20 +01:00
eu_dis = fuse & ( CHV_FGT_EU_DIS_SS1_R0_MASK |
CHV_FGT_EU_DIS_SS1_R1_MASK ) ;
2016-08-31 19:13:02 +03:00
sseu - > eu_total + = 8 - hweight32 ( eu_dis ) ;
2016-07-05 10:40:20 +01:00
}
/*
* CHV expected to always have a uniform distribution of EU
* across subslices .
*/
2016-08-31 19:13:05 +03:00
sseu - > eu_per_subslice = sseu_subslice_total ( sseu ) ?
sseu - > eu_total / sseu_subslice_total ( sseu ) :
2016-07-05 10:40:20 +01:00
0 ;
/*
* CHV supports subslice power gating on devices with more than
* one subslice , and supports EU power gating on devices with
* more than one EU pair per subslice .
*/
2016-08-31 19:13:02 +03:00
sseu - > has_slice_pg = 0 ;
2016-08-31 19:13:05 +03:00
sseu - > has_subslice_pg = sseu_subslice_total ( sseu ) > 1 ;
2016-08-31 19:13:02 +03:00
sseu - > has_eu_pg = ( sseu - > eu_per_subslice > 2 ) ;
2016-07-05 10:40:20 +01:00
}
static void gen9_sseu_info_init ( struct drm_i915_private * dev_priv )
{
struct intel_device_info * info = mkwrite_device_info ( dev_priv ) ;
2016-08-31 19:13:02 +03:00
struct sseu_dev_info * sseu = & info - > sseu ;
2016-07-05 10:40:20 +01:00
int s_max = 3 , ss_max = 4 , eu_max = 8 ;
int s , ss ;
2016-08-31 19:13:05 +03:00
u32 fuse2 , eu_disable ;
2016-07-05 10:40:20 +01:00
u8 eu_mask = 0xff ;
fuse2 = I915_READ ( GEN8_FUSE2 ) ;
2016-08-31 19:13:04 +03:00
sseu - > slice_mask = ( fuse2 & GEN8_F2_S_ENA_MASK ) > > GEN8_F2_S_ENA_SHIFT ;
2016-07-05 10:40:20 +01:00
/*
* The subslice disable field is global , i . e . it applies
* to each of the enabled slices .
*/
2016-08-31 19:13:05 +03:00
sseu - > subslice_mask = ( 1 < < ss_max ) - 1 ;
sseu - > subslice_mask & = ~ ( ( fuse2 & GEN9_F2_SS_DIS_MASK ) > >
GEN9_F2_SS_DIS_SHIFT ) ;
2016-07-05 10:40:20 +01:00
/*
* Iterate through enabled slices and subslices to
* count the total enabled EU .
*/
for ( s = 0 ; s < s_max ; s + + ) {
2016-08-31 19:13:04 +03:00
if ( ! ( sseu - > slice_mask & BIT ( s ) ) )
2016-07-05 10:40:20 +01:00
/* skip disabled slice */
continue ;
eu_disable = I915_READ ( GEN9_EU_DISABLE ( s ) ) ;
for ( ss = 0 ; ss < ss_max ; ss + + ) {
int eu_per_ss ;
2016-08-31 19:13:05 +03:00
if ( ! ( sseu - > subslice_mask & BIT ( ss ) ) )
2016-07-05 10:40:20 +01:00
/* skip disabled subslice */
continue ;
eu_per_ss = eu_max - hweight8 ( ( eu_disable > > ( ss * 8 ) ) &
eu_mask ) ;
/*
* Record which subslice ( s ) has ( have ) 7 EUs . we
* can tune the hash used to spread work among
* subslices if they are unbalanced .
*/
if ( eu_per_ss = = 7 )
2016-08-31 19:13:02 +03:00
sseu - > subslice_7eu [ s ] | = BIT ( ss ) ;
2016-07-05 10:40:20 +01:00
2016-08-31 19:13:02 +03:00
sseu - > eu_total + = eu_per_ss ;
2016-07-05 10:40:20 +01:00
}
}
/*
* SKL is expected to always have a uniform distribution
* of EU across subslices with the exception that any one
* EU in any one subslice may be fused off for die
* recovery . BXT is expected to be perfectly uniform in EU
* distribution .
*/
2016-08-31 19:13:05 +03:00
sseu - > eu_per_subslice = sseu_subslice_total ( sseu ) ?
2016-08-31 19:13:02 +03:00
DIV_ROUND_UP ( sseu - > eu_total ,
2016-08-31 19:13:05 +03:00
sseu_subslice_total ( sseu ) ) : 0 ;
2016-07-05 10:40:20 +01:00
/*
* SKL supports slice power gating on devices with more than
* one slice , and supports EU power gating on devices with
* more than one EU pair per subslice . BXT supports subslice
* power gating on devices with more than one subslice , and
* supports EU power gating on devices with more than one EU
* pair per subslice .
*/
2016-08-31 19:13:02 +03:00
sseu - > has_slice_pg =
2016-07-05 10:40:20 +01:00
( IS_SKYLAKE ( dev_priv ) | | IS_KABYLAKE ( dev_priv ) ) & &
2016-08-31 19:13:04 +03:00
hweight8 ( sseu - > slice_mask ) > 1 ;
2016-08-31 19:13:02 +03:00
sseu - > has_subslice_pg =
2017-01-09 16:51:35 +02:00
IS_GEN9_LP ( dev_priv ) & & sseu_subslice_total ( sseu ) > 1 ;
2016-08-31 19:13:02 +03:00
sseu - > has_eu_pg = sseu - > eu_per_subslice > 2 ;
2016-07-05 10:40:20 +01:00
if ( IS_BROXTON ( dev_priv ) ) {
2016-08-31 19:13:05 +03:00
# define IS_SS_DISABLED(ss) (!(sseu->subslice_mask & BIT(ss)))
2016-07-05 10:40:20 +01:00
/*
* There is a HW issue in 2 x6 fused down parts that requires
* Pooled EU to be enabled as a WA . The pool configuration
* changes depending upon which subslice is fused down . This
* doesn ' t affect if the device has all 3 subslices enabled .
*/
/* WaEnablePooledEuFor2x6:bxt */
2016-08-31 19:13:05 +03:00
info - > has_pooled_eu = ( ( hweight8 ( sseu - > subslice_mask ) = = 3 ) | |
( hweight8 ( sseu - > subslice_mask ) = = 2 & &
2016-07-05 10:40:20 +01:00
INTEL_REVID ( dev_priv ) < BXT_REVID_C0 ) ) ;
2016-08-31 19:13:02 +03:00
sseu - > min_eu_in_pool = 0 ;
2016-07-05 10:40:20 +01:00
if ( info - > has_pooled_eu ) {
2016-08-31 19:13:05 +03:00
if ( IS_SS_DISABLED ( 2 ) | | IS_SS_DISABLED ( 0 ) )
2016-08-31 19:13:02 +03:00
sseu - > min_eu_in_pool = 3 ;
2016-08-31 19:13:05 +03:00
else if ( IS_SS_DISABLED ( 1 ) )
2016-08-31 19:13:02 +03:00
sseu - > min_eu_in_pool = 6 ;
2016-07-05 10:40:20 +01:00
else
2016-08-31 19:13:02 +03:00
sseu - > min_eu_in_pool = 9 ;
2016-07-05 10:40:20 +01:00
}
# undef IS_SS_DISABLED
}
}
static void broadwell_sseu_info_init ( struct drm_i915_private * dev_priv )
{
2016-08-31 19:13:02 +03:00
struct sseu_dev_info * sseu = & mkwrite_device_info ( dev_priv ) - > sseu ;
2016-07-05 10:40:20 +01:00
const int s_max = 3 , ss_max = 3 , eu_max = 8 ;
int s , ss ;
2016-10-04 12:54:12 +03:00
u32 fuse2 , eu_disable [ 3 ] ; /* s_max */
2016-07-05 10:40:20 +01:00
fuse2 = I915_READ ( GEN8_FUSE2 ) ;
2016-08-31 19:13:04 +03:00
sseu - > slice_mask = ( fuse2 & GEN8_F2_S_ENA_MASK ) > > GEN8_F2_S_ENA_SHIFT ;
2016-08-31 19:13:05 +03:00
/*
* The subslice disable field is global , i . e . it applies
* to each of the enabled slices .
*/
sseu - > subslice_mask = BIT ( ss_max ) - 1 ;
sseu - > subslice_mask & = ~ ( ( fuse2 & GEN8_F2_SS_DIS_MASK ) > >
GEN8_F2_SS_DIS_SHIFT ) ;
2016-07-05 10:40:20 +01:00
eu_disable [ 0 ] = I915_READ ( GEN8_EU_DISABLE0 ) & GEN8_EU_DIS0_S0_MASK ;
eu_disable [ 1 ] = ( I915_READ ( GEN8_EU_DISABLE0 ) > > GEN8_EU_DIS0_S1_SHIFT ) |
( ( I915_READ ( GEN8_EU_DISABLE1 ) & GEN8_EU_DIS1_S1_MASK ) < <
( 32 - GEN8_EU_DIS0_S1_SHIFT ) ) ;
eu_disable [ 2 ] = ( I915_READ ( GEN8_EU_DISABLE1 ) > > GEN8_EU_DIS1_S2_SHIFT ) |
( ( I915_READ ( GEN8_EU_DISABLE2 ) & GEN8_EU_DIS2_S2_MASK ) < <
( 32 - GEN8_EU_DIS1_S2_SHIFT ) ) ;
/*
* Iterate through enabled slices and subslices to
* count the total enabled EU .
*/
for ( s = 0 ; s < s_max ; s + + ) {
2016-08-31 19:13:04 +03:00
if ( ! ( sseu - > slice_mask & BIT ( s ) ) )
2016-07-05 10:40:20 +01:00
/* skip disabled slice */
continue ;
for ( ss = 0 ; ss < ss_max ; ss + + ) {
u32 n_disabled ;
2016-08-31 19:13:05 +03:00
if ( ! ( sseu - > subslice_mask & BIT ( ss ) ) )
2016-07-05 10:40:20 +01:00
/* skip disabled subslice */
continue ;
n_disabled = hweight8 ( eu_disable [ s ] > > ( ss * eu_max ) ) ;
/*
* Record which subslices have 7 EUs .
*/
if ( eu_max - n_disabled = = 7 )
2016-08-31 19:13:02 +03:00
sseu - > subslice_7eu [ s ] | = 1 < < ss ;
2016-07-05 10:40:20 +01:00
2016-08-31 19:13:02 +03:00
sseu - > eu_total + = eu_max - n_disabled ;
2016-07-05 10:40:20 +01:00
}
}
/*
* BDW is expected to always have a uniform distribution of EU across
* subslices with the exception that any one EU in any one subslice may
* be fused off for die recovery .
*/
2016-08-31 19:13:05 +03:00
sseu - > eu_per_subslice = sseu_subslice_total ( sseu ) ?
DIV_ROUND_UP ( sseu - > eu_total ,
sseu_subslice_total ( sseu ) ) : 0 ;
2016-07-05 10:40:20 +01:00
/*
* BDW supports slice power gating on devices with more than
* one slice .
*/
2016-08-31 19:13:04 +03:00
sseu - > has_slice_pg = hweight8 ( sseu - > slice_mask ) > 1 ;
2016-08-31 19:13:02 +03:00
sseu - > has_subslice_pg = 0 ;
sseu - > has_eu_pg = 0 ;
2016-07-05 10:40:20 +01:00
}
/*
* Determine various intel_device_info fields at runtime .
*
* Use it when either :
* - it ' s judged too laborious to fill n static structures with the limit
* when a simple if statement does the job ,
* - run - time checks ( eg read fuse / strap registers ) are needed .
*
* This function needs to be called :
* - after the MMIO has been setup as we are reading registers ,
* - after the PCH has been detected ,
* - before the first usage of the fields it can tweak .
*/
void intel_device_info_runtime_init ( struct drm_i915_private * dev_priv )
{
struct intel_device_info * info = mkwrite_device_info ( dev_priv ) ;
enum pipe pipe ;
2017-01-02 15:54:41 +02:00
if ( INTEL_GEN ( dev_priv ) > = 9 ) {
info - > num_scalers [ PIPE_A ] = 2 ;
info - > num_scalers [ PIPE_B ] = 2 ;
info - > num_scalers [ PIPE_C ] = 1 ;
}
2016-07-05 10:40:20 +01:00
/*
* Skylake and Broxton currently don ' t expose the topmost plane as its
* use is exclusive with the legacy cursor and we only want to expose
* one of those , not both . Until we can safely expose the topmost plane
* as a DRM_PLANE_TYPE_CURSOR with all the features exposed / supported ,
* we don ' t expose the topmost plane at all to prevent ABI breakage
* down the line .
*/
2016-12-02 10:23:57 +02:00
if ( IS_GEMINILAKE ( dev_priv ) )
for_each_pipe ( dev_priv , pipe )
info - > num_sprites [ pipe ] = 3 ;
else if ( IS_BROXTON ( dev_priv ) ) {
2016-07-05 10:40:20 +01:00
info - > num_sprites [ PIPE_A ] = 2 ;
info - > num_sprites [ PIPE_B ] = 2 ;
info - > num_sprites [ PIPE_C ] = 1 ;
2016-10-25 18:58:00 +03:00
} else if ( IS_VALLEYVIEW ( dev_priv ) | | IS_CHERRYVIEW ( dev_priv ) ) {
2016-07-05 10:40:20 +01:00
for_each_pipe ( dev_priv , pipe )
info - > num_sprites [ pipe ] = 2 ;
2016-10-25 18:58:00 +03:00
} else if ( INTEL_GEN ( dev_priv ) > = 5 ) {
2016-07-05 10:40:20 +01:00
for_each_pipe ( dev_priv , pipe )
info - > num_sprites [ pipe ] = 1 ;
2016-10-25 18:58:00 +03:00
}
2016-07-05 10:40:20 +01:00
if ( i915 . disable_display ) {
DRM_INFO ( " Display disabled (module parameter) \n " ) ;
info - > num_pipes = 0 ;
} else if ( info - > num_pipes > 0 & &
( IS_GEN7 ( dev_priv ) | | IS_GEN8 ( dev_priv ) ) & &
HAS_PCH_SPLIT ( dev_priv ) ) {
u32 fuse_strap = I915_READ ( FUSE_STRAP ) ;
u32 sfuse_strap = I915_READ ( SFUSE_STRAP ) ;
/*
* SFUSE_STRAP is supposed to have a bit signalling the display
* is fused off . Unfortunately it seems that , at least in
* certain cases , fused off display means that PCH display
* reads don ' t land anywhere . In that case , we read 0 s .
*
* On CPT / PPT , we can detect this case as SFUSE_STRAP_FUSE_LOCK
* should be set when taking over after the firmware .
*/
if ( fuse_strap & ILK_INTERNAL_DISPLAY_DISABLE | |
sfuse_strap & SFUSE_STRAP_DISPLAY_DISABLED | |
( dev_priv - > pch_type = = PCH_CPT & &
! ( sfuse_strap & SFUSE_STRAP_FUSE_LOCK ) ) ) {
DRM_INFO ( " Display fused off, disabling \n " ) ;
info - > num_pipes = 0 ;
} else if ( fuse_strap & IVB_PIPE_C_DISABLE ) {
DRM_INFO ( " PipeC fused off \n " ) ;
info - > num_pipes - = 1 ;
}
} else if ( info - > num_pipes > 0 & & IS_GEN9 ( dev_priv ) ) {
u32 dfsm = I915_READ ( SKL_DFSM ) ;
u8 disabled_mask = 0 ;
bool invalid ;
int num_bits ;
if ( dfsm & SKL_DFSM_PIPE_A_DISABLE )
disabled_mask | = BIT ( PIPE_A ) ;
if ( dfsm & SKL_DFSM_PIPE_B_DISABLE )
disabled_mask | = BIT ( PIPE_B ) ;
if ( dfsm & SKL_DFSM_PIPE_C_DISABLE )
disabled_mask | = BIT ( PIPE_C ) ;
num_bits = hweight8 ( disabled_mask ) ;
switch ( disabled_mask ) {
case BIT ( PIPE_A ) :
case BIT ( PIPE_B ) :
case BIT ( PIPE_A ) | BIT ( PIPE_B ) :
case BIT ( PIPE_A ) | BIT ( PIPE_C ) :
invalid = true ;
break ;
default :
invalid = false ;
}
if ( num_bits > info - > num_pipes | | invalid )
DRM_ERROR ( " invalid pipe fuse configuration: 0x%x \n " ,
disabled_mask ) ;
else
info - > num_pipes - = num_bits ;
}
/* Initialize slice/subslice/EU info */
if ( IS_CHERRYVIEW ( dev_priv ) )
cherryview_sseu_info_init ( dev_priv ) ;
else if ( IS_BROADWELL ( dev_priv ) )
broadwell_sseu_info_init ( dev_priv ) ;
else if ( INTEL_INFO ( dev_priv ) - > gen > = 9 )
gen9_sseu_info_init ( dev_priv ) ;
info - > has_snoop = ! info - > has_llc ;
/* Snooping is broken on BXT A stepping. */
if ( IS_BXT_REVID ( dev_priv , 0 , BXT_REVID_A1 ) )
info - > has_snoop = false ;
2016-08-31 19:13:06 +03:00
DRM_DEBUG_DRIVER ( " slice mask: %04x \n " , info - > sseu . slice_mask ) ;
2016-08-31 19:13:04 +03:00
DRM_DEBUG_DRIVER ( " slice total: %u \n " , hweight8 ( info - > sseu . slice_mask ) ) ;
2016-08-31 19:13:05 +03:00
DRM_DEBUG_DRIVER ( " subslice total: %u \n " ,
sseu_subslice_total ( & info - > sseu ) ) ;
2016-08-31 19:13:06 +03:00
DRM_DEBUG_DRIVER ( " subslice mask %04x \n " , info - > sseu . subslice_mask ) ;
2016-08-31 19:13:02 +03:00
DRM_DEBUG_DRIVER ( " subslice per slice: %u \n " ,
2016-08-31 19:13:05 +03:00
hweight8 ( info - > sseu . subslice_mask ) ) ;
2016-08-31 19:13:02 +03:00
DRM_DEBUG_DRIVER ( " EU total: %u \n " , info - > sseu . eu_total ) ;
DRM_DEBUG_DRIVER ( " EU per subslice: %u \n " , info - > sseu . eu_per_subslice ) ;
2016-07-05 10:40:20 +01:00
DRM_DEBUG_DRIVER ( " has slice power gating: %s \n " ,
2016-08-31 19:13:02 +03:00
info - > sseu . has_slice_pg ? " y " : " n " ) ;
2016-07-05 10:40:20 +01:00
DRM_DEBUG_DRIVER ( " has subslice power gating: %s \n " ,
2016-08-31 19:13:02 +03:00
info - > sseu . has_subslice_pg ? " y " : " n " ) ;
2016-07-05 10:40:20 +01:00
DRM_DEBUG_DRIVER ( " has EU power gating: %s \n " ,
2016-08-31 19:13:02 +03:00
info - > sseu . has_eu_pg ? " y " : " n " ) ;
2016-07-05 10:40:20 +01:00
}