From: Lohita Mudimela <[email protected]> [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 <[email protected]> Signed-off-by: Lohita Mudimela <[email protected]> Signed-off-by: Ivan Lipski <[email protected]> --- .../drm/amd/display/modules/inc/mod_power.h | 23 - .../drm/amd/display/modules/power/Makefile | 2 +- .../gpu/drm/amd/display/modules/power/power.c | 562 +-------------- .../drm/amd/display/modules/power/power_abm.c | 96 --- .../amd/display/modules/power/power_helpers.c | 158 ----- .../amd/display/modules/power/power_helpers.h | 116 +++ .../drm/amd/display/modules/power/power_psr.c | 665 ++++++++++++++++++ 7 files changed, 785 insertions(+), 837 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/modules/power/power_psr.c diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h index 440e4284b6f0..f9814cf7bbdb 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h @@ -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_ */ diff --git a/drivers/gpu/drm/amd/display/modules/power/Makefile b/drivers/gpu/drm/amd/display/modules/power/Makefile index dd11f7d5617d..fc4ba5873fad 100644 --- a/drivers/gpu/drm/amd/display/modules/power/Makefile +++ b/drivers/gpu/drm/amd/display/modules/power/Makefile @@ -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 ************) diff --git a/drivers/gpu/drm/amd/display/modules/power/power.c b/drivers/gpu/drm/amd/display/modules/power/power.c index f8a0b252c745..214ecc1f550d 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power.c +++ b/drivers/gpu/drm/amd/display/modules/power/power.c @@ -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, diff --git a/drivers/gpu/drm/amd/display/modules/power/power_abm.c b/drivers/gpu/drm/amd/display/modules/power/power_abm.c index c41ace406519..8ed7ce26476e 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_abm.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_abm.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 1046fc35f8f9..2fc2e2929e95 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -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, diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h index 94d2521355ce..3a2ba87be706 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -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_ */ diff --git a/drivers/gpu/drm/amd/display/modules/power/power_psr.c b/drivers/gpu/drm/amd/display/modules/power/power_psr.c new file mode 100644 index 000000000000..5ecb570c204e --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/power/power_psr.c @@ -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; +} -- 2.43.0
