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