1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "dml2_debug.h"
6 
7 #include "dml_top_mcache.h"
8 #include "lib_float_math.h"
9 
10 #include "dml2_internal_shared_types.h"
11 
12 /*
13 * Takes an input set of mcache boundaries and finds the appropriate setting of cache programming.
14 * Returns true if a valid set of programming can be made, and false otherwise. "Valid" means
15 * that the horizontal viewport does not span more than 2 cache slices.
16 *
17 * It optionally also can apply a constant shift to all the cache boundaries.
18 */
19 static const uint32_t MCACHE_ID_UNASSIGNED = 0xF;
20 static const uint32_t SPLIT_LOCATION_UNDEFINED = 0xFFFF;
21 
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)22 static bool calculate_first_second_splitting(const int *mcache_boundaries, int num_boundaries, int shift,
23 	int pipe_h_vp_start, int pipe_h_vp_end, int *first_offset, int *second_offset)
24 {
25 	const int MAX_VP = 0xFFFFFF;
26 	int left_cache_id;
27 	int right_cache_id;
28 	int range_start;
29 	int range_end;
30 	bool success = false;
31 
32 	if (num_boundaries <= 1) {
33 		if (first_offset && second_offset) {
34 			*first_offset = 0;
35 			*second_offset = -1;
36 		}
37 		success = true;
38 		return success;
39 	} else {
40 		range_start = 0;
41 		for (left_cache_id = 0; left_cache_id < num_boundaries; left_cache_id++) {
42 			range_end = mcache_boundaries[left_cache_id] - shift - 1;
43 
44 			if (range_start <= pipe_h_vp_start && pipe_h_vp_start <= range_end)
45 				break;
46 
47 			range_start = range_end + 1;
48 		}
49 
50 		range_end = MAX_VP;
51 		for (right_cache_id = num_boundaries - 1; right_cache_id >= -1; right_cache_id--) {
52 			if (right_cache_id >= 0)
53 				range_start = mcache_boundaries[right_cache_id] - shift;
54 			else
55 				range_start = 0;
56 
57 			if (range_start <= pipe_h_vp_end && pipe_h_vp_end <= range_end) {
58 				break;
59 			}
60 			range_end = range_start - 1;
61 		}
62 		right_cache_id = (right_cache_id + 1) % num_boundaries;
63 
64 		if (right_cache_id == left_cache_id) {
65 			if (first_offset && second_offset) {
66 				*first_offset = left_cache_id;
67 				*second_offset = -1;
68 			}
69 			success = true;
70 		} else if (right_cache_id == (left_cache_id + 1) % num_boundaries) {
71 			if (first_offset && second_offset) {
72 				*first_offset = left_cache_id;
73 				*second_offset = right_cache_id;
74 			}
75 			success = true;
76 		}
77 	}
78 
79 	return success;
80 }
81 
82 /*
83 * For a given set of pipe start/end x positions, checks to see it can support the input mcache splitting.
84 * It also attempts to "optimize" by finding a shift if the default 0 shift does not work.
85 */
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)86 static bool find_shift_for_valid_cache_id_assignment(int *mcache_boundaries, unsigned int num_boundaries,
87 	int *pipe_vp_startx, int *pipe_vp_endx, unsigned int pipe_count, int shift_granularity, int *shift)
88 {
89 	int max_shift = 0xFFFF;
90 	unsigned int pipe_index;
91 	unsigned int i, slice_width;
92 	bool success = false;
93 
94 	for (i = 0; i < num_boundaries; i++) {
95 		if (i == 0)
96 			slice_width = mcache_boundaries[i];
97 		else
98 			slice_width = mcache_boundaries[i] - mcache_boundaries[i - 1];
99 
100 		if (max_shift > (int)slice_width) {
101 			max_shift = slice_width;
102 		}
103 	}
104 
105 	for (*shift = 0; *shift <= max_shift; *shift += shift_granularity) {
106 		success = true;
107 		for (pipe_index = 0; pipe_index < pipe_count; pipe_index++) {
108 			if (!calculate_first_second_splitting(mcache_boundaries, num_boundaries, *shift,
109 				pipe_vp_startx[pipe_index], pipe_vp_endx[pipe_index], 0, 0)) {
110 				success = false;
111 				break;
112 			}
113 		}
114 		if (success)
115 			break;
116 	}
117 
118 	return success;
119 }
120 
121 /*
122 * Counts the number of elements inside input array within the given span length.
123 * Formally, what is the size of the largest subset of the array where the largest and smallest element
124 * differ no more than the span.
125 */
count_elements_in_span(int * array,unsigned int array_size,unsigned int span)126 static unsigned int count_elements_in_span(int *array, unsigned int array_size, unsigned int span)
127 {
128 	unsigned int i;
129 	unsigned int span_start_value;
130 	unsigned int span_start_index;
131 	unsigned int greatest_element_count;
132 
133 	if (array_size == 0)
134 		return 1;
135 
136 	if (span == 0)
137 		return array_size > 0 ? 1 : 0;
138 
139 	span_start_value = 0;
140 	span_start_index = 0;
141 	greatest_element_count = 0;
142 
143 	while (span_start_index < array_size) {
144 		for (i = span_start_index; i < array_size; i++) {
145 			if (array[i] - span_start_value <= span) {
146 				if (i - span_start_index + 1 > greatest_element_count) {
147 					greatest_element_count = i - span_start_index + 1;
148 				}
149 			} else
150 				break;
151 		}
152 
153 		span_start_index++;
154 
155 		if (span_start_index < array_size) {
156 			span_start_value = array[span_start_index - 1] + 1;
157 		}
158 	}
159 
160 	return greatest_element_count;
161 }
162 
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)163 static bool calculate_h_split_for_scaling_transform(int full_vp_width, int h_active, int num_pipes,
164 	enum dml2_scaling_transform scaling_transform, int *pipe_vp_x_start, int *pipe_vp_x_end)
165 {
166 	int i, slice_width;
167 	const char MAX_SCL_VP_OVERLAP = 3;
168 	bool success = false;
169 
170 	switch (scaling_transform) {
171 	case dml2_scaling_transform_centered:
172 	case dml2_scaling_transform_aspect_ratio:
173 	case dml2_scaling_transform_fullscreen:
174 		slice_width = full_vp_width / num_pipes;
175 		for (i = 0; i < num_pipes; i++) {
176 			pipe_vp_x_start[i] = i * slice_width;
177 			pipe_vp_x_end[i] = (i + 1) * slice_width - 1;
178 
179 			if (pipe_vp_x_start[i] < MAX_SCL_VP_OVERLAP)
180 				pipe_vp_x_start[i] = 0;
181 			else
182 				pipe_vp_x_start[i] -= MAX_SCL_VP_OVERLAP;
183 
184 			if (pipe_vp_x_end[i] > full_vp_width - MAX_SCL_VP_OVERLAP - 1)
185 				pipe_vp_x_end[i] = full_vp_width - 1;
186 			else
187 				pipe_vp_x_end[i] += MAX_SCL_VP_OVERLAP;
188 		}
189 		break;
190 	case dml2_scaling_transform_explicit:
191 	default:
192 		success = false;
193 		break;
194 	}
195 
196 	return success;
197 }
198 
dml2_top_mcache_validate_admissability(struct top_mcache_validate_admissability_in_out * params)199 bool dml2_top_mcache_validate_admissability(struct top_mcache_validate_admissability_in_out *params)
200 {
201 	struct dml2_instance *dml = (struct dml2_instance *)params->dml2_instance;
202 	struct dml2_top_mcache_validate_admissability_locals *l = &dml->scratch.mcache_validate_admissability_locals;
203 
204 	const int MAX_PIXEL_OVERLAP = 6;
205 	int max_per_pipe_vp_p0 = 0;
206 	int max_per_pipe_vp_p1 = 0;
207 	int temp, p0shift, p1shift;
208 	unsigned int plane_index = 0;
209 	unsigned int i;
210 	unsigned int odm_combine_factor;
211 	unsigned int mpc_combine_factor;
212 	unsigned int num_dpps;
213 	unsigned int num_boundaries;
214 	enum dml2_scaling_transform scaling_transform;
215 	const struct dml2_plane_parameters *plane;
216 	const struct dml2_stream_parameters *stream;
217 
218 	bool p0pass = false;
219 	bool p1pass = false;
220 	bool all_pass = true;
221 
222 	for (plane_index = 0; plane_index < params->display_cfg->num_planes; plane_index++) {
223 		if (!params->display_cfg->plane_descriptors[plane_index].surface.dcc.enable)
224 			continue;
225 
226 		plane = &params->display_cfg->plane_descriptors[plane_index];
227 		stream = &params->display_cfg->stream_descriptors[plane->stream_index];
228 
229 		num_dpps = odm_combine_factor = params->cfg_support_info->stream_support_info[plane->stream_index].odms_used;
230 
231 		if (odm_combine_factor == 1)
232 			num_dpps = mpc_combine_factor = (unsigned int)params->cfg_support_info->plane_support_info[plane_index].dpps_used;
233 		else
234 			mpc_combine_factor = 1;
235 
236 		if (odm_combine_factor > 1) {
237 			max_per_pipe_vp_p0 = plane->surface.plane0.width;
238 			temp = (unsigned int)math_ceil(plane->composition.scaler_info.plane0.h_ratio * stream->timing.h_active / odm_combine_factor);
239 
240 			if (temp < max_per_pipe_vp_p0)
241 				max_per_pipe_vp_p0 = temp;
242 
243 			max_per_pipe_vp_p1 = plane->surface.plane1.width;
244 			temp = (unsigned int)math_ceil(plane->composition.scaler_info.plane1.h_ratio * stream->timing.h_active / odm_combine_factor);
245 
246 			if (temp < max_per_pipe_vp_p1)
247 				max_per_pipe_vp_p1 = temp;
248 		} else {
249 			max_per_pipe_vp_p0 = plane->surface.plane0.width / mpc_combine_factor;
250 			max_per_pipe_vp_p1 = plane->surface.plane1.width / mpc_combine_factor;
251 		}
252 
253 		max_per_pipe_vp_p0 += 2 * MAX_PIXEL_OVERLAP;
254 		max_per_pipe_vp_p1 += MAX_PIXEL_OVERLAP;
255 
256 		p0shift = 0;
257 		p1shift = 0;
258 
259 		// The last element in the unshifted boundary array will always be the first pixel outside the
260 		// plane, which means theres no mcache associated with it, so -1
261 		num_boundaries = params->mcache_allocations[plane_index].num_mcaches_plane0 == 0 ? 0 : params->mcache_allocations[plane_index].num_mcaches_plane0 - 1;
262 		if ((count_elements_in_span(params->mcache_allocations[plane_index].mcache_x_offsets_plane0,
263 			num_boundaries, max_per_pipe_vp_p0) <= 1) && (num_boundaries <= num_dpps)) {
264 			p0pass = true;
265 		}
266 		num_boundaries = params->mcache_allocations[plane_index].num_mcaches_plane1 == 0 ? 0 : params->mcache_allocations[plane_index].num_mcaches_plane1 - 1;
267 		if ((count_elements_in_span(params->mcache_allocations[plane_index].mcache_x_offsets_plane1,
268 			num_boundaries, max_per_pipe_vp_p1) <= 1) && (num_boundaries <= num_dpps)) {
269 			p1pass = true;
270 		}
271 
272 		if (!p0pass || !p1pass) {
273 			if (odm_combine_factor > 1) {
274 				num_dpps = odm_combine_factor;
275 				scaling_transform = plane->composition.scaling_transform;
276 			} else {
277 				num_dpps = mpc_combine_factor;
278 				scaling_transform = dml2_scaling_transform_fullscreen;
279 			}
280 
281 			if (!p0pass) {
282 				if (plane->composition.viewport.stationary) {
283 					calculate_h_split_for_scaling_transform(plane->surface.plane0.width,
284 						stream->timing.h_active, num_dpps, scaling_transform,
285 						&l->plane0.pipe_vp_startx[plane_index], &l->plane0.pipe_vp_endx[plane_index]);
286 					p0pass = find_shift_for_valid_cache_id_assignment(params->mcache_allocations[plane_index].mcache_x_offsets_plane0,
287 						params->mcache_allocations[plane_index].num_mcaches_plane0,
288 						&l->plane0.pipe_vp_startx[plane_index], &l->plane0.pipe_vp_endx[plane_index], num_dpps,
289 						params->mcache_allocations[plane_index].shift_granularity.p0, &p0shift);
290 				}
291 			}
292 			if (!p1pass) {
293 				if (plane->composition.viewport.stationary) {
294 					calculate_h_split_for_scaling_transform(plane->surface.plane1.width,
295 						stream->timing.h_active, num_dpps, scaling_transform,
296 						&l->plane0.pipe_vp_startx[plane_index], &l->plane0.pipe_vp_endx[plane_index]);
297 					p1pass = find_shift_for_valid_cache_id_assignment(params->mcache_allocations[plane_index].mcache_x_offsets_plane1,
298 						params->mcache_allocations[plane_index].num_mcaches_plane1,
299 						&l->plane1.pipe_vp_startx[plane_index], &l->plane1.pipe_vp_endx[plane_index], num_dpps,
300 						params->mcache_allocations[plane_index].shift_granularity.p1, &p1shift);
301 				}
302 			}
303 		}
304 
305 		if (p0pass && p1pass) {
306 			for (i = 0; i < params->mcache_allocations[plane_index].num_mcaches_plane0; i++) {
307 				params->mcache_allocations[plane_index].mcache_x_offsets_plane0[i] -= p0shift;
308 			}
309 			for (i = 0; i < params->mcache_allocations[plane_index].num_mcaches_plane1; i++) {
310 				params->mcache_allocations[plane_index].mcache_x_offsets_plane1[i] -= p1shift;
311 			}
312 		}
313 
314 		params->per_plane_status[plane_index] = p0pass && p1pass;
315 		all_pass &= p0pass && p1pass;
316 	}
317 
318 	return all_pass;
319 }
320 
reset_mcache_allocations(struct dml2_hubp_pipe_mcache_regs * per_plane_pipe_mcache_regs)321 static void reset_mcache_allocations(struct dml2_hubp_pipe_mcache_regs *per_plane_pipe_mcache_regs)
322 {
323 	// Initialize all entries to special valid MCache ID and special valid split coordinate
324 	per_plane_pipe_mcache_regs->main.p0.mcache_id_first = MCACHE_ID_UNASSIGNED;
325 	per_plane_pipe_mcache_regs->main.p0.mcache_id_second = MCACHE_ID_UNASSIGNED;
326 	per_plane_pipe_mcache_regs->main.p0.split_location = SPLIT_LOCATION_UNDEFINED;
327 
328 	per_plane_pipe_mcache_regs->mall.p0.mcache_id_first = MCACHE_ID_UNASSIGNED;
329 	per_plane_pipe_mcache_regs->mall.p0.mcache_id_second = MCACHE_ID_UNASSIGNED;
330 	per_plane_pipe_mcache_regs->mall.p0.split_location = SPLIT_LOCATION_UNDEFINED;
331 
332 	per_plane_pipe_mcache_regs->main.p1.mcache_id_first = MCACHE_ID_UNASSIGNED;
333 	per_plane_pipe_mcache_regs->main.p1.mcache_id_second = MCACHE_ID_UNASSIGNED;
334 	per_plane_pipe_mcache_regs->main.p1.split_location = SPLIT_LOCATION_UNDEFINED;
335 
336 	per_plane_pipe_mcache_regs->mall.p1.mcache_id_first = MCACHE_ID_UNASSIGNED;
337 	per_plane_pipe_mcache_regs->mall.p1.mcache_id_second = MCACHE_ID_UNASSIGNED;
338 	per_plane_pipe_mcache_regs->mall.p1.split_location = SPLIT_LOCATION_UNDEFINED;
339 }
340 
dml2_top_mcache_build_mcache_programming(struct dml2_build_mcache_programming_in_out * params)341 bool dml2_top_mcache_build_mcache_programming(struct dml2_build_mcache_programming_in_out *params)
342 {
343 	bool success = true;
344 	int config_index, pipe_index;
345 	int first_offset, second_offset;
346 	int free_per_plane_reg_index = 0;
347 
348 	memset(params->per_plane_pipe_mcache_regs, 0, DML2_MAX_PLANES * DML2_MAX_DCN_PIPES * sizeof(struct dml2_hubp_pipe_mcache_regs *));
349 
350 	for (config_index = 0; config_index < params->num_configurations; config_index++) {
351 		for (pipe_index = 0; pipe_index < params->mcache_configurations[config_index].num_pipes; pipe_index++) {
352 			// Allocate storage for the mcache regs
353 			params->per_plane_pipe_mcache_regs[config_index][pipe_index] = &params->mcache_regs_set[free_per_plane_reg_index++];
354 
355 			reset_mcache_allocations(params->per_plane_pipe_mcache_regs[config_index][pipe_index]);
356 
357 			if (params->mcache_configurations[config_index].plane_descriptor->surface.dcc.enable) {
358 				// P0 always enabled
359 				if (!calculate_first_second_splitting(params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane0,
360 					params->mcache_configurations[config_index].mcache_allocation->num_mcaches_plane0,
361 					0,
362 					params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane0.viewport_x_start,
363 					params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane0.viewport_x_start +
364 					params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane0.viewport_width - 1,
365 					&first_offset, &second_offset)) {
366 					success = false;
367 					break;
368 				}
369 
370 				params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p0.mcache_id_first =
371 					params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane0[first_offset];
372 
373 				params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p0.mcache_id_first =
374 					params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane0[first_offset];
375 
376 				if (second_offset >= 0) {
377 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p0.mcache_id_second =
378 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane0[second_offset];
379 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p0.split_location =
380 						params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane0[first_offset] - 1;
381 
382 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p0.mcache_id_second =
383 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane0[second_offset];
384 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p0.split_location =
385 						params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane0[first_offset] - 1;
386 				}
387 
388 				// Populate P1 if enabled
389 				if (params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1_enabled) {
390 					if (!calculate_first_second_splitting(params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane1,
391 						params->mcache_configurations[config_index].mcache_allocation->num_mcaches_plane1,
392 						0,
393 						params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1.viewport_x_start,
394 						params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1.viewport_x_start +
395 						params->mcache_configurations[config_index].pipe_configurations[pipe_index].plane1.viewport_width - 1,
396 						&first_offset, &second_offset)) {
397 						success = false;
398 						break;
399 					}
400 
401 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p1.mcache_id_first =
402 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane1[first_offset];
403 
404 					params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p1.mcache_id_first =
405 						params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane1[first_offset];
406 
407 					if (second_offset >= 0) {
408 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p1.mcache_id_second =
409 							params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_plane1[second_offset];
410 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->main.p1.split_location =
411 							params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane1[first_offset] - 1;
412 
413 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p1.mcache_id_second =
414 							params->mcache_configurations[config_index].mcache_allocation->global_mcache_ids_mall_plane1[second_offset];
415 						params->per_plane_pipe_mcache_regs[config_index][pipe_index]->mall.p1.split_location =
416 							params->mcache_configurations[config_index].mcache_allocation->mcache_x_offsets_plane1[first_offset] - 1;
417 					}
418 				}
419 			}
420 		}
421 	}
422 
423 	return success;
424 }
425 
dml2_top_mcache_assign_global_mcache_ids(struct top_mcache_assign_global_mcache_ids_in_out * params)426 void dml2_top_mcache_assign_global_mcache_ids(struct top_mcache_assign_global_mcache_ids_in_out *params)
427 {
428 	int i;
429 	unsigned int j;
430 	int next_unused_cache_id = 0;
431 
432 	for (i = 0; i < params->num_allocations; i++) {
433 		if (!params->allocations[i].valid)
434 			continue;
435 
436 		for (j = 0; j < params->allocations[i].num_mcaches_plane0; j++) {
437 			params->allocations[i].global_mcache_ids_plane0[j] = next_unused_cache_id++;
438 		}
439 		for (j = 0; j < params->allocations[i].num_mcaches_plane1; j++) {
440 			params->allocations[i].global_mcache_ids_plane1[j] = next_unused_cache_id++;
441 		}
442 
443 		// The "psuedo-last" slice is always wrapped around
444 		params->allocations[i].global_mcache_ids_plane0[params->allocations[i].num_mcaches_plane0] =
445 			params->allocations[i].global_mcache_ids_plane0[0];
446 		params->allocations[i].global_mcache_ids_plane1[params->allocations[i].num_mcaches_plane1] =
447 			params->allocations[i].global_mcache_ids_plane1[0];
448 
449 		// If we need dedicated caches for mall requesting, then we assign them here.
450 		if (params->allocations[i].requires_dedicated_mall_mcache) {
451 			for (j = 0; j < params->allocations[i].num_mcaches_plane0; j++) {
452 				params->allocations[i].global_mcache_ids_mall_plane0[j] = next_unused_cache_id++;
453 			}
454 			for (j = 0; j < params->allocations[i].num_mcaches_plane1; j++) {
455 				params->allocations[i].global_mcache_ids_mall_plane1[j] = next_unused_cache_id++;
456 			}
457 
458 			// The "psuedo-last" slice is always wrapped around
459 			params->allocations[i].global_mcache_ids_mall_plane0[params->allocations[i].num_mcaches_plane0] =
460 				params->allocations[i].global_mcache_ids_mall_plane0[0];
461 			params->allocations[i].global_mcache_ids_mall_plane1[params->allocations[i].num_mcaches_plane1] =
462 				params->allocations[i].global_mcache_ids_mall_plane1[0];
463 		}
464 
465 		// If P0 and P1 are sharing caches, then it means the largest mcache IDs for p0 and p1 can be the same
466 		// since mcache IDs are always ascending, then it means the largest mcacheID of p1 should be the
467 		// largest mcacheID of P0
468 		if (params->allocations[i].num_mcaches_plane0 > 0 && params->allocations[i].num_mcaches_plane1 > 0 &&
469 			params->allocations[i].last_slice_sharing.plane0_plane1) {
470 			params->allocations[i].global_mcache_ids_plane1[params->allocations[i].num_mcaches_plane1 - 1] =
471 				params->allocations[i].global_mcache_ids_plane0[params->allocations[i].num_mcaches_plane0 - 1];
472 		}
473 
474 		// If we need dedicated caches handle last slice sharing
475 		if (params->allocations[i].requires_dedicated_mall_mcache) {
476 			if (params->allocations[i].num_mcaches_plane0 > 0 && params->allocations[i].num_mcaches_plane1 > 0 &&
477 				params->allocations[i].last_slice_sharing.plane0_plane1) {
478 				params->allocations[i].global_mcache_ids_mall_plane1[params->allocations[i].num_mcaches_plane1 - 1] =
479 					params->allocations[i].global_mcache_ids_mall_plane0[params->allocations[i].num_mcaches_plane0 - 1];
480 			}
481 			// If mall_comb_mcache_l is set then it means that largest mcache ID for MALL p0 can be same as regular read p0
482 			if (params->allocations[i].num_mcaches_plane0 > 0 && params->allocations[i].last_slice_sharing.mall_comb_mcache_p0) {
483 				params->allocations[i].global_mcache_ids_mall_plane0[params->allocations[i].num_mcaches_plane0 - 1] =
484 					params->allocations[i].global_mcache_ids_plane0[params->allocations[i].num_mcaches_plane0 - 1];
485 			}
486 			// If mall_comb_mcache_c is set then it means that largest mcache ID for MALL p1 can be same as regular
487 			// read p1 (which can be same as regular read p0 if plane0_plane1 is also set)
488 			if (params->allocations[i].num_mcaches_plane1 > 0 && params->allocations[i].last_slice_sharing.mall_comb_mcache_p1) {
489 				params->allocations[i].global_mcache_ids_mall_plane1[params->allocations[i].num_mcaches_plane1 - 1] =
490 					params->allocations[i].global_mcache_ids_plane1[params->allocations[i].num_mcaches_plane1 - 1];
491 			}
492 		}
493 
494 		// If you don't need dedicated mall mcaches, the mall mcache assignments are identical to the normal requesting
495 		if (!params->allocations[i].requires_dedicated_mall_mcache) {
496 			memcpy(params->allocations[i].global_mcache_ids_mall_plane0, params->allocations[i].global_mcache_ids_plane0,
497 				sizeof(params->allocations[i].global_mcache_ids_mall_plane0));
498 			memcpy(params->allocations[i].global_mcache_ids_mall_plane1, params->allocations[i].global_mcache_ids_plane1,
499 				sizeof(params->allocations[i].global_mcache_ids_mall_plane1));
500 		}
501 	}
502 }
503 
dml2_top_mcache_calc_mcache_count_and_offsets(struct top_mcache_calc_mcache_count_and_offsets_in_out * params)504 bool dml2_top_mcache_calc_mcache_count_and_offsets(struct top_mcache_calc_mcache_count_and_offsets_in_out *params)
505 {
506 	struct dml2_instance *dml = (struct dml2_instance *)params->dml2_instance;
507 	struct dml2_top_mcache_verify_mcache_size_locals *l = &dml->scratch.mcache_verify_mcache_size_locals;
508 
509 	unsigned int total_mcaches_required;
510 	unsigned int i;
511 	bool result = false;
512 
513 	if (dml->soc_bbox.num_dcc_mcaches == 0) {
514 		return true;
515 	}
516 
517 	total_mcaches_required = 0;
518 	l->calc_mcache_params.instance = &dml->core_instance;
519 	for (i = 0; i < params->display_config->num_planes; i++) {
520 		if (!params->display_config->plane_descriptors[i].surface.dcc.enable) {
521 			memset(&params->mcache_allocations[i], 0, sizeof(struct dml2_mcache_surface_allocation));
522 			continue;
523 		}
524 
525 		l->calc_mcache_params.plane_descriptor = &params->display_config->plane_descriptors[i];
526 		l->calc_mcache_params.mcache_allocation = &params->mcache_allocations[i];
527 		l->calc_mcache_params.plane_index = i;
528 
529 		if (!dml->core_instance.calculate_mcache_allocation(&l->calc_mcache_params)) {
530 			result = false;
531 			break;
532 		}
533 
534 		if (params->mcache_allocations[i].valid) {
535 			total_mcaches_required += params->mcache_allocations[i].num_mcaches_plane0 + params->mcache_allocations[i].num_mcaches_plane1;
536 			if (params->mcache_allocations[i].last_slice_sharing.plane0_plane1)
537 				total_mcaches_required--;
538 		}
539 	}
540 	dml2_printf("DML_CORE_DCN3::%s: plane_%d, total_mcaches_required=%d\n", __func__, i, total_mcaches_required);
541 
542 	if (total_mcaches_required > dml->soc_bbox.num_dcc_mcaches) {
543 		result = false;
544 	} else {
545 		result = true;
546 	}
547 
548 	return result;
549 }
550