1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4
5 #include "dml2_pmo_dcn5_stage_optimizers.h"
6 #include "dml2_pmo_dcn6_stage_optimizers.h"
7 #include "dml2_debug.h"
8 #include "lib_float_math.h"
9
uclk_pstate_strategy_override_to_pstate_method(const enum dml2_uclk_pstate_change_strategy override_strategy)10 static enum dml2_pstate_method uclk_pstate_strategy_override_to_pstate_method(const enum dml2_uclk_pstate_change_strategy override_strategy)
11 {
12 enum dml2_pstate_method method = dml2_pstate_method_na;
13
14 switch (override_strategy) {
15 case dml2_uclk_pstate_change_strategy_force_vactive:
16 method = dml2_pstate_method_vactive;
17 break;
18 case dml2_uclk_pstate_change_strategy_force_vblank:
19 method = dml2_pstate_method_vblank;
20 break;
21 case dml2_uclk_pstate_change_strategy_force_drr:
22 method = dml2_pstate_method_fw_drr;
23 break;
24 case dml2_uclk_pstate_change_strategy_force_alternate:
25 method = dml2_pstate_method_alternate;
26 break;
27 case dml2_uclk_pstate_change_strategy_force_mall_svp:
28 case dml2_uclk_pstate_change_strategy_force_mall_full_frame:
29 case dml2_uclk_pstate_change_strategy_auto:
30 default:
31 method = dml2_pstate_method_na;
32 }
33
34 return method;
35 }
36
pstate_method_to_uclk_pstate_strategy_override(const enum dml2_pstate_method method)37 static enum dml2_uclk_pstate_change_strategy pstate_method_to_uclk_pstate_strategy_override(const enum dml2_pstate_method method)
38 {
39 enum dml2_uclk_pstate_change_strategy override_strategy = dml2_uclk_pstate_change_strategy_auto;
40
41 switch (method) {
42 case dml2_pstate_method_vactive:
43 case dml2_pstate_method_fw_vactive_drr:
44 override_strategy = dml2_uclk_pstate_change_strategy_force_vactive;
45 break;
46 case dml2_pstate_method_vblank:
47 case dml2_pstate_method_fw_vblank_drr:
48 override_strategy = dml2_uclk_pstate_change_strategy_force_vblank;
49 break;
50 case dml2_pstate_method_fw_drr:
51 override_strategy = dml2_uclk_pstate_change_strategy_force_drr;
52 break;
53 case dml2_pstate_method_alternate:
54 override_strategy = dml2_uclk_pstate_change_strategy_force_alternate;
55 break;
56 case dml2_pstate_method_fw_svp:
57 case dml2_pstate_method_fw_svp_drr:
58 case dml2_pstate_method_reserved_hw:
59 case dml2_pstate_method_reserved_fw:
60 case dml2_pstate_method_reserved_fw_drr_clamped:
61 case dml2_pstate_method_reserved_fw_drr_var:
62 case dml2_pstate_method_count:
63 case dml2_pstate_method_na:
64 default:
65 override_strategy = dml2_uclk_pstate_change_strategy_auto;
66 }
67
68 return override_strategy;
69 }
70
all_planes_match_method(const struct dml2_display_cfg * display_cfg,int plane_mask,enum dml2_pstate_method method)71 static bool all_planes_match_method(const struct dml2_display_cfg *display_cfg, int plane_mask, enum dml2_pstate_method method)
72 {
73 unsigned char i;
74
75 for (i = 0; i < DML2_MAX_PLANES; i++) {
76 if (is_bit_set_in_bitfield(plane_mask, i)) {
77 if (display_cfg->plane_descriptors[i].overrides.uclk_pstate_change_strategy != dml2_uclk_pstate_change_strategy_auto &&
78 display_cfg->plane_descriptors[i].overrides.uclk_pstate_change_strategy != pstate_method_to_uclk_pstate_strategy_override(method))
79 return false;
80 }
81 }
82
83 return true;
84 }
85
get_per_method_common_meta(const struct dml2_pstate_meta * stream_pstate_meta,enum dml2_pstate_method stream_pstate_method,int stream_idx)86 static const struct dml2_pstate_per_method_common_meta *get_per_method_common_meta(
87 const struct dml2_pstate_meta *stream_pstate_meta,
88 enum dml2_pstate_method stream_pstate_method,
89 int stream_idx)
90 {
91 const struct dml2_pstate_per_method_common_meta *stream_method_pstate_meta = NULL;
92
93 switch (stream_pstate_method) {
94 case dml2_pstate_method_vactive:
95 case dml2_pstate_method_fw_vactive_drr:
96 stream_method_pstate_meta = &stream_pstate_meta[stream_idx].method_vactive.common;
97 break;
98 case dml2_pstate_method_vblank:
99 case dml2_pstate_method_fw_vblank_drr:
100 stream_method_pstate_meta = &stream_pstate_meta[stream_idx].method_vblank.common;
101 break;
102 case dml2_pstate_method_fw_drr:
103 stream_method_pstate_meta = &stream_pstate_meta[stream_idx].method_drr.common;
104 break;
105 case dml2_pstate_method_alternate:
106 stream_method_pstate_meta = &stream_pstate_meta[stream_idx].method_alternate.common;
107 break;
108 case dml2_pstate_method_fw_svp:
109 case dml2_pstate_method_fw_svp_drr:
110 case dml2_pstate_method_reserved_hw:
111 case dml2_pstate_method_reserved_fw:
112 case dml2_pstate_method_reserved_fw_drr_clamped:
113 case dml2_pstate_method_reserved_fw_drr_var:
114 case dml2_pstate_method_count:
115 case dml2_pstate_method_na:
116 default:
117 stream_method_pstate_meta = NULL;
118 }
119
120 return stream_method_pstate_meta;
121 }
122
dcn6_get_params_for_pstate_type(const struct dml2_pmo_instance * pmo,const struct dml2_optimization_worksheet * worksheet,enum dml2_pstate_type pstate_type,double * allow_delay_us,double * blackout_us,double * watermark_us)123 static void dcn6_get_params_for_pstate_type(const struct dml2_pmo_instance *pmo,
124 const struct dml2_optimization_worksheet *worksheet,
125 enum dml2_pstate_type pstate_type,
126 double *allow_delay_us,
127 double *blackout_us,
128 double *watermark_us)
129 {
130 switch (pstate_type) {
131 case dml2_pstate_type_uclk:
132 *allow_delay_us = (double)pmo->ip_caps->fams2.max_allow_delay_us;
133 *blackout_us = pmo->utm_soc_bb->power_management_parameters.dram_clk_change_blackout_us;
134 *watermark_us = worksheet->validation_result.mode_support.global.watermarks.DRAMClockChangeWatermark;
135 break;
136 case dml2_pstate_type_fclk:
137 *allow_delay_us = (double)pmo->ip_caps->fams2.max_allow_delay_us; /* TODO placeholder */
138 *blackout_us = pmo->utm_soc_bb->power_management_parameters.fclk_change_blackout_us;
139 *watermark_us = worksheet->validation_result.mode_support.global.watermarks.FCLKChangeWatermark;
140 break;
141 case dml2_pstate_type_ppt:
142 *allow_delay_us = (double)pmo->ip_caps->ppt_max_allow_delay_us;
143 *blackout_us = math_max2(
144 pmo->utm_soc_bb->power_management_parameters.g7_ppt_blackout_us,
145 pmo->utm_soc_bb->power_management_parameters.g7_temperature_read_blackout_us);
146 *watermark_us = worksheet->validation_result.mode_support.global.watermarks.temp_read_or_ppt_watermark_us;
147 break;
148 case dml2_pstate_type_temp_read:
149 case dml2_pstate_type_dummy_pstate:
150 *allow_delay_us = (double)pmo->ip_caps->temp_read_max_allow_delay_us;
151 *blackout_us = math_max2(
152 pmo->utm_soc_bb->power_management_parameters.g7_ppt_blackout_us,
153 pmo->utm_soc_bb->power_management_parameters.g7_temperature_read_blackout_us);
154 *watermark_us = worksheet->validation_result.mode_support.global.watermarks.temp_read_or_ppt_watermark_us;
155 break;
156 case dml2_pstate_type_count:
157 default:
158 *allow_delay_us = 0.0;
159 *blackout_us = 0.0;
160 *watermark_us = 0.0;
161 break;
162 }
163 }
164
dcn6_is_timing_group_schedulable(const struct dml2_pstate_meta * stream_pstate_meta,const struct dml2_display_cfg * display_cfg,const enum dml2_pstate_method * per_stream_pstate_method,const unsigned int timing_group_idx,const double max_allow_delay_us,struct dml2_pstate_per_method_common_meta * group_pstate_meta,struct dml2_pmo_synchronized_timing_groups * s)165 static bool dcn6_is_timing_group_schedulable(
166 const struct dml2_pstate_meta *stream_pstate_meta,
167 const struct dml2_display_cfg *display_cfg,
168 const enum dml2_pstate_method *per_stream_pstate_method,
169 const unsigned int timing_group_idx,
170 const double max_allow_delay_us,
171 struct dml2_pstate_per_method_common_meta *group_pstate_meta,
172 struct dml2_pmo_synchronized_timing_groups *s)
173 {
174 unsigned int i;
175 const struct dml2_pstate_per_method_common_meta *stream_method_pstate_meta;
176 unsigned int base_stream_idx = 0;
177
178 /* find base stream idx */
179 for (base_stream_idx = 0; base_stream_idx < display_cfg->num_streams; base_stream_idx++) {
180 if (is_bit_set_in_bitfield(s->synchronized_timing_group_masks[timing_group_idx], base_stream_idx)) {
181 /* master stream found */
182 break;
183 }
184 }
185
186 /* init allow start and end lines for timing group */
187 stream_method_pstate_meta = get_per_method_common_meta(stream_pstate_meta, per_stream_pstate_method[base_stream_idx], base_stream_idx);
188 if (!stream_method_pstate_meta)
189 return false;
190
191 group_pstate_meta->allow_start_otg_vline = stream_method_pstate_meta->allow_start_otg_vline;
192 group_pstate_meta->allow_end_otg_vline = stream_method_pstate_meta->allow_end_otg_vline;
193 group_pstate_meta->period_us = stream_method_pstate_meta->period_us;
194 for (i = base_stream_idx + 1; i < display_cfg->num_streams; i++) {
195 if (is_bit_set_in_bitfield(s->synchronized_timing_group_masks[timing_group_idx], i)) {
196 stream_method_pstate_meta = get_per_method_common_meta(stream_pstate_meta, per_stream_pstate_method[i], i);
197 if (!stream_method_pstate_meta)
198 continue;
199
200 if (group_pstate_meta->allow_start_otg_vline < stream_method_pstate_meta->allow_start_otg_vline) {
201 /* set group allow start to larger otg vline */
202 group_pstate_meta->allow_start_otg_vline = stream_method_pstate_meta->allow_start_otg_vline;
203 }
204
205 if (group_pstate_meta->allow_end_otg_vline > stream_method_pstate_meta->allow_end_otg_vline) {
206 /* set group allow end to smaller otg vline */
207 group_pstate_meta->allow_end_otg_vline = stream_method_pstate_meta->allow_end_otg_vline;
208 }
209
210 /* check waveform still has positive width */
211 if (group_pstate_meta->allow_start_otg_vline >= group_pstate_meta->allow_end_otg_vline) {
212 /* timing group is not schedulable */
213 return false;
214 }
215 }
216 }
217
218 /* calculate the rest of the meta */
219 dcn5_build_method_scheduling_params(group_pstate_meta, &stream_pstate_meta[base_stream_idx]);
220
221 return group_pstate_meta->allow_time_us > 0.0 &&
222 group_pstate_meta->disallow_time_us <= max_allow_delay_us;
223 }
224
dcn6_is_pstate_schedulable(struct dml2_pstate_meta * stream_pstate_meta,const struct dml2_display_cfg * display_cfg,const enum dml2_pstate_method * per_stream_pstate_method,const double max_allow_delay_us,struct dml2_pmo_synchronized_timing_groups * synchronized_timing_groups,struct dml2_scheduling_check_locals * s)225 static bool dcn6_is_pstate_schedulable(
226 struct dml2_pstate_meta *stream_pstate_meta,
227 const struct dml2_display_cfg *display_cfg,
228 const enum dml2_pstate_method *per_stream_pstate_method,
229 const double max_allow_delay_us,
230 struct dml2_pmo_synchronized_timing_groups *synchronized_timing_groups,
231 struct dml2_scheduling_check_locals *s)
232 {
233 double max_disallow_time_us = 0.0;
234 unsigned int i, j;
235 bool schedulable;
236
237 memset(s->group_common_pstate_meta, 0, sizeof(s->group_common_pstate_meta));
238 memset(s->sorted_group_gtl_disallow_index, 0, sizeof(unsigned int) * DML2_MAX_PLANES);
239
240 /* search for a general solution to the schedule */
241
242 /* STAGE 0: Early return for special cases */
243 if (display_cfg->num_streams == 0) {
244 return true;
245 }
246
247 /* STAGE 1: confirm allow waves overlap for synchronizable streams */
248 schedulable = true;
249 for (i = 0; i < synchronized_timing_groups->num_timing_groups; i++) {
250 s->sorted_group_gtl_disallow_index[i] = i;
251 s->sorted_group_gtl_period_index[i] = i;
252 if (!dcn6_is_timing_group_schedulable(stream_pstate_meta,
253 display_cfg,
254 per_stream_pstate_method,
255 i,
256 max_allow_delay_us,
257 &s->group_common_pstate_meta[i],
258 synchronized_timing_groups)) {
259 /* synchronized timing group was not schedulable */
260 schedulable = false;
261 break;
262 }
263 max_disallow_time_us += s->group_common_pstate_meta[i].disallow_time_us;
264 }
265
266 if ((schedulable && synchronized_timing_groups->num_timing_groups <= 1) || !schedulable) {
267 /* 1. the only timing group was schedulable, so early pass
268 * 2. one of the timing groups was not schedulable, so early fail */
269 return schedulable;
270 }
271
272 /* STAGE 2: Check allow can't be masked entirely by other disallows */
273 schedulable = true;
274
275 /* sort disallow times from greatest to least */
276 for (i = 0; i < synchronized_timing_groups->num_timing_groups; i++) {
277 bool swapped = false;
278
279 for (j = 0; j < synchronized_timing_groups->num_timing_groups - 1; j++) {
280 double j_disallow_us = s->group_common_pstate_meta[s->sorted_group_gtl_disallow_index[j]].disallow_time_us;
281 double jp1_disallow_us = s->group_common_pstate_meta[s->sorted_group_gtl_disallow_index[j + 1]].disallow_time_us;
282 if (j_disallow_us < jp1_disallow_us) {
283 /* swap as A < B */
284 swap(s->sorted_group_gtl_disallow_index[j],
285 s->sorted_group_gtl_disallow_index[j+1]);
286 swapped = true;
287 }
288 }
289
290 /* sorted, exit early */
291 if (!swapped)
292 break;
293 }
294
295 /* Check worst case disallow region occurs in the middle of allow for the
296 * other display, or when >2 streams continue to halve the remaining allow time.
297 */
298 for (i = 0; i < synchronized_timing_groups->num_timing_groups; i++) {
299 if (s->group_common_pstate_meta[i].disallow_time_us <= 0.0) {
300 /* this timing group always allows */
301 continue;
302 }
303
304 double max_allow_time_us = s->group_common_pstate_meta[i].allow_time_us;
305 for (j = 0; j < synchronized_timing_groups->num_timing_groups; j++) {
306 unsigned int sorted_j = s->sorted_group_gtl_disallow_index[j];
307 /* stream can't overlap itself */
308 if (i != sorted_j && s->group_common_pstate_meta[sorted_j].disallow_time_us > 0.0) {
309 double unmasked_allow_time_us = (max_allow_time_us - s->group_common_pstate_meta[sorted_j].disallow_time_us) / 2;
310
311 max_allow_time_us = math_min2(
312 s->group_common_pstate_meta[sorted_j].allow_time_us,
313 unmasked_allow_time_us);
314
315 if (max_allow_time_us < 0.0) {
316 /* failed exit early */
317 break;
318 }
319 }
320 }
321
322 if (max_allow_time_us <= 0.0) {
323 /* not enough time for microschedule in the worst case */
324 schedulable = false;
325 break;
326 }
327 }
328
329 if (schedulable && max_disallow_time_us < max_allow_delay_us) {
330 return true;
331 }
332
333 /* STAGE 3: check larger allow can fit period of all other streams */
334 schedulable = true;
335
336 /* sort periods from greatest to least */
337 for (i = 0; i < synchronized_timing_groups->num_timing_groups; i++) {
338 bool swapped = false;
339
340 for (j = 0; j < synchronized_timing_groups->num_timing_groups - 1; j++) {
341 double j_period_us = s->group_common_pstate_meta[s->sorted_group_gtl_period_index[j]].period_us;
342 double jp1_period_us = s->group_common_pstate_meta[s->sorted_group_gtl_period_index[j + 1]].period_us;
343 if (j_period_us < jp1_period_us) {
344 /* swap as A < B */
345 swap(s->sorted_group_gtl_period_index[j],
346 s->sorted_group_gtl_period_index[j + 1]);
347 swapped = true;
348 }
349 }
350
351 /* sorted, exit early */
352 if (!swapped)
353 break;
354 }
355
356 /* check larger allow can fit period of all other streams */
357 for (i = 0; i < synchronized_timing_groups->num_timing_groups - 1; i++) {
358 unsigned int sorted_i = s->sorted_group_gtl_period_index[i];
359 unsigned int sorted_ip1 = s->sorted_group_gtl_period_index[i + 1];
360
361 if (s->group_common_pstate_meta[sorted_i].allow_time_us < s->group_common_pstate_meta[sorted_ip1].period_us ||
362 (synchronized_timing_groups->group_is_drr_enabled[sorted_ip1] && synchronized_timing_groups->group_is_drr_active[sorted_ip1])) {
363 schedulable = false;
364 break;
365 }
366 }
367
368 if (schedulable && max_disallow_time_us < max_allow_delay_us) {
369 return true;
370 }
371
372 /* STAGE 4: When using HW exclusive modes, check disallow alignments are within allowed threshold */
373 if (synchronized_timing_groups->num_timing_groups == 2 &&
374 !is_bit_set_in_bitfield(PMO_FW_STRATEGY_MASK, per_stream_pstate_method[0]) &&
375 !is_bit_set_in_bitfield(PMO_FW_STRATEGY_MASK, per_stream_pstate_method[1])) {
376 double sum_allow_time_us;
377 double shift_per_period;
378 double period_ratio;
379 double max_shift_us;
380
381 /* default period_0 > period_1 */
382 unsigned int lrg_idx = 0;
383 unsigned int sml_idx = 1;
384 if (s->group_common_pstate_meta[0].period_us < s->group_common_pstate_meta[1].period_us) {
385 /* period_0 < period_1 */
386 lrg_idx = 1;
387 sml_idx = 0;
388 }
389 period_ratio = s->group_common_pstate_meta[lrg_idx].period_us / s->group_common_pstate_meta[sml_idx].period_us;
390 shift_per_period = s->group_common_pstate_meta[sml_idx].period_us * (period_ratio - math_floor(period_ratio));
391 max_shift_us = s->group_common_pstate_meta[lrg_idx].disallow_time_us - s->group_common_pstate_meta[sml_idx].allow_time_us;
392 max_disallow_time_us = max_shift_us / shift_per_period * s->group_common_pstate_meta[lrg_idx].period_us;
393 sum_allow_time_us = s->group_common_pstate_meta[lrg_idx].allow_time_us + s->group_common_pstate_meta[sml_idx].allow_time_us;
394
395 if (shift_per_period > 0.0 &&
396 shift_per_period < sum_allow_time_us &&
397 max_disallow_time_us < max_allow_delay_us) {
398 schedulable = true;
399 }
400 }
401
402 return schedulable;
403 }
404
dcn6_update_worksheet_for_pstate_admissibility(struct dml2_optimization_worksheet * worksheet,struct dml2_pstate_meta * per_stream_pstate_meta,enum dml2_pstate_type pstate_type)405 static bool dcn6_update_worksheet_for_pstate_admissibility(struct dml2_optimization_worksheet *worksheet,
406 struct dml2_pstate_meta *per_stream_pstate_meta,
407 enum dml2_pstate_type pstate_type)
408 {
409 const double vblank_ratio = 0.8;
410 unsigned int plane_index, stream_index;
411 double ideal_relative_disallow, ideal_disallow_time_us, disallow_time_us;
412 double extra_time_required_us;
413 double vblank_time_us;
414 double min_unreserved_vblank_time_us;
415 double min_det_fill_delay_us;
416 double delta_max_det_fill_delay_us;
417 double delta_reserved_vblank_time_us;
418
419 int max_vactive_det_fill_delay_us;
420 long reserved_vblank_time_ns;
421 bool unvalidated_changes = false;
422
423 const struct dml2_display_cfg *display_config = worksheet->orig_dispcfg;
424 /* Two possible locations to obtain the extra time required to pass admissibility
425 * 1. Allocate some time from the reserved vblank
426 * 2. Use some of the time reserved for the vactive det fill delay
427 * For now statically favour getting most of the required time from the reserved vblank since
428 * configs failing pstate admissibility tend to have a large vblank to vactive ratio.
429 */
430
431 ideal_relative_disallow = 1.0;
432 if (display_config->num_streams > 1) {
433 /* The disallow region should be less than (0.5) ^ (number of displays - 1) * total frame time
434 * Calculation assumes identical displays / timings when performing the scheduling check
435 * Make the relative disallow 5% smaller than the ideal case to add extra margin
436 */
437 ideal_relative_disallow = (double)math_pow(0.5, (float)(display_config->num_streams - 1)) * 0.95;
438 }
439
440 for (stream_index = 0; stream_index < display_config->num_streams; stream_index++) {
441 disallow_time_us = per_stream_pstate_meta[stream_index].method_vactive.common.disallow_time_us;
442 ideal_disallow_time_us = per_stream_pstate_meta[stream_index].method_vactive.common.period_us * ideal_relative_disallow;
443
444 extra_time_required_us = 0.0;
445 delta_max_det_fill_delay_us = 0.0;
446 delta_reserved_vblank_time_us = 0.0;
447 if (disallow_time_us > ideal_disallow_time_us) {
448 /* minimum unreserved 15% of blank, or 50us left over for prefetch */
449 vblank_time_us = display_config->stream_descriptors[stream_index].timing.vblank_nom *
450 per_stream_pstate_meta[stream_index].otg_vline_time_us;
451 min_unreserved_vblank_time_us = math_min2(vblank_time_us * 0.15, 50);
452
453 /* minmum of blackout time (~2x VActive bandwidth) */
454 min_det_fill_delay_us = per_stream_pstate_meta[stream_index].blackout_otg_vlines *
455 per_stream_pstate_meta[stream_index].otg_vline_time_us;
456
457 extra_time_required_us = disallow_time_us - ideal_disallow_time_us;
458
459 /* try compressing VActive fill first */
460 delta_max_det_fill_delay_us = math_min2(extra_time_required_us * (1.0 - vblank_ratio),
461 math_max2(0.0,
462 per_stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us - min_det_fill_delay_us));
463 delta_max_det_fill_delay_us = math_floor2(delta_max_det_fill_delay_us, per_stream_pstate_meta[stream_index].otg_vline_time_us);
464 extra_time_required_us -= delta_max_det_fill_delay_us;
465
466 /* try reserving VBlank */
467 delta_reserved_vblank_time_us = math_min2(extra_time_required_us,
468 math_max2(0.0,
469 vblank_time_us - per_stream_pstate_meta[stream_index].method_vactive.reserved_vblank_required_us - min_unreserved_vblank_time_us));
470 delta_reserved_vblank_time_us = math_floor2(delta_reserved_vblank_time_us, per_stream_pstate_meta[stream_index].otg_vline_time_us);
471 extra_time_required_us -= delta_reserved_vblank_time_us;
472
473 if (extra_time_required_us > 0.0 &&
474 per_stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us > math_ceil2(delta_max_det_fill_delay_us + extra_time_required_us, per_stream_pstate_meta[stream_index].otg_vline_time_us)) {
475 /* final attempt to compress fill time */
476 delta_max_det_fill_delay_us = delta_max_det_fill_delay_us + extra_time_required_us;
477 delta_max_det_fill_delay_us = math_ceil2(delta_max_det_fill_delay_us, per_stream_pstate_meta[stream_index].otg_vline_time_us);
478 extra_time_required_us = 0.0;
479 }
480 }
481
482 /* Update the worksheet */
483 for (plane_index = 0; plane_index < display_config->num_planes; plane_index++) {
484 if (display_config->plane_descriptors[plane_index].stream_index != stream_index) {
485 continue;
486 }
487
488 max_vactive_det_fill_delay_us = 0;
489 if (worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][pstate_type] > 0.0) {
490 max_vactive_det_fill_delay_us = (int)math_floor(math_min2(
491 (double)worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][pstate_type],
492 per_stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us - delta_max_det_fill_delay_us));
493 } else {
494 max_vactive_det_fill_delay_us = (int)math_floor(
495 per_stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us - delta_max_det_fill_delay_us);
496 }
497
498 reserved_vblank_time_ns = (long)math_max2(
499 (double)worksheet->cur.config.reserved_vblank_time_ns[plane_index],
500 (per_stream_pstate_meta[stream_index].method_vactive.reserved_vblank_required_us + delta_reserved_vblank_time_us) * 1000.0);
501
502 if ((max_vactive_det_fill_delay_us > 0 && worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][pstate_type] == 0) ||
503 max_vactive_det_fill_delay_us < worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][pstate_type] ||
504 (reserved_vblank_time_ns > 0 && worksheet->cur.config.reserved_vblank_time_ns[plane_index] == 0) ||
505 reserved_vblank_time_ns > worksheet->cur.config.reserved_vblank_time_ns[plane_index]) {
506 /* only modify the worksheet if required */
507 worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][pstate_type] = max_vactive_det_fill_delay_us;
508 worksheet->cur.config.reserved_vblank_time_ns[plane_index] = reserved_vblank_time_ns;
509
510 worksheet->cur.unvalidated_change.bits.reserved_vblank_time = true;
511 unvalidated_changes = true;
512 }
513 DML_LOG_DEBUG("worksheet->cur.config.reserved_vblank_time_ns[%d] = %lu\n", plane_index, worksheet->cur.config.reserved_vblank_time_ns[plane_index]);
514 DML_LOG_DEBUG("worksheet->cur.config.max_vactive_det_fill_delay_us[%d] = %u\n", plane_index, worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][pstate_type]);
515 }
516 }
517
518 if (!worksheet->cur.config.fclk_pstate_support
519 || !worksheet->cur.config.ppt_temp_read_support) {
520 worksheet->cur.config.fclk_pstate_support = true;
521 worksheet->cur.config.ppt_temp_read_support = true;
522 worksheet->cur.unvalidated_change.bits.uclk_pstate_method = true;
523 unvalidated_changes = true;
524 }
525
526 return unvalidated_changes;
527 }
528
dcn6_get_vactive_latency_hiding(const struct dml2_validation_result * validation_res,int plane_mask)529 static int dcn6_get_vactive_latency_hiding(const struct dml2_validation_result *validation_res, int plane_mask)
530 {
531 unsigned char i;
532 int min_vactive_latency_hiding_us = 0xFFFFFFF;
533
534 if (!validation_res->is_mode_support_valid)
535 return min_vactive_latency_hiding_us;
536
537 for (i = 0; i < DML2_MAX_PLANES; i++) {
538 if (is_bit_set_in_bitfield(plane_mask, i)) {
539 if (validation_res->mode_support.cfg_support_info.plane_support_info[i].active_latency_hiding_us < min_vactive_latency_hiding_us)
540 min_vactive_latency_hiding_us = validation_res->mode_support.cfg_support_info.plane_support_info[i].active_latency_hiding_us;
541 }
542 }
543
544 return min_vactive_latency_hiding_us;
545 }
546
dcn6_get_vactive_det_fill_delay_us(const struct dml2_validation_result * validation_res,enum dml2_pstate_type pstate_type,int plane_mask)547 static int dcn6_get_vactive_det_fill_delay_us(
548 const struct dml2_validation_result *validation_res,
549 enum dml2_pstate_type pstate_type,
550 int plane_mask)
551 {
552 unsigned int i;
553 int max_vactive_det_fill_delay_us = 0;
554
555 for (i = 0; i < DML2_MAX_PLANES; i++) {
556 if (is_bit_set_in_bitfield(plane_mask, i)) {
557 if (validation_res->mode_support.cfg_support_info.plane_support_info[i].vactive_det_fill_delay_us[pstate_type] > max_vactive_det_fill_delay_us)
558 max_vactive_det_fill_delay_us = validation_res->mode_support.cfg_support_info.plane_support_info[i].vactive_det_fill_delay_us[pstate_type];
559 }
560 }
561
562 return max_vactive_det_fill_delay_us;
563 }
564
dcn6_get_required_vactive_det_fill_delay_us(const struct dml2_optimization_worksheet * worksheet,enum dml2_pstate_type pstate_type,int plane_mask)565 static int dcn6_get_required_vactive_det_fill_delay_us(
566 const struct dml2_optimization_worksheet *worksheet,
567 enum dml2_pstate_type pstate_type,
568 int plane_mask)
569 {
570 unsigned int i;
571 int max_vactive_det_fill_delay_us = 0;
572
573 for (i = 0; i < DML2_MAX_PLANES; i++) {
574 if (is_bit_set_in_bitfield(plane_mask, i)) {
575 if (worksheet->cur.config.max_vactive_det_fill_delay_us[i][pstate_type] > max_vactive_det_fill_delay_us)
576 max_vactive_det_fill_delay_us = worksheet->cur.config.max_vactive_det_fill_delay_us[i][pstate_type];
577 }
578 }
579
580 return max_vactive_det_fill_delay_us;
581 }
582
dcn6_all_timings_support_vactive(struct dml2_pmo_stage_optimizer * stage,const struct dml2_display_cfg * display_config,unsigned int mask)583 static bool dcn6_all_timings_support_vactive(struct dml2_pmo_stage_optimizer *stage,
584 const struct dml2_display_cfg *display_config,
585 unsigned int mask)
586 {
587 struct dml2_stage_optimizer_uclk_pstate_init_locals *s = &stage->func_locals->uclk_pstate_init;
588 unsigned int i;
589 bool valid = true;
590
591 // Create a remap array to enable simple iteration through only masked stream indicies
592 for (i = 0; i < display_config->num_streams; i++) {
593 if (is_bit_set_in_bitfield(mask, i)) {
594 /* check if stream has enough vactive margin, or single display in case blank can also be used */
595 valid &= is_bit_set_in_bitfield(s->stream_vactive_capability_mask, i) ||
596 display_config->num_streams == 1;
597 }
598 }
599
600 return valid;
601 }
602
validate_pstate_support_strategy_cofunctionality(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet,const struct dml2_display_cfg * display_cfg,const struct dml2_pmo_pstate_strategy * pstate_strategy)603 static bool validate_pstate_support_strategy_cofunctionality(struct dml2_pmo_stage_optimizer *stage,
604 struct dml2_optimization_worksheet *worksheet,
605 const struct dml2_display_cfg *display_cfg,
606 const struct dml2_pmo_pstate_strategy *pstate_strategy)
607 {
608 const struct dml2_pmo_instance *pmo = stage->pmo;
609
610 unsigned int stream_index = 0;
611
612 unsigned int drr_count = 0;
613 unsigned int drr_stream_mask = 0;
614 unsigned int vactive_count = 0;
615 unsigned int vactive_stream_mask = 0;
616 unsigned int vblank_count = 0;
617 unsigned int vblank_stream_mask = 0;
618 unsigned int alternate_count = 0;
619 unsigned int alternate_stream_mask = 0;
620
621 bool strategy_matches_forced_requirements = true;
622 bool strategy_matches_drr_requirements = true;
623
624 // Tabulate everything
625 for (stream_index = 0; stream_index < display_cfg->num_streams; stream_index++) {
626
627 if (!all_planes_match_method(display_cfg, worksheet->uclk_pstate.stream_plane_mask[stream_index],
628 pstate_strategy->per_stream_pstate_method[stream_index])) {
629 strategy_matches_forced_requirements = false;
630 break;
631 }
632
633 strategy_matches_drr_requirements &=
634 dcn5_stream_matches_drr_policy(stage, display_cfg, pstate_strategy->per_stream_pstate_method[stream_index], stream_index);
635
636 if (pstate_strategy->per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_drr) {
637 drr_count++;
638 set_bit_in_bitfield(&drr_stream_mask, stream_index);
639 } else if (pstate_strategy->per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive ||
640 pstate_strategy->per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vactive_drr) {
641 vactive_count++;
642 set_bit_in_bitfield(&vactive_stream_mask, stream_index);
643 } else if (pstate_strategy->per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank ||
644 pstate_strategy->per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vblank_drr) {
645 vblank_count++;
646 set_bit_in_bitfield(&vblank_stream_mask, stream_index);
647 } else if (pstate_strategy->per_stream_pstate_method[stream_index] == dml2_pstate_method_alternate) {
648 alternate_count++;
649 set_bit_in_bitfield(&alternate_stream_mask, stream_index);
650 }
651 }
652
653 if (!strategy_matches_forced_requirements || !strategy_matches_drr_requirements)
654 return false;
655
656 if (vactive_count > 0 && !dcn6_all_timings_support_vactive(stage, display_cfg, vactive_stream_mask))
657 return false;
658
659 if (vblank_count > 0 && (pmo->options->disable_vblank || !dcn5_all_timings_support_vblank(stage, display_cfg, vblank_stream_mask)))
660 return false;
661
662 if (drr_count > 0 && (pmo->options->disable_drr_var || !dcn5_all_timings_support_drr(stage, worksheet, display_cfg, drr_stream_mask)))
663 return false;
664
665 if (alternate_count > 0 && pmo->options->disable_alternate_memory_training)
666 return false;
667
668 return dcn6_is_pstate_schedulable(
669 worksheet->uclk_pstate.stream_pstate_meta,
670 display_cfg,
671 pstate_strategy->per_stream_pstate_method,
672 stage->func_locals->uclk_pstate_init.allow_delay_us,
673 &stage->func_locals->uclk_pstate_init.synchronized_timing_groups,
674 &stage->func_locals->uclk_pstate_init.scheduling_check_locals);
675 }
676
dcn6_build_pstate_meta_per_stream(const struct dml2_display_cfg * display_cfg,const struct dml2_ip_capabilities * ip_caps,const struct dml2_optimization_worksheet * worksheet,enum dml2_pstate_type pstate_type,double watermark_us,double blackout_us,double max_allow_delay_us,int stream_index,unsigned int stream_plane_mask,struct dml2_pstate_meta * stream_pstate_meta)677 static void dcn6_build_pstate_meta_per_stream(const struct dml2_display_cfg *display_cfg,
678 const struct dml2_ip_capabilities *ip_caps,
679 const struct dml2_optimization_worksheet *worksheet,
680 enum dml2_pstate_type pstate_type,
681 double watermark_us,
682 double blackout_us,
683 double max_allow_delay_us,
684 int stream_index,
685 unsigned int stream_plane_mask,
686 /* output */
687 struct dml2_pstate_meta *stream_pstate_meta)
688 {
689 const struct dml2_stream_parameters *stream_descriptor = &display_cfg->stream_descriptors[stream_index];
690 const struct dml2_timing_cfg *timing = &stream_descriptor->timing;
691
692 int max_det_fill_delay_otg_vlines;
693 int min_reserved_blank_otg_vlines;
694
695 /* worst case all other streams require some programming at the same time, 0 if only 1 stream */
696 double contention_delay_us = ((double)ip_caps->fams2.vertical_interrupt_ack_delay_us +
697 math_max2(ip_caps->fams2.drr_programming_delay_us, ip_caps->fams2.allow_programming_delay_us)) *
698 (display_cfg->num_streams - 1);
699
700 /* common */
701 stream_pstate_meta->valid = true;
702 stream_pstate_meta->nom_vtotal = stream_descriptor->timing.vblank_nom + stream_descriptor->timing.v_active;
703 stream_pstate_meta->otg_vline_time_us = (double)timing->h_total / timing->pixel_clock_khz * 1000.0;
704 stream_pstate_meta->vblank_start = timing->v_blank_end + timing->v_active;
705 stream_pstate_meta->nom_refresh_rate_hz = timing->pixel_clock_khz * 1000.0 /
706 (stream_pstate_meta->nom_vtotal * timing->h_total);
707 stream_pstate_meta->nom_frame_time_us =
708 (double)stream_pstate_meta->nom_vtotal * stream_pstate_meta->otg_vline_time_us;
709
710 if (stream_descriptor->timing.drr_config.enabled == true) {
711 if (stream_descriptor->timing.drr_config.min_refresh_uhz != 0.0) {
712 stream_pstate_meta->max_vtotal = (int)math_floor((double)stream_descriptor->timing.pixel_clock_khz /
713 ((double)stream_descriptor->timing.drr_config.min_refresh_uhz * stream_descriptor->timing.h_total) * 1e9);
714 } else {
715 /* assume min of 48Hz */
716 stream_pstate_meta->max_vtotal = (int)math_floor((double)stream_descriptor->timing.pixel_clock_khz /
717 (48000000.0 * stream_descriptor->timing.h_total) * 1e9);
718 }
719 } else {
720 stream_pstate_meta->max_vtotal = stream_pstate_meta->nom_vtotal;
721 }
722 stream_pstate_meta->min_refresh_rate_hz = timing->pixel_clock_khz * 1000.0 /
723 (stream_pstate_meta->max_vtotal * timing->h_total);
724 stream_pstate_meta->max_frame_time_us =
725 (double)stream_pstate_meta->max_vtotal * stream_pstate_meta->otg_vline_time_us;
726
727 stream_pstate_meta->scheduling_delay_otg_vlines =
728 (int)math_ceil(ip_caps->fams2.scheduling_delay_us / stream_pstate_meta->otg_vline_time_us);
729 stream_pstate_meta->vertical_interrupt_ack_delay_otg_vlines =
730 (int)math_ceil(ip_caps->fams2.vertical_interrupt_ack_delay_us / stream_pstate_meta->otg_vline_time_us);
731 stream_pstate_meta->contention_delay_otg_vlines =
732 (int)math_ceil(contention_delay_us / stream_pstate_meta->otg_vline_time_us);
733 /* worst case allow to target needs to account for all streams' allow events overlapping, and 1 line for error */
734 stream_pstate_meta->allow_to_target_delay_otg_vlines =
735 (int)(math_ceil((ip_caps->fams2.vertical_interrupt_ack_delay_us + contention_delay_us + ip_caps->fams2.allow_programming_delay_us) / stream_pstate_meta->otg_vline_time_us)) + 1;
736 stream_pstate_meta->min_allow_width_otg_vlines =
737 (int)math_ceil(ip_caps->fams2.min_allow_width_us / stream_pstate_meta->otg_vline_time_us);
738 stream_pstate_meta->blackout_otg_vlines = (int)math_ceil(blackout_us / stream_pstate_meta->otg_vline_time_us);
739 stream_pstate_meta->max_allow_delay_otg_vlines = (int)math_floor((double)max_allow_delay_us / stream_pstate_meta->otg_vline_time_us);
740 if (stream_pstate_meta->max_allow_delay_otg_vlines < 0)
741 stream_pstate_meta->max_allow_delay_otg_vlines = 0;
742 max_det_fill_delay_otg_vlines = (int)math_floor(
743 (double)dcn6_get_required_vactive_det_fill_delay_us(worksheet, pstate_type, stream_plane_mask) /
744 stream_pstate_meta->otg_vline_time_us);
745 min_reserved_blank_otg_vlines = (int)math_ceil(
746 (double)dcn5_get_minimum_reserved_time_us_for_planes(worksheet, stream_plane_mask) /
747 stream_pstate_meta->otg_vline_time_us);
748 stream_pstate_meta->nom_vblank_time_us = stream_descriptor->timing.vblank_nom * stream_pstate_meta->otg_vline_time_us;
749
750 /* scheduling params should be built based on the worst case for allow_time:disallow_time */
751
752 /* vactive */
753 stream_pstate_meta->method_vactive.vactive_latency_hiding_us =
754 (double)dcn6_get_vactive_latency_hiding(&worksheet->validation_result, stream_plane_mask);
755 if (stream_pstate_meta->method_vactive.vactive_latency_hiding_us < watermark_us) {
756 /* achieve single pulse of allow by utilizing blank */
757 stream_pstate_meta->method_vactive.reserved_vblank_required_us =
758 blackout_us -
759 stream_pstate_meta->method_vactive.vactive_latency_hiding_us;
760 stream_pstate_meta->method_vactive.reserved_blank_required_vlines = (int)math_max3(
761 0.0,
762 math_ceil(stream_pstate_meta->method_vactive.reserved_vblank_required_us /
763 stream_pstate_meta->otg_vline_time_us),
764 (double)min_reserved_blank_otg_vlines);
765 } else {
766 /* account for already reserved vblank */
767 stream_pstate_meta->method_vactive.reserved_vblank_required_us =
768 min_reserved_blank_otg_vlines *
769 stream_pstate_meta->otg_vline_time_us;
770 stream_pstate_meta->method_vactive.reserved_blank_required_vlines = min_reserved_blank_otg_vlines;
771 }
772
773 if (display_cfg->num_streams == 1) {
774 /* for single stream, guarantee at least an instant of allow */
775 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines = (int)math_floor(
776 math_max2(0.0,
777 timing->v_active - math_max2(1.0, stream_pstate_meta->min_allow_width_otg_vlines) -
778 (stream_pstate_meta->blackout_otg_vlines -
779 stream_pstate_meta->method_vactive.reserved_blank_required_vlines)));
780 } else {
781 /* for multi stream, bound to a max fill time defined by the parameter */
782 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines =
783 (int)math_floor((double)ip_caps->max_vactive_det_fill_delay_us / stream_pstate_meta->otg_vline_time_us);
784 }
785
786 if (max_det_fill_delay_otg_vlines > 0) {
787 /* consider existing DET fill time enforcement */
788 if (stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines > 0) {
789 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines = (int)math_min2(
790 (double)stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines,
791 (double)max_det_fill_delay_otg_vlines);
792 } else {
793 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines = max_det_fill_delay_otg_vlines;
794 }
795 }
796
797 /* consider max allow delay enforcement */
798 if (stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines > 0) {
799 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines = (int)math_min2(
800 (double)stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines,
801 math_max2(0.0,
802 stream_pstate_meta->max_allow_delay_otg_vlines +
803 stream_pstate_meta->method_vactive.reserved_blank_required_vlines -
804 (int)stream_descriptor->timing.vblank_nom -
805 stream_pstate_meta->blackout_otg_vlines));
806 } else {
807 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines = (int)math_max2(0.0,
808 stream_pstate_meta->max_allow_delay_otg_vlines +
809 stream_pstate_meta->method_vactive.reserved_blank_required_vlines -
810 (int)stream_descriptor->timing.vblank_nom -
811 stream_pstate_meta->blackout_otg_vlines);
812 }
813 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_us =
814 stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines *
815 stream_pstate_meta->otg_vline_time_us;
816
817 if (stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_us > 0.0) {
818 stream_pstate_meta->method_vactive.common.allow_start_otg_vline =
819 timing->v_blank_end + stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_otg_vlines;
820 stream_pstate_meta->method_vactive.common.allow_end_otg_vline =
821 stream_pstate_meta->vblank_start -
822 stream_pstate_meta->blackout_otg_vlines +
823 stream_pstate_meta->method_vactive.reserved_blank_required_vlines;
824 } else {
825 stream_pstate_meta->method_vactive.common.allow_start_otg_vline = 0;
826 stream_pstate_meta->method_vactive.common.allow_end_otg_vline = 0;
827 }
828 stream_pstate_meta->method_vactive.common.period_us = stream_pstate_meta->nom_frame_time_us;
829
830 /* vblank */
831 stream_pstate_meta->method_vblank.common.allow_start_otg_vline = stream_pstate_meta->vblank_start;
832 stream_pstate_meta->method_vblank.common.period_us = stream_pstate_meta->nom_frame_time_us;
833 stream_pstate_meta->method_vblank.common.allow_end_otg_vline =
834 stream_pstate_meta->method_vblank.common.allow_start_otg_vline + 1;
835
836 if (pstate_type == dml2_pstate_type_uclk) {
837 /* alternate */
838 stream_pstate_meta->method_alternate.programming_delay_otg_vlines =
839 (int)math_ceil(ip_caps->fams2.subvp_programming_delay_us / stream_pstate_meta->otg_vline_time_us);
840 stream_pstate_meta->method_alternate.pmfw_throttle_delay_otg_vlines =
841 (int)math_ceil(ip_caps->fams2.subvp_df_throttle_delay_us / stream_pstate_meta->otg_vline_time_us);
842 stream_pstate_meta->method_alternate.common.period_us = stream_pstate_meta->nom_frame_time_us;
843 stream_pstate_meta->method_alternate.common.allow_start_otg_vline = 0;
844 stream_pstate_meta->method_alternate.common.allow_end_otg_vline = stream_pstate_meta->nom_vtotal;
845
846 /* drr */
847 stream_pstate_meta->method_drr.common.period_us = stream_pstate_meta->nom_frame_time_us;
848 stream_pstate_meta->method_drr.programming_delay_otg_vlines =
849 (int)math_ceil(ip_caps->fams2.drr_programming_delay_us / stream_pstate_meta->otg_vline_time_us);
850 stream_pstate_meta->method_drr.common.allow_start_otg_vline =
851 stream_pstate_meta->vblank_start +
852 stream_pstate_meta->allow_to_target_delay_otg_vlines;
853
854 if (display_cfg->num_streams <= 1) {
855 /* only need to stretch vblank for blackout time */
856 stream_pstate_meta->method_drr.stretched_vtotal =
857 stream_pstate_meta->nom_vtotal +
858 stream_pstate_meta->allow_to_target_delay_otg_vlines +
859 stream_pstate_meta->min_allow_width_otg_vlines +
860 stream_pstate_meta->blackout_otg_vlines;
861 } else {
862 /* multi display needs to always be schedulable */
863 stream_pstate_meta->method_drr.stretched_vtotal =
864 stream_pstate_meta->nom_vtotal * 2 +
865 stream_pstate_meta->allow_to_target_delay_otg_vlines +
866 stream_pstate_meta->min_allow_width_otg_vlines +
867 stream_pstate_meta->blackout_otg_vlines;
868 }
869 stream_pstate_meta->method_drr.common.allow_end_otg_vline =
870 stream_pstate_meta->method_drr.stretched_vtotal -
871 stream_pstate_meta->blackout_otg_vlines;
872
873 dcn5_build_method_scheduling_params(&stream_pstate_meta->method_drr.common, stream_pstate_meta);
874 dcn5_build_method_scheduling_params(&stream_pstate_meta->method_alternate.common, stream_pstate_meta);
875 }
876
877 dcn5_build_method_scheduling_params(&stream_pstate_meta->method_vactive.common, stream_pstate_meta);
878 dcn5_build_method_scheduling_params(&stream_pstate_meta->method_vblank.common, stream_pstate_meta);
879 }
880
881
dml2_pmo_dcn6_stage_optimizer_uclk_pstate_init(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)882 static void dml2_pmo_dcn6_stage_optimizer_uclk_pstate_init(
883 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
884 {
885 const struct dml2_pmo_instance *pmo = stage->pmo;
886 struct dml2_stage_optimizer_uclk_pstate_init_locals *s = &stage->func_locals->uclk_pstate_init;
887
888 const struct dml2_display_cfg *display_config = worksheet->orig_dispcfg;
889 const struct dml2_plane_parameters *plane_descriptor;
890 const struct dml2_pmo_pstate_strategy *strategy_list = NULL;
891 struct dml2_pmo_pstate_strategy override_base_strategy = { 0 };
892 unsigned int strategy_list_size = 0;
893 unsigned int plane_index, i;
894 unsigned int stream_index;
895 bool build_override_strategy = true;
896
897 DML_LOG_COMP_IF_ENTER();
898 memset(s, 0, sizeof(struct dml2_stage_optimizer_uclk_pstate_init_locals));
899
900 if (display_config->overrides.all_streams_blanked) {
901 goto exit;
902 }
903
904 // First build the stream plane mask (array of bitfields indexed by stream, indicating plane mapping)
905 for (plane_index = 0; plane_index < display_config->num_planes; plane_index++) {
906 plane_descriptor = &display_config->plane_descriptors[plane_index];
907
908 set_bit_in_bitfield(&worksheet->uclk_pstate.stream_plane_mask[plane_descriptor->stream_index], plane_index);
909
910 build_override_strategy &= plane_descriptor->overrides.uclk_pstate_change_strategy != dml2_uclk_pstate_change_strategy_auto;
911 override_base_strategy.per_stream_pstate_method[plane_descriptor->stream_index] =
912 uclk_pstate_strategy_override_to_pstate_method(plane_descriptor->overrides.uclk_pstate_change_strategy);
913
914 /* Save initial reserved vblank time as pstate optimize may overwrite this value. But
915 * if validation or permissibility fails then we must restore to the original value.
916 */
917 worksheet->uclk_pstate.init_reserved_vblank_time_ns[plane_index] = worksheet->cur.config.reserved_vblank_time_ns[plane_index];
918 }
919
920 dcn6_get_params_for_pstate_type(pmo, worksheet, dml2_pstate_type_uclk, &s->allow_delay_us, &s->blackout_us, &s->watermark_us);
921
922 // Figure out which streams can do vactive, and also build up implicit FAMS2 meta
923 for (stream_index = 0; stream_index < display_config->num_streams; stream_index++) {
924 unsigned int stream_plane_mask = worksheet->uclk_pstate.stream_plane_mask[stream_index];
925 struct dml2_validation_result *validation_result = &worksheet->validation_result;
926
927 if (dcn5_get_vactive_pstate_margin(validation_result, stream_plane_mask) > 0)
928 set_bit_in_bitfield(&s->stream_vactive_capability_mask, stream_index);
929
930 /* pstate meta */
931 dcn6_build_pstate_meta_per_stream(worksheet->orig_dispcfg,
932 pmo->ip_caps,
933 worksheet,
934 dml2_pstate_type_uclk,
935 s->watermark_us,
936 s->blackout_us,
937 s->allow_delay_us,
938 stream_index,
939 stream_plane_mask,
940 &worksheet->uclk_pstate.stream_pstate_meta[stream_index]);
941 }
942
943 /* get synchronized timing groups */
944 dcn5_build_synchronized_timing_groups(&stage->func_locals->uclk_pstate_init.synchronized_timing_groups, display_config);
945
946 if (build_override_strategy) {
947 /* build expanded override strategy list (no permutations) */
948 override_base_strategy.allow_state_increase = true;
949 s->num_expanded_override_strategies = 0;
950 dcn5_insert_strategy_into_expanded_list(&override_base_strategy,
951 display_config->num_streams,
952 s->expanded_override_strategy_list,
953 &s->num_expanded_override_strategies);
954 dcn5_expand_variant_strategy(&override_base_strategy,
955 display_config->num_streams,
956 false,
957 s->expanded_override_strategy_list,
958 &s->num_expanded_override_strategies);
959
960 /* use override strategy list */
961 strategy_list = s->expanded_override_strategy_list;
962 strategy_list_size = s->num_expanded_override_strategies;
963 } else {
964 /* use predefined strategy list */
965 strategy_list = dcn5_get_expanded_strategy_list(stage, display_config->num_streams);
966 strategy_list_size = dcn5_get_num_expanded_strategies(stage, display_config->num_streams);
967 }
968
969 worksheet->uclk_pstate.num_pstate_candidates = 0;
970
971 if (!strategy_list || strategy_list_size == 0)
972 goto exit;
973
974 for (i = 0; i < strategy_list_size && worksheet->uclk_pstate.num_pstate_candidates < DML2_PMO_PSTATE_CANDIDATE_LIST_SIZE; i++) {
975 if (validate_pstate_support_strategy_cofunctionality(stage, worksheet, display_config, &strategy_list[i])) {
976 dcn5_insert_into_candidate_list(&strategy_list[i], display_config->num_streams, worksheet);
977 }
978 }
979
980 if (worksheet->uclk_pstate.num_pstate_candidates > 0) {
981 worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.num_pstate_candidates-1].allow_state_increase = true;
982 worksheet->uclk_pstate.cur_pstate_candidate = -1;
983 goto exit;
984 } else {
985 goto exit;
986 }
987 exit:
988 DML_LOG_COMP_IF_EXIT();
989 }
990
setup_planes_for_alternate_by_mask(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet,int plane_mask)991 static void setup_planes_for_alternate_by_mask(struct dml2_pmo_stage_optimizer *stage,
992 struct dml2_optimization_worksheet *worksheet,
993 int plane_mask)
994 {
995 (void)stage;
996 unsigned int plane_index;
997 const struct dml2_display_cfg *display_config = worksheet->orig_dispcfg;
998
999 for (plane_index = 0; plane_index < display_config->num_planes; plane_index++)
1000 if (is_bit_set_in_bitfield(plane_mask, plane_index))
1001 worksheet->cur.config.uclk_pstate_switch_modes[plane_index] = dml2_pstate_method_alternate;
1002 }
1003
dcn6_setup_planes_for_vactive_by_mask(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet,int plane_mask)1004 static void dcn6_setup_planes_for_vactive_by_mask(struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet, int plane_mask)
1005 {
1006 unsigned int plane_index;
1007 unsigned int stream_index;
1008 const struct dml2_display_cfg *display_config = worksheet->orig_dispcfg;
1009 const struct dml2_pmo_instance *pmo = stage->pmo;
1010
1011 for (plane_index = 0; plane_index < display_config->num_planes; plane_index++) {
1012 if (is_bit_set_in_bitfield(plane_mask, plane_index)) {
1013 stream_index = display_config->plane_descriptors[plane_index].stream_index;
1014
1015 worksheet->cur.config.uclk_pstate_switch_modes[plane_index] = dml2_pstate_method_vactive;
1016
1017 if (!pmo->options->disable_vactive_det_fill_bw_pad) {
1018 if (worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][dml2_pstate_type_uclk] > 0) {
1019 worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][dml2_pstate_type_uclk] = (int)math_min2(
1020 math_floor(worksheet->uclk_pstate.stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us),
1021 worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][dml2_pstate_type_uclk]);
1022 } else {
1023 worksheet->cur.config.max_vactive_det_fill_delay_us[plane_index][dml2_pstate_type_uclk] = (int)math_floor(
1024 worksheet->uclk_pstate.stream_pstate_meta[stream_index].method_vactive.max_vactive_det_fill_delay_us);
1025 }
1026 }
1027
1028 worksheet->cur.config.reserved_vblank_time_ns[plane_index] = (long)math_max2(
1029 worksheet->uclk_pstate.stream_pstate_meta[stream_index].method_vactive.reserved_vblank_required_us * 1000,
1030 worksheet->cur.config.reserved_vblank_time_ns[plane_index]);
1031 }
1032 }
1033 }
1034
setup_optimized_worksheet_for_uclk_pstate(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1035 static bool setup_optimized_worksheet_for_uclk_pstate(struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1036 {
1037 bool fams2_required = false;
1038 bool legacy_pstate_info_for_dmu = false;
1039 bool success = true;
1040 unsigned int stream_index, plane_index;
1041 int strategy_index = worksheet->uclk_pstate.cur_pstate_candidate;
1042 const struct dml2_plane_parameters *plane_descriptor;
1043
1044 for (plane_index = 0; plane_index < worksheet->orig_dispcfg->num_planes; plane_index++) {
1045 plane_descriptor = &worksheet->orig_dispcfg->plane_descriptors[plane_index];
1046 set_bit_in_bitfield(&worksheet->uclk_pstate.stream_plane_mask[plane_descriptor->stream_index], plane_index);
1047 }
1048
1049 for (stream_index = 0; stream_index < worksheet->orig_dispcfg->num_streams; stream_index++) {
1050
1051 if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_na) {
1052 success = false;
1053 break;
1054 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive) {
1055 legacy_pstate_info_for_dmu = true;
1056 dcn6_setup_planes_for_vactive_by_mask(stage, worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]);
1057 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank) {
1058 legacy_pstate_info_for_dmu = true;
1059 dcn5_setup_planes_for_vblank_by_mask(stage, worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]);
1060 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vactive_drr) {
1061 fams2_required = true;
1062 dcn5_setup_planes_for_vactive_drr_by_mask(stage, worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]);
1063 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vblank_drr) {
1064 fams2_required = true;
1065 dcn5_setup_planes_for_vblank_drr_by_mask(stage, worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]);
1066 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_drr) {
1067 fams2_required = true;
1068 dcn5_setup_planes_for_drr_by_mask(stage, worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]);
1069 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[strategy_index].per_stream_pstate_method[stream_index] == dml2_pstate_method_alternate) {
1070 fams2_required = true;
1071 setup_planes_for_alternate_by_mask(stage, worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]);
1072 }
1073 }
1074
1075 /* Indicate if FAMS2 required */
1076 if (success) {
1077 worksheet->cur.config.fams2_required = fams2_required;
1078 worksheet->cur.config.legacy_pstate_info_for_dmu = legacy_pstate_info_for_dmu;
1079 // Copy FAMS2 meta unconditionally - we need for vactive as well
1080 memcpy(&worksheet->cur.config.stream_pstate_meta,
1081 &worksheet->uclk_pstate.stream_pstate_meta,
1082 sizeof(struct dml2_pstate_meta) * DML2_MAX_PLANES);
1083 worksheet->cur.config.uclk_pstate_support = true;
1084 }
1085
1086 return success;
1087 }
1088
dml2_pmo_dcn6_stage_optimizer_uclk_pstate_optimize_next(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1089 static bool dml2_pmo_dcn6_stage_optimizer_uclk_pstate_optimize_next(
1090 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1091 {
1092 bool should_continue = true;
1093
1094 DML_LOG_COMP_IF_ENTER();
1095 /* Nothing to optimize if there are no candidates, so return false */
1096 if (worksheet->uclk_pstate.num_pstate_candidates == 0) {
1097 should_continue = false;
1098 goto exit;
1099 }
1100
1101 /* Optimization is completed if we find a candidate that passed validation and also passes permissibility.
1102 * There are scenarios where permissibility can pass even if validation fails, so we need to check the
1103 * validation result here as well.
1104 */
1105 if (worksheet->validation_result.is_mode_support_valid
1106 && stage->test_permissibility(stage, worksheet) == DML2_STATUS_OK) {
1107 should_continue = false;
1108 goto exit;
1109 }
1110
1111 /* If we've reached the end of the p-state candidate list, return false since
1112 * there's no more potential optimization options */
1113 if (worksheet->uclk_pstate.cur_pstate_candidate == worksheet->uclk_pstate.num_pstate_candidates - 1) {
1114 should_continue = false;
1115 goto exit;
1116 }
1117
1118 /* Reset current settings since the previous optimization attempt did not pass */
1119 dcn5_reset_worksheet_for_uclk_pstate(worksheet);
1120 worksheet->uclk_pstate.cur_pstate_candidate++;
1121 worksheet->cur.unvalidated_change.bits.uclk_pstate_method =
1122 setup_optimized_worksheet_for_uclk_pstate(stage, worksheet);
1123 DML_ASSERT_MSG(worksheet->cur.unvalidated_change.bits.uclk_pstate_method, "optimize_next must apply changes"
1124 " when returning true!\n");
1125
1126 exit:
1127 DML_LOG_DEBUG("%s exit with should_continue = %s\n", __func__, should_continue ? "true" : "false");
1128 DML_LOG_COMP_IF_EXIT();
1129 return should_continue;
1130 }
1131
dcn6_alternate_permissible(const struct dml2_validation_result * validation_res,const struct dml2_pmo_instance * pmo,const struct dml2_display_cfg * display_cfg,int stream_idx)1132 static bool dcn6_alternate_permissible(
1133 const struct dml2_validation_result *validation_res,
1134 const struct dml2_pmo_instance *pmo,
1135 const struct dml2_display_cfg *display_cfg,
1136 int stream_idx)
1137 {
1138 (void)pmo;
1139 unsigned int svp0_dst_lines = validation_res->mode_support.cfg_support_info.stream_support_info[stream_idx].alternate_svp0_dst_lines;
1140 unsigned int svp1_dst_lines = validation_res->mode_support.cfg_support_info.stream_support_info[stream_idx].alternate_svp1_dst_lines;
1141 unsigned int max_dst_y_pre = validation_res->mode_support.cfg_support_info.stream_support_info[stream_idx].max_dst_y_prefetch;
1142 unsigned int max_dst_y_after_scaler = validation_res->mode_support.cfg_support_info.stream_support_info[stream_idx].max_dst_y_after_scaler;
1143 const unsigned int max_hw_cursor_size = 135; // Actual is 128, but set to 135 for margin
1144
1145 // svp0 + svp1 < vtotal - vstartup is required to support alt-chan
1146 // TBD if we need to increase constraint to vtotal - vstartup - cursor_height -> required if last cursor deadline is beyond vblank end
1147 if (svp0_dst_lines + svp1_dst_lines >= display_cfg->stream_descriptors[stream_idx].timing.v_total - max_dst_y_pre - max_dst_y_after_scaler - max_hw_cursor_size)
1148 return false;
1149
1150 return true;
1151 }
1152
dml2_pmo_dcn6_stage_optimizer_uclk_pstate_test_permissibility(struct dml2_pmo_stage_optimizer * stage,const struct dml2_optimization_worksheet * worksheet)1153 static enum dml2_status dml2_pmo_dcn6_stage_optimizer_uclk_pstate_test_permissibility(
1154 struct dml2_pmo_stage_optimizer *stage, const struct dml2_optimization_worksheet *worksheet)
1155 {
1156 enum dml2_status status = DML2_STATUS_OK;
1157 unsigned int stream_index;
1158 const struct dml2_pmo_instance *pmo = stage->pmo;
1159
1160 int REQUIRED_RESERVED_TIME = 0;
1161
1162 DML_LOG_COMP_IF_ENTER();
1163
1164 /* Permissibility passes if all streams are blanked - p-state support is guaranteed for this case*/
1165 if (worksheet->orig_dispcfg->overrides.all_streams_blanked) {
1166 status = DML2_STATUS_OK;
1167 goto exit;
1168 }
1169
1170 /* If there are no pstate candidates then pstate support is false and permissibility fails */
1171 if (worksheet->uclk_pstate.num_pstate_candidates == 0) {
1172 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1173 goto exit;
1174 }
1175
1176 if (worksheet->uclk_pstate.cur_pstate_candidate < 0) {
1177 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1178 goto exit;
1179 }
1180
1181 if (!worksheet->validation_result.mode_support.global.uclk_pstate_supported) {
1182 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1183 goto exit;
1184 }
1185
1186 REQUIRED_RESERVED_TIME = (int)pmo->utm_soc_bb->power_management_parameters.dram_clk_change_blackout_us;
1187
1188 for (stream_index = 0; stream_index < worksheet->orig_dispcfg->num_streams; stream_index++) {
1189 const struct dml2_pstate_meta *stream_pstate_meta = &worksheet->cur.config.stream_pstate_meta[stream_index];
1190
1191 if (worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vactive ||
1192 worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vactive_drr) {
1193 if (worksheet->orig_dispcfg->num_streams == 1) {
1194 /* Peak VActive + VBlank (single stream only) */
1195 if (dcn6_get_vactive_latency_hiding(&worksheet->validation_result, worksheet->uclk_pstate.stream_plane_mask[stream_index]) +
1196 dcn5_get_minimum_reserved_time_us_for_planes(worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME) {
1197 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1198 break;
1199 }
1200 } else if (dcn5_get_vactive_pstate_margin(&worksheet->validation_result, worksheet->uclk_pstate.stream_plane_mask[stream_index]) < 0.0 ||
1201 dcn6_get_vactive_det_fill_delay_us(&worksheet->validation_result, dml2_pstate_type_uclk, worksheet->uclk_pstate.stream_plane_mask[stream_index]) > math_ceil(stream_pstate_meta->method_vactive.max_vactive_det_fill_delay_us)) {
1202 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1203 break;
1204 }
1205 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_vblank ||
1206 worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_vblank_drr) {
1207 if (dcn5_get_minimum_reserved_time_us_for_planes(worksheet, worksheet->uclk_pstate.stream_plane_mask[stream_index]) < REQUIRED_RESERVED_TIME) {
1208 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1209 break;
1210 }
1211 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_fw_drr) {
1212 if (!all_planes_match_method(worksheet->orig_dispcfg, worksheet->uclk_pstate.stream_plane_mask[stream_index], dml2_pstate_method_fw_drr)) {
1213 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1214 break;
1215 }
1216 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_alternate) {
1217 if (!all_planes_match_method(worksheet->orig_dispcfg, worksheet->uclk_pstate.stream_plane_mask[stream_index], dml2_pstate_method_alternate) ||
1218 !dcn6_alternate_permissible(&worksheet->validation_result, pmo, worksheet->orig_dispcfg, stream_index)) {
1219 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1220 break;
1221 }
1222 } else if (worksheet->uclk_pstate.pstate_strategy_candidates[worksheet->uclk_pstate.cur_pstate_candidate].per_stream_pstate_method[stream_index] == dml2_pstate_method_na) {
1223 status = DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE;
1224 break;
1225 }
1226 }
1227 exit:
1228 DML_LOG_DEBUG("%s exit with status = %s\n", __func__, dml2_status_str(status));
1229 DML_LOG_COMP_IF_EXIT();
1230 return status;
1231 }
1232
dml2_pmo_dcn6_stage_optimizer_uclk_pstate_create(struct dml2_pmo_instance * pmo,struct dml2_pmo_stage_optimizer * stage)1233 void dml2_pmo_dcn6_stage_optimizer_uclk_pstate_create(struct dml2_pmo_instance *pmo,
1234 struct dml2_pmo_stage_optimizer *stage)
1235 {
1236 stage->pmo = pmo;
1237 stage->func_locals = &pmo->scratch.pmo_dcn5.func_locals;
1238 stage->init = dml2_pmo_dcn6_stage_optimizer_uclk_pstate_init;
1239 stage->optimize_next = dml2_pmo_dcn6_stage_optimizer_uclk_pstate_optimize_next;
1240 stage->test_permissibility =
1241 dml2_pmo_dcn6_stage_optimizer_uclk_pstate_test_permissibility;
1242 }
1243
1244 /*
1245 * Counts the number of elements inside input array within the given span length.
1246 * Formally, what is the size of the largest subset of the array where the largest and smallest element
1247 * differ no more than the span.
1248 */
count_elements_in_span(const int * array,unsigned int array_size,unsigned int span)1249 static unsigned int count_elements_in_span(const int *array, unsigned int array_size, unsigned int span)
1250 {
1251 unsigned int i;
1252 unsigned int span_start_value;
1253 unsigned int span_start_index;
1254 unsigned int greatest_element_count;
1255
1256 if (array_size == 0)
1257 return 1;
1258
1259 if (span == 0)
1260 return array_size > 0 ? 1 : 0;
1261
1262 span_start_value = 0;
1263 span_start_index = 0;
1264 greatest_element_count = 0;
1265
1266 while (span_start_index < array_size) {
1267 for (i = span_start_index; i < array_size; i++) {
1268 if (array[i] - span_start_value <= span) {
1269 if (i - span_start_index + 1 > greatest_element_count) {
1270 greatest_element_count = i - span_start_index + 1;
1271 }
1272 } else
1273 break;
1274 }
1275
1276 span_start_index++;
1277
1278 if (span_start_index < array_size) {
1279 span_start_value = array[span_start_index - 1] + 1;
1280 }
1281 }
1282
1283 return greatest_element_count;
1284 }
1285
calculate_h_split_for_scaling_transform(int full_vp_width,int h_active,int num_pipes,enum dml2_scaling_transform scaling_transform,int * pipe_vp_x_start,int * pipe_vp_x_end)1286 static bool calculate_h_split_for_scaling_transform(int full_vp_width, int h_active, int num_pipes,
1287 enum dml2_scaling_transform scaling_transform, int *pipe_vp_x_start, int *pipe_vp_x_end)
1288 {
1289 (void)h_active;
1290 int i, slice_width;
1291 const char MAX_SCL_VP_OVERLAP = 3;
1292 bool success = false;
1293
1294 switch (scaling_transform) {
1295 case dml2_scaling_transform_centered:
1296 case dml2_scaling_transform_aspect_ratio:
1297 case dml2_scaling_transform_fullscreen:
1298 slice_width = full_vp_width / num_pipes;
1299 for (i = 0; i < num_pipes; i++) {
1300 pipe_vp_x_start[i] = i * slice_width;
1301 pipe_vp_x_end[i] = (i + 1) * slice_width - 1;
1302
1303 if (pipe_vp_x_start[i] < MAX_SCL_VP_OVERLAP)
1304 pipe_vp_x_start[i] = 0;
1305 else
1306 pipe_vp_x_start[i] -= MAX_SCL_VP_OVERLAP;
1307
1308 if (pipe_vp_x_end[i] > full_vp_width - MAX_SCL_VP_OVERLAP - 1)
1309 pipe_vp_x_end[i] = full_vp_width - 1;
1310 else
1311 pipe_vp_x_end[i] += MAX_SCL_VP_OVERLAP;
1312 }
1313 break;
1314 case dml2_scaling_transform_explicit:
1315 default:
1316 success = false;
1317 break;
1318 }
1319
1320 return success;
1321 }
1322
1323 /*
1324 * Takes an input set of mcache boundaries and finds the appropriate setting of cache programming.
1325 * Returns true if a valid set of programming can be made, and false otherwise. "Valid" means
1326 * that the horizontal viewport does not span more than 2 cache slices.
1327 *
1328 * It optionally also can apply a constant shift to all the cache boundaries.
1329 */
calculate_first_second_splitting(const int * mcache_boundaries,int num_boundaries,int shift,int pipe_h_vp_start,int pipe_h_vp_end,int * first_offset,int * second_offset)1330 static bool calculate_first_second_splitting(const int *mcache_boundaries, int num_boundaries, int shift,
1331 int pipe_h_vp_start, int pipe_h_vp_end, int *first_offset, int *second_offset)
1332 {
1333 const int MAX_VP = 0xFFFFFF;
1334 int left_cache_id;
1335 int right_cache_id;
1336 int range_start;
1337 int range_end;
1338 bool success = false;
1339
1340 if (num_boundaries <= 1) {
1341 if (first_offset && second_offset) {
1342 *first_offset = 0;
1343 *second_offset = -1;
1344 }
1345 success = true;
1346 return success;
1347 } else {
1348 range_start = 0;
1349 for (left_cache_id = 0; left_cache_id < num_boundaries; left_cache_id++) {
1350 range_end = mcache_boundaries[left_cache_id] - shift - 1;
1351
1352 if (range_start <= pipe_h_vp_start && pipe_h_vp_start <= range_end)
1353 break;
1354
1355 range_start = range_end + 1;
1356 }
1357
1358 range_end = MAX_VP;
1359 for (right_cache_id = num_boundaries - 1; right_cache_id >= -1; right_cache_id--) {
1360 if (right_cache_id >= 0)
1361 range_start = mcache_boundaries[right_cache_id] - shift;
1362 else
1363 range_start = 0;
1364
1365 if (range_start <= pipe_h_vp_end && pipe_h_vp_end <= range_end) {
1366 break;
1367 }
1368 range_end = range_start - 1;
1369 }
1370 right_cache_id = (right_cache_id + 1) % num_boundaries;
1371
1372 if (right_cache_id == left_cache_id) {
1373 if (first_offset && second_offset) {
1374 *first_offset = left_cache_id;
1375 *second_offset = -1;
1376 }
1377 success = true;
1378 } else if (right_cache_id == (left_cache_id + 1) % num_boundaries) {
1379 if (first_offset && second_offset) {
1380 *first_offset = left_cache_id;
1381 *second_offset = right_cache_id;
1382 }
1383 success = true;
1384 }
1385 }
1386
1387 return success;
1388 }
1389
1390 /*
1391 * For a given set of pipe start/end x positions, checks to see it can support the input mcache splitting.
1392 * It also attempts to "optimize" by finding a shift if the default 0 shift does not work.
1393 */
find_shift_for_valid_cache_id_assignment(const int * mcache_boundaries,unsigned int num_boundaries,int * pipe_vp_startx,int * pipe_vp_endx,unsigned int pipe_count,int shift_granularity,int * shift)1394 static bool find_shift_for_valid_cache_id_assignment(const int *mcache_boundaries, unsigned int num_boundaries,
1395 int *pipe_vp_startx, int *pipe_vp_endx, unsigned int pipe_count, int shift_granularity, int *shift)
1396 {
1397 int max_shift = 0xFFFF;
1398 unsigned int pipe_index;
1399 unsigned int i, slice_width;
1400 bool success = false;
1401
1402 for (i = 0; i < num_boundaries; i++) {
1403 if (i == 0)
1404 slice_width = mcache_boundaries[i];
1405 else
1406 slice_width = mcache_boundaries[i] - mcache_boundaries[i - 1];
1407
1408 if (max_shift > (int)slice_width) {
1409 max_shift = slice_width;
1410 }
1411 }
1412
1413 for (*shift = 0; *shift <= max_shift; *shift += shift_granularity) {
1414 success = true;
1415 for (pipe_index = 0; pipe_index < pipe_count; pipe_index++) {
1416 if (!calculate_first_second_splitting(mcache_boundaries, num_boundaries, *shift,
1417 pipe_vp_startx[pipe_index], pipe_vp_endx[pipe_index], NULL, NULL)) {
1418 success = false;
1419 break;
1420 }
1421 }
1422 if (success)
1423 break;
1424 }
1425
1426 return success;
1427 }
1428
1429
1430
dml2_pmo_dcn6_stage_optimizer_mcache_decide_shifts(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1431 static void dml2_pmo_dcn6_stage_optimizer_mcache_decide_shifts(struct dml2_pmo_stage_optimizer *stage,
1432 struct dml2_optimization_worksheet *worksheet)
1433 {
1434 (void)stage;
1435 const int MAX_PIXEL_OVERLAP = 6;
1436 int max_per_pipe_vp_p0 = 0;
1437 int max_per_pipe_vp_p1 = 0;
1438 int temp, p0shift, p1shift;
1439 unsigned int plane_index = 0;
1440 unsigned int i;
1441 unsigned int odm_combine_factor;
1442 unsigned int mpc_combine_factor;
1443 unsigned int num_dpps;
1444 unsigned int num_boundaries;
1445 enum dml2_scaling_transform scaling_transform;
1446 const struct dml2_plane_parameters *plane;
1447 const struct dml2_stream_parameters *stream;
1448 const struct dml2_mcache_surface_allocation *base_allocations = worksheet->validation_result.mcache_allocations;
1449 struct dml2_mcache_surface_allocation *new_allocations = worksheet->cur.config.mcache_allocations;
1450 bool p0pass = false;
1451 bool p1pass = false;
1452
1453 for (plane_index = 0; plane_index < worksheet->orig_dispcfg->num_planes; plane_index++) {
1454 if (!worksheet->orig_dispcfg->plane_descriptors[plane_index].surface.dcc.enable)
1455 continue;
1456
1457 plane = &worksheet->orig_dispcfg->plane_descriptors[plane_index];
1458 stream = &worksheet->orig_dispcfg->stream_descriptors[plane->stream_index];
1459
1460 odm_combine_factor = worksheet->cur.config.odm_combine_overrides[plane->stream_index] > 0 ?
1461 worksheet->cur.config.odm_combine_overrides[plane->stream_index] :
1462 worksheet->validation_result.mode_support.cfg_support_info.stream_support_info[plane->stream_index].odms_used;
1463 if (odm_combine_factor == 1) {
1464 mpc_combine_factor = worksheet->cur.config.mpc_combine_overrides[plane_index] > 0 ?
1465 worksheet->cur.config.mpc_combine_overrides[plane_index] :
1466 (unsigned int)worksheet->validation_result.mode_support.cfg_support_info.plane_support_info[plane_index].dpps_used;
1467 num_dpps = mpc_combine_factor;
1468 } else {
1469 mpc_combine_factor = 1;
1470 num_dpps = odm_combine_factor;
1471 }
1472
1473 if (odm_combine_factor > 1) {
1474 max_per_pipe_vp_p0 = plane->surface.plane0.width;
1475 temp = (unsigned int)math_ceil(
1476 plane->composition.scaler_info.plane0.h_ratio * stream->timing.h_active
1477 / odm_combine_factor);
1478 if (temp < max_per_pipe_vp_p0)
1479 max_per_pipe_vp_p0 = temp;
1480
1481 max_per_pipe_vp_p1 = plane->surface.plane1.width;
1482 temp = (unsigned int)math_ceil(
1483 plane->composition.scaler_info.plane1.h_ratio * stream->timing.h_active
1484 / odm_combine_factor);
1485 if (temp < max_per_pipe_vp_p1)
1486 max_per_pipe_vp_p1 = temp;
1487 } else {
1488 max_per_pipe_vp_p0 = plane->surface.plane0.width / mpc_combine_factor;
1489 max_per_pipe_vp_p1 = plane->surface.plane1.width / mpc_combine_factor;
1490 }
1491 max_per_pipe_vp_p0 += 2 * MAX_PIXEL_OVERLAP;
1492 max_per_pipe_vp_p1 += MAX_PIXEL_OVERLAP;
1493 p0shift = 0;
1494 p1shift = 0;
1495 // The last element in the unshifted boundary array will always be the first pixel outside the
1496 // plane, which means theres no mcache associated with it, so -1
1497 num_boundaries =
1498 base_allocations[plane_index].num_mcaches_plane0 == 0 ?
1499 0 : base_allocations[plane_index].num_mcaches_plane0 - 1;
1500 if ((count_elements_in_span(base_allocations[plane_index].mcache_x_offsets_plane0, num_boundaries,
1501 max_per_pipe_vp_p0) <= 1) && (num_boundaries <= num_dpps)) {
1502 p0pass = true;
1503 }
1504 num_boundaries =
1505 base_allocations[plane_index].num_mcaches_plane1 == 0 ?
1506 0 : base_allocations[plane_index].num_mcaches_plane1 - 1;
1507 if ((count_elements_in_span(base_allocations[plane_index].mcache_x_offsets_plane1, num_boundaries,
1508 max_per_pipe_vp_p1) <= 1) && (num_boundaries <= num_dpps)) {
1509 p1pass = true;
1510 }
1511 if (!p0pass || !p1pass) {
1512 if (odm_combine_factor > 1) {
1513 num_dpps = odm_combine_factor;
1514 scaling_transform = plane->composition.scaling_transform;
1515 } else {
1516 num_dpps = mpc_combine_factor;
1517 scaling_transform = dml2_scaling_transform_fullscreen;
1518 }
1519 if (!p0pass) {
1520 if (plane->composition.viewport.stationary) {
1521 calculate_h_split_for_scaling_transform(plane->surface.plane0.width,
1522 stream->timing.h_active, num_dpps, scaling_transform,
1523 &worksheet->mcache.plane0.pipe_vp_startx[plane_index],
1524 &worksheet->mcache.plane0.pipe_vp_endx[plane_index]);
1525 p0pass = find_shift_for_valid_cache_id_assignment(
1526 base_allocations[plane_index].mcache_x_offsets_plane0,
1527 base_allocations[plane_index].num_mcaches_plane0,
1528 &worksheet->mcache.plane0.pipe_vp_startx[plane_index],
1529 &worksheet->mcache.plane0.pipe_vp_endx[plane_index], num_dpps,
1530 base_allocations[plane_index].shift_granularity.p0, &p0shift);
1531 }
1532 }
1533 if (!p1pass) {
1534 if (plane->composition.viewport.stationary) {
1535 calculate_h_split_for_scaling_transform(plane->surface.plane1.width,
1536 stream->timing.h_active, num_dpps, scaling_transform,
1537 &worksheet->mcache.plane0.pipe_vp_startx[plane_index],
1538 &worksheet->mcache.plane0.pipe_vp_endx[plane_index]);
1539 p1pass = find_shift_for_valid_cache_id_assignment(
1540 base_allocations[plane_index].mcache_x_offsets_plane1,
1541 base_allocations[plane_index].num_mcaches_plane1,
1542 &worksheet->mcache.plane1.pipe_vp_startx[plane_index],
1543 &worksheet->mcache.plane1.pipe_vp_endx[plane_index], num_dpps,
1544 base_allocations[plane_index].shift_granularity.p1, &p1shift);
1545 }
1546 }
1547 }
1548 if (p0pass && p1pass) {
1549 for (i = 0; i < base_allocations[plane_index].num_mcaches_plane0; i++)
1550 new_allocations[plane_index].mcache_x_offsets_plane0[i] =
1551 base_allocations[plane_index].mcache_x_offsets_plane0[i] - p0shift;
1552 for (i = 0; i < base_allocations[plane_index].num_mcaches_plane1; i++)
1553 new_allocations[plane_index].mcache_x_offsets_plane1[i] =
1554 base_allocations[plane_index].mcache_x_offsets_plane1[i] - p1shift;
1555 }
1556 worksheet->mcache.per_plane_status[plane_index] = p0pass && p1pass;
1557 }
1558 }
1559
dml2_pmo_dcn6_stage_optimizer_mcache_test_permissibility(struct dml2_pmo_stage_optimizer * stage,const struct dml2_optimization_worksheet * worksheet)1560 static enum dml2_status dml2_pmo_dcn6_stage_optimizer_mcache_test_permissibility(
1561 struct dml2_pmo_stage_optimizer *stage, const struct dml2_optimization_worksheet *worksheet)
1562 {
1563 if (!dml2_pmo_dcn5_stage_optimizer_mcache_test_total_mcache_limit(stage, worksheet))
1564 return DML2_STATUS_OPTIMIZE_FAIL_MCACHE;
1565
1566 if (!dml2_pmo_dcn5_stage_optimizer_mcache_test_mcache_status(stage, worksheet))
1567 return DML2_STATUS_OPTIMIZE_FAIL_MCACHE;
1568
1569 return DML2_STATUS_OK;
1570 }
1571
dml2_pmo_dcn6_stage_optimizer_mcache_optimize_next(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1572 static bool dml2_pmo_dcn6_stage_optimizer_mcache_optimize_next(
1573 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1574 {
1575 if (!worksheet->validation_result.is_mode_support_valid
1576 || !worksheet->validation_result.is_mcache_allocation_valid)
1577 /* validation has failed, stop optimizing further */
1578 return false;
1579
1580 if (stage->test_permissibility(stage, worksheet) == DML2_STATUS_OK)
1581 /* optimization is permissible, no need to optimize further */
1582 return false;
1583
1584 if (worksheet->mcache.is_default_pipe_usage_attempted) {
1585 if (!dml2_pmo_dcn5_stage_optimizer_mcache_increment_pipe_usage(stage, worksheet))
1586 return false;
1587 } else {
1588 dml2_pmo_dcn5_stage_optimizer_mcache_apply_default_pipe_usage(stage, worksheet);
1589 worksheet->mcache.is_default_pipe_usage_attempted = true;
1590 }
1591
1592 dml2_pmo_dcn6_stage_optimizer_mcache_decide_shifts(stage, worksheet);
1593 worksheet->cur.unvalidated_change.bits.mcache_allocation = true;
1594
1595 return true;
1596 }
1597
dml2_pmo_dcn6_stage_optimizer_mcache_create(struct dml2_pmo_instance * pmo,struct dml2_pmo_stage_optimizer * stage)1598 void dml2_pmo_dcn6_stage_optimizer_mcache_create(struct dml2_pmo_instance *pmo,
1599 struct dml2_pmo_stage_optimizer *stage)
1600 {
1601 stage->pmo = pmo;
1602 stage->func_locals = &pmo->scratch.pmo_dcn5.func_locals;
1603 stage->init = dml2_pmo_dcn5_stage_optimizer_mcache_init;
1604 stage->optimize_next = dml2_pmo_dcn6_stage_optimizer_mcache_optimize_next;
1605 stage->test_permissibility =
1606 dml2_pmo_dcn6_stage_optimizer_mcache_test_permissibility;
1607 }
1608
dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_init(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1609 static void dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_init(
1610 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1611 {
1612 const struct dml2_utm_soc_bb *utm_soc_bb = stage->pmo->utm_soc_bb;
1613
1614 DML_LOG_COMP_IF_ENTER();
1615 worksheet->dcfclk_vmin.max_available_bandwidth_kbps =
1616 utm_soc_bb->vmin_limit.dcfclk_khz * utm_soc_bb->return_bus_width_bytes;
1617 DML_LOG_COMP_IF_EXIT();
1618 }
1619
dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_optimize_next(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1620 static bool dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_optimize_next(
1621 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1622 {
1623 bool should_continue = true;
1624 const struct dml2_utm_soc_bb *utm_soc_bb = stage->pmo->utm_soc_bb;
1625 const struct dml2_sop_table *sop_table = &utm_soc_bb->sop_table;
1626
1627 DML_LOG_COMP_IF_ENTER();
1628 if (utm_soc_bb->vmin_limit.dcfclk_khz == 0) {
1629 /* vmin limit for dcfclk is not configured in soc bb */
1630 should_continue = false;
1631 goto exit;
1632 }
1633
1634 if (worksheet->cur.config.enable_vmin_dcfclk) {
1635 /* vmin dcfclk is already enabled, nothing else to try */
1636 should_continue = false;
1637 goto exit;
1638 }
1639
1640 if (sop_table->sop_optimal_dcfclks_khz[worksheet->cur.config.min_sop_index] <= utm_soc_bb->vmin_limit.dcfclk_khz) {
1641 /* current sop optimal dcfclk is already less than vmin dcfclk */
1642 should_continue = false;
1643 goto exit;
1644 }
1645 if (worksheet->validation_result.mode_support.bandwidth_upper_bound.dcn5.urgent_bandwidth_kbps
1646 > worksheet->dcfclk_vmin.max_available_bandwidth_kbps) {
1647 /*
1648 * required urgent bandwidth exceeds max bandwidth available, reducing dcfclk will only increase
1649 * bandwidth requirements even more. It is guaranteed to fail bandwidth validation. No need to attempt.
1650 */
1651 should_continue = false;
1652 goto exit;
1653 }
1654
1655 worksheet->cur.unvalidated_change.bits.dcfclk_override = true;
1656 worksheet->cur.config.enable_vmin_dcfclk = true;
1657 exit:
1658 DML_LOG_DEBUG("%s exit with should_continue = %s\n", __func__, should_continue ? "true" : "false");
1659 DML_LOG_COMP_IF_EXIT();
1660 return should_continue;
1661 }
1662
dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_test_permissibility(struct dml2_pmo_stage_optimizer * stage,const struct dml2_optimization_worksheet * worksheet)1663 static enum dml2_status dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_test_permissibility(
1664 struct dml2_pmo_stage_optimizer *stage, const struct dml2_optimization_worksheet *worksheet)
1665 {
1666 (void)stage;
1667 enum dml2_status status = worksheet->cur.config.enable_vmin_dcfclk ?
1668 DML2_STATUS_OK : DML2_STATUS_OPTIMIZE_FAIL_VMIN_DCFCLK;
1669
1670 DML_LOG_COMP_IF_ENTER();
1671 DML_LOG_DEBUG("%s exit with status = %s\n", __func__, dml2_status_str(status));
1672 DML_LOG_COMP_IF_EXIT();
1673 return status;
1674 }
1675
dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_create(struct dml2_pmo_instance * pmo,struct dml2_pmo_stage_optimizer * stage)1676 void dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_create(struct dml2_pmo_instance *pmo,
1677 struct dml2_pmo_stage_optimizer *stage)
1678 {
1679 stage->pmo = pmo;
1680 stage->func_locals = &pmo->scratch.pmo_dcn5.func_locals;
1681 stage->init = dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_init;
1682 stage->optimize_next = dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_optimize_next;
1683 stage->test_permissibility =
1684 dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_test_permissibility;
1685 }
1686
dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_init(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1687 static void dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_init(
1688 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1689 {
1690 DML_LOG_COMP_IF_ENTER();
1691 worksheet->fclk_ppt_temp_read_pstate.is_attempted = false;
1692 memset(&stage->func_locals->fclk_ppt_temp_read_pstate_optimize, 0,
1693 sizeof(struct dml2_stage_optimizer_fclk_ppt_temp_read_pstate_optimize_locals));
1694 DML_LOG_COMP_IF_EXIT();
1695 }
1696
dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_optimize_next(struct dml2_pmo_stage_optimizer * stage,struct dml2_optimization_worksheet * worksheet)1697 static bool dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_optimize_next(
1698 struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet)
1699 {
1700 const struct dml2_pmo_instance *pmo = stage->pmo;
1701 const enum dml2_pstate_type pstate_type_list[3] = {
1702 dml2_pstate_type_fclk,
1703 dml2_pstate_type_ppt,
1704 dml2_pstate_type_temp_read,
1705 };
1706 struct dml2_stage_optimizer_fclk_ppt_temp_read_pstate_optimize_locals *l
1707 = &stage->func_locals->fclk_ppt_temp_read_pstate_optimize;
1708 const struct dml2_display_cfg *display_config = worksheet->orig_dispcfg;
1709 unsigned int stream_index, plane_index, plane_mask;
1710 unsigned int i;
1711 bool modified = false;
1712
1713 DML_LOG_COMP_IF_ENTER();
1714
1715 if (worksheet->fclk_ppt_temp_read_pstate.is_attempted) {
1716 DML_LOG_COMP_IF_EXIT();
1717 return false;
1718 }
1719
1720 worksheet->fclk_ppt_temp_read_pstate.is_attempted = true;
1721
1722 if (display_config->overrides.all_streams_blanked)
1723 goto exit;
1724
1725 for (i = 0; i < 3; i++) {
1726 dcn6_get_params_for_pstate_type(pmo, worksheet,
1727 pstate_type_list[i],
1728 &l->pstate_allow_delay_us,
1729 &l->pstate_blackout_us,
1730 &l->pstate_watermark_us);
1731
1732 if (l->pstate_blackout_us <= 0.0)
1733 continue;
1734
1735 for (stream_index = 0; stream_index < display_config->num_streams; stream_index++) {
1736 plane_mask = 0;
1737 for (plane_index = 0; plane_index < display_config->num_planes; plane_index++) {
1738 if (display_config->plane_descriptors[plane_index].stream_index == stream_index)
1739 set_bit_in_bitfield(&plane_mask, plane_index);
1740 }
1741
1742 l->per_stream_pstate_method[stream_index] = dml2_pstate_method_vactive;
1743
1744 dcn6_build_pstate_meta_per_stream(display_config,
1745 pmo->ip_caps,
1746 worksheet,
1747 pstate_type_list[i],
1748 l->pstate_watermark_us,
1749 l->pstate_blackout_us,
1750 l->pstate_allow_delay_us,
1751 stream_index,
1752 plane_mask,
1753 &l->per_stream_pstate_meta[stream_index]);
1754 }
1755
1756 /* always update the worksheet with latest requirements */
1757 if (dcn6_update_worksheet_for_pstate_admissibility(worksheet,
1758 l->per_stream_pstate_meta, pstate_type_list[i])) {
1759 modified = true;
1760 DML_LOG_VERBOSE("fclk_ppt_temp_read pstate not admissible with current worksheet, adjusting the reserved vblank time\n");
1761 }
1762 }
1763
1764 exit:
1765 DML_LOG_DEBUG("%s exit with should_continue = %s\n", __func__, modified ? "true" : "false");
1766 DML_LOG_COMP_IF_EXIT();
1767 return modified;
1768 }
1769
dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_test_permissibility(struct dml2_pmo_stage_optimizer * stage,const struct dml2_optimization_worksheet * worksheet)1770 static enum dml2_status dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_test_permissibility(
1771 struct dml2_pmo_stage_optimizer *stage, const struct dml2_optimization_worksheet *worksheet)
1772 {
1773 (void)stage;
1774 (void)worksheet;
1775 DML_LOG_COMP_IF_ENTER();
1776 DML_LOG_COMP_IF_EXIT();
1777 return DML2_STATUS_OK;
1778 }
1779
dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_create(struct dml2_pmo_instance * pmo,struct dml2_pmo_stage_optimizer * stage)1780 void dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_create(struct dml2_pmo_instance *pmo,
1781 struct dml2_pmo_stage_optimizer *stage)
1782 {
1783 stage->pmo = pmo;
1784 stage->func_locals = &pmo->scratch.pmo_dcn5.func_locals;
1785 stage->init = dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_init;
1786 stage->optimize_next = dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_optimize_next;
1787 stage->test_permissibility =
1788 dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_test_permissibility;
1789 }
1790