2022-02-09 13:35:23 +02:00
// SPDX-License-Identifier: MIT
/*
* Copyright © 2022 Intel Corporation
*/
# include "hsw_ips.h"
# include "i915_drv.h"
# include "i915_reg.h"
# include "intel_de.h"
# include "intel_display_types.h"
# include "intel_pcode.h"
static void hsw_ips_enable ( const struct intel_crtc_state * crtc_state )
{
struct intel_crtc * crtc = to_intel_crtc ( crtc_state - > uapi . crtc ) ;
struct drm_i915_private * i915 = to_i915 ( crtc - > base . dev ) ;
if ( ! crtc_state - > ips_enabled )
return ;
/*
* We can only enable IPS after we enable a plane and wait for a vblank
* This function is called from post_plane_update , which is run after
* a vblank wait .
*/
drm_WARN_ON ( & i915 - > drm ,
! ( crtc_state - > active_planes & ~ BIT ( PLANE_CURSOR ) ) ) ;
if ( IS_BROADWELL ( i915 ) ) {
drm_WARN_ON ( & i915 - > drm ,
snb_pcode_write ( i915 , DISPLAY_IPS_CONTROL ,
IPS_ENABLE | IPS_PCODE_CONTROL ) ) ;
/*
* Quoting Art Runyan : " its not safe to expect any particular
* value in IPS_CTL bit 31 after enabling IPS through the
* mailbox . " Moreover, the mailbox may return a bogus state,
* so we need to just enable it and continue on .
*/
} else {
intel_de_write ( i915 , IPS_CTL , IPS_ENABLE ) ;
/*
* The bit only becomes 1 in the next vblank , so this wait here
* is essentially intel_wait_for_vblank . If we don ' t have this
* and don ' t wait for vblanks until the end of crtc_enable , then
* the HW state readout code will complain that the expected
* IPS_CTL value is not the one we read .
*/
if ( intel_de_wait_for_set ( i915 , IPS_CTL , IPS_ENABLE , 50 ) )
drm_err ( & i915 - > drm ,
" Timed out waiting for IPS enable \n " ) ;
}
}
bool hsw_ips_disable ( const struct intel_crtc_state * crtc_state )
{
struct intel_crtc * crtc = to_intel_crtc ( crtc_state - > uapi . crtc ) ;
struct drm_i915_private * i915 = to_i915 ( crtc - > base . dev ) ;
bool need_vblank_wait = false ;
if ( ! crtc_state - > ips_enabled )
return need_vblank_wait ;
if ( IS_BROADWELL ( i915 ) ) {
drm_WARN_ON ( & i915 - > drm ,
snb_pcode_write ( i915 , DISPLAY_IPS_CONTROL , 0 ) ) ;
/*
* Wait for PCODE to finish disabling IPS . The BSpec specified
* 42 ms timeout value leads to occasional timeouts so use 100 ms
* instead .
*/
if ( intel_de_wait_for_clear ( i915 , IPS_CTL , IPS_ENABLE , 100 ) )
drm_err ( & i915 - > drm ,
" Timed out waiting for IPS disable \n " ) ;
} else {
intel_de_write ( i915 , IPS_CTL , 0 ) ;
intel_de_posting_read ( i915 , IPS_CTL ) ;
}
/* We need to wait for a vblank before we can disable the plane. */
need_vblank_wait = true ;
return need_vblank_wait ;
}
static bool hsw_ips_need_disable ( struct intel_atomic_state * state ,
struct intel_crtc * crtc )
{
struct drm_i915_private * i915 = to_i915 ( state - > base . dev ) ;
const struct intel_crtc_state * old_crtc_state =
intel_atomic_get_old_crtc_state ( state , crtc ) ;
const struct intel_crtc_state * new_crtc_state =
intel_atomic_get_new_crtc_state ( state , crtc ) ;
if ( ! old_crtc_state - > ips_enabled )
return false ;
if ( intel_crtc_needs_modeset ( new_crtc_state ) )
return true ;
/*
* Workaround : Do not read or write the pipe palette / gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled .
*
* Disable IPS before we program the LUT .
*/
if ( IS_HASWELL ( i915 ) & &
( new_crtc_state - > uapi . color_mgmt_changed | |
new_crtc_state - > update_pipe ) & &
new_crtc_state - > gamma_mode = = GAMMA_MODE_MODE_SPLIT )
return true ;
return ! new_crtc_state - > ips_enabled ;
}
bool hsw_ips_pre_update ( struct intel_atomic_state * state ,
struct intel_crtc * crtc )
{
const struct intel_crtc_state * old_crtc_state =
intel_atomic_get_old_crtc_state ( state , crtc ) ;
if ( ! hsw_ips_need_disable ( state , crtc ) )
return false ;
return hsw_ips_disable ( old_crtc_state ) ;
}
static bool hsw_ips_need_enable ( struct intel_atomic_state * state ,
struct intel_crtc * crtc )
{
struct drm_i915_private * i915 = to_i915 ( state - > base . dev ) ;
const struct intel_crtc_state * old_crtc_state =
intel_atomic_get_old_crtc_state ( state , crtc ) ;
const struct intel_crtc_state * new_crtc_state =
intel_atomic_get_new_crtc_state ( state , crtc ) ;
if ( ! new_crtc_state - > ips_enabled )
return false ;
if ( intel_crtc_needs_modeset ( new_crtc_state ) )
return true ;
/*
* Workaround : Do not read or write the pipe palette / gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled .
*
* Re - enable IPS after the LUT has been programmed .
*/
if ( IS_HASWELL ( i915 ) & &
( new_crtc_state - > uapi . color_mgmt_changed | |
new_crtc_state - > update_pipe ) & &
new_crtc_state - > gamma_mode = = GAMMA_MODE_MODE_SPLIT )
return true ;
/*
* We can ' t read out IPS on broadwell , assume the worst and
* forcibly enable IPS on the first fastset .
*/
if ( new_crtc_state - > update_pipe & & old_crtc_state - > inherited )
return true ;
return ! old_crtc_state - > ips_enabled ;
}
void hsw_ips_post_update ( struct intel_atomic_state * state ,
struct intel_crtc * crtc )
{
const struct intel_crtc_state * new_crtc_state =
intel_atomic_get_new_crtc_state ( state , crtc ) ;
if ( ! hsw_ips_need_enable ( state , crtc ) )
return ;
hsw_ips_enable ( new_crtc_state ) ;
}
/* IPS only exists on ULT machines and is tied to pipe A. */
bool hsw_crtc_supports_ips ( struct intel_crtc * crtc )
{
return HAS_IPS ( to_i915 ( crtc - > base . dev ) ) & & crtc - > pipe = = PIPE_A ;
}
bool hsw_crtc_state_ips_capable ( const struct intel_crtc_state * crtc_state )
{
struct intel_crtc * crtc = to_intel_crtc ( crtc_state - > uapi . crtc ) ;
struct drm_i915_private * i915 = to_i915 ( crtc - > base . dev ) ;
/* IPS only exists on ULT machines and is tied to pipe A. */
if ( ! hsw_crtc_supports_ips ( crtc ) )
return false ;
if ( ! i915 - > params . enable_ips )
return false ;
if ( crtc_state - > pipe_bpp > 24 )
return false ;
/*
* We compare against max which means we must take
* the increased cdclk requirement into account when
* calculating the new cdclk .
*
* Should measure whether using a lower cdclk w / o IPS
*/
if ( IS_BROADWELL ( i915 ) & &
crtc_state - > pixel_rate > i915 - > max_cdclk_freq * 95 / 100 )
return false ;
return true ;
}
int hsw_ips_compute_config ( struct intel_atomic_state * state ,
struct intel_crtc * crtc )
{
struct drm_i915_private * i915 = to_i915 ( state - > base . dev ) ;
struct intel_crtc_state * crtc_state =
intel_atomic_get_new_crtc_state ( state , crtc ) ;
crtc_state - > ips_enabled = false ;
if ( ! hsw_crtc_state_ips_capable ( crtc_state ) )
return 0 ;
/*
* When IPS gets enabled , the pipe CRC changes . Since IPS gets
* enabled and disabled dynamically based on package C states ,
* user space can ' t make reliable use of the CRCs , so let ' s just
* completely disable it .
*/
if ( crtc_state - > crc_enabled )
return 0 ;
/* IPS should be fine as long as at least one plane is enabled. */
if ( ! ( crtc_state - > active_planes & ~ BIT ( PLANE_CURSOR ) ) )
return 0 ;
if ( IS_BROADWELL ( i915 ) ) {
const struct intel_cdclk_state * cdclk_state ;
cdclk_state = intel_atomic_get_cdclk_state ( state ) ;
if ( IS_ERR ( cdclk_state ) )
return PTR_ERR ( cdclk_state ) ;
/* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
if ( crtc_state - > pixel_rate > cdclk_state - > logical . cdclk * 95 / 100 )
return 0 ;
}
crtc_state - > ips_enabled = true ;
return 0 ;
}
2022-02-09 13:35:24 +02:00
void hsw_ips_get_config ( struct intel_crtc_state * crtc_state )
{
struct intel_crtc * crtc = to_intel_crtc ( crtc_state - > uapi . crtc ) ;
struct drm_i915_private * i915 = to_i915 ( crtc - > base . dev ) ;
if ( ! hsw_crtc_supports_ips ( crtc ) )
return ;
if ( IS_HASWELL ( i915 ) ) {
crtc_state - > ips_enabled = intel_de_read ( i915 , IPS_CTL ) & IPS_ENABLE ;
} else {
/*
* We cannot readout IPS state on broadwell , set to
* true so we can set it to a defined state on first
* commit .
*/
crtc_state - > ips_enabled = true ;
}
}