xref: /linux/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_top/dml2_top_soc15.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "dml2_top_soc15.h"
6 #include "dml2_mcg_factory.h"
7 #include "dml2_dpmm_factory.h"
8 #include "dml2_core_factory.h"
9 #include "dml2_pmo_factory.h"
10 #include "lib_float_math.h"
11 #include "dml2_debug.h"
setup_unoptimized_display_config_with_meta(const struct dml2_instance * dml,struct display_configuation_with_meta * out,const struct dml2_display_cfg * display_config)12 static void setup_unoptimized_display_config_with_meta(const struct dml2_instance *dml, struct display_configuation_with_meta *out, const struct dml2_display_cfg *display_config)
13 {
14 	memcpy(&out->display_config, display_config, sizeof(struct dml2_display_cfg));
15 	out->stage1.min_clk_index_for_latency = dml->min_clk_table.dram_bw_table.num_entries - 1; //dml->min_clk_table.clean_me_up.soc_bb.num_states - 1;
16 }
17 
setup_speculative_display_config_with_meta(const struct dml2_instance * dml,struct display_configuation_with_meta * out,const struct dml2_display_cfg * display_config)18 static void setup_speculative_display_config_with_meta(const struct dml2_instance *dml, struct display_configuation_with_meta *out, const struct dml2_display_cfg *display_config)
19 {
20 	memcpy(&out->display_config, display_config, sizeof(struct dml2_display_cfg));
21 	out->stage1.min_clk_index_for_latency = 0;
22 }
23 
copy_display_configuration_with_meta(struct display_configuation_with_meta * dst,const struct display_configuation_with_meta * src)24 static void copy_display_configuration_with_meta(struct display_configuation_with_meta *dst, const struct display_configuation_with_meta *src)
25 {
26 	memcpy(dst, src, sizeof(struct display_configuation_with_meta));
27 }
28 
dml2_top_optimization_init_function_min_clk_for_latency(const struct optimization_init_function_params * params)29 static bool dml2_top_optimization_init_function_min_clk_for_latency(const struct optimization_init_function_params *params)
30 {
31 	struct dml2_optimization_stage1_state *state = &params->display_config->stage1;
32 
33 	state->performed = true;
34 
35 	return true;
36 }
37 
dml2_top_optimization_test_function_min_clk_for_latency(const struct optimization_test_function_params * params)38 static bool dml2_top_optimization_test_function_min_clk_for_latency(const struct optimization_test_function_params *params)
39 {
40 	struct dml2_optimization_stage1_state *state = &params->display_config->stage1;
41 
42 	return state->min_clk_index_for_latency == 0;
43 }
44 
dml2_top_optimization_optimize_function_min_clk_for_latency(const struct optimization_optimize_function_params * params)45 static bool dml2_top_optimization_optimize_function_min_clk_for_latency(const struct optimization_optimize_function_params *params)
46 {
47 	bool result = false;
48 
49 	if (params->display_config->stage1.min_clk_index_for_latency > 0) {
50 		copy_display_configuration_with_meta(params->optimized_display_config, params->display_config);
51 		params->optimized_display_config->stage1.min_clk_index_for_latency--;
52 		result = true;
53 	}
54 
55 	return result;
56 }
57 
dml2_top_optimization_test_function_mcache(const struct optimization_test_function_params * params)58 static bool dml2_top_optimization_test_function_mcache(const struct optimization_test_function_params *params)
59 {
60 	struct dml2_optimization_test_function_locals *l = params->locals;
61 	bool mcache_success = false;
62 	bool result = false;
63 
64 	memset(l, 0, sizeof(struct dml2_optimization_test_function_locals));
65 
66 	l->test_mcache.calc_mcache_count_params.dml2_instance = params->dml;
67 	l->test_mcache.calc_mcache_count_params.display_config = &params->display_config->display_config;
68 	l->test_mcache.calc_mcache_count_params.mcache_allocations = params->display_config->stage2.mcache_allocations;
69 
70 	result = dml2_top_mcache_calc_mcache_count_and_offsets(&l->test_mcache.calc_mcache_count_params); // use core to get the basic mcache_allocations
71 
72 	if (result) {
73 		l->test_mcache.assign_global_mcache_ids_params.allocations = params->display_config->stage2.mcache_allocations;
74 		l->test_mcache.assign_global_mcache_ids_params.num_allocations = params->display_config->display_config.num_planes;
75 
76 		dml2_top_mcache_assign_global_mcache_ids(&l->test_mcache.assign_global_mcache_ids_params);
77 
78 		l->test_mcache.validate_admissibility_params.dml2_instance = params->dml;
79 		l->test_mcache.validate_admissibility_params.display_cfg = &params->display_config->display_config;
80 		l->test_mcache.validate_admissibility_params.mcache_allocations = params->display_config->stage2.mcache_allocations;
81 		l->test_mcache.validate_admissibility_params.cfg_support_info = &params->display_config->mode_support_result.cfg_support_info;
82 
83 		mcache_success = dml2_top_mcache_validate_admissability(&l->test_mcache.validate_admissibility_params); // also find the shift to make mcache allocation works
84 
85 		memcpy(params->display_config->stage2.per_plane_mcache_support, l->test_mcache.validate_admissibility_params.per_plane_status, sizeof(bool) * DML2_MAX_PLANES);
86 	}
87 
88 	return mcache_success;
89 }
90 
dml2_top_optimization_optimize_function_mcache(const struct optimization_optimize_function_params * params)91 static bool dml2_top_optimization_optimize_function_mcache(const struct optimization_optimize_function_params *params)
92 {
93 	struct dml2_optimization_optimize_function_locals *l = params->locals;
94 	bool optimize_success = false;
95 
96 	if (params->last_candidate_supported == false)
97 		return false;
98 
99 	copy_display_configuration_with_meta(params->optimized_display_config, params->display_config);
100 
101 	l->optimize_mcache.optimize_mcache_params.instance = &params->dml->pmo_instance;
102 	l->optimize_mcache.optimize_mcache_params.dcc_mcache_supported = params->display_config->stage2.per_plane_mcache_support;
103 	l->optimize_mcache.optimize_mcache_params.display_config = &params->display_config->display_config;
104 	l->optimize_mcache.optimize_mcache_params.optimized_display_cfg = &params->optimized_display_config->display_config;
105 	l->optimize_mcache.optimize_mcache_params.cfg_support_info = &params->optimized_display_config->mode_support_result.cfg_support_info;
106 
107 	optimize_success = params->dml->pmo_instance.optimize_dcc_mcache(&l->optimize_mcache.optimize_mcache_params);
108 
109 	return optimize_success;
110 }
111 
dml2_top_optimization_init_function_vmin(const struct optimization_init_function_params * params)112 static bool dml2_top_optimization_init_function_vmin(const struct optimization_init_function_params *params)
113 {
114 	struct dml2_optimization_init_function_locals *l = params->locals;
115 
116 	l->vmin.init_params.instance = &params->dml->pmo_instance;
117 	l->vmin.init_params.base_display_config = params->display_config;
118 	return params->dml->pmo_instance.init_for_vmin(&l->vmin.init_params);
119 }
120 
dml2_top_optimization_test_function_vmin(const struct optimization_test_function_params * params)121 static bool dml2_top_optimization_test_function_vmin(const struct optimization_test_function_params *params)
122 {
123 	struct dml2_optimization_test_function_locals *l = params->locals;
124 
125 	l->test_vmin.pmo_test_vmin_params.instance = &params->dml->pmo_instance;
126 	l->test_vmin.pmo_test_vmin_params.display_config = params->display_config;
127 	l->test_vmin.pmo_test_vmin_params.vmin_limits = &params->dml->soc_bbox.vmin_limit;
128 	return params->dml->pmo_instance.test_for_vmin(&l->test_vmin.pmo_test_vmin_params);
129 }
130 
dml2_top_optimization_optimize_function_vmin(const struct optimization_optimize_function_params * params)131 static bool dml2_top_optimization_optimize_function_vmin(const struct optimization_optimize_function_params *params)
132 {
133 	struct dml2_optimization_optimize_function_locals *l = params->locals;
134 
135 	if (params->last_candidate_supported == false)
136 		return false;
137 
138 	l->optimize_vmin.pmo_optimize_vmin_params.instance = &params->dml->pmo_instance;
139 	l->optimize_vmin.pmo_optimize_vmin_params.base_display_config = params->display_config;
140 	l->optimize_vmin.pmo_optimize_vmin_params.optimized_display_config = params->optimized_display_config;
141 	return params->dml->pmo_instance.optimize_for_vmin(&l->optimize_vmin.pmo_optimize_vmin_params);
142 }
143 
dml2_top_optimization_init_function_uclk_pstate(const struct optimization_init_function_params * params)144 static bool dml2_top_optimization_init_function_uclk_pstate(const struct optimization_init_function_params *params)
145 {
146 	struct dml2_optimization_init_function_locals *l = params->locals;
147 
148 	l->uclk_pstate.init_params.instance = &params->dml->pmo_instance;
149 	l->uclk_pstate.init_params.base_display_config = params->display_config;
150 
151 	return params->dml->pmo_instance.init_for_uclk_pstate(&l->uclk_pstate.init_params);
152 }
153 
dml2_top_optimization_test_function_uclk_pstate(const struct optimization_test_function_params * params)154 static bool dml2_top_optimization_test_function_uclk_pstate(const struct optimization_test_function_params *params)
155 {
156 	struct dml2_optimization_test_function_locals *l = params->locals;
157 
158 	l->uclk_pstate.test_params.instance = &params->dml->pmo_instance;
159 	l->uclk_pstate.test_params.base_display_config = params->display_config;
160 
161 	return params->dml->pmo_instance.test_for_uclk_pstate(&l->uclk_pstate.test_params);
162 }
163 
dml2_top_optimization_optimize_function_uclk_pstate(const struct optimization_optimize_function_params * params)164 static bool dml2_top_optimization_optimize_function_uclk_pstate(const struct optimization_optimize_function_params *params)
165 {
166 	struct dml2_optimization_optimize_function_locals *l = params->locals;
167 
168 	l->uclk_pstate.optimize_params.instance = &params->dml->pmo_instance;
169 	l->uclk_pstate.optimize_params.base_display_config = params->display_config;
170 	l->uclk_pstate.optimize_params.optimized_display_config = params->optimized_display_config;
171 	l->uclk_pstate.optimize_params.last_candidate_failed = !params->last_candidate_supported;
172 
173 	return params->dml->pmo_instance.optimize_for_uclk_pstate(&l->uclk_pstate.optimize_params);
174 }
175 
dml2_top_optimization_init_function_stutter(const struct optimization_init_function_params * params)176 static bool dml2_top_optimization_init_function_stutter(const struct optimization_init_function_params *params)
177 {
178 	struct dml2_optimization_init_function_locals *l = params->locals;
179 
180 	l->uclk_pstate.init_params.instance = &params->dml->pmo_instance;
181 	l->uclk_pstate.init_params.base_display_config = params->display_config;
182 
183 	return params->dml->pmo_instance.init_for_stutter(&l->stutter.stutter_params);
184 }
185 
dml2_top_optimization_test_function_stutter(const struct optimization_test_function_params * params)186 static bool dml2_top_optimization_test_function_stutter(const struct optimization_test_function_params *params)
187 {
188 	struct dml2_optimization_test_function_locals *l = params->locals;
189 
190 	l->stutter.stutter_params.instance = &params->dml->pmo_instance;
191 	l->stutter.stutter_params.base_display_config = params->display_config;
192 	return params->dml->pmo_instance.test_for_stutter(&l->stutter.stutter_params);
193 }
194 
dml2_top_optimization_optimize_function_stutter(const struct optimization_optimize_function_params * params)195 static bool dml2_top_optimization_optimize_function_stutter(const struct optimization_optimize_function_params *params)
196 {
197 	struct dml2_optimization_optimize_function_locals *l = params->locals;
198 
199 	l->stutter.stutter_params.instance = &params->dml->pmo_instance;
200 	l->stutter.stutter_params.base_display_config = params->display_config;
201 	l->stutter.stutter_params.optimized_display_config = params->optimized_display_config;
202 	l->stutter.stutter_params.last_candidate_failed = !params->last_candidate_supported;
203 	return params->dml->pmo_instance.optimize_for_stutter(&l->stutter.stutter_params);
204 }
205 
dml2_top_optimization_perform_optimization_phase(struct dml2_optimization_phase_locals * l,const struct optimization_phase_params * params)206 static bool dml2_top_optimization_perform_optimization_phase(struct dml2_optimization_phase_locals *l, const struct optimization_phase_params *params)
207 {
208 	bool test_passed = false;
209 	bool optimize_succeeded = true;
210 	bool candidate_validation_passed = true;
211 	struct optimization_init_function_params init_params = { 0 };
212 	struct optimization_test_function_params test_params = { 0 };
213 	struct optimization_optimize_function_params optimize_params = { 0 };
214 
215 	if (!params->dml ||
216 		!params->optimize_function ||
217 		!params->test_function ||
218 		!params->display_config ||
219 		!params->optimized_display_config)
220 		return false;
221 
222 	copy_display_configuration_with_meta(&l->cur_candidate_display_cfg, params->display_config);
223 
224 	init_params.locals = &l->init_function_locals;
225 	init_params.dml = params->dml;
226 	init_params.display_config = &l->cur_candidate_display_cfg;
227 
228 	if (params->init_function && !params->init_function(&init_params))
229 		return false;
230 
231 	test_params.locals = &l->test_function_locals;
232 	test_params.dml = params->dml;
233 	test_params.display_config = &l->cur_candidate_display_cfg;
234 
235 	test_passed = params->test_function(&test_params);
236 
237 	while (!test_passed && optimize_succeeded) {
238 		memset(&optimize_params, 0, sizeof(struct optimization_optimize_function_params));
239 
240 		optimize_params.locals = &l->optimize_function_locals;
241 		optimize_params.dml = params->dml;
242 		optimize_params.display_config = &l->cur_candidate_display_cfg;
243 		optimize_params.optimized_display_config = &l->next_candidate_display_cfg;
244 		optimize_params.last_candidate_supported = candidate_validation_passed;
245 
246 		optimize_succeeded = params->optimize_function(&optimize_params);
247 
248 		if (optimize_succeeded) {
249 			l->mode_support_params.instance = &params->dml->core_instance;
250 			l->mode_support_params.display_cfg = &l->next_candidate_display_cfg;
251 			l->mode_support_params.min_clk_table = &params->dml->min_clk_table;
252 
253 			if (l->next_candidate_display_cfg.stage3.performed)
254 				l->mode_support_params.min_clk_index = l->next_candidate_display_cfg.stage3.min_clk_index_for_latency;
255 			else
256 				l->mode_support_params.min_clk_index = l->next_candidate_display_cfg.stage1.min_clk_index_for_latency;
257 			candidate_validation_passed = params->dml->core_instance.mode_support(&l->mode_support_params);
258 			l->next_candidate_display_cfg.mode_support_result = l->mode_support_params.mode_support_result;
259 		}
260 
261 		if (optimize_succeeded && candidate_validation_passed) {
262 			memset(&test_params, 0, sizeof(struct optimization_test_function_params));
263 			test_params.locals = &l->test_function_locals;
264 			test_params.dml = params->dml;
265 			test_params.display_config = &l->next_candidate_display_cfg;
266 			test_passed = params->test_function(&test_params);
267 
268 			copy_display_configuration_with_meta(&l->cur_candidate_display_cfg, &l->next_candidate_display_cfg);
269 
270 			// If optimization is not all or nothing, then store partial progress in output
271 			if (!params->all_or_nothing)
272 				copy_display_configuration_with_meta(params->optimized_display_config, &l->next_candidate_display_cfg);
273 		}
274 	}
275 
276 	if (test_passed)
277 		copy_display_configuration_with_meta(params->optimized_display_config, &l->cur_candidate_display_cfg);
278 
279 	return test_passed;
280 }
281 
dml2_top_optimization_perform_optimization_phase_1(struct dml2_optimization_phase_locals * l,const struct optimization_phase_params * params)282 static bool dml2_top_optimization_perform_optimization_phase_1(struct dml2_optimization_phase_locals *l, const struct optimization_phase_params *params)
283 {
284 	int highest_state, lowest_state, cur_state;
285 	bool supported = false;
286 
287 	if (!params->dml ||
288 		!params->optimize_function ||
289 		!params->test_function ||
290 		!params->display_config ||
291 		!params->optimized_display_config)
292 		return false;
293 
294 	copy_display_configuration_with_meta(&l->cur_candidate_display_cfg, params->display_config);
295 	highest_state = l->cur_candidate_display_cfg.stage1.min_clk_index_for_latency;
296 	lowest_state = 0;
297 
298 	while (highest_state > lowest_state) {
299 		cur_state = (highest_state + lowest_state) / 2;
300 
301 		l->mode_support_params.instance = &params->dml->core_instance;
302 		l->mode_support_params.display_cfg = &l->cur_candidate_display_cfg;
303 		l->mode_support_params.min_clk_table = &params->dml->min_clk_table;
304 		l->mode_support_params.min_clk_index = cur_state;
305 		supported = params->dml->core_instance.mode_support(&l->mode_support_params);
306 
307 		if (supported) {
308 			l->cur_candidate_display_cfg.mode_support_result = l->mode_support_params.mode_support_result;
309 			highest_state = cur_state;
310 		} else {
311 			lowest_state = cur_state + 1;
312 		}
313 	}
314 	l->cur_candidate_display_cfg.stage1.min_clk_index_for_latency = lowest_state;
315 
316 	copy_display_configuration_with_meta(params->optimized_display_config, &l->cur_candidate_display_cfg);
317 
318 	return true;
319 }
320 
321 /*
322 * Takes an input set of mcache boundaries and finds the appropriate setting of cache programming.
323 * Returns true if a valid set of programming can be made, and false otherwise. "Valid" means
324 * that the horizontal viewport does not span more than 2 cache slices.
325 *
326 * It optionally also can apply a constant shift to all the cache boundaries.
327 */
328 static const uint32_t MCACHE_ID_UNASSIGNED = 0xF;
329 static const uint32_t SPLIT_LOCATION_UNDEFINED = 0xFFFF;
330 
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)331 static bool calculate_first_second_splitting(const int *mcache_boundaries, int num_boundaries, int shift,
332 	int pipe_h_vp_start, int pipe_h_vp_end, int *first_offset, int *second_offset)
333 {
334 	const int MAX_VP = 0xFFFFFF;
335 	int left_cache_id;
336 	int right_cache_id;
337 	int range_start;
338 	int range_end;
339 	bool success = false;
340 
341 	if (num_boundaries <= 1) {
342 		if (first_offset && second_offset) {
343 			*first_offset = 0;
344 			*second_offset = -1;
345 		}
346 		success = true;
347 		return success;
348 	} else {
349 		range_start = 0;
350 		for (left_cache_id = 0; left_cache_id < num_boundaries; left_cache_id++) {
351 			range_end = mcache_boundaries[left_cache_id] - shift - 1;
352 
353 			if (range_start <= pipe_h_vp_start && pipe_h_vp_start <= range_end)
354 				break;
355 
356 			range_start = range_end + 1;
357 		}
358 
359 		range_end = MAX_VP;
360 		for (right_cache_id = num_boundaries - 1; right_cache_id >= -1; right_cache_id--) {
361 			if (right_cache_id >= 0)
362 				range_start = mcache_boundaries[right_cache_id] - shift;
363 			else
364 				range_start = 0;
365 
366 			if (range_start <= pipe_h_vp_end && pipe_h_vp_end <= range_end) {
367 				break;
368 			}
369 			range_end = range_start - 1;
370 		}
371 		right_cache_id = (right_cache_id + 1) % num_boundaries;
372 
373 		if (right_cache_id == left_cache_id) {
374 			if (first_offset && second_offset) {
375 				*first_offset = left_cache_id;
376 				*second_offset = -1;
377 			}
378 			success = true;
379 		} else if (right_cache_id == (left_cache_id + 1) % num_boundaries) {
380 			if (first_offset && second_offset) {
381 				*first_offset = left_cache_id;
382 				*second_offset = right_cache_id;
383 			}
384 			success = true;
385 		}
386 	}
387 
388 	return success;
389 }
390 
391 /*
392 * For a given set of pipe start/end x positions, checks to see it can support the input mcache splitting.
393 * It also attempts to "optimize" by finding a shift if the default 0 shift does not work.
394 */
find_shift_for_valid_cache_id_assignment(int * mcache_boundaries,unsigned int num_boundaries,int * pipe_vp_startx,int * pipe_vp_endx,unsigned int pipe_count,int shift_granularity,int * shift)395 static bool find_shift_for_valid_cache_id_assignment(int *mcache_boundaries, unsigned int num_boundaries,
396 	int *pipe_vp_startx, int *pipe_vp_endx, unsigned int pipe_count, int shift_granularity, int *shift)
397 {
398 	int max_shift = 0xFFFF;
399 	unsigned int pipe_index;
400 	unsigned int i, slice_width;
401 	bool success = false;
402 
403 	for (i = 0; i < num_boundaries; i++) {
404 		if (i == 0)
405 			slice_width = mcache_boundaries[i];
406 		else
407 			slice_width = mcache_boundaries[i] - mcache_boundaries[i - 1];
408 
409 		if (max_shift > (int)slice_width) {
410 			max_shift = slice_width;
411 		}
412 	}
413 
414 	for (*shift = 0; *shift <= max_shift; *shift += shift_granularity) {
415 		success = true;
416 		for (pipe_index = 0; pipe_index < pipe_count; pipe_index++) {
417 			if (!calculate_first_second_splitting(mcache_boundaries, num_boundaries, *shift,
418 				pipe_vp_startx[pipe_index], pipe_vp_endx[pipe_index], 0, 0)) {
419 				success = false;
420 				break;
421 			}
422 		}
423 		if (success)
424 			break;
425 	}
426 
427 	return success;
428 }
429 
430 /*
431 * Counts the number of elements inside input array within the given span length.
432 * Formally, what is the size of the largest subset of the array where the largest and smallest element
433 * differ no more than the span.
434 */
count_elements_in_span(int * array,unsigned int array_size,unsigned int span)435 static unsigned int count_elements_in_span(int *array, unsigned int array_size, unsigned int span)
436 {
437 	unsigned int i;
438 	unsigned int span_start_value;
439 	unsigned int span_start_index;
440 	unsigned int greatest_element_count;
441 
442 	if (array_size == 0)
443 		return 1;
444 
445 	if (span == 0)
446 		return array_size > 0 ? 1 : 0;
447 
448 	span_start_value = 0;
449 	span_start_index = 0;
450 	greatest_element_count = 0;
451 
452 	while (span_start_index < array_size) {
453 		for (i = span_start_index; i < array_size; i++) {
454 			if (array[i] - span_start_value <= span) {
455 				if (i - span_start_index + 1 > greatest_element_count) {
456 					greatest_element_count = i - span_start_index + 1;
457 				}
458 			} else
459 				break;
460 		}
461 
462 		span_start_index++;
463 
464 		if (span_start_index < array_size) {
465 			span_start_value = array[span_start_index - 1] + 1;
466 		}
467 	}
468 
469 	return greatest_element_count;
470 }
471 
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)472 static bool calculate_h_split_for_scaling_transform(int full_vp_width, int h_active, int num_pipes,
473 	enum dml2_scaling_transform scaling_transform, int *pipe_vp_x_start, int *pipe_vp_x_end)
474 {
475 	int i, slice_width;
476 	const char MAX_SCL_VP_OVERLAP = 3;
477 	bool success = false;
478 
479 	switch (scaling_transform) {
480 	case dml2_scaling_transform_centered:
481 	case dml2_scaling_transform_aspect_ratio:
482 	case dml2_scaling_transform_fullscreen:
483 		slice_width = full_vp_width / num_pipes;
484 		for (i = 0; i < num_pipes; i++) {
485 			pipe_vp_x_start[i] = i * slice_width;
486 			pipe_vp_x_end[i] = (i + 1) * slice_width - 1;
487 
488 			if (pipe_vp_x_start[i] < MAX_SCL_VP_OVERLAP)
489 				pipe_vp_x_start[i] = 0;
490 			else
491 				pipe_vp_x_start[i] -= MAX_SCL_VP_OVERLAP;
492 
493 			if (pipe_vp_x_end[i] > full_vp_width - MAX_SCL_VP_OVERLAP - 1)
494 				pipe_vp_x_end[i] = full_vp_width - 1;
495 			else
496 				pipe_vp_x_end[i] += MAX_SCL_VP_OVERLAP;
497 		}
498 		break;
499 	case dml2_scaling_transform_explicit:
500 	default:
501 		success = false;
502 		break;
503 	}
504 
505 	return success;
506 }
507 
dml2_top_mcache_validate_admissability(struct top_mcache_validate_admissability_in_out * params)508 bool dml2_top_mcache_validate_admissability(struct top_mcache_validate_admissability_in_out *params)
509 {
510 	struct dml2_instance *dml = (struct dml2_instance *)params->dml2_instance;
511 	struct dml2_top_mcache_validate_admissability_locals *l = &dml->scratch.mcache_validate_admissability_locals;
512 
513 	const int MAX_PIXEL_OVERLAP = 6;
514 	int max_per_pipe_vp_p0 = 0;
515 	int max_per_pipe_vp_p1 = 0;
516 	int temp, p0shift, p1shift;
517 	unsigned int plane_index = 0;
518 	unsigned int i;
519 	unsigned int odm_combine_factor;
520 	unsigned int mpc_combine_factor;
521 	unsigned int num_dpps;
522 	unsigned int num_boundaries;
523 	enum dml2_scaling_transform scaling_transform;
524 	const struct dml2_plane_parameters *plane;
525 	const struct dml2_stream_parameters *stream;
526 
527 	bool p0pass = false;
528 	bool p1pass = false;
529 	bool all_pass = true;
530 
531 	for (plane_index = 0; plane_index < params->display_cfg->num_planes; plane_index++) {
532 		if (!params->display_cfg->plane_descriptors[plane_index].surface.dcc.enable)
533 			continue;
534 
535 		plane = &params->display_cfg->plane_descriptors[plane_index];
536 		stream = &params->display_cfg->stream_descriptors[plane->stream_index];
537 
538 		num_dpps = odm_combine_factor = params->cfg_support_info->stream_support_info[plane->stream_index].odms_used;
539 
540 		if (odm_combine_factor == 1)
541 			num_dpps = mpc_combine_factor = (unsigned int)params->cfg_support_info->plane_support_info[plane_index].dpps_used;
542 		else
543 			mpc_combine_factor = 1;
544 
545 		if (odm_combine_factor > 1) {
546 			max_per_pipe_vp_p0 = plane->surface.plane0.width;
547 			temp = (unsigned int)math_ceil(plane->composition.scaler_info.plane0.h_ratio * stream->timing.h_active / odm_combine_factor);
548 
549 			if (temp < max_per_pipe_vp_p0)
550 				max_per_pipe_vp_p0 = temp;
551 
552 			max_per_pipe_vp_p1 = plane->surface.plane1.width;
553 			temp = (unsigned int)math_ceil(plane->composition.scaler_info.plane1.h_ratio * stream->timing.h_active / odm_combine_factor);
554 
555 			if (temp < max_per_pipe_vp_p1)
556 				max_per_pipe_vp_p1 = temp;
557 		} else {
558 			max_per_pipe_vp_p0 = plane->surface.plane0.width / mpc_combine_factor;
559 			max_per_pipe_vp_p1 = plane->surface.plane1.width / mpc_combine_factor;
560 		}
561 
562 		max_per_pipe_vp_p0 += 2 * MAX_PIXEL_OVERLAP;
563 		max_per_pipe_vp_p1 += MAX_PIXEL_OVERLAP;
564 
565 		p0shift = 0;
566 		p1shift = 0;
567 
568 		// The last element in the unshifted boundary array will always be the first pixel outside the
569 		// plane, which means theres no mcache associated with it, so -1
570 		num_boundaries = params->mcache_allocations[plane_index].num_mcaches_plane0 == 0 ? 0 : params->mcache_allocations[plane_index].num_mcaches_plane0 - 1;
571 		if ((count_elements_in_span(params->mcache_allocations[plane_index].mcache_x_offsets_plane0,
572 			num_boundaries, max_per_pipe_vp_p0) <= 1) && (num_boundaries <= num_dpps)) {
573 			p0pass = true;
574 		}
575 		num_boundaries = params->mcache_allocations[plane_index].num_mcaches_plane1 == 0 ? 0 : params->mcache_allocations[plane_index].num_mcaches_plane1 - 1;
576 		if ((count_elements_in_span(params->mcache_allocations[plane_index].mcache_x_offsets_plane1,
577 			num_boundaries, max_per_pipe_vp_p1) <= 1) && (num_boundaries <= num_dpps)) {
578 			p1pass = true;
579 		}
580 
581 		if (!p0pass || !p1pass) {
582 			if (odm_combine_factor > 1) {
583 				num_dpps = odm_combine_factor;
584 				scaling_transform = plane->composition.scaling_transform;
585 			} else {
586 				num_dpps = mpc_combine_factor;
587 				scaling_transform = dml2_scaling_transform_fullscreen;
588 			}
589 
590 			if (!p0pass) {
591 				if (plane->composition.viewport.stationary) {
592 					calculate_h_split_for_scaling_transform(plane->surface.plane0.width,
593 						stream->timing.h_active, num_dpps, scaling_transform,
594 						&l->plane0.pipe_vp_startx[plane_index], &l->plane0.pipe_vp_endx[plane_index]);
595 					p0pass = find_shift_for_valid_cache_id_assignment(params->mcache_allocations[plane_index].mcache_x_offsets_plane0,
596 						params->mcache_allocations[plane_index].num_mcaches_plane0,
597 						&l->plane0.pipe_vp_startx[plane_index], &l->plane0.pipe_vp_endx[plane_index], num_dpps,
598 						params->mcache_allocations[plane_index].shift_granularity.p0, &p0shift);
599 				}
600 			}
601 			if (!p1pass) {
602 				if (plane->composition.viewport.stationary) {
603 					calculate_h_split_for_scaling_transform(plane->surface.plane1.width,
604 						stream->timing.h_active, num_dpps, scaling_transform,
605 						&l->plane0.pipe_vp_startx[plane_index], &l->plane0.pipe_vp_endx[plane_index]);
606 					p1pass = find_shift_for_valid_cache_id_assignment(params->mcache_allocations[plane_index].mcache_x_offsets_plane1,
607 						params->mcache_allocations[plane_index].num_mcaches_plane1,
608 						&l->plane1.pipe_vp_startx[plane_index], &l->plane1.pipe_vp_endx[plane_index], num_dpps,
609 						params->mcache_allocations[plane_index].shift_granularity.p1, &p1shift);
610 				}
611 			}
612 		}
613 
614 		if (p0pass && p1pass) {
615 			for (i = 0; i < params->mcache_allocations[plane_index].num_mcaches_plane0; i++) {
616 				params->mcache_allocations[plane_index].mcache_x_offsets_plane0[i] -= p0shift;
617 			}
618 			for (i = 0; i < params->mcache_allocations[plane_index].num_mcaches_plane1; i++) {
619 				params->mcache_allocations[plane_index].mcache_x_offsets_plane1[i] -= p1shift;
620 			}
621 		}
622 
623 		params->per_plane_status[plane_index] = p0pass && p1pass;
624 		all_pass &= p0pass && p1pass;
625 	}
626 
627 	return all_pass;
628 }
629 
reset_mcache_allocations(struct dml2_hubp_pipe_mcache_regs * per_plane_pipe_mcache_regs)630 static void reset_mcache_allocations(struct dml2_hubp_pipe_mcache_regs *per_plane_pipe_mcache_regs)
631 {
632 	// Initialize all entries to special valid MCache ID and special valid split coordinate
633 	per_plane_pipe_mcache_regs->main.p0.mcache_id_first = MCACHE_ID_UNASSIGNED;
634 	per_plane_pipe_mcache_regs->main.p0.mcache_id_second = MCACHE_ID_UNASSIGNED;
635 	per_plane_pipe_mcache_regs->main.p0.split_location = SPLIT_LOCATION_UNDEFINED;
636 
637 	per_plane_pipe_mcache_regs->mall.p0.mcache_id_first = MCACHE_ID_UNASSIGNED;
638 	per_plane_pipe_mcache_regs->mall.p0.mcache_id_second = MCACHE_ID_UNASSIGNED;
639 	per_plane_pipe_mcache_regs->mall.p0.split_location = SPLIT_LOCATION_UNDEFINED;
640 
641 	per_plane_pipe_mcache_regs->main.p1.mcache_id_first = MCACHE_ID_UNASSIGNED;
642 	per_plane_pipe_mcache_regs->main.p1.mcache_id_second = MCACHE_ID_UNASSIGNED;
643 	per_plane_pipe_mcache_regs->main.p1.split_location = SPLIT_LOCATION_UNDEFINED;
644 
645 	per_plane_pipe_mcache_regs->mall.p1.mcache_id_first = MCACHE_ID_UNASSIGNED;
646 	per_plane_pipe_mcache_regs->mall.p1.mcache_id_second = MCACHE_ID_UNASSIGNED;
647 	per_plane_pipe_mcache_regs->mall.p1.split_location = SPLIT_LOCATION_UNDEFINED;
648 }
649 
dml2_top_mcache_assign_global_mcache_ids(struct top_mcache_assign_global_mcache_ids_in_out * params)650 void dml2_top_mcache_assign_global_mcache_ids(struct top_mcache_assign_global_mcache_ids_in_out *params)
651 {
652 	int i;
653 	unsigned int j;
654 	int next_unused_cache_id = 0;
655 
656 	for (i = 0; i < params->num_allocations; i++) {
657 		if (!params->allocations[i].valid)
658 			continue;
659 
660 		for (j = 0; j < params->allocations[i].num_mcaches_plane0; j++) {
661 			params->allocations[i].global_mcache_ids_plane0[j] = next_unused_cache_id++;
662 		}
663 		for (j = 0; j < params->allocations[i].num_mcaches_plane1; j++) {
664 			params->allocations[i].global_mcache_ids_plane1[j] = next_unused_cache_id++;
665 		}
666 
667 		// The "psuedo-last" slice is always wrapped around
668 		params->allocations[i].global_mcache_ids_plane0[params->allocations[i].num_mcaches_plane0] =
669 			params->allocations[i].global_mcache_ids_plane0[0];
670 		params->allocations[i].global_mcache_ids_plane1[params->allocations[i].num_mcaches_plane1] =
671 			params->allocations[i].global_mcache_ids_plane1[0];
672 
673 		// If we need dedicated caches for mall requesting, then we assign them here.
674 		if (params->allocations[i].requires_dedicated_mall_mcache) {
675 			for (j = 0; j < params->allocations[i].num_mcaches_plane0; j++) {
676 				params->allocations[i].global_mcache_ids_mall_plane0[j] = next_unused_cache_id++;
677 			}
678 			for (j = 0; j < params->allocations[i].num_mcaches_plane1; j++) {
679 				params->allocations[i].global_mcache_ids_mall_plane1[j] = next_unused_cache_id++;
680 			}
681 
682 			// The "psuedo-last" slice is always wrapped around
683 			params->allocations[i].global_mcache_ids_mall_plane0[params->allocations[i].num_mcaches_plane0] =
684 				params->allocations[i].global_mcache_ids_mall_plane0[0];
685 			params->allocations[i].global_mcache_ids_mall_plane1[params->allocations[i].num_mcaches_plane1] =
686 				params->allocations[i].global_mcache_ids_mall_plane1[0];
687 		}
688 
689 		// If P0 and P1 are sharing caches, then it means the largest mcache IDs for p0 and p1 can be the same
690 		// since mcache IDs are always ascending, then it means the largest mcacheID of p1 should be the
691 		// largest mcacheID of P0
692 		if (params->allocations[i].num_mcaches_plane0 > 0 && params->allocations[i].num_mcaches_plane1 > 0 &&
693 			params->allocations[i].last_slice_sharing.plane0_plane1) {
694 			params->allocations[i].global_mcache_ids_plane1[params->allocations[i].num_mcaches_plane1 - 1] =
695 				params->allocations[i].global_mcache_ids_plane0[params->allocations[i].num_mcaches_plane0 - 1];
696 		}
697 
698 		// If we need dedicated caches handle last slice sharing
699 		if (params->allocations[i].requires_dedicated_mall_mcache) {
700 			if (params->allocations[i].num_mcaches_plane0 > 0 && params->allocations[i].num_mcaches_plane1 > 0 &&
701 				params->allocations[i].last_slice_sharing.plane0_plane1) {
702 				params->allocations[i].global_mcache_ids_mall_plane1[params->allocations[i].num_mcaches_plane1 - 1] =
703 					params->allocations[i].global_mcache_ids_mall_plane0[params->allocations[i].num_mcaches_plane0 - 1];
704 			}
705 			// If mall_comb_mcache_l is set then it means that largest mcache ID for MALL p0 can be same as regular read p0
706 			if (params->allocations[i].num_mcaches_plane0 > 0 && params->allocations[i].last_slice_sharing.mall_comb_mcache_p0) {
707 				params->allocations[i].global_mcache_ids_mall_plane0[params->allocations[i].num_mcaches_plane0 - 1] =
708 					params->allocations[i].global_mcache_ids_plane0[params->allocations[i].num_mcaches_plane0 - 1];
709 			}
710 			// If mall_comb_mcache_c is set then it means that largest mcache ID for MALL p1 can be same as regular
711 			// read p1 (which can be same as regular read p0 if plane0_plane1 is also set)
712 			if (params->allocations[i].num_mcaches_plane1 > 0 && params->allocations[i].last_slice_sharing.mall_comb_mcache_p1) {
713 				params->allocations[i].global_mcache_ids_mall_plane1[params->allocations[i].num_mcaches_plane1 - 1] =
714 					params->allocations[i].global_mcache_ids_plane1[params->allocations[i].num_mcaches_plane1 - 1];
715 			}
716 		}
717 
718 		// If you don't need dedicated mall mcaches, the mall mcache assignments are identical to the normal requesting
719 		if (!params->allocations[i].requires_dedicated_mall_mcache) {
720 			memcpy(params->allocations[i].global_mcache_ids_mall_plane0, params->allocations[i].global_mcache_ids_plane0,
721 				sizeof(params->allocations[i].global_mcache_ids_mall_plane0));
722 			memcpy(params->allocations[i].global_mcache_ids_mall_plane1, params->allocations[i].global_mcache_ids_plane1,
723 				sizeof(params->allocations[i].global_mcache_ids_mall_plane1));
724 		}
725 	}
726 }
727 
dml2_top_mcache_calc_mcache_count_and_offsets(struct top_mcache_calc_mcache_count_and_offsets_in_out * params)728 bool dml2_top_mcache_calc_mcache_count_and_offsets(struct top_mcache_calc_mcache_count_and_offsets_in_out *params)
729 {
730 	struct dml2_instance *dml = (struct dml2_instance *)params->dml2_instance;
731 	struct dml2_top_mcache_verify_mcache_size_locals *l = &dml->scratch.mcache_verify_mcache_size_locals;
732 
733 	unsigned int total_mcaches_required;
734 	unsigned int i;
735 	bool result = false;
736 
737 	if (dml->soc_bbox.num_dcc_mcaches == 0) {
738 		return true;
739 	}
740 
741 	total_mcaches_required = 0;
742 	l->calc_mcache_params.instance = &dml->core_instance;
743 	for (i = 0; i < params->display_config->num_planes; i++) {
744 		if (!params->display_config->plane_descriptors[i].surface.dcc.enable) {
745 			memset(&params->mcache_allocations[i], 0, sizeof(struct dml2_mcache_surface_allocation));
746 			continue;
747 		}
748 
749 		l->calc_mcache_params.plane_descriptor = &params->display_config->plane_descriptors[i];
750 		l->calc_mcache_params.mcache_allocation = &params->mcache_allocations[i];
751 		l->calc_mcache_params.plane_index = i;
752 
753 		if (!dml->core_instance.calculate_mcache_allocation(&l->calc_mcache_params)) {
754 			result = false;
755 			break;
756 		}
757 
758 		if (params->mcache_allocations[i].valid) {
759 			total_mcaches_required += params->mcache_allocations[i].num_mcaches_plane0 + params->mcache_allocations[i].num_mcaches_plane1;
760 			if (params->mcache_allocations[i].last_slice_sharing.plane0_plane1)
761 				total_mcaches_required--;
762 		}
763 	}
764 	dml2_printf("DML_CORE_DCN3::%s: plane_%d, total_mcaches_required=%d\n", __func__, i, total_mcaches_required);
765 
766 	if (total_mcaches_required > dml->soc_bbox.num_dcc_mcaches) {
767 		result = false;
768 	} else {
769 		result = true;
770 	}
771 
772 	return result;
773 }
774 
dml2_top_soc15_check_mode_supported(struct dml2_check_mode_supported_in_out * in_out)775 static bool dml2_top_soc15_check_mode_supported(struct dml2_check_mode_supported_in_out *in_out)
776 {
777 	struct dml2_instance *dml = (struct dml2_instance *)in_out->dml2_instance;
778 	struct dml2_check_mode_supported_locals *l = &dml->scratch.check_mode_supported_locals;
779 	struct dml2_display_cfg_programming *dpmm_programming = &dml->dpmm_instance.dpmm_scratch.programming;
780 
781 	bool result = false;
782 	bool mcache_success = false;
783 	memset(dpmm_programming, 0, sizeof(struct dml2_display_cfg_programming));
784 
785 	setup_unoptimized_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
786 
787 	l->mode_support_params.instance = &dml->core_instance;
788 	l->mode_support_params.display_cfg = &l->base_display_config_with_meta;
789 	l->mode_support_params.min_clk_table = &dml->min_clk_table;
790 	l->mode_support_params.min_clk_index = l->base_display_config_with_meta.stage1.min_clk_index_for_latency;
791 	result = dml->core_instance.mode_support(&l->mode_support_params);
792 	l->base_display_config_with_meta.mode_support_result = l->mode_support_params.mode_support_result;
793 
794 	if (result) {
795 		struct optimization_phase_params mcache_phase =	{
796 		.dml = dml,
797 		.display_config = &l->base_display_config_with_meta,
798 		.test_function = dml2_top_optimization_test_function_mcache,
799 		.optimize_function = dml2_top_optimization_optimize_function_mcache,
800 		.optimized_display_config = &l->optimized_display_config_with_meta,
801 		.all_or_nothing = false,
802 		};
803 		mcache_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &mcache_phase);
804 	}
805 
806 	/*
807 	* Call DPMM to map all requirements to minimum clock state
808 	*/
809 	if (result) {
810 		l->dppm_map_mode_params.min_clk_table = &dml->min_clk_table;
811 		l->dppm_map_mode_params.display_cfg = &l->base_display_config_with_meta;
812 		l->dppm_map_mode_params.programming = dpmm_programming;
813 		l->dppm_map_mode_params.soc_bb = &dml->soc_bbox;
814 		l->dppm_map_mode_params.ip = &dml->core_instance.clean_me_up.mode_lib.ip;
815 		result = dml->dpmm_instance.map_mode_to_soc_dpm(&l->dppm_map_mode_params);
816 	}
817 
818 	in_out->is_supported = mcache_success;
819 	result = result && in_out->is_supported;
820 
821 	return result;
822 }
823 
dml2_top_soc15_build_mode_programming(struct dml2_build_mode_programming_in_out * in_out)824 static bool dml2_top_soc15_build_mode_programming(struct dml2_build_mode_programming_in_out *in_out)
825 {
826 	struct dml2_instance *dml = (struct dml2_instance *)in_out->dml2_instance;
827 	struct dml2_build_mode_programming_locals *l = &dml->scratch.build_mode_programming_locals;
828 
829 	bool result = false;
830 	bool mcache_success = false;
831 	bool uclk_pstate_success = false;
832 	bool vmin_success = false;
833 	bool stutter_success = false;
834 	unsigned int i;
835 
836 	memset(l, 0, sizeof(struct dml2_build_mode_programming_locals));
837 	memset(in_out->programming, 0, sizeof(struct dml2_display_cfg_programming));
838 
839 	memcpy(&in_out->programming->display_config, in_out->display_config, sizeof(struct dml2_display_cfg));
840 
841 	setup_speculative_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
842 
843 	l->mode_support_params.instance = &dml->core_instance;
844 	l->mode_support_params.display_cfg = &l->base_display_config_with_meta;
845 	l->mode_support_params.min_clk_table = &dml->min_clk_table;
846 	l->mode_support_params.min_clk_index = l->base_display_config_with_meta.stage1.min_clk_index_for_latency;
847 	result = dml->core_instance.mode_support(&l->mode_support_params);
848 
849 	l->base_display_config_with_meta.mode_support_result = l->mode_support_params.mode_support_result;
850 
851 	if (!result) {
852 		setup_unoptimized_display_config_with_meta(dml, &l->base_display_config_with_meta, in_out->display_config);
853 
854 		l->mode_support_params.instance = &dml->core_instance;
855 		l->mode_support_params.display_cfg = &l->base_display_config_with_meta;
856 		l->mode_support_params.min_clk_table = &dml->min_clk_table;
857 		l->mode_support_params.min_clk_index = l->base_display_config_with_meta.stage1.min_clk_index_for_latency;
858 		result = dml->core_instance.mode_support(&l->mode_support_params);
859 		l->base_display_config_with_meta.mode_support_result = l->mode_support_params.mode_support_result;
860 
861 		if (!result) {
862 			l->informative_params.instance = &dml->core_instance;
863 			l->informative_params.programming = in_out->programming;
864 			l->informative_params.mode_is_supported = false;
865 			dml->core_instance.populate_informative(&l->informative_params);
866 
867 			return false;
868 		}
869 
870 		/*
871 		* Phase 1: Determine minimum clocks to satisfy latency requirements for this mode
872 		*/
873 		memset(&l->min_clock_for_latency_phase, 0, sizeof(struct optimization_phase_params));
874 		l->min_clock_for_latency_phase.dml = dml;
875 		l->min_clock_for_latency_phase.display_config = &l->base_display_config_with_meta;
876 		l->min_clock_for_latency_phase.init_function = dml2_top_optimization_init_function_min_clk_for_latency;
877 		l->min_clock_for_latency_phase.test_function = dml2_top_optimization_test_function_min_clk_for_latency;
878 		l->min_clock_for_latency_phase.optimize_function = dml2_top_optimization_optimize_function_min_clk_for_latency;
879 		l->min_clock_for_latency_phase.optimized_display_config = &l->optimized_display_config_with_meta;
880 		l->min_clock_for_latency_phase.all_or_nothing = false;
881 
882 		dml2_top_optimization_perform_optimization_phase_1(&l->optimization_phase_locals, &l->min_clock_for_latency_phase);
883 
884 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
885 	}
886 
887 	/*
888 	* Phase 2: Satisfy DCC mcache requirements
889 	*/
890 	memset(&l->mcache_phase, 0, sizeof(struct optimization_phase_params));
891 	l->mcache_phase.dml = dml;
892 	l->mcache_phase.display_config = &l->base_display_config_with_meta;
893 	l->mcache_phase.test_function = dml2_top_optimization_test_function_mcache;
894 	l->mcache_phase.optimize_function = dml2_top_optimization_optimize_function_mcache;
895 	l->mcache_phase.optimized_display_config = &l->optimized_display_config_with_meta;
896 	l->mcache_phase.all_or_nothing = true;
897 
898 	mcache_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->mcache_phase);
899 
900 	if (!mcache_success) {
901 		l->informative_params.instance = &dml->core_instance;
902 		l->informative_params.programming = in_out->programming;
903 		l->informative_params.mode_is_supported = false;
904 
905 		dml->core_instance.populate_informative(&l->informative_params);
906 
907 		in_out->programming->informative.failed_mcache_validation = true;
908 		return false;
909 	}
910 
911 	memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
912 
913 	/*
914 	* Phase 3: Optimize for Pstate
915 	*/
916 	memset(&l->uclk_pstate_phase, 0, sizeof(struct optimization_phase_params));
917 	l->uclk_pstate_phase.dml = dml;
918 	l->uclk_pstate_phase.display_config = &l->base_display_config_with_meta;
919 	l->uclk_pstate_phase.init_function = dml2_top_optimization_init_function_uclk_pstate;
920 	l->uclk_pstate_phase.test_function = dml2_top_optimization_test_function_uclk_pstate;
921 	l->uclk_pstate_phase.optimize_function = dml2_top_optimization_optimize_function_uclk_pstate;
922 	l->uclk_pstate_phase.optimized_display_config = &l->optimized_display_config_with_meta;
923 	l->uclk_pstate_phase.all_or_nothing = true;
924 
925 	uclk_pstate_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->uclk_pstate_phase);
926 
927 	if (uclk_pstate_success) {
928 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
929 		l->base_display_config_with_meta.stage3.success = true;
930 	}
931 
932 	/*
933 	* Phase 4: Optimize for Vmin
934 	*/
935 	memset(&l->vmin_phase, 0, sizeof(struct optimization_phase_params));
936 	l->vmin_phase.dml = dml;
937 	l->vmin_phase.display_config = &l->base_display_config_with_meta;
938 	l->vmin_phase.init_function = dml2_top_optimization_init_function_vmin;
939 	l->vmin_phase.test_function = dml2_top_optimization_test_function_vmin;
940 	l->vmin_phase.optimize_function = dml2_top_optimization_optimize_function_vmin;
941 	l->vmin_phase.optimized_display_config = &l->optimized_display_config_with_meta;
942 	l->vmin_phase.all_or_nothing = false;
943 
944 	vmin_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->vmin_phase);
945 
946 	if (l->optimized_display_config_with_meta.stage4.performed) {
947 		/*
948 		 * when performed is true, optimization has applied to
949 		 * optimized_display_config_with_meta and it has passed mode
950 		 * support. However it may or may not pass the test function to
951 		 * reach actual Vmin. As long as voltage is optimized even if it
952 		 * doesn't reach Vmin level, there is still power benefit so in
953 		 * this case we will still copy this optimization into base
954 		 * display config.
955 		 */
956 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
957 		l->base_display_config_with_meta.stage4.success = vmin_success;
958 	}
959 
960 	/*
961 	* Phase 5: Optimize for Stutter
962 	*/
963 	memset(&l->stutter_phase, 0, sizeof(struct optimization_phase_params));
964 	l->stutter_phase.dml = dml;
965 	l->stutter_phase.display_config = &l->base_display_config_with_meta;
966 	l->stutter_phase.init_function = dml2_top_optimization_init_function_stutter;
967 	l->stutter_phase.test_function = dml2_top_optimization_test_function_stutter;
968 	l->stutter_phase.optimize_function = dml2_top_optimization_optimize_function_stutter;
969 	l->stutter_phase.optimized_display_config = &l->optimized_display_config_with_meta;
970 	l->stutter_phase.all_or_nothing = true;
971 
972 	stutter_success = dml2_top_optimization_perform_optimization_phase(&l->optimization_phase_locals, &l->stutter_phase);
973 
974 	if (stutter_success) {
975 		memcpy(&l->base_display_config_with_meta, &l->optimized_display_config_with_meta, sizeof(struct display_configuation_with_meta));
976 		l->base_display_config_with_meta.stage5.success = true;
977 	}
978 
979 	/*
980 	* Populate mcache programming
981 	*/
982 	for (i = 0; i < in_out->display_config->num_planes; i++) {
983 		in_out->programming->plane_programming[i].mcache_allocation = l->base_display_config_with_meta.stage2.mcache_allocations[i];
984 	}
985 
986 	/*
987 	* Call DPMM to map all requirements to minimum clock state
988 	*/
989 	if (result) {
990 		l->dppm_map_mode_params.min_clk_table = &dml->min_clk_table;
991 		l->dppm_map_mode_params.display_cfg = &l->base_display_config_with_meta;
992 		l->dppm_map_mode_params.programming = in_out->programming;
993 		l->dppm_map_mode_params.soc_bb = &dml->soc_bbox;
994 		l->dppm_map_mode_params.ip = &dml->core_instance.clean_me_up.mode_lib.ip;
995 		result = dml->dpmm_instance.map_mode_to_soc_dpm(&l->dppm_map_mode_params);
996 		if (!result)
997 			in_out->programming->informative.failed_dpmm = true;
998 	}
999 
1000 	if (result) {
1001 		l->mode_programming_params.instance = &dml->core_instance;
1002 		l->mode_programming_params.display_cfg = &l->base_display_config_with_meta;
1003 		l->mode_programming_params.cfg_support_info = &l->base_display_config_with_meta.mode_support_result.cfg_support_info;
1004 		l->mode_programming_params.programming = in_out->programming;
1005 		result = dml->core_instance.mode_programming(&l->mode_programming_params);
1006 		if (!result)
1007 			in_out->programming->informative.failed_mode_programming = true;
1008 	}
1009 
1010 	if (result) {
1011 		l->dppm_map_watermarks_params.core = &dml->core_instance;
1012 		l->dppm_map_watermarks_params.display_cfg = &l->base_display_config_with_meta;
1013 		l->dppm_map_watermarks_params.programming = in_out->programming;
1014 		result = dml->dpmm_instance.map_watermarks(&l->dppm_map_watermarks_params);
1015 	}
1016 
1017 	l->informative_params.instance = &dml->core_instance;
1018 	l->informative_params.programming = in_out->programming;
1019 	l->informative_params.mode_is_supported = result;
1020 
1021 	dml->core_instance.populate_informative(&l->informative_params);
1022 
1023 	return result;
1024 }
1025 
dml2_top_soc15_build_mcache_programming(struct dml2_build_mcache_programming_in_out * params)1026 bool dml2_top_soc15_build_mcache_programming(struct dml2_build_mcache_programming_in_out *params)
1027 {
1028 	bool success = true;
1029 	int config_index, pipe_index;
1030 	int first_offset, second_offset;
1031 	int free_per_plane_reg_index = 0;
1032 
1033 	memset(params->per_plane_pipe_mcache_regs, 0, DML2_MAX_PLANES * DML2_MAX_DCN_PIPES * sizeof(struct dml2_hubp_pipe_mcache_regs *));
1034 
1035 	for (config_index = 0; config_index < params->num_configurations; config_index++) {
1036 		for (pipe_index = 0; pipe_index < params->mcache_configurations[config_index].num_pipes; pipe_index++) {
1037 			// Allocate storage for the mcache regs
1038 			params->per_plane_pipe_mcache_regs[config_index][pipe_index] = &params->mcache_regs_set[free_per_plane_reg_index++];
1039 
1040 			reset_mcache_allocations(params->per_plane_pipe_mcache_regs[config_index][pipe_index]);
1041 
1042 			if (params->mcache_configurations[config_index].plane_descriptor->surface.dcc.enable) {
1043 				// P0 always enabled
1044 				if (!calculate_first_second_splitting(params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane0,
1045 					params->mcache_configurations[config_index].mcache_allocation->num_mcaches_plane0,
1046 					0,
1047 					params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane0.viewport_x_start,
1048 					params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane0.viewport_x_start +
1049 					params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane0.viewport_width - 1,
1050 					&first_offset, &second_offset)) {
1051 					success = false;
1052 					break;
1053 				}
1054 
1055 				params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p0.mcache_id_first =
1056 					params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane0[first_offset];
1057 
1058 				params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p0.mcache_id_first =
1059 					params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane0[first_offset];
1060 
1061 				if (second_offset >= 0) {
1062 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p0.mcache_id_second =
1063 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane0[second_offset];
1064 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p0.split_location =
1065 						params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane0[first_offset] - 1;
1066 
1067 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p0.mcache_id_second =
1068 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane0[second_offset];
1069 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p0.split_location =
1070 						params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane0[first_offset] - 1;
1071 				}
1072 
1073 				// Populate P1 if enabled
1074 				if (params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1_enabled) {
1075 					if (!calculate_first_second_splitting(params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane1,
1076 						params->mcache_configurations[config_index].mcache_allocation->num_mcaches_plane1,
1077 						0,
1078 						params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1.viewport_x_start,
1079 						params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1.viewport_x_start +
1080 						params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1.viewport_width - 1,
1081 						&first_offset, &second_offset)) {
1082 						success = false;
1083 						break;
1084 					}
1085 
1086 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p1.mcache_id_first =
1087 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane1[first_offset];
1088 
1089 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p1.mcache_id_first =
1090 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane1[first_offset];
1091 
1092 					if (second_offset >= 0) {
1093 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p1.mcache_id_second =
1094 							params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane1[second_offset];
1095 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p1.split_location =
1096 							params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane1[first_offset] - 1;
1097 
1098 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p1.mcache_id_second =
1099 							params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane1[second_offset];
1100 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p1.split_location =
1101 							params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane1[first_offset] - 1;
1102 					}
1103 				}
1104 			}
1105 		}
1106 	}
1107 
1108 	return success;
1109 }
1110 
1111 static const struct dml2_top_funcs soc15_funcs = {
1112 	.check_mode_supported = dml2_top_soc15_check_mode_supported,
1113 	.build_mode_programming = dml2_top_soc15_build_mode_programming,
1114 	.build_mcache_programming = dml2_top_soc15_build_mcache_programming,
1115 };
1116 
dml2_top_soc15_initialize_instance(struct dml2_initialize_instance_in_out * in_out)1117 bool dml2_top_soc15_initialize_instance(struct dml2_initialize_instance_in_out *in_out)
1118 {
1119 	struct dml2_instance *dml = (struct dml2_instance *)in_out->dml2_instance;
1120 	struct dml2_initialize_instance_locals *l = &dml->scratch.initialize_instance_locals;
1121 	struct dml2_core_initialize_in_out core_init_params = { 0 };
1122 	struct dml2_mcg_build_min_clock_table_params_in_out mcg_build_min_clk_params = { 0 };
1123 	struct dml2_pmo_initialize_in_out pmo_init_params = { 0 };
1124 	bool result = false;
1125 
1126 	memset(l, 0, sizeof(struct dml2_initialize_instance_locals));
1127 	memset(dml, 0, sizeof(struct dml2_instance));
1128 
1129 	memcpy(&dml->ip_caps, &in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
1130 	memcpy(&dml->soc_bbox, &in_out->soc_bb, sizeof(struct dml2_soc_bb));
1131 
1132 	dml->project_id = in_out->options.project_id;
1133 	dml->pmo_options = in_out->options.pmo_options;
1134 
1135 	// Initialize All Components
1136 	result = dml2_mcg_create(in_out->options.project_id, &dml->mcg_instance);
1137 
1138 	if (result)
1139 		result = dml2_dpmm_create(in_out->options.project_id, &dml->dpmm_instance);
1140 
1141 	if (result)
1142 		result = dml2_core_create(in_out->options.project_id, &dml->core_instance);
1143 
1144 	if (result) {
1145 		mcg_build_min_clk_params.soc_bb = &in_out->soc_bb;
1146 		mcg_build_min_clk_params.min_clk_table = &dml->min_clk_table;
1147 		result = dml->mcg_instance.build_min_clock_table(&mcg_build_min_clk_params);
1148 	}
1149 
1150 	if (result) {
1151 		core_init_params.project_id = in_out->options.project_id;
1152 		core_init_params.instance = &dml->core_instance;
1153 		core_init_params.minimum_clock_table = &dml->min_clk_table;
1154 		core_init_params.explicit_ip_bb = in_out->overrides.explicit_ip_bb;
1155 		core_init_params.explicit_ip_bb_size = in_out->overrides.explicit_ip_bb_size;
1156 		core_init_params.ip_caps = &in_out->ip_caps;
1157 		core_init_params.soc_bb = &in_out->soc_bb;
1158 		result = dml->core_instance.initialize(&core_init_params);
1159 
1160 		if (core_init_params.explicit_ip_bb && core_init_params.explicit_ip_bb_size > 0) {
1161 			memcpy(&dml->ip_caps, &in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
1162 		}
1163 	}
1164 
1165 	if (result)
1166 		result = dml2_pmo_create(in_out->options.project_id, &dml->pmo_instance);
1167 
1168 	if (result) {
1169 		pmo_init_params.instance = &dml->pmo_instance;
1170 		pmo_init_params.soc_bb = &dml->soc_bbox;
1171 		pmo_init_params.ip_caps = &dml->ip_caps;
1172 		pmo_init_params.mcg_clock_table_size = dml->min_clk_table.dram_bw_table.num_entries;
1173 		pmo_init_params.options = &dml->pmo_options;
1174 		dml->pmo_instance.initialize(&pmo_init_params);
1175 	}
1176 	dml->funcs = soc15_funcs;
1177 	return result;
1178 }
1179