@ -1,5 +1,5 @@
/*
* Copyright ( c ) 2016 - 2018 , The Linux Foundation . All rights reserved .
* Copyright ( c ) 2016 - 2019 , The Linux Foundation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
@ -1628,7 +1628,7 @@ static void adjust_timing_by_ctrl_count(const struct dsi_display *display,
mode - > timing . h_back_porch / = sublinks_count ;
mode - > timing . h_skew / = sublinks_count ;
mode - > pixel_clk_khz / = sublinks_count ;
} else if ( display - > ctrl_count > 1 ) {
} else {
mode - > timing . h_active / = display - > ctrl_count ;
mode - > timing . h_front_porch / = display - > ctrl_count ;
mode - > timing . h_sync_width / = display - > ctrl_count ;
@ -2255,7 +2255,7 @@ static int dsi_display_set_clk_src(struct dsi_display *display)
m_ctrl = & display - > ctrl [ display - > clk_master_idx ] ;
rc = dsi_ctrl_set_clock_source ( m_ctrl - > ctrl ,
& display - > clock_info . src _clks) ;
& display - > clock_info . mux _clks) ;
if ( rc ) {
pr_err ( " [%s] failed to set source clocks for master, rc=%d \n " ,
display - > name , rc ) ;
@ -2269,7 +2269,7 @@ static int dsi_display_set_clk_src(struct dsi_display *display)
continue ;
rc = dsi_ctrl_set_clock_source ( ctrl - > ctrl ,
& display - > clock_info . src _clks) ;
& display - > clock_info . mux _clks) ;
if ( rc ) {
pr_err ( " [%s] failed to set source clocks, rc=%d \n " ,
display - > name , rc ) ;
@ -2938,6 +2938,7 @@ static int dsi_display_clocks_init(struct dsi_display *display)
struct dsi_clk_link_set * src = & display - > clock_info . src_clks ;
struct dsi_clk_link_set * mux = & display - > clock_info . mux_clks ;
struct dsi_clk_link_set * shadow = & display - > clock_info . shadow_clks ;
struct dsi_dyn_clk_caps * dyn_clk_caps = & ( display - > panel - > dyn_clk_caps ) ;
num_clk = dsi_display_get_clocks_count ( display ) ;
@ -2953,7 +2954,32 @@ static int dsi_display_clocks_init(struct dsi_display *display)
rc = PTR_ERR ( dsi_clk ) ;
pr_err ( " failed to get %s, rc=%d \n " , clk_name , rc ) ;
goto error ;
if ( dsi_display_check_prefix ( mux_byte , clk_name ) ) {
mux - > byte_clk = NULL ;
goto error ;
}
if ( dsi_display_check_prefix ( mux_pixel , clk_name ) ) {
mux - > pixel_clk = NULL ;
goto error ;
}
if ( dyn_clk_caps - > dyn_clk_support ) {
if ( dsi_display_check_prefix ( src_byte ,
clk_name ) )
src - > byte_clk = NULL ;
if ( dsi_display_check_prefix ( src_pixel ,
clk_name ) )
src - > pixel_clk = NULL ;
if ( dsi_display_check_prefix ( shadow_byte ,
clk_name ) )
shadow - > byte_clk = NULL ;
if ( dsi_display_check_prefix ( shadow_pixel ,
clk_name ) )
shadow - > pixel_clk = NULL ;
dyn_clk_caps - > dyn_clk_support = false ;
}
}
if ( dsi_display_check_prefix ( src_byte , clk_name ) ) {
@ -3746,6 +3772,305 @@ static bool dsi_display_is_seamless_dfps_possible(
return true ;
}
static int dsi_display_update_dsi_bitrate ( struct dsi_display * display ,
u32 bit_clk_rate )
{
int rc = 0 ;
int i ;
pr_debug ( " %s:bit rate:%d \n " , __func__ , bit_clk_rate ) ;
if ( ! display - > panel ) {
pr_err ( " Invalid params \n " ) ;
return - EINVAL ;
}
if ( bit_clk_rate = = 0 ) {
pr_err ( " Invalid bit clock rate \n " ) ;
return - EINVAL ;
}
display - > config . bit_clk_rate_hz = bit_clk_rate ;
for ( i = 0 ; i < display - > ctrl_count ; i + + ) {
struct dsi_display_ctrl * dsi_disp_ctrl = & display - > ctrl [ i ] ;
struct dsi_ctrl * ctrl = dsi_disp_ctrl - > ctrl ;
u32 num_of_lanes = 0 , bpp ;
u64 bit_rate , pclk_rate , bit_rate_per_lane , byte_clk_rate ;
struct dsi_host_common_cfg * host_cfg ;
mutex_lock ( & ctrl - > ctrl_lock ) ;
host_cfg = & display - > panel - > host_config ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_0 )
num_of_lanes + + ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_1 )
num_of_lanes + + ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_2 )
num_of_lanes + + ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_3 )
num_of_lanes + + ;
if ( num_of_lanes = = 0 ) {
pr_err ( " Invalid lane count \n " ) ;
rc = - EINVAL ;
goto error ;
}
bpp = dsi_pixel_format_to_bpp ( host_cfg - > dst_format ) ;
bit_rate = display - > config . bit_clk_rate_hz * num_of_lanes ;
bit_rate_per_lane = bit_rate ;
do_div ( bit_rate_per_lane , num_of_lanes ) ;
pclk_rate = bit_rate ;
do_div ( pclk_rate , bpp ) ;
byte_clk_rate = bit_rate_per_lane ;
do_div ( byte_clk_rate , 8 ) ;
pr_debug ( " bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu \n " ,
bit_rate , bit_rate_per_lane ) ;
pr_debug ( " byte_clk_rate = %llu, pclk_rate = %llu \n " ,
byte_clk_rate , pclk_rate ) ;
ctrl - > clk_freq . byte_clk_rate = byte_clk_rate ;
ctrl - > clk_freq . pix_clk_rate = pclk_rate ;
rc = dsi_clk_set_link_frequencies ( display - > dsi_clk_handle ,
ctrl - > clk_freq , ctrl - > cell_index ) ;
if ( rc ) {
pr_err ( " Failed to update link frequencies \n " ) ;
goto error ;
}
ctrl - > host_config . bit_clk_rate_hz = bit_clk_rate ;
error :
mutex_unlock ( & ctrl - > ctrl_lock ) ;
/* TODO: recover ctrl->clk_freq in case of failure */
if ( rc )
return rc ;
}
return 0 ;
}
static void _dsi_display_calc_pipe_delay ( struct dsi_display * display ,
struct dsi_dyn_clk_delay * delay ,
struct dsi_display_mode * mode )
{
u32 esc_clk_rate_hz ;
u32 pclk_to_esc_ratio , byte_to_esc_ratio , hr_bit_to_esc_ratio ;
u32 hsync_period = 0 ;
struct dsi_display_ctrl * m_ctrl ;
struct dsi_ctrl * dsi_ctrl ;
struct dsi_phy_cfg * cfg ;
m_ctrl = & display - > ctrl [ display - > clk_master_idx ] ;
dsi_ctrl = m_ctrl - > ctrl ;
cfg = & ( m_ctrl - > phy - > cfg ) ;
esc_clk_rate_hz = dsi_ctrl - > clk_freq . esc_clk_rate * 1000 ;
pclk_to_esc_ratio = ( ( dsi_ctrl - > clk_freq . pix_clk_rate * 1000 ) /
esc_clk_rate_hz ) ;
byte_to_esc_ratio = ( ( dsi_ctrl - > clk_freq . byte_clk_rate * 1000 ) /
esc_clk_rate_hz ) ;
hr_bit_to_esc_ratio = ( ( dsi_ctrl - > clk_freq . byte_clk_rate * 4 * 1000 ) /
esc_clk_rate_hz ) ;
hsync_period = DSI_H_TOTAL_DSC ( & mode - > timing ) ;
delay - > pipe_delay = ( hsync_period + 1 ) / pclk_to_esc_ratio ;
if ( ! display - > panel - > video_config . eof_bllp_lp11_en )
delay - > pipe_delay + = ( 17 / pclk_to_esc_ratio ) +
( ( 21 + ( display - > config . common_config . t_clk_pre + 1 ) +
( display - > config . common_config . t_clk_post + 1 ) ) /
byte_to_esc_ratio ) +
( ( ( ( cfg - > timing . lane_v3 [ 8 ] > > 1 ) + 1 ) +
( ( cfg - > timing . lane_v3 [ 6 ] > > 1 ) + 1 ) +
( ( cfg - > timing . lane_v3 [ 3 ] * 4 ) +
( cfg - > timing . lane_v3 [ 5 ] > > 1 ) + 1 ) +
( ( cfg - > timing . lane_v3 [ 7 ] > > 1 ) + 1 ) +
( ( cfg - > timing . lane_v3 [ 1 ] > > 1 ) + 1 ) +
( ( cfg - > timing . lane_v3 [ 4 ] > > 1 ) + 1 ) ) /
hr_bit_to_esc_ratio ) ;
delay - > pipe_delay2 = 0 ;
if ( display - > panel - > host_config . force_hs_clk_lane )
delay - > pipe_delay2 = ( 6 / byte_to_esc_ratio ) +
( ( ( ( cfg - > timing . lane_v3 [ 1 ] > > 1 ) + 1 ) +
( ( cfg - > timing . lane_v3 [ 4 ] > > 1 ) + 1 ) ) /
hr_bit_to_esc_ratio ) ;
/* 130 us pll delay recommended by h/w doc */
delay - > pll_delay = ( ( 130 * esc_clk_rate_hz ) / 1000000 ) * 2 ;
}
static int _dsi_display_dyn_update_clks ( struct dsi_display * display ,
struct link_clk_freq * bkp_freq )
{
int rc = 0 , i ;
struct dsi_display_ctrl * m_ctrl , * ctrl ;
m_ctrl = & display - > ctrl [ display - > clk_master_idx ] ;
dsi_clk_prepare_enable ( & display - > clock_info . src_clks ) ;
rc = dsi_clk_update_parent ( & display - > clock_info . shadow_clks ,
& display - > clock_info . mux_clks ) ;
if ( rc ) {
pr_err ( " failed update mux parent to shadow \n " ) ;
goto exit ;
}
for ( i = 0 ; ( i < display - > ctrl_count ) & &
( i < MAX_DSI_CTRLS_PER_DISPLAY ) ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
if ( ! ctrl - > ctrl )
continue ;
rc = dsi_clk_set_byte_clk_rate ( display - > dsi_clk_handle ,
ctrl - > ctrl - > clk_freq . byte_clk_rate , i ) ;
if ( rc ) {
pr_err ( " failed to set byte rate for index:%d \n " , i ) ;
goto recover_byte_clk ;
}
rc = dsi_clk_set_pixel_clk_rate ( display - > dsi_clk_handle ,
ctrl - > ctrl - > clk_freq . pix_clk_rate , i ) ;
if ( rc ) {
pr_err ( " failed to set pix rate for index:%d \n " , i ) ;
goto recover_pix_clk ;
}
}
for ( i = 0 ; ( i < display - > ctrl_count ) & &
( i < MAX_DSI_CTRLS_PER_DISPLAY ) ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
if ( ctrl = = m_ctrl )
continue ;
dsi_phy_dynamic_refresh_trigger ( ctrl - > phy , false ) ;
}
dsi_phy_dynamic_refresh_trigger ( m_ctrl - > phy , true ) ;
/* wait for dynamic refresh done */
for ( i = 0 ; ( i < display - > ctrl_count ) & &
( i < MAX_DSI_CTRLS_PER_DISPLAY ) ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
rc = dsi_ctrl_wait4dynamic_refresh_done ( ctrl - > ctrl ) ;
if ( rc ) {
pr_err ( " wait4dynamic refresh failed for dsi:%d \n " , i ) ;
goto recover_pix_clk ;
} else {
pr_info ( " dynamic refresh done on dsi: %s \n " ,
i ? " slave " : " master " ) ;
}
}
for ( i = 0 ; ( i < display - > ctrl_count ) & &
( i < MAX_DSI_CTRLS_PER_DISPLAY ) ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
dsi_phy_dynamic_refresh_clear ( ctrl - > phy ) ;
}
rc = dsi_clk_update_parent ( & display - > clock_info . src_clks ,
& display - > clock_info . mux_clks ) ;
if ( rc )
pr_err ( " could not switch back to src clks %d \n " , rc ) ;
dsi_clk_disable_unprepare ( & display - > clock_info . src_clks ) ;
return rc ;
recover_pix_clk :
for ( i = 0 ; ( i < display - > ctrl_count ) & &
( i < MAX_DSI_CTRLS_PER_DISPLAY ) ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
if ( ! ctrl - > ctrl )
continue ;
dsi_clk_set_pixel_clk_rate ( display - > dsi_clk_handle ,
bkp_freq - > pix_clk_rate , i ) ;
}
recover_byte_clk :
for ( i = 0 ; ( i < display - > ctrl_count ) & &
( i < MAX_DSI_CTRLS_PER_DISPLAY ) ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
if ( ! ctrl - > ctrl )
continue ;
dsi_clk_set_byte_clk_rate ( display - > dsi_clk_handle ,
bkp_freq - > byte_clk_rate , i ) ;
}
exit :
dsi_clk_disable_unprepare ( & display - > clock_info . src_clks ) ;
return rc ;
}
static int dsi_display_dynamic_clk_switch ( struct dsi_display * display ,
struct dsi_display_mode * mode )
{
int rc = 0 , mask , i ;
struct dsi_display_ctrl * m_ctrl , * ctrl ;
struct dsi_dyn_clk_delay delay ;
struct link_clk_freq bkp_freq ;
dsi_panel_acquire_panel_lock ( display - > panel ) ;
m_ctrl = & display - > ctrl [ display - > clk_master_idx ] ;
dsi_display_clk_ctrl ( display - > dsi_clk_handle , DSI_ALL_CLKS , DSI_CLK_ON ) ;
/* mask PLL unlock, FIFO overflow and underflow errors */
mask = BIT ( DSI_PLL_UNLOCK_ERR ) | BIT ( DSI_FIFO_UNDERFLOW ) |
BIT ( DSI_FIFO_OVERFLOW ) ;
dsi_display_mask_ctrl_error_interrupts ( display , mask , true ) ;
/* update the phy timings based on new mode */
for ( i = 0 ; i < display - > ctrl_count ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
dsi_phy_update_phy_timings ( ctrl - > phy , & display - > config ) ;
}
/* back up existing rates to handle failure case */
bkp_freq . byte_clk_rate = m_ctrl - > ctrl - > clk_freq . byte_clk_rate ;
bkp_freq . pix_clk_rate = m_ctrl - > ctrl - > clk_freq . pix_clk_rate ;
bkp_freq . esc_clk_rate = m_ctrl - > ctrl - > clk_freq . esc_clk_rate ;
rc = dsi_display_update_dsi_bitrate ( display , mode - > timing . clk_rate_hz ) ;
if ( rc ) {
pr_err ( " failed set link frequencies %d \n " , rc ) ;
goto exit ;
}
/* calculate pipe delays */
_dsi_display_calc_pipe_delay ( display , & delay , mode ) ;
/* configure dynamic refresh ctrl registers */
for ( i = 0 ; i < display - > ctrl_count ; i + + ) {
ctrl = & display - > ctrl [ i ] ;
if ( ! ctrl - > phy )
continue ;
if ( ctrl = = m_ctrl )
dsi_phy_config_dynamic_refresh ( ctrl - > phy , & delay , true ) ;
else
dsi_phy_config_dynamic_refresh ( ctrl - > phy , & delay ,
false ) ;
}
rc = _dsi_display_dyn_update_clks ( display , & bkp_freq ) ;
exit :
dsi_display_mask_ctrl_error_interrupts ( display , mask , false ) ;
dsi_display_clk_ctrl ( display - > dsi_clk_handle , DSI_ALL_CLKS ,
DSI_CLK_OFF ) ;
/* store newly calculated phy timings in mode private info */
dsi_phy_dyn_refresh_cache_phy_timings ( m_ctrl - > phy ,
mode - > priv_info - > phy_timing_val ,
mode - > priv_info - > phy_timing_len ) ;
dsi_panel_release_panel_lock ( display - > panel ) ;
return rc ;
}
static int dsi_display_dfps_update ( struct dsi_display * display ,
struct dsi_display_mode * dsi_mode )
{
@ -4011,6 +4336,16 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
display - > name , rc ) ;
goto error ;
}
} else if ( mode - > dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK ) {
rc = dsi_display_dynamic_clk_switch ( display , mode ) ;
if ( rc )
pr_err ( " dynamic clk change failed %d \n " , rc ) ;
/*
* skip rest of the opearations since
* dsi_display_dynamic_clk_switch ( ) already takes
* care of them .
*/
return rc ;
}
display_for_each_ctrl ( i , display ) {
@ -4255,85 +4590,6 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
return rc ;
}
static int dsi_display_request_update_dsi_bitrate ( struct dsi_display * display ,
u32 bit_clk_rate )
{
int rc = 0 ;
int i ;
pr_debug ( " %s:bit rate:%d \n " , __func__ , bit_clk_rate ) ;
if ( ! display - > panel ) {
pr_err ( " Invalid params \n " ) ;
return - EINVAL ;
}
if ( bit_clk_rate = = 0 ) {
pr_err ( " Invalid bit clock rate \n " ) ;
return - EINVAL ;
}
display - > config . bit_clk_rate_hz_override = bit_clk_rate ;
display_for_each_ctrl ( i , display ) {
struct dsi_display_ctrl * dsi_disp_ctrl = & display - > ctrl [ i ] ;
struct dsi_ctrl * ctrl = dsi_disp_ctrl - > ctrl ;
u32 num_of_lanes = 0 ;
u32 bpp = 3 ;
u64 bit_rate , pclk_rate , bit_rate_per_lane , byte_clk_rate ;
struct dsi_host_common_cfg * host_cfg ;
mutex_lock ( & ctrl - > ctrl_lock ) ;
host_cfg = & display - > panel - > host_config ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_0 )
num_of_lanes + + ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_1 )
num_of_lanes + + ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_2 )
num_of_lanes + + ;
if ( host_cfg - > data_lanes & DSI_DATA_LANE_3 )
num_of_lanes + + ;
if ( num_of_lanes = = 0 ) {
pr_err ( " Invalid lane count \n " ) ;
rc = - EINVAL ;
goto error ;
}
bit_rate = display - > config . bit_clk_rate_hz_override *
num_of_lanes ;
bit_rate_per_lane = bit_rate ;
do_div ( bit_rate_per_lane , num_of_lanes ) ;
pclk_rate = bit_rate ;
do_div ( pclk_rate , ( 8 * bpp ) ) ;
byte_clk_rate = bit_rate_per_lane ;
do_div ( byte_clk_rate , 8 ) ;
pr_debug ( " bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu \n " ,
bit_rate , bit_rate_per_lane ) ;
pr_debug ( " byte_clk_rate = %llu, pclk_rate = %llu \n " ,
byte_clk_rate , pclk_rate ) ;
ctrl - > clk_freq . byte_clk_rate = byte_clk_rate ;
ctrl - > clk_freq . pix_clk_rate = pclk_rate ;
rc = dsi_clk_set_link_frequencies ( display - > dsi_clk_handle ,
ctrl - > clk_freq , ctrl - > cell_index ) ;
if ( rc ) {
pr_err ( " Failed to update link frequencies \n " ) ;
goto error ;
}
ctrl - > host_config . bit_clk_rate_hz_override = bit_clk_rate ;
error :
mutex_unlock ( & ctrl - > ctrl_lock ) ;
/* TODO: recover ctrl->clk_freq in case of failure */
if ( rc )
return rc ;
}
return 0 ;
}
static ssize_t sysfs_dynamic_dsi_clk_read ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
@ -4384,6 +4640,11 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev,
return rc ;
}
if ( display - > panel - > panel_mode ! = DSI_OP_CMD_MODE ) {
pr_err ( " only supported for command mode \n " ) ;
return - ENOTSUPP ;
}
if ( clk_rate < = 0 ) {
pr_err ( " %s: bitrate should be greater than 0 \n " , __func__ ) ;
return - EINVAL ;
@ -4399,7 +4660,7 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev,
mutex_lock ( & display - > display_lock ) ;
display - > cached_clk_rate = clk_rate ;
rc = dsi_display_request_ update_dsi_bitrate ( display , clk_rate ) ;
rc = dsi_display_update_dsi_bitrate ( display , clk_rate ) ;
if ( ! rc ) {
pr_info ( " %s: bit clk is ready to be configured to '%d' \n " ,
__func__ , clk_rate ) ;
@ -5554,7 +5815,8 @@ static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
u32 * count )
{
struct dsi_dfps_capabilities dfps_caps ;
int num_dfps_rates , rc = 0 ;
struct dsi_dyn_clk_caps * dyn_clk_caps ;
int num_dfps_rates , num_bit_clks , rc = 0 ;
if ( ! display | | ! display - > panel ) {
pr_err ( " invalid display:%d panel:%d \n " , display ! = NULL ,
@ -5571,12 +5833,16 @@ static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
return rc ;
}
num_dfps_rates = ! dfps_caps . dfps_support ? 1 :
dfps_caps . max_refresh_rate -
dfps_caps . min_refresh_rate + 1 ;
num_dfps_rates = ! dfps_caps . dfps_support ? 1 : dfps_caps . dfps_list_len ;
dyn_clk_caps = & ( display - > panel - > dyn_clk_caps ) ;
num_bit_clks = ! dyn_clk_caps - > dyn_clk_support ? 1 :
dyn_clk_caps - > bit_clk_list_len ;
/* Inflate num_of_modes by fps in dfps */
* count = display - > panel - > num_timing_nodes * num_dfps_rates ;
/* Inflate num_of_modes by fps and bit clks in dfps */
* count = display - > panel - > num_timing_nodes *
num_dfps_rates * num_bit_clks ;
return 0 ;
}
@ -5599,6 +5865,73 @@ int dsi_display_get_mode_count(struct dsi_display *display,
return 0 ;
}
static void _dsi_display_populate_bit_clks ( struct dsi_display * display ,
int start , int end , u32 * mode_idx )
{
struct dsi_dyn_clk_caps * dyn_clk_caps ;
struct dsi_display_mode * src , * dst ;
struct dsi_host_common_cfg * cfg ;
int i , j , total_modes , bpp , lanes = 0 ;
if ( ! display | | ! mode_idx )
return ;
dyn_clk_caps = & ( display - > panel - > dyn_clk_caps ) ;
if ( ! dyn_clk_caps - > dyn_clk_support )
return ;
cfg = & ( display - > panel - > host_config ) ;
bpp = dsi_pixel_format_to_bpp ( cfg - > dst_format ) ;
if ( cfg - > data_lanes & DSI_DATA_LANE_0 )
lanes + + ;
if ( cfg - > data_lanes & DSI_DATA_LANE_1 )
lanes + + ;
if ( cfg - > data_lanes & DSI_DATA_LANE_2 )
lanes + + ;
if ( cfg - > data_lanes & DSI_DATA_LANE_3 )
lanes + + ;
dsi_display_get_mode_count_no_lock ( display , & total_modes ) ;
for ( i = start ; i < end ; i + + ) {
src = & display - > modes [ i ] ;
if ( ! src )
return ;
/*
* TODO : currently setting the first bit rate in
* the list as preferred rate . But ideally should
* be based on user or device tree preferrence .
*/
src - > timing . clk_rate_hz = dyn_clk_caps - > bit_clk_list [ 0 ] ;
src - > pixel_clk_khz =
div_u64 ( src - > timing . clk_rate_hz * lanes , bpp ) ;
src - > pixel_clk_khz / = 1000 ;
src - > pixel_clk_khz * = display - > ctrl_count ;
}
for ( i = 1 ; i < dyn_clk_caps - > bit_clk_list_len ; i + + ) {
if ( * mode_idx > = total_modes )
return ;
for ( j = start ; j < end ; j + + ) {
src = & display - > modes [ j ] ;
dst = & display - > modes [ * mode_idx ] ;
if ( ! src | | ! dst ) {
pr_err ( " invalid mode index \n " ) ;
return ;
}
memcpy ( dst , src , sizeof ( struct dsi_display_mode ) ) ;
dst - > timing . clk_rate_hz = dyn_clk_caps - > bit_clk_list [ i ] ;
dst - > pixel_clk_khz =
div_u64 ( dst - > timing . clk_rate_hz * lanes , bpp ) ;
dst - > pixel_clk_khz / = 1000 ;
dst - > pixel_clk_khz * = display - > ctrl_count ;
( * mode_idx ) + + ;
}
}
}
void dsi_display_put_mode ( struct dsi_display * display ,
struct dsi_display_mode * mode )
{
@ -5613,7 +5946,8 @@ int dsi_display_get_modes(struct dsi_display *display,
bool is_split_link ;
u32 num_dfps_rates , panel_mode_count , total_mode_count ;
u32 sublinks_count , mode_idx , array_idx = 0 ;
int i , rc = - EINVAL ;
struct dsi_dyn_clk_caps * dyn_clk_caps ;
int i , start , end , rc = - EINVAL ;
if ( ! display | | ! out_modes ) {
pr_err ( " Invalid params \n " ) ;
@ -5645,9 +5979,9 @@ int dsi_display_get_modes(struct dsi_display *display,
goto error ;
}
num_dfps_rates = ! dfps_caps . dfps_support ? 1 :
dfps_caps . max_refresh_rate -
dfps_caps . min_refresh_rate + 1 ;
dyn_clk_caps = & ( display - > panel - > dyn_clk_caps ) ;
num_dfps_rates = ! dfps_caps . dfps_support ? 1 : dfps_caps . dfps_list_len ;
panel_mode_count = display - > panel - > num_timing_nodes ;
@ -5677,7 +6011,7 @@ int dsi_display_get_modes(struct dsi_display *display,
panel_mode . timing . h_back_porch * = sublinks_count ;
panel_mode . timing . h_skew * = sublinks_count ;
panel_mode . pixel_clk_khz * = sublinks_count ;
} else if ( display - > ctrl_count > 1 ) {
} else {
panel_mode . timing . h_active * = display - > ctrl_count ;
panel_mode . timing . h_front_porch * = display - > ctrl_count ;
panel_mode . timing . h_sync_width * = display - > ctrl_count ;
@ -5686,6 +6020,8 @@ int dsi_display_get_modes(struct dsi_display *display,
panel_mode . pixel_clk_khz * = display - > ctrl_count ;
}
start = array_idx ;
for ( i = 0 ; i < num_dfps_rates ; i + + ) {
struct dsi_display_mode * sub_mode =
& display - > modes [ array_idx ] ;
@ -5698,24 +6034,23 @@ int dsi_display_get_modes(struct dsi_display *display,
}
memcpy ( sub_mode , & panel_mode , sizeof ( panel_mode ) ) ;
array_idx + + ;
if ( dfps_caps . dfps_support ) {
curr_refresh_rate =
sub_mode - > timing . refresh_rate ;
sub_mode - > timing . refresh_rate =
dfps_caps . min_refresh_rate +
( i % num_dfps_rates ) ;
if ( ! dfps_caps . dfps_support )
continue ;
dsi_display_get_dfps_timing ( display ,
sub_mode , curr_refresh_rate ) ;
curr_refresh_rate = sub_mode - > timing . refresh_rate ;
sub_mode - > timing . refresh_rate = dfps_caps . dfps_list [ i ] ;
sub_mode - > pixel_clk_khz =
( DSI_H_TOTAL_DSC ( & sub_mode - > timing ) *
DSI_V_TOTAL ( & sub_mode - > timing ) *
sub_mode - > timing . refresh_rate ) / 1000 ;
}
array_idx + + ;
dsi_display_get_dfps_timing ( display , sub_mode ,
curr_refresh_rate ) ;
}
end = array_idx ;
/*
* if dynamic clk switch is supported then update all the bit
* clk rates .
*/
_dsi_display_populate_bit_clks ( display , start , end , & array_idx ) ;
}
exit :
@ -5812,7 +6147,8 @@ int dsi_display_find_mode(struct dsi_display *display,
if ( cmp - > timing . v_active = = m - > timing . v_active & &
cmp - > timing . h_active = = m - > timing . h_active & &
cmp - > timing . refresh_rate = = m - > timing . refresh_rate ) {
cmp - > timing . refresh_rate = = m - > timing . refresh_rate & &
cmp - > pixel_clk_khz = = m - > pixel_clk_khz ) {
* out_mode = m ;
rc = 0 ;
break ;
@ -5821,9 +6157,10 @@ int dsi_display_find_mode(struct dsi_display *display,
mutex_unlock ( & display - > display_lock ) ;
if ( ! * out_mode ) {
pr_err ( " [%s] failed to find mode for v_active %u h_active %u rate %u \n " ,
pr_err ( " [%s] failed to find mode for v_active %u h_active %u fps %u pclk %u \n " ,
display - > name , cmp - > timing . v_active ,
cmp - > timing . h_active , cmp - > timing . refresh_rate ) ;
cmp - > timing . h_active , cmp - > timing . refresh_rate ,
cmp - > pixel_clk_khz ) ;
rc = - ENOENT ;
}
@ -5831,7 +6168,7 @@ int dsi_display_find_mode(struct dsi_display *display,
}
/**
* dsi_display_validate_mode_vrr ( ) - Validate if varaible refresh case .
* dsi_display_validate_mode_change ( ) - Validate if varaible refresh case .
* @ display : DSI display handle .
* @ cur_dsi_mode : Current DSI mode .
* @ mode : Mode value structure to be validated .
@ -5839,16 +6176,15 @@ int dsi_display_find_mode(struct dsi_display *display,
* is change in fps but vactive and hactive are same .
* Return : error code .
*/
int dsi_display_validate_mode_vrr ( struct dsi_display * display ,
struct dsi_display_mode * cur_dsi_ mode ,
struct dsi_display_mode * mode )
int dsi_display_validate_mode_change ( struct dsi_display * display ,
struct dsi_display_mode * cur_mode ,
struct dsi_display_mode * adj_ mode)
{
int rc = 0 ;
struct dsi_display_mode adj_mode , cur_mode ;
struct dsi_dfps_capabilities dfps_caps ;
u32 curr_refresh_rate ;
struct dsi_dyn_clk_caps * dyn_clk_caps ;
if ( ! display | | ! mode ) {
if ( ! display | | ! adj_ mode) {
pr_err ( " Invalid params \n " ) ;
return - EINVAL ;
}
@ -5860,65 +6196,43 @@ int dsi_display_validate_mode_vrr(struct dsi_display *display,
mutex_lock ( & display - > display_lock ) ;
adj_mode = * mode ;
cur_mode = * cur_dsi_mode ;
if ( ( cur_mode . timing . refresh_rate ! = adj_mode . timing . refresh_rate ) & &
( cur_mode . timing . v_active = = adj_mode . timing . v_active ) & &
( cur_mode . timing . h_active = = adj_mode . timing . h_active ) ) {
curr_refresh_rate = cur_mode . timing . refresh_rate ;
rc = dsi_panel_get_dfps_caps ( display - > panel , & dfps_caps ) ;
if ( rc ) {
pr_err ( " [%s] failed to get dfps caps from panel \n " ,
display - > name ) ;
goto error ;
}
cur_mode . timing . refresh_rate =
adj_mode . timing . refresh_rate ;
rc = dsi_display_get_dfps_timing ( display ,
& cur_mode , curr_refresh_rate ) ;
if ( rc ) {
pr_err ( " [%s] seamless vrr not possible rc=%d \n " ,
display - > name , rc ) ;
goto error ;
if ( ( cur_mode - > timing . v_active = = adj_mode - > timing . v_active ) & &
( cur_mode - > timing . h_active = = adj_mode - > timing . h_active ) ) {
/* dfps change use case */
if ( cur_mode - > timing . refresh_rate ! =
adj_mode - > timing . refresh_rate ) {
dsi_panel_get_dfps_caps ( display - > panel , & dfps_caps ) ;
if ( ! dfps_caps . dfps_support ) {
pr_err ( " invalid mode dfps not supported \n " ) ;
rc = - ENOTSUPP ;
goto error ;
}
pr_debug ( " Mode switch is seamless variable refresh \n " ) ;
adj_mode - > dsi_mode_flags | = DSI_MODE_FLAG_VRR ;
SDE_EVT32 ( cur_mode - > timing . refresh_rate ,
adj_mode - > timing . refresh_rate ,
cur_mode - > timing . h_front_porch ,
adj_mode - > timing . h_front_porch ) ;
}
switch ( dfps_caps . type ) {
/*
* Ignore any round off factors in porch calculation .
* Worse case is set to 5.
*/
case DSI_DFPS_IMMEDIATE_VFP :
if ( abs ( DSI_V_TOTAL ( & cur_mode . timing ) -
DSI_V_TOTAL ( & adj_mode . timing ) ) > 5 )
pr_err ( " Mismatch vfp fps:%d new:%d given:%d \n " ,
adj_mode . timing . refresh_rate ,
cur_mode . timing . v_front_porch ,
adj_mode . timing . v_front_porch ) ;
break ;
case DSI_DFPS_IMMEDIATE_HFP :
if ( abs ( DSI_H_TOTAL_DSC ( & cur_mode . timing ) -
DSI_H_TOTAL_DSC ( & adj_mode . timing ) ) > 5 )
pr_err ( " Mismatch hfp fps:%d new:%d given:%d \n " ,
adj_mode . timing . refresh_rate ,
cur_mode . timing . h_front_porch ,
adj_mode . timing . h_front_porch ) ;
break ;
default :
pr_err ( " Unsupported DFPS mode %d \n " ,
dfps_caps . type ) ;
rc = - ENOTSUPP ;
/* dynamic clk change use case */
if ( cur_mode - > pixel_clk_khz ! = adj_mode - > pixel_clk_khz ) {
dyn_clk_caps = & ( display - > panel - > dyn_clk_caps ) ;
if ( ! dyn_clk_caps - > dyn_clk_support ) {
pr_err ( " dyn clk change not supported \n " ) ;
rc = - ENOTSUPP ;
goto error ;
}
if ( adj_mode - > dsi_mode_flags & DSI_MODE_FLAG_VRR ) {
pr_err ( " dfps and dyn clk not supported in same commit \n " ) ;
rc = - ENOTSUPP ;
goto error ;
}
pr_debug ( " dynamic clk change detected \n " ) ;
adj_mode - > dsi_mode_flags | = DSI_MODE_FLAG_DYN_CLK ;
SDE_EVT32 ( cur_mode - > pixel_clk_khz ,
adj_mode - > pixel_clk_khz ) ;
}
pr_debug ( " Mode switch is seamless variable refresh \n " ) ;
mode - > dsi_mode_flags | = DSI_MODE_FLAG_VRR ;
SDE_EVT32 ( curr_refresh_rate , adj_mode . timing . refresh_rate ,
cur_mode . timing . h_front_porch ,
adj_mode . timing . h_front_porch ) ;
}
error :