* configurations, ensuring p-state watermark support in the blank period only.
*/
+static const double MIN_VACTIVE_MARGIN_PCT = 0.25; // We need more than non-zero margin because DET buffer granularity can alter vactive latency hiding
+
static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_1_display[] = {
// VBlank only
{
- .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
+ .per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
};
static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_2_display[] = {
// VBlank only for both displays
{
- .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
+ .per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
};
static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_3_display[] = {
// VBlank only for all three displays
{
- .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na },
+ .per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na },
.allow_state_increase = true,
},
};
static const struct dml2_pmo_pstate_strategy dcn42_strategy_list_4_display[] = {
// VBlank only for all four displays
{
- .per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank },
+ .per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive },
.allow_state_increase = true,
},
};
static const int dcn42_strategy_list_4_display_size = sizeof(dcn42_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy);
+static bool is_bit_set_in_bitfield(unsigned int bit_field, unsigned int bit_offset)
+{
+ if (bit_field & (0x1 << bit_offset))
+ return true;
+
+ return false;
+}
+
+static void setup_planes_for_vactive_by_mask(struct display_configuation_with_meta *display_config,
+ struct dml2_pmo_instance *pmo,
+ int plane_mask)
+{
+ unsigned int plane_index;
+ unsigned int stream_index;
+ struct dml2_plane_parameters *plane;
+
+ for (plane_index = 0; plane_index < display_config->display_config.num_planes; plane_index++) {
+ if (is_bit_set_in_bitfield(plane_mask, plane_index)) {
+ plane = &display_config->display_config.plane_descriptors[plane_index];
+ stream_index = display_config->display_config.plane_descriptors[plane_index].stream_index;
+
+ plane->overrides.reserved_vblank_time_ns = (long)math_max2(pmo->soc_bb->power_management_parameters.dram_clk_change_blackout_us * 1000.0,
+ plane->overrides.reserved_vblank_time_ns);
+ if (!pmo->options->disable_vactive_det_fill_bw_pad) {
+ display_config->display_config.plane_descriptors[plane_index].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_uclk] =
+ (unsigned int)math_floor(pmo->scratch.pmo_dcn4.stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us);
+ }
+
+ display_config->stage3.pstate_switch_modes[plane_index] = dml2_pstate_method_vactive;
+ }
+ }
+}
+
+static void reset_display_configuration(struct display_configuation_with_meta *display_config)
+{
+ unsigned int plane_index;
+ unsigned int stream_index;
+ struct dml2_plane_parameters *plane;
+
+ for (stream_index = 0; stream_index < display_config->display_config.num_streams; stream_index++) {
+ display_config->stage3.stream_svp_meta[stream_index].valid = false;
+ }
+
+ for (plane_index = 0; plane_index < display_config->display_config.num_planes; plane_index++) {
+ plane = &display_config->display_config.plane_descriptors[plane_index];
+
+ // Unset SubVP
+ plane->overrides.legacy_svp_config = dml2_svp_mode_override_auto;
+
+ // Remove reserve time
+ plane->overrides.reserved_vblank_time_ns = 0;
+
+ // Reset strategy to auto
+ plane->overrides.uclk_pstate_change_strategy = dml2_uclk_pstate_change_strategy_auto;
+
+ display_config->stage3.pstate_switch_modes[plane_index] = dml2_pstate_method_na;
+ }
+}
+
+static bool setup_display_config(struct display_configuation_with_meta *display_config, struct dml2_pmo_instance *pmo, int strategy_index)
+{
+ struct dml2_pmo_scratch *scratch = &pmo->scratch;
+
+ bool fams2_required = false;
+ bool success = true;
+ unsigned int stream_index;
+
+ reset_display_configuration(display_config);
+
+ for (stream_index = 0; stream_index < display_config->display_config.num_streams; stream_index++) {
+
+ if (pmo->scratch.pmo_dcn4.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_na) {
+ success = false;
+ break;
+ } else if (scratch->pmo_dcn4.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive) {
+ setup_planes_for_vactive_by_mask(display_config, pmo, scratch->pmo_dcn4.stream_plane_mask[stream_index]);
+ }
+ }
+
+ /* copy FAMS2 meta */
+ if (success) {
+ display_config->stage3.fams2_required = fams2_required;
+ memcpy(&display_config->stage3.stream_pstate_meta,
+ &scratch->pmo_dcn4.stream_pstate_meta,
+ sizeof(struct dml2_pstate_meta) * DML2_MAX_PLANES);
+ }
+
+ return success;
+}
+
+bool pmo_dcn42_fams2_optimize_for_pstate_support(struct dml2_pmo_optimize_for_pstate_support_in_out *in_out)
+{
+ bool success = false;
+ struct dml2_pmo_scratch *s = &in_out->instance->scratch;
+
+ memcpy(in_out->optimized_display_config, in_out->base_display_config, sizeof(struct display_configuation_with_meta));
+
+ if (in_out->last_candidate_failed) {
+ if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].allow_state_increase &&
+ s->pmo_dcn4.cur_latency_index < s->pmo_dcn4.max_latency_index - 1) {
+ s->pmo_dcn4.cur_latency_index++;
+
+ success = true;
+ }
+ }
+
+ if (!success) {
+ s->pmo_dcn4.cur_latency_index = s->pmo_dcn4.min_latency_index;
+ s->pmo_dcn4.cur_pstate_candidate++;
+
+ if (s->pmo_dcn4.cur_pstate_candidate < s->pmo_dcn4.num_pstate_candidates) {
+ success = true;
+ }
+ }
+
+ if (success) {
+ in_out->optimized_display_config->stage3.min_clk_index_for_latency = s->pmo_dcn4.cur_latency_index;
+ setup_display_config(in_out->optimized_display_config, in_out->instance, in_out->instance->scratch.pmo_dcn4.cur_pstate_candidate);
+ }
+
+ return success;
+}
+
bool pmo_dcn42_test_for_pstate_support(struct dml2_pmo_test_for_pstate_support_in_out *in_out)
{
const struct dml2_pmo_scratch *s = &in_out->instance->scratch;
- const int REQUIRED_RESERVED_TIME =
- (int)in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us;
bool p_state_supported = true;
unsigned int stream_index;
- if (in_out->base_display_config->display_config.overrides.all_streams_blanked)
- return true;
-
if (s->pmo_dcn4.cur_pstate_candidate < 0)
return false;
for (stream_index = 0; stream_index < in_out->base_display_config->display_config.num_streams; stream_index++) {
- if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank) {
- if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME ||
- dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) > 0) {
+ if (s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive) {
+ if (dcn4_get_minimum_reserved_time_us_for_planes(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (int)in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us ||
+ dcn4_get_vactive_pstate_margin(in_out->base_display_config, s->pmo_dcn4.stream_plane_mask[stream_index]) < (int)(MIN_VACTIVE_MARGIN_PCT * in_out->instance->soc_bb->power_management_parameters.dram_clk_change_blackout_us)) {
p_state_supported = false;
break;
}
bool result = false;
bool mcache_success = false;
+ bool uclk_pstate_success = false;
memset(dpmm_programming, 0, sizeof(struct dml2_display_cfg_programming));
setup_unoptimized_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
mcache_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &mcache_phase);
}
+ if (result) {
+ if (dml->pmo_options.force_mandatory_uclk_pstate_support) {
+ struct optimization_phase_params uclk_phase = {
+ .dml = dml,
+ .display_config = &l->base_display_config_with_meta,
+ .init_function = dml2_top_optimization_init_function_uclk_pstate,
+ .test_function = dml2_top_optimization_test_function_uclk_pstate,
+ .optimize_function = dml2_top_optimization_optimize_function_uclk_pstate,
+ .optimized_display_config = &l->optimized_display_config_with_meta,
+ .all_or_nothing = false,
+ };
+
+ uclk_pstate_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &uclk_phase);
+ } else {
+ uclk_pstate_success = true;
+ }
+ }
+
/*
* Call DPMM to map all requirements to minimum clock state
*/
result = dml->dpmm_instance.map_mode_to_soc_dpm(&l->dppm_map_mode_params);
}
- in_out->is_supported = mcache_success;
+ in_out->is_supported = mcache_success & uclk_pstate_success;
result = result && in_out->is_supported;
return result;
if (uclk_pstate_success) {
memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
l->base_display_config_with_meta.stage3.success = true;
+ } else if (dml->pmo_options.force_mandatory_uclk_pstate_support) {
+ l->informative_params.instance = &dml->core_instance;
+ l->informative_params.programming = in_out->programming;
+ l->informative_params.mode_is_supported = false;
+
+ dml->core_instance.populate_informative(&l->informative_params);
+
+ in_out->programming->informative.failed_mcache_validation = true;
+ return false;
}
/*