Merge tag 'drm-intel-gt-next-2023-06-08' of git://anongit.freedesktop.org/drm/drm...
[sfrench/cifs-2.6.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 "virtual/virtual_link_hwss.h"
45 #include "link/hwss/link_hwss_dio.h"
46 #include "link/hwss/link_hwss_dpia.h"
47 #include "link/hwss/link_hwss_hpo_dp.h"
48
49 #if defined(CONFIG_DRM_AMD_DC_SI)
50 #include "dce60/dce60_resource.h"
51 #endif
52 #include "dce80/dce80_resource.h"
53 #include "dce100/dce100_resource.h"
54 #include "dce110/dce110_resource.h"
55 #include "dce112/dce112_resource.h"
56 #include "dce120/dce120_resource.h"
57 #include "dcn10/dcn10_resource.h"
58 #include "dcn20/dcn20_resource.h"
59 #include "dcn21/dcn21_resource.h"
60 #include "dcn201/dcn201_resource.h"
61 #include "dcn30/dcn30_resource.h"
62 #include "dcn301/dcn301_resource.h"
63 #include "dcn302/dcn302_resource.h"
64 #include "dcn303/dcn303_resource.h"
65 #include "dcn31/dcn31_resource.h"
66 #include "dcn314/dcn314_resource.h"
67 #include "dcn315/dcn315_resource.h"
68 #include "dcn316/dcn316_resource.h"
69 #include "../dcn32/dcn32_resource.h"
70 #include "../dcn321/dcn321_resource.h"
71
72 #define DC_LOGGER_INIT(logger)
73
74 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
75 {
76         enum dce_version dc_version = DCE_VERSION_UNKNOWN;
77
78         switch (asic_id.chip_family) {
79
80 #if defined(CONFIG_DRM_AMD_DC_SI)
81         case FAMILY_SI:
82                 if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
83                     ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
84                     ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
85                         dc_version = DCE_VERSION_6_0;
86                 else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
87                         dc_version = DCE_VERSION_6_4;
88                 else
89                         dc_version = DCE_VERSION_6_1;
90                 break;
91 #endif
92         case FAMILY_CI:
93                 dc_version = DCE_VERSION_8_0;
94                 break;
95         case FAMILY_KV:
96                 if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
97                     ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
98                     ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
99                         dc_version = DCE_VERSION_8_3;
100                 else
101                         dc_version = DCE_VERSION_8_1;
102                 break;
103         case FAMILY_CZ:
104                 dc_version = DCE_VERSION_11_0;
105                 break;
106
107         case FAMILY_VI:
108                 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
109                                 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
110                         dc_version = DCE_VERSION_10_0;
111                         break;
112                 }
113                 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
114                                 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
115                                 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
116                         dc_version = DCE_VERSION_11_2;
117                 }
118                 if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
119                         dc_version = DCE_VERSION_11_22;
120                 break;
121         case FAMILY_AI:
122                 if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
123                         dc_version = DCE_VERSION_12_1;
124                 else
125                         dc_version = DCE_VERSION_12_0;
126                 break;
127         case FAMILY_RV:
128                 dc_version = DCN_VERSION_1_0;
129                 if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
130                         dc_version = DCN_VERSION_1_01;
131                 if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
132                         dc_version = DCN_VERSION_2_1;
133                 if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
134                         dc_version = DCN_VERSION_2_1;
135                 break;
136
137         case FAMILY_NV:
138                 dc_version = DCN_VERSION_2_0;
139                 if (asic_id.chip_id == DEVICE_ID_NV_13FE || asic_id.chip_id == DEVICE_ID_NV_143F) {
140                         dc_version = DCN_VERSION_2_01;
141                         break;
142                 }
143                 if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
144                         dc_version = DCN_VERSION_3_0;
145                 if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
146                         dc_version = DCN_VERSION_3_02;
147                 if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
148                         dc_version = DCN_VERSION_3_03;
149                 break;
150
151         case FAMILY_VGH:
152                 dc_version = DCN_VERSION_3_01;
153                 break;
154
155         case FAMILY_YELLOW_CARP:
156                 if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
157                         dc_version = DCN_VERSION_3_1;
158                 break;
159         case AMDGPU_FAMILY_GC_10_3_6:
160                 if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
161                         dc_version = DCN_VERSION_3_15;
162                 break;
163         case AMDGPU_FAMILY_GC_10_3_7:
164                 if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
165                         dc_version = DCN_VERSION_3_16;
166                 break;
167         case AMDGPU_FAMILY_GC_11_0_0:
168                 dc_version = DCN_VERSION_3_2;
169                 if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
170                         dc_version = DCN_VERSION_3_21;
171                 break;
172         case AMDGPU_FAMILY_GC_11_0_1:
173                 dc_version = DCN_VERSION_3_14;
174                 break;
175         default:
176                 dc_version = DCE_VERSION_UNKNOWN;
177                 break;
178         }
179         return dc_version;
180 }
181
182 struct resource_pool *dc_create_resource_pool(struct dc  *dc,
183                                               const struct dc_init_data *init_data,
184                                               enum dce_version dc_version)
185 {
186         struct resource_pool *res_pool = NULL;
187
188         switch (dc_version) {
189 #if defined(CONFIG_DRM_AMD_DC_SI)
190         case DCE_VERSION_6_0:
191                 res_pool = dce60_create_resource_pool(
192                         init_data->num_virtual_links, dc);
193                 break;
194         case DCE_VERSION_6_1:
195                 res_pool = dce61_create_resource_pool(
196                         init_data->num_virtual_links, dc);
197                 break;
198         case DCE_VERSION_6_4:
199                 res_pool = dce64_create_resource_pool(
200                         init_data->num_virtual_links, dc);
201                 break;
202 #endif
203         case DCE_VERSION_8_0:
204                 res_pool = dce80_create_resource_pool(
205                                 init_data->num_virtual_links, dc);
206                 break;
207         case DCE_VERSION_8_1:
208                 res_pool = dce81_create_resource_pool(
209                                 init_data->num_virtual_links, dc);
210                 break;
211         case DCE_VERSION_8_3:
212                 res_pool = dce83_create_resource_pool(
213                                 init_data->num_virtual_links, dc);
214                 break;
215         case DCE_VERSION_10_0:
216                 res_pool = dce100_create_resource_pool(
217                                 init_data->num_virtual_links, dc);
218                 break;
219         case DCE_VERSION_11_0:
220                 res_pool = dce110_create_resource_pool(
221                                 init_data->num_virtual_links, dc,
222                                 init_data->asic_id);
223                 break;
224         case DCE_VERSION_11_2:
225         case DCE_VERSION_11_22:
226                 res_pool = dce112_create_resource_pool(
227                                 init_data->num_virtual_links, dc);
228                 break;
229         case DCE_VERSION_12_0:
230         case DCE_VERSION_12_1:
231                 res_pool = dce120_create_resource_pool(
232                                 init_data->num_virtual_links, dc);
233                 break;
234
235 #if defined(CONFIG_DRM_AMD_DC_FP)
236         case DCN_VERSION_1_0:
237         case DCN_VERSION_1_01:
238                 res_pool = dcn10_create_resource_pool(init_data, dc);
239                 break;
240         case DCN_VERSION_2_0:
241                 res_pool = dcn20_create_resource_pool(init_data, dc);
242                 break;
243         case DCN_VERSION_2_1:
244                 res_pool = dcn21_create_resource_pool(init_data, dc);
245                 break;
246         case DCN_VERSION_2_01:
247                 res_pool = dcn201_create_resource_pool(init_data, dc);
248                 break;
249         case DCN_VERSION_3_0:
250                 res_pool = dcn30_create_resource_pool(init_data, dc);
251                 break;
252         case DCN_VERSION_3_01:
253                 res_pool = dcn301_create_resource_pool(init_data, dc);
254                 break;
255         case DCN_VERSION_3_02:
256                 res_pool = dcn302_create_resource_pool(init_data, dc);
257                 break;
258         case DCN_VERSION_3_03:
259                 res_pool = dcn303_create_resource_pool(init_data, dc);
260                 break;
261         case DCN_VERSION_3_1:
262                 res_pool = dcn31_create_resource_pool(init_data, dc);
263                 break;
264         case DCN_VERSION_3_14:
265                 res_pool = dcn314_create_resource_pool(init_data, dc);
266                 break;
267         case DCN_VERSION_3_15:
268                 res_pool = dcn315_create_resource_pool(init_data, dc);
269                 break;
270         case DCN_VERSION_3_16:
271                 res_pool = dcn316_create_resource_pool(init_data, dc);
272                 break;
273         case DCN_VERSION_3_2:
274                 res_pool = dcn32_create_resource_pool(init_data, dc);
275                 break;
276         case DCN_VERSION_3_21:
277                 res_pool = dcn321_create_resource_pool(init_data, dc);
278                 break;
279 #endif /* CONFIG_DRM_AMD_DC_FP */
280         default:
281                 break;
282         }
283
284         if (res_pool != NULL) {
285                 if (dc->ctx->dc_bios->fw_info_valid) {
286                         res_pool->ref_clocks.xtalin_clock_inKhz =
287                                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
288                         /* initialize with firmware data first, no all
289                          * ASIC have DCCG SW component. FPGA or
290                          * simulation need initialization of
291                          * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
292                          * with xtalin_clock_inKhz
293                          */
294                         res_pool->ref_clocks.dccg_ref_clock_inKhz =
295                                 res_pool->ref_clocks.xtalin_clock_inKhz;
296                         res_pool->ref_clocks.dchub_ref_clock_inKhz =
297                                 res_pool->ref_clocks.xtalin_clock_inKhz;
298                 } else
299                         ASSERT_CRITICAL(false);
300         }
301
302         return res_pool;
303 }
304
305 void dc_destroy_resource_pool(struct dc  *dc)
306 {
307         if (dc) {
308                 if (dc->res_pool)
309                         dc->res_pool->funcs->destroy(&dc->res_pool);
310
311                 kfree(dc->hwseq);
312         }
313 }
314
315 static void update_num_audio(
316         const struct resource_straps *straps,
317         unsigned int *num_audio,
318         struct audio_support *aud_support)
319 {
320         aud_support->dp_audio = true;
321         aud_support->hdmi_audio_native = false;
322         aud_support->hdmi_audio_on_dongle = false;
323
324         if (straps->hdmi_disable == 0) {
325                 if (straps->dc_pinstraps_audio & 0x2) {
326                         aud_support->hdmi_audio_on_dongle = true;
327                         aud_support->hdmi_audio_native = true;
328                 }
329         }
330
331         switch (straps->audio_stream_number) {
332         case 0: /* multi streams supported */
333                 break;
334         case 1: /* multi streams not supported */
335                 *num_audio = 1;
336                 break;
337         default:
338                 DC_ERR("DC: unexpected audio fuse!\n");
339         }
340 }
341
342 bool resource_construct(
343         unsigned int num_virtual_links,
344         struct dc  *dc,
345         struct resource_pool *pool,
346         const struct resource_create_funcs *create_funcs)
347 {
348         struct dc_context *ctx = dc->ctx;
349         const struct resource_caps *caps = pool->res_cap;
350         int i;
351         unsigned int num_audio = caps->num_audio;
352         struct resource_straps straps = {0};
353
354         if (create_funcs->read_dce_straps)
355                 create_funcs->read_dce_straps(dc->ctx, &straps);
356
357         pool->audio_count = 0;
358         if (create_funcs->create_audio) {
359                 /* find the total number of streams available via the
360                  * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
361                  * registers (one for each pin) starting from pin 1
362                  * up to the max number of audio pins.
363                  * We stop on the first pin where
364                  * PORT_CONNECTIVITY == 1 (as instructed by HW team).
365                  */
366                 update_num_audio(&straps, &num_audio, &pool->audio_support);
367                 for (i = 0; i < caps->num_audio; i++) {
368                         struct audio *aud = create_funcs->create_audio(ctx, i);
369
370                         if (aud == NULL) {
371                                 DC_ERR("DC: failed to create audio!\n");
372                                 return false;
373                         }
374                         if (!aud->funcs->endpoint_valid(aud)) {
375                                 aud->funcs->destroy(&aud);
376                                 break;
377                         }
378                         pool->audios[i] = aud;
379                         pool->audio_count++;
380                 }
381         }
382
383         pool->stream_enc_count = 0;
384         if (create_funcs->create_stream_encoder) {
385                 for (i = 0; i < caps->num_stream_encoder; i++) {
386                         pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
387                         if (pool->stream_enc[i] == NULL)
388                                 DC_ERR("DC: failed to create stream_encoder!\n");
389                         pool->stream_enc_count++;
390                 }
391         }
392
393         pool->hpo_dp_stream_enc_count = 0;
394         if (create_funcs->create_hpo_dp_stream_encoder) {
395                 for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
396                         pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
397                         if (pool->hpo_dp_stream_enc[i] == NULL)
398                                 DC_ERR("DC: failed to create HPO DP stream encoder!\n");
399                         pool->hpo_dp_stream_enc_count++;
400
401                 }
402         }
403
404         pool->hpo_dp_link_enc_count = 0;
405         if (create_funcs->create_hpo_dp_link_encoder) {
406                 for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
407                         pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
408                         if (pool->hpo_dp_link_enc[i] == NULL)
409                                 DC_ERR("DC: failed to create HPO DP link encoder!\n");
410                         pool->hpo_dp_link_enc_count++;
411                 }
412         }
413
414         for (i = 0; i < caps->num_mpc_3dlut; i++) {
415                 pool->mpc_lut[i] = dc_create_3dlut_func();
416                 if (pool->mpc_lut[i] == NULL)
417                         DC_ERR("DC: failed to create MPC 3dlut!\n");
418                 pool->mpc_shaper[i] = dc_create_transfer_func();
419                 if (pool->mpc_shaper[i] == NULL)
420                         DC_ERR("DC: failed to create MPC shaper!\n");
421         }
422
423         dc->caps.dynamic_audio = false;
424         if (pool->audio_count < pool->stream_enc_count) {
425                 dc->caps.dynamic_audio = true;
426         }
427         for (i = 0; i < num_virtual_links; i++) {
428                 pool->stream_enc[pool->stream_enc_count] =
429                         virtual_stream_encoder_create(
430                                         ctx, ctx->dc_bios);
431                 if (pool->stream_enc[pool->stream_enc_count] == NULL) {
432                         DC_ERR("DC: failed to create stream_encoder!\n");
433                         return false;
434                 }
435                 pool->stream_enc_count++;
436         }
437
438         dc->hwseq = create_funcs->create_hwseq(ctx);
439
440         return true;
441 }
442 static int find_matching_clock_source(
443                 const struct resource_pool *pool,
444                 struct clock_source *clock_source)
445 {
446
447         int i;
448
449         for (i = 0; i < pool->clk_src_count; i++) {
450                 if (pool->clock_sources[i] == clock_source)
451                         return i;
452         }
453         return -1;
454 }
455
456 void resource_unreference_clock_source(
457                 struct resource_context *res_ctx,
458                 const struct resource_pool *pool,
459                 struct clock_source *clock_source)
460 {
461         int i = find_matching_clock_source(pool, clock_source);
462
463         if (i > -1)
464                 res_ctx->clock_source_ref_count[i]--;
465
466         if (pool->dp_clock_source == clock_source)
467                 res_ctx->dp_clock_source_ref_count--;
468 }
469
470 void resource_reference_clock_source(
471                 struct resource_context *res_ctx,
472                 const struct resource_pool *pool,
473                 struct clock_source *clock_source)
474 {
475         int i = find_matching_clock_source(pool, clock_source);
476
477         if (i > -1)
478                 res_ctx->clock_source_ref_count[i]++;
479
480         if (pool->dp_clock_source == clock_source)
481                 res_ctx->dp_clock_source_ref_count++;
482 }
483
484 int resource_get_clock_source_reference(
485                 struct resource_context *res_ctx,
486                 const struct resource_pool *pool,
487                 struct clock_source *clock_source)
488 {
489         int i = find_matching_clock_source(pool, clock_source);
490
491         if (i > -1)
492                 return res_ctx->clock_source_ref_count[i];
493
494         if (pool->dp_clock_source == clock_source)
495                 return res_ctx->dp_clock_source_ref_count;
496
497         return -1;
498 }
499
500 bool resource_are_vblanks_synchronizable(
501         struct dc_stream_state *stream1,
502         struct dc_stream_state *stream2)
503 {
504         uint32_t base60_refresh_rates[] = {10, 20, 5};
505         uint8_t i;
506         uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
507         uint64_t frame_time_diff;
508
509         if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
510                 stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
511                 dc_is_dp_signal(stream1->signal) &&
512                 dc_is_dp_signal(stream2->signal) &&
513                 false == stream1->has_non_synchronizable_pclk &&
514                 false == stream2->has_non_synchronizable_pclk &&
515                 stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
516                 stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
517                 /* disable refresh rates higher than 60Hz for now */
518                 if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
519                                 stream1->timing.v_total > 60)
520                         return false;
521                 if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
522                                 stream2->timing.v_total > 60)
523                         return false;
524                 frame_time_diff = (uint64_t)10000 *
525                         stream1->timing.h_total *
526                         stream1->timing.v_total *
527                         stream2->timing.pix_clk_100hz;
528                 frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
529                 frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
530                 frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
531                 for (i = 0; i < rr_count; i++) {
532                         int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
533
534                         if (diff < 0)
535                                 diff = -diff;
536                         if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
537                                 return true;
538                 }
539         }
540         return false;
541 }
542
543 bool resource_are_streams_timing_synchronizable(
544         struct dc_stream_state *stream1,
545         struct dc_stream_state *stream2)
546 {
547         if (stream1->timing.h_total != stream2->timing.h_total)
548                 return false;
549
550         if (stream1->timing.v_total != stream2->timing.v_total)
551                 return false;
552
553         if (stream1->timing.h_addressable
554                                 != stream2->timing.h_addressable)
555                 return false;
556
557         if (stream1->timing.v_addressable
558                                 != stream2->timing.v_addressable)
559                 return false;
560
561         if (stream1->timing.v_front_porch
562                                 != stream2->timing.v_front_porch)
563                 return false;
564
565         if (stream1->timing.pix_clk_100hz
566                                 != stream2->timing.pix_clk_100hz)
567                 return false;
568
569         if (stream1->clamping.c_depth != stream2->clamping.c_depth)
570                 return false;
571
572         if (stream1->phy_pix_clk != stream2->phy_pix_clk
573                         && (!dc_is_dp_signal(stream1->signal)
574                         || !dc_is_dp_signal(stream2->signal)))
575                 return false;
576
577         if (stream1->view_format != stream2->view_format)
578                 return false;
579
580         if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
581                 return false;
582
583         return true;
584 }
585 static bool is_dp_and_hdmi_sharable(
586                 struct dc_stream_state *stream1,
587                 struct dc_stream_state *stream2)
588 {
589         if (stream1->ctx->dc->caps.disable_dp_clk_share)
590                 return false;
591
592         if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
593                 stream2->clamping.c_depth != COLOR_DEPTH_888)
594                 return false;
595
596         return true;
597
598 }
599
600 static bool is_sharable_clk_src(
601         const struct pipe_ctx *pipe_with_clk_src,
602         const struct pipe_ctx *pipe)
603 {
604         if (pipe_with_clk_src->clock_source == NULL)
605                 return false;
606
607         if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
608                 return false;
609
610         if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
611                 (dc_is_dp_signal(pipe->stream->signal) &&
612                 !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
613                                      pipe->stream)))
614                 return false;
615
616         if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
617                         && dc_is_dual_link_signal(pipe->stream->signal))
618                 return false;
619
620         if (dc_is_hdmi_signal(pipe->stream->signal)
621                         && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
622                 return false;
623
624         if (!resource_are_streams_timing_synchronizable(
625                         pipe_with_clk_src->stream, pipe->stream))
626                 return false;
627
628         return true;
629 }
630
631 struct clock_source *resource_find_used_clk_src_for_sharing(
632                                         struct resource_context *res_ctx,
633                                         struct pipe_ctx *pipe_ctx)
634 {
635         int i;
636
637         for (i = 0; i < MAX_PIPES; i++) {
638                 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
639                         return res_ctx->pipe_ctx[i].clock_source;
640         }
641
642         return NULL;
643 }
644
645 static enum pixel_format convert_pixel_format_to_dalsurface(
646                 enum surface_pixel_format surface_pixel_format)
647 {
648         enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
649
650         switch (surface_pixel_format) {
651         case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
652                 dal_pixel_format = PIXEL_FORMAT_INDEX8;
653                 break;
654         case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
655                 dal_pixel_format = PIXEL_FORMAT_RGB565;
656                 break;
657         case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
658                 dal_pixel_format = PIXEL_FORMAT_RGB565;
659                 break;
660         case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
661                 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
662                 break;
663         case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
664                 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
665                 break;
666         case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
667                 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
668                 break;
669         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
670                 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
671                 break;
672         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
673                 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
674                 break;
675         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
676         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
677                 dal_pixel_format = PIXEL_FORMAT_FP16;
678                 break;
679         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
680         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
681                 dal_pixel_format = PIXEL_FORMAT_420BPP8;
682                 break;
683         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
684         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
685                 dal_pixel_format = PIXEL_FORMAT_420BPP10;
686                 break;
687         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
688         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
689         default:
690                 dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
691                 break;
692         }
693         return dal_pixel_format;
694 }
695
696 static inline void get_vp_scan_direction(
697         enum dc_rotation_angle rotation,
698         bool horizontal_mirror,
699         bool *orthogonal_rotation,
700         bool *flip_vert_scan_dir,
701         bool *flip_horz_scan_dir)
702 {
703         *orthogonal_rotation = false;
704         *flip_vert_scan_dir = false;
705         *flip_horz_scan_dir = false;
706         if (rotation == ROTATION_ANGLE_180) {
707                 *flip_vert_scan_dir = true;
708                 *flip_horz_scan_dir = true;
709         } else if (rotation == ROTATION_ANGLE_90) {
710                 *orthogonal_rotation = true;
711                 *flip_horz_scan_dir = true;
712         } else if (rotation == ROTATION_ANGLE_270) {
713                 *orthogonal_rotation = true;
714                 *flip_vert_scan_dir = true;
715         }
716
717         if (horizontal_mirror)
718                 *flip_horz_scan_dir = !*flip_horz_scan_dir;
719 }
720
721 int get_num_mpc_splits(struct pipe_ctx *pipe)
722 {
723         int mpc_split_count = 0;
724         struct pipe_ctx *other_pipe = pipe->bottom_pipe;
725
726         while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
727                 mpc_split_count++;
728                 other_pipe = other_pipe->bottom_pipe;
729         }
730         other_pipe = pipe->top_pipe;
731         while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
732                 mpc_split_count++;
733                 other_pipe = other_pipe->top_pipe;
734         }
735
736         return mpc_split_count;
737 }
738
739 int get_num_odm_splits(struct pipe_ctx *pipe)
740 {
741         int odm_split_count = 0;
742         struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
743         while (next_pipe) {
744                 odm_split_count++;
745                 next_pipe = next_pipe->next_odm_pipe;
746         }
747         pipe = pipe->prev_odm_pipe;
748         while (pipe) {
749                 odm_split_count++;
750                 pipe = pipe->prev_odm_pipe;
751         }
752         return odm_split_count;
753 }
754
755 static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx)
756 {
757         *split_count = get_num_odm_splits(pipe_ctx);
758         *split_idx = 0;
759         if (*split_count == 0) {
760                 /*Check for mpc split*/
761                 struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
762
763                 *split_count = get_num_mpc_splits(pipe_ctx);
764                 while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
765                         (*split_idx)++;
766                         split_pipe = split_pipe->top_pipe;
767                 }
768
769                 /* MPO window on right side of ODM split */
770                 if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe)
771                         (*split_idx)++;
772         } else {
773                 /*Get odm split index*/
774                 struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
775
776                 while (split_pipe) {
777                         (*split_idx)++;
778                         split_pipe = split_pipe->prev_odm_pipe;
779                 }
780         }
781 }
782
783 /*
784  * This is a preliminary vp size calculation to allow us to check taps support.
785  * The result is completely overridden afterwards.
786  */
787 static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
788 {
789         struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
790
791         data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width));
792         data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height));
793         data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width));
794         data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height));
795         if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
796                         pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
797                 swap(data->viewport.width, data->viewport.height);
798                 swap(data->viewport_c.width, data->viewport_c.height);
799         }
800 }
801
802 static void calculate_recout(struct pipe_ctx *pipe_ctx)
803 {
804         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
805         const struct dc_stream_state *stream = pipe_ctx->stream;
806         struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
807         struct rect surf_clip = plane_state->clip_rect;
808         bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
809         int split_count, split_idx;
810
811         calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
812         if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
813                 split_idx = 0;
814
815         /*
816          * Only the leftmost ODM pipe should be offset by a nonzero distance
817          */
818         if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) {
819                 /* MPO window on right side of ODM split */
820                 data->recout.x = stream->dst.x + (surf_clip.x - stream->src.x - stream->src.width/2) *
821                                 stream->dst.width / stream->src.width;
822         } else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
823                 data->recout.x = stream->dst.x;
824                 if (stream->src.x < surf_clip.x)
825                         data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
826                                                 / stream->src.width;
827         } else
828                 data->recout.x = 0;
829
830         if (stream->src.x > surf_clip.x)
831                 surf_clip.width -= stream->src.x - surf_clip.x;
832         data->recout.width = surf_clip.width * stream->dst.width / stream->src.width;
833         if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width)
834                 data->recout.width = stream->dst.x + stream->dst.width - data->recout.x;
835
836         data->recout.y = stream->dst.y;
837         if (stream->src.y < surf_clip.y)
838                 data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height
839                                                 / stream->src.height;
840         else if (stream->src.y > surf_clip.y)
841                 surf_clip.height -= stream->src.y - surf_clip.y;
842
843         data->recout.height = surf_clip.height * stream->dst.height / stream->src.height;
844         if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height)
845                 data->recout.height = stream->dst.y + stream->dst.height - data->recout.y;
846
847         /* Handle h & v split */
848         if (split_tb) {
849                 ASSERT(data->recout.height % 2 == 0);
850                 data->recout.height /= 2;
851         } else if (split_count) {
852                 if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) {
853                         /* extra pixels in the division remainder need to go to pipes after
854                          * the extra pixel index minus one(epimo) defined here as:
855                          */
856                         int epimo = split_count - data->recout.width % (split_count + 1);
857
858                         data->recout.x += (data->recout.width / (split_count + 1)) * split_idx;
859                         if (split_idx > epimo)
860                                 data->recout.x += split_idx - epimo - 1;
861                         ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0);
862                         data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
863                 } else {
864                         /* odm */
865                         if (split_idx == split_count) {
866                                 /* rightmost pipe is the remainder recout */
867                                 data->recout.width -= data->h_active * split_count - data->recout.x;
868
869                                 /* ODM combine cases with MPO we can get negative widths */
870                                 if (data->recout.width < 0)
871                                         data->recout.width = 0;
872
873                                 data->recout.x = 0;
874                         } else
875                                 data->recout.width = data->h_active - data->recout.x;
876                 }
877         }
878 }
879
880 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
881 {
882         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
883         const struct dc_stream_state *stream = pipe_ctx->stream;
884         struct rect surf_src = plane_state->src_rect;
885         const int in_w = stream->src.width;
886         const int in_h = stream->src.height;
887         const int out_w = stream->dst.width;
888         const int out_h = stream->dst.height;
889
890         /*Swap surf_src height and width since scaling ratios are in recout rotation*/
891         if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
892                         pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
893                 swap(surf_src.height, surf_src.width);
894
895         pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
896                                         surf_src.width,
897                                         plane_state->dst_rect.width);
898         pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
899                                         surf_src.height,
900                                         plane_state->dst_rect.height);
901
902         if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
903                 pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
904         else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
905                 pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
906
907         pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
908                 pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
909         pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
910                 pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
911
912         pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
913         pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
914
915         if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
916                         || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
917                 pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
918                 pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
919         }
920         pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
921                         pipe_ctx->plane_res.scl_data.ratios.horz, 19);
922         pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
923                         pipe_ctx->plane_res.scl_data.ratios.vert, 19);
924         pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
925                         pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
926         pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
927                         pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
928 }
929
930
931 /*
932  * We completely calculate vp offset, size and inits here based entirely on scaling
933  * ratios and recout for pixel perfect pipe combine.
934  */
935 static void calculate_init_and_vp(
936                 bool flip_scan_dir,
937                 int recout_offset_within_recout_full,
938                 int recout_size,
939                 int src_size,
940                 int taps,
941                 struct fixed31_32 ratio,
942                 struct fixed31_32 *init,
943                 int *vp_offset,
944                 int *vp_size)
945 {
946         struct fixed31_32 temp;
947         int int_part;
948
949         /*
950          * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
951          * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
952          * All following calculations are based on this logic.
953          *
954          * Init calculated according to formula:
955          *      init = (scaling_ratio + number_of_taps + 1) / 2
956          *      init_bot = init + scaling_ratio
957          *      to get pixel perfect combine add the fraction from calculating vp offset
958          */
959         temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
960         *vp_offset = dc_fixpt_floor(temp);
961         temp.value &= 0xffffffff;
962         *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
963                         dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
964         /*
965          * If viewport has non 0 offset and there are more taps than covered by init then
966          * we should decrease the offset and increase init so we are never sampling
967          * outside of viewport.
968          */
969         int_part = dc_fixpt_floor(*init);
970         if (int_part < taps) {
971                 int_part = taps - int_part;
972                 if (int_part > *vp_offset)
973                         int_part = *vp_offset;
974                 *vp_offset -= int_part;
975                 *init = dc_fixpt_add_int(*init, int_part);
976         }
977         /*
978          * If taps are sampling outside of viewport at end of recout and there are more pixels
979          * available in the surface we should increase the viewport size, regardless set vp to
980          * only what is used.
981          */
982         temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
983         *vp_size = dc_fixpt_floor(temp);
984         if (*vp_size + *vp_offset > src_size)
985                 *vp_size = src_size - *vp_offset;
986
987         /* We did all the math assuming we are scanning same direction as display does,
988          * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
989          * is flipped we simply need to calculate offset from the other side of plane.
990          * Note that outside of viewport all scaling hardware works in recout space.
991          */
992         if (flip_scan_dir)
993                 *vp_offset = src_size - *vp_offset - *vp_size;
994 }
995
996 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
997 {
998         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
999         const struct dc_stream_state *stream = pipe_ctx->stream;
1000         struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
1001         struct rect src = plane_state->src_rect;
1002         int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
1003                                 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
1004         int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y;
1005         bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
1006
1007         calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
1008         /*
1009          * recout full is what the recout would have been if we didnt clip
1010          * the source plane at all. We only care about left(ro_lb) and top(ro_tb)
1011          * offsets of recout within recout full because those are the directions
1012          * we scan from and therefore the only ones that affect inits.
1013          */
1014         recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
1015                         * stream->dst.width / stream->src.width;
1016         recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
1017                         * stream->dst.height / stream->src.height;
1018         if (pipe_ctx->prev_odm_pipe && split_idx)
1019                 ro_lb = data->h_active * split_idx - recout_full_x;
1020         else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe)
1021                 ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x;
1022         else
1023                 ro_lb = data->recout.x - recout_full_x;
1024         ro_tb = data->recout.y - recout_full_y;
1025         ASSERT(ro_lb >= 0 && ro_tb >= 0);
1026
1027         /*
1028          * Work in recout rotation since that requires less transformations
1029          */
1030         get_vp_scan_direction(
1031                         plane_state->rotation,
1032                         plane_state->horizontal_mirror,
1033                         &orthogonal_rotation,
1034                         &flip_vert_scan_dir,
1035                         &flip_horz_scan_dir);
1036
1037         if (orthogonal_rotation) {
1038                 swap(src.width, src.height);
1039                 swap(flip_vert_scan_dir, flip_horz_scan_dir);
1040         }
1041
1042         calculate_init_and_vp(
1043                         flip_horz_scan_dir,
1044                         ro_lb,
1045                         data->recout.width,
1046                         src.width,
1047                         data->taps.h_taps,
1048                         data->ratios.horz,
1049                         &data->inits.h,
1050                         &data->viewport.x,
1051                         &data->viewport.width);
1052         calculate_init_and_vp(
1053                         flip_horz_scan_dir,
1054                         ro_lb,
1055                         data->recout.width,
1056                         src.width / vpc_div,
1057                         data->taps.h_taps_c,
1058                         data->ratios.horz_c,
1059                         &data->inits.h_c,
1060                         &data->viewport_c.x,
1061                         &data->viewport_c.width);
1062         calculate_init_and_vp(
1063                         flip_vert_scan_dir,
1064                         ro_tb,
1065                         data->recout.height,
1066                         src.height,
1067                         data->taps.v_taps,
1068                         data->ratios.vert,
1069                         &data->inits.v,
1070                         &data->viewport.y,
1071                         &data->viewport.height);
1072         calculate_init_and_vp(
1073                         flip_vert_scan_dir,
1074                         ro_tb,
1075                         data->recout.height,
1076                         src.height / vpc_div,
1077                         data->taps.v_taps_c,
1078                         data->ratios.vert_c,
1079                         &data->inits.v_c,
1080                         &data->viewport_c.y,
1081                         &data->viewport_c.height);
1082         if (orthogonal_rotation) {
1083                 swap(data->viewport.x, data->viewport.y);
1084                 swap(data->viewport.width, data->viewport.height);
1085                 swap(data->viewport_c.x, data->viewport_c.y);
1086                 swap(data->viewport_c.width, data->viewport_c.height);
1087         }
1088         data->viewport.x += src.x;
1089         data->viewport.y += src.y;
1090         ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
1091         data->viewport_c.x += src.x / vpc_div;
1092         data->viewport_c.y += src.y / vpc_div;
1093 }
1094
1095 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
1096 {
1097         const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1098         struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
1099         bool res = false;
1100         DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
1101
1102         /* Invalid input */
1103         if (!plane_state->dst_rect.width ||
1104                         !plane_state->dst_rect.height ||
1105                         !plane_state->src_rect.width ||
1106                         !plane_state->src_rect.height) {
1107                 ASSERT(0);
1108                 return false;
1109         }
1110
1111         pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
1112                         pipe_ctx->plane_state->format);
1113
1114         /* Timing borders are part of vactive that we are also supposed to skip in addition
1115          * to any stream dst offset. Since dm logic assumes dst is in addressable
1116          * space we need to add the left and top borders to dst offsets temporarily.
1117          * TODO: fix in DM, stream dst is supposed to be in vactive
1118          */
1119         pipe_ctx->stream->dst.x += timing->h_border_left;
1120         pipe_ctx->stream->dst.y += timing->v_border_top;
1121
1122         /* Calculate H and V active size */
1123         pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable +
1124                         timing->h_border_left + timing->h_border_right;
1125         pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable +
1126                 timing->v_border_top + timing->v_border_bottom;
1127         if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) {
1128                 pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1;
1129
1130                 DC_LOG_SCALER("%s pipe %d: next_odm_pipe:%d   prev_odm_pipe:%d\n",
1131                                 __func__,
1132                                 pipe_ctx->pipe_idx,
1133                                 pipe_ctx->next_odm_pipe ? pipe_ctx->next_odm_pipe->pipe_idx : -1,
1134                                 pipe_ctx->prev_odm_pipe ? pipe_ctx->prev_odm_pipe->pipe_idx : -1);
1135         }       /* ODM + windows MPO, where window is on either right or left ODM half */
1136         else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) {
1137
1138                 pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1;
1139
1140                 DC_LOG_SCALER("%s ODM + windows MPO: pipe:%d top_pipe:%d   top_pipe->next_odm_pipe:%d   top_pipe->prev_odm_pipe:%d\n",
1141                                 __func__,
1142                                 pipe_ctx->pipe_idx,
1143                                 pipe_ctx->top_pipe->pipe_idx,
1144                                 pipe_ctx->top_pipe->next_odm_pipe ? pipe_ctx->top_pipe->next_odm_pipe->pipe_idx : -1,
1145                                 pipe_ctx->top_pipe->prev_odm_pipe ? pipe_ctx->top_pipe->prev_odm_pipe->pipe_idx : -1);
1146         }
1147         /* depends on h_active */
1148         calculate_recout(pipe_ctx);
1149         /* depends on pixel format */
1150         calculate_scaling_ratios(pipe_ctx);
1151         /* depends on scaling ratios and recout, does not calculate offset yet */
1152         calculate_viewport_size(pipe_ctx);
1153
1154         if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) {
1155                 /* Stopgap for validation of ODM + MPO on one side of screen case */
1156                 if (pipe_ctx->plane_res.scl_data.viewport.height < 1 ||
1157                                 pipe_ctx->plane_res.scl_data.viewport.width < 1)
1158                         return false;
1159         }
1160
1161         /*
1162          * LB calculations depend on vp size, h/v_active and scaling ratios
1163          * Setting line buffer pixel depth to 24bpp yields banding
1164          * on certain displays, such as the Sharp 4k. 36bpp is needed
1165          * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1166          * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
1167          * precision on DCN display engines, but apparently not for DCE, as
1168          * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
1169          * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
1170          * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
1171          * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
1172          */
1173         if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
1174                 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1175         else
1176                 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1177
1178         pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
1179
1180         if (pipe_ctx->plane_res.xfm != NULL)
1181                 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1182                                 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1183
1184         if (pipe_ctx->plane_res.dpp != NULL)
1185                 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1186                                 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1187
1188
1189         if (!res) {
1190                 /* Try 24 bpp linebuffer */
1191                 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
1192
1193                 if (pipe_ctx->plane_res.xfm != NULL)
1194                         res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1195                                         pipe_ctx->plane_res.xfm,
1196                                         &pipe_ctx->plane_res.scl_data,
1197                                         &plane_state->scaling_quality);
1198
1199                 if (pipe_ctx->plane_res.dpp != NULL)
1200                         res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1201                                         pipe_ctx->plane_res.dpp,
1202                                         &pipe_ctx->plane_res.scl_data,
1203                                         &plane_state->scaling_quality);
1204         }
1205
1206         /*
1207          * Depends on recout, scaling ratios, h_active and taps
1208          * May need to re-check lb size after this in some obscure scenario
1209          */
1210         if (res)
1211                 calculate_inits_and_viewports(pipe_ctx);
1212
1213         /*
1214          * Handle side by side and top bottom 3d recout offsets after vp calculation
1215          * since 3d is special and needs to calculate vp as if there is no recout offset
1216          * This may break with rotation, good thing we aren't mixing hw rotation and 3d
1217          */
1218         if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
1219                 ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
1220                         (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
1221                                 pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
1222                 if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1223                         pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
1224                 else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1225                         pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
1226         }
1227
1228         if (!pipe_ctx->stream->ctx->dc->config.enable_windowed_mpo_odm) {
1229                 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE ||
1230                                 pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1231                         res = false;
1232         } else {
1233                 /* Clamp minimum viewport size */
1234                 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE)
1235                         pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
1236                 if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1237                         pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
1238         }
1239
1240         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"
1241                         "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",
1242                         __func__,
1243                         pipe_ctx->pipe_idx,
1244                         pipe_ctx->plane_res.scl_data.viewport.height,
1245                         pipe_ctx->plane_res.scl_data.viewport.width,
1246                         pipe_ctx->plane_res.scl_data.viewport.x,
1247                         pipe_ctx->plane_res.scl_data.viewport.y,
1248                         pipe_ctx->plane_res.scl_data.recout.height,
1249                         pipe_ctx->plane_res.scl_data.recout.width,
1250                         pipe_ctx->plane_res.scl_data.recout.x,
1251                         pipe_ctx->plane_res.scl_data.recout.y,
1252                         pipe_ctx->plane_res.scl_data.h_active,
1253                         pipe_ctx->plane_res.scl_data.v_active,
1254                         plane_state->src_rect.height,
1255                         plane_state->src_rect.width,
1256                         plane_state->src_rect.x,
1257                         plane_state->src_rect.y,
1258                         plane_state->dst_rect.height,
1259                         plane_state->dst_rect.width,
1260                         plane_state->dst_rect.x,
1261                         plane_state->dst_rect.y,
1262                         plane_state->clip_rect.height,
1263                         plane_state->clip_rect.width,
1264                         plane_state->clip_rect.x,
1265                         plane_state->clip_rect.y);
1266
1267         pipe_ctx->stream->dst.x -= timing->h_border_left;
1268         pipe_ctx->stream->dst.y -= timing->v_border_top;
1269
1270         return res;
1271 }
1272
1273
1274 enum dc_status resource_build_scaling_params_for_context(
1275         const struct dc  *dc,
1276         struct dc_state *context)
1277 {
1278         int i;
1279
1280         for (i = 0; i < MAX_PIPES; i++) {
1281                 if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
1282                                 context->res_ctx.pipe_ctx[i].stream != NULL)
1283                         if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
1284                                 return DC_FAIL_SCALING;
1285         }
1286
1287         return DC_OK;
1288 }
1289
1290 struct pipe_ctx *find_idle_secondary_pipe(
1291                 struct resource_context *res_ctx,
1292                 const struct resource_pool *pool,
1293                 const struct pipe_ctx *primary_pipe)
1294 {
1295         int i;
1296         struct pipe_ctx *secondary_pipe = NULL;
1297
1298         /*
1299          * We add a preferred pipe mapping to avoid the chance that
1300          * MPCCs already in use will need to be reassigned to other trees.
1301          * For example, if we went with the strict, assign backwards logic:
1302          *
1303          * (State 1)
1304          * Display A on, no surface, top pipe = 0
1305          * Display B on, no surface, top pipe = 1
1306          *
1307          * (State 2)
1308          * Display A on, no surface, top pipe = 0
1309          * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1310          *
1311          * (State 3)
1312          * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1313          * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1314          *
1315          * The state 2->3 transition requires remapping MPCC 5 from display B
1316          * to display A.
1317          *
1318          * However, with the preferred pipe logic, state 2 would look like:
1319          *
1320          * (State 2)
1321          * Display A on, no surface, top pipe = 0
1322          * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1323          *
1324          * This would then cause 2->3 to not require remapping any MPCCs.
1325          */
1326         if (primary_pipe) {
1327                 int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
1328                 if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
1329                         secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
1330                         secondary_pipe->pipe_idx = preferred_pipe_idx;
1331                 }
1332         }
1333
1334         /*
1335          * search backwards for the second pipe to keep pipe
1336          * assignment more consistent
1337          */
1338         if (!secondary_pipe)
1339                 for (i = pool->pipe_count - 1; i >= 0; i--) {
1340                         if (res_ctx->pipe_ctx[i].stream == NULL) {
1341                                 secondary_pipe = &res_ctx->pipe_ctx[i];
1342                                 secondary_pipe->pipe_idx = i;
1343                                 break;
1344                         }
1345                 }
1346
1347         return secondary_pipe;
1348 }
1349
1350 struct pipe_ctx *resource_get_head_pipe_for_stream(
1351                 struct resource_context *res_ctx,
1352                 struct dc_stream_state *stream)
1353 {
1354         int i;
1355
1356         for (i = 0; i < MAX_PIPES; i++) {
1357                 if (res_ctx->pipe_ctx[i].stream == stream
1358                                 && !res_ctx->pipe_ctx[i].top_pipe
1359                                 && !res_ctx->pipe_ctx[i].prev_odm_pipe)
1360                         return &res_ctx->pipe_ctx[i];
1361         }
1362         return NULL;
1363 }
1364
1365 static struct pipe_ctx *resource_get_tail_pipe(
1366                 struct resource_context *res_ctx,
1367                 struct pipe_ctx *head_pipe)
1368 {
1369         struct pipe_ctx *tail_pipe;
1370
1371         tail_pipe = head_pipe->bottom_pipe;
1372
1373         while (tail_pipe) {
1374                 head_pipe = tail_pipe;
1375                 tail_pipe = tail_pipe->bottom_pipe;
1376         }
1377
1378         return head_pipe;
1379 }
1380
1381 /*
1382  * A free_pipe for a stream is defined here as a pipe
1383  * that has no surface attached yet
1384  */
1385 static struct pipe_ctx *acquire_free_pipe_for_head(
1386                 struct dc_state *context,
1387                 const struct resource_pool *pool,
1388                 struct pipe_ctx *head_pipe)
1389 {
1390         int i;
1391         struct resource_context *res_ctx = &context->res_ctx;
1392
1393         if (!head_pipe->plane_state)
1394                 return head_pipe;
1395
1396         /* Re-use pipe already acquired for this stream if available*/
1397         for (i = pool->pipe_count - 1; i >= 0; i--) {
1398                 if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
1399                                 !res_ctx->pipe_ctx[i].plane_state) {
1400                         return &res_ctx->pipe_ctx[i];
1401                 }
1402         }
1403
1404         /*
1405          * At this point we have no re-useable pipe for this stream and we need
1406          * to acquire an idle one to satisfy the request
1407          */
1408
1409         if (!pool->funcs->acquire_idle_pipe_for_layer) {
1410                 if (!pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer)
1411                         return NULL;
1412                 else
1413                         return pool->funcs->acquire_idle_pipe_for_head_pipe_in_layer(context, pool, head_pipe->stream, head_pipe);
1414         }
1415
1416         return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
1417 }
1418
1419 static int acquire_first_split_pipe(
1420                 struct resource_context *res_ctx,
1421                 const struct resource_pool *pool,
1422                 struct dc_stream_state *stream)
1423 {
1424         int i;
1425
1426         for (i = 0; i < pool->pipe_count; i++) {
1427                 struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
1428
1429                 if (split_pipe->top_pipe &&
1430                                 split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
1431                         split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
1432                         if (split_pipe->bottom_pipe)
1433                                 split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
1434
1435                         if (split_pipe->top_pipe->plane_state)
1436                                 resource_build_scaling_params(split_pipe->top_pipe);
1437
1438                         memset(split_pipe, 0, sizeof(*split_pipe));
1439                         split_pipe->stream_res.tg = pool->timing_generators[i];
1440                         split_pipe->plane_res.hubp = pool->hubps[i];
1441                         split_pipe->plane_res.ipp = pool->ipps[i];
1442                         split_pipe->plane_res.dpp = pool->dpps[i];
1443                         split_pipe->stream_res.opp = pool->opps[i];
1444                         split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
1445                         split_pipe->pipe_idx = i;
1446
1447                         split_pipe->stream = stream;
1448                         return i;
1449                 }
1450         }
1451         return -1;
1452 }
1453
1454 bool dc_add_plane_to_context(
1455                 const struct dc *dc,
1456                 struct dc_stream_state *stream,
1457                 struct dc_plane_state *plane_state,
1458                 struct dc_state *context)
1459 {
1460         int i;
1461         struct resource_pool *pool = dc->res_pool;
1462         struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
1463         struct dc_stream_status *stream_status = NULL;
1464         struct pipe_ctx *prev_right_head = NULL;
1465         struct pipe_ctx *free_right_pipe = NULL;
1466         struct pipe_ctx *prev_left_head = NULL;
1467
1468         DC_LOGGER_INIT(stream->ctx->logger);
1469         for (i = 0; i < context->stream_count; i++)
1470                 if (context->streams[i] == stream) {
1471                         stream_status = &context->stream_status[i];
1472                         break;
1473                 }
1474         if (stream_status == NULL) {
1475                 dm_error("Existing stream not found; failed to attach surface!\n");
1476                 return false;
1477         }
1478
1479
1480         if (stream_status->plane_count == MAX_SURFACE_NUM) {
1481                 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
1482                                 plane_state, MAX_SURFACE_NUM);
1483                 return false;
1484         }
1485
1486         head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
1487
1488         if (!head_pipe) {
1489                 dm_error("Head pipe not found for stream_state %p !\n", stream);
1490                 return false;
1491         }
1492
1493         /* retain new surface, but only once per stream */
1494         dc_plane_state_retain(plane_state);
1495
1496         while (head_pipe) {
1497                 free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
1498
1499                 if (!free_pipe) {
1500                         int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
1501                         if (pipe_idx >= 0)
1502                                 free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
1503                 }
1504
1505                 if (!free_pipe) {
1506                         dc_plane_state_release(plane_state);
1507                         return false;
1508                 }
1509
1510                 free_pipe->plane_state = plane_state;
1511
1512                 if (head_pipe != free_pipe) {
1513                         tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
1514                         ASSERT(tail_pipe);
1515
1516                         /* ODM + window MPO, where MPO window is on right half only */
1517                         if (free_pipe->plane_state &&
1518                                 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2) &&
1519                                 tail_pipe->next_odm_pipe) {
1520
1521                                 /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on
1522                                  *  the right side, then we will invalidate a 2nd one on the right side
1523                                  */
1524                                 if (head_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
1525                                         dc_plane_state_release(plane_state);
1526                                         return false;
1527                                 }
1528
1529                                 DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d  tail_pipe->next_odm_pipe:%d\n",
1530                                                 __func__,
1531                                                 free_pipe->pipe_idx,
1532                                                 tail_pipe->next_odm_pipe ? tail_pipe->next_odm_pipe->pipe_idx : -1);
1533
1534                                 /*
1535                                  * We want to avoid the case where the right side already has a pipe assigned to
1536                                  *  it and is different from free_pipe ( which would cause trigger a pipe
1537                                  *  reallocation ).
1538                                  * Check the old context to see if the right side already has a pipe allocated
1539                                  * - If not, continue to use free_pipe
1540                                  * - If the right side already has a pipe, use that pipe instead if its available
1541                                  */
1542
1543                                 /*
1544                                  * We also want to avoid the case where with three plane ( 2 MPO videos ), we have
1545                                  *  both videos on the left side so one of the videos is invalidated.  Then we
1546                                  *  move the invalidated video back to the right side.  If the order of the plane
1547                                  *  states is such that the right MPO plane is processed first, the free pipe
1548                                  *  selected by the head will be the left MPO pipe. But since there was no right
1549                                  *  MPO pipe, it will assign the free pipe to the right MPO pipe instead and
1550                                  *  a pipe reallocation will occur.
1551                                  * Check the old context to see if the left side already has a pipe allocated
1552                                  * - If not, continue to use free_pipe
1553                                  * - If the left side is already using this pipe, then pick another pipe for right
1554                                  */
1555
1556                                 prev_right_head = &dc->current_state->res_ctx.pipe_ctx[tail_pipe->next_odm_pipe->pipe_idx];
1557                                 if ((prev_right_head->bottom_pipe) &&
1558                                         (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) {
1559                                         free_right_pipe = acquire_free_pipe_for_head(context, pool, tail_pipe->next_odm_pipe);
1560                                 } else {
1561                                         prev_left_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->pipe_idx];
1562                                         if ((prev_left_head->bottom_pipe) &&
1563                                                 (free_pipe->pipe_idx == prev_left_head->bottom_pipe->pipe_idx)) {
1564                                                 free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
1565                                         }
1566                                 }
1567
1568                                 if (free_right_pipe) {
1569                                         free_pipe->stream = NULL;
1570                                         memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource));
1571                                         memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource));
1572                                         free_pipe->plane_state = NULL;
1573                                         free_pipe->pipe_idx = 0;
1574                                         free_right_pipe->plane_state = plane_state;
1575                                         free_pipe = free_right_pipe;
1576                                 }
1577
1578                                 free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg;
1579                                 free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm;
1580                                 free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp;
1581                                 free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc;
1582                                 free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio;
1583                                 free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source;
1584
1585                                 free_pipe->top_pipe = tail_pipe->next_odm_pipe;
1586                                 tail_pipe->next_odm_pipe->bottom_pipe = free_pipe;
1587                         } else if (free_pipe->plane_state &&
1588                                 (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)
1589                                 && head_pipe->next_odm_pipe) {
1590
1591                                 /* For ODM + window MPO, support 3 plane ( 2 MPO ) case.
1592                                  * Here we have a desktop ODM + left window MPO and a new MPO window appears
1593                                  *  on the right side only.  It fails the first case, because tail_pipe is the
1594                                  *  left window MPO, so it has no next_odm_pipe.  So in this scenario, we check
1595                                  *  for head_pipe->next_odm_pipe instead
1596                                  */
1597                                 DC_LOG_SCALER("%s - ODM + win MPO (left) + win MPO (right). free_pipe:%d  head_pipe->next_odm:%d\n",
1598                                                 __func__,
1599                                                 free_pipe->pipe_idx,
1600                                                 head_pipe->next_odm_pipe ? head_pipe->next_odm_pipe->pipe_idx : -1);
1601
1602                                 /*
1603                                  * We want to avoid the case where the right side already has a pipe assigned to
1604                                  *  it and is different from free_pipe ( which would cause trigger a pipe
1605                                  *  reallocation ).
1606                                  * Check the old context to see if the right side already has a pipe allocated
1607                                  * - If not, continue to use free_pipe
1608                                  * - If the right side already has a pipe, use that pipe instead if its available
1609                                  */
1610                                 prev_right_head = &dc->current_state->res_ctx.pipe_ctx[head_pipe->next_odm_pipe->pipe_idx];
1611                                 if ((prev_right_head->bottom_pipe) &&
1612                                         (free_pipe->pipe_idx != prev_right_head->bottom_pipe->pipe_idx)) {
1613                                         free_right_pipe = acquire_free_pipe_for_head(context, pool, head_pipe->next_odm_pipe);
1614                                         if (free_right_pipe) {
1615                                                 free_pipe->stream = NULL;
1616                                                 memset(&free_pipe->stream_res, 0, sizeof(struct stream_resource));
1617                                                 memset(&free_pipe->plane_res, 0, sizeof(struct plane_resource));
1618                                                 free_pipe->plane_state = NULL;
1619                                                 free_pipe->pipe_idx = 0;
1620                                                 free_right_pipe->plane_state = plane_state;
1621                                                 free_pipe = free_right_pipe;
1622                                         }
1623                                 }
1624
1625                                 free_pipe->stream_res.tg = head_pipe->next_odm_pipe->stream_res.tg;
1626                                 free_pipe->stream_res.abm = head_pipe->next_odm_pipe->stream_res.abm;
1627                                 free_pipe->stream_res.opp = head_pipe->next_odm_pipe->stream_res.opp;
1628                                 free_pipe->stream_res.stream_enc = head_pipe->next_odm_pipe->stream_res.stream_enc;
1629                                 free_pipe->stream_res.audio = head_pipe->next_odm_pipe->stream_res.audio;
1630                                 free_pipe->clock_source = head_pipe->next_odm_pipe->clock_source;
1631
1632                                 free_pipe->top_pipe = head_pipe->next_odm_pipe;
1633                                 head_pipe->next_odm_pipe->bottom_pipe = free_pipe;
1634                         } else {
1635
1636                                 /* For ODM + window MPO, in 3 plane case, if we already have a MPO window on
1637                                  *  the left side, then we will invalidate a 2nd one on the left side
1638                                  */
1639                                 if (head_pipe->next_odm_pipe && tail_pipe->top_pipe) {
1640                                         dc_plane_state_release(plane_state);
1641                                         return false;
1642                                 }
1643
1644                                 free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
1645                                 free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
1646                                 free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
1647                                 free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
1648                                 free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
1649                                 free_pipe->clock_source = tail_pipe->clock_source;
1650
1651                                 free_pipe->top_pipe = tail_pipe;
1652                                 tail_pipe->bottom_pipe = free_pipe;
1653
1654                                 /* Connect MPO pipes together if MPO window is in the centre */
1655                                 if (!(free_pipe->plane_state &&
1656                                                 (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <=
1657                                                 free_pipe->stream->src.x + free_pipe->stream->src.width/2))) {
1658                                         if (!free_pipe->next_odm_pipe &&
1659                                                 tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
1660                                                 free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe;
1661                                                 tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe;
1662                                         }
1663                                         if (!free_pipe->prev_odm_pipe &&
1664                                                 tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) {
1665                                                 free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
1666                                                 tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
1667                                         }
1668                                 }
1669                         }
1670                 }
1671
1672                 /* ODM + window MPO, where MPO window is on left half only */
1673                 if (free_pipe->plane_state &&
1674                         (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <=
1675                         free_pipe->stream->src.x + free_pipe->stream->src.width/2)) {
1676                         DC_LOG_SCALER("%s - ODM + window MPO(left). free_pipe:%d\n",
1677                                         __func__,
1678                                         free_pipe->pipe_idx);
1679                         break;
1680                 }
1681                 /* ODM + window MPO, where MPO window is on right half only */
1682                 if (free_pipe->plane_state &&
1683                         (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.x + free_pipe->stream->src.width/2)) {
1684                         DC_LOG_SCALER("%s - ODM + window MPO(right). free_pipe:%d\n",
1685                                         __func__,
1686                                         free_pipe->pipe_idx);
1687                         break;
1688                 }
1689
1690                 head_pipe = head_pipe->next_odm_pipe;
1691         }
1692         /* assign new surfaces*/
1693         stream_status->plane_states[stream_status->plane_count] = plane_state;
1694
1695         stream_status->plane_count++;
1696
1697         return true;
1698 }
1699
1700 bool dc_remove_plane_from_context(
1701                 const struct dc *dc,
1702                 struct dc_stream_state *stream,
1703                 struct dc_plane_state *plane_state,
1704                 struct dc_state *context)
1705 {
1706         int i;
1707         struct dc_stream_status *stream_status = NULL;
1708         struct resource_pool *pool = dc->res_pool;
1709
1710         if (!plane_state)
1711                 return true;
1712
1713         for (i = 0; i < context->stream_count; i++)
1714                 if (context->streams[i] == stream) {
1715                         stream_status = &context->stream_status[i];
1716                         break;
1717                 }
1718
1719         if (stream_status == NULL) {
1720                 dm_error("Existing stream not found; failed to remove plane.\n");
1721                 return false;
1722         }
1723
1724         /* release pipe for plane*/
1725         for (i = pool->pipe_count - 1; i >= 0; i--) {
1726                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1727
1728                 if (pipe_ctx->plane_state == plane_state) {
1729                         if (pipe_ctx->top_pipe)
1730                                 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
1731
1732                         /* Second condition is to avoid setting NULL to top pipe
1733                          * of tail pipe making it look like head pipe in subsequent
1734                          * deletes
1735                          */
1736                         if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
1737                                 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
1738
1739                         /*
1740                          * For head pipe detach surfaces from pipe for tail
1741                          * pipe just zero it out
1742                          */
1743                         if (!pipe_ctx->top_pipe)
1744                                 pipe_ctx->plane_state = NULL;
1745                         else
1746                                 memset(pipe_ctx, 0, sizeof(*pipe_ctx));
1747                 }
1748         }
1749
1750
1751         for (i = 0; i < stream_status->plane_count; i++) {
1752                 if (stream_status->plane_states[i] == plane_state) {
1753                         dc_plane_state_release(stream_status->plane_states[i]);
1754                         break;
1755                 }
1756         }
1757
1758         if (i == stream_status->plane_count) {
1759                 dm_error("Existing plane_state not found; failed to detach it!\n");
1760                 return false;
1761         }
1762
1763         stream_status->plane_count--;
1764
1765         /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
1766         for (; i < stream_status->plane_count; i++)
1767                 stream_status->plane_states[i] = stream_status->plane_states[i + 1];
1768
1769         stream_status->plane_states[stream_status->plane_count] = NULL;
1770
1771         return true;
1772 }
1773
1774 /**
1775  * dc_rem_all_planes_for_stream - Remove planes attached to the target stream.
1776  *
1777  * @dc: Current dc state.
1778  * @stream: Target stream, which we want to remove the attached plans.
1779  * @context: New context.
1780  *
1781  * Return:
1782  * Return true if DC was able to remove all planes from the target
1783  * stream, otherwise, return false.
1784  */
1785 bool dc_rem_all_planes_for_stream(
1786                 const struct dc *dc,
1787                 struct dc_stream_state *stream,
1788                 struct dc_state *context)
1789 {
1790         int i, old_plane_count;
1791         struct dc_stream_status *stream_status = NULL;
1792         struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
1793
1794         for (i = 0; i < context->stream_count; i++)
1795                         if (context->streams[i] == stream) {
1796                                 stream_status = &context->stream_status[i];
1797                                 break;
1798                         }
1799
1800         if (stream_status == NULL) {
1801                 dm_error("Existing stream %p not found!\n", stream);
1802                 return false;
1803         }
1804
1805         old_plane_count = stream_status->plane_count;
1806
1807         for (i = 0; i < old_plane_count; i++)
1808                 del_planes[i] = stream_status->plane_states[i];
1809
1810         for (i = 0; i < old_plane_count; i++)
1811                 if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context))
1812                         return false;
1813
1814         return true;
1815 }
1816
1817 static bool add_all_planes_for_stream(
1818                 const struct dc *dc,
1819                 struct dc_stream_state *stream,
1820                 const struct dc_validation_set set[],
1821                 int set_count,
1822                 struct dc_state *context)
1823 {
1824         int i, j;
1825
1826         for (i = 0; i < set_count; i++)
1827                 if (set[i].stream == stream)
1828                         break;
1829
1830         if (i == set_count) {
1831                 dm_error("Stream %p not found in set!\n", stream);
1832                 return false;
1833         }
1834
1835         for (j = 0; j < set[i].plane_count; j++)
1836                 if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context))
1837                         return false;
1838
1839         return true;
1840 }
1841
1842 bool dc_add_all_planes_for_stream(
1843                 const struct dc *dc,
1844                 struct dc_stream_state *stream,
1845                 struct dc_plane_state * const *plane_states,
1846                 int plane_count,
1847                 struct dc_state *context)
1848 {
1849         struct dc_validation_set set;
1850         int i;
1851
1852         set.stream = stream;
1853         set.plane_count = plane_count;
1854
1855         for (i = 0; i < plane_count; i++)
1856                 set.plane_states[i] = plane_states[i];
1857
1858         return add_all_planes_for_stream(dc, stream, &set, 1, context);
1859 }
1860
1861 bool is_timing_changed(struct dc_stream_state *cur_stream,
1862                        struct dc_stream_state *new_stream)
1863 {
1864         if (cur_stream == NULL)
1865                 return true;
1866
1867         /* If output color space is changed, need to reprogram info frames */
1868         if (cur_stream->output_color_space != new_stream->output_color_space)
1869                 return true;
1870
1871         return memcmp(
1872                 &cur_stream->timing,
1873                 &new_stream->timing,
1874                 sizeof(struct dc_crtc_timing)) != 0;
1875 }
1876
1877 static bool are_stream_backends_same(
1878         struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
1879 {
1880         if (stream_a == stream_b)
1881                 return true;
1882
1883         if (stream_a == NULL || stream_b == NULL)
1884                 return false;
1885
1886         if (is_timing_changed(stream_a, stream_b))
1887                 return false;
1888
1889         if (stream_a->signal != stream_b->signal)
1890                 return false;
1891
1892         if (stream_a->dpms_off != stream_b->dpms_off)
1893                 return false;
1894
1895         return true;
1896 }
1897
1898 /*
1899  * dc_is_stream_unchanged() - Compare two stream states for equivalence.
1900  *
1901  * Checks if there a difference between the two states
1902  * that would require a mode change.
1903  *
1904  * Does not compare cursor position or attributes.
1905  */
1906 bool dc_is_stream_unchanged(
1907         struct dc_stream_state *old_stream, struct dc_stream_state *stream)
1908 {
1909
1910         if (!are_stream_backends_same(old_stream, stream))
1911                 return false;
1912
1913         if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
1914                 return false;
1915
1916         /*compare audio info*/
1917         if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
1918                 return false;
1919
1920         return true;
1921 }
1922
1923 /*
1924  * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
1925  */
1926 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
1927                                     struct dc_stream_state *stream)
1928 {
1929         if (old_stream == stream)
1930                 return true;
1931
1932         if (old_stream == NULL || stream == NULL)
1933                 return false;
1934
1935         if (memcmp(&old_stream->src,
1936                         &stream->src,
1937                         sizeof(struct rect)) != 0)
1938                 return false;
1939
1940         if (memcmp(&old_stream->dst,
1941                         &stream->dst,
1942                         sizeof(struct rect)) != 0)
1943                 return false;
1944
1945         return true;
1946 }
1947
1948 static void update_stream_engine_usage(
1949                 struct resource_context *res_ctx,
1950                 const struct resource_pool *pool,
1951                 struct stream_encoder *stream_enc,
1952                 bool acquired)
1953 {
1954         int i;
1955
1956         for (i = 0; i < pool->stream_enc_count; i++) {
1957                 if (pool->stream_enc[i] == stream_enc)
1958                         res_ctx->is_stream_enc_acquired[i] = acquired;
1959         }
1960 }
1961
1962 static void update_hpo_dp_stream_engine_usage(
1963                 struct resource_context *res_ctx,
1964                 const struct resource_pool *pool,
1965                 struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
1966                 bool acquired)
1967 {
1968         int i;
1969
1970         for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
1971                 if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
1972                         res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
1973         }
1974 }
1975
1976 static inline int find_acquired_hpo_dp_link_enc_for_link(
1977                 const struct resource_context *res_ctx,
1978                 const struct dc_link *link)
1979 {
1980         int i;
1981
1982         for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
1983                 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
1984                                 res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
1985                         return i;
1986
1987         return -1;
1988 }
1989
1990 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
1991                 const struct resource_pool *pool)
1992 {
1993         int i;
1994
1995         for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
1996                 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
1997                         break;
1998
1999         return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
2000                         i < pool->hpo_dp_link_enc_count) ? i : -1;
2001 }
2002
2003 static inline void acquire_hpo_dp_link_enc(
2004                 struct resource_context *res_ctx,
2005                 unsigned int link_index,
2006                 int enc_index)
2007 {
2008         res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
2009         res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
2010 }
2011
2012 static inline void retain_hpo_dp_link_enc(
2013                 struct resource_context *res_ctx,
2014                 int enc_index)
2015 {
2016         res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
2017 }
2018
2019 static inline void release_hpo_dp_link_enc(
2020                 struct resource_context *res_ctx,
2021                 int enc_index)
2022 {
2023         ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
2024         res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
2025 }
2026
2027 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
2028                 const struct resource_pool *pool,
2029                 struct pipe_ctx *pipe_ctx,
2030                 struct dc_stream_state *stream)
2031 {
2032         int enc_index;
2033
2034         enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2035
2036         if (enc_index >= 0) {
2037                 retain_hpo_dp_link_enc(res_ctx, enc_index);
2038         } else {
2039                 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
2040                 if (enc_index >= 0)
2041                         acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
2042         }
2043
2044         if (enc_index >= 0)
2045                 pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
2046
2047         return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
2048 }
2049
2050 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
2051                 struct pipe_ctx *pipe_ctx,
2052                 struct dc_stream_state *stream)
2053 {
2054         int enc_index;
2055
2056         enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2057
2058         if (enc_index >= 0) {
2059                 release_hpo_dp_link_enc(res_ctx, enc_index);
2060                 pipe_ctx->link_res.hpo_dp_link_enc = NULL;
2061         }
2062 }
2063
2064 /* TODO: release audio object */
2065 void update_audio_usage(
2066                 struct resource_context *res_ctx,
2067                 const struct resource_pool *pool,
2068                 struct audio *audio,
2069                 bool acquired)
2070 {
2071         int i;
2072         for (i = 0; i < pool->audio_count; i++) {
2073                 if (pool->audios[i] == audio)
2074                         res_ctx->is_audio_acquired[i] = acquired;
2075         }
2076 }
2077
2078 static int acquire_first_free_pipe(
2079                 struct resource_context *res_ctx,
2080                 const struct resource_pool *pool,
2081                 struct dc_stream_state *stream)
2082 {
2083         int i;
2084
2085         for (i = 0; i < pool->pipe_count; i++) {
2086                 if (!res_ctx->pipe_ctx[i].stream) {
2087                         struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
2088
2089                         pipe_ctx->stream_res.tg = pool->timing_generators[i];
2090                         pipe_ctx->plane_res.mi = pool->mis[i];
2091                         pipe_ctx->plane_res.hubp = pool->hubps[i];
2092                         pipe_ctx->plane_res.ipp = pool->ipps[i];
2093                         pipe_ctx->plane_res.xfm = pool->transforms[i];
2094                         pipe_ctx->plane_res.dpp = pool->dpps[i];
2095                         pipe_ctx->stream_res.opp = pool->opps[i];
2096                         if (pool->dpps[i])
2097                                 pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst;
2098                         pipe_ctx->pipe_idx = i;
2099
2100                         if (i >= pool->timing_generator_count) {
2101                                 int tg_inst = pool->timing_generator_count - 1;
2102
2103                                 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
2104                                 pipe_ctx->stream_res.opp = pool->opps[tg_inst];
2105                         }
2106
2107                         pipe_ctx->stream = stream;
2108                         return i;
2109                 }
2110         }
2111         return -1;
2112 }
2113
2114 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
2115                 struct resource_context *res_ctx,
2116                 const struct resource_pool *pool,
2117                 struct dc_stream_state *stream)
2118 {
2119         int i;
2120
2121         for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
2122                 if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
2123                                 pool->hpo_dp_stream_enc[i]) {
2124
2125                         return pool->hpo_dp_stream_enc[i];
2126                 }
2127         }
2128
2129         return NULL;
2130 }
2131
2132 static struct audio *find_first_free_audio(
2133                 struct resource_context *res_ctx,
2134                 const struct resource_pool *pool,
2135                 enum engine_id id,
2136                 enum dce_version dc_version)
2137 {
2138         int i, available_audio_count;
2139
2140         available_audio_count = pool->audio_count;
2141
2142         for (i = 0; i < available_audio_count; i++) {
2143                 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
2144                         /*we have enough audio endpoint, find the matching inst*/
2145                         if (id != i)
2146                                 continue;
2147                         return pool->audios[i];
2148                 }
2149         }
2150
2151         /* use engine id to find free audio */
2152         if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
2153                 return pool->audios[id];
2154         }
2155         /*not found the matching one, first come first serve*/
2156         for (i = 0; i < available_audio_count; i++) {
2157                 if (res_ctx->is_audio_acquired[i] == false) {
2158                         return pool->audios[i];
2159                 }
2160         }
2161         return NULL;
2162 }
2163
2164 /*
2165  * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state.
2166  */
2167 enum dc_status dc_add_stream_to_ctx(
2168                 struct dc *dc,
2169                 struct dc_state *new_ctx,
2170                 struct dc_stream_state *stream)
2171 {
2172         enum dc_status res;
2173         DC_LOGGER_INIT(dc->ctx->logger);
2174
2175         if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) {
2176                 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
2177                 return DC_ERROR_UNEXPECTED;
2178         }
2179
2180         new_ctx->streams[new_ctx->stream_count] = stream;
2181         dc_stream_retain(stream);
2182         new_ctx->stream_count++;
2183
2184         res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
2185         if (res != DC_OK)
2186                 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
2187
2188         return res;
2189 }
2190
2191 /*
2192  * dc_remove_stream_from_ctx() - Remove a stream from a dc_state.
2193  */
2194 enum dc_status dc_remove_stream_from_ctx(
2195                         struct dc *dc,
2196                         struct dc_state *new_ctx,
2197                         struct dc_stream_state *stream)
2198 {
2199         int i;
2200         struct dc_context *dc_ctx = dc->ctx;
2201         struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
2202         struct pipe_ctx *odm_pipe;
2203
2204         if (!del_pipe) {
2205                 DC_ERROR("Pipe not found for stream %p !\n", stream);
2206                 return DC_ERROR_UNEXPECTED;
2207         }
2208
2209         odm_pipe = del_pipe->next_odm_pipe;
2210
2211         /* Release primary pipe */
2212         ASSERT(del_pipe->stream_res.stream_enc);
2213         update_stream_engine_usage(
2214                         &new_ctx->res_ctx,
2215                                 dc->res_pool,
2216                         del_pipe->stream_res.stream_enc,
2217                         false);
2218
2219         if (dc->link_srv->dp_is_128b_132b_signal(del_pipe)) {
2220                 update_hpo_dp_stream_engine_usage(
2221                         &new_ctx->res_ctx, dc->res_pool,
2222                         del_pipe->stream_res.hpo_dp_stream_enc,
2223                         false);
2224                 remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream);
2225         }
2226
2227         if (del_pipe->stream_res.audio)
2228                 update_audio_usage(
2229                         &new_ctx->res_ctx,
2230                         dc->res_pool,
2231                         del_pipe->stream_res.audio,
2232                         false);
2233
2234         resource_unreference_clock_source(&new_ctx->res_ctx,
2235                                           dc->res_pool,
2236                                           del_pipe->clock_source);
2237
2238         if (dc->res_pool->funcs->remove_stream_from_ctx)
2239                 dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
2240
2241         while (odm_pipe) {
2242                 struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
2243
2244                 memset(odm_pipe, 0, sizeof(*odm_pipe));
2245                 odm_pipe = next_odm_pipe;
2246         }
2247         memset(del_pipe, 0, sizeof(*del_pipe));
2248
2249         for (i = 0; i < new_ctx->stream_count; i++)
2250                 if (new_ctx->streams[i] == stream)
2251                         break;
2252
2253         if (new_ctx->streams[i] != stream) {
2254                 DC_ERROR("Context doesn't have stream %p !\n", stream);
2255                 return DC_ERROR_UNEXPECTED;
2256         }
2257
2258         dc_stream_release(new_ctx->streams[i]);
2259         new_ctx->stream_count--;
2260
2261         /* Trim back arrays */
2262         for (; i < new_ctx->stream_count; i++) {
2263                 new_ctx->streams[i] = new_ctx->streams[i + 1];
2264                 new_ctx->stream_status[i] = new_ctx->stream_status[i + 1];
2265         }
2266
2267         new_ctx->streams[new_ctx->stream_count] = NULL;
2268         memset(
2269                         &new_ctx->stream_status[new_ctx->stream_count],
2270                         0,
2271                         sizeof(new_ctx->stream_status[0]));
2272
2273         return DC_OK;
2274 }
2275
2276 static struct dc_stream_state *find_pll_sharable_stream(
2277                 struct dc_stream_state *stream_needs_pll,
2278                 struct dc_state *context)
2279 {
2280         int i;
2281
2282         for (i = 0; i < context->stream_count; i++) {
2283                 struct dc_stream_state *stream_has_pll = context->streams[i];
2284
2285                 /* We are looking for non dp, non virtual stream */
2286                 if (resource_are_streams_timing_synchronizable(
2287                         stream_needs_pll, stream_has_pll)
2288                         && !dc_is_dp_signal(stream_has_pll->signal)
2289                         && stream_has_pll->link->connector_signal
2290                         != SIGNAL_TYPE_VIRTUAL)
2291                         return stream_has_pll;
2292
2293         }
2294
2295         return NULL;
2296 }
2297
2298 static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
2299 {
2300         uint32_t pix_clk = timing->pix_clk_100hz;
2301         uint32_t normalized_pix_clk = pix_clk;
2302
2303         if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
2304                 pix_clk /= 2;
2305         if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
2306                 switch (timing->display_color_depth) {
2307                 case COLOR_DEPTH_666:
2308                 case COLOR_DEPTH_888:
2309                         normalized_pix_clk = pix_clk;
2310                         break;
2311                 case COLOR_DEPTH_101010:
2312                         normalized_pix_clk = (pix_clk * 30) / 24;
2313                         break;
2314                 case COLOR_DEPTH_121212:
2315                         normalized_pix_clk = (pix_clk * 36) / 24;
2316                 break;
2317                 case COLOR_DEPTH_161616:
2318                         normalized_pix_clk = (pix_clk * 48) / 24;
2319                 break;
2320                 default:
2321                         ASSERT(0);
2322                 break;
2323                 }
2324         }
2325         return normalized_pix_clk;
2326 }
2327
2328 static void calculate_phy_pix_clks(struct dc_stream_state *stream)
2329 {
2330         /* update actual pixel clock on all streams */
2331         if (dc_is_hdmi_signal(stream->signal))
2332                 stream->phy_pix_clk = get_norm_pix_clk(
2333                         &stream->timing) / 10;
2334         else
2335                 stream->phy_pix_clk =
2336                         stream->timing.pix_clk_100hz / 10;
2337
2338         if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
2339                 stream->phy_pix_clk *= 2;
2340 }
2341
2342 static int acquire_resource_from_hw_enabled_state(
2343                 struct resource_context *res_ctx,
2344                 const struct resource_pool *pool,
2345                 struct dc_stream_state *stream)
2346 {
2347         struct dc_link *link = stream->link;
2348         unsigned int i, inst, tg_inst = 0;
2349         uint32_t numPipes = 1;
2350         uint32_t id_src[4] = {0};
2351
2352         /* Check for enabled DIG to identify enabled display */
2353         if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
2354                 return -1;
2355
2356         inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
2357
2358         if (inst == ENGINE_ID_UNKNOWN)
2359                 return -1;
2360
2361         for (i = 0; i < pool->stream_enc_count; i++) {
2362                 if (pool->stream_enc[i]->id == inst) {
2363                         tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
2364                                 pool->stream_enc[i]);
2365                         break;
2366                 }
2367         }
2368
2369         // tg_inst not found
2370         if (i == pool->stream_enc_count)
2371                 return -1;
2372
2373         if (tg_inst >= pool->timing_generator_count)
2374                 return -1;
2375
2376         if (!res_ctx->pipe_ctx[tg_inst].stream) {
2377                 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
2378
2379                 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
2380                 id_src[0] = tg_inst;
2381
2382                 if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
2383                         pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
2384                                                 &numPipes, &id_src[0], &id_src[1]);
2385
2386                 if (id_src[0] == 0xf && id_src[1] == 0xf) {
2387                         id_src[0] = tg_inst;
2388                         numPipes = 1;
2389                 }
2390
2391                 for (i = 0; i < numPipes; i++) {
2392                         //Check if src id invalid
2393                         if (id_src[i] == 0xf)
2394                                 return -1;
2395
2396                         pipe_ctx = &res_ctx->pipe_ctx[id_src[i]];
2397
2398                         pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
2399                         pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
2400                         pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
2401                         pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
2402                         pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
2403                         pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
2404                         pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
2405
2406                         if (pool->dpps[id_src[i]]) {
2407                                 pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;
2408
2409                                 if (pool->mpc->funcs->read_mpcc_state) {
2410                                         struct mpcc_state s = {0};
2411
2412                                         pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
2413
2414                                         if (s.dpp_id < MAX_MPCC)
2415                                                 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
2416                                                                 s.dpp_id;
2417
2418                                         if (s.bot_mpcc_id < MAX_MPCC)
2419                                                 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
2420                                                                 &pool->mpc->mpcc_array[s.bot_mpcc_id];
2421
2422                                         if (s.opp_id < MAX_OPP)
2423                                                 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
2424                                 }
2425                         }
2426                         pipe_ctx->pipe_idx = id_src[i];
2427
2428                         if (id_src[i] >= pool->timing_generator_count) {
2429                                 id_src[i] = pool->timing_generator_count - 1;
2430
2431                                 pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
2432                                 pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
2433                         }
2434
2435                         pipe_ctx->stream = stream;
2436                 }
2437
2438                 if (numPipes == 2) {
2439                         stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
2440                         res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
2441                         res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
2442                         res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
2443                         res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
2444                 } else
2445                         stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
2446
2447                 return id_src[0];
2448         }
2449
2450         return -1;
2451 }
2452
2453 static void mark_seamless_boot_stream(
2454                 const struct dc  *dc,
2455                 struct dc_stream_state *stream)
2456 {
2457         struct dc_bios *dcb = dc->ctx->dc_bios;
2458
2459         if (dc->config.allow_seamless_boot_optimization &&
2460                         !dcb->funcs->is_accelerated_mode(dcb)) {
2461                 if (dc_validate_boot_timing(dc, stream->sink, &stream->timing))
2462                         stream->apply_seamless_boot_optimization = true;
2463         }
2464 }
2465
2466 enum dc_status resource_map_pool_resources(
2467                 const struct dc  *dc,
2468                 struct dc_state *context,
2469                 struct dc_stream_state *stream)
2470 {
2471         const struct resource_pool *pool = dc->res_pool;
2472         int i;
2473         struct dc_context *dc_ctx = dc->ctx;
2474         struct pipe_ctx *pipe_ctx = NULL;
2475         int pipe_idx = -1;
2476
2477         calculate_phy_pix_clks(stream);
2478
2479         mark_seamless_boot_stream(dc, stream);
2480
2481         if (stream->apply_seamless_boot_optimization) {
2482                 pipe_idx = acquire_resource_from_hw_enabled_state(
2483                                 &context->res_ctx,
2484                                 pool,
2485                                 stream);
2486                 if (pipe_idx < 0)
2487                         /* hw resource was assigned to other stream */
2488                         stream->apply_seamless_boot_optimization = false;
2489         }
2490
2491         if (pipe_idx < 0)
2492                 /* acquire new resources */
2493                 pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
2494
2495         if (pipe_idx < 0)
2496                 pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
2497
2498         if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL)
2499                 return DC_NO_CONTROLLER_RESOURCE;
2500
2501         pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
2502
2503         pipe_ctx->stream_res.stream_enc =
2504                 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
2505                         &context->res_ctx, pool, stream);
2506
2507         if (!pipe_ctx->stream_res.stream_enc)
2508                 return DC_NO_STREAM_ENC_RESOURCE;
2509
2510         update_stream_engine_usage(
2511                 &context->res_ctx, pool,
2512                 pipe_ctx->stream_res.stream_enc,
2513                 true);
2514
2515         /* Allocate DP HPO Stream Encoder based on signal, hw capabilities
2516          * and link settings
2517          */
2518         if (dc_is_dp_signal(stream->signal)) {
2519                 if (!dc->link_srv->dp_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings))
2520                         return DC_FAIL_DP_LINK_BANDWIDTH;
2521                 if (dc->link_srv->dp_get_encoding_format(
2522                                 &pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
2523                         pipe_ctx->stream_res.hpo_dp_stream_enc =
2524                                         find_first_free_match_hpo_dp_stream_enc_for_link(
2525                                                         &context->res_ctx, pool, stream);
2526
2527                         if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
2528                                 return DC_NO_STREAM_ENC_RESOURCE;
2529
2530                         update_hpo_dp_stream_engine_usage(
2531                                         &context->res_ctx, pool,
2532                                         pipe_ctx->stream_res.hpo_dp_stream_enc,
2533                                         true);
2534                         if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
2535                                 return DC_NO_LINK_ENC_RESOURCE;
2536                 }
2537         }
2538
2539         /* TODO: Add check if ASIC support and EDID audio */
2540         if (!stream->converter_disable_audio &&
2541             dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
2542             stream->audio_info.mode_count && stream->audio_info.flags.all) {
2543                 pipe_ctx->stream_res.audio = find_first_free_audio(
2544                 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
2545
2546                 /*
2547                  * Audio assigned in order first come first get.
2548                  * There are asics which has number of audio
2549                  * resources less then number of pipes
2550                  */
2551                 if (pipe_ctx->stream_res.audio)
2552                         update_audio_usage(&context->res_ctx, pool,
2553                                            pipe_ctx->stream_res.audio, true);
2554         }
2555
2556         /* Add ABM to the resource if on EDP */
2557         if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
2558                 if (pool->abm)
2559                         pipe_ctx->stream_res.abm = pool->abm;
2560                 else
2561                         pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
2562         }
2563
2564         for (i = 0; i < context->stream_count; i++)
2565                 if (context->streams[i] == stream) {
2566                         context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
2567                         context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
2568                         context->stream_status[i].audio_inst =
2569                                 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
2570
2571                         return DC_OK;
2572                 }
2573
2574         DC_ERROR("Stream %p not found in new ctx!\n", stream);
2575         return DC_ERROR_UNEXPECTED;
2576 }
2577
2578 /**
2579  * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
2580  *
2581  * @dc: copy out of dc->current_state
2582  * @dst_ctx: copy into this
2583  *
2584  * This function makes a shallow copy of the current DC state and increments
2585  * refcounts on existing streams and planes.
2586  */
2587 void dc_resource_state_copy_construct_current(
2588                 const struct dc *dc,
2589                 struct dc_state *dst_ctx)
2590 {
2591         dc_resource_state_copy_construct(dc->current_state, dst_ctx);
2592 }
2593
2594
2595 void dc_resource_state_construct(
2596                 const struct dc *dc,
2597                 struct dc_state *dst_ctx)
2598 {
2599         dst_ctx->clk_mgr = dc->clk_mgr;
2600
2601         /* Initialise DIG link encoder resource tracking variables. */
2602         link_enc_cfg_init(dc, dst_ctx);
2603 }
2604
2605
2606 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
2607 {
2608         if (dc->res_pool == NULL)
2609                 return false;
2610
2611         return dc->res_pool->res_cap->num_dsc > 0;
2612 }
2613
2614 static bool planes_changed_for_existing_stream(struct dc_state *context,
2615                                                struct dc_stream_state *stream,
2616                                                const struct dc_validation_set set[],
2617                                                int set_count)
2618 {
2619         int i, j;
2620         struct dc_stream_status *stream_status = NULL;
2621
2622         for (i = 0; i < context->stream_count; i++) {
2623                 if (context->streams[i] == stream) {
2624                         stream_status = &context->stream_status[i];
2625                         break;
2626                 }
2627         }
2628
2629         if (!stream_status)
2630                 ASSERT(0);
2631
2632         for (i = 0; i < set_count; i++)
2633                 if (set[i].stream == stream)
2634                         break;
2635
2636         if (i == set_count)
2637                 ASSERT(0);
2638
2639         if (set[i].plane_count != stream_status->plane_count)
2640                 return true;
2641
2642         for (j = 0; j < set[i].plane_count; j++)
2643                 if (set[i].plane_states[j] != stream_status->plane_states[j])
2644                         return true;
2645
2646         return false;
2647 }
2648
2649 /**
2650  * dc_validate_with_context - Validate and update the potential new stream in the context object
2651  *
2652  * @dc: Used to get the current state status
2653  * @set: An array of dc_validation_set with all the current streams reference
2654  * @set_count: Total of streams
2655  * @context: New context
2656  * @fast_validate: Enable or disable fast validation
2657  *
2658  * This function updates the potential new stream in the context object. It
2659  * creates multiple lists for the add, remove, and unchanged streams. In
2660  * particular, if the unchanged streams have a plane that changed, it is
2661  * necessary to remove all planes from the unchanged streams. In summary, this
2662  * function is responsible for validating the new context.
2663  *
2664  * Return:
2665  * In case of success, return DC_OK (1), otherwise, return a DC error.
2666  */
2667 enum dc_status dc_validate_with_context(struct dc *dc,
2668                                         const struct dc_validation_set set[],
2669                                         int set_count,
2670                                         struct dc_state *context,
2671                                         bool fast_validate)
2672 {
2673         struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
2674         struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
2675         struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
2676         int old_stream_count = context->stream_count;
2677         enum dc_status res = DC_ERROR_UNEXPECTED;
2678         int unchanged_streams_count = 0;
2679         int del_streams_count = 0;
2680         int add_streams_count = 0;
2681         bool found = false;
2682         int i, j, k;
2683
2684         DC_LOGGER_INIT(dc->ctx->logger);
2685
2686         /* First build a list of streams to be remove from current context */
2687         for (i = 0; i < old_stream_count; i++) {
2688                 struct dc_stream_state *stream = context->streams[i];
2689
2690                 for (j = 0; j < set_count; j++) {
2691                         if (stream == set[j].stream) {
2692                                 found = true;
2693                                 break;
2694                         }
2695                 }
2696
2697                 if (!found)
2698                         del_streams[del_streams_count++] = stream;
2699
2700                 found = false;
2701         }
2702
2703         /* Second, build a list of new streams */
2704         for (i = 0; i < set_count; i++) {
2705                 struct dc_stream_state *stream = set[i].stream;
2706
2707                 for (j = 0; j < old_stream_count; j++) {
2708                         if (stream == context->streams[j]) {
2709                                 found = true;
2710                                 break;
2711                         }
2712                 }
2713
2714                 if (!found)
2715                         add_streams[add_streams_count++] = stream;
2716
2717                 found = false;
2718         }
2719
2720         /* Build a list of unchanged streams which is necessary for handling
2721          * planes change such as added, removed, and updated.
2722          */
2723         for (i = 0; i < set_count; i++) {
2724                 /* Check if stream is part of the delete list */
2725                 for (j = 0; j < del_streams_count; j++) {
2726                         if (set[i].stream == del_streams[j]) {
2727                                 found = true;
2728                                 break;
2729                         }
2730                 }
2731
2732                 if (!found) {
2733                         /* Check if stream is part of the add list */
2734                         for (j = 0; j < add_streams_count; j++) {
2735                                 if (set[i].stream == add_streams[j]) {
2736                                         found = true;
2737                                         break;
2738                                 }
2739                         }
2740                 }
2741
2742                 if (!found)
2743                         unchanged_streams[unchanged_streams_count++] = set[i].stream;
2744
2745                 found = false;
2746         }
2747
2748         /* Remove all planes for unchanged streams if planes changed */
2749         for (i = 0; i < unchanged_streams_count; i++) {
2750                 if (planes_changed_for_existing_stream(context,
2751                                                        unchanged_streams[i],
2752                                                        set,
2753                                                        set_count)) {
2754                         if (!dc_rem_all_planes_for_stream(dc,
2755                                                           unchanged_streams[i],
2756                                                           context)) {
2757                                 res = DC_FAIL_DETACH_SURFACES;
2758                                 goto fail;
2759                         }
2760                 }
2761         }
2762
2763         /* Remove all planes for removed streams and then remove the streams */
2764         for (i = 0; i < del_streams_count; i++) {
2765                 /* Need to cpy the dwb data from the old stream in order to efc to work */
2766                 if (del_streams[i]->num_wb_info > 0) {
2767                         for (j = 0; j < add_streams_count; j++) {
2768                                 if (del_streams[i]->sink == add_streams[j]->sink) {
2769                                         add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
2770                                         for (k = 0; k < del_streams[i]->num_wb_info; k++)
2771                                                 add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
2772                                 }
2773                         }
2774                 }
2775
2776                 if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) {
2777                         res = DC_FAIL_DETACH_SURFACES;
2778                         goto fail;
2779                 }
2780
2781                 res = dc_remove_stream_from_ctx(dc, context, del_streams[i]);
2782                 if (res != DC_OK)
2783                         goto fail;
2784         }
2785
2786         /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx
2787          * matches. This may change in the future if seamless_boot_stream can be
2788          * multiple.
2789          */
2790         for (i = 0; i < add_streams_count; i++) {
2791                 mark_seamless_boot_stream(dc, add_streams[i]);
2792                 if (add_streams[i]->apply_seamless_boot_optimization && i != 0) {
2793                         struct dc_stream_state *temp = add_streams[0];
2794
2795                         add_streams[0] = add_streams[i];
2796                         add_streams[i] = temp;
2797                         break;
2798                 }
2799         }
2800
2801         /* Add new streams and then add all planes for the new stream */
2802         for (i = 0; i < add_streams_count; i++) {
2803                 calculate_phy_pix_clks(add_streams[i]);
2804                 res = dc_add_stream_to_ctx(dc, context, add_streams[i]);
2805                 if (res != DC_OK)
2806                         goto fail;
2807
2808                 if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
2809                         res = DC_FAIL_ATTACH_SURFACES;
2810                         goto fail;
2811                 }
2812         }
2813
2814         /* Add all planes for unchanged streams if planes changed */
2815         for (i = 0; i < unchanged_streams_count; i++) {
2816                 if (planes_changed_for_existing_stream(context,
2817                                                        unchanged_streams[i],
2818                                                        set,
2819                                                        set_count)) {
2820                         if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
2821                                 res = DC_FAIL_ATTACH_SURFACES;
2822                                 goto fail;
2823                         }
2824                 }
2825         }
2826
2827         res = dc_validate_global_state(dc, context, fast_validate);
2828
2829 fail:
2830         if (res != DC_OK)
2831                 DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
2832                                __func__,
2833                                res);
2834
2835         return res;
2836 }
2837
2838 /**
2839  * dc_validate_global_state() - Determine if hardware can support a given state
2840  *
2841  * @dc: dc struct for this driver
2842  * @new_ctx: state to be validated
2843  * @fast_validate: set to true if only yes/no to support matters
2844  *
2845  * Checks hardware resource availability and bandwidth requirement.
2846  *
2847  * Return:
2848  * DC_OK if the result can be programmed. Otherwise, an error code.
2849  */
2850 enum dc_status dc_validate_global_state(
2851                 struct dc *dc,
2852                 struct dc_state *new_ctx,
2853                 bool fast_validate)
2854 {
2855         enum dc_status result = DC_ERROR_UNEXPECTED;
2856         int i, j;
2857
2858         if (!new_ctx)
2859                 return DC_ERROR_UNEXPECTED;
2860
2861         if (dc->res_pool->funcs->validate_global) {
2862                 result = dc->res_pool->funcs->validate_global(dc, new_ctx);
2863                 if (result != DC_OK)
2864                         return result;
2865         }
2866
2867         for (i = 0; i < new_ctx->stream_count; i++) {
2868                 struct dc_stream_state *stream = new_ctx->streams[i];
2869
2870                 for (j = 0; j < dc->res_pool->pipe_count; j++) {
2871                         struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
2872
2873                         if (pipe_ctx->stream != stream)
2874                                 continue;
2875
2876                         if (dc->res_pool->funcs->patch_unknown_plane_state &&
2877                                         pipe_ctx->plane_state &&
2878                                         pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
2879                                 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
2880                                 if (result != DC_OK)
2881                                         return result;
2882                         }
2883
2884                         /* Switch to dp clock source only if there is
2885                          * no non dp stream that shares the same timing
2886                          * with the dp stream.
2887                          */
2888                         if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
2889                                 !find_pll_sharable_stream(stream, new_ctx)) {
2890
2891                                 resource_unreference_clock_source(
2892                                                 &new_ctx->res_ctx,
2893                                                 dc->res_pool,
2894                                                 pipe_ctx->clock_source);
2895
2896                                 pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
2897                                 resource_reference_clock_source(
2898                                                 &new_ctx->res_ctx,
2899                                                 dc->res_pool,
2900                                                  pipe_ctx->clock_source);
2901                         }
2902                 }
2903         }
2904
2905         result = resource_build_scaling_params_for_context(dc, new_ctx);
2906
2907         if (result == DC_OK)
2908                 if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
2909                         result = DC_FAIL_BANDWIDTH_VALIDATE;
2910
2911         /*
2912          * Only update link encoder to stream assignment after bandwidth validation passed.
2913          * TODO: Split out assignment and validation.
2914          */
2915         if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false)
2916                 dc->res_pool->funcs->link_encs_assign(
2917                         dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
2918
2919         return result;
2920 }
2921
2922 static void patch_gamut_packet_checksum(
2923                 struct dc_info_packet *gamut_packet)
2924 {
2925         /* For gamut we recalc checksum */
2926         if (gamut_packet->valid) {
2927                 uint8_t chk_sum = 0;
2928                 uint8_t *ptr;
2929                 uint8_t i;
2930
2931                 /*start of the Gamut data. */
2932                 ptr = &gamut_packet->sb[3];
2933
2934                 for (i = 0; i <= gamut_packet->sb[1]; i++)
2935                         chk_sum += ptr[i];
2936
2937                 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
2938         }
2939 }
2940
2941 static void set_avi_info_frame(
2942                 struct dc_info_packet *info_packet,
2943                 struct pipe_ctx *pipe_ctx)
2944 {
2945         struct dc_stream_state *stream = pipe_ctx->stream;
2946         enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
2947         uint32_t pixel_encoding = 0;
2948         enum scanning_type scan_type = SCANNING_TYPE_NODATA;
2949         enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
2950         bool itc = false;
2951         uint8_t itc_value = 0;
2952         uint8_t cn0_cn1 = 0;
2953         unsigned int cn0_cn1_value = 0;
2954         uint8_t *check_sum = NULL;
2955         uint8_t byte_index = 0;
2956         union hdmi_info_packet hdmi_info;
2957         union display_content_support support = {0};
2958         unsigned int vic = pipe_ctx->stream->timing.vic;
2959         unsigned int rid = pipe_ctx->stream->timing.rid;
2960         unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
2961         enum dc_timing_3d_format format;
2962
2963         memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
2964
2965         color_space = pipe_ctx->stream->output_color_space;
2966         if (color_space == COLOR_SPACE_UNKNOWN)
2967                 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
2968                         COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
2969
2970         /* Initialize header */
2971         hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
2972         /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
2973         * not be used in HDMI 2.0 (Section 10.1) */
2974         hdmi_info.bits.header.version = 2;
2975         hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
2976
2977         /*
2978          * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
2979          * according to HDMI 2.0 spec (Section 10.1)
2980          */
2981
2982         switch (stream->timing.pixel_encoding) {
2983         case PIXEL_ENCODING_YCBCR422:
2984                 pixel_encoding = 1;
2985                 break;
2986
2987         case PIXEL_ENCODING_YCBCR444:
2988                 pixel_encoding = 2;
2989                 break;
2990         case PIXEL_ENCODING_YCBCR420:
2991                 pixel_encoding = 3;
2992                 break;
2993
2994         case PIXEL_ENCODING_RGB:
2995         default:
2996                 pixel_encoding = 0;
2997         }
2998
2999         /* Y0_Y1_Y2 : The pixel encoding */
3000         /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
3001         hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding;
3002
3003         /* A0 = 1 Active Format Information valid */
3004         hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
3005
3006         /* B0, B1 = 3; Bar info data is valid */
3007         hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
3008
3009         hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
3010
3011         /* S0, S1 : Underscan / Overscan */
3012         /* TODO: un-hardcode scan type */
3013         scan_type = SCANNING_TYPE_UNDERSCAN;
3014         hdmi_info.bits.S0_S1 = scan_type;
3015
3016         /* C0, C1 : Colorimetry */
3017         if (color_space == COLOR_SPACE_YCBCR709 ||
3018                         color_space == COLOR_SPACE_YCBCR709_LIMITED)
3019                 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
3020         else if (color_space == COLOR_SPACE_YCBCR601 ||
3021                         color_space == COLOR_SPACE_YCBCR601_LIMITED)
3022                 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
3023         else {
3024                 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
3025         }
3026         if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE ||
3027                         color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE ||
3028                         color_space == COLOR_SPACE_2020_YCBCR) {
3029                 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
3030                 hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
3031         } else if (color_space == COLOR_SPACE_ADOBERGB) {
3032                 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
3033                 hdmi_info.bits.C0_C1   = COLORIMETRY_EXTENDED;
3034         }
3035
3036         if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR &&
3037                         stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) {
3038                 hdmi_info.bits.EC0_EC2 = 0;
3039                 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
3040         }
3041
3042         /* TODO: un-hardcode aspect ratio */
3043         aspect = stream->timing.aspect_ratio;
3044
3045         switch (aspect) {
3046         case ASPECT_RATIO_4_3:
3047         case ASPECT_RATIO_16_9:
3048                 hdmi_info.bits.M0_M1 = aspect;
3049                 break;
3050
3051         case ASPECT_RATIO_NO_DATA:
3052         case ASPECT_RATIO_64_27:
3053         case ASPECT_RATIO_256_135:
3054         default:
3055                 hdmi_info.bits.M0_M1 = 0;
3056         }
3057
3058         /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
3059         hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
3060
3061         /* TODO: un-hardcode cn0_cn1 and itc */
3062
3063         cn0_cn1 = 0;
3064         cn0_cn1_value = 0;
3065
3066         itc = true;
3067         itc_value = 1;
3068
3069         support = stream->content_support;
3070
3071         if (itc) {
3072                 if (!support.bits.valid_content_type) {
3073                         cn0_cn1_value = 0;
3074                 } else {
3075                         if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) {
3076                                 if (support.bits.graphics_content == 1) {
3077                                         cn0_cn1_value = 0;
3078                                 }
3079                         } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) {
3080                                 if (support.bits.photo_content == 1) {
3081                                         cn0_cn1_value = 1;
3082                                 } else {
3083                                         cn0_cn1_value = 0;
3084                                         itc_value = 0;
3085                                 }
3086                         } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) {
3087                                 if (support.bits.cinema_content == 1) {
3088                                         cn0_cn1_value = 2;
3089                                 } else {
3090                                         cn0_cn1_value = 0;
3091                                         itc_value = 0;
3092                                 }
3093                         } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) {
3094                                 if (support.bits.game_content == 1) {
3095                                         cn0_cn1_value = 3;
3096                                 } else {
3097                                         cn0_cn1_value = 0;
3098                                         itc_value = 0;
3099                                 }
3100                         }
3101                 }
3102                 hdmi_info.bits.CN0_CN1 = cn0_cn1_value;
3103                 hdmi_info.bits.ITC = itc_value;
3104         }
3105
3106         if (stream->qs_bit == 1) {
3107                 if (color_space == COLOR_SPACE_SRGB ||
3108                         color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
3109                         hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_FULL_RANGE;
3110                 else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
3111                                         color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
3112                         hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_LIMITED_RANGE;
3113                 else
3114                         hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
3115         } else
3116                 hdmi_info.bits.Q0_Q1   = RGB_QUANTIZATION_DEFAULT_RANGE;
3117
3118         /* TODO : We should handle YCC quantization */
3119         /* but we do not have matrix calculation */
3120         hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
3121
3122         ///VIC
3123         if (pipe_ctx->stream->timing.hdmi_vic != 0)
3124                 vic = 0;
3125         format = stream->timing.timing_3d_format;
3126         /*todo, add 3DStereo support*/
3127         if (format != TIMING_3D_FORMAT_NONE) {
3128                 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
3129                 switch (pipe_ctx->stream->timing.hdmi_vic) {
3130                 case 1:
3131                         vic = 95;
3132                         break;
3133                 case 2:
3134                         vic = 94;
3135                         break;
3136                 case 3:
3137                         vic = 93;
3138                         break;
3139                 case 4:
3140                         vic = 98;
3141                         break;
3142                 default:
3143                         break;
3144                 }
3145         }
3146         /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
3147         hdmi_info.bits.VIC0_VIC7 = vic;
3148         if (vic >= 128)
3149                 hdmi_info.bits.header.version = 3;
3150         /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
3151          * the Source shall use 20 AVI InfoFrame Version 4
3152          */
3153         if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
3154                         hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
3155                 hdmi_info.bits.header.version = 4;
3156                 hdmi_info.bits.header.length = 14;
3157         }
3158
3159         if (rid != 0 && fr_ind != 0) {
3160                 hdmi_info.bits.header.version = 5;
3161                 hdmi_info.bits.header.length = 15;
3162
3163                 hdmi_info.bits.FR0_FR3 = fr_ind & 0xF;
3164                 hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1;
3165                 hdmi_info.bits.RID0_RID5 = rid;
3166         }
3167
3168         /* pixel repetition
3169          * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
3170          * repetition start from 1 */
3171         hdmi_info.bits.PR0_PR3 = 0;
3172
3173         /* Bar Info
3174          * barTop:    Line Number of End of Top Bar.
3175          * barBottom: Line Number of Start of Bottom Bar.
3176          * barLeft:   Pixel Number of End of Left Bar.
3177          * barRight:  Pixel Number of Start of Right Bar. */
3178         hdmi_info.bits.bar_top = stream->timing.v_border_top;
3179         hdmi_info.bits.bar_bottom = (stream->timing.v_total
3180                         - stream->timing.v_border_bottom + 1);
3181         hdmi_info.bits.bar_left  = stream->timing.h_border_left;
3182         hdmi_info.bits.bar_right = (stream->timing.h_total
3183                         - stream->timing.h_border_right + 1);
3184
3185     /* Additional Colorimetry Extension
3186      * Used in conduction with C0-C1 and EC0-EC2
3187      * 0 = DCI-P3 RGB (D65)
3188      * 1 = DCI-P3 RGB (theater)
3189      */
3190         hdmi_info.bits.ACE0_ACE3 = 0;
3191
3192         /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
3193         check_sum = &hdmi_info.packet_raw_data.sb[0];
3194
3195         *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
3196
3197         for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
3198                 *check_sum += hdmi_info.packet_raw_data.sb[byte_index];
3199
3200         /* one byte complement */
3201         *check_sum = (uint8_t) (0x100 - *check_sum);
3202
3203         /* Store in hw_path_mode */
3204         info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
3205         info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
3206         info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
3207
3208         for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
3209                 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
3210
3211         info_packet->valid = true;
3212 }
3213
3214 static void set_vendor_info_packet(
3215                 struct dc_info_packet *info_packet,
3216                 struct dc_stream_state *stream)
3217 {
3218         /* SPD info packet for FreeSync */
3219
3220         /* Check if Freesync is supported. Return if false. If true,
3221          * set the corresponding bit in the info packet
3222          */
3223         if (!stream->vsp_infopacket.valid)
3224                 return;
3225
3226         *info_packet = stream->vsp_infopacket;
3227 }
3228
3229 static void set_spd_info_packet(
3230                 struct dc_info_packet *info_packet,
3231                 struct dc_stream_state *stream)
3232 {
3233         /* SPD info packet for FreeSync */
3234
3235         /* Check if Freesync is supported. Return if false. If true,
3236          * set the corresponding bit in the info packet
3237          */
3238         if (!stream->vrr_infopacket.valid)
3239                 return;
3240
3241         *info_packet = stream->vrr_infopacket;
3242 }
3243
3244 static void set_hdr_static_info_packet(
3245                 struct dc_info_packet *info_packet,
3246                 struct dc_stream_state *stream)
3247 {
3248         /* HDR Static Metadata info packet for HDR10 */
3249
3250         if (!stream->hdr_static_metadata.valid ||
3251                         stream->use_dynamic_meta)
3252                 return;
3253
3254         *info_packet = stream->hdr_static_metadata;
3255 }
3256
3257 static void set_vsc_info_packet(
3258                 struct dc_info_packet *info_packet,
3259                 struct dc_stream_state *stream)
3260 {
3261         if (!stream->vsc_infopacket.valid)
3262                 return;
3263
3264         *info_packet = stream->vsc_infopacket;
3265 }
3266 static void set_hfvs_info_packet(
3267                 struct dc_info_packet *info_packet,
3268                 struct dc_stream_state *stream)
3269 {
3270         if (!stream->hfvsif_infopacket.valid)
3271                 return;
3272
3273         *info_packet = stream->hfvsif_infopacket;
3274 }
3275
3276 static void adaptive_sync_override_dp_info_packets_sdp_line_num(
3277                 const struct dc_crtc_timing *timing,
3278                 struct enc_sdp_line_num *sdp_line_num,
3279                 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
3280 {
3281         uint32_t asic_blank_start = 0;
3282         uint32_t asic_blank_end   = 0;
3283         uint32_t v_update = 0;
3284
3285         const struct dc_crtc_timing *tg = timing;
3286
3287         /* blank_start = frame end - front porch */
3288         asic_blank_start = tg->v_total - tg->v_front_porch;
3289
3290         /* blank_end = blank_start - active */
3291         asic_blank_end = (asic_blank_start - tg->v_border_bottom -
3292                                                 tg->v_addressable - tg->v_border_top);
3293
3294         if (pipe_dlg_param->vstartup_start > asic_blank_end) {
3295                 v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end));
3296                 sdp_line_num->adaptive_sync_line_num_valid = true;
3297                 sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
3298         } else {
3299                 sdp_line_num->adaptive_sync_line_num_valid = false;
3300                 sdp_line_num->adaptive_sync_line_num = 0;
3301         }
3302 }
3303
3304 static void set_adaptive_sync_info_packet(
3305                 struct dc_info_packet *info_packet,
3306                 const struct dc_stream_state *stream,
3307                 struct encoder_info_frame *info_frame,
3308                 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
3309 {
3310         if (!stream->adaptive_sync_infopacket.valid)
3311                 return;
3312
3313         adaptive_sync_override_dp_info_packets_sdp_line_num(
3314                         &stream->timing,
3315                         &info_frame->sdp_line_num,
3316                         pipe_dlg_param);
3317
3318         *info_packet = stream->adaptive_sync_infopacket;
3319 }
3320
3321 static void set_vtem_info_packet(
3322                 struct dc_info_packet *info_packet,
3323                 struct dc_stream_state *stream)
3324 {
3325         if (!stream->vtem_infopacket.valid)
3326                 return;
3327
3328         *info_packet = stream->vtem_infopacket;
3329 }
3330
3331 void dc_resource_state_destruct(struct dc_state *context)
3332 {
3333         int i, j;
3334
3335         for (i = 0; i < context->stream_count; i++) {
3336                 for (j = 0; j < context->stream_status[i].plane_count; j++)
3337                         dc_plane_state_release(
3338                                 context->stream_status[i].plane_states[j]);
3339
3340                 context->stream_status[i].plane_count = 0;
3341                 dc_stream_release(context->streams[i]);
3342                 context->streams[i] = NULL;
3343         }
3344         context->stream_count = 0;
3345 }
3346
3347 void dc_resource_state_copy_construct(
3348                 const struct dc_state *src_ctx,
3349                 struct dc_state *dst_ctx)
3350 {
3351         int i, j;
3352         struct kref refcount = dst_ctx->refcount;
3353
3354         *dst_ctx = *src_ctx;
3355
3356         for (i = 0; i < MAX_PIPES; i++) {
3357                 struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i];
3358
3359                 if (cur_pipe->top_pipe)
3360                         cur_pipe->top_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
3361
3362                 if (cur_pipe->bottom_pipe)
3363                         cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
3364
3365                 if (cur_pipe->next_odm_pipe)
3366                         cur_pipe->next_odm_pipe =  &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
3367
3368                 if (cur_pipe->prev_odm_pipe)
3369                         cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
3370         }
3371
3372         for (i = 0; i < dst_ctx->stream_count; i++) {
3373                 dc_stream_retain(dst_ctx->streams[i]);
3374                 for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++)
3375                         dc_plane_state_retain(
3376                                 dst_ctx->stream_status[i].plane_states[j]);
3377         }
3378
3379         /* context refcount should not be overridden */
3380         dst_ctx->refcount = refcount;
3381
3382 }
3383
3384 struct clock_source *dc_resource_find_first_free_pll(
3385                 struct resource_context *res_ctx,
3386                 const struct resource_pool *pool)
3387 {
3388         int i;
3389
3390         for (i = 0; i < pool->clk_src_count; ++i) {
3391                 if (res_ctx->clock_source_ref_count[i] == 0)
3392                         return pool->clock_sources[i];
3393         }
3394
3395         return NULL;
3396 }
3397
3398 void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
3399 {
3400         enum signal_type signal = SIGNAL_TYPE_NONE;
3401         struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
3402
3403         /* default all packets to invalid */
3404         info->avi.valid = false;
3405         info->gamut.valid = false;
3406         info->vendor.valid = false;
3407         info->spd.valid = false;
3408         info->hdrsmd.valid = false;
3409         info->vsc.valid = false;
3410         info->hfvsif.valid = false;
3411         info->vtem.valid = false;
3412         info->adaptive_sync.valid = false;
3413         signal = pipe_ctx->stream->signal;
3414
3415         /* HDMi and DP have different info packets*/
3416         if (dc_is_hdmi_signal(signal)) {
3417                 set_avi_info_frame(&info->avi, pipe_ctx);
3418
3419                 set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
3420                 set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream);
3421                 set_vtem_info_packet(&info->vtem, pipe_ctx->stream);
3422
3423                 set_spd_info_packet(&info->spd, pipe_ctx->stream);
3424
3425                 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
3426
3427         } else if (dc_is_dp_signal(signal)) {
3428                 set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
3429
3430                 set_spd_info_packet(&info->spd, pipe_ctx->stream);
3431
3432                 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
3433                 set_adaptive_sync_info_packet(&info->adaptive_sync,
3434                                                                                 pipe_ctx->stream,
3435                                                                                 info,
3436                                                                                 &pipe_ctx->pipe_dlg_param);
3437         }
3438
3439         patch_gamut_packet_checksum(&info->gamut);
3440 }
3441
3442 enum dc_status resource_map_clock_resources(
3443                 const struct dc  *dc,
3444                 struct dc_state *context,
3445                 struct dc_stream_state *stream)
3446 {
3447         /* acquire new resources */
3448         const struct resource_pool *pool = dc->res_pool;
3449         struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
3450                                 &context->res_ctx, stream);
3451
3452         if (!pipe_ctx)
3453                 return DC_ERROR_UNEXPECTED;
3454
3455         if (dc_is_dp_signal(pipe_ctx->stream->signal)
3456                 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
3457                 pipe_ctx->clock_source = pool->dp_clock_source;
3458         else {
3459                 pipe_ctx->clock_source = NULL;
3460
3461                 if (!dc->config.disable_disp_pll_sharing)
3462                         pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
3463                                 &context->res_ctx,
3464                                 pipe_ctx);
3465
3466                 if (pipe_ctx->clock_source == NULL)
3467                         pipe_ctx->clock_source =
3468                                 dc_resource_find_first_free_pll(
3469                                         &context->res_ctx,
3470                                         pool);
3471         }
3472
3473         if (pipe_ctx->clock_source == NULL)
3474                 return DC_NO_CLOCK_SOURCE_RESOURCE;
3475
3476         resource_reference_clock_source(
3477                 &context->res_ctx, pool,
3478                 pipe_ctx->clock_source);
3479
3480         return DC_OK;
3481 }
3482
3483 /*
3484  * Note: We need to disable output if clock sources change,
3485  * since bios does optimization and doesn't apply if changing
3486  * PHY when not already disabled.
3487  */
3488 bool pipe_need_reprogram(
3489                 struct pipe_ctx *pipe_ctx_old,
3490                 struct pipe_ctx *pipe_ctx)
3491 {
3492         if (!pipe_ctx_old->stream)
3493                 return false;
3494
3495         if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
3496                 return true;
3497
3498         if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
3499                 return true;
3500
3501         if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
3502                 return true;
3503
3504         if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
3505                         && pipe_ctx_old->stream != pipe_ctx->stream)
3506                 return true;
3507
3508         if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
3509                 return true;
3510
3511         if (is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
3512                 return true;
3513
3514         if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
3515                 return true;
3516
3517         if (false == pipe_ctx_old->stream->link->link_state_valid &&
3518                 false == pipe_ctx_old->stream->dpms_off)
3519                 return true;
3520
3521         if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
3522                 return true;
3523
3524         if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
3525                 return true;
3526         if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
3527                 return true;
3528
3529         /* DIG link encoder resource assignment for stream changed. */
3530         if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
3531                 bool need_reprogram = false;
3532                 struct dc *dc = pipe_ctx_old->stream->ctx->dc;
3533                 struct link_encoder *link_enc_prev =
3534                         link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream);
3535
3536                 if (link_enc_prev != pipe_ctx->stream->link_enc)
3537                         need_reprogram = true;
3538
3539                 return need_reprogram;
3540         }
3541
3542         return false;
3543 }
3544
3545 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
3546                 struct bit_depth_reduction_params *fmt_bit_depth)
3547 {
3548         enum dc_dither_option option = stream->dither_option;
3549         enum dc_pixel_encoding pixel_encoding =
3550                         stream->timing.pixel_encoding;
3551
3552         memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
3553
3554         if (option == DITHER_OPTION_DEFAULT) {
3555                 switch (stream->timing.display_color_depth) {
3556                 case COLOR_DEPTH_666:
3557                         option = DITHER_OPTION_SPATIAL6;
3558                         break;
3559                 case COLOR_DEPTH_888:
3560                         option = DITHER_OPTION_SPATIAL8;
3561                         break;
3562                 case COLOR_DEPTH_101010:
3563                         option = DITHER_OPTION_SPATIAL10;
3564                         break;
3565                 default:
3566                         option = DITHER_OPTION_DISABLE;
3567                 }
3568         }
3569
3570         if (option == DITHER_OPTION_DISABLE)
3571                 return;
3572
3573         if (option == DITHER_OPTION_TRUN6) {
3574                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3575                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
3576         } else if (option == DITHER_OPTION_TRUN8 ||
3577                         option == DITHER_OPTION_TRUN8_SPATIAL6 ||
3578                         option == DITHER_OPTION_TRUN8_FM6) {
3579                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3580                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
3581         } else if (option == DITHER_OPTION_TRUN10        ||
3582                         option == DITHER_OPTION_TRUN10_SPATIAL6   ||
3583                         option == DITHER_OPTION_TRUN10_SPATIAL8   ||
3584                         option == DITHER_OPTION_TRUN10_FM8     ||
3585                         option == DITHER_OPTION_TRUN10_FM6     ||
3586                         option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
3587                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3588                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
3589         }
3590
3591         /* special case - Formatter can only reduce by 4 bits at most.
3592          * When reducing from 12 to 6 bits,
3593          * HW recommends we use trunc with round mode
3594          * (if we did nothing, trunc to 10 bits would be used)
3595          * note that any 12->10 bit reduction is ignored prior to DCE8,
3596          * as the input was 10 bits.
3597          */
3598         if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
3599                         option == DITHER_OPTION_SPATIAL6 ||
3600                         option == DITHER_OPTION_FM6) {
3601                 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
3602                 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
3603                 fmt_bit_depth->flags.TRUNCATE_MODE = 1;
3604         }
3605
3606         /* spatial dither
3607          * note that spatial modes 1-3 are never used
3608          */
3609         if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM            ||
3610                         option == DITHER_OPTION_SPATIAL6 ||
3611                         option == DITHER_OPTION_TRUN10_SPATIAL6      ||
3612                         option == DITHER_OPTION_TRUN8_SPATIAL6) {
3613                 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
3614                 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
3615                 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
3616                 fmt_bit_depth->flags.RGB_RANDOM =
3617                                 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
3618         } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM            ||
3619                         option == DITHER_OPTION_SPATIAL8 ||
3620                         option == DITHER_OPTION_SPATIAL8_FM6        ||
3621                         option == DITHER_OPTION_TRUN10_SPATIAL8      ||
3622                         option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
3623                 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
3624                 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
3625                 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
3626                 fmt_bit_depth->flags.RGB_RANDOM =
3627                                 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
3628         } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
3629                         option == DITHER_OPTION_SPATIAL10 ||
3630                         option == DITHER_OPTION_SPATIAL10_FM8 ||
3631                         option == DITHER_OPTION_SPATIAL10_FM6) {
3632                 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
3633                 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
3634                 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
3635                 fmt_bit_depth->flags.RGB_RANDOM =
3636                                 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
3637         }
3638
3639         if (option == DITHER_OPTION_SPATIAL6 ||
3640                         option == DITHER_OPTION_SPATIAL8 ||
3641                         option == DITHER_OPTION_SPATIAL10) {
3642                 fmt_bit_depth->flags.FRAME_RANDOM = 0;
3643         } else {
3644                 fmt_bit_depth->flags.FRAME_RANDOM = 1;
3645         }
3646
3647         //////////////////////
3648         //// temporal dither
3649         //////////////////////
3650         if (option == DITHER_OPTION_FM6           ||
3651                         option == DITHER_OPTION_SPATIAL8_FM6     ||
3652                         option == DITHER_OPTION_SPATIAL10_FM6     ||
3653                         option == DITHER_OPTION_TRUN10_FM6     ||
3654                         option == DITHER_OPTION_TRUN8_FM6      ||
3655                         option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
3656                 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
3657                 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
3658         } else if (option == DITHER_OPTION_FM8        ||
3659                         option == DITHER_OPTION_SPATIAL10_FM8  ||
3660                         option == DITHER_OPTION_TRUN10_FM8) {
3661                 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
3662                 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
3663         } else if (option == DITHER_OPTION_FM10) {
3664                 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
3665                 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
3666         }
3667
3668         fmt_bit_depth->pixel_encoding = pixel_encoding;
3669 }
3670
3671 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
3672 {
3673         struct dc_link *link = stream->link;
3674         struct timing_generator *tg = dc->res_pool->timing_generators[0];
3675         enum dc_status res = DC_OK;
3676
3677         calculate_phy_pix_clks(stream);
3678
3679         if (!tg->funcs->validate_timing(tg, &stream->timing))
3680                 res = DC_FAIL_CONTROLLER_VALIDATE;
3681
3682         if (res == DC_OK) {
3683                 if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
3684                                 !link->link_enc->funcs->validate_output_with_stream(
3685                                                 link->link_enc, stream))
3686                         res = DC_FAIL_ENC_VALIDATE;
3687         }
3688
3689         /* TODO: validate audio ASIC caps, encoder */
3690
3691         if (res == DC_OK)
3692                 res = dc->link_srv->validate_mode_timing(stream,
3693                       link,
3694                       &stream->timing);
3695
3696         return res;
3697 }
3698
3699 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
3700 {
3701         enum dc_status res = DC_OK;
3702
3703         /* check if surface has invalid dimensions */
3704         if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 ||
3705                 plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0)
3706                 return DC_FAIL_SURFACE_VALIDATE;
3707
3708         /* TODO For now validates pixel format only */
3709         if (dc->res_pool->funcs->validate_plane)
3710                 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
3711
3712         return res;
3713 }
3714
3715 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
3716 {
3717         switch (format) {
3718         case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
3719                 return 8;
3720         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
3721         case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
3722                 return 12;
3723         case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
3724         case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
3725         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
3726         case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
3727                 return 16;
3728         case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
3729         case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
3730         case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
3731         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
3732         case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
3733         case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
3734         case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
3735                 return 32;
3736         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
3737         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
3738         case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
3739         case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
3740                 return 64;
3741         default:
3742                 ASSERT_CRITICAL(false);
3743                 return -1;
3744         }
3745 }
3746 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
3747 {
3748         if (modes) {
3749                 if (modes->sample_rates.rate.RATE_192)
3750                         return 192000;
3751                 if (modes->sample_rates.rate.RATE_176_4)
3752                         return 176400;
3753                 if (modes->sample_rates.rate.RATE_96)
3754                         return 96000;
3755                 if (modes->sample_rates.rate.RATE_88_2)
3756                         return 88200;
3757                 if (modes->sample_rates.rate.RATE_48)
3758                         return 48000;
3759                 if (modes->sample_rates.rate.RATE_44_1)
3760                         return 44100;
3761                 if (modes->sample_rates.rate.RATE_32)
3762                         return 32000;
3763         }
3764         /*original logic when no audio info*/
3765         return 441000;
3766 }
3767
3768 void get_audio_check(struct audio_info *aud_modes,
3769         struct audio_check *audio_chk)
3770 {
3771         unsigned int i;
3772         unsigned int max_sample_rate = 0;
3773
3774         if (aud_modes) {
3775                 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
3776
3777                 audio_chk->max_audiosample_rate = 0;
3778                 for (i = 0; i < aud_modes->mode_count; i++) {
3779                         max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
3780                         if (audio_chk->max_audiosample_rate < max_sample_rate)
3781                                 audio_chk->max_audiosample_rate = max_sample_rate;
3782                         /*dts takes the same as type 2: AP = 0.25*/
3783                 }
3784                 /*check which one take more bandwidth*/
3785                 if (audio_chk->max_audiosample_rate > 192000)
3786                         audio_chk->audio_packet_type = 0x9;/*AP =1*/
3787                 audio_chk->acat = 0;/*not support*/
3788         }
3789 }
3790
3791 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc(
3792                 const struct resource_context *res_ctx,
3793                 const struct resource_pool *const pool,
3794                 const struct dc_link *link)
3795 {
3796         struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
3797         int enc_index;
3798
3799         enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link);
3800
3801         if (enc_index < 0)
3802                 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
3803
3804         if (enc_index >= 0)
3805                 hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
3806
3807         return hpo_dp_link_enc;
3808 }
3809
3810 bool get_temp_dp_link_res(struct dc_link *link,
3811                 struct link_resource *link_res,
3812                 struct dc_link_settings *link_settings)
3813 {
3814         const struct dc *dc  = link->dc;
3815         const struct resource_context *res_ctx = &dc->current_state->res_ctx;
3816
3817         memset(link_res, 0, sizeof(*link_res));
3818
3819         if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
3820                 link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx,
3821                                 dc->res_pool, link);
3822                 if (!link_res->hpo_dp_link_enc)
3823                         return false;
3824         }
3825         return true;
3826 }
3827
3828 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
3829                 struct dc_state *context)
3830 {
3831         int i, j;
3832         struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
3833
3834         /* If pipe backend is reset, need to reset pipe syncd status */
3835         for (i = 0; i < dc->res_pool->pipe_count; i++) {
3836                 pipe_ctx_old =  &dc->current_state->res_ctx.pipe_ctx[i];
3837                 pipe_ctx = &context->res_ctx.pipe_ctx[i];
3838
3839                 if (!pipe_ctx_old->stream)
3840                         continue;
3841
3842                 if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
3843                         continue;
3844
3845                 if (!pipe_ctx->stream ||
3846                                 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
3847
3848                         /* Reset all the syncd pipes from the disabled pipe */
3849                         for (j = 0; j < dc->res_pool->pipe_count; j++) {
3850                                 pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
3851                                 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
3852                                         !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
3853                                         SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
3854                         }
3855                 }
3856         }
3857 }
3858
3859 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
3860         struct dc_state *context,
3861         uint8_t disabled_master_pipe_idx)
3862 {
3863         int i;
3864         struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
3865
3866         pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
3867         if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
3868                 !IS_PIPE_SYNCD_VALID(pipe_ctx))
3869                 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
3870
3871         /* for the pipe disabled, check if any slave pipe exists and assert */
3872         for (i = 0; i < dc->res_pool->pipe_count; i++) {
3873                 pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
3874
3875                 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
3876                     IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) {
3877                         struct pipe_ctx *first_pipe = pipe_ctx_check;
3878
3879                         while (first_pipe->prev_odm_pipe)
3880                                 first_pipe = first_pipe->prev_odm_pipe;
3881                         /* When ODM combine is enabled, this case is expected. If the disabled pipe
3882                          * is part of the ODM tree, then we should not print an error.
3883                          * */
3884                         if (first_pipe->pipe_idx == disabled_master_pipe_idx)
3885                                 continue;
3886
3887                         DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
3888                                    i, disabled_master_pipe_idx);
3889                 }
3890         }
3891 }
3892
3893 void reset_sync_context_for_pipe(const struct dc *dc,
3894         struct dc_state *context,
3895         uint8_t pipe_idx)
3896 {
3897         int i;
3898         struct pipe_ctx *pipe_ctx_reset;
3899
3900         /* reset the otg sync context for the pipe and its slave pipes if any */
3901         for (i = 0; i < dc->res_pool->pipe_count; i++) {
3902                 pipe_ctx_reset = &context->res_ctx.pipe_ctx[i];
3903
3904                 if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) &&
3905                         IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx))
3906                         SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i);
3907         }
3908 }
3909
3910 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
3911 {
3912         /* TODO - get transmitter to phy idx mapping from DMUB */
3913         uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A;
3914
3915         if (dc->ctx->dce_version == DCN_VERSION_3_1 &&
3916                         dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
3917                 switch (transmitter) {
3918                 case TRANSMITTER_UNIPHY_A:
3919                         phy_idx = 0;
3920                         break;
3921                 case TRANSMITTER_UNIPHY_B:
3922                         phy_idx = 1;
3923                         break;
3924                 case TRANSMITTER_UNIPHY_C:
3925                         phy_idx = 5;
3926                         break;
3927                 case TRANSMITTER_UNIPHY_D:
3928                         phy_idx = 6;
3929                         break;
3930                 case TRANSMITTER_UNIPHY_E:
3931                         phy_idx = 4;
3932                         break;
3933                 default:
3934                         phy_idx = 0;
3935                         break;
3936                 }
3937         }
3938
3939         return phy_idx;
3940 }
3941
3942 const struct link_hwss *get_link_hwss(const struct dc_link *link,
3943                 const struct link_resource *link_res)
3944 {
3945         /* Link_hwss is only accessible by getter function instead of accessing
3946          * by pointers in dc with the intent to protect against breaking polymorphism.
3947          */
3948         if (can_use_hpo_dp_link_hwss(link, link_res))
3949                 /* TODO: some assumes that if decided link settings is 128b/132b
3950                  * channel coding format hpo_dp_link_enc should be used.
3951                  * Others believe that if hpo_dp_link_enc is available in link
3952                  * resource then hpo_dp_link_enc must be used. This bound between
3953                  * hpo_dp_link_enc != NULL and decided link settings is loosely coupled
3954                  * with a premise that both hpo_dp_link_enc pointer and decided link
3955                  * settings are determined based on single policy function like
3956                  * "decide_link_settings" from upper layer. This "convention"
3957                  * cannot be maintained and enforced at current level.
3958                  * Therefore a refactor is due so we can enforce a strong bound
3959                  * between those two parameters at this level.
3960                  *
3961                  * To put it simple, we want to make enforcement at low level so that
3962                  * we will not return link hwss if caller plans to do 8b/10b
3963                  * with an hpo encoder. Or we can return a very dummy one that doesn't
3964                  * do work for all functions
3965                  */
3966                 return get_hpo_dp_link_hwss();
3967         else if (can_use_dpia_link_hwss(link, link_res))
3968                 return get_dpia_link_hwss();
3969         else if (can_use_dio_link_hwss(link, link_res))
3970                 return get_dio_link_hwss();
3971         else
3972                 return get_virtual_link_hwss();
3973 }
3974
3975 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream)
3976 {
3977         bool divisible = false;
3978         uint16_t h_blank_start = 0;
3979         uint16_t h_blank_end = 0;
3980
3981         if (stream) {
3982                 h_blank_start = stream->timing.h_total - stream->timing.h_front_porch;
3983                 h_blank_end = h_blank_start - stream->timing.h_addressable;
3984
3985                 /* HTOTAL, Hblank start/end, and Hsync start/end all must be
3986                  * divisible by 2 in order for the horizontal timing params
3987                  * to be considered divisible by 2. Hsync start is always 0.
3988                  */
3989                 divisible = (stream->timing.h_total % 2 == 0) &&
3990                                 (h_blank_start % 2 == 0) &&
3991                                 (h_blank_end % 2 == 0) &&
3992                                 (stream->timing.h_sync_width % 2 == 0);
3993         }
3994         return divisible;
3995 }
3996
3997 bool dc_resource_acquire_secondary_pipe_for_mpc_odm(
3998                 const struct dc *dc,
3999                 struct dc_state *state,
4000                 struct pipe_ctx *pri_pipe,
4001                 struct pipe_ctx *sec_pipe,
4002                 bool odm)
4003 {
4004         int pipe_idx = sec_pipe->pipe_idx;
4005         struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev;
4006         const struct resource_pool *pool = dc->res_pool;
4007
4008         sec_top = sec_pipe->top_pipe;
4009         sec_bottom = sec_pipe->bottom_pipe;
4010         sec_next = sec_pipe->next_odm_pipe;
4011         sec_prev = sec_pipe->prev_odm_pipe;
4012
4013         *sec_pipe = *pri_pipe;
4014
4015         sec_pipe->top_pipe = sec_top;
4016         sec_pipe->bottom_pipe = sec_bottom;
4017         sec_pipe->next_odm_pipe = sec_next;
4018         sec_pipe->prev_odm_pipe = sec_prev;
4019
4020         sec_pipe->pipe_idx = pipe_idx;
4021         sec_pipe->plane_res.mi = pool->mis[pipe_idx];
4022         sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
4023         sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
4024         sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
4025         sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
4026         sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
4027         sec_pipe->stream_res.dsc = NULL;
4028         if (odm) {
4029                 if (!sec_pipe->top_pipe)
4030                         sec_pipe->stream_res.opp = pool->opps[pipe_idx];
4031                 else
4032                         sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
4033                 if (sec_pipe->stream->timing.flags.DSC == 1) {
4034 #if defined(CONFIG_DRM_AMD_DC_FP)
4035                         dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx);
4036 #endif
4037                         ASSERT(sec_pipe->stream_res.dsc);
4038                         if (sec_pipe->stream_res.dsc == NULL)
4039                                 return false;
4040                 }
4041 #if defined(CONFIG_DRM_AMD_DC_FP)
4042                 dcn20_build_mapped_resource(dc, state, sec_pipe->stream);
4043 #endif
4044         }
4045
4046         return true;
4047 }
4048
4049 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
4050                 struct dc_state *context,
4051                 struct pipe_ctx *pipe_ctx)
4052 {
4053         if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
4054                 if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) {
4055                         pipe_ctx->stream_res.hpo_dp_stream_enc =
4056                                         find_first_free_match_hpo_dp_stream_enc_for_link(
4057                                                         &context->res_ctx, dc->res_pool, pipe_ctx->stream);
4058
4059                         if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
4060                                 return DC_NO_STREAM_ENC_RESOURCE;
4061
4062                         update_hpo_dp_stream_engine_usage(
4063                                         &context->res_ctx, dc->res_pool,
4064                                         pipe_ctx->stream_res.hpo_dp_stream_enc,
4065                                         true);
4066                 }
4067
4068                 if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) {
4069                         if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream))
4070                                 return DC_NO_LINK_ENC_RESOURCE;
4071                 }
4072         } else {
4073                 if (pipe_ctx->stream_res.hpo_dp_stream_enc) {
4074                         update_hpo_dp_stream_engine_usage(
4075                                         &context->res_ctx, dc->res_pool,
4076                                         pipe_ctx->stream_res.hpo_dp_stream_enc,
4077                                         false);
4078                         pipe_ctx->stream_res.hpo_dp_stream_enc = NULL;
4079                 }
4080                 if (pipe_ctx->link_res.hpo_dp_link_enc)
4081                         remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream);
4082         }
4083
4084         return DC_OK;
4085 }
4086