]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / gpu / drm / amd / display / dc / dml2 / dml2_dc_resource_mgmt.c
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Copyright 2023 Advanced Micro Devices, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: AMD
24  *
25  */
26
27 #include "dml2_mall_phantom.h"
28
29 #include "dml2_dc_types.h"
30 #include "dml2_internal_types.h"
31 #include "dml2_utils.h"
32 #include "dml2_dc_resource_mgmt.h"
33
34 #define MAX_ODM_FACTOR 4
35 #define MAX_MPCC_FACTOR 4
36
37 struct dc_plane_pipe_pool {
38         int pipes_assigned_to_plane[MAX_ODM_FACTOR][MAX_MPCC_FACTOR];
39         bool pipe_used[MAX_ODM_FACTOR][MAX_MPCC_FACTOR];
40         int num_pipes_assigned_to_plane_for_mpcc_combine;
41         int num_pipes_assigned_to_plane_for_odm_combine;
42 };
43
44 struct dc_pipe_mapping_scratch {
45         struct {
46                 unsigned int odm_factor;
47                 unsigned int odm_slice_end_x[MAX_PIPES];
48                 struct pipe_ctx *next_higher_pipe_for_odm_slice[MAX_PIPES];
49         } odm_info;
50         struct {
51                 unsigned int mpc_factor;
52                 struct pipe_ctx *prev_odm_pipe;
53         } mpc_info;
54
55         struct dc_plane_pipe_pool pipe_pool;
56 };
57
58 static bool get_plane_id(struct dml2_context *dml2, const struct dc_state *state, const struct dc_plane_state *plane,
59         unsigned int stream_id, unsigned int plane_index, unsigned int *plane_id)
60 {
61         int i, j;
62         bool is_plane_duplicate = dml2->v20.scratch.plane_duplicate_exists;
63
64         if (!plane_id)
65                 return false;
66
67         for (i = 0; i < state->stream_count; i++) {
68                 if (state->streams[i]->stream_id == stream_id) {
69                         for (j = 0; j < state->stream_status[i].plane_count; j++) {
70                                 if (state->stream_status[i].plane_states[j] == plane &&
71                                         (!is_plane_duplicate || (j == plane_index))) {
72                                         *plane_id = (i << 16) | j;
73                                         return true;
74                                 }
75                         }
76                 }
77         }
78
79         return false;
80 }
81
82 static int find_disp_cfg_idx_by_plane_id(struct dml2_dml_to_dc_pipe_mapping *mapping, unsigned int plane_id)
83 {
84         int i;
85
86         for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
87                 if (mapping->disp_cfg_to_plane_id_valid[i] && mapping->disp_cfg_to_plane_id[i] == plane_id)
88                         return  i;
89         }
90
91         ASSERT(false);
92         return __DML2_WRAPPER_MAX_STREAMS_PLANES__;
93 }
94
95 static int find_disp_cfg_idx_by_stream_id(struct dml2_dml_to_dc_pipe_mapping *mapping, unsigned int stream_id)
96 {
97         int i;
98
99         for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
100                 if (mapping->disp_cfg_to_stream_id_valid[i] && mapping->disp_cfg_to_stream_id[i] == stream_id)
101                         return  i;
102         }
103
104         ASSERT(false);
105         return __DML2_WRAPPER_MAX_STREAMS_PLANES__;
106 }
107
108 // The master pipe of a stream is defined as the top pipe in odm slice 0
109 static struct pipe_ctx *find_master_pipe_of_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int stream_id)
110 {
111         int i;
112
113         for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
114                 if (state->res_ctx.pipe_ctx[i].stream && state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) {
115                         if (!state->res_ctx.pipe_ctx[i].prev_odm_pipe && !state->res_ctx.pipe_ctx[i].top_pipe)
116                                 return &state->res_ctx.pipe_ctx[i];
117                 }
118         }
119
120         return NULL;
121 }
122
123 static struct pipe_ctx *find_master_pipe_of_plane(struct dml2_context *ctx,
124         struct dc_state *state, unsigned int plane_id)
125 {
126         int i;
127         unsigned int plane_id_assigned_to_pipe;
128
129         for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
130                 if (state->res_ctx.pipe_ctx[i].plane_state && get_plane_id(ctx, state, state->res_ctx.pipe_ctx[i].plane_state,
131                         state->res_ctx.pipe_ctx[i].stream->stream_id,
132                         ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[state->res_ctx.pipe_ctx[i].pipe_idx], &plane_id_assigned_to_pipe)) {
133                         if (plane_id_assigned_to_pipe == plane_id)
134                                 return &state->res_ctx.pipe_ctx[i];
135                 }
136         }
137
138         return NULL;
139 }
140
141 static unsigned int find_pipes_assigned_to_plane(struct dml2_context *ctx,
142         struct dc_state *state, unsigned int plane_id, unsigned int *pipes)
143 {
144         int i;
145         unsigned int num_found = 0;
146         unsigned int plane_id_assigned_to_pipe = -1;
147
148         for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
149                 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
150
151                 if (!pipe->plane_state || !pipe->stream)
152                         continue;
153
154                 get_plane_id(ctx, state, pipe->plane_state, pipe->stream->stream_id,
155                                         ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[pipe->pipe_idx],
156                                         &plane_id_assigned_to_pipe);
157                 if (plane_id_assigned_to_pipe == plane_id && !pipe->prev_odm_pipe
158                                 && (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) {
159                         while (pipe) {
160                                 struct pipe_ctx *mpc_pipe = pipe;
161
162                                 while (mpc_pipe) {
163                                         pipes[num_found++] = mpc_pipe->pipe_idx;
164                                         mpc_pipe = mpc_pipe->bottom_pipe;
165                                         if (!mpc_pipe)
166                                                 break;
167                                         if (mpc_pipe->plane_state != pipe->plane_state)
168                                                 mpc_pipe = NULL;
169                                 }
170                                 pipe = pipe->next_odm_pipe;
171                         }
172                         break;
173                 }
174         }
175
176         return num_found;
177 }
178
179 static bool validate_pipe_assignment(const struct dml2_context *ctx, const struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, const struct dml2_dml_to_dc_pipe_mapping *mapping)
180 {
181 //      int i, j, k;
182 //
183 //      unsigned int plane_id;
184 //
185 //      unsigned int disp_cfg_index;
186 //
187 //      unsigned int pipes_assigned_to_plane[MAX_PIPES];
188 //      unsigned int num_pipes_assigned_to_plane;
189 //
190 //      struct pipe_ctx *top_pipe;
191 //
192 //      for (i = 0; i < state->stream_count; i++) {
193 //              for (j = 0; j < state->stream_status[i]->plane_count; j++) {
194 //                      if (get_plane_id(state, state->stream_status.plane_states[j], &plane_id)) {
195 //                              disp_cfg_index = find_disp_cfg_idx_by_plane_id(mapping, plane_id);
196 //                              num_pipes_assigned_to_plane = find_pipes_assigned_to_plane(ctx, state, plane_id, pipes_assigned_to_plane);
197 //
198 //                              if (disp_cfg_index >= 0 && num_pipes_assigned_to_plane > 0) {
199 //                                      // Verify the number of pipes assigned matches
200 //                                      if (disp_cfg->hw.DPPPerSurface != num_pipes_assigned_to_plane)
201 //                                              return false;
202 //
203 //                                      top_pipe = find_top_pipe_in_tree(state->res_ctx.pipe_ctx[pipes_assigned_to_plane[0]]);
204 //
205 //                                      // Verify MPC and ODM combine
206 //                                      if (disp_cfg->hw.ODMMode == dml_odm_mode_bypass) {
207 //                                              verify_combine_tree(top_pipe, state->streams[i]->stream_id, plane_id, state, false);
208 //                                      } else {
209 //                                              verify_combine_tree(top_pipe, state->streams[i]->stream_id, plane_id, state, true);
210 //                                      }
211 //
212 //                                      // TODO: could also do additional verification that the pipes in tree are the same as
213 //                                      // pipes_assigned_to_plane
214 //                              } else {
215 //                                      ASSERT(false);
216 //                                      return false;
217 //                              }
218 //                      } else {
219 //                              ASSERT(false);
220 //                              return false;
221 //                      }
222 //              }
223 //      }
224         return true;
225 }
226
227 static bool is_plane_using_pipe(const struct pipe_ctx *pipe)
228 {
229         if (pipe->plane_state)
230                 return true;
231
232         return false;
233 }
234
235 static bool is_pipe_free(const struct pipe_ctx *pipe)
236 {
237         if (!pipe->plane_state && !pipe->stream)
238                 return true;
239
240         return false;
241 }
242
243 static unsigned int find_preferred_pipe_candidates(const struct dc_state *existing_state,
244         const int pipe_count,
245         const unsigned int stream_id,
246         unsigned int *preferred_pipe_candidates)
247 {
248         unsigned int num_preferred_candidates = 0;
249         int i;
250
251         /* There is only one case which we consider for adding a pipe to the preferred
252          * pipe candidate array:
253          *
254          * 1. If the existing stream id of the pipe is equivalent to the stream id
255          * of the stream we are trying to achieve MPC/ODM combine for. This allows
256          * us to minimize the changes in pipe topology during the transition.
257          *
258          * However this condition comes with a caveat. We need to ignore pipes that will
259          * require a change in OPP but still have the same stream id. For example during
260          * an MPC to ODM transiton.
261          */
262         if (existing_state) {
263                 for (i = 0; i < pipe_count; i++) {
264                         if (existing_state->res_ctx.pipe_ctx[i].stream && existing_state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) {
265                                 if (existing_state->res_ctx.pipe_ctx[i].plane_res.hubp &&
266                                         existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i)
267                                         continue;
268
269                                 preferred_pipe_candidates[num_preferred_candidates++] = i;
270                         }
271                 }
272         }
273
274         return num_preferred_candidates;
275 }
276
277 static unsigned int find_last_resort_pipe_candidates(const struct dc_state *existing_state,
278         const int pipe_count,
279         const unsigned int stream_id,
280         unsigned int *last_resort_pipe_candidates)
281 {
282         unsigned int num_last_resort_candidates = 0;
283         int i;
284
285         /* There are two cases where we would like to add a given pipe into the last
286          * candidate array:
287          *
288          * 1. If the pipe requires a change in OPP, for example during an MPC
289          * to ODM transiton.
290          *
291          * 2. If the pipe already has an enabled OTG.
292          */
293         if (existing_state) {
294                 for (i  = 0; i < pipe_count; i++) {
295                         if ((existing_state->res_ctx.pipe_ctx[i].plane_res.hubp &&
296                                 existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i) ||
297                                 existing_state->res_ctx.pipe_ctx[i].stream_res.tg)
298                                 last_resort_pipe_candidates[num_last_resort_candidates++] = i;
299                 }
300         }
301
302         return num_last_resort_candidates;
303 }
304
305 static bool is_pipe_in_candidate_array(const unsigned int pipe_idx,
306         const unsigned int *candidate_array,
307         const unsigned int candidate_array_size)
308 {
309         int i;
310
311         for (i = 0; i < candidate_array_size; i++) {
312                 if (candidate_array[i] == pipe_idx)
313                         return true;
314         }
315
316         return false;
317 }
318
319 static bool find_more_pipes_for_stream(struct dml2_context *ctx,
320         struct dc_state *state, // The state we want to find a free mapping in
321         unsigned int stream_id, // The stream we want this pipe to drive
322         int *assigned_pipes,
323         int *assigned_pipe_count,
324         int pipes_needed,
325         const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to
326 {
327         struct pipe_ctx *pipe = NULL;
328         unsigned int preferred_pipe_candidates[MAX_PIPES] = {0};
329         unsigned int last_resort_pipe_candidates[MAX_PIPES] = {0};
330         unsigned int num_preferred_candidates = 0;
331         unsigned int num_last_resort_candidates = 0;
332         int i;
333
334         if (existing_state) {
335                 num_preferred_candidates =
336                         find_preferred_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, preferred_pipe_candidates);
337
338                 num_last_resort_candidates =
339                         find_last_resort_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, last_resort_pipe_candidates);
340         }
341
342         // First see if any of the preferred are unmapped, and choose those instead
343         for (i = 0; pipes_needed > 0 && i < num_preferred_candidates; i++) {
344                 pipe = &state->res_ctx.pipe_ctx[preferred_pipe_candidates[i]];
345                 if (!is_plane_using_pipe(pipe)) {
346                         pipes_needed--;
347                         // TODO: This doens't make sense really, pipe_idx should always be valid
348                         pipe->pipe_idx = preferred_pipe_candidates[i];
349                         assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx;
350                 }
351         }
352
353         // We like to pair pipes starting from the higher order indicies for combining
354         for (i = ctx->config.dcn_pipe_count - 1; pipes_needed > 0 && i >= 0; i--) {
355                 // Ignore any pipes that are the preferred or last resort candidate
356                 if (is_pipe_in_candidate_array(i, preferred_pipe_candidates, num_preferred_candidates) ||
357                         is_pipe_in_candidate_array(i, last_resort_pipe_candidates, num_last_resort_candidates))
358                         continue;
359
360                 pipe = &state->res_ctx.pipe_ctx[i];
361                 if (!is_plane_using_pipe(pipe)) {
362                         pipes_needed--;
363                         // TODO: This doens't make sense really, pipe_idx should always be valid
364                         pipe->pipe_idx = i;
365                         assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx;
366                 }
367         }
368
369         // Only use the last resort pipe candidates as a last resort
370         for (i = 0; pipes_needed > 0 && i < num_last_resort_candidates; i++) {
371                 pipe = &state->res_ctx.pipe_ctx[last_resort_pipe_candidates[i]];
372                 if (!is_plane_using_pipe(pipe)) {
373                         pipes_needed--;
374                         // TODO: This doens't make sense really, pipe_idx should always be valid
375                         pipe->pipe_idx = last_resort_pipe_candidates[i];
376                         assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx;
377                 }
378         }
379
380         ASSERT(pipes_needed <= 0); // Validation should prevent us from building a pipe context that exceeds the number of HW resoruces available
381
382         return pipes_needed <= 0;
383 }
384
385 static bool find_more_free_pipes(struct dml2_context *ctx,
386         struct dc_state *state, // The state we want to find a free mapping in
387         unsigned int stream_id, // The stream we want this pipe to drive
388         int *assigned_pipes,
389         int *assigned_pipe_count,
390         int pipes_needed,
391         const struct dc_state *existing_state) // The state (optional) that we want to minimize remapping relative to
392 {
393         struct pipe_ctx *pipe = NULL;
394         unsigned int preferred_pipe_candidates[MAX_PIPES] = {0};
395         unsigned int last_resort_pipe_candidates[MAX_PIPES] = {0};
396         unsigned int num_preferred_candidates = 0;
397         unsigned int num_last_resort_candidates = 0;
398         int i;
399
400         if (existing_state) {
401                 num_preferred_candidates =
402                         find_preferred_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, preferred_pipe_candidates);
403
404                 num_last_resort_candidates =
405                         find_last_resort_pipe_candidates(existing_state, ctx->config.dcn_pipe_count, stream_id, last_resort_pipe_candidates);
406         }
407
408         // First see if any of the preferred are unmapped, and choose those instead
409         for (i = 0; pipes_needed > 0 && i < num_preferred_candidates; i++) {
410                 pipe = &state->res_ctx.pipe_ctx[preferred_pipe_candidates[i]];
411                 if (is_pipe_free(pipe)) {
412                         pipes_needed--;
413                         // TODO: This doens't make sense really, pipe_idx should always be valid
414                         pipe->pipe_idx = preferred_pipe_candidates[i];
415                         assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx;
416                 }
417         }
418
419         // We like to pair pipes starting from the higher order indicies for combining
420         for (i = ctx->config.dcn_pipe_count - 1; pipes_needed > 0 && i >= 0; i--) {
421                 // Ignore any pipes that are the preferred or last resort candidate
422                 if (is_pipe_in_candidate_array(i, preferred_pipe_candidates, num_preferred_candidates) ||
423                         is_pipe_in_candidate_array(i, last_resort_pipe_candidates, num_last_resort_candidates))
424                         continue;
425
426                 pipe = &state->res_ctx.pipe_ctx[i];
427                 if (is_pipe_free(pipe)) {
428                         pipes_needed--;
429                         // TODO: This doens't make sense really, pipe_idx should always be valid
430                         pipe->pipe_idx = i;
431                         assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx;
432                 }
433         }
434
435         // Only use the last resort pipe candidates as a last resort
436         for (i = 0; pipes_needed > 0 && i < num_last_resort_candidates; i++) {
437                 pipe = &state->res_ctx.pipe_ctx[last_resort_pipe_candidates[i]];
438                 if (is_pipe_free(pipe)) {
439                         pipes_needed--;
440                         // TODO: This doens't make sense really, pipe_idx should always be valid
441                         pipe->pipe_idx = last_resort_pipe_candidates[i];
442                         assigned_pipes[(*assigned_pipe_count)++] = pipe->pipe_idx;
443                 }
444         }
445
446         ASSERT(pipes_needed == 0); // Validation should prevent us from building a pipe context that exceeds the number of HW resoruces available
447
448         return pipes_needed == 0;
449 }
450
451 static void sort_pipes_for_splitting(struct dc_plane_pipe_pool *pipes)
452 {
453         bool sorted, swapped;
454         unsigned int cur_index;
455         unsigned int temp;
456         int odm_slice_index;
457
458         for (odm_slice_index = 0; odm_slice_index < pipes->num_pipes_assigned_to_plane_for_odm_combine; odm_slice_index++) {
459                 // Sort each MPCC set
460                 //Un-optimized bubble sort, but that's okay for array sizes <= 6
461
462                 if (pipes->num_pipes_assigned_to_plane_for_mpcc_combine <= 1)
463                         sorted = true;
464                 else
465                         sorted = false;
466
467                 cur_index = 0;
468                 swapped = false;
469                 while (!sorted) {
470                         if (pipes->pipes_assigned_to_plane[odm_slice_index][cur_index] > pipes->pipes_assigned_to_plane[odm_slice_index][cur_index + 1]) {
471                                 temp = pipes->pipes_assigned_to_plane[odm_slice_index][cur_index];
472                                 pipes->pipes_assigned_to_plane[odm_slice_index][cur_index] = pipes->pipes_assigned_to_plane[odm_slice_index][cur_index + 1];
473                                 pipes->pipes_assigned_to_plane[odm_slice_index][cur_index + 1] = temp;
474
475                                 swapped = true;
476                         }
477
478                         cur_index++;
479
480                         if (cur_index == pipes->num_pipes_assigned_to_plane_for_mpcc_combine - 1) {
481                                 cur_index = 0;
482
483                                 if (swapped)
484                                         sorted = false;
485                                 else
486                                         sorted = true;
487
488                                 swapped = false;
489                         }
490
491                 }
492         }
493 }
494
495 // For example, 3840 x 2160, ODM2:1 has a slice array of [1919, 3839], meaning, slice0 spans h_pixels 0->1919, and slice1 spans 1920->3840
496 static void calculate_odm_slices(const struct dc_stream_state *stream, unsigned int odm_factor, unsigned int *odm_slice_end_x)
497 {
498         unsigned int slice_size = 0;
499         int i;
500
501         if (odm_factor < 1 || odm_factor > 4) {
502                 ASSERT(false);
503                 return;
504         }
505
506         slice_size = stream->src.width / odm_factor;
507
508         for (i = 0; i < odm_factor; i++)
509                 odm_slice_end_x[i] = (slice_size * (i + 1)) - 1;
510
511         odm_slice_end_x[odm_factor - 1] = stream->src.width - 1;
512 }
513
514 static bool is_plane_in_odm_slice(const struct dc_plane_state *plane, unsigned int slice_index, unsigned int *odm_slice_end_x, unsigned int num_slices)
515 {
516         unsigned int slice_start_x, slice_end_x;
517
518         if (slice_index == 0)
519                 slice_start_x = 0;
520         else
521                 slice_start_x = odm_slice_end_x[slice_index - 1] + 1;
522
523         slice_end_x = odm_slice_end_x[slice_index];
524
525         if (plane->clip_rect.x + plane->clip_rect.width < slice_start_x)
526                 return false;
527
528         if (plane->clip_rect.x > slice_end_x)
529                 return false;
530
531         return true;
532 }
533
534 static void add_odm_slice_to_odm_tree(struct dml2_context *ctx,
535                 struct dc_state *state,
536                 struct dc_pipe_mapping_scratch *scratch,
537                 unsigned int odm_slice_index)
538 {
539         struct pipe_ctx *pipe = NULL;
540         int i;
541
542         // MPCC Combine + ODM Combine is not supported, so there should never be a case where the current plane
543         // has more than 1 pipe mapped to it for a given slice.
544         ASSERT(scratch->pipe_pool.num_pipes_assigned_to_plane_for_mpcc_combine == 1 || scratch->pipe_pool.num_pipes_assigned_to_plane_for_odm_combine == 1);
545
546         for (i = 0; i < scratch->pipe_pool.num_pipes_assigned_to_plane_for_mpcc_combine; i++) {
547                 pipe = &state->res_ctx.pipe_ctx[scratch->pipe_pool.pipes_assigned_to_plane[odm_slice_index][i]];
548
549                 if (scratch->mpc_info.prev_odm_pipe)
550                         scratch->mpc_info.prev_odm_pipe->next_odm_pipe = pipe;
551
552                 pipe->prev_odm_pipe = scratch->mpc_info.prev_odm_pipe;
553                 pipe->next_odm_pipe = NULL;
554         }
555         scratch->mpc_info.prev_odm_pipe = pipe;
556 }
557
558 static struct pipe_ctx *add_plane_to_blend_tree(struct dml2_context *ctx,
559         struct dc_state *state,
560         const struct dc_plane_state *plane,
561         struct dc_plane_pipe_pool *pipe_pool,
562         unsigned int odm_slice,
563         struct pipe_ctx *top_pipe)
564 {
565         int i;
566
567         for (i = 0; i < pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine; i++) {
568                 if (top_pipe)
569                         top_pipe->bottom_pipe = &state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]];
570
571                 pipe_pool->pipe_used[odm_slice][i] = true;
572
573                 state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]].top_pipe = top_pipe;
574                 state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]].bottom_pipe = NULL;
575
576                 top_pipe = &state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][i]];
577         }
578
579         // After running the above loop, the top pipe actually ends up pointing to the bottom of this MPCC combine tree, so we are actually
580         // returning the bottom pipe here
581         return top_pipe;
582 }
583
584 static unsigned int find_pipes_assigned_to_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int stream_id, unsigned int *pipes)
585 {
586         int i;
587         unsigned int num_found = 0;
588
589         for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
590                 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
591
592                 if (pipe->stream && pipe->stream->stream_id == stream_id && !pipe->top_pipe && !pipe->prev_odm_pipe) {
593                         while (pipe) {
594                                 pipes[num_found++] = pipe->pipe_idx;
595                                 pipe = pipe->next_odm_pipe;
596                         }
597                         break;
598                 }
599         }
600
601         return num_found;
602 }
603
604 static struct pipe_ctx *assign_pipes_to_stream(struct dml2_context *ctx, struct dc_state *state,
605                 const struct dc_stream_state *stream,
606                 int odm_factor,
607                 struct dc_plane_pipe_pool *pipe_pool,
608                 const struct dc_state *existing_state)
609 {
610         struct pipe_ctx *master_pipe;
611         unsigned int pipes_needed;
612         unsigned int pipes_assigned;
613         unsigned int pipes[MAX_PIPES] = {0};
614         unsigned int next_pipe_to_assign;
615         int odm_slice;
616
617         pipes_needed = odm_factor;
618
619         master_pipe = find_master_pipe_of_stream(ctx, state, stream->stream_id);
620         ASSERT(master_pipe);
621
622         pipes_assigned = find_pipes_assigned_to_stream(ctx, state, stream->stream_id, pipes);
623
624         find_more_free_pipes(ctx, state, stream->stream_id, pipes, &pipes_assigned, pipes_needed - pipes_assigned, existing_state);
625
626         ASSERT(pipes_assigned == pipes_needed);
627
628         next_pipe_to_assign = 0;
629         for (odm_slice = 0; odm_slice < odm_factor; odm_slice++)
630                 pipe_pool->pipes_assigned_to_plane[odm_slice][0] = pipes[next_pipe_to_assign++];
631
632         pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine = 1;
633         pipe_pool->num_pipes_assigned_to_plane_for_odm_combine = odm_factor;
634
635         return master_pipe;
636 }
637
638 static struct pipe_ctx *assign_pipes_to_plane(struct dml2_context *ctx, struct dc_state *state,
639                 const struct dc_stream_state *stream,
640                 const struct dc_plane_state *plane,
641                 int odm_factor,
642                 int mpc_factor,
643                 int plane_index,
644                 struct dc_plane_pipe_pool *pipe_pool,
645                 const struct dc_state *existing_state)
646 {
647         struct pipe_ctx *master_pipe = NULL;
648         unsigned int plane_id;
649         unsigned int pipes_needed;
650         unsigned int pipes_assigned;
651         unsigned int pipes[MAX_PIPES] = {0};
652         unsigned int next_pipe_to_assign;
653         int odm_slice, mpc_slice;
654
655         if (!get_plane_id(ctx, state, plane, stream->stream_id, plane_index, &plane_id)) {
656                 ASSERT(false);
657                 return master_pipe;
658         }
659
660         pipes_needed = mpc_factor * odm_factor;
661
662         master_pipe = find_master_pipe_of_plane(ctx, state, plane_id);
663         ASSERT(master_pipe);
664
665         pipes_assigned = find_pipes_assigned_to_plane(ctx, state, plane_id, pipes);
666
667         find_more_pipes_for_stream(ctx, state, stream->stream_id, pipes, &pipes_assigned, pipes_needed - pipes_assigned, existing_state);
668
669         ASSERT(pipes_assigned >= pipes_needed);
670
671         next_pipe_to_assign = 0;
672         for (odm_slice = 0; odm_slice < odm_factor; odm_slice++)
673                 for (mpc_slice = 0; mpc_slice < mpc_factor; mpc_slice++)
674                         pipe_pool->pipes_assigned_to_plane[odm_slice][mpc_slice] = pipes[next_pipe_to_assign++];
675
676         pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine = mpc_factor;
677         pipe_pool->num_pipes_assigned_to_plane_for_odm_combine = odm_factor;
678
679         return master_pipe;
680 }
681
682 static bool is_pipe_used(const struct dc_plane_pipe_pool *pool, unsigned int pipe_idx)
683 {
684         int i, j;
685
686         for (i = 0; i < pool->num_pipes_assigned_to_plane_for_odm_combine; i++) {
687                 for (j = 0; j < pool->num_pipes_assigned_to_plane_for_mpcc_combine; j++) {
688                         if (pool->pipes_assigned_to_plane[i][j] == pipe_idx && pool->pipe_used[i][j])
689                                 return true;
690                 }
691         }
692
693         return false;
694 }
695
696 static void free_pipe(struct pipe_ctx *pipe)
697 {
698         memset(pipe, 0, sizeof(struct pipe_ctx));
699 }
700
701 static void free_unused_pipes_for_plane(struct dml2_context *ctx, struct dc_state *state,
702         const struct dc_plane_state *plane, const struct dc_plane_pipe_pool *pool, unsigned int stream_id, int plane_index)
703 {
704         int i;
705         bool is_plane_duplicate = ctx->v20.scratch.plane_duplicate_exists;
706
707         for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
708                 if (state->res_ctx.pipe_ctx[i].plane_state == plane &&
709                         state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id &&
710                         (!is_plane_duplicate ||
711                         ctx->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_index[state->res_ctx.pipe_ctx[i].pipe_idx] == plane_index) &&
712                         !is_pipe_used(pool, state->res_ctx.pipe_ctx[i].pipe_idx)) {
713                         free_pipe(&state->res_ctx.pipe_ctx[i]);
714                 }
715         }
716 }
717
718 static void remove_pipes_from_blend_trees(struct dml2_context *ctx, struct dc_state *state, struct dc_plane_pipe_pool *pipe_pool, unsigned int odm_slice)
719 {
720         struct pipe_ctx *pipe;
721         int i;
722
723         for (i = 0; i < pipe_pool->num_pipes_assigned_to_plane_for_mpcc_combine; i++) {
724                 pipe = &state->res_ctx.pipe_ctx[pipe_pool->pipes_assigned_to_plane[odm_slice][0]];
725                 if (pipe->top_pipe)
726                         pipe->top_pipe->bottom_pipe = pipe->bottom_pipe;
727
728                 if (pipe->bottom_pipe)
729                         pipe->bottom_pipe = pipe->top_pipe;
730
731                 pipe_pool->pipe_used[odm_slice][i] = true;
732         }
733 }
734
735 static void map_pipes_for_stream(struct dml2_context *ctx, struct dc_state *state, const struct dc_stream_state *stream,
736                 struct dc_pipe_mapping_scratch *scratch, const struct dc_state *existing_state)
737 {
738         int odm_slice_index;
739         struct pipe_ctx *master_pipe = NULL;
740
741
742         master_pipe = assign_pipes_to_stream(ctx, state, stream, scratch->odm_info.odm_factor, &scratch->pipe_pool, existing_state);
743         sort_pipes_for_splitting(&scratch->pipe_pool);
744
745         for (odm_slice_index = 0; odm_slice_index < scratch->odm_info.odm_factor; odm_slice_index++) {
746                 remove_pipes_from_blend_trees(ctx, state, &scratch->pipe_pool, odm_slice_index);
747
748                 add_odm_slice_to_odm_tree(ctx, state, scratch, odm_slice_index);
749
750                 ctx->config.callbacks.acquire_secondary_pipe_for_mpc_odm(ctx->config.callbacks.dc, state,
751                         master_pipe, &state->res_ctx.pipe_ctx[scratch->pipe_pool.pipes_assigned_to_plane[odm_slice_index][0]], true);
752         }
753 }
754
755 static void map_pipes_for_plane(struct dml2_context *ctx, struct dc_state *state, const struct dc_stream_state *stream, const struct dc_plane_state *plane,
756                 int plane_index, struct dc_pipe_mapping_scratch *scratch, const struct dc_state *existing_state)
757 {
758         int odm_slice_index;
759         unsigned int plane_id;
760         struct pipe_ctx *master_pipe = NULL;
761         int i;
762
763         if (!get_plane_id(ctx, state, plane, stream->stream_id, plane_index, &plane_id)) {
764                 ASSERT(false);
765                 return;
766         }
767
768         master_pipe = assign_pipes_to_plane(ctx, state, stream, plane, scratch->odm_info.odm_factor,
769                         scratch->mpc_info.mpc_factor, plane_index, &scratch->pipe_pool, existing_state);
770         sort_pipes_for_splitting(&scratch->pipe_pool);
771
772         for (odm_slice_index = 0; odm_slice_index < scratch->odm_info.odm_factor; odm_slice_index++) {
773                 // We build the tree for one ODM slice at a time.
774                 // Each ODM slice shares a common OPP
775                 if (!is_plane_in_odm_slice(plane, odm_slice_index, scratch->odm_info.odm_slice_end_x, scratch->odm_info.odm_factor)) {
776                         continue;
777                 }
778
779                 // Now we have a list of all pipes to be used for this plane/stream, now setup the tree.
780                 scratch->odm_info.next_higher_pipe_for_odm_slice[odm_slice_index] = add_plane_to_blend_tree(ctx, state,
781                                 plane,
782                                 &scratch->pipe_pool,
783                                 odm_slice_index,
784                                 scratch->odm_info.next_higher_pipe_for_odm_slice[odm_slice_index]);
785
786                 add_odm_slice_to_odm_tree(ctx, state, scratch, odm_slice_index);
787
788                 for (i = 0; i < scratch->pipe_pool.num_pipes_assigned_to_plane_for_mpcc_combine; i++) {
789
790                         ctx->config.callbacks.acquire_secondary_pipe_for_mpc_odm(ctx->config.callbacks.dc, state,
791                                 master_pipe, &state->res_ctx.pipe_ctx[scratch->pipe_pool.pipes_assigned_to_plane[odm_slice_index][i]], true);
792                 }
793         }
794
795         free_unused_pipes_for_plane(ctx, state, plane, &scratch->pipe_pool, stream->stream_id, plane_index);
796 }
797
798 static unsigned int get_target_mpc_factor(struct dml2_context *ctx,
799                 struct dc_state *state,
800                 const struct dml_display_cfg_st *disp_cfg,
801                 struct dml2_dml_to_dc_pipe_mapping *mapping,
802                 const struct dc_stream_status *status,
803                 const struct dc_stream_state *stream,
804                 int plane_idx)
805 {
806         unsigned int plane_id;
807         unsigned int cfg_idx;
808         unsigned int mpc_factor;
809
810         if (ctx->architecture == dml2_architecture_20) {
811                 get_plane_id(ctx, state, status->plane_states[plane_idx],
812                                 stream->stream_id, plane_idx, &plane_id);
813                 cfg_idx = find_disp_cfg_idx_by_plane_id(mapping, plane_id);
814                 mpc_factor = (unsigned int)disp_cfg->hw.DPPPerSurface[cfg_idx];
815         } else if (ctx->architecture == dml2_architecture_21) {
816                 if (ctx->config.svp_pstate.callbacks.get_stream_subvp_type(state, stream) == SUBVP_PHANTOM) {
817                         struct dc_stream_state *main_stream;
818                         struct dc_stream_status *main_stream_status;
819
820                         /* get stream id of main stream */
821                         main_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(state, stream);
822                         if (!main_stream) {
823                                 ASSERT(false);
824                                 return 1;
825                         }
826
827                         main_stream_status = ctx->config.callbacks.get_stream_status(state, main_stream);
828                         if (!main_stream_status) {
829                                 ASSERT(false);
830                                 return 1;
831                         }
832
833                         /* get plane id for associated main plane */
834                         get_plane_id(ctx, state, main_stream_status->plane_states[plane_idx],
835                                         main_stream->stream_id, plane_idx, &plane_id);
836                 } else {
837                         get_plane_id(ctx, state, status->plane_states[plane_idx],
838                                         stream->stream_id, plane_idx, &plane_id);
839                 }
840
841                 cfg_idx = find_disp_cfg_idx_by_plane_id(mapping, plane_id);
842                 mpc_factor = ctx->v21.mode_programming.programming->plane_programming[cfg_idx].num_dpps_required;
843         } else {
844                 mpc_factor = 1;
845                 ASSERT(false);
846         }
847
848         /* For stereo timings, we need to pipe split */
849         if (dml2_is_stereo_timing(stream))
850                 mpc_factor = 2;
851
852         return mpc_factor;
853 }
854
855 static unsigned int get_target_odm_factor(
856                 const struct dml2_context *ctx,
857                 struct dc_state *state,
858                 const struct dml_display_cfg_st *disp_cfg,
859                 struct dml2_dml_to_dc_pipe_mapping *mapping,
860                 const struct dc_stream_state *stream)
861 {
862         unsigned int cfg_idx;
863
864         if (ctx->architecture == dml2_architecture_20) {
865                 cfg_idx = find_disp_cfg_idx_by_stream_id(
866                                 mapping, stream->stream_id);
867                 switch (disp_cfg->hw.ODMMode[cfg_idx]) {
868                 case dml_odm_mode_bypass:
869                         return 1;
870                 case dml_odm_mode_combine_2to1:
871                         return 2;
872                 case dml_odm_mode_combine_4to1:
873                         return 4;
874                 default:
875                         break;
876                 }
877         } else if (ctx->architecture == dml2_architecture_21) {
878                 if (ctx->config.svp_pstate.callbacks.get_stream_subvp_type(state, stream) == SUBVP_PHANTOM) {
879                         struct dc_stream_state *main_stream;
880
881                         /* get stream id of main stream */
882                         main_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(state, stream);
883                         if (!main_stream)
884                                 goto failed;
885
886                         /* get cfg idx for associated main stream */
887                         cfg_idx = find_disp_cfg_idx_by_stream_id(
888                                         mapping, main_stream->stream_id);
889                 } else {
890                         cfg_idx = find_disp_cfg_idx_by_stream_id(
891                                         mapping, stream->stream_id);
892                 }
893
894                 return ctx->v21.mode_programming.programming->stream_programming[cfg_idx].num_odms_required;
895         }
896
897 failed:
898         ASSERT(false);
899         return 1;
900 }
901
902 static unsigned int get_source_odm_factor(const struct dml2_context *ctx,
903                 struct dc_state *state,
904                 const struct dc_stream_state *stream)
905 {
906         struct pipe_ctx *otg_master = ctx->config.callbacks.get_otg_master_for_stream(&state->res_ctx, stream);
907
908         if (!otg_master)
909                 return 0;
910
911         return ctx->config.callbacks.get_odm_slice_count(otg_master);
912 }
913
914 static unsigned int get_source_mpc_factor(const struct dml2_context *ctx,
915                 struct dc_state *state,
916                 const struct dc_plane_state *plane)
917 {
918         struct pipe_ctx *dpp_pipes[MAX_PIPES] = {0};
919         int dpp_pipe_count = ctx->config.callbacks.get_dpp_pipes_for_plane(plane,
920                         &state->res_ctx, dpp_pipes);
921
922         ASSERT(dpp_pipe_count > 0);
923         return ctx->config.callbacks.get_mpc_slice_count(dpp_pipes[0]);
924 }
925
926
927 static void populate_mpc_factors_for_stream(
928                 struct dml2_context *ctx,
929                 const struct dml_display_cfg_st *disp_cfg,
930                 struct dml2_dml_to_dc_pipe_mapping *mapping,
931                 struct dc_state *state,
932                 unsigned int stream_idx,
933                 struct dml2_pipe_combine_factor odm_factor,
934                 struct dml2_pipe_combine_factor mpc_factors[MAX_PIPES])
935 {
936         const struct dc_stream_status *status = &state->stream_status[stream_idx];
937         int i;
938
939         for (i = 0; i < status->plane_count; i++) {
940                 mpc_factors[i].source = get_source_mpc_factor(ctx, state, status->plane_states[i]);
941                 mpc_factors[i].target = (odm_factor.target == 1) ?
942                                 get_target_mpc_factor(ctx, state, disp_cfg, mapping, status, state->streams[stream_idx], i) : 1;
943         }
944 }
945
946 static void populate_odm_factors(const struct dml2_context *ctx,
947                 const struct dml_display_cfg_st *disp_cfg,
948                 struct dml2_dml_to_dc_pipe_mapping *mapping,
949                 struct dc_state *state,
950                 struct dml2_pipe_combine_factor odm_factors[MAX_PIPES])
951 {
952         int i;
953
954         for (i = 0; i < state->stream_count; i++) {
955                 odm_factors[i].source = get_source_odm_factor(ctx, state, state->streams[i]);
956                 odm_factors[i].target = get_target_odm_factor(
957                                 ctx, state, disp_cfg, mapping, state->streams[i]);
958         }
959 }
960
961 static bool unmap_dc_pipes_for_stream(struct dml2_context *ctx,
962                 struct dc_state *state,
963                 const struct dc_state *existing_state,
964                 const struct dc_stream_state *stream,
965                 const struct dc_stream_status *status,
966                 struct dml2_pipe_combine_factor odm_factor,
967                 struct dml2_pipe_combine_factor mpc_factors[MAX_PIPES])
968 {
969         int plane_idx;
970         bool result = true;
971
972         for (plane_idx = 0; plane_idx < status->plane_count; plane_idx++)
973                 if (mpc_factors[plane_idx].target < mpc_factors[plane_idx].source)
974                         result &= ctx->config.callbacks.update_pipes_for_plane_with_slice_count(
975                                         state,
976                                         existing_state,
977                                         ctx->config.callbacks.dc->res_pool,
978                                         status->plane_states[plane_idx],
979                                         mpc_factors[plane_idx].target);
980         if (odm_factor.target < odm_factor.source)
981                 result &= ctx->config.callbacks.update_pipes_for_stream_with_slice_count(
982                                 state,
983                                 existing_state,
984                                 ctx->config.callbacks.dc->res_pool,
985                                 stream,
986                                 odm_factor.target);
987         return result;
988 }
989
990 static bool map_dc_pipes_for_stream(struct dml2_context *ctx,
991                 struct dc_state *state,
992                 const struct dc_state *existing_state,
993                 const struct dc_stream_state *stream,
994                 const struct dc_stream_status *status,
995                 struct dml2_pipe_combine_factor odm_factor,
996                 struct dml2_pipe_combine_factor mpc_factors[MAX_PIPES])
997 {
998         int plane_idx;
999         bool result = true;
1000
1001         for (plane_idx = 0; plane_idx < status->plane_count; plane_idx++)
1002                 if (mpc_factors[plane_idx].target > mpc_factors[plane_idx].source)
1003                         result &= ctx->config.callbacks.update_pipes_for_plane_with_slice_count(
1004                                         state,
1005                                         existing_state,
1006                                         ctx->config.callbacks.dc->res_pool,
1007                                         status->plane_states[plane_idx],
1008                                         mpc_factors[plane_idx].target);
1009         if (odm_factor.target > odm_factor.source)
1010                 result &= ctx->config.callbacks.update_pipes_for_stream_with_slice_count(
1011                                 state,
1012                                 existing_state,
1013                                 ctx->config.callbacks.dc->res_pool,
1014                                 stream,
1015                                 odm_factor.target);
1016         return result;
1017 }
1018
1019 static bool map_dc_pipes_with_callbacks(struct dml2_context *ctx,
1020                 struct dc_state *state,
1021                 const struct dml_display_cfg_st *disp_cfg,
1022                 struct dml2_dml_to_dc_pipe_mapping *mapping,
1023                 const struct dc_state *existing_state)
1024 {
1025         int i;
1026         bool result = true;
1027
1028         populate_odm_factors(ctx, disp_cfg, mapping, state, ctx->pipe_combine_scratch.odm_factors);
1029         for (i = 0; i < state->stream_count; i++)
1030                 populate_mpc_factors_for_stream(ctx, disp_cfg, mapping, state,
1031                                 i, ctx->pipe_combine_scratch.odm_factors[i], ctx->pipe_combine_scratch.mpc_factors[i]);
1032         for (i = 0; i < state->stream_count; i++)
1033                 result &= unmap_dc_pipes_for_stream(ctx, state, existing_state, state->streams[i],
1034                                 &state->stream_status[i], ctx->pipe_combine_scratch.odm_factors[i], ctx->pipe_combine_scratch.mpc_factors[i]);
1035         for (i = 0; i < state->stream_count; i++)
1036                 result &= map_dc_pipes_for_stream(ctx, state, existing_state, state->streams[i],
1037                                 &state->stream_status[i], ctx->pipe_combine_scratch.odm_factors[i], ctx->pipe_combine_scratch.mpc_factors[i]);
1038
1039         return result;
1040 }
1041
1042 bool dml2_map_dc_pipes(struct dml2_context *ctx, struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, struct dml2_dml_to_dc_pipe_mapping *mapping, const struct dc_state *existing_state)
1043 {
1044         int stream_index, plane_index, i;
1045
1046         unsigned int stream_disp_cfg_index;
1047         unsigned int plane_disp_cfg_index;
1048         unsigned int disp_cfg_index_max;
1049
1050         unsigned int plane_id;
1051         unsigned int stream_id;
1052
1053         const unsigned int *ODMMode, *DPPPerSurface;
1054         unsigned int odm_mode_array[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}, dpp_per_surface_array[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
1055         struct dc_pipe_mapping_scratch scratch;
1056
1057         if (ctx->config.map_dc_pipes_with_callbacks)
1058                 return map_dc_pipes_with_callbacks(
1059                                 ctx, state, disp_cfg, mapping, existing_state);
1060
1061         if (ctx->architecture == dml2_architecture_21) {
1062                 /*
1063                  * Extract ODM and DPP outputs from DML2.1 and map them in an array as required for pipe mapping in dml2_map_dc_pipes.
1064                  * As data cannot be directly extracted in const pointers, assign these arrays to const pointers before proceeding to
1065                  * maximize the reuse of existing code. Const pointers are required because dml2.0 dml_display_cfg_st is const.
1066                  *
1067                  */
1068                 for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) {
1069                         odm_mode_array[i] = ctx->v21.mode_programming.programming->stream_programming[i].num_odms_required;
1070                         dpp_per_surface_array[i] = ctx->v21.mode_programming.programming->plane_programming[i].num_dpps_required;
1071                 }
1072
1073                 ODMMode = (const unsigned int *)odm_mode_array;
1074                 DPPPerSurface = (const unsigned int *)dpp_per_surface_array;
1075                 disp_cfg_index_max = __DML2_WRAPPER_MAX_STREAMS_PLANES__;
1076         } else {
1077                 ODMMode = (unsigned int *)disp_cfg->hw.ODMMode;
1078                 DPPPerSurface = disp_cfg->hw.DPPPerSurface;
1079                 disp_cfg_index_max = __DML_NUM_PLANES__;
1080         }
1081
1082         for (stream_index = 0; stream_index < state->stream_count; stream_index++) {
1083                 memset(&scratch, 0, sizeof(struct dc_pipe_mapping_scratch));
1084
1085                 stream_id = state->streams[stream_index]->stream_id;
1086                 stream_disp_cfg_index = find_disp_cfg_idx_by_stream_id(mapping, stream_id);
1087                 if (stream_disp_cfg_index >= disp_cfg_index_max)
1088                         continue;
1089
1090                 if (ODMMode[stream_disp_cfg_index] == dml_odm_mode_bypass) {
1091                         scratch.odm_info.odm_factor = 1;
1092                 } else if (ODMMode[stream_disp_cfg_index] == dml_odm_mode_combine_2to1) {
1093                         scratch.odm_info.odm_factor = 2;
1094                 } else if (ODMMode[stream_disp_cfg_index] == dml_odm_mode_combine_4to1) {
1095                         scratch.odm_info.odm_factor = 4;
1096                 } else {
1097                         ASSERT(false);
1098                         scratch.odm_info.odm_factor = 1;
1099                 }
1100
1101                 /* After DML2.1 update, ODM interpretation needs to change and is no longer same as for DML2.0.
1102                  * This is not an issue with new resource management logic. This block ensure backcompat
1103                  * with legacy pipe management with updated DML.
1104                  * */
1105                 if (ctx->architecture == dml2_architecture_21) {
1106                         if (ODMMode[stream_disp_cfg_index] == 1) {
1107                                 scratch.odm_info.odm_factor = 1;
1108                         } else if (ODMMode[stream_disp_cfg_index] == 2) {
1109                                 scratch.odm_info.odm_factor = 2;
1110                         } else if (ODMMode[stream_disp_cfg_index] == 4) {
1111                                 scratch.odm_info.odm_factor = 4;
1112                         } else {
1113                                 ASSERT(false);
1114                                 scratch.odm_info.odm_factor = 1;
1115                         }
1116                 }
1117                 calculate_odm_slices(state->streams[stream_index], scratch.odm_info.odm_factor, scratch.odm_info.odm_slice_end_x);
1118
1119                 // If there are no planes, you still want to setup ODM...
1120                 if (state->stream_status[stream_index].plane_count == 0) {
1121                         map_pipes_for_stream(ctx, state, state->streams[stream_index], &scratch, existing_state);
1122                 }
1123
1124                 for (plane_index = 0; plane_index < state->stream_status[stream_index].plane_count; plane_index++) {
1125                         // Planes are ordered top to bottom.
1126                         if (get_plane_id(ctx, state, state->stream_status[stream_index].plane_states[plane_index],
1127                                 stream_id, plane_index, &plane_id)) {
1128                                 plane_disp_cfg_index = find_disp_cfg_idx_by_plane_id(mapping, plane_id);
1129
1130                                 // Setup mpc_info for this plane
1131                                 scratch.mpc_info.prev_odm_pipe = NULL;
1132                                 if (scratch.odm_info.odm_factor == 1 && plane_disp_cfg_index < disp_cfg_index_max) {
1133                                         // If ODM combine is not inuse, then the number of pipes
1134                                         // per plane is determined by MPC combine factor
1135                                         scratch.mpc_info.mpc_factor = DPPPerSurface[plane_disp_cfg_index];
1136
1137                                         //For stereo timings, we need to pipe split
1138                                         if (dml2_is_stereo_timing(state->streams[stream_index]))
1139                                                 scratch.mpc_info.mpc_factor = 2;
1140                                 } else {
1141                                         // If ODM combine is enabled, then we use at most 1 pipe per
1142                                         // odm slice per plane, i.e. MPC combine is never used
1143                                         scratch.mpc_info.mpc_factor = 1;
1144                                 }
1145
1146                                 ASSERT(scratch.odm_info.odm_factor * scratch.mpc_info.mpc_factor > 0);
1147
1148                                 // Clear the pool assignment scratch (which is per plane)
1149                                 memset(&scratch.pipe_pool, 0, sizeof(struct dc_plane_pipe_pool));
1150
1151                                 map_pipes_for_plane(ctx, state, state->streams[stream_index],
1152                                         state->stream_status[stream_index].plane_states[plane_index], plane_index, &scratch, existing_state);
1153                         } else {
1154                                 // Plane ID cannot be generated, therefore no DML mapping can be performed.
1155                                 ASSERT(false);
1156                         }
1157                 }
1158
1159         }
1160
1161         if (!validate_pipe_assignment(ctx, state, disp_cfg, mapping))
1162                 ASSERT(false);
1163
1164         for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
1165                 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
1166
1167                 if (pipe->plane_state) {
1168                         if (!ctx->config.callbacks.build_scaling_params(pipe)) {
1169                                 ASSERT(false);
1170                         }
1171                 }
1172
1173                 if (ctx->config.callbacks.build_test_pattern_params &&
1174                                 pipe->stream &&
1175                                 pipe->prev_odm_pipe == NULL &&
1176                                 pipe->top_pipe == NULL)
1177                         ctx->config.callbacks.build_test_pattern_params(&state->res_ctx, pipe);
1178         }
1179
1180         return true;
1181 }
This page took 0.104549 seconds and 4 git commands to generate.