mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
drm/amd/display: Refactor PSR functionality into dedicated power_psr module
[Why] Extract all PSR (Panel Self Refresh) related functions from power.c into a new power_psr.c module for better code organization and maintainability. [How] Create new power_psr.c file containing all PSR-related functions moved from power.c. Remove static qualifier from shared functions to enable cross-file access: - psr_context_to_mod_power_psr_context: Convert PSR context to module power PSR context - map_index_from_stream: Map stream to power entity index - delay_two_frames: Wait for two frame periods Add function declarations to header. Maintain forward declaration of struct core_power for type compatibility. Reviewed-by: Anthony Koo <anthony.koo@amd.com> Signed-off-by: Lohita Mudimela <lohita.mudimela@amd.com> Signed-off-by: Ivan Lipski <ivan.lipski@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
ab5c6213cf
commit
b11107cb63
|
|
@ -414,27 +414,4 @@ bool mod_power_backlight_nits_to_percent(struct mod_power *mod_power,
|
|||
unsigned int backlight_millinit,
|
||||
unsigned int *backlight_millipercent);
|
||||
|
||||
void initialize_backlight_caps(struct core_power *core_power, unsigned int inst);
|
||||
|
||||
unsigned int backlight_millipercent_to_pwm(
|
||||
struct core_power *core_power, unsigned int millipercent, unsigned int inst);
|
||||
|
||||
unsigned int backlight_millipercent_to_millinit(
|
||||
struct core_power *core_power, unsigned int millipercent, unsigned int inst);
|
||||
|
||||
void fill_backlight_level_params(struct core_power *core_power,
|
||||
struct set_backlight_level_params *backlight_level_params,
|
||||
int panel_inst, uint8_t aux_inst, unsigned int backlight_pwm,
|
||||
enum backlight_control_type backlight_control_type,
|
||||
unsigned int backlight_millinit, unsigned int transition_time_millisec,
|
||||
bool is_hdr);
|
||||
|
||||
bool mod_power_hw_init_backlight(struct mod_power *mod_power);
|
||||
|
||||
void mod_power_update_backlight_on_mode_change(
|
||||
struct core_power *core_power,
|
||||
struct dc_link *link,
|
||||
unsigned int panel_inst,
|
||||
uint8_t aux_inst,
|
||||
bool is_hdr);
|
||||
#endif /* MODULES_INC_MOD_POWER_H_ */
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
# Makefile for the 'power' sub-module of DAL.
|
||||
#
|
||||
|
||||
MOD_POWER = power_helpers.o power.o power_abm.o
|
||||
MOD_POWER = power_helpers.o power.o power_abm.o power_psr.o
|
||||
|
||||
AMD_DAL_MOD_POWER = $(addprefix $(AMDDALPATH)/modules/power/,$(MOD_POWER))
|
||||
#$(info ************ DAL POWER MODULE MAKEFILE ************)
|
||||
|
|
|
|||
|
|
@ -42,101 +42,6 @@
|
|||
#define SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS 500
|
||||
#define LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND 25000
|
||||
|
||||
|
||||
struct backlight_state {
|
||||
/* HW uses u16.16 format for backlight PWM */
|
||||
unsigned int backlight_pwm;
|
||||
/* DM may call power module to set backlight
|
||||
* targeting percent brightness
|
||||
*/
|
||||
unsigned int backlight_millipercent;
|
||||
/* DM may call power module to set backlight based on an explicit
|
||||
* nits value.
|
||||
*/
|
||||
unsigned int backlight_millinit;
|
||||
unsigned int frame_ramp;
|
||||
bool smooth_brightness_enabled;
|
||||
bool isHDR;
|
||||
};
|
||||
struct power_entity {
|
||||
struct dc_stream_state *stream;
|
||||
struct psr_caps *caps;
|
||||
struct mod_power_psr_context *psr_context;
|
||||
|
||||
/*PSR cached properties*/
|
||||
bool psr_enabled;
|
||||
unsigned int psr_events;
|
||||
unsigned int psr_power_opt;
|
||||
unsigned int replay_events;
|
||||
};
|
||||
|
||||
struct pwr_backlight_properties {
|
||||
bool use_nits_based_brightness;
|
||||
bool disable_fractional_pwm;
|
||||
|
||||
unsigned int min_abm_backlight;
|
||||
unsigned int num_backlight_levels;
|
||||
|
||||
bool backlight_ramping_override;
|
||||
unsigned int backlight_ramping_reduction;
|
||||
unsigned int backlight_ramping_start;
|
||||
|
||||
/* Backlight cached properties */
|
||||
unsigned int ac_backlight_percent;
|
||||
unsigned int dc_backlight_percent;
|
||||
|
||||
/* backlight LUT stored in HW u16.16 format*/
|
||||
unsigned int *backlight_lut;
|
||||
unsigned int min_backlight_pwm;
|
||||
unsigned int max_backlight_pwm;
|
||||
unsigned int backlight_range;
|
||||
|
||||
/* Describes the panel's min and max luminance in millinits measured
|
||||
* on full white screen, in min and max backlight settings.
|
||||
*/
|
||||
unsigned int min_brightness_millinits;
|
||||
unsigned int max_brightness_millinits;
|
||||
unsigned int nits_range;
|
||||
|
||||
bool backlight_caps_valid;
|
||||
bool use_custom_backlight_caps;
|
||||
unsigned int custom_backlight_caps_config_no;
|
||||
bool use_linear_backlight_curve;
|
||||
};
|
||||
|
||||
struct dmcu_varibright_cached_properties {
|
||||
unsigned int varibright_config_setting;
|
||||
unsigned int varibright_level;
|
||||
unsigned int varibright_hw_level;
|
||||
unsigned int def_varibright_level;
|
||||
bool varibright_user_enable;
|
||||
bool varibright_active;
|
||||
};
|
||||
|
||||
struct core_power {
|
||||
struct mod_power mod_public;
|
||||
struct dc *dc;
|
||||
struct power_entity *map;
|
||||
struct dmcu_varibright_cached_properties varibright_prop;
|
||||
struct pwr_backlight_properties bl_prop[MAX_NUM_EDP];
|
||||
struct backlight_state bl_state[MAX_NUM_EDP];
|
||||
unsigned int edp_num;
|
||||
|
||||
bool psr_smu_optimizations_support;
|
||||
bool multi_disp_optimizations_support;
|
||||
|
||||
unsigned int num_entities;
|
||||
};
|
||||
|
||||
union dmcu_abm_set_bl_params {
|
||||
struct {
|
||||
unsigned int gradual_change : 1; /* [0:0] */
|
||||
unsigned int reserved : 15; /* [15:1] */
|
||||
unsigned int frame_ramp : 16; /* [31:16] */
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
/* If system or panel does not report some sort of brightness percent to nits
|
||||
* mapping, we will use following default values so backlight control using
|
||||
* nits based interfaces will still work, but might not describe panel
|
||||
|
|
@ -155,24 +60,10 @@ static const unsigned int default_dc_backlight_percent = 70;
|
|||
#define MOD_POWER_TO_CORE(mod_power)\
|
||||
container_of(mod_power, struct core_power, mod_public)
|
||||
|
||||
static unsigned int calc_psr_num_static_frames(unsigned int vsync_rate_hz)
|
||||
{
|
||||
/* Initialize fail-safe to 2 static frames. */
|
||||
unsigned int num_frames_static = 2;
|
||||
|
||||
/* Calculate number of frames such that at least 30 ms has passed.
|
||||
* Round up to ensure the static period is not shorter than 30 ms.
|
||||
*/
|
||||
if (vsync_rate_hz != 0)
|
||||
num_frames_static = DIV_ROUND_UP(30000 * vsync_rate_hz, 1000000);
|
||||
|
||||
return num_frames_static;
|
||||
}
|
||||
|
||||
/* Given a specific dc_stream* this function finds its equivalent
|
||||
* on the core_freesync->map and returns the corresponding index
|
||||
*/
|
||||
static unsigned int map_index_from_stream(struct core_power *core_power,
|
||||
unsigned int map_index_from_stream(struct core_power *core_power,
|
||||
const struct dc_stream_state *stream)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
|
|
@ -572,11 +463,8 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power,
|
|||
unsigned int stream_index = 0;
|
||||
struct core_power *core_power = NULL;
|
||||
struct dc_link *link = NULL;
|
||||
struct psr_config psr_config = {0};
|
||||
struct psr_context psr_context = {0};
|
||||
struct dc *dc = NULL;
|
||||
unsigned int panel_inst = 0;
|
||||
int active_psr_events = 0;
|
||||
int active_replay_events = 0;
|
||||
|
||||
if ((mod_power == NULL) || (stream == NULL))
|
||||
|
|
@ -594,7 +482,6 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power,
|
|||
|
||||
dc = core_power->dc;
|
||||
link = dc_stream_get_link(stream);
|
||||
active_psr_events = core_power->map[stream_index].psr_events;
|
||||
active_replay_events = core_power->map[stream_index].replay_events;
|
||||
if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) {
|
||||
ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF);
|
||||
|
|
@ -602,38 +489,8 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power,
|
|||
|
||||
mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr);
|
||||
|
||||
mod_power_calc_psr_configs(&psr_config, link, stream);
|
||||
|
||||
psr_config.psr_exit_link_training_required = core_power->map[stream_index].caps->psr_exit_link_training_required;
|
||||
|
||||
if (dc->ctx->asic_id.chip_family >= AMDGPU_FAMILY_GC_11_0_1)
|
||||
psr_config.allow_smu_optimizations =
|
||||
core_power->psr_smu_optimizations_support && dc_is_embedded_signal(stream->signal);
|
||||
else
|
||||
psr_config.allow_smu_optimizations =
|
||||
core_power->psr_smu_optimizations_support && mod_power_only_edp(dc->current_state, stream);
|
||||
|
||||
psr_config.allow_multi_disp_optimizations = core_power->multi_disp_optimizations_support;
|
||||
|
||||
psr_config.rate_control_caps = core_power->map[stream_index].caps->rate_control_caps;
|
||||
|
||||
if (active_psr_events & psr_event_os_request_force_ffu) {
|
||||
psr_config.os_request_force_ffu = true;
|
||||
}
|
||||
/*
|
||||
* DSC support:
|
||||
* DSC slice height value must be 'mod' by su_y_granularity.
|
||||
* According to Panel Vendor, there might be varied conditions to fulfill.
|
||||
* Right now, DSC slice height value must be multiple of su_y_granularity.
|
||||
*
|
||||
* The value of DSC slice height is determined in DSC Driver but it does not
|
||||
* propagated out here, so we need to calculate it as below 'slice_height'.
|
||||
*/
|
||||
psr_su_set_dsc_slice_height(dc, link,
|
||||
(struct dc_stream_state *) stream,
|
||||
&psr_config);
|
||||
|
||||
dc_link_setup_psr(link, stream, &psr_config, &psr_context);
|
||||
/* Handle PSR notification */
|
||||
mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index);
|
||||
|
||||
link->replay_settings.replay_smu_opt_enable =
|
||||
(link->replay_settings.config.replay_smu_opt_supported &&
|
||||
|
|
@ -650,419 +507,6 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void mod_power_psr_set_power_opt(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream,
|
||||
unsigned int active_psr_events,
|
||||
bool psr_enable_request)
|
||||
{
|
||||
(void)psr_enable_request;
|
||||
struct core_power *core_power = NULL;
|
||||
struct dc_link *link = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
unsigned int power_opt = 0;
|
||||
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
if (active_psr_events == 0) {
|
||||
/* Static Screen */
|
||||
power_opt |= (psr_power_opt_smu_opt_static_screen | psr_power_opt_z10_static_screen |
|
||||
psr_power_opt_ds_disable_allow);
|
||||
}
|
||||
|
||||
/* psr_power_opt_flag is a configuration parameter into the module that determines
|
||||
* which optimizations to enable during psr
|
||||
*/
|
||||
power_opt &= core_power->map[stream_index].caps->psr_power_opt_flag;
|
||||
if (core_power->map[stream_index].psr_power_opt != power_opt) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"mod_power set_power_opt: psr_power_opt=0x%04x, power_opt=0x%04x"
|
||||
"active_psr_events=0x%04x, psr_power_opt_flag=0x%04x",
|
||||
core_power->map[stream_index].psr_power_opt,
|
||||
power_opt,
|
||||
active_psr_events,
|
||||
core_power->map[stream_index].caps->psr_power_opt_flag);
|
||||
dc_link_set_psr_allow_active(link, NULL, false, false, &power_opt);
|
||||
core_power->map[stream_index].psr_power_opt = power_opt;
|
||||
}
|
||||
}
|
||||
|
||||
static bool set_psr_enable(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream,
|
||||
bool psr_enable,
|
||||
bool wait,
|
||||
bool force_static)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
enum dc_psr_state state = PSR_STATE0;
|
||||
unsigned int retry_count;
|
||||
const unsigned int max_retry = 1000;
|
||||
struct dc_link *link = NULL;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: ERROR: stream=%p num_entities=%u",
|
||||
stream,
|
||||
core_power->num_entities);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (psr_enable) {
|
||||
unsigned int vsync_rate_hz;
|
||||
struct dc_static_screen_params params = {0};
|
||||
|
||||
vsync_rate_hz = (unsigned int)div_u64(div_u64((
|
||||
stream->timing.pix_clk_100hz * 100),
|
||||
stream->timing.v_total),
|
||||
stream->timing.h_total);
|
||||
|
||||
params.triggers.cursor_update = true;
|
||||
params.triggers.overlay_update = true;
|
||||
params.triggers.surface_update = true;
|
||||
params.num_frames = calc_psr_num_static_frames(vsync_rate_hz);
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: CALCS: pix_clk_100hz=%u v_total=%u h_total=%u vsync_rate_hz=%u num_frames=%u",
|
||||
stream->timing.pix_clk_100hz,
|
||||
stream->timing.v_total,
|
||||
stream->timing.h_total,
|
||||
vsync_rate_hz,
|
||||
params.num_frames);
|
||||
|
||||
dc_stream_set_static_screen_params(core_power->dc,
|
||||
&stream, 1,
|
||||
¶ms);
|
||||
}
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
if (!dc_link_set_psr_allow_active(link, &psr_enable, false, force_static, NULL)) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: ERROR: stream=%p link=%p psr_enable=%d",
|
||||
stream,
|
||||
link,
|
||||
psr_enable);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wait == true) {
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: BEGIN WAIT: psr_enable=%d",
|
||||
(int)psr_enable);
|
||||
|
||||
for (retry_count = 0; retry_count <= max_retry; retry_count++) {
|
||||
dc_link_get_psr_state(link, &state);
|
||||
if (psr_enable) {
|
||||
if (state != PSR_STATE0 &&
|
||||
(!force_static || state == PSR_STATE3))
|
||||
break;
|
||||
} else {
|
||||
if (state == PSR_STATE0)
|
||||
break;
|
||||
}
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: END WAIT: psr_enable=%d",
|
||||
(int)psr_enable);
|
||||
|
||||
/* assert if max retry hit */
|
||||
if (retry_count >= max_retry) {
|
||||
ASSERT(0);
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: ERROR: retry_count=%u: Unexpectedly long wait for PSR state change.",
|
||||
retry_count);
|
||||
}
|
||||
} else {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: PSR state change initiated (wait=false): psr_enable=%d",
|
||||
(int)psr_enable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_get_psr_event(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream,
|
||||
unsigned int *active_psr_events)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
*active_psr_events = core_power->map[stream_index].psr_events;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_set_psr_event(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream, bool set_event,
|
||||
enum psr_event event, bool wait)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
unsigned int active_psr_events = 0;
|
||||
bool psr_enable_request = false;
|
||||
bool force_static = false;
|
||||
|
||||
if (mod_power == NULL || stream == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (core_power->num_entities == 0) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"mod_power set_psr_event: ERROR: stream=%p event=%d num_entities=%u",
|
||||
stream,
|
||||
(int)event,
|
||||
core_power->num_entities);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
if (set_event)
|
||||
core_power->map[stream_index].psr_events |= event;
|
||||
else
|
||||
core_power->map[stream_index].psr_events &= ~event;
|
||||
|
||||
active_psr_events = core_power->map[stream_index].psr_events;
|
||||
|
||||
// ignore other events when we're in forced psr enabled state
|
||||
if (active_psr_events & psr_event_dynamic_display_switch &&
|
||||
event != psr_event_dynamic_display_switch)
|
||||
return false;
|
||||
|
||||
// ignore other events when we're in forced psr enabled state
|
||||
if (active_psr_events & psr_event_os_override_hold &&
|
||||
event != psr_event_os_override_hold)
|
||||
return false;
|
||||
|
||||
// ignore other events when we're in forced psr enabled state
|
||||
// dds events need to be processed while in dynamic_link_rate_control
|
||||
if (active_psr_events & psr_event_dynamic_link_rate_control &&
|
||||
event != psr_event_dynamic_link_rate_control &&
|
||||
event != psr_event_dds_defer_stream_enable &&
|
||||
event != psr_event_dynamic_display_switch)
|
||||
return false;
|
||||
|
||||
if (active_psr_events & (psr_event_test_harness_disable_psr | psr_event_os_request_disable))
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_pause)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_test_harness_enable_psr)
|
||||
psr_enable_request = true;
|
||||
else if (active_psr_events & psr_event_dynamic_display_switch) {
|
||||
psr_enable_request = true;
|
||||
force_static = true;
|
||||
} else if (active_psr_events & psr_event_dynamic_link_rate_control) {
|
||||
psr_enable_request = true;
|
||||
force_static = true;
|
||||
} else if (active_psr_events & psr_event_edp_panel_off_disable_psr)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & (psr_event_hw_programming |
|
||||
psr_event_defer_enable |
|
||||
psr_event_dds_defer_stream_enable |
|
||||
psr_event_vrr_transition |
|
||||
psr_event_immediate_flip))
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_big_screen_video)
|
||||
psr_enable_request = true;
|
||||
else if (active_psr_events & psr_event_full_screen)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_mpo_video_selective_update)
|
||||
psr_enable_request = true;
|
||||
else if (active_psr_events & psr_event_vsync)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_crc_window_active)
|
||||
psr_enable_request = false;
|
||||
else
|
||||
psr_enable_request = true;
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"mod_power set_psr_event: before: psr_enabled=%d -> request: set_event=%d event=0x%04x -> result: psr_events=0x%04x psr_enable_request=%d",
|
||||
(int)core_power->map[stream_index].psr_enabled,
|
||||
(int)set_event,
|
||||
(unsigned int)event,
|
||||
(unsigned int)core_power->map[stream_index].psr_events,
|
||||
(int)psr_enable_request);
|
||||
mod_power_psr_set_power_opt(mod_power, stream, active_psr_events, psr_enable_request);
|
||||
|
||||
if (core_power->map[stream_index].psr_enabled != psr_enable_request || force_static) {
|
||||
if (set_psr_enable(mod_power, stream, psr_enable_request, wait, force_static)) {
|
||||
core_power->map[stream_index].psr_enabled = psr_enable_request;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_get_psr_state(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
enum dc_psr_state *state)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
const struct dc_link *link = NULL;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
return dc_link_get_psr_state(link, state);
|
||||
}
|
||||
|
||||
bool mod_power_get_psr_enabled_status(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
bool *psr_enabled)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
*psr_enabled = core_power->map[stream_index].psr_enabled;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_power_psr_residency(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
unsigned int *residency,
|
||||
const uint8_t mode)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
const struct dc_link *link = NULL;
|
||||
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
if (link != NULL)
|
||||
link->dc->link_srv->edp_get_psr_residency(link, residency, mode);
|
||||
}
|
||||
bool mod_power_psr_get_active_psr_events(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream, unsigned int *active_psr_events)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
if (active_psr_events == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
*active_psr_events = core_power->map[stream_index].psr_events;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_psr_set_sink_vtotal_in_psr_active(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
uint16_t psr_vtotal_idle,
|
||||
uint16_t psr_vtotal_su)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
const struct dc_link *link = NULL;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
return link->dc->link_srv->edp_set_sink_vtotal_in_psr_active(
|
||||
link, psr_vtotal_idle, psr_vtotal_su);
|
||||
}
|
||||
|
||||
static bool mod_power_set_replay_active(struct dc_stream_state *stream,
|
||||
bool replay_active,
|
||||
bool wait,
|
||||
|
|
|
|||
|
|
@ -233,102 +233,6 @@ struct iram_table_v_2_2 {
|
|||
#define MOD_POWER_MAX_CONCURRENT_STREAMS 32
|
||||
#define SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS 500
|
||||
|
||||
|
||||
|
||||
struct backlight_state {
|
||||
/* HW uses u16.16 format for backlight PWM */
|
||||
unsigned int backlight_pwm;
|
||||
/* DM may call power module to set backlight
|
||||
* targeting percent brightness
|
||||
*/
|
||||
unsigned int backlight_millipercent;
|
||||
/* DM may call power module to set backlight based on an explicit
|
||||
* nits value.
|
||||
*/
|
||||
unsigned int backlight_millinit;
|
||||
unsigned int frame_ramp;
|
||||
bool smooth_brightness_enabled;
|
||||
bool isHDR;
|
||||
};
|
||||
struct power_entity {
|
||||
struct dc_stream_state *stream;
|
||||
struct psr_caps *caps;
|
||||
struct mod_power_psr_context *psr_context;
|
||||
|
||||
/*PSR cached properties*/
|
||||
bool psr_enabled;
|
||||
unsigned int psr_events;
|
||||
unsigned int psr_power_opt;
|
||||
unsigned int replay_events;
|
||||
};
|
||||
|
||||
struct pwr_backlight_properties {
|
||||
bool use_nits_based_brightness;
|
||||
bool disable_fractional_pwm;
|
||||
|
||||
unsigned int min_abm_backlight;
|
||||
unsigned int num_backlight_levels;
|
||||
|
||||
bool backlight_ramping_override;
|
||||
unsigned int backlight_ramping_reduction;
|
||||
unsigned int backlight_ramping_start;
|
||||
|
||||
/* Backlight cached properties */
|
||||
unsigned int ac_backlight_percent;
|
||||
unsigned int dc_backlight_percent;
|
||||
|
||||
/* backlight LUT stored in HW u16.16 format*/
|
||||
unsigned int *backlight_lut;
|
||||
unsigned int min_backlight_pwm;
|
||||
unsigned int max_backlight_pwm;
|
||||
unsigned int backlight_range;
|
||||
|
||||
/* Describes the panel's min and max luminance in millinits measured
|
||||
* on full white screen, in min and max backlight settings.
|
||||
*/
|
||||
unsigned int min_brightness_millinits;
|
||||
unsigned int max_brightness_millinits;
|
||||
unsigned int nits_range;
|
||||
|
||||
bool backlight_caps_valid;
|
||||
bool use_custom_backlight_caps;
|
||||
unsigned int custom_backlight_caps_config_no;
|
||||
bool use_linear_backlight_curve;
|
||||
};
|
||||
|
||||
struct dmcu_varibright_cached_properties {
|
||||
unsigned int varibright_config_setting;
|
||||
unsigned int varibright_level;
|
||||
unsigned int varibright_hw_level;
|
||||
unsigned int def_varibright_level;
|
||||
bool varibright_user_enable;
|
||||
bool varibright_active;
|
||||
};
|
||||
|
||||
struct core_power {
|
||||
struct mod_power mod_public;
|
||||
struct dc *dc;
|
||||
struct power_entity *map;
|
||||
struct dmcu_varibright_cached_properties varibright_prop;
|
||||
struct pwr_backlight_properties bl_prop[MAX_NUM_EDP];
|
||||
struct backlight_state bl_state[MAX_NUM_EDP];
|
||||
unsigned int edp_num;
|
||||
|
||||
bool psr_smu_optimizations_support;
|
||||
bool multi_disp_optimizations_support;
|
||||
|
||||
unsigned int num_entities;
|
||||
};
|
||||
|
||||
union dmcu_abm_set_bl_params {
|
||||
struct {
|
||||
unsigned int gradual_change : 1; /* [0:0] */
|
||||
unsigned int reserved : 15; /* [15:1] */
|
||||
unsigned int frame_ramp : 16; /* [31:16] */
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
|
||||
/* If system or panel does not report some sort of brightness percent to nits
|
||||
* mapping, we will use following default values so backlight control using
|
||||
* nits based interfaces will still work, but might not describe panel
|
||||
|
|
|
|||
|
|
@ -33,129 +33,6 @@
|
|||
#define bswap16_based_on_endian(big_endian, value) \
|
||||
((big_endian) ? cpu_to_be16(value) : cpu_to_le16(value))
|
||||
|
||||
/*
|
||||
* is_psr_su_specific_panel() - check if sink is AMD vendor-specific PSR-SU
|
||||
* supported eDP device.
|
||||
*
|
||||
* @link: dc link pointer
|
||||
*
|
||||
* Return: true if AMDGPU vendor specific PSR-SU eDP panel
|
||||
*/
|
||||
bool is_psr_su_specific_panel(struct dc_link *link)
|
||||
{
|
||||
bool isPSRSUSupported = false;
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
|
||||
if (dpcd_caps->edp_rev >= DP_EDP_14) {
|
||||
if (dpcd_caps->psr_info.psr_version >= DP_PSR2_WITH_Y_COORD_ET_SUPPORTED)
|
||||
isPSRSUSupported = true;
|
||||
/*
|
||||
* Some panels will report PSR capabilities over additional DPCD bits.
|
||||
* Such panels are approved despite reporting only PSR v3, as long as
|
||||
* the additional bits are reported.
|
||||
*/
|
||||
if (dpcd_caps->sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) {
|
||||
/*
|
||||
* This is the temporary workaround to disable PSRSU when system turned on
|
||||
* DSC function on the sepcific sink.
|
||||
*/
|
||||
if (dpcd_caps->psr_info.psr_version < DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
|
||||
((dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x08) ||
|
||||
(dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x07)))
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x01)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1)
|
||||
isPSRSUSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isPSRSUSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* mod_power_calc_psr_configs() - calculate/update generic psr configuration fields.
|
||||
* @psr_config: [output], psr configuration structure to be updated
|
||||
* @link: [input] dc link pointer
|
||||
* @stream: [input] dc stream state pointer
|
||||
*
|
||||
* calculate and update the psr configuration fields that are not DM specific, i.e. such
|
||||
* fields which are based on DPCD caps or timing information. To setup PSR in DMUB FW,
|
||||
* this helper is assumed to be called before the call of the DC helper dc_link_setup_psr().
|
||||
*
|
||||
* PSR config fields to be updated within the helper:
|
||||
* - psr_rfb_setup_time
|
||||
* - psr_sdp_transmit_line_num_deadline
|
||||
* - line_time_in_us
|
||||
* - su_y_granularity
|
||||
* - su_granularity_required
|
||||
* - psr_frame_capture_indication_req
|
||||
* - psr_exit_link_training_required
|
||||
*
|
||||
* PSR config fields that are DM specific and NOT updated within the helper:
|
||||
* - allow_smu_optimizations
|
||||
* - allow_multi_disp_optimizations
|
||||
*/
|
||||
void mod_power_calc_psr_configs(struct psr_config *psr_config,
|
||||
struct dc_link *link,
|
||||
const struct dc_stream_state *stream)
|
||||
{
|
||||
unsigned int num_vblank_lines = 0;
|
||||
unsigned int vblank_time_in_us = 0;
|
||||
unsigned int sdp_tx_deadline_in_us = 0;
|
||||
unsigned int line_time_in_us = 0;
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
const int psr_setup_time_step_in_us = 55; /* refer to eDP spec DPCD 0x071h */
|
||||
|
||||
/* timing parameters */
|
||||
num_vblank_lines = stream->timing.v_total -
|
||||
stream->timing.v_addressable -
|
||||
stream->timing.v_border_top -
|
||||
stream->timing.v_border_bottom;
|
||||
|
||||
vblank_time_in_us = (stream->timing.h_total * num_vblank_lines * 1000) / (stream->timing.pix_clk_100hz / 10);
|
||||
|
||||
line_time_in_us = ((stream->timing.h_total * 1000) / (stream->timing.pix_clk_100hz / 10)) + 1;
|
||||
|
||||
/**
|
||||
* psr configuration fields
|
||||
*
|
||||
* as per eDP 1.5 pg. 377 of 459, DPCD 0x071h bits [3:1], psr setup time bits interpreted as below
|
||||
* 000b <--> 330 us (default)
|
||||
* 001b <--> 275 us
|
||||
* 010b <--> 220 us
|
||||
* 011b <--> 165 us
|
||||
* 100b <--> 110 us
|
||||
* 101b <--> 055 us
|
||||
* 110b <--> 000 us
|
||||
*/
|
||||
psr_config->psr_rfb_setup_time =
|
||||
(6 - dpcd_caps->psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME) * psr_setup_time_step_in_us;
|
||||
|
||||
if (psr_config->psr_rfb_setup_time > vblank_time_in_us) {
|
||||
link->psr_settings.psr_frame_capture_indication_req = true;
|
||||
link->psr_settings.psr_sdp_transmit_line_num_deadline = num_vblank_lines;
|
||||
} else {
|
||||
sdp_tx_deadline_in_us = vblank_time_in_us - psr_config->psr_rfb_setup_time;
|
||||
|
||||
/* Set the last possible line SDP may be transmitted without violating the RFB setup time */
|
||||
link->psr_settings.psr_frame_capture_indication_req = false;
|
||||
link->psr_settings.psr_sdp_transmit_line_num_deadline = sdp_tx_deadline_in_us / line_time_in_us;
|
||||
}
|
||||
|
||||
psr_config->psr_sdp_transmit_line_num_deadline = link->psr_settings.psr_sdp_transmit_line_num_deadline;
|
||||
psr_config->line_time_in_us = line_time_in_us;
|
||||
psr_config->su_y_granularity = dpcd_caps->psr_info.psr2_su_y_granularity_cap;
|
||||
psr_config->su_granularity_required = dpcd_caps->psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED;
|
||||
psr_config->psr_frame_capture_indication_req = link->psr_settings.psr_frame_capture_indication_req;
|
||||
psr_config->psr_exit_link_training_required =
|
||||
!link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED;
|
||||
}
|
||||
|
||||
void init_replay_config(struct dc_link *link, struct replay_config *pr_config)
|
||||
{
|
||||
link->replay_settings.config = *pr_config;
|
||||
|
|
@ -166,41 +43,6 @@ bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_s
|
|||
return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal);
|
||||
}
|
||||
|
||||
bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
|
||||
struct dc_stream_state *stream,
|
||||
struct psr_config *config)
|
||||
{
|
||||
uint32_t pic_height;
|
||||
uint32_t slice_height;
|
||||
|
||||
config->dsc_slice_height = 0;
|
||||
if (!(link->connector_signal & SIGNAL_TYPE_EDP) ||
|
||||
!dc->caps.edp_dsc_support ||
|
||||
link->panel_config.dsc.disable_dsc_edp ||
|
||||
!link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT ||
|
||||
!stream->timing.dsc_cfg.num_slices_v)
|
||||
return true;
|
||||
|
||||
pic_height = stream->timing.v_addressable +
|
||||
stream->timing.v_border_top + stream->timing.v_border_bottom;
|
||||
|
||||
if (stream->timing.dsc_cfg.num_slices_v == 0)
|
||||
return false;
|
||||
|
||||
slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v;
|
||||
config->dsc_slice_height = (uint16_t)slice_height;
|
||||
|
||||
if (slice_height) {
|
||||
if (config->su_y_granularity &&
|
||||
(slice_height % config->su_y_granularity)) {
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_replay_frame_skip_number(struct dc_link *link,
|
||||
enum replay_coasting_vtotal_type type,
|
||||
uint32_t coasting_vtotal_refresh_rate_uhz,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,99 @@ struct dmcu_iram_parameters {
|
|||
unsigned int min_abm_backlight;
|
||||
unsigned int set;
|
||||
};
|
||||
struct backlight_state {
|
||||
/* HW uses u16.16 format for backlight PWM */
|
||||
unsigned int backlight_pwm;
|
||||
/* DM may call power module to set backlight
|
||||
* targeting percent brightness
|
||||
*/
|
||||
unsigned int backlight_millipercent;
|
||||
/* DM may call power module to set backlight based on an explicit
|
||||
* nits value.
|
||||
*/
|
||||
unsigned int backlight_millinit;
|
||||
unsigned int frame_ramp;
|
||||
bool smooth_brightness_enabled;
|
||||
bool isHDR;
|
||||
};
|
||||
struct power_entity {
|
||||
struct dc_stream_state *stream;
|
||||
struct psr_caps *caps;
|
||||
struct mod_power_psr_context *psr_context;
|
||||
|
||||
/*PSR cached properties*/
|
||||
bool psr_enabled;
|
||||
unsigned int psr_events;
|
||||
unsigned int psr_power_opt;
|
||||
unsigned int replay_events;
|
||||
};
|
||||
|
||||
struct pwr_backlight_properties {
|
||||
bool use_nits_based_brightness;
|
||||
bool disable_fractional_pwm;
|
||||
|
||||
unsigned int min_abm_backlight;
|
||||
unsigned int num_backlight_levels;
|
||||
|
||||
bool backlight_ramping_override;
|
||||
unsigned int backlight_ramping_reduction;
|
||||
unsigned int backlight_ramping_start;
|
||||
|
||||
/* Backlight cached properties */
|
||||
unsigned int ac_backlight_percent;
|
||||
unsigned int dc_backlight_percent;
|
||||
|
||||
/* backlight LUT stored in HW u16.16 format*/
|
||||
unsigned int *backlight_lut;
|
||||
unsigned int min_backlight_pwm;
|
||||
unsigned int max_backlight_pwm;
|
||||
unsigned int backlight_range;
|
||||
|
||||
/* Describes the panel's min and max luminance in millinits measured
|
||||
* on full white screen, in min and max backlight settings.
|
||||
*/
|
||||
unsigned int min_brightness_millinits;
|
||||
unsigned int max_brightness_millinits;
|
||||
unsigned int nits_range;
|
||||
|
||||
bool backlight_caps_valid;
|
||||
bool use_custom_backlight_caps;
|
||||
unsigned int custom_backlight_caps_config_no;
|
||||
bool use_linear_backlight_curve;
|
||||
};
|
||||
|
||||
struct dmcu_varibright_cached_properties {
|
||||
unsigned int varibright_config_setting;
|
||||
unsigned int varibright_level;
|
||||
unsigned int varibright_hw_level;
|
||||
unsigned int def_varibright_level;
|
||||
bool varibright_user_enable;
|
||||
bool varibright_active;
|
||||
};
|
||||
|
||||
struct core_power {
|
||||
struct mod_power mod_public;
|
||||
struct dc *dc;
|
||||
struct power_entity *map;
|
||||
struct dmcu_varibright_cached_properties varibright_prop;
|
||||
struct pwr_backlight_properties bl_prop[MAX_NUM_EDP];
|
||||
struct backlight_state bl_state[MAX_NUM_EDP];
|
||||
unsigned int edp_num;
|
||||
|
||||
bool psr_smu_optimizations_support;
|
||||
bool multi_disp_optimizations_support;
|
||||
|
||||
unsigned int num_entities;
|
||||
};
|
||||
|
||||
union dmcu_abm_set_bl_params {
|
||||
struct {
|
||||
unsigned int gradual_change : 1; /* [0:0] */
|
||||
unsigned int reserved : 15; /* [15:1] */
|
||||
unsigned int frame_ramp : 16; /* [31:16] */
|
||||
} bits;
|
||||
unsigned int u32All;
|
||||
};
|
||||
bool dmcu_load_iram(struct dmcu *dmcu,
|
||||
struct dmcu_iram_parameters params);
|
||||
bool dmub_init_abm_config(struct resource_pool *res_pool,
|
||||
|
|
@ -87,4 +179,28 @@ bool fill_custom_backlight_caps(unsigned int config_no,
|
|||
void reset_replay_dsync_error_count(struct dc_link *link);
|
||||
void change_replay_to_psr(struct dc_link *link);
|
||||
void change_psr_to_replay(struct dc_link *link);
|
||||
void initialize_backlight_caps(struct core_power *core_power, unsigned int inst);
|
||||
unsigned int backlight_millipercent_to_pwm(
|
||||
struct core_power *core_power, unsigned int millipercent, unsigned int inst);
|
||||
unsigned int backlight_millipercent_to_millinit(
|
||||
struct core_power *core_power, unsigned int millipercent, unsigned int inst);
|
||||
void fill_backlight_level_params(struct core_power *core_power,
|
||||
struct set_backlight_level_params *backlight_level_params,
|
||||
int panel_inst, uint8_t aux_inst, unsigned int backlight_pwm,
|
||||
enum backlight_control_type backlight_control_type,
|
||||
unsigned int backlight_millinit, unsigned int transition_time_millisec,
|
||||
bool is_hdr);
|
||||
bool mod_power_hw_init_backlight(struct mod_power *mod_power);
|
||||
void mod_power_update_backlight_on_mode_change(
|
||||
struct core_power *core_power,
|
||||
struct dc_link *link,
|
||||
unsigned int panel_inst,
|
||||
uint8_t aux_inst,
|
||||
bool is_hdr);
|
||||
unsigned int map_index_from_stream(struct core_power *core_power,
|
||||
const struct dc_stream_state *stream);
|
||||
bool mod_power_psr_notify_mode_change(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
unsigned int stream_index);
|
||||
#endif /* MODULES_POWER_POWER_HELPERS_H_ */
|
||||
|
|
|
|||
665
drivers/gpu/drm/amd/display/modules/power/power_psr.c
Normal file
665
drivers/gpu/drm/amd/display/modules/power/power_psr.c
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2026 Advanced Micro Devices, Inc.
|
||||
|
||||
#include "dm_services.h"
|
||||
#include "dc.h"
|
||||
#include "mod_power.h"
|
||||
#include "core_types.h"
|
||||
#include "dmcu.h"
|
||||
#include "abm.h"
|
||||
#include "power_helpers.h"
|
||||
#include "dce/dmub_psr.h"
|
||||
#include "dal_asic_id.h"
|
||||
#include "link_service.h"
|
||||
#include <linux/math.h>
|
||||
|
||||
#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
|
||||
#define DC_TRACE_LEVEL_MESSAGEP(...) /* do nothing */
|
||||
#include "dc/inc/hw/dmcu.h"
|
||||
#include "dc/inc/hw/abm.h"
|
||||
#include "dmub_cmd.h"
|
||||
|
||||
#define MOD_POWER_TO_CORE(mod_power)\
|
||||
container_of(mod_power, struct core_power, mod_public)
|
||||
|
||||
static unsigned int calc_psr_num_static_frames(unsigned int vsync_rate_hz)
|
||||
{
|
||||
/* Initialize fail-safe to 2 static frames. */
|
||||
unsigned int num_frames_static = 2;
|
||||
|
||||
/* Calculate number of frames such that at least 30 ms has passed.
|
||||
* Round up to ensure the static period is not shorter than 30 ms.
|
||||
*/
|
||||
if (vsync_rate_hz != 0)
|
||||
num_frames_static = DIV_ROUND_UP(30000 * vsync_rate_hz, 1000000);
|
||||
|
||||
return num_frames_static;
|
||||
}
|
||||
|
||||
bool mod_power_psr_notify_mode_change(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
unsigned int stream_index)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
struct dc *dc = NULL;
|
||||
struct psr_config psr_config = {0};
|
||||
struct psr_context psr_context = {0};
|
||||
int active_psr_events = 0;
|
||||
|
||||
if ((mod_power == NULL) || (stream == NULL) || (link == NULL))
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
dc = core_power->dc;
|
||||
|
||||
// NO num_entities check here - already validated by caller
|
||||
// stream_index is passed as validated parameter
|
||||
active_psr_events = core_power->map[stream_index].psr_events;
|
||||
|
||||
/* Calculate PSR configurations */
|
||||
mod_power_calc_psr_configs(&psr_config, link, stream);
|
||||
|
||||
psr_config.psr_exit_link_training_required =
|
||||
core_power->map[stream_index].caps->psr_exit_link_training_required;
|
||||
if (dc->ctx->asic_id.chip_family >= AMDGPU_FAMILY_GC_11_0_1)
|
||||
psr_config.allow_smu_optimizations =
|
||||
core_power->psr_smu_optimizations_support && dc_is_embedded_signal(stream->signal);
|
||||
else
|
||||
psr_config.allow_smu_optimizations =
|
||||
core_power->psr_smu_optimizations_support &&
|
||||
mod_power_only_edp(dc->current_state, stream);
|
||||
|
||||
psr_config.allow_multi_disp_optimizations = core_power->multi_disp_optimizations_support;
|
||||
|
||||
psr_config.rate_control_caps = core_power->map[stream_index].caps->rate_control_caps;
|
||||
|
||||
if (active_psr_events & psr_event_os_request_force_ffu)
|
||||
psr_config.os_request_force_ffu = true;
|
||||
|
||||
/*
|
||||
* DSC support:
|
||||
* DSC slice height value must be 'mod' by su_y_granularity.
|
||||
* According to Panel Vendor, there might be varied conditions to fulfill.
|
||||
* Right now, DSC slice height value must be multiple of su_y_granularity.
|
||||
*
|
||||
* The value of DSC slice height is determined in DSC Driver but it does not
|
||||
* propagated out here, so we need to calculate it as below 'slice_height'.
|
||||
*/
|
||||
psr_su_set_dsc_slice_height(dc, link,
|
||||
(struct dc_stream_state *) stream,
|
||||
&psr_config);
|
||||
|
||||
dc_link_setup_psr(link, stream, &psr_config, &psr_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mod_power_psr_set_power_opt(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream,
|
||||
unsigned int active_psr_events,
|
||||
bool psr_enable_request)
|
||||
{
|
||||
(void)psr_enable_request;
|
||||
struct core_power *core_power = NULL;
|
||||
struct dc_link *link = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
unsigned int power_opt = 0;
|
||||
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
if (active_psr_events == 0) {
|
||||
/* Static Screen */
|
||||
power_opt |= (psr_power_opt_smu_opt_static_screen | psr_power_opt_z10_static_screen |
|
||||
psr_power_opt_ds_disable_allow);
|
||||
}
|
||||
|
||||
/* psr_power_opt_flag is a configuration parameter into the module that determines
|
||||
* which optimizations to enable during psr
|
||||
*/
|
||||
power_opt &= core_power->map[stream_index].caps->psr_power_opt_flag;
|
||||
if (core_power->map[stream_index].psr_power_opt != power_opt) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"mod_power set_power_opt: psr_power_opt=0x%04x, power_opt=0x%04x active_psr_events=0x%04x, psr_power_opt_flag=0x%04x",
|
||||
core_power->map[stream_index].psr_power_opt,
|
||||
power_opt,
|
||||
active_psr_events,
|
||||
core_power->map[stream_index].caps->psr_power_opt_flag);
|
||||
dc_link_set_psr_allow_active(link, NULL, false, false, &power_opt);
|
||||
core_power->map[stream_index].psr_power_opt = power_opt;
|
||||
}
|
||||
}
|
||||
|
||||
static bool set_psr_enable(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream,
|
||||
bool psr_enable,
|
||||
bool wait,
|
||||
bool force_static)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
enum dc_psr_state state = PSR_STATE0;
|
||||
unsigned int retry_count;
|
||||
const unsigned int max_retry = 1000;
|
||||
struct dc_link *link = NULL;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: ERROR: stream=%p num_entities=%u",
|
||||
stream,
|
||||
core_power->num_entities);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (psr_enable) {
|
||||
unsigned int vsync_rate_hz;
|
||||
struct dc_static_screen_params params = {0};
|
||||
|
||||
vsync_rate_hz = (unsigned int)div_u64(div_u64((
|
||||
stream->timing.pix_clk_100hz * 100),
|
||||
stream->timing.v_total),
|
||||
stream->timing.h_total);
|
||||
|
||||
params.triggers.cursor_update = true;
|
||||
params.triggers.overlay_update = true;
|
||||
params.triggers.surface_update = true;
|
||||
params.num_frames = calc_psr_num_static_frames(vsync_rate_hz);
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: CALCS: pix_clk_100hz=%u v_total=%u h_total=%u vsync_rate_hz=%u num_frames=%u",
|
||||
stream->timing.pix_clk_100hz,
|
||||
stream->timing.v_total,
|
||||
stream->timing.h_total,
|
||||
vsync_rate_hz,
|
||||
params.num_frames);
|
||||
|
||||
dc_stream_set_static_screen_params(core_power->dc,
|
||||
&stream, 1,
|
||||
¶ms);
|
||||
}
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
if (!dc_link_set_psr_allow_active(link, &psr_enable, false, force_static, NULL)) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: ERROR: stream=%p link=%p psr_enable=%d",
|
||||
stream,
|
||||
link,
|
||||
psr_enable);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wait == true) {
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: BEGIN WAIT: psr_enable=%d",
|
||||
(int)psr_enable);
|
||||
|
||||
for (retry_count = 0; retry_count <= max_retry; retry_count++) {
|
||||
dc_link_get_psr_state(link, &state);
|
||||
if (psr_enable) {
|
||||
if (state != PSR_STATE0 &&
|
||||
(!force_static || state == PSR_STATE3))
|
||||
break;
|
||||
} else {
|
||||
if (state == PSR_STATE0)
|
||||
break;
|
||||
}
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: END WAIT: psr_enable=%d",
|
||||
(int)psr_enable);
|
||||
|
||||
/* assert if max retry hit */
|
||||
if (retry_count >= max_retry) {
|
||||
ASSERT(0);
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: ERROR: retry_count=%u: Unexpectedly long wait for PSR state change.",
|
||||
retry_count);
|
||||
}
|
||||
} else {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"set psr enable: PSR state change initiated (wait=false): psr_enable=%d",
|
||||
(int)psr_enable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_get_psr_event(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream,
|
||||
unsigned int *active_psr_events)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
*active_psr_events = core_power->map[stream_index].psr_events;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_set_psr_event(struct mod_power *mod_power,
|
||||
struct dc_stream_state *stream, bool set_event,
|
||||
enum psr_event event, bool wait)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
unsigned int active_psr_events = 0;
|
||||
bool psr_enable_request = false;
|
||||
bool force_static = false;
|
||||
|
||||
if (mod_power == NULL || stream == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (core_power->num_entities == 0) {
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"mod_power set_psr_event: ERROR: stream=%p event=%d num_entities=%u",
|
||||
stream,
|
||||
(int)event,
|
||||
core_power->num_entities);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
if (set_event)
|
||||
core_power->map[stream_index].psr_events |= event;
|
||||
else
|
||||
core_power->map[stream_index].psr_events &= ~event;
|
||||
|
||||
active_psr_events = core_power->map[stream_index].psr_events;
|
||||
|
||||
// ignore other events when we're in forced psr enabled state
|
||||
if (active_psr_events & psr_event_dynamic_display_switch &&
|
||||
event != psr_event_dynamic_display_switch)
|
||||
return false;
|
||||
|
||||
// ignore other events when we're in forced psr enabled state
|
||||
if (active_psr_events & psr_event_os_override_hold &&
|
||||
event != psr_event_os_override_hold)
|
||||
return false;
|
||||
|
||||
// ignore other events when we're in forced psr enabled state
|
||||
// dds events need to be processed while in dynamic_link_rate_control
|
||||
if (active_psr_events & psr_event_dynamic_link_rate_control &&
|
||||
event != psr_event_dynamic_link_rate_control &&
|
||||
event != psr_event_dds_defer_stream_enable &&
|
||||
event != psr_event_dynamic_display_switch)
|
||||
return false;
|
||||
|
||||
if (active_psr_events & (psr_event_test_harness_disable_psr | psr_event_os_request_disable))
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_pause)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_test_harness_enable_psr)
|
||||
psr_enable_request = true;
|
||||
else if (active_psr_events & psr_event_dynamic_display_switch) {
|
||||
psr_enable_request = true;
|
||||
force_static = true;
|
||||
} else if (active_psr_events & psr_event_dynamic_link_rate_control) {
|
||||
psr_enable_request = true;
|
||||
force_static = true;
|
||||
} else if (active_psr_events & psr_event_edp_panel_off_disable_psr)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & (psr_event_hw_programming |
|
||||
psr_event_defer_enable |
|
||||
psr_event_dds_defer_stream_enable |
|
||||
psr_event_vrr_transition |
|
||||
psr_event_immediate_flip))
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_big_screen_video)
|
||||
psr_enable_request = true;
|
||||
else if (active_psr_events & psr_event_full_screen)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_mpo_video_selective_update)
|
||||
psr_enable_request = true;
|
||||
else if (active_psr_events & psr_event_vsync)
|
||||
psr_enable_request = false;
|
||||
else if (active_psr_events & psr_event_crc_window_active)
|
||||
psr_enable_request = false;
|
||||
else
|
||||
psr_enable_request = true;
|
||||
|
||||
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,
|
||||
WPP_BIT_FLAG_Firmware_PsrState,
|
||||
"mod_power set_psr_event: before: psr_enabled=%d -> request: set_event=%d event=0x%04x -> result: psr_events=0x%04x psr_enable_request=%d",
|
||||
(int)core_power->map[stream_index].psr_enabled,
|
||||
(int)set_event,
|
||||
(unsigned int)event,
|
||||
(unsigned int)core_power->map[stream_index].psr_events,
|
||||
(int)psr_enable_request);
|
||||
mod_power_psr_set_power_opt(mod_power, stream, active_psr_events, psr_enable_request);
|
||||
|
||||
if (core_power->map[stream_index].psr_enabled != psr_enable_request || force_static) {
|
||||
if (set_psr_enable(mod_power, stream, psr_enable_request, wait, force_static))
|
||||
core_power->map[stream_index].psr_enabled = psr_enable_request;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_get_psr_state(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
enum dc_psr_state *state)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
const struct dc_link *link = NULL;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
return dc_link_get_psr_state(link, state);
|
||||
}
|
||||
|
||||
bool mod_power_get_psr_enabled_status(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
bool *psr_enabled)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
*psr_enabled = core_power->map[stream_index].psr_enabled;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_power_psr_residency(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
unsigned int *residency,
|
||||
const uint8_t mode)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
const struct dc_link *link = NULL;
|
||||
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
if (link != NULL)
|
||||
link->dc->link_srv->edp_get_psr_residency(link, residency, mode);
|
||||
}
|
||||
bool mod_power_psr_get_active_psr_events(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream, unsigned int *active_psr_events)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
if (active_psr_events == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
*active_psr_events = core_power->map[stream_index].psr_events;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_power_psr_set_sink_vtotal_in_psr_active(struct mod_power *mod_power,
|
||||
const struct dc_stream_state *stream,
|
||||
uint16_t psr_vtotal_idle,
|
||||
uint16_t psr_vtotal_su)
|
||||
{
|
||||
struct core_power *core_power = NULL;
|
||||
unsigned int stream_index = 0;
|
||||
const struct dc_link *link = NULL;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (mod_power == NULL)
|
||||
return false;
|
||||
|
||||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||||
|
||||
if (core_power->num_entities == 0)
|
||||
return false;
|
||||
|
||||
stream_index = map_index_from_stream(core_power, stream);
|
||||
|
||||
if (!core_power->map[stream_index].caps->psr_version)
|
||||
return false;
|
||||
|
||||
link = dc_stream_get_link(stream);
|
||||
|
||||
return link->dc->link_srv->edp_set_sink_vtotal_in_psr_active(
|
||||
link, psr_vtotal_idle, psr_vtotal_su);
|
||||
}
|
||||
/*
|
||||
* is_psr_su_specific_panel() - check if sink is AMD vendor-specific PSR-SU
|
||||
* supported eDP device.
|
||||
*
|
||||
* @link: dc link pointer
|
||||
*
|
||||
* Return: true if AMDGPU vendor specific PSR-SU eDP panel
|
||||
*/
|
||||
bool is_psr_su_specific_panel(struct dc_link *link)
|
||||
{
|
||||
bool isPSRSUSupported = false;
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
|
||||
if (dpcd_caps->edp_rev >= DP_EDP_14) {
|
||||
if (dpcd_caps->psr_info.psr_version >= DP_PSR2_WITH_Y_COORD_ET_SUPPORTED)
|
||||
isPSRSUSupported = true;
|
||||
/*
|
||||
* Some panels will report PSR capabilities over additional DPCD bits.
|
||||
* Such panels are approved despite reporting only PSR v3, as long as
|
||||
* the additional bits are reported.
|
||||
*/
|
||||
if (dpcd_caps->sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) {
|
||||
/*
|
||||
* This is the temporary workaround to disable PSRSU when system turned on
|
||||
* DSC function on the sepcific sink.
|
||||
*/
|
||||
if (dpcd_caps->psr_info.psr_version < DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
|
||||
((dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x08) ||
|
||||
(dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x07)))
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x01)
|
||||
isPSRSUSupported = false;
|
||||
else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1)
|
||||
isPSRSUSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isPSRSUSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* mod_power_calc_psr_configs() - calculate/update generic psr configuration fields.
|
||||
* @psr_config: [output], psr configuration structure to be updated
|
||||
* @link: [input] dc link pointer
|
||||
* @stream: [input] dc stream state pointer
|
||||
*
|
||||
* calculate and update the psr configuration fields that are not DM specific, i.e. such
|
||||
* fields which are based on DPCD caps or timing information. To setup PSR in DMUB FW,
|
||||
* this helper is assumed to be called before the call of the DC helper dc_link_setup_psr().
|
||||
*
|
||||
* PSR config fields to be updated within the helper:
|
||||
* - psr_rfb_setup_time
|
||||
* - psr_sdp_transmit_line_num_deadline
|
||||
* - line_time_in_us
|
||||
* - su_y_granularity
|
||||
* - su_granularity_required
|
||||
* - psr_frame_capture_indication_req
|
||||
* - psr_exit_link_training_required
|
||||
*
|
||||
* PSR config fields that are DM specific and NOT updated within the helper:
|
||||
* - allow_smu_optimizations
|
||||
* - allow_multi_disp_optimizations
|
||||
*/
|
||||
void mod_power_calc_psr_configs(struct psr_config *psr_config,
|
||||
struct dc_link *link,
|
||||
const struct dc_stream_state *stream)
|
||||
{
|
||||
unsigned int num_vblank_lines = 0;
|
||||
unsigned int vblank_time_in_us = 0;
|
||||
unsigned int sdp_tx_deadline_in_us = 0;
|
||||
unsigned int line_time_in_us = 0;
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
const int psr_setup_time_step_in_us = 55; /* refer to eDP spec DPCD 0x071h */
|
||||
|
||||
/* timing parameters */
|
||||
num_vblank_lines = stream->timing.v_total -
|
||||
stream->timing.v_addressable -
|
||||
stream->timing.v_border_top -
|
||||
stream->timing.v_border_bottom;
|
||||
|
||||
vblank_time_in_us = (stream->timing.h_total * num_vblank_lines * 1000) / (stream->timing.pix_clk_100hz / 10);
|
||||
|
||||
line_time_in_us = ((stream->timing.h_total * 1000) / (stream->timing.pix_clk_100hz / 10)) + 1;
|
||||
|
||||
/**
|
||||
* psr configuration fields
|
||||
*
|
||||
* as per eDP 1.5 pg. 377 of 459, DPCD 0x071h bits [3:1], psr setup time bits interpreted as below
|
||||
* 000b <--> 330 us (default)
|
||||
* 001b <--> 275 us
|
||||
* 010b <--> 220 us
|
||||
* 011b <--> 165 us
|
||||
* 100b <--> 110 us
|
||||
* 101b <--> 055 us
|
||||
* 110b <--> 000 us
|
||||
*/
|
||||
psr_config->psr_rfb_setup_time =
|
||||
(6 - dpcd_caps->psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME) * psr_setup_time_step_in_us;
|
||||
|
||||
if (psr_config->psr_rfb_setup_time > vblank_time_in_us) {
|
||||
link->psr_settings.psr_frame_capture_indication_req = true;
|
||||
link->psr_settings.psr_sdp_transmit_line_num_deadline = num_vblank_lines;
|
||||
} else {
|
||||
sdp_tx_deadline_in_us = vblank_time_in_us - psr_config->psr_rfb_setup_time;
|
||||
|
||||
/* Set the last possible line SDP may be transmitted without violating the RFB setup time */
|
||||
link->psr_settings.psr_frame_capture_indication_req = false;
|
||||
link->psr_settings.psr_sdp_transmit_line_num_deadline = sdp_tx_deadline_in_us / line_time_in_us;
|
||||
}
|
||||
|
||||
psr_config->psr_sdp_transmit_line_num_deadline = link->psr_settings.psr_sdp_transmit_line_num_deadline;
|
||||
psr_config->line_time_in_us = line_time_in_us;
|
||||
psr_config->su_y_granularity = dpcd_caps->psr_info.psr2_su_y_granularity_cap;
|
||||
psr_config->su_granularity_required = dpcd_caps->psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED;
|
||||
psr_config->psr_frame_capture_indication_req = link->psr_settings.psr_frame_capture_indication_req;
|
||||
psr_config->psr_exit_link_training_required =
|
||||
!link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED;
|
||||
}
|
||||
|
||||
bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
|
||||
struct dc_stream_state *stream,
|
||||
struct psr_config *config)
|
||||
{
|
||||
uint32_t pic_height;
|
||||
uint32_t slice_height;
|
||||
|
||||
config->dsc_slice_height = 0;
|
||||
if (!(link->connector_signal & SIGNAL_TYPE_EDP) ||
|
||||
!dc->caps.edp_dsc_support ||
|
||||
link->panel_config.dsc.disable_dsc_edp ||
|
||||
!link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT ||
|
||||
!stream->timing.dsc_cfg.num_slices_v)
|
||||
return true;
|
||||
|
||||
pic_height = stream->timing.v_addressable +
|
||||
stream->timing.v_border_top + stream->timing.v_border_bottom;
|
||||
|
||||
if (stream->timing.dsc_cfg.num_slices_v == 0)
|
||||
return false;
|
||||
|
||||
slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v;
|
||||
config->dsc_slice_height = (uint16_t)slice_height;
|
||||
|
||||
if (slice_height) {
|
||||
if (config->su_y_granularity &&
|
||||
(slice_height % config->su_y_granularity)) {
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user