Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / dc / core / dc_resource.c
1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25
26 #include "dm_services.h"
27
28 #include "resource.h"
29 #include "include/irq_service_interface.h"
30 #include "link_encoder.h"
31 #include "stream_encoder.h"
32 #include "opp.h"
33 #include "timing_generator.h"
34 #include "transform.h"
35 #include "dccg.h"
36 #include "dchubbub.h"
37 #include "dpp.h"
38 #include "core_types.h"
39 #include "set_mode_types.h"
40 #include "virtual/virtual_stream_encoder.h"
41 #include "dpcd_defs.h"
42 #include "link_enc_cfg.h"
43 #include "link.h"
44 #include "clk_mgr.h"
45 #include "dc_state_priv.h"
46 #include "virtual/virtual_link_hwss.h"
47 #include "link/hwss/link_hwss_dio.h"
48 #include "link/hwss/link_hwss_dpia.h"
49 #include "link/hwss/link_hwss_hpo_dp.h"
50 #include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h"
51 #include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h"
52
53 #if defined(CONFIG_DRM_AMD_DC_SI)
54 #include "dce60/dce60_resource.h"
55 #endif
56 #include "dce80/dce80_resource.h"
57 #include "dce100/dce100_resource.h"
58 #include "dce110/dce110_resource.h"
59 #include "dce112/dce112_resource.h"
60 #include "dce120/dce120_resource.h"
61 #include "dcn10/dcn10_resource.h"
62 #include "dcn20/dcn20_resource.h"
63 #include "dcn21/dcn21_resource.h"
64 #include "dcn201/dcn201_resource.h"
65 #include "dcn30/dcn30_resource.h"
66 #include "dcn301/dcn301_resource.h"
67 #include "dcn302/dcn302_resource.h"
68 #include "dcn303/dcn303_resource.h"
69 #include "dcn31/dcn31_resource.h"
70 #include "dcn314/dcn314_resource.h"
71 #include "dcn315/dcn315_resource.h"
72 #include "dcn316/dcn316_resource.h"
73 #include "dcn32/dcn32_resource.h"
74 #include "dcn321/dcn321_resource.h"
75 #include "dcn35/dcn35_resource.h"
76 #include "dcn351/dcn351_resource.h"
77
78 #define VISUAL_CONFIRM_BASE_DEFAULT 3
79 #define VISUAL_CONFIRM_BASE_MIN 1
80 #define VISUAL_CONFIRM_BASE_MAX 10
81 /* we choose 240 because it is a common denominator of common v addressable
82  * such as 2160, 1440, 1200, 960. So we take 1/240 portion of v addressable as
83  * the visual confirm dpp offset height. So visual confirm height can stay
84  * relatively the same independent from timing used.
85  */
86 #define VISUAL_CONFIRM_DPP_OFFSET_DENO 240
87
88 #define DC_LOGGER \
89         dc->ctx->logger
90 #define DC_LOGGER_INIT(logger)
91
92 #include "dml2/dml2_wrapper.h"
93
94 #define UNABLE_TO_SPLIT -1
95
96 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
97 {
98         enum dce_version dc_version = DCE_VERSION_UNKNOWN;
99
100         switch (asic_id.chip_family) {
101
102 #if defined(CONFIG_DRM_AMD_DC_SI)
103         case FAMILY_SI:
104                 if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
105                     ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
106                     ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
107                         dc_version = DCE_VERSION_6_0;
108                 else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
109                         dc_version = DCE_VERSION_6_4;
110                 else
111                         dc_version = DCE_VERSION_6_1;
112                 break;
113 #endif
114         case FAMILY_CI:
115                 dc_version = DCE_VERSION_8_0;
116                 break;
117         case FAMILY_KV:
118                 if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
119                     ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
120                     ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
121                         dc_version = DCE_VERSION_8_3;
122                 else
123                         dc_version = DCE_VERSION_8_1;
124                 break;
125         case FAMILY_CZ:
126                 dc_version = DCE_VERSION_11_0;
127                 break;
128
129         case FAMILY_VI:
130                 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
131                                 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
132                         dc_version = DCE_VERSION_10_0;
133                         break;
134                 }
135                 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
136                                 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
137                                 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
138                         dc_version = DCE_VERSION_11_2;
139                 }
140                 if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
141                         dc_version = DCE_VERSION_11_22;
142                 break;
143         case FAMILY_AI:
144                 if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
145                         dc_version = DCE_VERSION_12_1;
146                 else
147                         dc_version = DCE_VERSION_12_0;
148                 break;
149         case FAMILY_RV:
150                 dc_version = DCN_VERSION_1_0;
151                 if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
152                         dc_version = DCN_VERSION_1_01;
153                 if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
154                         dc_version = DCN_VERSION_2_1;
155                 if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
156                         dc_version = DCN_VERSION_2_1;
157                 break;
158
159         case FAMILY_NV:
160                 dc_version = DCN_VERSION_2_0;
161                 if (asic_id.chip_id == DEVICE_ID_NV_13FE || asic_id.chip_id == DEVICE_ID_NV_143F) {
162                         dc_version = DCN_VERSION_2_01;
163                         break;
164                 }
165                 if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
166                         dc_version = DCN_VERSION_3_0;
167                 if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
168                         dc_version = DCN_VERSION_3_02;
169                 if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
170                         dc_version = DCN_VERSION_3_03;
171                 break;
172
173         case FAMILY_VGH:
174                 dc_version = DCN_VERSION_3_01;
175                 break;
176
177         case FAMILY_YELLOW_CARP:
178                 if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
179                         dc_version = DCN_VERSION_3_1;
180                 break;
181         case AMDGPU_FAMILY_GC_10_3_6:
182                 if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
183                         dc_version = DCN_VERSION_3_15;
184                 break;
185         case AMDGPU_FAMILY_GC_10_3_7:
186                 if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
187                         dc_version = DCN_VERSION_3_16;
188                 break;
189         case AMDGPU_FAMILY_GC_11_0_0:
190                 dc_version = DCN_VERSION_3_2;
191                 if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
192                         dc_version = DCN_VERSION_3_21;
193                 break;
194         case AMDGPU_FAMILY_GC_11_0_1:
195                 dc_version = DCN_VERSION_3_14;
196                 break;
197         case AMDGPU_FAMILY_GC_11_5_0:
198                 dc_version = DCN_VERSION_3_5;
199                 if (ASICREV_IS_GC_11_0_4(asic_id.hw_internal_rev))
200                         dc_version = DCN_VERSION_3_51;
201                 break;
202         default:
203                 dc_version = DCE_VERSION_UNKNOWN;
204                 break;
205         }
206         return dc_version;
207 }
208
209 struct resource_pool *dc_create_resource_pool(struct dc  *dc,
210                                               const struct dc_init_data *init_data,
211                                               enum dce_version dc_version)
212 {
213         struct resource_pool *res_pool = NULL;
214
215         switch (dc_version) {
216 #if defined(CONFIG_DRM_AMD_DC_SI)
217         case DCE_VERSION_6_0:
218                 res_pool = dce60_create_resource_pool(
219                         init_data->num_virtual_links, dc);
220                 break;
221         case DCE_VERSION_6_1:
222                 res_pool = dce61_create_resource_pool(
223                         init_data->num_virtual_links, dc);
224                 break;
225         case DCE_VERSION_6_4:
226                 res_pool = dce64_create_resource_pool(
227                         init_data->num_virtual_links, dc);
228                 break;
229 #endif
230         case DCE_VERSION_8_0:
231                 res_pool = dce80_create_resource_pool(
232                                 init_data->num_virtual_links, dc);
233                 break;
234         case DCE_VERSION_8_1:
235                 res_pool = dce81_create_resource_pool(
236                                 init_data->num_virtual_links, dc);
237                 break;
238         case DCE_VERSION_8_3:
239                 res_pool = dce83_create_resource_pool(
240                                 init_data->num_virtual_links, dc);
241                 break;
242         case DCE_VERSION_10_0:
243                 res_pool = dce100_create_resource_pool(
244                                 init_data->num_virtual_links, dc);
245                 break;
246         case DCE_VERSION_11_0:
247                 res_pool = dce110_create_resource_pool(
248                                 init_data->num_virtual_links, dc,
249                                 init_data->asic_id);
250                 break;
251         case DCE_VERSION_11_2:
252         case DCE_VERSION_11_22:
253                 res_pool = dce112_create_resource_pool(
254                                 init_data->num_virtual_links, dc);
255                 break;
256         case DCE_VERSION_12_0:
257         case DCE_VERSION_12_1:
258                 res_pool = dce120_create_resource_pool(
259                                 init_data->num_virtual_links, dc);
260                 break;
261
262 #if defined(CONFIG_DRM_AMD_DC_FP)
263         case DCN_VERSION_1_0:
264         case DCN_VERSION_1_01:
265                 res_pool = dcn10_create_resource_pool(init_data, dc);
266                 break;
267         case DCN_VERSION_2_0:
268                 res_pool = dcn20_create_resource_pool(init_data, dc);
269                 break;
270         case DCN_VERSION_2_1:
271                 res_pool = dcn21_create_resource_pool(init_data, dc);
272                 break;
273         case DCN_VERSION_2_01:
274                 res_pool = dcn201_create_resource_pool(init_data, dc);
275                 break;
276         case DCN_VERSION_3_0:
277                 res_pool = dcn30_create_resource_pool(init_data, dc);
278                 break;
279         case DCN_VERSION_3_01:
280                 res_pool = dcn301_create_resource_pool(init_data, dc);
281                 break;
282         case DCN_VERSION_3_02:
283                 res_pool = dcn302_create_resource_pool(init_data, dc);
284                 break;
285         case DCN_VERSION_3_03:
286                 res_pool = dcn303_create_resource_pool(init_data, dc);
287                 break;
288         case DCN_VERSION_3_1:
289                 res_pool = dcn31_create_resource_pool(init_data, dc);
290                 break;
291         case DCN_VERSION_3_14:
292                 res_pool = dcn314_create_resource_pool(init_data, dc);
293                 break;
294         case DCN_VERSION_3_15:
295                 res_pool = dcn315_create_resource_pool(init_data, dc);
296                 break;
297         case DCN_VERSION_3_16:
298                 res_pool = dcn316_create_resource_pool(init_data, dc);
299                 break;
300         case DCN_VERSION_3_2:
301                 res_pool = dcn32_create_resource_pool(init_data, dc);
302                 break;
303         case DCN_VERSION_3_21:
304                 res_pool = dcn321_create_resource_pool(init_data, dc);
305                 break;
306         case DCN_VERSION_3_5:
307                 res_pool = dcn35_create_resource_pool(init_data, dc);
308                 break;
309         case DCN_VERSION_3_51:
310                 res_pool = dcn351_create_resource_pool(init_data, dc);
311                 break;
312 #endif /* CONFIG_DRM_AMD_DC_FP */
313         default:
314                 break;
315         }
316
317         if (res_pool != NULL) {
318                 if (dc->ctx->dc_bios->fw_info_valid) {
319                         res_pool->ref_clocks.xtalin_clock_inKhz =
320                                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
321                         /* initialize with firmware data first, no all
322                          * ASIC have DCCG SW component. FPGA or
323                          * simulation need initialization of
324                          * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
325                          * with xtalin_clock_inKhz
326                          */
327                         res_pool->ref_clocks.dccg_ref_clock_inKhz =
328                                 res_pool->ref_clocks.xtalin_clock_inKhz;
329                         res_pool->ref_clocks.dchub_ref_clock_inKhz =
330                                 res_pool->ref_clocks.xtalin_clock_inKhz;
331                         if (dc->debug.using_dml2)
332                                 if (res_pool->hubbub && res_pool->hubbub->funcs->get_dchub_ref_freq)
333                                         res_pool->hubbub->funcs->get_dchub_ref_freq(res_pool->hubbub,
334                                                                                     res_pool->ref_clocks.dccg_ref_clock_inKhz,
335                                                                                     &res_pool->ref_clocks.dchub_ref_clock_inKhz);
336                 } else
337                         ASSERT_CRITICAL(false);
338         }
339
340         return res_pool;
341 }
342
343 void dc_destroy_resource_pool(struct dc  *dc)
344 {
345         if (dc) {
346                 if (dc->res_pool)
347                         dc->res_pool->funcs->destroy(&dc->res_pool);
348
349                 kfree(dc->hwseq);
350         }
351 }
352
353 static void update_num_audio(
354         const struct resource_straps *straps,
355         unsigned int *num_audio,
356         struct audio_support *aud_support)
357 {
358         aud_support->dp_audio = true;
359         aud_support->hdmi_audio_native = false;
360         aud_support->hdmi_audio_on_dongle = false;
361
362         if (straps->hdmi_disable == 0) {
363                 if (straps->dc_pinstraps_audio & 0x2) {
364                         aud_support->hdmi_audio_on_dongle = true;
365                         aud_support->hdmi_audio_native = true;
366                 }
367         }
368
369         switch (straps->audio_stream_number) {
370         case 0: /* multi streams supported */
371                 break;
372         case 1: /* multi streams not supported */
373                 *num_audio = 1;
374                 break;
375         default:
376                 DC_ERR("DC: unexpected audio fuse!\n");
377         }
378 }
379
380 bool resource_construct(
381         unsigned int num_virtual_links,
382         struct dc  *dc,
383         struct resource_pool *pool,
384         const struct resource_create_funcs *create_funcs)
385 {
386         struct dc_context *ctx = dc->ctx;
387         const struct resource_caps *caps = pool->res_cap;
388         int i;
389         unsigned int num_audio = caps->num_audio;
390         struct resource_straps straps = {0};
391
392         if (create_funcs->read_dce_straps)
393                 create_funcs->read_dce_straps(dc->ctx, &straps);
394
395         pool->audio_count = 0;
396         if (create_funcs->create_audio) {
397                 /* find the total number of streams available via the
398                  * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
399                  * registers (one for each pin) starting from pin 1
400                  * up to the max number of audio pins.
401                  * We stop on the first pin where
402                  * PORT_CONNECTIVITY == 1 (as instructed by HW team).
403                  */
404                 update_num_audio(&straps, &num_audio, &pool->audio_support);
405                 for (i = 0; i < caps->num_audio; i++) {
406                         struct audio *aud = create_funcs->create_audio(ctx, i);
407
408                         if (aud == NULL) {
409                                 DC_ERR("DC: failed to create audio!\n");
410                                 return false;
411                         }
412                         if (!aud->funcs->endpoint_valid(aud)) {
413                                 aud->funcs->destroy(&aud);
414                                 break;
415                         }
416                         pool->audios[i] = aud;
417                         pool->audio_count++;
418                 }
419         }
420
421         pool->stream_enc_count = 0;
422         if (create_funcs->create_stream_encoder) {
423                 for (i = 0; i < caps->num_stream_encoder; i++) {
424                         pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
425                         if (pool->stream_enc[i] == NULL)
426                                 DC_ERR("DC: failed to create stream_encoder!\n");
427                         pool->stream_enc_count++;
428                 }
429         }
430
431         pool->hpo_dp_stream_enc_count = 0;
432         if (create_funcs->create_hpo_dp_stream_encoder) {
433                 for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
434                         pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
435                         if (pool->hpo_dp_stream_enc[i] == NULL)
436                                 DC_ERR("DC: failed to create HPO DP stream encoder!\n");
437                         pool->hpo_dp_stream_enc_count++;
438
439                 }
440         }
441
442         pool->hpo_dp_link_enc_count = 0;
443         if (create_funcs->create_hpo_dp_link_encoder) {
444                 for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
445                         pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
446                         if (pool->hpo_dp_link_enc[i] == NULL)
447                                 DC_ERR("DC: failed to create HPO DP link encoder!\n");
448                         pool->hpo_dp_link_enc_count++;
449                 }
450         }
451
452         for (i = 0; i < caps->num_mpc_3dlut; i++) {
453                 pool->mpc_lut[i] = dc_create_3dlut_func();
454                 if (pool->mpc_lut[i] == NULL)
455                         DC_ERR("DC: failed to create MPC 3dlut!\n");
456                 pool->mpc_shaper[i] = dc_create_transfer_func();
457                 if (pool->mpc_shaper[i] == NULL)
458                         DC_ERR("DC: failed to create MPC shaper!\n");
459         }
460
461         dc->caps.dynamic_audio = false;
462         if (pool->audio_count < pool->stream_enc_count) {
463                 dc->caps.dynamic_audio = true;
464         }
465         for (i = 0; i < num_virtual_links; i++) {
466                 pool->stream_enc[pool->stream_enc_count] =
467                         virtual_stream_encoder_create(
468                                         ctx, ctx->dc_bios);
469                 if (pool->stream_enc[pool->stream_enc_count] == NULL) {
470                         DC_ERR("DC: failed to create stream_encoder!\n");
471                         return false;
472                 }
473                 pool->stream_enc_count++;
474         }
475
476         dc->hwseq = create_funcs->create_hwseq(ctx);
477
478         return true;
479 }
480 static int find_matching_clock_source(
481                 const struct resource_pool *pool,
482                 struct clock_source *clock_source)
483 {
484
485         int i;
486
487         for (i = 0; i < pool->clk_src_count; i++) {
488                 if (pool->clock_sources[i] == clock_source)
489                         return i;
490         }
491         return -1;
492 }
493
494 void resource_unreference_clock_source(
495                 struct resource_context *res_ctx,
496                 const struct resource_pool *pool,
497                 struct clock_source *clock_source)
498 {
499         int i = find_matching_clock_source(pool, clock_source);
500
501         if (i > -1)
502                 res_ctx->clock_source_ref_count[i]--;
503
504         if (pool->dp_clock_source == clock_source)
505                 res_ctx->dp_clock_source_ref_count--;
506 }
507
508 void resource_reference_clock_source(
509                 struct resource_context *res_ctx,
510                 const struct resource_pool *pool,
511                 struct clock_source *clock_source)
512 {
513         int i = find_matching_clock_source(pool, clock_source);
514
515         if (i > -1)
516                 res_ctx->clock_source_ref_count[i]++;
517
518         if (pool->dp_clock_source == clock_source)
519                 res_ctx->dp_clock_source_ref_count++;
520 }
521
522 int resource_get_clock_source_reference(
523                 struct resource_context *res_ctx,
524                 const struct resource_pool *pool,
525                 struct clock_source *clock_source)
526 {
527         int i = find_matching_clock_source(pool, clock_source);
528
529         if (i > -1)
530                 return res_ctx->clock_source_ref_count[i];
531
532         if (pool->dp_clock_source == clock_source)
533                 return res_ctx->dp_clock_source_ref_count;
534
535         return -1;
536 }
537
538 bool resource_are_vblanks_synchronizable(
539         struct dc_stream_state *stream1,
540         struct dc_stream_state *stream2)
541 {
542         uint32_t base60_refresh_rates[] = {10, 20, 5};
543         uint8_t i;
544         uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
545         uint64_t frame_time_diff;
546
547         if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
548                 stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
549                 dc_is_dp_signal(stream1->signal) &&
550                 dc_is_dp_signal(stream2->signal) &&
551                 false == stream1->has_non_synchronizable_pclk &&
552                 false == stream2->has_non_synchronizable_pclk &&
553                 stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
554                 stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
555                 /* disable refresh rates higher than 60Hz for now */
556                 if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
557                                 stream1->timing.v_total > 60)
558                         return false;
559                 if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
560                                 stream2->timing.v_total > 60)
561                         return false;
562                 frame_time_diff = (uint64_t)10000 *
563                         stream1->timing.h_total *
564                         stream1->timing.v_total *
565                         stream2->timing.pix_clk_100hz;
566                 frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
567                 frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
568                 frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
569                 for (i = 0; i < rr_count; i++) {
570                         int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
571
572                         if (diff < 0)
573                                 diff = -diff;
574                         if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
575                                 return true;
576                 }
577         }
578         return false;
579 }
580
581 bool resource_are_streams_timing_synchronizable(
582         struct dc_stream_state *stream1,
583         struct dc_stream_state *stream2)
584 {
585         if (stream1->timing.h_total != stream2->timing.h_total)
586                 return false;
587
588         if (stream1->timing.v_total != stream2->timing.v_total)
589                 return false;
590
591         if (stream1->timing.h_addressable
592                                 != stream2->timing.h_addressable)
593                 return false;
594
595         if (stream1->timing.v_addressable
596                                 != stream2->timing.v_addressable)
597                 return false;
598
599         if (stream1->timing.v_front_porch
600                                 != stream2->timing.v_front_porch)
601                 return false;
602
603         if (stream1->timing.pix_clk_100hz
604                                 != stream2->timing.pix_clk_100hz)
605                 return false;
606
607         if (stream1->clamping.c_depth != stream2->clamping.c_depth)
608                 return false;
609
610         if (stream1->phy_pix_clk != stream2->phy_pix_clk
611                         && (!dc_is_dp_signal(stream1->signal)
612                         || !dc_is_dp_signal(stream2->signal)))
613                 return false;
614
615         if (stream1->view_format != stream2->view_format)
616                 return false;
617
618         if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
619                 return false;
620
621         return true;
622 }
623 static bool is_dp_and_hdmi_sharable(
624                 struct dc_stream_state *stream1,
625                 struct dc_stream_state *stream2)
626 {
627         if (stream1->ctx->dc->caps.disable_dp_clk_share)
628                 return false;
629
630         if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
631                 stream2->clamping.c_depth != COLOR_DEPTH_888)
632                 return false;
633
634         return true;
635
636 }
637
638 static bool is_sharable_clk_src(
639         const struct pipe_ctx *pipe_with_clk_src,
640         const struct pipe_ctx *pipe)
641 {
642         if (pipe_with_clk_src->clock_source == NULL)
643                 return false;
644
645         if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
646                 return false;
647
648         if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
649                 (dc_is_dp_signal(pipe->stream->signal) &&
650                 !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
651                                      pipe->stream)))
652                 return false;
653
654         if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
655                         && dc_is_dual_link_signal(pipe->stream->signal))
656                 return false;
657
658         if (dc_is_hdmi_signal(pipe->stream->signal)
659                         && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
660                 return false;
661
662         if (!resource_are_streams_timing_synchronizable(
663                         pipe_with_clk_src->stream, pipe->stream))
664                 return false;
665
666         return true;
667 }
668
669 struct clock_source *resource_find_used_clk_src_for_sharing(
670                                         struct resource_context *res_ctx,
671                                         struct pipe_ctx *pipe_ctx)
672 {
673         int i;
674
675         for (i = 0; i < MAX_PIPES; i++) {
676                 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
677                         return res_ctx->pipe_ctx[i].clock_source;
678         }
679
680         return NULL;
681 }
682
683 static enum pixel_format convert_pixel_format_to_dalsurface(
684                 enum surface_pixel_format surface_pixel_format)
685 {
686         enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
687
688         switch (surface_pixel_format) {
689         case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
690                 dal_pixel_format = PIXEL_FORMAT_INDEX8;
691                 break;
692         case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
693                 dal_pixel_format = PIXEL_FORMAT_RGB565;
694                 break;
695         case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
696                 dal_pixel_format = PIXEL_FORMAT_RGB565;
697                 break;
698         case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
699                 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
700                 break;
701         case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
702                 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
703                 break;
704         case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
705                 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
706                 break;
707         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
708                 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
709                 break;
710         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
711                 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
712                 break;
713         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
714         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
715                 dal_pixel_format = PIXEL_FORMAT_FP16;
716                 break;
717         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
718         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
719                 dal_pixel_format = PIXEL_FORMAT_420BPP8;
720                 break;
721         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
722         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
723                 dal_pixel_format = PIXEL_FORMAT_420BPP10;
724                 break;
725         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
726         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
727         default:
728                 dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
729                 break;
730         }
731         return dal_pixel_format;
732 }
733
734 static inline void get_vp_scan_direction(
735         enum dc_rotation_angle rotation,
736         bool horizontal_mirror,
737         bool *orthogonal_rotation,
738         bool *flip_vert_scan_dir,
739         bool *flip_horz_scan_dir)
740 {
741         *orthogonal_rotation = false;
742         *flip_vert_scan_dir = false;
743         *flip_horz_scan_dir = false;
744         if (rotation == ROTATION_ANGLE_180) {
745                 *flip_vert_scan_dir = true;
746                 *flip_horz_scan_dir = true;
747         } else if (rotation == ROTATION_ANGLE_90) {
748                 *orthogonal_rotation = true;
749                 *flip_horz_scan_dir = true;
750         } else if (rotation == ROTATION_ANGLE_270) {
751                 *orthogonal_rotation = true;
752                 *flip_vert_scan_dir = true;
753         }
754
755         if (horizontal_mirror)
756                 *flip_horz_scan_dir = !*flip_horz_scan_dir;
757 }
758
759 /*
760  * This is a preliminary vp size calculation to allow us to check taps support.
761  * The result is completely overridden afterwards.
762  */
763 static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
764 {
765         struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
766
767         data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width));
768         data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height));
769         data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width));
770         data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height));
771         if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
772                         pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
773                 swap(data->viewport.width, data->viewport.height);
774                 swap(data->viewport_c.width, data->viewport_c.height);
775         }
776 }
777
778 static struct rect intersect_rec(const struct rect *r0, const struct rect *r1)
779 {
780         struct rect rec;
781         int r0_x_end = r0->x + r0->width;
782         int r1_x_end = r1->x + r1->width;
783         int r0_y_end = r0->y + r0->height;
784         int r1_y_end = r1->y + r1->height;
785
786         rec.x = r0->x > r1->x ? r0->x : r1->x;
787         rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;
788         rec.y = r0->y > r1->y ? r0->y : r1->y;
789         rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;
790
791         /* in case that there is no intersection */
792         if (rec.width < 0 || rec.height < 0)
793                 memset(&rec, 0, sizeof(rec));
794
795         return rec;
796 }
797
798 static struct rect shift_rec(const struct rect *rec_in, int x, int y)
799 {
800         struct rect rec_out = *rec_in;
801
802         rec_out.x += x;
803         rec_out.y += y;
804
805         return rec_out;
806 }
807
808 static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx)
809 {
810         const struct dc_stream_state *stream = pipe_ctx->stream;
811         int odm_slice_count = resource_get_odm_slice_count(pipe_ctx);
812         int odm_slice_idx = resource_get_odm_slice_index(pipe_ctx);
813         bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
814         int h_active = stream->timing.h_addressable +
815                         stream->timing.h_border_left +
816                         stream->timing.h_border_right;
817         int odm_slice_width = h_active / odm_slice_count;
818         struct rect odm_rec;
819
820         odm_rec.x = odm_slice_width * odm_slice_idx;
821         odm_rec.width = is_last_odm_slice ?
822                         /* last slice width is the reminder of h_active */
823                         h_active - odm_slice_width * (odm_slice_count - 1) :
824                         /* odm slice width is the floor of h_active / count */
825                         odm_slice_width;
826         odm_rec.y = 0;
827         odm_rec.height = stream->timing.v_addressable +
828                         stream->timing.v_border_bottom +
829                         stream->timing.v_border_top;
830
831         return odm_rec;
832 }
833
834 static struct rect calculate_plane_rec_in_timing_active(
835                 struct pipe_ctx *pipe_ctx,
836                 const struct rect *rec_in)
837 {
838         /*
839          * The following diagram shows an example where we map a 1920x1200
840          * desktop to a 2560x1440 timing with a plane rect in the middle
841          * of the screen. To map a plane rect from Stream Source to Timing
842          * Active space, we first multiply stream scaling ratios (i.e 2304/1920
843          * horizontal and 1440/1200 vertical) to the plane's x and y, then
844          * we add stream destination offsets (i.e 128 horizontal, 0 vertical).
845          * This will give us a plane rect's position in Timing Active. However
846          * we have to remove the fractional. The rule is that we find left/right
847          * and top/bottom positions and round the value to the adjacent integer.
848          *
849          * Stream Source Space
850          * ------------
851          *        __________________________________________________
852          *       |Stream Source (1920 x 1200) ^                     |
853          *       |                            y                     |
854          *       |         <------- w --------|>                    |
855          *       |          __________________V                     |
856          *       |<-- x -->|Plane//////////////| ^                  |
857          *       |         |(pre scale)////////| |                  |
858          *       |         |///////////////////| |                  |
859          *       |         |///////////////////| h                  |
860          *       |         |///////////////////| |                  |
861          *       |         |///////////////////| |                  |
862          *       |         |///////////////////| V                  |
863          *       |                                                  |
864          *       |                                                  |
865          *       |__________________________________________________|
866          *
867          *
868          * Timing Active Space
869          * ---------------------------------
870          *
871          *       Timing Active (2560 x 1440)
872          *        __________________________________________________
873          *       |*****|  Stteam Destination (2304 x 1440)    |*****|
874          *       |*****|                                      |*****|
875          *       |<128>|                                      |*****|
876          *       |*****|     __________________               |*****|
877          *       |*****|    |Plane/////////////|              |*****|
878          *       |*****|    |(post scale)//////|              |*****|
879          *       |*****|    |//////////////////|              |*****|
880          *       |*****|    |//////////////////|              |*****|
881          *       |*****|    |//////////////////|              |*****|
882          *       |*****|    |//////////////////|              |*****|
883          *       |*****|                                      |*****|
884          *       |*****|                                      |*****|
885          *       |*****|                                      |*****|
886          *       |*****|______________________________________|*****|
887          *
888          * So the resulting formulas are shown below:
889          *
890          * recout_x = 128 + round(plane_x * 2304 / 1920)
891          * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x
892          * recout_y = 0 + round(plane_y * 1440 / 1280)
893          * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y
894          *
895          * NOTE: fixed point division is not error free. To reduce errors
896          * introduced by fixed point division, we divide only after
897          * multiplication is complete.
898          */
899         const struct dc_stream_state *stream = pipe_ctx->stream;
900         struct rect rec_out = {0};
901         struct fixed31_32 temp;
902
903         temp = dc_fixpt_from_fraction(rec_in->x * stream->dst.width,
904                         stream->src.width);
905         rec_out.x = stream->dst.x + dc_fixpt_round(temp);
906
907         temp = dc_fixpt_from_fraction(
908                         (rec_in->x + rec_in->width) * stream->dst.width,
909                         stream->src.width);
910         rec_out.width = stream->dst.x + dc_fixpt_round(temp) - rec_out.x;
911
912         temp = dc_fixpt_from_fraction(rec_in->y * stream->dst.height,
913                         stream->src.height);
914         rec_out.y = stream->dst.y + dc_fixpt_round(temp);
915
916         temp = dc_fixpt_from_fraction(
917                         (rec_in->y + rec_in->height) * stream->dst.height,
918                         stream->src.height);
919         rec_out.height = stream->dst.y + dc_fixpt_round(temp) - rec_out.y;
920
921         return rec_out;
922 }
923
924 static struct rect calculate_mpc_slice_in_timing_active(
925                 struct pipe_ctx *pipe_ctx,
926                 struct rect *plane_clip_rec)
927 {
928         const struct dc_stream_state *stream = pipe_ctx->stream;
929         int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx);
930         int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx);
931         int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
932         struct rect mpc_rec;
933
934         mpc_rec.width = plane_clip_rec->width / mpc_slice_count;
935         mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
936         mpc_rec.height = plane_clip_rec->height;
937         mpc_rec.y = plane_clip_rec->y;
938         ASSERT(mpc_slice_count == 1 ||
939                         stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE ||
940                         mpc_rec.width % 2 == 0);
941
942         /* extra pixels in the division remainder need to go to pipes after
943          * the extra pixel index minus one(epimo) defined here as:
944          */
945         if (mpc_slice_idx > epimo) {
946                 mpc_rec.x += mpc_slice_idx - epimo - 1;
947                 mpc_rec.width += 1;
948         }
949
950         if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
951                 ASSERT(mpc_rec.height % 2 == 0);
952                 mpc_rec.height /= 2;
953         }
954         return mpc_rec;
955 }
956
957 static void adjust_recout_for_visual_confirm(struct rect *recout,
958                 struct pipe_ctx *pipe_ctx)
959 {
960         struct dc *dc = pipe_ctx->stream->ctx->dc;
961         int dpp_offset, base_offset;
962
963         if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE || !pipe_ctx->plane_res.dpp)
964                 return;
965
966         dpp_offset = pipe_ctx->stream->timing.v_addressable / VISUAL_CONFIRM_DPP_OFFSET_DENO;
967         dpp_offset *= pipe_ctx->plane_res.dpp->inst;
968
969         if ((dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_BASE_MIN) &&
970                         dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_BASE_MAX)
971                 base_offset = dc->debug.visual_confirm_rect_height;
972         else
973                 base_offset = VISUAL_CONFIRM_BASE_DEFAULT;
974
975         recout->height -= base_offset;
976         recout->height -= dpp_offset;
977 }
978
979 /*
980  * The function maps a plane clip from Stream Source Space to ODM Slice Space
981  * and calculates the rec of the overlapping area of MPC slice of the plane
982  * clip, ODM slice associated with the pipe context and stream destination rec.
983  */
984 static void calculate_recout(struct pipe_ctx *pipe_ctx)
985 {
986         /*
987          * A plane clip represents the desired plane size and position in Stream
988          * Source Space. Stream Source is the destination where all planes are
989          * blended (i.e. positioned, scaled and overlaid). It is a canvas where
990          * all planes associated with the current stream are drawn together.
991          * After Stream Source is completed, we will further scale and
992          * reposition the entire canvas of the stream source to Stream
993          * Destination in Timing Active Space. This could be due to display
994          * overscan adjustment where we will need to rescale and reposition all
995          * the planes so they can fit into a TV with overscan or downscale
996          * upscale features such as GPU scaling or VSR.
997          *
998          * This two step blending is a virtual procedure in software. In
999          * hardware there is no such thing as Stream Source. all planes are
1000          * blended once in Timing Active Space. Software virtualizes a Stream
1001          * Source space to decouple the math complicity so scaling param
1002          * calculation focuses on one step at a time.
1003          *
1004          * In the following two diagrams, user applied 10% overscan adjustment
1005          * so the Stream Source needs to be scaled down a little before mapping
1006          * to Timing Active Space. As a result the Plane Clip is also scaled
1007          * down by the same ratio, Plane Clip position (i.e. x and y) with
1008          * respect to Stream Source is also scaled down. To map it in Timing
1009          * Active Space additional x and y offsets from Stream Destination are
1010          * added to Plane Clip as well.
1011          *
1012          * Stream Source Space
1013          * ------------
1014          *        __________________________________________________
1015          *       |Stream Source (3840 x 2160) ^                     |
1016          *       |                            y                     |
1017          *       |                            |                     |
1018          *       |          __________________V                     |
1019          *       |<-- x -->|Plane Clip/////////|                    |
1020          *       |         |(pre scale)////////|                    |
1021          *       |         |///////////////////|                    |
1022          *       |         |///////////////////|                    |
1023          *       |         |///////////////////|                    |
1024          *       |         |///////////////////|                    |
1025          *       |         |///////////////////|                    |
1026          *       |                                                  |
1027          *       |                                                  |
1028          *       |__________________________________________________|
1029          *
1030          *
1031          * Timing Active Space (3840 x 2160)
1032          * ---------------------------------
1033          *
1034          *       Timing Active
1035          *        __________________________________________________
1036          *       | y_____________________________________________   |
1037          *       |x |Stream Destination (3456 x 1944)            |  |
1038          *       |  |                                            |  |
1039          *       |  |        __________________                  |  |
1040          *       |  |       |Plane Clip////////|                 |  |
1041          *       |  |       |(post scale)//////|                 |  |
1042          *       |  |       |//////////////////|                 |  |
1043          *       |  |       |//////////////////|                 |  |
1044          *       |  |       |//////////////////|                 |  |
1045          *       |  |       |//////////////////|                 |  |
1046          *       |  |                                            |  |
1047          *       |  |                                            |  |
1048          *       |  |____________________________________________|  |
1049          *       |__________________________________________________|
1050          *
1051          *
1052          * In Timing Active Space a plane clip could be further sliced into
1053          * pieces called MPC slices. Each Pipe Context is responsible for
1054          * processing only one MPC slice so the plane processing workload can be
1055          * distributed to multiple DPP Pipes. MPC slices could be blended
1056          * together to a single ODM slice. Each ODM slice is responsible for
1057          * processing a portion of Timing Active divided horizontally so the
1058          * output pixel processing workload can be distributed to multiple OPP
1059          * pipes. All ODM slices are mapped together in ODM block so all MPC
1060          * slices belong to different ODM slices could be pieced together to
1061          * form a single image in Timing Active. MPC slices must belong to
1062          * single ODM slice. If an MPC slice goes across ODM slice boundary, it
1063          * needs to be divided into two MPC slices one for each ODM slice.
1064          *
1065          * In the following diagram the output pixel processing workload is
1066          * divided horizontally into two ODM slices one for each OPP blend tree.
1067          * OPP0 blend tree is responsible for processing left half of Timing
1068          * Active, while OPP2 blend tree is responsible for processing right
1069          * half.
1070          *
1071          * The plane has two MPC slices. However since the right MPC slice goes
1072          * across ODM boundary, two DPP pipes are needed one for each OPP blend
1073          * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).
1074          *
1075          * Assuming that we have a Pipe Context associated with OPP0 and DPP1
1076          * working on processing the plane in the diagram. We want to know the
1077          * width and height of the shaded rectangle and its relative position
1078          * with respect to the ODM slice0. This is called the recout of the pipe
1079          * context.
1080          *
1081          * Planes can be at arbitrary size and position and there could be an
1082          * arbitrary number of MPC and ODM slices. The algorithm needs to take
1083          * all scenarios into account.
1084          *
1085          * Timing Active Space (3840 x 2160)
1086          * ---------------------------------
1087          *
1088          *       Timing Active
1089          *        __________________________________________________
1090          *       |OPP0(ODM slice0)^        |OPP2(ODM slice1)        |
1091          *       |                y        |                        |
1092          *       |                |  <- w ->                        |
1093          *       |           _____V________|____                    |
1094          *       |          |DPP0 ^  |DPP1 |DPP2|                   |
1095          *       |<------ x |-----|->|/////|    |                   |
1096          *       |          |     |  |/////|    |                   |
1097          *       |          |     h  |/////|    |                   |
1098          *       |          |     |  |/////|    |                   |
1099          *       |          |_____V__|/////|____|                   |
1100          *       |                         |                        |
1101          *       |                         |                        |
1102          *       |                         |                        |
1103          *       |_________________________|________________________|
1104          *
1105          *
1106          */
1107         struct rect plane_clip;
1108         struct rect mpc_slice_of_plane_clip;
1109         struct rect odm_slice;
1110         struct rect overlapping_area;
1111
1112         plane_clip = calculate_plane_rec_in_timing_active(pipe_ctx,
1113                         &pipe_ctx->plane_state->clip_rect);
1114         /* guard plane clip from drawing beyond stream dst here */
1115         plane_clip = intersect_rec(&plane_clip,
1116                                 &pipe_ctx->stream->dst);
1117         mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(
1118                         pipe_ctx, &plane_clip);
1119         odm_slice = calculate_odm_slice_in_timing_active(pipe_ctx);
1120         overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice);
1121         if (overlapping_area.height > 0 &&
1122                         overlapping_area.width > 0) {
1123                 /* shift the overlapping area so it is with respect to current
1124                  * ODM slice's position
1125                  */
1126                 pipe_ctx->plane_res.scl_data.recout = shift_rec(
1127                                 &overlapping_area,
1128                                 -odm_slice.x, -odm_slice.y);
1129                 adjust_recout_for_visual_confirm(
1130                                 &pipe_ctx->plane_res.scl_data.recout,
1131                                 pipe_ctx);
1132         } else {
1133                 /* if there is no overlap, zero recout */
1134                 memset(&pipe_ctx->plane_res.scl_data.recout, 0,
1135                                 sizeof(struct rect));
1136         }
1137
1138 }
1139
1140 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
1141 {
1142         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1143         const struct dc_stream_state *stream = pipe_ctx->stream;
1144         struct rect surf_src = plane_state->src_rect;
1145         const int in_w = stream->src.width;
1146         const int in_h = stream->src.height;
1147         const int out_w = stream->dst.width;
1148         const int out_h = stream->dst.height;
1149
1150         /*Swap surf_src height and width since scaling ratios are in recout rotation*/
1151         if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
1152                         pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
1153                 swap(surf_src.height, surf_src.width);
1154
1155         pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
1156                                         surf_src.width,
1157                                         plane_state->dst_rect.width);
1158         pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
1159                                         surf_src.height,
1160                                         plane_state->dst_rect.height);
1161
1162         if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1163                 pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
1164         else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1165                 pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
1166
1167         pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
1168                 pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
1169         pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
1170                 pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
1171
1172         pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
1173         pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
1174
1175         if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
1176                         || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
1177                 pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
1178                 pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
1179         }
1180         pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
1181                         pipe_ctx->plane_res.scl_data.ratios.horz, 19);
1182         pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
1183                         pipe_ctx->plane_res.scl_data.ratios.vert, 19);
1184         pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
1185                         pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
1186         pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
1187                         pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
1188 }
1189
1190
1191 /*
1192  * We completely calculate vp offset, size and inits here based entirely on scaling
1193  * ratios and recout for pixel perfect pipe combine.
1194  */
1195 static void calculate_init_and_vp(
1196                 bool flip_scan_dir,
1197                 int recout_offset_within_recout_full,
1198                 int recout_size,
1199                 int src_size,
1200                 int taps,
1201                 struct fixed31_32 ratio,
1202                 struct fixed31_32 *init,
1203                 int *vp_offset,
1204                 int *vp_size)
1205 {
1206         struct fixed31_32 temp;
1207         int int_part;
1208
1209         /*
1210          * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
1211          * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
1212          * All following calculations are based on this logic.
1213          *
1214          * Init calculated according to formula:
1215          *      init = (scaling_ratio + number_of_taps + 1) / 2
1216          *      init_bot = init + scaling_ratio
1217          *      to get pixel perfect combine add the fraction from calculating vp offset
1218          */
1219         temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
1220         *vp_offset = dc_fixpt_floor(temp);
1221         temp.value &= 0xffffffff;
1222         *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
1223                         dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
1224         /*
1225          * If viewport has non 0 offset and there are more taps than covered by init then
1226          * we should decrease the offset and increase init so we are never sampling
1227          * outside of viewport.
1228          */
1229         int_part = dc_fixpt_floor(*init);
1230         if (int_part < taps) {
1231                 int_part = taps - int_part;
1232                 if (int_part > *vp_offset)
1233                         int_part = *vp_offset;
1234                 *vp_offset -= int_part;
1235                 *init = dc_fixpt_add_int(*init, int_part);
1236         }
1237         /*
1238          * If taps are sampling outside of viewport at end of recout and there are more pixels
1239          * available in the surface we should increase the viewport size, regardless set vp to
1240          * only what is used.
1241          */
1242         temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
1243         *vp_size = dc_fixpt_floor(temp);
1244         if (*vp_size + *vp_offset > src_size)
1245                 *vp_size = src_size - *vp_offset;
1246
1247         /* We did all the math assuming we are scanning same direction as display does,
1248          * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
1249          * is flipped we simply need to calculate offset from the other side of plane.
1250          * Note that outside of viewport all scaling hardware works in recout space.
1251          */
1252         if (flip_scan_dir)
1253                 *vp_offset = src_size - *vp_offset - *vp_size;
1254 }
1255
1256 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
1257 {
1258         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1259         struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
1260         struct rect src = plane_state->src_rect;
1261         struct rect recout_dst_in_active_timing;
1262         struct rect recout_clip_in_active_timing;
1263         struct rect recout_clip_in_recout_dst;
1264         struct rect overlap_in_active_timing;
1265         struct rect odm_slice = calculate_odm_slice_in_timing_active(pipe_ctx);
1266         int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
1267                                 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
1268         bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
1269
1270         recout_clip_in_active_timing = shift_rec(
1271                         &data->recout, odm_slice.x, odm_slice.y);
1272         recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(
1273                         pipe_ctx, &plane_state->dst_rect);
1274         overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing,
1275                         &recout_dst_in_active_timing);
1276         if (overlap_in_active_timing.width > 0 &&
1277                         overlap_in_active_timing.height > 0)
1278                 recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing,
1279                                 -recout_dst_in_active_timing.x,
1280                                 -recout_dst_in_active_timing.y);
1281         else
1282                 memset(&recout_clip_in_recout_dst, 0, sizeof(struct rect));
1283
1284         /*
1285          * Work in recout rotation since that requires less transformations
1286          */
1287         get_vp_scan_direction(
1288                         plane_state->rotation,
1289                         plane_state->horizontal_mirror,
1290                         &orthogonal_rotation,
1291                         &flip_vert_scan_dir,
1292                         &flip_horz_scan_dir);
1293
1294         if (orthogonal_rotation) {
1295                 swap(src.width, src.height);
1296                 swap(flip_vert_scan_dir, flip_horz_scan_dir);
1297         }
1298
1299         calculate_init_and_vp(
1300                         flip_horz_scan_dir,
1301                         recout_clip_in_recout_dst.x,
1302                         data->recout.width,
1303                         src.width,
1304                         data->taps.h_taps,
1305                         data->ratios.horz,
1306                         &data->inits.h,
1307                         &data->viewport.x,
1308                         &data->viewport.width);
1309         calculate_init_and_vp(
1310                         flip_horz_scan_dir,
1311                         recout_clip_in_recout_dst.x,
1312                         data->recout.width,
1313                         src.width / vpc_div,
1314                         data->taps.h_taps_c,
1315                         data->ratios.horz_c,
1316                         &data->inits.h_c,
1317                         &data->viewport_c.x,
1318                         &data->viewport_c.width);
1319         calculate_init_and_vp(
1320                         flip_vert_scan_dir,
1321                         recout_clip_in_recout_dst.y,
1322                         data->recout.height,
1323                         src.height,
1324                         data->taps.v_taps,
1325                         data->ratios.vert,
1326                         &data->inits.v,
1327                         &data->viewport.y,
1328                         &data->viewport.height);
1329         calculate_init_and_vp(
1330                         flip_vert_scan_dir,
1331                         recout_clip_in_recout_dst.y,
1332                         data->recout.height,
1333                         src.height / vpc_div,
1334                         data->taps.v_taps_c,
1335                         data->ratios.vert_c,
1336                         &data->inits.v_c,
1337                         &data->viewport_c.y,
1338                         &data->viewport_c.height);
1339         if (orthogonal_rotation) {
1340                 swap(data->viewport.x, data->viewport.y);
1341                 swap(data->viewport.width, data->viewport.height);
1342                 swap(data->viewport_c.x, data->viewport_c.y);
1343                 swap(data->viewport_c.width, data->viewport_c.height);
1344         }
1345         data->viewport.x += src.x;
1346         data->viewport.y += src.y;
1347         ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
1348         data->viewport_c.x += src.x / vpc_div;
1349         data->viewport_c.y += src.y / vpc_div;
1350 }
1351
1352 static bool is_subvp_high_refresh_candidate(struct dc_stream_state *stream)
1353 {
1354         uint32_t refresh_rate;
1355         struct dc *dc = stream->ctx->dc;
1356
1357         refresh_rate = (stream->timing.pix_clk_100hz * (uint64_t)100 +
1358                 stream->timing.v_total * stream->timing.h_total - (uint64_t)1);
1359         refresh_rate = div_u64(refresh_rate, stream->timing.v_total);
1360         refresh_rate = div_u64(refresh_rate, stream->timing.h_total);
1361
1362         /* If there's any stream that fits the SubVP high refresh criteria,
1363          * we must return true. This is because cursor updates are asynchronous
1364          * with full updates, so we could transition into a SubVP config and
1365          * remain in HW cursor mode if there's no cursor update which will
1366          * then cause corruption.
1367          */
1368         if ((refresh_rate >= 120 && refresh_rate <= 175 &&
1369                         stream->timing.v_addressable >= 1080 &&
1370                         stream->timing.v_addressable <= 2160) &&
1371                         (dc->current_state->stream_count > 1 ||
1372                         (dc->current_state->stream_count == 1 && !stream->allow_freesync)))
1373                 return true;
1374
1375         return false;
1376 }
1377
1378 static enum controller_dp_test_pattern convert_dp_to_controller_test_pattern(
1379                                 enum dp_test_pattern test_pattern)
1380 {
1381         enum controller_dp_test_pattern controller_test_pattern;
1382
1383         switch (test_pattern) {
1384         case DP_TEST_PATTERN_COLOR_SQUARES:
1385                 controller_test_pattern =
1386                                 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
1387         break;
1388         case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
1389                 controller_test_pattern =
1390                                 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
1391         break;
1392         case DP_TEST_PATTERN_VERTICAL_BARS:
1393                 controller_test_pattern =
1394                                 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
1395         break;
1396         case DP_TEST_PATTERN_HORIZONTAL_BARS:
1397                 controller_test_pattern =
1398                                 CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
1399         break;
1400         case DP_TEST_PATTERN_COLOR_RAMP:
1401                 controller_test_pattern =
1402                                 CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
1403         break;
1404         default:
1405                 controller_test_pattern =
1406                                 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
1407         break;
1408         }
1409
1410         return controller_test_pattern;
1411 }
1412
1413 static enum controller_dp_color_space convert_dp_to_controller_color_space(
1414                 enum dp_test_pattern_color_space color_space)
1415 {
1416         enum controller_dp_color_space controller_color_space;
1417
1418         switch (color_space) {
1419         case DP_TEST_PATTERN_COLOR_SPACE_RGB:
1420                 controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
1421                 break;
1422         case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
1423                 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
1424                 break;
1425         case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
1426                 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
1427                 break;
1428         case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
1429         default:
1430                 controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
1431                 break;
1432         }
1433
1434         return controller_color_space;
1435 }
1436
1437 void resource_build_test_pattern_params(struct resource_context *res_ctx,
1438                                 struct pipe_ctx *otg_master)
1439 {
1440         int odm_slice_width, last_odm_slice_width, offset = 0;
1441         struct pipe_ctx *opp_heads[MAX_PIPES];
1442         struct test_pattern_params *params;
1443         int odm_cnt = 1;
1444         enum controller_dp_test_pattern controller_test_pattern;
1445         enum controller_dp_color_space controller_color_space;
1446         enum dc_color_depth color_depth = otg_master->stream->timing.display_color_depth;
1447         int h_active = otg_master->stream->timing.h_addressable +
1448                 otg_master->stream->timing.h_border_left +
1449                 otg_master->stream->timing.h_border_right;
1450         int v_active = otg_master->stream->timing.v_addressable +
1451                 otg_master->stream->timing.v_border_bottom +
1452                 otg_master->stream->timing.v_border_top;
1453         int i;
1454
1455         controller_test_pattern = convert_dp_to_controller_test_pattern(
1456                         otg_master->stream->test_pattern.type);
1457         controller_color_space = convert_dp_to_controller_color_space(
1458                         otg_master->stream->test_pattern.color_space);
1459
1460         odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads);
1461
1462         odm_slice_width = h_active / odm_cnt;
1463         last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1);
1464
1465         for (i = 0; i < odm_cnt; i++) {
1466                 params = &opp_heads[i]->stream_res.test_pattern_params;
1467                 params->test_pattern = controller_test_pattern;
1468                 params->color_space = controller_color_space;
1469                 params->color_depth = color_depth;
1470                 params->height = v_active;
1471                 params->offset = offset;
1472
1473                 if (i < odm_cnt - 1)
1474                         params->width = odm_slice_width;
1475                 else
1476                         params->width = last_odm_slice_width;
1477
1478                 offset += odm_slice_width;
1479         }
1480 }
1481
1482 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
1483 {
1484         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1485         struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
1486         const struct rect odm_slice_rec = calculate_odm_slice_in_timing_active(pipe_ctx);
1487         bool res = false;
1488         DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
1489
1490         /* Invalid input */
1491         if (!plane_state->dst_rect.width ||
1492                         !plane_state->dst_rect.height ||
1493                         !plane_state->src_rect.width ||
1494                         !plane_state->src_rect.height) {
1495                 ASSERT(0);
1496                 return false;
1497         }
1498
1499         pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
1500                         pipe_ctx->plane_state->format);
1501
1502         /* Timing borders are part of vactive that we are also supposed to skip in addition
1503          * to any stream dst offset. Since dm logic assumes dst is in addressable
1504          * space we need to add the left and top borders to dst offsets temporarily.
1505          * TODO: fix in DM, stream dst is supposed to be in vactive
1506          */
1507         pipe_ctx->stream->dst.x += timing->h_border_left;
1508         pipe_ctx->stream->dst.y += timing->v_border_top;
1509
1510         /* Calculate H and V active size */
1511         pipe_ctx->plane_res.scl_data.h_active = odm_slice_rec.width;
1512         pipe_ctx->plane_res.scl_data.v_active = odm_slice_rec.height;
1513
1514         /* depends on h_active */
1515         calculate_recout(pipe_ctx);
1516         /* depends on pixel format */
1517         calculate_scaling_ratios(pipe_ctx);
1518         /* depends on scaling ratios and recout, does not calculate offset yet */
1519         calculate_viewport_size(pipe_ctx);
1520
1521         /*
1522          * LB calculations depend on vp size, h/v_active and scaling ratios
1523          * Setting line buffer pixel depth to 24bpp yields banding
1524          * on certain displays, such as the Sharp 4k. 36bpp is needed
1525          * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1526          * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
1527          * precision on DCN display engines, but apparently not for DCE, as
1528          * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
1529          * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
1530          * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
1531          * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
1532          */
1533         if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
1534                 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1535         else
1536                 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1537
1538         pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
1539
1540         if (pipe_ctx->plane_res.xfm != NULL)
1541                 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1542                                 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1543
1544         if (pipe_ctx->plane_res.dpp != NULL)
1545                 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1546                                 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1547
1548
1549         if (!res) {
1550                 /* Try 24 bpp linebuffer */
1551                 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
1552
1553                 if (pipe_ctx->plane_res.xfm != NULL)
1554                         res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1555                                         pipe_ctx->plane_res.xfm,
1556                                         &pipe_ctx->plane_res.scl_data,
1557                                         &plane_state->scaling_quality);
1558
1559                 if (pipe_ctx->plane_res.dpp != NULL)
1560                         res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1561                                         pipe_ctx->plane_res.dpp,
1562                                         &pipe_ctx->plane_res.scl_data,
1563                                         &plane_state->scaling_quality);
1564         }
1565
1566         /*
1567          * Depends on recout, scaling ratios, h_active and taps
1568          * May need to re-check lb size after this in some obscure scenario
1569          */
1570         if (res)
1571                 calculate_inits_and_viewports(pipe_ctx);
1572
1573         /*
1574          * Handle side by side and top bottom 3d recout offsets after vp calculation
1575          * since 3d is special and needs to calculate vp as if there is no recout offset
1576          * This may break with rotation, good thing we aren't mixing hw rotation and 3d
1577          */
1578         if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
1579                 ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
1580                         (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
1581                                 pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
1582                 if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1583                         pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
1584                 else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1585                         pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
1586         }
1587
1588         /* Clamp minimum viewport size */
1589         if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE)
1590                 pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
1591         if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1592                 pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
1593
1594
1595         DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d  Recout: height:%d width:%d x:%d y:%d  HACTIVE:%d VACTIVE:%d\n"
1596                         "src_rect: height:%d width:%d x:%d y:%d  dst_rect: height:%d width:%d x:%d y:%d  clip_rect: height:%d width:%d x:%d y:%d\n",
1597                         __func__,
1598                         pipe_ctx->pipe_idx,
1599                         pipe_ctx->plane_res.scl_data.viewport.height,
1600                         pipe_ctx->plane_res.scl_data.viewport.width,
1601                         pipe_ctx->plane_res.scl_data.viewport.x,
1602                         pipe_ctx->plane_res.scl_data.viewport.y,
1603                         pipe_ctx->plane_res.scl_data.recout.height,
1604                         pipe_ctx->plane_res.scl_data.recout.width,
1605                         pipe_ctx->plane_res.scl_data.recout.x,
1606                         pipe_ctx->plane_res.scl_data.recout.y,
1607                         pipe_ctx->plane_res.scl_data.h_active,
1608                         pipe_ctx->plane_res.scl_data.v_active,
1609                         plane_state->src_rect.height,
1610                         plane_state->src_rect.width,
1611                         plane_state->src_rect.x,
1612                         plane_state->src_rect.y,
1613                         plane_state->dst_rect.height,
1614                         plane_state->dst_rect.width,
1615                         plane_state->dst_rect.x,
1616                         plane_state->dst_rect.y,
1617                         plane_state->clip_rect.height,
1618                         plane_state->clip_rect.width,
1619                         plane_state->clip_rect.x,
1620                         plane_state->clip_rect.y);
1621
1622         pipe_ctx->stream->dst.x -= timing->h_border_left;
1623         pipe_ctx->stream->dst.y -= timing->v_border_top;
1624
1625         return res;
1626 }
1627
1628
1629 enum dc_status resource_build_scaling_params_for_context(
1630         const struct dc  *dc,
1631         struct dc_state *context)
1632 {
1633         int i;
1634
1635         for (i = 0; i < MAX_PIPES; i++) {
1636                 if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
1637                                 context->res_ctx.pipe_ctx[i].stream != NULL)
1638                         if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
1639                                 return DC_FAIL_SCALING;
1640         }
1641
1642         return DC_OK;
1643 }
1644
1645 struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
1646                 struct resource_context *res_ctx,
1647                 const struct resource_pool *pool,
1648                 const struct pipe_ctx *primary_pipe)
1649 {
1650         int i;
1651         struct pipe_ctx *secondary_pipe = NULL;
1652
1653         /*
1654          * We add a preferred pipe mapping to avoid the chance that
1655          * MPCCs already in use will need to be reassigned to other trees.
1656          * For example, if we went with the strict, assign backwards logic:
1657          *
1658          * (State 1)
1659          * Display A on, no surface, top pipe = 0
1660          * Display B on, no surface, top pipe = 1
1661          *
1662          * (State 2)
1663          * Display A on, no surface, top pipe = 0
1664          * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1665          *
1666          * (State 3)
1667          * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1668          * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1669          *
1670          * The state 2->3 transition requires remapping MPCC 5 from display B
1671          * to display A.
1672          *
1673          * However, with the preferred pipe logic, state 2 would look like:
1674          *
1675          * (State 2)
1676          * Display A on, no surface, top pipe = 0
1677          * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1678          *
1679          * This would then cause 2->3 to not require remapping any MPCCs.
1680          */
1681         if (primary_pipe) {
1682                 int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
1683                 if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
1684                         secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
1685                         secondary_pipe->pipe_idx = preferred_pipe_idx;
1686                 }
1687         }
1688
1689         /*
1690          * search backwards for the second pipe to keep pipe
1691          * assignment more consistent
1692          */
1693         if (!secondary_pipe)
1694                 for (i = pool->pipe_count - 1; i >= 0; i--) {
1695                         if (res_ctx->pipe_ctx[i].stream == NULL) {
1696                                 secondary_pipe = &res_ctx->pipe_ctx[i];
1697                                 secondary_pipe->pipe_idx = i;
1698                                 break;
1699                         }
1700                 }
1701
1702         return secondary_pipe;
1703 }
1704
1705 int resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(
1706                 const struct resource_context *cur_res_ctx,
1707                 struct resource_context *new_res_ctx,
1708                 const struct pipe_ctx *cur_otg_master)
1709 {
1710         const struct pipe_ctx *cur_sec_opp_head = cur_otg_master->next_odm_pipe;
1711         struct pipe_ctx *new_pipe;
1712         int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1713
1714         while (cur_sec_opp_head) {
1715                 new_pipe = &new_res_ctx->pipe_ctx[cur_sec_opp_head->pipe_idx];
1716                 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1717                         free_pipe_idx = cur_sec_opp_head->pipe_idx;
1718                         break;
1719                 }
1720                 cur_sec_opp_head = cur_sec_opp_head->next_odm_pipe;
1721         }
1722
1723         return free_pipe_idx;
1724 }
1725
1726 int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
1727                 const struct resource_context *cur_res_ctx,
1728                 struct resource_context *new_res_ctx,
1729                 const struct pipe_ctx *cur_opp_head)
1730 {
1731         const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
1732         struct pipe_ctx *new_pipe;
1733         int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1734
1735         while (cur_sec_dpp) {
1736                 /* find a free pipe used in current opp blend tree,
1737                  * this is to avoid MPO pipe switching to different opp blending
1738                  * tree
1739                  */
1740                 new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
1741                 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1742                         free_pipe_idx = cur_sec_dpp->pipe_idx;
1743                         break;
1744                 }
1745                 cur_sec_dpp = cur_sec_dpp->bottom_pipe;
1746         }
1747
1748         return free_pipe_idx;
1749 }
1750
1751 int recource_find_free_pipe_not_used_in_cur_res_ctx(
1752                 const struct resource_context *cur_res_ctx,
1753                 struct resource_context *new_res_ctx,
1754                 const struct resource_pool *pool)
1755 {
1756         int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1757         const struct pipe_ctx *new_pipe, *cur_pipe;
1758         int i;
1759
1760         for (i = 0; i < pool->pipe_count; i++) {
1761                 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1762                 new_pipe = &new_res_ctx->pipe_ctx[i];
1763
1764                 if (resource_is_pipe_type(cur_pipe, FREE_PIPE) &&
1765                                 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1766                         free_pipe_idx = i;
1767                         break;
1768                 }
1769         }
1770
1771         return free_pipe_idx;
1772 }
1773
1774 int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
1775                 const struct resource_context *cur_res_ctx,
1776                 struct resource_context *new_res_ctx,
1777                 const struct resource_pool *pool)
1778 {
1779         int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1780         const struct pipe_ctx *new_pipe, *cur_pipe;
1781         int i;
1782
1783         for (i = 0; i < pool->pipe_count; i++) {
1784                 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1785                 new_pipe = &new_res_ctx->pipe_ctx[i];
1786
1787                 if (resource_is_pipe_type(cur_pipe, OTG_MASTER) &&
1788                                 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1789                         free_pipe_idx = i;
1790                         break;
1791                 }
1792         }
1793
1794         return free_pipe_idx;
1795 }
1796
1797 int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
1798                 const struct resource_context *cur_res_ctx,
1799                 struct resource_context *new_res_ctx,
1800                 const struct resource_pool *pool)
1801 {
1802         int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1803         const struct pipe_ctx *new_pipe, *cur_pipe;
1804         int i;
1805
1806         for (i = 0; i < pool->pipe_count; i++) {
1807                 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1808                 new_pipe = &new_res_ctx->pipe_ctx[i];
1809
1810                 if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
1811                                 !resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
1812                                 resource_get_mpc_slice_index(cur_pipe) > 0 &&
1813                                 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1814                         free_pipe_idx = i;
1815                         break;
1816                 }
1817         }
1818
1819         return free_pipe_idx;
1820 }
1821
1822 int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
1823                 const struct resource_pool *pool)
1824 {
1825         int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1826         const struct pipe_ctx *new_pipe;
1827         int i;
1828
1829         for (i = 0; i < pool->pipe_count; i++) {
1830                 new_pipe = &new_res_ctx->pipe_ctx[i];
1831
1832                 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1833                         free_pipe_idx = i;
1834                         break;
1835                 }
1836         }
1837
1838         return free_pipe_idx;
1839 }
1840
1841 bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
1842 {
1843         switch (type) {
1844         case OTG_MASTER:
1845                 return !pipe_ctx->prev_odm_pipe &&
1846                                 !pipe_ctx->top_pipe &&
1847                                 pipe_ctx->stream;
1848         case OPP_HEAD:
1849                 return !pipe_ctx->top_pipe && pipe_ctx->stream;
1850         case DPP_PIPE:
1851                 return pipe_ctx->plane_state && pipe_ctx->stream;
1852         case FREE_PIPE:
1853                 return !pipe_ctx->plane_state && !pipe_ctx->stream;
1854         default:
1855                 return false;
1856         }
1857 }
1858
1859 struct pipe_ctx *resource_get_otg_master_for_stream(
1860                 struct resource_context *res_ctx,
1861                 const struct dc_stream_state *stream)
1862 {
1863         int i;
1864
1865         for (i = 0; i < MAX_PIPES; i++) {
1866                 if (res_ctx->pipe_ctx[i].stream == stream &&
1867                                 resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER))
1868                         return &res_ctx->pipe_ctx[i];
1869         }
1870         return NULL;
1871 }
1872
1873 int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master,
1874                 struct resource_context *res_ctx,
1875                 struct pipe_ctx *opp_heads[MAX_PIPES])
1876 {
1877         struct pipe_ctx *opp_head = &res_ctx->pipe_ctx[otg_master->pipe_idx];
1878         int i = 0;
1879
1880         if (!resource_is_pipe_type(otg_master, OTG_MASTER)) {
1881                 ASSERT(0);
1882                 return 0;
1883         }
1884         while (opp_head) {
1885                 ASSERT(i < MAX_PIPES);
1886                 opp_heads[i++] = opp_head;
1887                 opp_head = opp_head->next_odm_pipe;
1888         }
1889         return i;
1890 }
1891
1892 int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head,
1893                 struct resource_context *res_ctx,
1894                 struct pipe_ctx *dpp_pipes[MAX_PIPES])
1895 {
1896         struct pipe_ctx *pipe = &res_ctx->pipe_ctx[opp_head->pipe_idx];
1897         int i = 0;
1898
1899         if (!resource_is_pipe_type(opp_head, OPP_HEAD)) {
1900                 ASSERT(0);
1901                 return 0;
1902         }
1903         while (pipe && resource_is_pipe_type(pipe, DPP_PIPE)) {
1904                 ASSERT(i < MAX_PIPES);
1905                 dpp_pipes[i++] = pipe;
1906                 pipe = pipe->bottom_pipe;
1907         }
1908         return i;
1909 }
1910
1911 int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane,
1912                 struct resource_context *res_ctx,
1913                 struct pipe_ctx *dpp_pipes[MAX_PIPES])
1914 {
1915         int i = 0, j;
1916         struct pipe_ctx *pipe;
1917
1918         for (j = 0; j < MAX_PIPES; j++) {
1919                 pipe = &res_ctx->pipe_ctx[j];
1920                 if (pipe->plane_state == plane && pipe->prev_odm_pipe == NULL) {
1921                         if (resource_is_pipe_type(pipe, OPP_HEAD) ||
1922                                         pipe->top_pipe->plane_state != plane)
1923                                 break;
1924                 }
1925         }
1926
1927         if (j < MAX_PIPES) {
1928                 if (pipe->next_odm_pipe)
1929                         while (pipe) {
1930                                 dpp_pipes[i++] = pipe;
1931                                 pipe = pipe->next_odm_pipe;
1932                         }
1933                 else
1934                         while (pipe && pipe->plane_state == plane) {
1935                                 dpp_pipes[i++] = pipe;
1936                                 pipe = pipe->bottom_pipe;
1937                         }
1938         }
1939         return i;
1940 }
1941
1942 struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx)
1943 {
1944         struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx);
1945
1946         while (otg_master->prev_odm_pipe)
1947                 otg_master = otg_master->prev_odm_pipe;
1948         return otg_master;
1949 }
1950
1951 struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx)
1952 {
1953         struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx;
1954
1955         ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE));
1956         while (opp_head->top_pipe)
1957                 opp_head = opp_head->top_pipe;
1958         return opp_head;
1959 }
1960
1961 struct pipe_ctx *resource_get_primary_dpp_pipe(const struct pipe_ctx *dpp_pipe)
1962 {
1963         struct pipe_ctx *pri_dpp_pipe = (struct pipe_ctx *) dpp_pipe;
1964
1965         ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE));
1966         while (pri_dpp_pipe->prev_odm_pipe)
1967                 pri_dpp_pipe = pri_dpp_pipe->prev_odm_pipe;
1968         while (pri_dpp_pipe->top_pipe &&
1969                         pri_dpp_pipe->top_pipe->plane_state == pri_dpp_pipe->plane_state)
1970                 pri_dpp_pipe = pri_dpp_pipe->top_pipe;
1971         return pri_dpp_pipe;
1972 }
1973
1974
1975 int resource_get_mpc_slice_index(const struct pipe_ctx *pipe_ctx)
1976 {
1977         struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
1978         int index = 0;
1979
1980         while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
1981                 index++;
1982                 split_pipe = split_pipe->top_pipe;
1983         }
1984
1985         return index;
1986 }
1987
1988 int resource_get_mpc_slice_count(const struct pipe_ctx *pipe)
1989 {
1990         int mpc_split_count = 1;
1991         const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
1992
1993         while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
1994                 mpc_split_count++;
1995                 other_pipe = other_pipe->bottom_pipe;
1996         }
1997         other_pipe = pipe->top_pipe;
1998         while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
1999                 mpc_split_count++;
2000                 other_pipe = other_pipe->top_pipe;
2001         }
2002
2003         return mpc_split_count;
2004 }
2005
2006 int resource_get_odm_slice_count(const struct pipe_ctx *pipe)
2007 {
2008         int odm_split_count = 1;
2009
2010         pipe = resource_get_otg_master(pipe);
2011
2012         while (pipe->next_odm_pipe) {
2013                 odm_split_count++;
2014                 pipe = pipe->next_odm_pipe;
2015         }
2016         return odm_split_count;
2017 }
2018
2019 int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx)
2020 {
2021         int index = 0;
2022
2023         pipe_ctx = resource_get_opp_head(pipe_ctx);
2024         if (!pipe_ctx)
2025                 return 0;
2026
2027         while (pipe_ctx->prev_odm_pipe) {
2028                 index++;
2029                 pipe_ctx = pipe_ctx->prev_odm_pipe;
2030         }
2031
2032         return index;
2033 }
2034
2035 bool resource_is_pipe_topology_changed(const struct dc_state *state_a,
2036                 const struct dc_state *state_b)
2037 {
2038         int i;
2039         const struct pipe_ctx *pipe_a, *pipe_b;
2040
2041         if (state_a->stream_count != state_b->stream_count)
2042                 return true;
2043
2044         for (i = 0; i < MAX_PIPES; i++) {
2045                 pipe_a = &state_a->res_ctx.pipe_ctx[i];
2046                 pipe_b = &state_b->res_ctx.pipe_ctx[i];
2047
2048                 if (pipe_a->stream && !pipe_b->stream)
2049                         return true;
2050                 else if (!pipe_a->stream && pipe_b->stream)
2051                         return true;
2052
2053                 if (pipe_a->plane_state && !pipe_b->plane_state)
2054                         return true;
2055                 else if (!pipe_a->plane_state && pipe_b->plane_state)
2056                         return true;
2057
2058                 if (pipe_a->bottom_pipe && pipe_b->bottom_pipe) {
2059                         if (pipe_a->bottom_pipe->pipe_idx != pipe_b->bottom_pipe->pipe_idx)
2060                                 return true;
2061                         if ((pipe_a->bottom_pipe->plane_state == pipe_a->plane_state) &&
2062                                         (pipe_b->bottom_pipe->plane_state != pipe_b->plane_state))
2063                                 return true;
2064                         else if ((pipe_a->bottom_pipe->plane_state != pipe_a->plane_state) &&
2065                                         (pipe_b->bottom_pipe->plane_state == pipe_b->plane_state))
2066                                 return true;
2067                 } else if (pipe_a->bottom_pipe || pipe_b->bottom_pipe) {
2068                         return true;
2069                 }
2070
2071                 if (pipe_a->next_odm_pipe && pipe_b->next_odm_pipe) {
2072                         if (pipe_a->next_odm_pipe->pipe_idx != pipe_b->next_odm_pipe->pipe_idx)
2073                                 return true;
2074                 } else if (pipe_a->next_odm_pipe || pipe_b->next_odm_pipe) {
2075                         return true;
2076                 }
2077         }
2078         return false;
2079 }
2080
2081 bool resource_is_odm_topology_changed(const struct pipe_ctx *otg_master_a,
2082                 const struct pipe_ctx *otg_master_b)
2083 {
2084         const struct pipe_ctx *opp_head_a = otg_master_a;
2085         const struct pipe_ctx *opp_head_b = otg_master_b;
2086
2087         if (!resource_is_pipe_type(otg_master_a, OTG_MASTER) ||
2088                         !resource_is_pipe_type(otg_master_b, OTG_MASTER))
2089                 return true;
2090
2091         while (opp_head_a && opp_head_b) {
2092                 if (opp_head_a->stream_res.opp != opp_head_b->stream_res.opp)
2093                         return true;
2094                 if ((opp_head_a->next_odm_pipe && !opp_head_b->next_odm_pipe) ||
2095                                 (!opp_head_a->next_odm_pipe && opp_head_b->next_odm_pipe))
2096                         return true;
2097                 opp_head_a = opp_head_a->next_odm_pipe;
2098                 opp_head_b = opp_head_b->next_odm_pipe;
2099         }
2100
2101         return false;
2102 }
2103
2104 /*
2105  * Sample log:
2106  *    pipe topology update
2107  *  ________________________
2108  * | plane0  slice0  stream0|
2109  * |DPP0----OPP0----OTG0----| <--- case 0 (OTG master pipe with plane)
2110  * | plane1 |       |       |
2111  * |DPP1----|       |       | <--- case 5 (DPP pipe not in last slice)
2112  * | plane0  slice1 |       |
2113  * |DPP2----OPP2----|       | <--- case 2 (OPP head pipe with plane)
2114  * | plane1 |               |
2115  * |DPP3----|               | <--- case 4 (DPP pipe in last slice)
2116  * |         slice0  stream1|
2117  * |DPG4----OPP4----OTG4----| <--- case 1 (OTG master pipe without plane)
2118  * |         slice1 |       |
2119  * |DPG5----OPP5----|       | <--- case 3 (OPP head pipe without plane)
2120  * |________________________|
2121  */
2122
2123 static void resource_log_pipe(struct dc *dc, struct pipe_ctx *pipe,
2124                 int stream_idx, int slice_idx, int plane_idx, int slice_count,
2125                 bool is_primary)
2126 {
2127         DC_LOGGER_INIT(dc->ctx->logger);
2128
2129         if (slice_idx == 0 && plane_idx == 0 && is_primary) {
2130                 /* case 0 (OTG master pipe with plane) */
2131                 DC_LOG_DC(" | plane%d  slice%d  stream%d|",
2132                                 plane_idx, slice_idx, stream_idx);
2133                 DC_LOG_DC(" |DPP%d----OPP%d----OTG%d----|",
2134                                 pipe->plane_res.dpp->inst,
2135                                 pipe->stream_res.opp->inst,
2136                                 pipe->stream_res.tg->inst);
2137         } else if (slice_idx == 0 && plane_idx == -1) {
2138                 /* case 1 (OTG master pipe without plane) */
2139                 DC_LOG_DC(" |         slice%d  stream%d|",
2140                                 slice_idx, stream_idx);
2141                 DC_LOG_DC(" |DPG%d----OPP%d----OTG%d----|",
2142                                 pipe->stream_res.opp->inst,
2143                                 pipe->stream_res.opp->inst,
2144                                 pipe->stream_res.tg->inst);
2145         } else if (slice_idx != 0 && plane_idx == 0 && is_primary) {
2146                 /* case 2 (OPP head pipe with plane) */
2147                 DC_LOG_DC(" | plane%d  slice%d |       |",
2148                                 plane_idx, slice_idx);
2149                 DC_LOG_DC(" |DPP%d----OPP%d----|       |",
2150                                 pipe->plane_res.dpp->inst,
2151                                 pipe->stream_res.opp->inst);
2152         } else if (slice_idx != 0 && plane_idx == -1) {
2153                 /* case 3 (OPP head pipe without plane) */
2154                 DC_LOG_DC(" |         slice%d |       |", slice_idx);
2155                 DC_LOG_DC(" |DPG%d----OPP%d----|       |",
2156                                 pipe->plane_res.dpp->inst,
2157                                 pipe->stream_res.opp->inst);
2158         } else if (slice_idx == slice_count - 1) {
2159                 /* case 4 (DPP pipe in last slice) */
2160                 DC_LOG_DC(" | plane%d |               |", plane_idx);
2161                 DC_LOG_DC(" |DPP%d----|               |",
2162                                 pipe->plane_res.dpp->inst);
2163         } else {
2164                 /* case 5 (DPP pipe not in last slice) */
2165                 DC_LOG_DC(" | plane%d |       |       |", plane_idx);
2166                 DC_LOG_DC(" |DPP%d----|       |       |",
2167                                 pipe->plane_res.dpp->inst);
2168         }
2169 }
2170
2171 void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state)
2172 {
2173         struct pipe_ctx *otg_master;
2174         struct pipe_ctx *opp_heads[MAX_PIPES];
2175         struct pipe_ctx *dpp_pipes[MAX_PIPES];
2176
2177         int stream_idx, slice_idx, dpp_idx, plane_idx, slice_count, dpp_count;
2178         bool is_primary;
2179         DC_LOGGER_INIT(dc->ctx->logger);
2180
2181         DC_LOG_DC("    pipe topology update");
2182         DC_LOG_DC("  ________________________");
2183         for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) {
2184                 otg_master = resource_get_otg_master_for_stream(
2185                                 &state->res_ctx, state->streams[stream_idx]);
2186                 if (!otg_master || otg_master->stream_res.tg == NULL) {
2187                         DC_LOG_DC("topology update: otg_master NULL stream_idx %d!\n", stream_idx);
2188                         return;
2189                 }
2190                 slice_count = resource_get_opp_heads_for_otg_master(otg_master,
2191                                 &state->res_ctx, opp_heads);
2192                 for (slice_idx = 0; slice_idx < slice_count; slice_idx++) {
2193                         plane_idx = -1;
2194                         if (opp_heads[slice_idx]->plane_state) {
2195                                 dpp_count = resource_get_dpp_pipes_for_opp_head(
2196                                                 opp_heads[slice_idx],
2197                                                 &state->res_ctx,
2198                                                 dpp_pipes);
2199                                 for (dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) {
2200                                         is_primary = !dpp_pipes[dpp_idx]->top_pipe ||
2201                                                         dpp_pipes[dpp_idx]->top_pipe->plane_state != dpp_pipes[dpp_idx]->plane_state;
2202                                         if (is_primary)
2203                                                 plane_idx++;
2204                                         resource_log_pipe(dc, dpp_pipes[dpp_idx],
2205                                                         stream_idx, slice_idx,
2206                                                         plane_idx, slice_count,
2207                                                         is_primary);
2208                                 }
2209                         } else {
2210                                 resource_log_pipe(dc, opp_heads[slice_idx],
2211                                                 stream_idx, slice_idx, plane_idx,
2212                                                 slice_count, true);
2213                         }
2214
2215                 }
2216         }
2217         DC_LOG_DC(" |________________________|\n");
2218 }
2219
2220 static struct pipe_ctx *get_tail_pipe(
2221                 struct pipe_ctx *head_pipe)
2222 {
2223         struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe;
2224
2225         while (tail_pipe) {
2226                 head_pipe = tail_pipe;
2227                 tail_pipe = tail_pipe->bottom_pipe;
2228         }
2229
2230         return head_pipe;
2231 }
2232
2233 static struct pipe_ctx *get_last_opp_head(
2234                 struct pipe_ctx *opp_head)
2235 {
2236         ASSERT(resource_is_pipe_type(opp_head, OPP_HEAD));
2237         while (opp_head->next_odm_pipe)
2238                 opp_head = opp_head->next_odm_pipe;
2239         return opp_head;
2240 }
2241
2242 static struct pipe_ctx *get_last_dpp_pipe_in_mpcc_combine(
2243                 struct pipe_ctx *dpp_pipe)
2244 {
2245         ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE));
2246         while (dpp_pipe->bottom_pipe &&
2247                         dpp_pipe->plane_state == dpp_pipe->bottom_pipe->plane_state)
2248                 dpp_pipe = dpp_pipe->bottom_pipe;
2249         return dpp_pipe;
2250 }
2251
2252 static bool update_pipe_params_after_odm_slice_count_change(
2253                 struct pipe_ctx *otg_master,
2254                 struct dc_state *context,
2255                 const struct resource_pool *pool)
2256 {
2257         int i;
2258         struct pipe_ctx *pipe;
2259         bool result = true;
2260
2261         for (i = 0; i < pool->pipe_count && result; i++) {
2262                 pipe = &context->res_ctx.pipe_ctx[i];
2263                 if (pipe->stream == otg_master->stream && pipe->plane_state)
2264                         result = resource_build_scaling_params(pipe);
2265         }
2266
2267         if (pool->funcs->build_pipe_pix_clk_params)
2268                 pool->funcs->build_pipe_pix_clk_params(otg_master);
2269         return result;
2270 }
2271
2272 static bool update_pipe_params_after_mpc_slice_count_change(
2273                 const struct dc_plane_state *plane,
2274                 struct dc_state *context,
2275                 const struct resource_pool *pool)
2276 {
2277         int i;
2278         struct pipe_ctx *pipe;
2279         bool result = true;
2280
2281         for (i = 0; i < pool->pipe_count && result; i++) {
2282                 pipe = &context->res_ctx.pipe_ctx[i];
2283                 if (pipe->plane_state == plane)
2284                         result = resource_build_scaling_params(pipe);
2285         }
2286         return result;
2287 }
2288
2289 static int acquire_first_split_pipe(
2290                 struct resource_context *res_ctx,
2291                 const struct resource_pool *pool,
2292                 struct dc_stream_state *stream)
2293 {
2294         int i;
2295
2296         for (i = 0; i < pool->pipe_count; i++) {
2297                 struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
2298
2299                 if (split_pipe->top_pipe &&
2300                                 split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
2301                         split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
2302                         if (split_pipe->bottom_pipe)
2303                                 split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
2304
2305                         if (split_pipe->top_pipe->plane_state)
2306                                 resource_build_scaling_params(split_pipe->top_pipe);
2307
2308                         memset(split_pipe, 0, sizeof(*split_pipe));
2309                         split_pipe->stream_res.tg = pool->timing_generators[i];
2310                         split_pipe->plane_res.hubp = pool->hubps[i];
2311                         split_pipe->plane_res.ipp = pool->ipps[i];
2312                         split_pipe->plane_res.dpp = pool->dpps[i];
2313                         split_pipe->stream_res.opp = pool->opps[i];
2314                         split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
2315                         split_pipe->pipe_idx = i;
2316
2317                         split_pipe->stream = stream;
2318                         return i;
2319                 }
2320         }
2321         return FREE_PIPE_INDEX_NOT_FOUND;
2322 }
2323
2324 static void update_stream_engine_usage(
2325                 struct resource_context *res_ctx,
2326                 const struct resource_pool *pool,
2327                 struct stream_encoder *stream_enc,
2328                 bool acquired)
2329 {
2330         int i;
2331
2332         for (i = 0; i < pool->stream_enc_count; i++) {
2333                 if (pool->stream_enc[i] == stream_enc)
2334                         res_ctx->is_stream_enc_acquired[i] = acquired;
2335         }
2336 }
2337
2338 static void update_hpo_dp_stream_engine_usage(
2339                 struct resource_context *res_ctx,
2340                 const struct resource_pool *pool,
2341                 struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
2342                 bool acquired)
2343 {
2344         int i;
2345
2346         for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
2347                 if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
2348                         res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
2349         }
2350 }
2351
2352 static inline int find_acquired_hpo_dp_link_enc_for_link(
2353                 const struct resource_context *res_ctx,
2354                 const struct dc_link *link)
2355 {
2356         int i;
2357
2358         for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
2359                 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
2360                                 res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
2361                         return i;
2362
2363         return -1;
2364 }
2365
2366 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
2367                 const struct resource_pool *pool)
2368 {
2369         int i;
2370
2371         for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
2372                 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
2373                         break;
2374
2375         return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
2376                         i < pool->hpo_dp_link_enc_count) ? i : -1;
2377 }
2378
2379 static inline void acquire_hpo_dp_link_enc(
2380                 struct resource_context *res_ctx,
2381                 unsigned int link_index,
2382                 int enc_index)
2383 {
2384         res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
2385         res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
2386 }
2387
2388 static inline void retain_hpo_dp_link_enc(
2389                 struct resource_context *res_ctx,
2390                 int enc_index)
2391 {
2392         res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
2393 }
2394
2395 static inline void release_hpo_dp_link_enc(
2396                 struct resource_context *res_ctx,
2397                 int enc_index)
2398 {
2399         ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
2400         res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
2401 }
2402
2403 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
2404                 const struct resource_pool *pool,
2405                 struct pipe_ctx *pipe_ctx,
2406                 struct dc_stream_state *stream)
2407 {
2408         int enc_index;
2409
2410         enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2411
2412         if (enc_index >= 0) {
2413                 retain_hpo_dp_link_enc(res_ctx, enc_index);
2414         } else {
2415                 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
2416                 if (enc_index >= 0)
2417                         acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
2418         }
2419
2420         if (enc_index >= 0)
2421                 pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
2422
2423         return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
2424 }
2425
2426 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
2427                 struct pipe_ctx *pipe_ctx,
2428                 struct dc_stream_state *stream)
2429 {
2430         int enc_index;
2431
2432         enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2433
2434         if (enc_index >= 0) {
2435                 release_hpo_dp_link_enc(res_ctx, enc_index);
2436                 pipe_ctx->link_res.hpo_dp_link_enc = NULL;
2437         }
2438 }
2439
2440 enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx,
2441                 const struct resource_pool *pool,
2442                 struct dc_stream_state *stream)
2443 {
2444         struct dc *dc = stream->ctx->dc;
2445
2446         return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
2447 }
2448
2449 void resource_remove_otg_master_for_stream_output(struct dc_state *context,
2450                 const struct resource_pool *pool,
2451                 struct dc_stream_state *stream)
2452 {
2453         struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
2454                         &context->res_ctx, stream);
2455
2456         if (!otg_master)
2457                 return;
2458
2459         ASSERT(resource_get_odm_slice_count(otg_master) == 1);
2460         ASSERT(otg_master->plane_state == NULL);
2461         ASSERT(otg_master->stream_res.stream_enc);
2462         update_stream_engine_usage(
2463                         &context->res_ctx,
2464                         pool,
2465                         otg_master->stream_res.stream_enc,
2466                         false);
2467
2468         if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master)) {
2469                 update_hpo_dp_stream_engine_usage(
2470                         &context->res_ctx, pool,
2471                         otg_master->stream_res.hpo_dp_stream_enc,
2472                         false);
2473                 remove_hpo_dp_link_enc_from_ctx(
2474                                 &context->res_ctx, otg_master, stream);
2475         }
2476         if (otg_master->stream_res.audio)
2477                 update_audio_usage(
2478                         &context->res_ctx,
2479                         pool,
2480                         otg_master->stream_res.audio,
2481                         false);
2482
2483         resource_unreference_clock_source(&context->res_ctx,
2484                                           pool,
2485                                           otg_master->clock_source);
2486
2487         if (pool->funcs->remove_stream_from_ctx)
2488                 pool->funcs->remove_stream_from_ctx(
2489                                 stream->ctx->dc, context, stream);
2490         memset(otg_master, 0, sizeof(*otg_master));
2491 }
2492
2493 /* For each OPP head of an OTG master, add top plane at plane index 0.
2494  *
2495  * In the following example, the stream has 2 ODM slices without a top plane.
2496  * By adding a plane 0 to OPP heads, we are configuring our hardware to render
2497  * plane 0 by using each OPP head's DPP.
2498  *
2499  *       Inter-pipe Relation (Before Adding Plane)
2500  *        __________________________________________________
2501  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2502  *       |        |               | slice 0   |             |
2503  *       |   0    |               |blank ----ODM----------- |
2504  *       |        |               | slice 1 | |             |
2505  *       |   1    |               |blank ---- |             |
2506  *       |________|_______________|___________|_____________|
2507  *
2508  *       Inter-pipe Relation (After Adding Plane)
2509  *        __________________________________________________
2510  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2511  *       |        |  plane 0      | slice 0   |             |
2512  *       |   0    | -------------------------ODM----------- |
2513  *       |        |  plane 0      | slice 1 | |             |
2514  *       |   1    | ------------------------- |             |
2515  *       |________|_______________|___________|_____________|
2516  */
2517 static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe,
2518                 struct dc_plane_state *plane_state,
2519                 struct dc_state *context)
2520 {
2521         struct pipe_ctx *opp_head_pipe = otg_master_pipe;
2522
2523         while (opp_head_pipe) {
2524                 if (opp_head_pipe->plane_state) {
2525                         ASSERT(0);
2526                         return false;
2527                 }
2528                 opp_head_pipe->plane_state = plane_state;
2529                 opp_head_pipe = opp_head_pipe->next_odm_pipe;
2530         }
2531
2532         return true;
2533 }
2534
2535 /* For each OPP head of an OTG master, acquire a secondary DPP pipe and add
2536  * the plane. So the plane is added to all ODM slices associated with the OTG
2537  * master pipe in the bottom layer.
2538  *
2539  * In the following example, the stream has 2 ODM slices and a top plane 0.
2540  * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our
2541  * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and
2542  * render plane 1 using new pipes' DPP in the Z axis below plane 0.
2543  *
2544  *       Inter-pipe Relation (Before Adding Plane)
2545  *        __________________________________________________
2546  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2547  *       |        |  plane 0      | slice 0   |             |
2548  *       |   0    | -------------------------ODM----------- |
2549  *       |        |  plane 0      | slice 1 | |             |
2550  *       |   1    | ------------------------- |             |
2551  *       |________|_______________|___________|_____________|
2552  *
2553  *       Inter-pipe Relation (After Acquiring and Adding Plane)
2554  *        __________________________________________________
2555  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2556  *       |        |  plane 0      | slice 0   |             |
2557  *       |   0    | -------------MPC---------ODM----------- |
2558  *       |        |  plane 1    | |         | |             |
2559  *       |   2    | ------------- |         | |             |
2560  *       |        |  plane 0      | slice 1 | |             |
2561  *       |   1    | -------------MPC--------- |             |
2562  *       |        |  plane 1    | |           |             |
2563  *       |   3    | ------------- |           |             |
2564  *       |________|_______________|___________|_____________|
2565  */
2566 static bool acquire_secondary_dpp_pipes_and_add_plane(
2567                 struct pipe_ctx *otg_master_pipe,
2568                 struct dc_plane_state *plane_state,
2569                 struct dc_state *new_ctx,
2570                 struct dc_state *cur_ctx,
2571                 struct resource_pool *pool)
2572 {
2573         struct pipe_ctx *opp_head_pipe, *sec_pipe, *tail_pipe;
2574
2575         if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
2576                 ASSERT(0);
2577                 return false;
2578         }
2579
2580         opp_head_pipe = otg_master_pipe;
2581         while (opp_head_pipe) {
2582                 sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
2583                                 cur_ctx,
2584                                 new_ctx,
2585                                 pool,
2586                                 opp_head_pipe);
2587                 if (!sec_pipe) {
2588                         /* try tearing down MPCC combine */
2589                         int pipe_idx = acquire_first_split_pipe(
2590                                         &new_ctx->res_ctx, pool,
2591                                         otg_master_pipe->stream);
2592
2593                         if (pipe_idx >= 0)
2594                                 sec_pipe = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
2595                 }
2596
2597                 if (!sec_pipe)
2598                         return false;
2599
2600                 sec_pipe->plane_state = plane_state;
2601
2602                 /* establish pipe relationship */
2603                 tail_pipe = get_tail_pipe(opp_head_pipe);
2604                 tail_pipe->bottom_pipe = sec_pipe;
2605                 sec_pipe->top_pipe = tail_pipe;
2606                 sec_pipe->bottom_pipe = NULL;
2607                 if (tail_pipe->prev_odm_pipe) {
2608                         ASSERT(tail_pipe->prev_odm_pipe->bottom_pipe);
2609                         sec_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
2610                         tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = sec_pipe;
2611                 } else {
2612                         sec_pipe->prev_odm_pipe = NULL;
2613                 }
2614
2615                 opp_head_pipe = opp_head_pipe->next_odm_pipe;
2616         }
2617         return true;
2618 }
2619
2620 bool resource_append_dpp_pipes_for_plane_composition(
2621                 struct dc_state *new_ctx,
2622                 struct dc_state *cur_ctx,
2623                 struct resource_pool *pool,
2624                 struct pipe_ctx *otg_master_pipe,
2625                 struct dc_plane_state *plane_state)
2626 {
2627         if (otg_master_pipe->plane_state == NULL)
2628                 return add_plane_to_opp_head_pipes(otg_master_pipe,
2629                                 plane_state, new_ctx);
2630         else
2631                 return acquire_secondary_dpp_pipes_and_add_plane(
2632                                 otg_master_pipe, plane_state, new_ctx,
2633                                 cur_ctx, pool);
2634 }
2635
2636 void resource_remove_dpp_pipes_for_plane_composition(
2637                 struct dc_state *context,
2638                 const struct resource_pool *pool,
2639                 const struct dc_plane_state *plane_state)
2640 {
2641         int i;
2642         for (i = pool->pipe_count - 1; i >= 0; i--) {
2643                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2644
2645                 if (pipe_ctx->plane_state == plane_state) {
2646                         if (pipe_ctx->top_pipe)
2647                                 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
2648
2649                         /* Second condition is to avoid setting NULL to top pipe
2650                          * of tail pipe making it look like head pipe in subsequent
2651                          * deletes
2652                          */
2653                         if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
2654                                 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
2655
2656                         /*
2657                          * For head pipe detach surfaces from pipe for tail
2658                          * pipe just zero it out
2659                          */
2660                         if (!pipe_ctx->top_pipe)
2661                                 pipe_ctx->plane_state = NULL;
2662                         else
2663                                 memset(pipe_ctx, 0, sizeof(*pipe_ctx));
2664                 }
2665         }
2666 }
2667
2668 /*
2669  * Increase ODM slice count by 1 by acquiring pipes and adding a new ODM slice
2670  * at the last index.
2671  * return - true if a new ODM slice is added and required pipes are acquired.
2672  * false if new_ctx is no longer a valid state after new ODM slice is added.
2673  *
2674  * This is achieved by duplicating MPC blending tree from previous ODM slice.
2675  * In the following example, we have a single MPC tree and 1 ODM slice 0. We
2676  * want to add a new odm slice by duplicating the MPC blending tree and add
2677  * ODM slice 1.
2678  *
2679  *       Inter-pipe Relation (Before Acquiring and Adding ODM Slice)
2680  *        __________________________________________________
2681  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2682  *       |        |  plane 0      | slice 0   |             |
2683  *       |   0    | -------------MPC---------ODM----------- |
2684  *       |        |  plane 1    | |           |             |
2685  *       |   1    | ------------- |           |             |
2686  *       |________|_______________|___________|_____________|
2687  *
2688  *       Inter-pipe Relation (After Acquiring and Adding ODM Slice)
2689  *        __________________________________________________
2690  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2691  *       |        |  plane 0      | slice 0   |             |
2692  *       |   0    | -------------MPC---------ODM----------- |
2693  *       |        |  plane 1    | |         | |             |
2694  *       |   1    | ------------- |         | |             |
2695  *       |        |  plane 0      | slice 1 | |             |
2696  *       |   2    | -------------MPC--------- |             |
2697  *       |        |  plane 1    | |           |             |
2698  *       |   3    | ------------- |           |             |
2699  *       |________|_______________|___________|_____________|
2700  */
2701 static bool acquire_pipes_and_add_odm_slice(
2702                 struct pipe_ctx *otg_master_pipe,
2703                 struct dc_state *new_ctx,
2704                 const struct dc_state *cur_ctx,
2705                 const struct resource_pool *pool)
2706 {
2707         struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
2708         struct pipe_ctx *new_opp_head;
2709         struct pipe_ctx *last_top_dpp_pipe, *last_bottom_dpp_pipe,
2710                         *new_top_dpp_pipe, *new_bottom_dpp_pipe;
2711
2712         if (!pool->funcs->acquire_free_pipe_as_secondary_opp_head) {
2713                 ASSERT(0);
2714                 return false;
2715         }
2716         new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head(
2717                                         cur_ctx, new_ctx, pool,
2718                                         otg_master_pipe);
2719         if (!new_opp_head)
2720                 return false;
2721
2722         last_opp_head->next_odm_pipe = new_opp_head;
2723         new_opp_head->prev_odm_pipe = last_opp_head;
2724         new_opp_head->next_odm_pipe = NULL;
2725         new_opp_head->plane_state = last_opp_head->plane_state;
2726         last_top_dpp_pipe = last_opp_head;
2727         new_top_dpp_pipe = new_opp_head;
2728
2729         while (last_top_dpp_pipe->bottom_pipe) {
2730                 last_bottom_dpp_pipe = last_top_dpp_pipe->bottom_pipe;
2731                 new_bottom_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
2732                                 cur_ctx, new_ctx, pool,
2733                                 new_opp_head);
2734                 if (!new_bottom_dpp_pipe)
2735                         return false;
2736
2737                 new_bottom_dpp_pipe->plane_state = last_bottom_dpp_pipe->plane_state;
2738                 new_top_dpp_pipe->bottom_pipe = new_bottom_dpp_pipe;
2739                 new_bottom_dpp_pipe->top_pipe = new_top_dpp_pipe;
2740                 last_bottom_dpp_pipe->next_odm_pipe = new_bottom_dpp_pipe;
2741                 new_bottom_dpp_pipe->prev_odm_pipe = last_bottom_dpp_pipe;
2742                 new_bottom_dpp_pipe->next_odm_pipe = NULL;
2743                 last_top_dpp_pipe = last_bottom_dpp_pipe;
2744         }
2745
2746         return true;
2747 }
2748
2749 /*
2750  * Decrease ODM slice count by 1 by releasing pipes and removing the ODM slice
2751  * at the last index.
2752  * return - true if the last ODM slice is removed and related pipes are
2753  * released. false if there is no removable ODM slice.
2754  *
2755  * In the following example, we have 2 MPC trees and ODM slice 0 and slice 1.
2756  * We want to remove the last ODM i.e slice 1. We are releasing secondary DPP
2757  * pipe 3 and OPP head pipe 2.
2758  *
2759  *       Inter-pipe Relation (Before Releasing and Removing ODM Slice)
2760  *        __________________________________________________
2761  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2762  *       |        |  plane 0      | slice 0   |             |
2763  *       |   0    | -------------MPC---------ODM----------- |
2764  *       |        |  plane 1    | |         | |             |
2765  *       |   1    | ------------- |         | |             |
2766  *       |        |  plane 0      | slice 1 | |             |
2767  *       |   2    | -------------MPC--------- |             |
2768  *       |        |  plane 1    | |           |             |
2769  *       |   3    | ------------- |           |             |
2770  *       |________|_______________|___________|_____________|
2771  *
2772  *       Inter-pipe Relation (After Releasing and Removing ODM Slice)
2773  *        __________________________________________________
2774  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2775  *       |        |  plane 0      | slice 0   |             |
2776  *       |   0    | -------------MPC---------ODM----------- |
2777  *       |        |  plane 1    | |           |             |
2778  *       |   1    | ------------- |           |             |
2779  *       |________|_______________|___________|_____________|
2780  */
2781 static bool release_pipes_and_remove_odm_slice(
2782                 struct pipe_ctx *otg_master_pipe,
2783                 struct dc_state *context,
2784                 const struct resource_pool *pool)
2785 {
2786         struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
2787         struct pipe_ctx *tail_pipe = get_tail_pipe(last_opp_head);
2788
2789         if (!pool->funcs->release_pipe) {
2790                 ASSERT(0);
2791                 return false;
2792         }
2793
2794         if (resource_is_pipe_type(last_opp_head, OTG_MASTER))
2795                 return false;
2796
2797         while (tail_pipe->top_pipe) {
2798                 tail_pipe->prev_odm_pipe->next_odm_pipe = NULL;
2799                 tail_pipe = tail_pipe->top_pipe;
2800                 pool->funcs->release_pipe(context, tail_pipe->bottom_pipe, pool);
2801                 tail_pipe->bottom_pipe = NULL;
2802         }
2803         last_opp_head->prev_odm_pipe->next_odm_pipe = NULL;
2804         pool->funcs->release_pipe(context, last_opp_head, pool);
2805
2806         return true;
2807 }
2808
2809 /*
2810  * Increase MPC slice count by 1 by acquiring a new DPP pipe and add it as the
2811  * last MPC slice of the plane associated with dpp_pipe.
2812  *
2813  * return - true if a new MPC slice is added and required pipes are acquired.
2814  * false if new_ctx is no longer a valid state after new MPC slice is added.
2815  *
2816  * In the following example, we add a new MPC slice for plane 0 into the
2817  * new_ctx. To do so we pass pipe 0 as dpp_pipe. The function acquires a new DPP
2818  * pipe 2 for plane 0 as the bottom most pipe for plane 0.
2819  *
2820  *       Inter-pipe Relation (Before Acquiring and Adding MPC Slice)
2821  *        __________________________________________________
2822  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2823  *       |        |  plane 0      |           |             |
2824  *       |   0    | -------------MPC----------------------- |
2825  *       |        |  plane 1    | |           |             |
2826  *       |   1    | ------------- |           |             |
2827  *       |________|_______________|___________|_____________|
2828  *
2829  *       Inter-pipe Relation (After Acquiring and Adding MPC Slice)
2830  *        __________________________________________________
2831  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2832  *       |        |  plane 0      |           |             |
2833  *       |   0    | -------------MPC----------------------- |
2834  *       |        |  plane 0    | |           |             |
2835  *       |   2    | ------------- |           |             |
2836  *       |        |  plane 1    | |           |             |
2837  *       |   1    | ------------- |           |             |
2838  *       |________|_______________|___________|_____________|
2839  */
2840 static bool acquire_dpp_pipe_and_add_mpc_slice(
2841                 struct pipe_ctx *dpp_pipe,
2842                 struct dc_state *new_ctx,
2843                 const struct dc_state *cur_ctx,
2844                 const struct resource_pool *pool)
2845 {
2846         struct pipe_ctx *last_dpp_pipe =
2847                         get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
2848         struct pipe_ctx *opp_head = resource_get_opp_head(dpp_pipe);
2849         struct pipe_ctx *new_dpp_pipe;
2850
2851         if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
2852                 ASSERT(0);
2853                 return false;
2854         }
2855         new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
2856                         cur_ctx, new_ctx, pool, opp_head);
2857         if (!new_dpp_pipe || resource_get_odm_slice_count(dpp_pipe) > 1)
2858                 return false;
2859
2860         new_dpp_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
2861         if (new_dpp_pipe->bottom_pipe)
2862                 new_dpp_pipe->bottom_pipe->top_pipe = new_dpp_pipe;
2863         new_dpp_pipe->top_pipe = last_dpp_pipe;
2864         last_dpp_pipe->bottom_pipe = new_dpp_pipe;
2865         new_dpp_pipe->plane_state = last_dpp_pipe->plane_state;
2866
2867         return true;
2868 }
2869
2870 /*
2871  * Reduce MPC slice count by 1 by releasing the bottom DPP pipe in MPCC combine
2872  * with dpp_pipe and removing last MPC slice of the plane associated with
2873  * dpp_pipe.
2874  *
2875  * return - true if the last MPC slice of the plane associated with dpp_pipe is
2876  * removed and last DPP pipe in MPCC combine with dpp_pipe is released.
2877  * false if there is no removable MPC slice.
2878  *
2879  * In the following example, we remove an MPC slice for plane 0 from the
2880  * context. To do so we pass pipe 0 as dpp_pipe. The function releases pipe 1 as
2881  * it is the last pipe for plane 0.
2882  *
2883  *       Inter-pipe Relation (Before Releasing and Removing MPC Slice)
2884  *        __________________________________________________
2885  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2886  *       |        |  plane 0      |           |             |
2887  *       |   0    | -------------MPC----------------------- |
2888  *       |        |  plane 0    | |           |             |
2889  *       |   1    | ------------- |           |             |
2890  *       |        |  plane 1    | |           |             |
2891  *       |   2    | ------------- |           |             |
2892  *       |________|_______________|___________|_____________|
2893  *
2894  *       Inter-pipe Relation (After Releasing and Removing MPC Slice)
2895  *        __________________________________________________
2896  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
2897  *       |        |  plane 0      |           |             |
2898  *       |   0    | -------------MPC----------------------- |
2899  *       |        |  plane 1    | |           |             |
2900  *       |   2    | ------------- |           |             |
2901  *       |________|_______________|___________|_____________|
2902  */
2903 static bool release_dpp_pipe_and_remove_mpc_slice(
2904                 struct pipe_ctx *dpp_pipe,
2905                 struct dc_state *context,
2906                 const struct resource_pool *pool)
2907 {
2908         struct pipe_ctx *last_dpp_pipe =
2909                         get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
2910
2911         if (!pool->funcs->release_pipe) {
2912                 ASSERT(0);
2913                 return false;
2914         }
2915
2916         if (resource_is_pipe_type(last_dpp_pipe, OPP_HEAD) ||
2917                         resource_get_odm_slice_count(dpp_pipe) > 1)
2918                 return false;
2919
2920         last_dpp_pipe->top_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
2921         if (last_dpp_pipe->bottom_pipe)
2922                 last_dpp_pipe->bottom_pipe->top_pipe = last_dpp_pipe->top_pipe;
2923         pool->funcs->release_pipe(context, last_dpp_pipe, pool);
2924
2925         return true;
2926 }
2927
2928 bool resource_update_pipes_for_stream_with_slice_count(
2929                 struct dc_state *new_ctx,
2930                 const struct dc_state *cur_ctx,
2931                 const struct resource_pool *pool,
2932                 const struct dc_stream_state *stream,
2933                 int new_slice_count)
2934 {
2935         int i;
2936         struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
2937                         &new_ctx->res_ctx, stream);
2938         int cur_slice_count = resource_get_odm_slice_count(otg_master);
2939         bool result = true;
2940
2941         if (new_slice_count == cur_slice_count)
2942                 return result;
2943
2944         if (new_slice_count > cur_slice_count)
2945                 for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
2946                         result = acquire_pipes_and_add_odm_slice(
2947                                         otg_master, new_ctx, cur_ctx, pool);
2948         else
2949                 for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
2950                         result = release_pipes_and_remove_odm_slice(
2951                                         otg_master, new_ctx, pool);
2952         if (result)
2953                 result = update_pipe_params_after_odm_slice_count_change(
2954                                 otg_master, new_ctx, pool);
2955         return result;
2956 }
2957
2958 bool resource_update_pipes_for_plane_with_slice_count(
2959                 struct dc_state *new_ctx,
2960                 const struct dc_state *cur_ctx,
2961                 const struct resource_pool *pool,
2962                 const struct dc_plane_state *plane,
2963                 int new_slice_count)
2964 {
2965         int i;
2966         int dpp_pipe_count;
2967         int cur_slice_count;
2968         struct pipe_ctx *dpp_pipes[MAX_PIPES];
2969         bool result = true;
2970
2971         dpp_pipe_count = resource_get_dpp_pipes_for_plane(plane,
2972                         &new_ctx->res_ctx, dpp_pipes);
2973         ASSERT(dpp_pipe_count > 0);
2974         cur_slice_count = resource_get_mpc_slice_count(dpp_pipes[0]);
2975
2976         if (new_slice_count == cur_slice_count)
2977                 return result;
2978
2979         if (new_slice_count > cur_slice_count)
2980                 for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
2981                         result = acquire_dpp_pipe_and_add_mpc_slice(
2982                                         dpp_pipes[0], new_ctx, cur_ctx, pool);
2983         else
2984                 for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
2985                         result = release_dpp_pipe_and_remove_mpc_slice(
2986                                         dpp_pipes[0], new_ctx, pool);
2987         if (result)
2988                 result = update_pipe_params_after_mpc_slice_count_change(
2989                                 dpp_pipes[0]->plane_state, new_ctx, pool);
2990         return result;
2991 }
2992
2993 bool dc_is_timing_changed(struct dc_stream_state *cur_stream,
2994                        struct dc_stream_state *new_stream)
2995 {
2996         if (cur_stream == NULL)
2997                 return true;
2998
2999         /* If output color space is changed, need to reprogram info frames */
3000         if (cur_stream->output_color_space != new_stream->output_color_space)
3001                 return true;
3002
3003         return memcmp(
3004                 &cur_stream->timing,
3005                 &new_stream->timing,
3006                 sizeof(struct dc_crtc_timing)) != 0;
3007 }
3008
3009 static bool are_stream_backends_same(
3010         struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
3011 {
3012         if (stream_a == stream_b)
3013                 return true;
3014
3015         if (stream_a == NULL || stream_b == NULL)
3016                 return false;
3017
3018         if (dc_is_timing_changed(stream_a, stream_b))
3019                 return false;
3020
3021         if (stream_a->signal != stream_b->signal)
3022                 return false;
3023
3024         if (stream_a->dpms_off != stream_b->dpms_off)
3025                 return false;
3026
3027         return true;
3028 }
3029
3030 /*
3031  * dc_is_stream_unchanged() - Compare two stream states for equivalence.
3032  *
3033  * Checks if there a difference between the two states
3034  * that would require a mode change.
3035  *
3036  * Does not compare cursor position or attributes.
3037  */
3038 bool dc_is_stream_unchanged(
3039         struct dc_stream_state *old_stream, struct dc_stream_state *stream)
3040 {
3041
3042         if (!are_stream_backends_same(old_stream, stream))
3043                 return false;
3044
3045         if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
3046                 return false;
3047
3048         /*compare audio info*/
3049         if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
3050                 return false;
3051
3052         return true;
3053 }
3054
3055 /*
3056  * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
3057  */
3058 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
3059                                     struct dc_stream_state *stream)
3060 {
3061         if (old_stream == stream)
3062                 return true;
3063
3064         if (old_stream == NULL || stream == NULL)
3065                 return false;
3066
3067         if (memcmp(&old_stream->src,
3068                         &stream->src,
3069                         sizeof(struct rect)) != 0)
3070                 return false;
3071
3072         if (memcmp(&old_stream->dst,
3073                         &stream->dst,
3074                         sizeof(struct rect)) != 0)
3075                 return false;
3076
3077         return true;
3078 }
3079
3080 /* TODO: release audio object */
3081 void update_audio_usage(
3082                 struct resource_context *res_ctx,
3083                 const struct resource_pool *pool,
3084                 struct audio *audio,
3085                 bool acquired)
3086 {
3087         int i;
3088         for (i = 0; i < pool->audio_count; i++) {
3089                 if (pool->audios[i] == audio)
3090                         res_ctx->is_audio_acquired[i] = acquired;
3091         }
3092 }
3093
3094 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
3095                 struct resource_context *res_ctx,
3096                 const struct resource_pool *pool,
3097                 struct dc_stream_state *stream)
3098 {
3099         int i;
3100
3101         for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
3102                 if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
3103                                 pool->hpo_dp_stream_enc[i]) {
3104
3105                         return pool->hpo_dp_stream_enc[i];
3106                 }
3107         }
3108
3109         return NULL;
3110 }
3111
3112 static struct audio *find_first_free_audio(
3113                 struct resource_context *res_ctx,
3114                 const struct resource_pool *pool,
3115                 enum engine_id id,
3116                 enum dce_version dc_version)
3117 {
3118         int i, available_audio_count;
3119
3120         available_audio_count = pool->audio_count;
3121
3122         for (i = 0; i < available_audio_count; i++) {
3123                 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
3124                         /*we have enough audio endpoint, find the matching inst*/
3125                         if (id != i)
3126                                 continue;
3127                         return pool->audios[i];
3128                 }
3129         }
3130
3131         /* use engine id to find free audio */
3132         if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
3133                 return pool->audios[id];
3134         }
3135         /*not found the matching one, first come first serve*/
3136         for (i = 0; i < available_audio_count; i++) {
3137                 if (res_ctx->is_audio_acquired[i] == false) {
3138                         return pool->audios[i];
3139                 }
3140         }
3141         return NULL;
3142 }
3143
3144 static struct dc_stream_state *find_pll_sharable_stream(
3145                 struct dc_stream_state *stream_needs_pll,
3146                 struct dc_state *context)
3147 {
3148         int i;
3149
3150         for (i = 0; i < context->stream_count; i++) {
3151                 struct dc_stream_state *stream_has_pll = context->streams[i];
3152
3153                 /* We are looking for non dp, non virtual stream */
3154                 if (resource_are_streams_timing_synchronizable(
3155                         stream_needs_pll, stream_has_pll)
3156                         && !dc_is_dp_signal(stream_has_pll->signal)
3157                         && stream_has_pll->link->connector_signal
3158                         != SIGNAL_TYPE_VIRTUAL)
3159                         return stream_has_pll;
3160
3161         }
3162
3163         return NULL;
3164 }
3165
3166 static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
3167 {
3168         uint32_t pix_clk = timing->pix_clk_100hz;
3169         uint32_t normalized_pix_clk = pix_clk;
3170
3171         if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
3172                 pix_clk /= 2;
3173         if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
3174                 switch (timing->display_color_depth) {
3175                 case COLOR_DEPTH_666:
3176                 case COLOR_DEPTH_888:
3177                         normalized_pix_clk = pix_clk;
3178                         break;
3179                 case COLOR_DEPTH_101010:
3180                         normalized_pix_clk = (pix_clk * 30) / 24;
3181                         break;
3182                 case COLOR_DEPTH_121212:
3183                         normalized_pix_clk = (pix_clk * 36) / 24;
3184                 break;
3185                 case COLOR_DEPTH_161616:
3186                         normalized_pix_clk = (pix_clk * 48) / 24;
3187                 break;
3188                 default:
3189                         ASSERT(0);
3190                 break;
3191                 }
3192         }
3193         return normalized_pix_clk;
3194 }
3195
3196 static void calculate_phy_pix_clks(struct dc_stream_state *stream)
3197 {
3198         /* update actual pixel clock on all streams */
3199         if (dc_is_hdmi_signal(stream->signal))
3200                 stream->phy_pix_clk = get_norm_pix_clk(
3201                         &stream->timing) / 10;
3202         else
3203                 stream->phy_pix_clk =
3204                         stream->timing.pix_clk_100hz / 10;
3205
3206         if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
3207                 stream->phy_pix_clk *= 2;
3208 }
3209
3210 static int acquire_resource_from_hw_enabled_state(
3211                 struct resource_context *res_ctx,
3212                 const struct resource_pool *pool,
3213                 struct dc_stream_state *stream)
3214 {
3215         struct dc_link *link = stream->link;
3216         unsigned int i, inst, tg_inst = 0;
3217         uint32_t numPipes = 1;
3218         uint32_t id_src[4] = {0};
3219
3220         /* Check for enabled DIG to identify enabled display */
3221         if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
3222                 return -1;
3223
3224         inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
3225
3226         if (inst == ENGINE_ID_UNKNOWN)
3227                 return -1;
3228
3229         for (i = 0; i < pool->stream_enc_count; i++) {
3230                 if (pool->stream_enc[i]->id == inst) {
3231                         tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
3232                                 pool->stream_enc[i]);
3233                         break;
3234                 }
3235         }
3236
3237         // tg_inst not found
3238         if (i == pool->stream_enc_count)
3239                 return -1;
3240
3241         if (tg_inst >= pool->timing_generator_count)
3242                 return -1;
3243
3244         if (!res_ctx->pipe_ctx[tg_inst].stream) {
3245                 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
3246
3247                 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
3248                 id_src[0] = tg_inst;
3249
3250                 if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
3251                         pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
3252                                                 &numPipes, &id_src[0], &id_src[1]);
3253
3254                 if (id_src[0] == 0xf && id_src[1] == 0xf) {
3255                         id_src[0] = tg_inst;
3256                         numPipes = 1;
3257                 }
3258
3259                 for (i = 0; i < numPipes; i++) {
3260                         //Check if src id invalid
3261                         if (id_src[i] == 0xf)
3262                                 return -1;
3263
3264                         pipe_ctx = &res_ctx->pipe_ctx[id_src[i]];
3265
3266                         pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
3267                         pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
3268                         pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
3269                         pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
3270                         pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
3271                         pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
3272                         pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
3273
3274                         if (pool->dpps[id_src[i]]) {
3275                                 pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;
3276
3277                                 if (pool->mpc->funcs->read_mpcc_state) {
3278                                         struct mpcc_state s = {0};
3279
3280                                         pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
3281
3282                                         if (s.dpp_id < MAX_MPCC)
3283                                                 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
3284                                                                 s.dpp_id;
3285
3286                                         if (s.bot_mpcc_id < MAX_MPCC)
3287                                                 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
3288                                                                 &pool->mpc->mpcc_array[s.bot_mpcc_id];
3289
3290                                         if (s.opp_id < MAX_OPP)
3291                                                 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
3292                                 }
3293                         }
3294                         pipe_ctx->pipe_idx = id_src[i];
3295
3296                         if (id_src[i] >= pool->timing_generator_count) {
3297                                 id_src[i] = pool->timing_generator_count - 1;
3298
3299                                 pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
3300                                 pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
3301                         }
3302
3303                         pipe_ctx->stream = stream;
3304                 }
3305
3306                 if (numPipes == 2) {
3307                         stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
3308                         res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
3309                         res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
3310                         res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
3311                         res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
3312                 } else
3313                         stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
3314
3315                 return id_src[0];
3316         }
3317
3318         return -1;
3319 }
3320
3321 static void mark_seamless_boot_stream(
3322                 const struct dc  *dc,
3323                 struct dc_stream_state *stream)
3324 {
3325         struct dc_bios *dcb = dc->ctx->dc_bios;
3326
3327         if (dc->config.allow_seamless_boot_optimization &&
3328                         !dcb->funcs->is_accelerated_mode(dcb)) {
3329                 if (dc_validate_boot_timing(dc, stream->sink, &stream->timing))
3330                         stream->apply_seamless_boot_optimization = true;
3331         }
3332 }
3333
3334 /*
3335  * Acquire a pipe as OTG master and assign to the stream in new dc context.
3336  * return - true if OTG master pipe is acquired and new dc context is updated.
3337  * false if it fails to acquire an OTG master pipe for this stream.
3338  *
3339  * In the example below, we acquired pipe 0 as OTG master pipe for the stream.
3340  * After the function its Inter-pipe Relation is represented by the diagram
3341  * below.
3342  *
3343  *       Inter-pipe Relation
3344  *        __________________________________________________
3345  *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
3346  *       |        |               |           |             |
3347  *       |   0    |               |blank ------------------ |
3348  *       |________|_______________|___________|_____________|
3349  */
3350 static bool acquire_otg_master_pipe_for_stream(
3351                 const struct dc_state *cur_ctx,
3352                 struct dc_state *new_ctx,
3353                 const struct resource_pool *pool,
3354                 struct dc_stream_state *stream)
3355 {
3356         /* TODO: Move this function to DCN specific resource file and acquire
3357          * DSC resource here. The reason is that the function should have the
3358          * same level of responsibility as when we acquire secondary OPP head.
3359          * We acquire DSC when we acquire secondary OPP head, so we should
3360          * acquire DSC when we acquire OTG master.
3361          */
3362         int pipe_idx;
3363         struct pipe_ctx *pipe_ctx = NULL;
3364
3365         /*
3366          * Upper level code is responsible to optimize unnecessary addition and
3367          * removal for unchanged streams. So unchanged stream will keep the same
3368          * OTG master instance allocated. When current stream is removed and a
3369          * new stream is added, we want to reuse the OTG instance made available
3370          * by the removed stream first. If not found, we try to avoid of using
3371          * any free pipes already used in current context as this could tear
3372          * down exiting ODM/MPC/MPO configuration unnecessarily.
3373          */
3374         pipe_idx = recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
3375                         &cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
3376         if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
3377                 pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx(
3378                                 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
3379         if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
3380                 pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool);
3381         if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) {
3382                 pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
3383                 memset(pipe_ctx, 0, sizeof(*pipe_ctx));
3384                 pipe_ctx->pipe_idx = pipe_idx;
3385                 pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx];
3386                 pipe_ctx->plane_res.mi = pool->mis[pipe_idx];
3387                 pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx];
3388                 pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx];
3389                 pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx];
3390                 pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx];
3391                 pipe_ctx->stream_res.opp = pool->opps[pipe_idx];
3392                 if (pool->dpps[pipe_idx])
3393                         pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
3394
3395                 if (pipe_idx >= pool->timing_generator_count) {
3396                         int tg_inst = pool->timing_generator_count - 1;
3397
3398                         pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
3399                         pipe_ctx->stream_res.opp = pool->opps[tg_inst];
3400                 }
3401
3402                 pipe_ctx->stream = stream;
3403         } else {
3404                 pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream);
3405         }
3406
3407         return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND;
3408 }
3409
3410 enum dc_status resource_map_pool_resources(
3411                 const struct dc  *dc,
3412                 struct dc_state *context,
3413                 struct dc_stream_state *stream)
3414 {
3415         const struct resource_pool *pool = dc->res_pool;
3416         int i;
3417         struct dc_context *dc_ctx = dc->ctx;
3418         struct pipe_ctx *pipe_ctx = NULL;
3419         int pipe_idx = -1;
3420         bool acquired = false;
3421
3422         calculate_phy_pix_clks(stream);
3423
3424         mark_seamless_boot_stream(dc, stream);
3425
3426         if (stream->apply_seamless_boot_optimization) {
3427                 pipe_idx = acquire_resource_from_hw_enabled_state(
3428                                 &context->res_ctx,
3429                                 pool,
3430                                 stream);
3431                 if (pipe_idx < 0)
3432                         /* hw resource was assigned to other stream */
3433                         stream->apply_seamless_boot_optimization = false;
3434                 else
3435                         acquired = true;
3436         }
3437
3438         if (!acquired)
3439                 /* acquire new resources */
3440                 acquired = acquire_otg_master_pipe_for_stream(dc->current_state,
3441                                 context, pool, stream);
3442
3443         pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
3444
3445         if (!pipe_ctx || pipe_ctx->stream_res.tg == NULL)
3446                 return DC_NO_CONTROLLER_RESOURCE;
3447
3448         pipe_ctx->stream_res.stream_enc =
3449                 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
3450                         &context->res_ctx, pool, stream);
3451
3452         if (!pipe_ctx->stream_res.stream_enc)
3453                 return DC_NO_STREAM_ENC_RESOURCE;
3454
3455         update_stream_engine_usage(
3456                 &context->res_ctx, pool,
3457                 pipe_ctx->stream_res.stream_enc,
3458                 true);
3459
3460         /* Allocate DP HPO Stream Encoder based on signal, hw capabilities
3461          * and link settings
3462          */
3463         if (dc_is_dp_signal(stream->signal)) {
3464                 if (!dc->link_srv->dp_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings))
3465                         return DC_FAIL_DP_LINK_BANDWIDTH;
3466                 if (dc->link_srv->dp_get_encoding_format(
3467                                 &pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
3468                         pipe_ctx->stream_res.hpo_dp_stream_enc =
3469                                         find_first_free_match_hpo_dp_stream_enc_for_link(
3470                                                         &context->res_ctx, pool, stream);
3471
3472                         if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
3473                                 return DC_NO_STREAM_ENC_RESOURCE;
3474
3475                         update_hpo_dp_stream_engine_usage(
3476                                         &context->res_ctx, pool,
3477                                         pipe_ctx->stream_res.hpo_dp_stream_enc,
3478                                         true);
3479                         if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
3480                                 return DC_NO_LINK_ENC_RESOURCE;
3481                 }
3482         }
3483
3484         /* TODO: Add check if ASIC support and EDID audio */
3485         if (!stream->converter_disable_audio &&
3486             dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
3487             stream->audio_info.mode_count && stream->audio_info.flags.all) {
3488                 pipe_ctx->stream_res.audio = find_first_free_audio(
3489                 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
3490
3491                 /*
3492                  * Audio assigned in order first come first get.
3493                  * There are asics which has number of audio
3494                  * resources less then number of pipes
3495                  */
3496                 if (pipe_ctx->stream_res.audio)
3497                         update_audio_usage(&context->res_ctx, pool,
3498                                            pipe_ctx->stream_res.audio, true);
3499         }
3500
3501         /* Add ABM to the resource if on EDP */
3502         if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
3503                 if (pool->abm)
3504                         pipe_ctx->stream_res.abm = pool->abm;
3505                 else
3506                         pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
3507         }
3508
3509         for (i = 0; i < context->stream_count; i++)
3510                 if (context->streams[i] == stream) {
3511                         context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
3512                         context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
3513                         context->stream_status[i].audio_inst =
3514                                 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
3515
3516                         return DC_OK;
3517                 }
3518
3519         DC_ERROR("Stream %p not found in new ctx!\n", stream);
3520         return DC_ERROR_UNEXPECTED;
3521 }
3522
3523 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
3524 {
3525         if (dc->res_pool == NULL)
3526                 return false;
3527
3528         return dc->res_pool->res_cap->num_dsc > 0;
3529 }
3530
3531 static bool planes_changed_for_existing_stream(struct dc_state *context,
3532                                                struct dc_stream_state *stream,
3533                                                const struct dc_validation_set set[],
3534                                                int set_count)
3535 {
3536         int i, j;
3537         struct dc_stream_status *stream_status = NULL;
3538
3539         for (i = 0; i < context->stream_count; i++) {
3540                 if (context->streams[i] == stream) {
3541                         stream_status = &context->stream_status[i];
3542                         break;
3543                 }
3544         }
3545
3546         if (!stream_status)
3547                 ASSERT(0);
3548
3549         for (i = 0; i < set_count; i++)
3550                 if (set[i].stream == stream)
3551                         break;
3552
3553         if (i == set_count)
3554                 ASSERT(0);
3555
3556         if (set[i].plane_count != stream_status->plane_count)
3557                 return true;
3558
3559         for (j = 0; j < set[i].plane_count; j++)
3560                 if (set[i].plane_states[j] != stream_status->plane_states[j])
3561                         return true;
3562
3563         return false;
3564 }
3565
3566 static bool add_all_planes_for_stream(
3567                 const struct dc *dc,
3568                 struct dc_stream_state *stream,
3569                 const struct dc_validation_set set[],
3570                 int set_count,
3571                 struct dc_state *state)
3572 {
3573         int i, j;
3574
3575         for (i = 0; i < set_count; i++)
3576                 if (set[i].stream == stream)
3577                         break;
3578
3579         if (i == set_count) {
3580                 dm_error("Stream %p not found in set!\n", stream);
3581                 return false;
3582         }
3583
3584         for (j = 0; j < set[i].plane_count; j++)
3585                 if (!dc_state_add_plane(dc, stream, set[i].plane_states[j], state))
3586                         return false;
3587
3588         return true;
3589 }
3590
3591 /**
3592  * dc_validate_with_context - Validate and update the potential new stream in the context object
3593  *
3594  * @dc: Used to get the current state status
3595  * @set: An array of dc_validation_set with all the current streams reference
3596  * @set_count: Total of streams
3597  * @context: New context
3598  * @fast_validate: Enable or disable fast validation
3599  *
3600  * This function updates the potential new stream in the context object. It
3601  * creates multiple lists for the add, remove, and unchanged streams. In
3602  * particular, if the unchanged streams have a plane that changed, it is
3603  * necessary to remove all planes from the unchanged streams. In summary, this
3604  * function is responsible for validating the new context.
3605  *
3606  * Return:
3607  * In case of success, return DC_OK (1), otherwise, return a DC error.
3608  */
3609 enum dc_status dc_validate_with_context(struct dc *dc,
3610                                         const struct dc_validation_set set[],
3611                                         int set_count,
3612                                         struct dc_state *context,
3613                                         bool fast_validate)
3614 {
3615         struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
3616         struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
3617         struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
3618         int old_stream_count = context->stream_count;
3619         enum dc_status res = DC_ERROR_UNEXPECTED;
3620         int unchanged_streams_count = 0;
3621         int del_streams_count = 0;
3622         int add_streams_count = 0;
3623         bool found = false;
3624         int i, j, k;
3625
3626         DC_LOGGER_INIT(dc->ctx->logger);
3627
3628         /* First build a list of streams to be remove from current context */
3629         for (i = 0; i < old_stream_count; i++) {
3630                 struct dc_stream_state *stream = context->streams[i];
3631
3632                 for (j = 0; j < set_count; j++) {
3633                         if (stream == set[j].stream) {
3634                                 found = true;
3635                                 break;
3636                         }
3637                 }
3638
3639                 if (!found)
3640                         del_streams[del_streams_count++] = stream;
3641
3642                 found = false;
3643         }
3644
3645         /* Second, build a list of new streams */
3646         for (i = 0; i < set_count; i++) {
3647                 struct dc_stream_state *stream = set[i].stream;
3648
3649                 for (j = 0; j < old_stream_count; j++) {
3650                         if (stream == context->streams[j]) {
3651                                 found = true;
3652                                 break;
3653                         }
3654                 }
3655
3656                 if (!found)
3657                         add_streams[add_streams_count++] = stream;
3658
3659                 found = false;
3660         }
3661
3662         /* Build a list of unchanged streams which is necessary for handling
3663          * planes change such as added, removed, and updated.
3664          */
3665         for (i = 0; i < set_count; i++) {
3666                 /* Check if stream is part of the delete list */
3667                 for (j = 0; j < del_streams_count; j++) {
3668                         if (set[i].stream == del_streams[j]) {
3669                                 found = true;
3670                                 break;
3671                         }
3672                 }
3673
3674                 if (!found) {
3675                         /* Check if stream is part of the add list */
3676                         for (j = 0; j < add_streams_count; j++) {
3677                                 if (set[i].stream == add_streams[j]) {
3678                                         found = true;
3679                                         break;
3680                                 }
3681                         }
3682                 }
3683
3684                 if (!found)
3685                         unchanged_streams[unchanged_streams_count++] = set[i].stream;
3686
3687                 found = false;
3688         }
3689
3690         /* Remove all planes for unchanged streams if planes changed */
3691         for (i = 0; i < unchanged_streams_count; i++) {
3692                 if (planes_changed_for_existing_stream(context,
3693                                                        unchanged_streams[i],
3694                                                        set,
3695                                                        set_count)) {
3696
3697                         if (!dc_state_rem_all_planes_for_stream(dc,
3698                                                           unchanged_streams[i],
3699                                                           context)) {
3700                                 res = DC_FAIL_DETACH_SURFACES;
3701                                 goto fail;
3702                         }
3703                 }
3704         }
3705
3706         /* Remove all planes for removed streams and then remove the streams */
3707         for (i = 0; i < del_streams_count; i++) {
3708                 /* Need to cpy the dwb data from the old stream in order to efc to work */
3709                 if (del_streams[i]->num_wb_info > 0) {
3710                         for (j = 0; j < add_streams_count; j++) {
3711                                 if (del_streams[i]->sink == add_streams[j]->sink) {
3712                                         add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
3713                                         for (k = 0; k < del_streams[i]->num_wb_info; k++)
3714                                                 add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
3715                                 }
3716                         }
3717                 }
3718
3719                 if (dc_state_get_stream_subvp_type(context, del_streams[i]) == SUBVP_PHANTOM) {
3720                         /* remove phantoms specifically */
3721                         if (!dc_state_rem_all_phantom_planes_for_stream(dc, del_streams[i], context, true)) {
3722                                 res = DC_FAIL_DETACH_SURFACES;
3723                                 goto fail;
3724                         }
3725
3726                         res = dc_state_remove_phantom_stream(dc, context, del_streams[i]);
3727                         dc_state_release_phantom_stream(dc, context, del_streams[i]);
3728                 } else {
3729                         if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) {
3730                                 res = DC_FAIL_DETACH_SURFACES;
3731                                 goto fail;
3732                         }
3733
3734                         res = dc_state_remove_stream(dc, context, del_streams[i]);
3735                 }
3736
3737                 if (res != DC_OK)
3738                         goto fail;
3739         }
3740
3741         /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx
3742          * matches. This may change in the future if seamless_boot_stream can be
3743          * multiple.
3744          */
3745         for (i = 0; i < add_streams_count; i++) {
3746                 mark_seamless_boot_stream(dc, add_streams[i]);
3747                 if (add_streams[i]->apply_seamless_boot_optimization && i != 0) {
3748                         struct dc_stream_state *temp = add_streams[0];
3749
3750                         add_streams[0] = add_streams[i];
3751                         add_streams[i] = temp;
3752                         break;
3753                 }
3754         }
3755
3756         /* Add new streams and then add all planes for the new stream */
3757         for (i = 0; i < add_streams_count; i++) {
3758                 calculate_phy_pix_clks(add_streams[i]);
3759                 res = dc_state_add_stream(dc, context, add_streams[i]);
3760                 if (res != DC_OK)
3761                         goto fail;
3762
3763                 if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
3764                         res = DC_FAIL_ATTACH_SURFACES;
3765                         goto fail;
3766                 }
3767         }
3768
3769         /* Add all planes for unchanged streams if planes changed */
3770         for (i = 0; i < unchanged_streams_count; i++) {
3771                 if (planes_changed_for_existing_stream(context,
3772                                                        unchanged_streams[i],
3773                                                        set,
3774                                                        set_count)) {
3775                         if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
3776                                 res = DC_FAIL_ATTACH_SURFACES;
3777                                 goto fail;
3778                         }
3779                 }
3780         }
3781
3782         res = dc_validate_global_state(dc, context, fast_validate);
3783
3784 fail:
3785         if (res != DC_OK)
3786                 DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
3787                                __func__,
3788                                res);
3789
3790         return res;
3791 }
3792
3793 /**
3794  * dc_validate_global_state() - Determine if hardware can support a given state
3795  *
3796  * @dc: dc struct for this driver
3797  * @new_ctx: state to be validated
3798  * @fast_validate: set to true if only yes/no to support matters
3799  *
3800  * Checks hardware resource availability and bandwidth requirement.
3801  *
3802  * Return:
3803  * DC_OK if the result can be programmed. Otherwise, an error code.
3804  */
3805 enum dc_status dc_validate_global_state(
3806                 struct dc *dc,
3807                 struct dc_state *new_ctx,
3808                 bool fast_validate)
3809 {
3810         enum dc_status result = DC_ERROR_UNEXPECTED;
3811         int i, j;
3812
3813         if (!new_ctx)
3814                 return DC_ERROR_UNEXPECTED;
3815
3816         if (dc->res_pool->funcs->validate_global) {
3817                 result = dc->res_pool->funcs->validate_global(dc, new_ctx);
3818                 if (result != DC_OK)
3819                         return result;
3820         }
3821
3822         for (i = 0; i < new_ctx->stream_count; i++) {
3823                 struct dc_stream_state *stream = new_ctx->streams[i];
3824
3825                 for (j = 0; j < dc->res_pool->pipe_count; j++) {
3826                         struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
3827
3828                         if (pipe_ctx->stream != stream)
3829                                 continue;
3830
3831                         if (dc->res_pool->funcs->patch_unknown_plane_state &&
3832                                         pipe_ctx->plane_state &&
3833                                         pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
3834                                 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
3835                                 if (result != DC_OK)
3836                                         return result;
3837                         }
3838
3839                         /* Switch to dp clock source only if there is
3840                          * no non dp stream that shares the same timing
3841                          * with the dp stream.
3842                          */
3843                         if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
3844                                 !find_pll_sharable_stream(stream, new_ctx)) {
3845
3846                                 resource_unreference_clock_source(
3847                                                 &new_ctx->res_ctx,
3848                                                 dc->res_pool,
3849                                                 pipe_ctx->clock_source);
3850
3851                                 pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
3852                                 resource_reference_clock_source(
3853                                                 &new_ctx->res_ctx,
3854                                                 dc->res_pool,
3855                                                  pipe_ctx->clock_source);
3856                         }
3857                 }
3858         }
3859
3860         result = resource_build_scaling_params_for_context(dc, new_ctx);
3861
3862         if (result == DC_OK)
3863                 if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
3864                         result = DC_FAIL_BANDWIDTH_VALIDATE;
3865
3866         /*
3867          * Only update link encoder to stream assignment after bandwidth validation passed.
3868          * TODO: Split out assignment and validation.
3869          */
3870         if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false)
3871                 dc->res_pool->funcs->link_encs_assign(
3872                         dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
3873
3874         return result;
3875 }
3876
3877 static void patch_gamut_packet_checksum(
3878                 struct dc_info_packet *gamut_packet)
3879 {
3880         /* For gamut we recalc checksum */
3881         if (gamut_packet->valid) {
3882                 uint8_t chk_sum = 0;
3883                 uint8_t *ptr;
3884                 uint8_t i;
3885
3886                 /*start of the Gamut data. */
3887                 ptr = &gamut_packet->sb[3];
3888
3889                 for (i = 0; i <= gamut_packet->sb[1]; i++)
3890                         chk_sum += ptr[i];
3891
3892                 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
3893         }
3894 }
3895
3896 static void set_avi_info_frame(
3897                 struct dc_info_packet *info_packet,
3898                 struct pipe_ctx *pipe_ctx)
3899 {
3900         struct dc_stream_state *stream = pipe_ctx->stream;
3901         enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
3902         uint32_t pixel_encoding = 0;
3903         enum scanning_type scan_type = SCANNING_TYPE_NODATA;
3904         enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
3905         uint8_t *check_sum = NULL;
3906         uint8_t byte_index = 0;
3907         union hdmi_info_packet hdmi_info;
3908         unsigned int vic = pipe_ctx->stream->timing.vic;
3909         unsigned int rid = pipe_ctx->stream->timing.rid;
3910         unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
3911         enum dc_timing_3d_format format;
3912
3913         memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
3914
3915         color_space = pipe_ctx->stream->output_color_space;
3916         if (color_space == COLOR_SPACE_UNKNOWN)
3917                 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
3918                         COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
3919
3920         /* Initialize header */
3921         hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
3922         /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
3923         * not be used in HDMI 2.0 (Section 10.1) */
3924         hdmi_info.bits.header.version = 2;
3925         hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
3926
3927         /*
3928          * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
3929          * according to HDMI 2.0 spec (Section 10.1)
3930          */
3931
3932         switch (stream->timing.pixel_encoding) {
3933         case PIXEL_ENCODING_YCBCR422:
3934                 pixel_encoding = 1;
3935                 break;
3936
3937         case PIXEL_ENCODING_YCBCR444:
3938                 pixel_encoding = 2;
3939                 break;
3940         case PIXEL_ENCODING_YCBCR420:
3941                 pixel_encoding = 3;
3942                 break;
3943
3944         case PIXEL_ENCODING_RGB:
3945         default:
3946                 pixel_encoding = 0;
3947         }
3948
3949         /* Y0_Y1_Y2 : The pixel encoding */
3950         /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
3951         hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding;
3952
3953         /* A0 = 1 Active Format Information valid */
3954         hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
3955
3956         /* B0, B1 = 3; Bar info data is valid */
3957         hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
3958
3959         hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
3960
3961         /* S0, S1 : Underscan / Overscan */
3962         /* TODO: un-hardcode scan type */
3963         scan_type = SCANNING_TYPE_UNDERSCAN;
3964         hdmi_info.bits.S0_S1 = scan_type;
3965
3966         /* C0, C1 : Colorimetry */
3967         switch (color_space) {
3968         case COLOR_SPACE_YCBCR709:
3969         case COLOR_SPACE_YCBCR709_LIMITED:
3970                 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
3971                 break;
3972         case COLOR_SPACE_YCBCR601:
3973         case COLOR_SPACE_YCBCR601_LIMITED:
3974                 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
3975                 break;
3976         case COLOR_SPACE_2020_RGB_FULLRANGE:
3977         case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
3978         case COLOR_SPACE_2020_YCBCR:
3979                 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
3980                 hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
3981                 break;
3982         case COLOR_SPACE_ADOBERGB:
3983                 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
3984                 hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
3985                 break;
3986         case COLOR_SPACE_SRGB:
3987         default:
3988                 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
3989                 break;
3990         }
3991
3992         if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR &&
3993                         stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) {
3994                 hdmi_info.bits.EC0_EC2 = 0;
3995                 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
3996         }
3997
3998         /* TODO: un-hardcode aspect ratio */
3999         aspect = stream->timing.aspect_ratio;
4000
4001         switch (aspect) {
4002         case ASPECT_RATIO_4_3:
4003         case ASPECT_RATIO_16_9:
4004                 hdmi_info.bits.M0_M1 = aspect;
4005                 break;
4006
4007         case ASPECT_RATIO_NO_DATA:
4008         case ASPECT_RATIO_64_27:
4009         case ASPECT_RATIO_256_135:
4010         default:
4011                 hdmi_info.bits.M0_M1 = 0;
4012         }
4013
4014         /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
4015         hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
4016
4017         switch (stream->content_type) {
4018         case DISPLAY_CONTENT_TYPE_NO_DATA:
4019                 hdmi_info.bits.CN0_CN1 = 0;
4020                 hdmi_info.bits.ITC = 1;
4021                 break;
4022         case DISPLAY_CONTENT_TYPE_GRAPHICS:
4023                 hdmi_info.bits.CN0_CN1 = 0;
4024                 hdmi_info.bits.ITC = 1;
4025                 break;
4026         case DISPLAY_CONTENT_TYPE_PHOTO:
4027                 hdmi_info.bits.CN0_CN1 = 1;
4028                 hdmi_info.bits.ITC = 1;
4029                 break;
4030         case DISPLAY_CONTENT_TYPE_CINEMA:
4031                 hdmi_info.bits.CN0_CN1 = 2;
4032                 hdmi_info.bits.ITC = 1;
4033                 break;
4034         case DISPLAY_CONTENT_TYPE_GAME:
4035                 hdmi_info.bits.CN0_CN1 = 3;
4036                 hdmi_info.bits.ITC = 1;
4037                 break;
4038         }
4039
4040         if (stream->qs_bit == 1) {
4041                 if (color_space == COLOR_SPACE_SRGB ||
4042                         color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
4043                         hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_FULL_RANGE;
4044                 else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
4045                                         color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
4046                         hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_LIMITED_RANGE;
4047                 else
4048                         hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
4049         } else
4050                 hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
4051
4052         /* TODO : We should handle YCC quantization */
4053         /* but we do not have matrix calculation */
4054         hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
4055
4056         ///VIC
4057         if (pipe_ctx->stream->timing.hdmi_vic != 0)
4058                 vic = 0;
4059         format = stream->timing.timing_3d_format;
4060         /*todo, add 3DStereo support*/
4061         if (format != TIMING_3D_FORMAT_NONE) {
4062                 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
4063                 switch (pipe_ctx->stream->timing.hdmi_vic) {
4064                 case 1:
4065                         vic = 95;
4066                         break;
4067                 case 2:
4068                         vic = 94;
4069                         break;
4070                 case 3:
4071                         vic = 93;
4072                         break;
4073                 case 4:
4074                         vic = 98;
4075                         break;
4076                 default:
4077                         break;
4078                 }
4079         }
4080         /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
4081         hdmi_info.bits.VIC0_VIC7 = vic;
4082         if (vic >= 128)
4083                 hdmi_info.bits.header.version = 3;
4084         /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
4085          * the Source shall use 20 AVI InfoFrame Version 4
4086          */
4087         if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
4088                         hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
4089                 hdmi_info.bits.header.version = 4;
4090                 hdmi_info.bits.header.length = 14;
4091         }
4092
4093         if (rid != 0 && fr_ind != 0) {
4094                 hdmi_info.bits.header.version = 5;
4095                 hdmi_info.bits.header.length = 15;
4096
4097                 hdmi_info.bits.FR0_FR3 = fr_ind & 0xF;
4098                 hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1;
4099                 hdmi_info.bits.RID0_RID5 = rid;
4100         }
4101
4102         /* pixel repetition
4103          * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
4104          * repetition start from 1 */
4105         hdmi_info.bits.PR0_PR3 = 0;
4106
4107         /* Bar Info
4108          * barTop:    Line Number of End of Top Bar.
4109          * barBottom: Line Number of Start of Bottom Bar.
4110          * barLeft:   Pixel Number of End of Left Bar.
4111          * barRight:  Pixel Number of Start of Right Bar. */
4112         hdmi_info.bits.bar_top = stream->timing.v_border_top;
4113         hdmi_info.bits.bar_bottom = (stream->timing.v_total
4114                         - stream->timing.v_border_bottom + 1);
4115         hdmi_info.bits.bar_left  = stream->timing.h_border_left;
4116         hdmi_info.bits.bar_right = (stream->timing.h_total
4117                         - stream->timing.h_border_right + 1);
4118
4119     /* Additional Colorimetry Extension
4120      * Used in conduction with C0-C1 and EC0-EC2
4121      * 0 = DCI-P3 RGB (D65)
4122      * 1 = DCI-P3 RGB (theater)
4123      */
4124         hdmi_info.bits.ACE0_ACE3 = 0;
4125
4126         /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
4127         check_sum = &hdmi_info.packet_raw_data.sb[0];
4128
4129         *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
4130
4131         for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
4132                 *check_sum += hdmi_info.packet_raw_data.sb[byte_index];
4133
4134         /* one byte complement */
4135         *check_sum = (uint8_t) (0x100 - *check_sum);
4136
4137         /* Store in hw_path_mode */
4138         info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
4139         info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
4140         info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
4141
4142         for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
4143                 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
4144
4145         info_packet->valid = true;
4146 }
4147
4148 static void set_vendor_info_packet(
4149                 struct dc_info_packet *info_packet,
4150                 struct dc_stream_state *stream)
4151 {
4152         /* SPD info packet for FreeSync */
4153
4154         /* Check if Freesync is supported. Return if false. If true,
4155          * set the corresponding bit in the info packet
4156          */
4157         if (!stream->vsp_infopacket.valid)
4158                 return;
4159
4160         *info_packet = stream->vsp_infopacket;
4161 }
4162
4163 static void set_spd_info_packet(
4164                 struct dc_info_packet *info_packet,
4165                 struct dc_stream_state *stream)
4166 {
4167         /* SPD info packet for FreeSync */
4168
4169         /* Check if Freesync is supported. Return if false. If true,
4170          * set the corresponding bit in the info packet
4171          */
4172         if (!stream->vrr_infopacket.valid)
4173                 return;
4174
4175         *info_packet = stream->vrr_infopacket;
4176 }
4177
4178 static void set_hdr_static_info_packet(
4179                 struct dc_info_packet *info_packet,
4180                 struct dc_stream_state *stream)
4181 {
4182         /* HDR Static Metadata info packet for HDR10 */
4183
4184         if (!stream->hdr_static_metadata.valid ||
4185                         stream->use_dynamic_meta)
4186                 return;
4187
4188         *info_packet = stream->hdr_static_metadata;
4189 }
4190
4191 static void set_vsc_info_packet(
4192                 struct dc_info_packet *info_packet,
4193                 struct dc_stream_state *stream)
4194 {
4195         if (!stream->vsc_infopacket.valid)
4196                 return;
4197
4198         *info_packet = stream->vsc_infopacket;
4199 }
4200 static void set_hfvs_info_packet(
4201                 struct dc_info_packet *info_packet,
4202                 struct dc_stream_state *stream)
4203 {
4204         if (!stream->hfvsif_infopacket.valid)
4205                 return;
4206
4207         *info_packet = stream->hfvsif_infopacket;
4208 }
4209
4210 static void adaptive_sync_override_dp_info_packets_sdp_line_num(
4211                 const struct dc_crtc_timing *timing,
4212                 struct enc_sdp_line_num *sdp_line_num,
4213                 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
4214 {
4215         uint32_t asic_blank_start = 0;
4216         uint32_t asic_blank_end   = 0;
4217         uint32_t v_update = 0;
4218
4219         const struct dc_crtc_timing *tg = timing;
4220
4221         /* blank_start = frame end - front porch */
4222         asic_blank_start = tg->v_total - tg->v_front_porch;
4223
4224         /* blank_end = blank_start - active */
4225         asic_blank_end = (asic_blank_start - tg->v_border_bottom -
4226                                                 tg->v_addressable - tg->v_border_top);
4227
4228         if (pipe_dlg_param->vstartup_start > asic_blank_end) {
4229                 v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end));
4230                 sdp_line_num->adaptive_sync_line_num_valid = true;
4231                 sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
4232         } else {
4233                 sdp_line_num->adaptive_sync_line_num_valid = false;
4234                 sdp_line_num->adaptive_sync_line_num = 0;
4235         }
4236 }
4237
4238 static void set_adaptive_sync_info_packet(
4239                 struct dc_info_packet *info_packet,
4240                 const struct dc_stream_state *stream,
4241                 struct encoder_info_frame *info_frame,
4242                 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
4243 {
4244         if (!stream->adaptive_sync_infopacket.valid)
4245                 return;
4246
4247         adaptive_sync_override_dp_info_packets_sdp_line_num(
4248                         &stream->timing,
4249                         &info_frame->sdp_line_num,
4250                         pipe_dlg_param);
4251
4252         *info_packet = stream->adaptive_sync_infopacket;
4253 }
4254
4255 static void set_vtem_info_packet(
4256                 struct dc_info_packet *info_packet,
4257                 struct dc_stream_state *stream)
4258 {
4259         if (!stream->vtem_infopacket.valid)
4260                 return;
4261
4262         *info_packet = stream->vtem_infopacket;
4263 }
4264
4265 struct clock_source *dc_resource_find_first_free_pll(
4266                 struct resource_context *res_ctx,
4267                 const struct resource_pool *pool)
4268 {
4269         int i;
4270
4271         for (i = 0; i < pool->clk_src_count; ++i) {
4272                 if (res_ctx->clock_source_ref_count[i] == 0)
4273                         return pool->clock_sources[i];
4274         }
4275
4276         return NULL;
4277 }
4278
4279 void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
4280 {
4281         enum signal_type signal = SIGNAL_TYPE_NONE;
4282         struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
4283
4284         /* default all packets to invalid */
4285         info->avi.valid = false;
4286         info->gamut.valid = false;
4287         info->vendor.valid = false;
4288         info->spd.valid = false;
4289         info->hdrsmd.valid = false;
4290         info->vsc.valid = false;
4291         info->hfvsif.valid = false;
4292         info->vtem.valid = false;
4293         info->adaptive_sync.valid = false;
4294         signal = pipe_ctx->stream->signal;
4295
4296         /* HDMi and DP have different info packets*/
4297         if (dc_is_hdmi_signal(signal)) {
4298                 set_avi_info_frame(&info->avi, pipe_ctx);
4299
4300                 set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
4301                 set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream);
4302                 set_vtem_info_packet(&info->vtem, pipe_ctx->stream);
4303
4304                 set_spd_info_packet(&info->spd, pipe_ctx->stream);
4305
4306                 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
4307
4308         } else if (dc_is_dp_signal(signal)) {
4309                 set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
4310
4311                 set_spd_info_packet(&info->spd, pipe_ctx->stream);
4312
4313                 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
4314                 set_adaptive_sync_info_packet(&info->adaptive_sync,
4315                                                                                 pipe_ctx->stream,
4316                                                                                 info,
4317                                                                                 &pipe_ctx->pipe_dlg_param);
4318         }
4319
4320         patch_gamut_packet_checksum(&info->gamut);
4321 }
4322
4323 enum dc_status resource_map_clock_resources(
4324                 const struct dc  *dc,
4325                 struct dc_state *context,
4326                 struct dc_stream_state *stream)
4327 {
4328         /* acquire new resources */
4329         const struct resource_pool *pool = dc->res_pool;
4330         struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
4331                                 &context->res_ctx, stream);
4332
4333         if (!pipe_ctx)
4334                 return DC_ERROR_UNEXPECTED;
4335
4336         if (dc_is_dp_signal(pipe_ctx->stream->signal)
4337                 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
4338                 pipe_ctx->clock_source = pool->dp_clock_source;
4339         else {
4340                 pipe_ctx->clock_source = NULL;
4341
4342                 if (!dc->config.disable_disp_pll_sharing)
4343                         pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
4344                                 &context->res_ctx,
4345                                 pipe_ctx);
4346
4347                 if (pipe_ctx->clock_source == NULL)
4348                         pipe_ctx->clock_source =
4349                                 dc_resource_find_first_free_pll(
4350                                         &context->res_ctx,
4351                                         pool);
4352         }
4353
4354         if (pipe_ctx->clock_source == NULL)
4355                 return DC_NO_CLOCK_SOURCE_RESOURCE;
4356
4357         resource_reference_clock_source(
4358                 &context->res_ctx, pool,
4359                 pipe_ctx->clock_source);
4360
4361         return DC_OK;
4362 }
4363
4364 /*
4365  * Note: We need to disable output if clock sources change,
4366  * since bios does optimization and doesn't apply if changing
4367  * PHY when not already disabled.
4368  */
4369 bool pipe_need_reprogram(
4370                 struct pipe_ctx *pipe_ctx_old,
4371                 struct pipe_ctx *pipe_ctx)
4372 {
4373         if (!pipe_ctx_old->stream)
4374                 return false;
4375
4376         if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
4377                 return true;
4378
4379         if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
4380                 return true;
4381
4382         if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
4383                 return true;
4384
4385         if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
4386                         && pipe_ctx_old->stream != pipe_ctx->stream)
4387                 return true;
4388
4389         if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
4390                 return true;
4391
4392         if (dc_is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
4393                 return true;
4394
4395         if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
4396                 return true;
4397
4398         if (false == pipe_ctx_old->stream->link->link_state_valid &&
4399                 false == pipe_ctx_old->stream->dpms_off)
4400                 return true;
4401
4402         if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
4403                 return true;
4404
4405         if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
4406                 return true;
4407         if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
4408                 return true;
4409
4410         /* DIG link encoder resource assignment for stream changed. */
4411         if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
4412                 bool need_reprogram = false;
4413                 struct dc *dc = pipe_ctx_old->stream->ctx->dc;
4414                 struct link_encoder *link_enc_prev =
4415                         link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream);
4416
4417                 if (link_enc_prev != pipe_ctx->stream->link_enc)
4418                         need_reprogram = true;
4419
4420                 return need_reprogram;
4421         }
4422
4423         return false;
4424 }
4425
4426 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
4427                 struct bit_depth_reduction_params *fmt_bit_depth)
4428 {
4429         enum dc_dither_option option = stream->dither_option;
4430         enum dc_pixel_encoding pixel_encoding =
4431                         stream->timing.pixel_encoding;
4432
4433         memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
4434
4435         if (option == DITHER_OPTION_DEFAULT) {
4436                 switch (stream->timing.display_color_depth) {
4437                 case COLOR_DEPTH_666:
4438                         option = DITHER_OPTION_SPATIAL6;
4439                         break;
4440                 case COLOR_DEPTH_888:
4441                         option = DITHER_OPTION_SPATIAL8;
4442                         break;
4443                 case COLOR_DEPTH_101010:
4444                         option = DITHER_OPTION_TRUN10;
4445                         break;
4446                 default:
4447                         option = DITHER_OPTION_DISABLE;
4448                 }
4449         }
4450
4451         if (option == DITHER_OPTION_DISABLE)
4452                 return;
4453
4454         if (option == DITHER_OPTION_TRUN6) {
4455                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4456                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
4457         } else if (option == DITHER_OPTION_TRUN8 ||
4458                         option == DITHER_OPTION_TRUN8_SPATIAL6 ||
4459                         option == DITHER_OPTION_TRUN8_FM6) {
4460                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4461                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
4462         } else if (option == DITHER_OPTION_TRUN10        ||
4463                         option == DITHER_OPTION_TRUN10_SPATIAL6   ||
4464                         option == DITHER_OPTION_TRUN10_SPATIAL8   ||
4465                         option == DITHER_OPTION_TRUN10_FM8     ||
4466                         option == DITHER_OPTION_TRUN10_FM6     ||
4467                         option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
4468                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4469                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
4470                 if (option == DITHER_OPTION_TRUN10)
4471                         fmt_bit_depth->flags.TRUNCATE_MODE = 1;
4472         }
4473
4474         /* special case - Formatter can only reduce by 4 bits at most.
4475          * When reducing from 12 to 6 bits,
4476          * HW recommends we use trunc with round mode
4477          * (if we did nothing, trunc to 10 bits would be used)
4478          * note that any 12->10 bit reduction is ignored prior to DCE8,
4479          * as the input was 10 bits.
4480          */
4481         if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
4482                         option == DITHER_OPTION_SPATIAL6 ||
4483                         option == DITHER_OPTION_FM6) {
4484                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4485                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
4486                 fmt_bit_depth->flags.TRUNCATE_MODE = 1;
4487         }
4488
4489         /* spatial dither
4490          * note that spatial modes 1-3 are never used
4491          */
4492         if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM            ||
4493                         option == DITHER_OPTION_SPATIAL6 ||
4494                         option == DITHER_OPTION_TRUN10_SPATIAL6      ||
4495                         option == DITHER_OPTION_TRUN8_SPATIAL6) {
4496                 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
4497                 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
4498                 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
4499                 fmt_bit_depth->flags.RGB_RANDOM =
4500                                 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
4501         } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM            ||
4502                         option == DITHER_OPTION_SPATIAL8 ||
4503                         option == DITHER_OPTION_SPATIAL8_FM6        ||
4504                         option == DITHER_OPTION_TRUN10_SPATIAL8      ||
4505                         option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
4506                 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
4507                 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
4508                 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
4509                 fmt_bit_depth->flags.RGB_RANDOM =
4510                                 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
4511         } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
4512                         option == DITHER_OPTION_SPATIAL10 ||
4513                         option == DITHER_OPTION_SPATIAL10_FM8 ||
4514                         option == DITHER_OPTION_SPATIAL10_FM6) {
4515                 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
4516                 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
4517                 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
4518                 fmt_bit_depth->flags.RGB_RANDOM =
4519                                 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
4520         }
4521
4522         if (option == DITHER_OPTION_SPATIAL6 ||
4523                         option == DITHER_OPTION_SPATIAL8 ||
4524                         option == DITHER_OPTION_SPATIAL10) {
4525                 fmt_bit_depth->flags.FRAME_RANDOM = 0;
4526         } else {
4527                 fmt_bit_depth->flags.FRAME_RANDOM = 1;
4528         }
4529
4530         //////////////////////
4531         //// temporal dither
4532         //////////////////////
4533         if (option == DITHER_OPTION_FM6           ||
4534                         option == DITHER_OPTION_SPATIAL8_FM6     ||
4535                         option == DITHER_OPTION_SPATIAL10_FM6     ||
4536                         option == DITHER_OPTION_TRUN10_FM6     ||
4537                         option == DITHER_OPTION_TRUN8_FM6      ||
4538                         option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
4539                 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
4540                 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
4541         } else if (option == DITHER_OPTION_FM8        ||
4542                         option == DITHER_OPTION_SPATIAL10_FM8  ||
4543                         option == DITHER_OPTION_TRUN10_FM8) {
4544                 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
4545                 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
4546         } else if (option == DITHER_OPTION_FM10) {
4547                 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
4548                 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
4549         }
4550
4551         fmt_bit_depth->pixel_encoding = pixel_encoding;
4552 }
4553
4554 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
4555 {
4556         struct dc_link *link = stream->link;
4557         struct timing_generator *tg = dc->res_pool->timing_generators[0];
4558         enum dc_status res = DC_OK;
4559
4560         calculate_phy_pix_clks(stream);
4561
4562         if (!tg->funcs->validate_timing(tg, &stream->timing))
4563                 res = DC_FAIL_CONTROLLER_VALIDATE;
4564
4565         if (res == DC_OK) {
4566                 if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
4567                                 !link->link_enc->funcs->validate_output_with_stream(
4568                                                 link->link_enc, stream))
4569                         res = DC_FAIL_ENC_VALIDATE;
4570         }
4571
4572         /* TODO: validate audio ASIC caps, encoder */
4573
4574         if (res == DC_OK)
4575                 res = dc->link_srv->validate_mode_timing(stream,
4576                       link,
4577                       &stream->timing);
4578
4579         return res;
4580 }
4581
4582 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
4583 {
4584         enum dc_status res = DC_OK;
4585
4586         /* check if surface has invalid dimensions */
4587         if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 ||
4588                 plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0)
4589                 return DC_FAIL_SURFACE_VALIDATE;
4590
4591         /* TODO For now validates pixel format only */
4592         if (dc->res_pool->funcs->validate_plane)
4593                 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
4594
4595         return res;
4596 }
4597
4598 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
4599 {
4600         switch (format) {
4601         case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
4602                 return 8;
4603         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
4604         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
4605                 return 12;
4606         case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
4607         case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
4608         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
4609         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
4610                 return 16;
4611         case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
4612         case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
4613         case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
4614         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
4615         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
4616         case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
4617         case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
4618                 return 32;
4619         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
4620         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
4621         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
4622         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
4623                 return 64;
4624         default:
4625                 ASSERT_CRITICAL(false);
4626                 return -1;
4627         }
4628 }
4629 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
4630 {
4631         if (modes) {
4632                 if (modes->sample_rates.rate.RATE_192)
4633                         return 192000;
4634                 if (modes->sample_rates.rate.RATE_176_4)
4635                         return 176400;
4636                 if (modes->sample_rates.rate.RATE_96)
4637                         return 96000;
4638                 if (modes->sample_rates.rate.RATE_88_2)
4639                         return 88200;
4640                 if (modes->sample_rates.rate.RATE_48)
4641                         return 48000;
4642                 if (modes->sample_rates.rate.RATE_44_1)
4643                         return 44100;
4644                 if (modes->sample_rates.rate.RATE_32)
4645                         return 32000;
4646         }
4647         /*original logic when no audio info*/
4648         return 441000;
4649 }
4650
4651 void get_audio_check(struct audio_info *aud_modes,
4652         struct audio_check *audio_chk)
4653 {
4654         unsigned int i;
4655         unsigned int max_sample_rate = 0;
4656
4657         if (aud_modes) {
4658                 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
4659
4660                 audio_chk->max_audiosample_rate = 0;
4661                 for (i = 0; i < aud_modes->mode_count; i++) {
4662                         max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
4663                         if (audio_chk->max_audiosample_rate < max_sample_rate)
4664                                 audio_chk->max_audiosample_rate = max_sample_rate;
4665                         /*dts takes the same as type 2: AP = 0.25*/
4666                 }
4667                 /*check which one take more bandwidth*/
4668                 if (audio_chk->max_audiosample_rate > 192000)
4669                         audio_chk->audio_packet_type = 0x9;/*AP =1*/
4670                 audio_chk->acat = 0;/*not support*/
4671         }
4672 }
4673
4674 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc(
4675                 const struct resource_context *res_ctx,
4676                 const struct resource_pool *const pool,
4677                 const struct dc_link *link)
4678 {
4679         struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
4680         int enc_index;
4681
4682         enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link);
4683
4684         if (enc_index < 0)
4685                 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
4686
4687         if (enc_index >= 0)
4688                 hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
4689
4690         return hpo_dp_link_enc;
4691 }
4692
4693 bool get_temp_dp_link_res(struct dc_link *link,
4694                 struct link_resource *link_res,
4695                 struct dc_link_settings *link_settings)
4696 {
4697         const struct dc *dc  = link->dc;
4698         const struct resource_context *res_ctx = &dc->current_state->res_ctx;
4699
4700         memset(link_res, 0, sizeof(*link_res));
4701
4702         if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
4703                 link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx,
4704                                 dc->res_pool, link);
4705                 if (!link_res->hpo_dp_link_enc)
4706                         return false;
4707         }
4708         return true;
4709 }
4710
4711 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
4712                 struct dc_state *context)
4713 {
4714         int i, j;
4715         struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
4716
4717         /* If pipe backend is reset, need to reset pipe syncd status */
4718         for (i = 0; i < dc->res_pool->pipe_count; i++) {
4719                 pipe_ctx_old =  &dc->current_state->res_ctx.pipe_ctx[i];
4720                 pipe_ctx = &context->res_ctx.pipe_ctx[i];
4721
4722                 if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER))
4723                         continue;
4724
4725                 if (!pipe_ctx->stream ||
4726                                 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
4727
4728                         /* Reset all the syncd pipes from the disabled pipe */
4729                         for (j = 0; j < dc->res_pool->pipe_count; j++) {
4730                                 pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
4731                                 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
4732                                         !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
4733                                         SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
4734                         }
4735                 }
4736         }
4737 }
4738
4739 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
4740         struct dc_state *context,
4741         uint8_t disabled_master_pipe_idx)
4742 {
4743         int i;
4744         struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
4745
4746         pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
4747         if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
4748                 !IS_PIPE_SYNCD_VALID(pipe_ctx))
4749                 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
4750
4751         /* for the pipe disabled, check if any slave pipe exists and assert */
4752         for (i = 0; i < dc->res_pool->pipe_count; i++) {
4753                 pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
4754
4755                 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
4756                     IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) {
4757                         struct pipe_ctx *first_pipe = pipe_ctx_check;
4758
4759                         while (first_pipe->prev_odm_pipe)
4760                                 first_pipe = first_pipe->prev_odm_pipe;
4761                         /* When ODM combine is enabled, this case is expected. If the disabled pipe
4762                          * is part of the ODM tree, then we should not print an error.
4763                          * */
4764                         if (first_pipe->pipe_idx == disabled_master_pipe_idx)
4765                                 continue;
4766
4767                         DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
4768                                    i, disabled_master_pipe_idx);
4769                 }
4770         }
4771 }
4772
4773 void reset_sync_context_for_pipe(const struct dc *dc,
4774         struct dc_state *context,
4775         uint8_t pipe_idx)
4776 {
4777         int i;
4778         struct pipe_ctx *pipe_ctx_reset;
4779
4780         /* reset the otg sync context for the pipe and its slave pipes if any */
4781         for (i = 0; i < dc->res_pool->pipe_count; i++) {
4782                 pipe_ctx_reset = &context->res_ctx.pipe_ctx[i];
4783
4784                 if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) &&
4785                         IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx))
4786                         SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i);
4787         }
4788 }
4789
4790 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
4791 {
4792         /* TODO - get transmitter to phy idx mapping from DMUB */
4793         uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A;
4794
4795         if (dc->ctx->dce_version == DCN_VERSION_3_1 &&
4796                         dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
4797                 switch (transmitter) {
4798                 case TRANSMITTER_UNIPHY_A:
4799                         phy_idx = 0;
4800                         break;
4801                 case TRANSMITTER_UNIPHY_B:
4802                         phy_idx = 1;
4803                         break;
4804                 case TRANSMITTER_UNIPHY_C:
4805                         phy_idx = 5;
4806                         break;
4807                 case TRANSMITTER_UNIPHY_D:
4808                         phy_idx = 6;
4809                         break;
4810                 case TRANSMITTER_UNIPHY_E:
4811                         phy_idx = 4;
4812                         break;
4813                 default:
4814                         phy_idx = 0;
4815                         break;
4816                 }
4817         }
4818
4819         return phy_idx;
4820 }
4821
4822 const struct link_hwss *get_link_hwss(const struct dc_link *link,
4823                 const struct link_resource *link_res)
4824 {
4825         /* Link_hwss is only accessible by getter function instead of accessing
4826          * by pointers in dc with the intent to protect against breaking polymorphism.
4827          */
4828         if (can_use_hpo_dp_link_hwss(link, link_res))
4829                 /* TODO: some assumes that if decided link settings is 128b/132b
4830                  * channel coding format hpo_dp_link_enc should be used.
4831                  * Others believe that if hpo_dp_link_enc is available in link
4832                  * resource then hpo_dp_link_enc must be used. This bound between
4833                  * hpo_dp_link_enc != NULL and decided link settings is loosely coupled
4834                  * with a premise that both hpo_dp_link_enc pointer and decided link
4835                  * settings are determined based on single policy function like
4836                  * "decide_link_settings" from upper layer. This "convention"
4837                  * cannot be maintained and enforced at current level.
4838                  * Therefore a refactor is due so we can enforce a strong bound
4839                  * between those two parameters at this level.
4840                  *
4841                  * To put it simple, we want to make enforcement at low level so that
4842                  * we will not return link hwss if caller plans to do 8b/10b
4843                  * with an hpo encoder. Or we can return a very dummy one that doesn't
4844                  * do work for all functions
4845                  */
4846                 return (requires_fixed_vs_pe_retimer_hpo_link_hwss(link) ?
4847                                 get_hpo_fixed_vs_pe_retimer_dp_link_hwss() : get_hpo_dp_link_hwss());
4848         else if (can_use_dpia_link_hwss(link, link_res))
4849                 return get_dpia_link_hwss();
4850         else if (can_use_dio_link_hwss(link, link_res))
4851                 return (requires_fixed_vs_pe_retimer_dio_link_hwss(link)) ?
4852                                 get_dio_fixed_vs_pe_retimer_link_hwss() : get_dio_link_hwss();
4853         else
4854                 return get_virtual_link_hwss();
4855 }
4856
4857 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream)
4858 {
4859         bool divisible = false;
4860         uint16_t h_blank_start = 0;
4861         uint16_t h_blank_end = 0;
4862
4863         if (stream) {
4864                 h_blank_start = stream->timing.h_total - stream->timing.h_front_porch;
4865                 h_blank_end = h_blank_start - stream->timing.h_addressable;
4866
4867                 /* HTOTAL, Hblank start/end, and Hsync start/end all must be
4868                  * divisible by 2 in order for the horizontal timing params
4869                  * to be considered divisible by 2. Hsync start is always 0.
4870                  */
4871                 divisible = (stream->timing.h_total % 2 == 0) &&
4872                                 (h_blank_start % 2 == 0) &&
4873                                 (h_blank_end % 2 == 0) &&
4874                                 (stream->timing.h_sync_width % 2 == 0);
4875         }
4876         return divisible;
4877 }
4878
4879 /* This interface is deprecated for new DCNs. It is replaced by the following
4880  * new interfaces. These two interfaces encapsulate pipe selection priority
4881  * with DCN specific minimum hardware transition optimization algorithm. With
4882  * the new interfaces caller no longer needs to know the implementation detail
4883  * of a pipe topology.
4884  *
4885  * resource_update_pipes_with_odm_slice_count
4886  * resource_update_pipes_with_mpc_slice_count
4887  *
4888  */
4889 bool dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy(
4890                 const struct dc *dc,
4891                 struct dc_state *state,
4892                 struct pipe_ctx *pri_pipe,
4893                 struct pipe_ctx *sec_pipe,
4894                 bool odm)
4895 {
4896         int pipe_idx = sec_pipe->pipe_idx;
4897         struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev;
4898         const struct resource_pool *pool = dc->res_pool;
4899
4900         sec_top = sec_pipe->top_pipe;
4901         sec_bottom = sec_pipe->bottom_pipe;
4902         sec_next = sec_pipe->next_odm_pipe;
4903         sec_prev = sec_pipe->prev_odm_pipe;
4904
4905         if (pri_pipe == NULL)
4906                 return false;
4907
4908         *sec_pipe = *pri_pipe;
4909
4910         sec_pipe->top_pipe = sec_top;
4911         sec_pipe->bottom_pipe = sec_bottom;
4912         sec_pipe->next_odm_pipe = sec_next;
4913         sec_pipe->prev_odm_pipe = sec_prev;
4914
4915         sec_pipe->pipe_idx = pipe_idx;
4916         sec_pipe->plane_res.mi = pool->mis[pipe_idx];
4917         sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
4918         sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
4919         sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
4920         sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
4921         sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
4922         sec_pipe->stream_res.dsc = NULL;
4923         if (odm) {
4924                 if (!sec_pipe->top_pipe)
4925                         sec_pipe->stream_res.opp = pool->opps[pipe_idx];
4926                 else
4927                         sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
4928                 if (sec_pipe->stream->timing.flags.DSC == 1) {
4929 #if defined(CONFIG_DRM_AMD_DC_FP)
4930                         dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx);
4931 #endif
4932                         ASSERT(sec_pipe->stream_res.dsc);
4933                         if (sec_pipe->stream_res.dsc == NULL)
4934                                 return false;
4935                 }
4936 #if defined(CONFIG_DRM_AMD_DC_FP)
4937                 dcn20_build_mapped_resource(dc, state, sec_pipe->stream);
4938 #endif
4939         }
4940
4941         return true;
4942 }
4943
4944 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
4945                 struct dc_state *context,
4946                 struct pipe_ctx *pipe_ctx)
4947 {
4948         if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
4949                 if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) {
4950                         pipe_ctx->stream_res.hpo_dp_stream_enc =
4951                                         find_first_free_match_hpo_dp_stream_enc_for_link(
4952                                                         &context->res_ctx, dc->res_pool, pipe_ctx->stream);
4953
4954                         if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
4955                                 return DC_NO_STREAM_ENC_RESOURCE;
4956
4957                         update_hpo_dp_stream_engine_usage(
4958                                         &context->res_ctx, dc->res_pool,
4959                                         pipe_ctx->stream_res.hpo_dp_stream_enc,
4960                                         true);
4961                 }
4962
4963                 if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) {
4964                         if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream))
4965                                 return DC_NO_LINK_ENC_RESOURCE;
4966                 }
4967         } else {
4968                 if (pipe_ctx->stream_res.hpo_dp_stream_enc) {
4969                         update_hpo_dp_stream_engine_usage(
4970                                         &context->res_ctx, dc->res_pool,
4971                                         pipe_ctx->stream_res.hpo_dp_stream_enc,
4972                                         false);
4973                         pipe_ctx->stream_res.hpo_dp_stream_enc = NULL;
4974                 }
4975                 if (pipe_ctx->link_res.hpo_dp_link_enc)
4976                         remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream);
4977         }
4978
4979         return DC_OK;
4980 }
4981
4982 bool check_subvp_sw_cursor_fallback_req(const struct dc *dc, struct dc_stream_state *stream)
4983 {
4984         if (!dc->debug.disable_subvp_high_refresh && is_subvp_high_refresh_candidate(stream))
4985                 return true;
4986         if (dc->current_state->stream_count == 1 && stream->timing.v_addressable >= 2880 &&
4987                         ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120)
4988                 return true;
4989         else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 1080 &&
4990                         ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120)
4991                 return true;
4992
4993         return false;
4994 }