]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drm/amd/display: Initialise encoder assignment when initialising dc_state
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / amd / display / dc / core / dc_resource.c
CommitLineData
4562236b 1/*
9ce6aae1 2 * Copyright 2012-15 Advanced Micro Devices, Inc.
4562236b
HW
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 */
4fc4dca8
SR
25
26#include <linux/slab.h>
27
4562236b
HW
28#include "dm_services.h"
29
30#include "resource.h"
31#include "include/irq_service_interface.h"
32#include "link_encoder.h"
33#include "stream_encoder.h"
34#include "opp.h"
35#include "timing_generator.h"
36#include "transform.h"
33d7598d
JL
37#include "dccg.h"
38#include "dchubbub.h"
d94585a0 39#include "dpp.h"
5ac3d3c9 40#include "core_types.h"
4562236b 41#include "set_mode_types.h"
4562236b 42#include "virtual/virtual_stream_encoder.h"
3b94a400 43#include "dpcd_defs.h"
6f941d4e 44#include "link_enc_cfg.h"
4562236b 45
683b5950
MR
46#if defined(CONFIG_DRM_AMD_DC_SI)
47#include "dce60/dce60_resource.h"
48#endif
4562236b
HW
49#include "dce80/dce80_resource.h"
50#include "dce100/dce100_resource.h"
51#include "dce110/dce110_resource.h"
52#include "dce112/dce112_resource.h"
cf2156e2 53#include "dce120/dce120_resource.h"
b86a1aa3 54#if defined(CONFIG_DRM_AMD_DC_DCN)
ff5ef992 55#include "dcn10/dcn10_resource.h"
7ed4e635 56#include "dcn20/dcn20_resource.h"
e22ece54 57#include "dcn21/dcn21_resource.h"
20f2ffe5
AD
58#include "dcn30/dcn30_resource.h"
59#include "dcn301/dcn301_resource.h"
60#include "dcn302/dcn302_resource.h"
cd6d421e 61#include "dcn303/dcn303_resource.h"
8fe44c08 62#include "dcn31/dcn31_resource.h"
36d26912 63#endif
5d4b05dd
BL
64
65#define DC_LOGGER_INIT(logger)
66
4562236b
HW
67enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
68{
69 enum dce_version dc_version = DCE_VERSION_UNKNOWN;
70 switch (asic_id.chip_family) {
71
683b5950
MR
72#if defined(CONFIG_DRM_AMD_DC_SI)
73 case FAMILY_SI:
74 if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
75 ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
76 ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
34b0c779 77 dc_version = DCE_VERSION_6_0;
683b5950
MR
78 else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
79 dc_version = DCE_VERSION_6_4;
80 else
81 dc_version = DCE_VERSION_6_1;
82 break;
83#endif
4562236b 84 case FAMILY_CI:
4562236b
HW
85 dc_version = DCE_VERSION_8_0;
86 break;
ebfdf0d0
AD
87 case FAMILY_KV:
88 if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
89 ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
90 ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
91 dc_version = DCE_VERSION_8_3;
92 else
93 dc_version = DCE_VERSION_8_1;
94 break;
4562236b
HW
95 case FAMILY_CZ:
96 dc_version = DCE_VERSION_11_0;
97 break;
98
99 case FAMILY_VI:
100 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
101 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
102 dc_version = DCE_VERSION_10_0;
103 break;
104 }
105 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
b264d345
JL
106 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
107 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
4562236b
HW
108 dc_version = DCE_VERSION_11_2;
109 }
0c75d5ac
JFZ
110 if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
111 dc_version = DCE_VERSION_11_22;
4562236b 112 break;
2c8ad2d5 113 case FAMILY_AI:
b8b6ce89
LL
114 if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
115 dc_version = DCE_VERSION_12_1;
116 else
117 dc_version = DCE_VERSION_12_0;
2c8ad2d5 118 break;
b86a1aa3 119#if defined(CONFIG_DRM_AMD_DC_DCN)
ff5ef992
AD
120 case FAMILY_RV:
121 dc_version = DCN_VERSION_1_0;
0e3d73f1
BL
122 if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
123 dc_version = DCN_VERSION_1_01;
e22ece54
BL
124 if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
125 dc_version = DCN_VERSION_2_1;
9ba93114
RL
126 if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
127 dc_version = DCN_VERSION_2_1;
ff5ef992 128 break;
7ed4e635 129
7ed4e635
HW
130 case FAMILY_NV:
131 dc_version = DCN_VERSION_2_0;
5dba4991
BL
132 if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
133 dc_version = DCN_VERSION_3_0;
36d26912
BL
134 if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
135 dc_version = DCN_VERSION_3_02;
cd6d421e
AP
136 if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
137 dc_version = DCN_VERSION_3_03;
7ed4e635 138 break;
3a83e4e6 139
3a83e4e6
RL
140 case FAMILY_VGH:
141 dc_version = DCN_VERSION_3_01;
142 break;
2083640f 143
2083640f
NK
144 case FAMILY_YELLOW_CARP:
145 if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
146 dc_version = DCN_VERSION_3_1;
147 break;
148#endif
149
4562236b
HW
150 default:
151 dc_version = DCE_VERSION_UNKNOWN;
152 break;
153 }
154 return dc_version;
155}
156
d9673c92
HW
157struct resource_pool *dc_create_resource_pool(struct dc *dc,
158 const struct dc_init_data *init_data,
159 enum dce_version dc_version)
4562236b 160{
5ac3d3c9 161 struct resource_pool *res_pool = NULL;
4562236b
HW
162
163 switch (dc_version) {
683b5950
MR
164#if defined(CONFIG_DRM_AMD_DC_SI)
165 case DCE_VERSION_6_0:
166 res_pool = dce60_create_resource_pool(
167 init_data->num_virtual_links, dc);
168 break;
169 case DCE_VERSION_6_1:
170 res_pool = dce61_create_resource_pool(
171 init_data->num_virtual_links, dc);
172 break;
173 case DCE_VERSION_6_4:
174 res_pool = dce64_create_resource_pool(
175 init_data->num_virtual_links, dc);
176 break;
177#endif
4562236b 178 case DCE_VERSION_8_0:
7992a629 179 res_pool = dce80_create_resource_pool(
d9673c92 180 init_data->num_virtual_links, dc);
7992a629 181 break;
ebfdf0d0 182 case DCE_VERSION_8_1:
7992a629 183 res_pool = dce81_create_resource_pool(
d9673c92 184 init_data->num_virtual_links, dc);
7992a629 185 break;
ebfdf0d0 186 case DCE_VERSION_8_3:
7992a629 187 res_pool = dce83_create_resource_pool(
d9673c92 188 init_data->num_virtual_links, dc);
5ac3d3c9 189 break;
4562236b 190 case DCE_VERSION_10_0:
5ac3d3c9 191 res_pool = dce100_create_resource_pool(
d9673c92 192 init_data->num_virtual_links, dc);
5ac3d3c9 193 break;
4562236b 194 case DCE_VERSION_11_0:
5ac3d3c9 195 res_pool = dce110_create_resource_pool(
d9673c92
HW
196 init_data->num_virtual_links, dc,
197 init_data->asic_id);
5ac3d3c9 198 break;
4562236b 199 case DCE_VERSION_11_2:
0c75d5ac 200 case DCE_VERSION_11_22:
5ac3d3c9 201 res_pool = dce112_create_resource_pool(
d9673c92 202 init_data->num_virtual_links, dc);
5ac3d3c9 203 break;
2c8ad2d5 204 case DCE_VERSION_12_0:
b8b6ce89 205 case DCE_VERSION_12_1:
2c8ad2d5 206 res_pool = dce120_create_resource_pool(
d9673c92 207 init_data->num_virtual_links, dc);
2c8ad2d5 208 break;
ff5ef992 209
b86a1aa3 210#if defined(CONFIG_DRM_AMD_DC_DCN)
ff5ef992 211 case DCN_VERSION_1_0:
0e3d73f1 212 case DCN_VERSION_1_01:
d9673c92 213 res_pool = dcn10_create_resource_pool(init_data, dc);
ff5ef992 214 break;
7ed4e635
HW
215 case DCN_VERSION_2_0:
216 res_pool = dcn20_create_resource_pool(init_data, dc);
217 break;
e22ece54
BL
218 case DCN_VERSION_2_1:
219 res_pool = dcn21_create_resource_pool(init_data, dc);
220 break;
5dba4991
BL
221 case DCN_VERSION_3_0:
222 res_pool = dcn30_create_resource_pool(init_data, dc);
223 break;
3a83e4e6
RL
224 case DCN_VERSION_3_01:
225 res_pool = dcn301_create_resource_pool(init_data, dc);
226 break;
36d26912
BL
227 case DCN_VERSION_3_02:
228 res_pool = dcn302_create_resource_pool(init_data, dc);
229 break;
cd6d421e
AP
230 case DCN_VERSION_3_03:
231 res_pool = dcn303_create_resource_pool(init_data, dc);
232 break;
2083640f
NK
233 case DCN_VERSION_3_1:
234 res_pool = dcn31_create_resource_pool(init_data, dc);
235 break;
3a83e4e6 236#endif
4562236b
HW
237 default:
238 break;
239 }
f49cfa27 240
5ac3d3c9 241 if (res_pool != NULL) {
9adc8050 242 if (dc->ctx->dc_bios->fw_info_valid) {
41a5a2a8 243 res_pool->ref_clocks.xtalin_clock_inKhz =
9adc8050 244 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
41a5a2a8 245 /* initialize with firmware data first, no all
246 * ASIC have DCCG SW component. FPGA or
247 * simulation need initialization of
248 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
249 * with xtalin_clock_inKhz
250 */
251 res_pool->ref_clocks.dccg_ref_clock_inKhz =
252 res_pool->ref_clocks.xtalin_clock_inKhz;
253 res_pool->ref_clocks.dchub_ref_clock_inKhz =
254 res_pool->ref_clocks.xtalin_clock_inKhz;
255 } else
256 ASSERT_CRITICAL(false);
5ac3d3c9 257 }
4562236b 258
5ac3d3c9 259 return res_pool;
4562236b
HW
260}
261
fb3466a4 262void dc_destroy_resource_pool(struct dc *dc)
4562236b
HW
263{
264 if (dc) {
265 if (dc->res_pool)
266 dc->res_pool->funcs->destroy(&dc->res_pool);
267
d029810c 268 kfree(dc->hwseq);
4562236b
HW
269 }
270}
271
272static void update_num_audio(
273 const struct resource_straps *straps,
274 unsigned int *num_audio,
275 struct audio_support *aud_support)
276{
b8e9eb72
CL
277 aud_support->dp_audio = true;
278 aud_support->hdmi_audio_native = false;
279 aud_support->hdmi_audio_on_dongle = false;
280
4562236b 281 if (straps->hdmi_disable == 0) {
4562236b
HW
282 if (straps->dc_pinstraps_audio & 0x2) {
283 aud_support->hdmi_audio_on_dongle = true;
b8e9eb72 284 aud_support->hdmi_audio_native = true;
4562236b
HW
285 }
286 }
287
288 switch (straps->audio_stream_number) {
289 case 0: /* multi streams supported */
290 break;
291 case 1: /* multi streams not supported */
292 *num_audio = 1;
293 break;
294 default:
295 DC_ERR("DC: unexpected audio fuse!\n");
17a96033 296 }
4562236b
HW
297}
298
299bool resource_construct(
300 unsigned int num_virtual_links,
fb3466a4 301 struct dc *dc,
4562236b
HW
302 struct resource_pool *pool,
303 const struct resource_create_funcs *create_funcs)
304{
305 struct dc_context *ctx = dc->ctx;
306 const struct resource_caps *caps = pool->res_cap;
307 int i;
308 unsigned int num_audio = caps->num_audio;
309 struct resource_straps straps = {0};
310
311 if (create_funcs->read_dce_straps)
312 create_funcs->read_dce_straps(dc->ctx, &straps);
313
314 pool->audio_count = 0;
315 if (create_funcs->create_audio) {
316 /* find the total number of streams available via the
317 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
318 * registers (one for each pin) starting from pin 1
319 * up to the max number of audio pins.
320 * We stop on the first pin where
321 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
322 */
323 update_num_audio(&straps, &num_audio, &pool->audio_support);
5feb9f07 324 for (i = 0; i < caps->num_audio; i++) {
4562236b
HW
325 struct audio *aud = create_funcs->create_audio(ctx, i);
326
327 if (aud == NULL) {
328 DC_ERR("DC: failed to create audio!\n");
329 return false;
330 }
4562236b
HW
331 if (!aud->funcs->endpoint_valid(aud)) {
332 aud->funcs->destroy(&aud);
333 break;
334 }
4562236b
HW
335 pool->audios[i] = aud;
336 pool->audio_count++;
337 }
338 }
339
340 pool->stream_enc_count = 0;
341 if (create_funcs->create_stream_encoder) {
342 for (i = 0; i < caps->num_stream_encoder; i++) {
343 pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
344 if (pool->stream_enc[i] == NULL)
345 DC_ERR("DC: failed to create stream_encoder!\n");
346 pool->stream_enc_count++;
347 }
348 }
929c3aaa 349
20f2ffe5 350#if defined(CONFIG_DRM_AMD_DC_DCN)
5dba4991
BL
351 for (i = 0; i < caps->num_mpc_3dlut; i++) {
352 pool->mpc_lut[i] = dc_create_3dlut_func();
353 if (pool->mpc_lut[i] == NULL)
354 DC_ERR("DC: failed to create MPC 3dlut!\n");
355 pool->mpc_shaper[i] = dc_create_transfer_func();
356 if (pool->mpc_shaper[i] == NULL)
357 DC_ERR("DC: failed to create MPC shaper!\n");
358 }
359#endif
4176664b
CL
360 dc->caps.dynamic_audio = false;
361 if (pool->audio_count < pool->stream_enc_count) {
362 dc->caps.dynamic_audio = true;
363 }
4562236b
HW
364 for (i = 0; i < num_virtual_links; i++) {
365 pool->stream_enc[pool->stream_enc_count] =
366 virtual_stream_encoder_create(
367 ctx, ctx->dc_bios);
368 if (pool->stream_enc[pool->stream_enc_count] == NULL) {
369 DC_ERR("DC: failed to create stream_encoder!\n");
370 return false;
371 }
372 pool->stream_enc_count++;
373 }
374
375 dc->hwseq = create_funcs->create_hwseq(ctx);
376
377 return true;
378}
ad8960a6
ML
379static int find_matching_clock_source(
380 const struct resource_pool *pool,
381 struct clock_source *clock_source)
382{
4562236b 383
ad8960a6
ML
384 int i;
385
386 for (i = 0; i < pool->clk_src_count; i++) {
387 if (pool->clock_sources[i] == clock_source)
388 return i;
389 }
390 return -1;
391}
4562236b 392
21e67d4d 393void resource_unreference_clock_source(
4562236b 394 struct resource_context *res_ctx,
a2b8659d 395 const struct resource_pool *pool,
4a629536 396 struct clock_source *clock_source)
4562236b 397{
ad8960a6 398 int i = find_matching_clock_source(pool, clock_source);
4562236b 399
ad8960a6 400 if (i > -1)
4562236b
HW
401 res_ctx->clock_source_ref_count[i]--;
402
21e67d4d 403 if (pool->dp_clock_source == clock_source)
4562236b 404 res_ctx->dp_clock_source_ref_count--;
4562236b
HW
405}
406
407void resource_reference_clock_source(
408 struct resource_context *res_ctx,
a2b8659d 409 const struct resource_pool *pool,
4562236b
HW
410 struct clock_source *clock_source)
411{
ad8960a6 412 int i = find_matching_clock_source(pool, clock_source);
4562236b 413
ad8960a6 414 if (i > -1)
4562236b 415 res_ctx->clock_source_ref_count[i]++;
4562236b 416
a2b8659d 417 if (pool->dp_clock_source == clock_source)
4562236b
HW
418 res_ctx->dp_clock_source_ref_count++;
419}
420
ad8960a6
ML
421int resource_get_clock_source_reference(
422 struct resource_context *res_ctx,
423 const struct resource_pool *pool,
424 struct clock_source *clock_source)
425{
426 int i = find_matching_clock_source(pool, clock_source);
427
428 if (i > -1)
429 return res_ctx->clock_source_ref_count[i];
430
431 if (pool->dp_clock_source == clock_source)
432 return res_ctx->dp_clock_source_ref_count;
433
434 return -1;
435}
436
77a2b726
VS
437bool resource_are_vblanks_synchronizable(
438 struct dc_stream_state *stream1,
439 struct dc_stream_state *stream2)
440{
441 uint32_t base60_refresh_rates[] = {10, 20, 5};
442 uint8_t i;
d0b3bbd3 443 uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
783bf403 444 uint64_t frame_time_diff;
77a2b726
VS
445
446 if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
447 stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
448 dc_is_dp_signal(stream1->signal) &&
449 dc_is_dp_signal(stream2->signal) &&
450 false == stream1->has_non_synchronizable_pclk &&
451 false == stream2->has_non_synchronizable_pclk &&
452 stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
453 stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
454 /* disable refresh rates higher than 60Hz for now */
455 if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
456 stream1->timing.v_total > 60)
457 return false;
458 if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
459 stream2->timing.v_total > 60)
460 return false;
783bf403 461 frame_time_diff = (uint64_t)10000 *
77a2b726
VS
462 stream1->timing.h_total *
463 stream1->timing.v_total *
783bf403
VS
464 stream2->timing.pix_clk_100hz;
465 frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
466 frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
467 frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
77a2b726 468 for (i = 0; i < rr_count; i++) {
783bf403 469 int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
77a2b726
VS
470
471 if (diff < 0)
472 diff = -diff;
473 if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
474 return true;
475 }
476 }
477 return false;
478}
479
4562236b 480bool resource_are_streams_timing_synchronizable(
0971c40e
HW
481 struct dc_stream_state *stream1,
482 struct dc_stream_state *stream2)
4562236b 483{
4fa086b9 484 if (stream1->timing.h_total != stream2->timing.h_total)
4562236b
HW
485 return false;
486
4fa086b9 487 if (stream1->timing.v_total != stream2->timing.v_total)
4562236b
HW
488 return false;
489
4fa086b9
LSL
490 if (stream1->timing.h_addressable
491 != stream2->timing.h_addressable)
4562236b
HW
492 return false;
493
4fa086b9
LSL
494 if (stream1->timing.v_addressable
495 != stream2->timing.v_addressable)
4562236b
HW
496 return false;
497
8582aea2
DG
498 if (stream1->timing.v_front_porch
499 != stream2->timing.v_front_porch)
500 return false;
501
380604e2
KC
502 if (stream1->timing.pix_clk_100hz
503 != stream2->timing.pix_clk_100hz)
4562236b
HW
504 return false;
505
3e27e10e
ML
506 if (stream1->clamping.c_depth != stream2->clamping.c_depth)
507 return false;
508
4562236b 509 if (stream1->phy_pix_clk != stream2->phy_pix_clk
7e2fe319
CL
510 && (!dc_is_dp_signal(stream1->signal)
511 || !dc_is_dp_signal(stream2->signal)))
4562236b
HW
512 return false;
513
d77f778e
CL
514 if (stream1->view_format != stream2->view_format)
515 return false;
516
0460f9ab
JL
517 if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
518 return false;
519
4562236b
HW
520 return true;
521}
3e27e10e
ML
522static bool is_dp_and_hdmi_sharable(
523 struct dc_stream_state *stream1,
524 struct dc_stream_state *stream2)
525{
526 if (stream1->ctx->dc->caps.disable_dp_clk_share)
527 return false;
528
529 if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
d77f778e 530 stream2->clamping.c_depth != COLOR_DEPTH_888)
43fbbe89 531 return false;
3e27e10e
ML
532
533 return true;
534
535}
4562236b
HW
536
537static bool is_sharable_clk_src(
538 const struct pipe_ctx *pipe_with_clk_src,
539 const struct pipe_ctx *pipe)
540{
541 if (pipe_with_clk_src->clock_source == NULL)
542 return false;
543
544 if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
545 return false;
546
3e27e10e
ML
547 if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
548 (dc_is_dp_signal(pipe->stream->signal) &&
549 !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
550 pipe->stream)))
4562236b
HW
551 return false;
552
553 if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
fc69009e 554 && dc_is_dual_link_signal(pipe->stream->signal))
4562236b
HW
555 return false;
556
557 if (dc_is_hdmi_signal(pipe->stream->signal)
fc69009e 558 && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
4562236b
HW
559 return false;
560
561 if (!resource_are_streams_timing_synchronizable(
562 pipe_with_clk_src->stream, pipe->stream))
563 return false;
564
565 return true;
566}
567
568struct clock_source *resource_find_used_clk_src_for_sharing(
569 struct resource_context *res_ctx,
570 struct pipe_ctx *pipe_ctx)
571{
572 int i;
573
574 for (i = 0; i < MAX_PIPES; i++) {
575 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
576 return res_ctx->pipe_ctx[i].clock_source;
577 }
578
579 return NULL;
580}
581
582static enum pixel_format convert_pixel_format_to_dalsurface(
583 enum surface_pixel_format surface_pixel_format)
584{
585 enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
586
587 switch (surface_pixel_format) {
588 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
589 dal_pixel_format = PIXEL_FORMAT_INDEX8;
590 break;
591 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
592 dal_pixel_format = PIXEL_FORMAT_RGB565;
593 break;
594 case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
595 dal_pixel_format = PIXEL_FORMAT_RGB565;
596 break;
597 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
598 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
599 break;
8693049a 600 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
4562236b
HW
601 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
602 break;
603 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
604 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
605 break;
606 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
607 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
608 break;
609 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
610 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
611 break;
612 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
613 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
614 dal_pixel_format = PIXEL_FORMAT_FP16;
615 break;
616 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
4562236b 617 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
87449a90 618 dal_pixel_format = PIXEL_FORMAT_420BPP8;
4562236b 619 break;
ffbcd19a
VP
620 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
621 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
87449a90 622 dal_pixel_format = PIXEL_FORMAT_420BPP10;
ffbcd19a 623 break;
4562236b 624 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
050cd3d6 625 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
4562236b
HW
626 default:
627 dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
628 break;
629 }
630 return dal_pixel_format;
631}
632
9b6067c0
DL
633static inline void get_vp_scan_direction(
634 enum dc_rotation_angle rotation,
635 bool horizontal_mirror,
636 bool *orthogonal_rotation,
637 bool *flip_vert_scan_dir,
638 bool *flip_horz_scan_dir)
4562236b 639{
9b6067c0
DL
640 *orthogonal_rotation = false;
641 *flip_vert_scan_dir = false;
642 *flip_horz_scan_dir = false;
643 if (rotation == ROTATION_ANGLE_180) {
644 *flip_vert_scan_dir = true;
645 *flip_horz_scan_dir = true;
646 } else if (rotation == ROTATION_ANGLE_90) {
647 *orthogonal_rotation = true;
648 *flip_horz_scan_dir = true;
649 } else if (rotation == ROTATION_ANGLE_270) {
650 *orthogonal_rotation = true;
651 *flip_vert_scan_dir = true;
652 }
653
654 if (horizontal_mirror)
655 *flip_horz_scan_dir = !*flip_horz_scan_dir;
4562236b
HW
656}
657
570bc18c
DL
658int get_num_mpc_splits(struct pipe_ctx *pipe)
659{
660 int mpc_split_count = 0;
661 struct pipe_ctx *other_pipe = pipe->bottom_pipe;
662
663 while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
664 mpc_split_count++;
665 other_pipe = other_pipe->bottom_pipe;
666 }
667 other_pipe = pipe->top_pipe;
668 while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
669 mpc_split_count++;
670 other_pipe = other_pipe->top_pipe;
671 }
672
673 return mpc_split_count;
674}
675
228a10d4
AD
676int get_num_odm_splits(struct pipe_ctx *pipe)
677{
678 int odm_split_count = 0;
679 struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
680 while (next_pipe) {
681 odm_split_count++;
682 next_pipe = next_pipe->next_odm_pipe;
683 }
684 pipe = pipe->prev_odm_pipe;
685 while (pipe) {
686 odm_split_count++;
687 pipe = pipe->prev_odm_pipe;
688 }
689 return odm_split_count;
690}
691
5bf24270
DL
692static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx)
693{
694 *split_count = get_num_odm_splits(pipe_ctx);
695 *split_idx = 0;
696 if (*split_count == 0) {
697 /*Check for mpc split*/
698 struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
699
570bc18c 700 *split_count = get_num_mpc_splits(pipe_ctx);
5bf24270
DL
701 while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
702 (*split_idx)++;
5bf24270
DL
703 split_pipe = split_pipe->top_pipe;
704 }
5bf24270
DL
705 } else {
706 /*Get odm split index*/
707 struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
708
709 while (split_pipe) {
710 (*split_idx)++;
711 split_pipe = split_pipe->prev_odm_pipe;
712 }
713 }
714}
715
6566cae7
DL
716/*
717 * This is a preliminary vp size calculation to allow us to check taps support.
718 * The result is completely overridden afterwards.
719 */
720static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
4562236b 721{
6702a9ac 722 struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
9b6067c0 723
6566cae7
DL
724 data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width));
725 data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height));
726 data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width));
727 data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height));
728 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
729 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
730 swap(data->viewport.width, data->viewport.height);
731 swap(data->viewport_c.width, data->viewport_c.height);
9b6067c0 732 }
4562236b
HW
733}
734
9b6067c0 735static void calculate_recout(struct pipe_ctx *pipe_ctx)
4562236b 736{
3be5262e 737 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
0971c40e 738 const struct dc_stream_state *stream = pipe_ctx->stream;
5bf24270 739 struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
3be5262e 740 struct rect surf_clip = plane_state->clip_rect;
6566cae7
DL
741 bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
742 int split_count, split_idx;
5bf24270
DL
743
744 calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
6566cae7
DL
745 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
746 split_idx = 0;
5bf24270 747
05e3d830
WC
748 /*
749 * Only the leftmost ODM pipe should be offset by a nonzero distance
750 */
6566cae7 751 if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
05e3d830 752 data->recout.x = stream->dst.x;
25b31581
WC
753 if (stream->src.x < surf_clip.x)
754 data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
4fa086b9 755 / stream->src.width;
25b31581
WC
756 } else
757 data->recout.x = 0;
758
84aef2ab
DL
759 if (stream->src.x > surf_clip.x)
760 surf_clip.width -= stream->src.x - surf_clip.x;
5bf24270
DL
761 data->recout.width = surf_clip.width * stream->dst.width / stream->src.width;
762 if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width)
763 data->recout.width = stream->dst.x + stream->dst.width - data->recout.x;
4562236b 764
5bf24270 765 data->recout.y = stream->dst.y;
4fa086b9 766 if (stream->src.y < surf_clip.y)
5bf24270 767 data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height
4fa086b9 768 / stream->src.height;
84aef2ab
DL
769 else if (stream->src.y > surf_clip.y)
770 surf_clip.height -= stream->src.y - surf_clip.y;
4562236b 771
5bf24270
DL
772 data->recout.height = surf_clip.height * stream->dst.height / stream->src.height;
773 if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height)
774 data->recout.height = stream->dst.y + stream->dst.height - data->recout.y;
b2d0a103 775
6566cae7
DL
776 /* Handle h & v split */
777 if (split_tb) {
778 ASSERT(data->recout.height % 2 == 0);
5bf24270 779 data->recout.height /= 2;
6566cae7 780 } else if (split_count) {
5bf24270 781 if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) {
6566cae7
DL
782 /* extra pixels in the division remainder need to go to pipes after
783 * the extra pixel index minus one(epimo) defined here as:
784 */
785 int epimo = split_count - data->recout.width % (split_count + 1);
786
5bf24270
DL
787 data->recout.x += (data->recout.width / (split_count + 1)) * split_idx;
788 if (split_idx > epimo)
789 data->recout.x += split_idx - epimo - 1;
6566cae7
DL
790 ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0);
791 data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
792 } else {
793 /* odm */
794 if (split_idx == split_count) {
795 /* rightmost pipe is the remainder recout */
796 data->recout.width -= data->h_active * split_count - data->recout.x;
665f2850
AC
797
798 /* ODM combine cases with MPO we can get negative widths */
799 if (data->recout.width < 0)
800 data->recout.width = 0;
801
6566cae7
DL
802 data->recout.x = 0;
803 } else
804 data->recout.width = data->h_active - data->recout.x;
5bf24270 805 }
5bf24270 806 }
4562236b
HW
807}
808
b2d0a103 809static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
4562236b 810{
3be5262e 811 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
0971c40e 812 const struct dc_stream_state *stream = pipe_ctx->stream;
3be5262e 813 struct rect surf_src = plane_state->src_rect;
4fa086b9
LSL
814 const int in_w = stream->src.width;
815 const int in_h = stream->src.height;
816 const int out_w = stream->dst.width;
817 const int out_h = stream->dst.height;
4562236b 818
9b6067c0 819 /*Swap surf_src height and width since scaling ratios are in recout rotation*/
3be5262e
HW
820 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
821 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
9b6067c0 822 swap(surf_src.height, surf_src.width);
86006a7f 823
eb0e5154 824 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
86006a7f 825 surf_src.width,
3be5262e 826 plane_state->dst_rect.width);
eb0e5154 827 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
86006a7f 828 surf_src.height,
3be5262e 829 plane_state->dst_rect.height);
4562236b 830
4fa086b9 831 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
6702a9ac 832 pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
4fa086b9 833 else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
6702a9ac 834 pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
4562236b 835
6702a9ac
HW
836 pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
837 pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
838 pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
839 pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
4562236b 840
6702a9ac
HW
841 pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
842 pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
4562236b 843
6702a9ac
HW
844 if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
845 || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
846 pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
847 pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
4562236b 848 }
0002d3ac
DL
849 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
850 pipe_ctx->plane_res.scl_data.ratios.horz, 19);
851 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
852 pipe_ctx->plane_res.scl_data.ratios.vert, 19);
853 pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
854 pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
855 pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
856 pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
4562236b
HW
857}
858
6566cae7
DL
859
860/*
861 * We completely calculate vp offset, size and inits here based entirely on scaling
862 * ratios and recout for pixel perfect pipe combine.
863 */
864static void calculate_init_and_vp(
9b6067c0 865 bool flip_scan_dir,
6566cae7
DL
866 int recout_offset_within_recout_full,
867 int recout_size,
9b6067c0
DL
868 int src_size,
869 int taps,
870 struct fixed31_32 ratio,
871 struct fixed31_32 *init,
872 int *vp_offset,
873 int *vp_size)
b2d0a103 874{
6566cae7
DL
875 struct fixed31_32 temp;
876 int int_part;
b2d0a103 877
6566cae7
DL
878 /*
879 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
880 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
881 * All following calculations are based on this logic.
882 *
883 * Init calculated according to formula:
884 * init = (scaling_ratio + number_of_taps + 1) / 2
885 * init_bot = init + scaling_ratio
886 * to get pixel perfect combine add the fraction from calculating vp offset
887 */
888 temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
889 *vp_offset = dc_fixpt_floor(temp);
890 temp.value &= 0xffffffff;
891 *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
892 dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
893 /*
894 * If viewport has non 0 offset and there are more taps than covered by init then
895 * we should decrease the offset and increase init so we are never sampling
896 * outside of viewport.
897 */
898 int_part = dc_fixpt_floor(*init);
899 if (int_part < taps) {
900 int_part = taps - int_part;
901 if (int_part > *vp_offset)
902 int_part = *vp_offset;
903 *vp_offset -= int_part;
904 *init = dc_fixpt_add_int(*init, int_part);
b2d0a103 905 }
6566cae7
DL
906 /*
907 * If taps are sampling outside of viewport at end of recout and there are more pixels
908 * available in the surface we should increase the viewport size, regardless set vp to
909 * only what is used.
910 */
911 temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
912 *vp_size = dc_fixpt_floor(temp);
913 if (*vp_size + *vp_offset > src_size)
914 *vp_size = src_size - *vp_offset;
915
916 /* We did all the math assuming we are scanning same direction as display does,
917 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
918 * is flipped we simply need to calculate offset from the other side of plane.
919 * Note that outside of viewport all scaling hardware works in recout space.
920 */
921 if (flip_scan_dir)
922 *vp_offset = src_size - *vp_offset - *vp_size;
9b6067c0 923}
9a08f51f 924
6566cae7 925static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
9b6067c0
DL
926{
927 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
928 const struct dc_stream_state *stream = pipe_ctx->stream;
929 struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
6566cae7 930 struct rect src = plane_state->src_rect;
9b6067c0 931 int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
6566cae7
DL
932 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
933 int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y;
9b6067c0 934 bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
6566cae7
DL
935
936 calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
937 /*
938 * recout full is what the recout would have been if we didnt clip
939 * the source plane at all. We only care about left(ro_lb) and top(ro_tb)
940 * offsets of recout within recout full because those are the directions
941 * we scan from and therefore the only ones that affect inits.
942 */
943 recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
944 * stream->dst.width / stream->src.width;
945 recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
946 * stream->dst.height / stream->src.height;
947 if (pipe_ctx->prev_odm_pipe && split_idx)
948 ro_lb = data->h_active * split_idx - recout_full_x;
949 else
950 ro_lb = data->recout.x - recout_full_x;
951 ro_tb = data->recout.y - recout_full_y;
952 ASSERT(ro_lb >= 0 && ro_tb >= 0);
9a08f51f 953
9b6067c0 954 /*
6566cae7 955 * Work in recout rotation since that requires less transformations
9b6067c0
DL
956 */
957 get_vp_scan_direction(
958 plane_state->rotation,
959 plane_state->horizontal_mirror,
960 &orthogonal_rotation,
961 &flip_vert_scan_dir,
962 &flip_horz_scan_dir);
963
9b6067c0 964 if (orthogonal_rotation) {
9b6067c0 965 swap(src.width, src.height);
6566cae7 966 swap(flip_vert_scan_dir, flip_horz_scan_dir);
9b6067c0 967 }
9a08f51f 968
6566cae7 969 calculate_init_and_vp(
9b6067c0 970 flip_horz_scan_dir,
6566cae7
DL
971 ro_lb,
972 data->recout.width,
973 src.width,
974 data->taps.h_taps,
975 data->ratios.horz,
976 &data->inits.h,
9b6067c0
DL
977 &data->viewport.x,
978 &data->viewport.width);
6566cae7 979 calculate_init_and_vp(
9b6067c0 980 flip_horz_scan_dir,
6566cae7
DL
981 ro_lb,
982 data->recout.width,
983 src.width / vpc_div,
984 data->taps.h_taps_c,
985 data->ratios.horz_c,
986 &data->inits.h_c,
9b6067c0
DL
987 &data->viewport_c.x,
988 &data->viewport_c.width);
6566cae7 989 calculate_init_and_vp(
9b6067c0 990 flip_vert_scan_dir,
6566cae7
DL
991 ro_tb,
992 data->recout.height,
993 src.height,
994 data->taps.v_taps,
995 data->ratios.vert,
996 &data->inits.v,
9b6067c0
DL
997 &data->viewport.y,
998 &data->viewport.height);
6566cae7 999 calculate_init_and_vp(
9b6067c0 1000 flip_vert_scan_dir,
6566cae7
DL
1001 ro_tb,
1002 data->recout.height,
1003 src.height / vpc_div,
1004 data->taps.v_taps_c,
1005 data->ratios.vert_c,
1006 &data->inits.v_c,
9b6067c0
DL
1007 &data->viewport_c.y,
1008 &data->viewport_c.height);
6566cae7
DL
1009 if (orthogonal_rotation) {
1010 swap(data->viewport.x, data->viewport.y);
1011 swap(data->viewport.width, data->viewport.height);
1012 swap(data->viewport_c.x, data->viewport_c.y);
1013 swap(data->viewport_c.width, data->viewport_c.height);
89d07b66 1014 }
6566cae7
DL
1015 data->viewport.x += src.x;
1016 data->viewport.y += src.y;
1017 ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
1018 data->viewport_c.x += src.x / vpc_div;
1019 data->viewport_c.y += src.y / vpc_div;
89d07b66
ST
1020}
1021
b2d0a103 1022bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
4562236b 1023{
3be5262e 1024 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
4fa086b9 1025 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
b2d0a103 1026 bool res = false;
5d4b05dd 1027 DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
6566cae7 1028
6702a9ac 1029 pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
3be5262e 1030 pipe_ctx->plane_state->format);
b2d0a103 1031
6566cae7
DL
1032 /* Timing borders are part of vactive that we are also supposed to skip in addition
1033 * to any stream dst offset. Since dm logic assumes dst is in addressable
4dc8e494 1034 * space we need to add the left and top borders to dst offsets temporarily.
6566cae7
DL
1035 * TODO: fix in DM, stream dst is supposed to be in vactive
1036 */
1037 pipe_ctx->stream->dst.x += timing->h_border_left;
1038 pipe_ctx->stream->dst.y += timing->v_border_top;
4562236b 1039
6566cae7
DL
1040 /* Calculate H and V active size */
1041 pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable +
1042 timing->h_border_left + timing->h_border_right;
1043 pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable +
1044 timing->v_border_top + timing->v_border_bottom;
1045 if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe)
1046 pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1;
4562236b 1047
6566cae7 1048 /* depends on h_active */
9b6067c0 1049 calculate_recout(pipe_ctx);
6566cae7
DL
1050 /* depends on pixel format */
1051 calculate_scaling_ratios(pipe_ctx);
1052 /* depends on scaling ratios and recout, does not calculate offset yet */
1053 calculate_viewport_size(pipe_ctx);
4562236b 1054
e13c2ea2
JC
1055 /* Stopgap for validation of ODM + MPO on one side of screen case */
1056 if (pipe_ctx->plane_res.scl_data.viewport.height < 1 ||
1057 pipe_ctx->plane_res.scl_data.viewport.width < 1)
1058 return false;
1059
6566cae7
DL
1060 /*
1061 * LB calculations depend on vp size, h/v_active and scaling ratios
4562236b 1062 * Setting line buffer pixel depth to 24bpp yields banding
a316db72
MK
1063 * on certain displays, such as the Sharp 4k. 36bpp is needed
1064 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1065 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
72a7cf0a
MK
1066 * precision on at least DCN display engines. However, at least
1067 * Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
1068 * so use only 30 bpp on DCE_VERSION_11_0. Testing with DCE 11.2 and 8.3
1069 * did not show such problems, so this seems to be the exception.
4562236b 1070 */
353ca0fa 1071 if (plane_state->ctx->dce_version > DCE_VERSION_11_0)
72a7cf0a
MK
1072 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1073 else
1074 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1075
33eef72f 1076 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
4562236b 1077
d94585a0
YHL
1078 if (pipe_ctx->plane_res.xfm != NULL)
1079 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1080 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1081
1082 if (pipe_ctx->plane_res.dpp != NULL)
1083 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1084 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
f7938bc0 1085
f7938bc0 1086
4562236b
HW
1087 if (!res) {
1088 /* Try 24 bpp linebuffer */
6702a9ac 1089 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
4562236b 1090
1b6c8067
BL
1091 if (pipe_ctx->plane_res.xfm != NULL)
1092 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1093 pipe_ctx->plane_res.xfm,
1094 &pipe_ctx->plane_res.scl_data,
1095 &plane_state->scaling_quality);
1096
1097 if (pipe_ctx->plane_res.dpp != NULL)
1098 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1099 pipe_ctx->plane_res.dpp,
1100 &pipe_ctx->plane_res.scl_data,
1101 &plane_state->scaling_quality);
4562236b
HW
1102 }
1103
6566cae7
DL
1104 /*
1105 * Depends on recout, scaling ratios, h_active and taps
1106 * May need to re-check lb size after this in some obscure scenario
1107 */
b2d0a103 1108 if (res)
6566cae7
DL
1109 calculate_inits_and_viewports(pipe_ctx);
1110
1111 /*
1112 * Handle side by side and top bottom 3d recout offsets after vp calculation
1113 * since 3d is special and needs to calculate vp as if there is no recout offset
1114 * This may break with rotation, good thing we aren't mixing hw rotation and 3d
1115 */
1116 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
1117 ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
1118 (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
1119 pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
1120 if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1121 pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
1122 else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1123 pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
1124 }
1125
1126 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE ||
1127 pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1128 res = false;
b2d0a103 1129
3c0dcf9f
DL
1130 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"
1131 "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",
1132 __func__,
1133 pipe_ctx->pipe_idx,
1134 pipe_ctx->plane_res.scl_data.viewport.height,
1135 pipe_ctx->plane_res.scl_data.viewport.width,
1136 pipe_ctx->plane_res.scl_data.viewport.x,
1137 pipe_ctx->plane_res.scl_data.viewport.y,
1138 pipe_ctx->plane_res.scl_data.recout.height,
1139 pipe_ctx->plane_res.scl_data.recout.width,
1140 pipe_ctx->plane_res.scl_data.recout.x,
1141 pipe_ctx->plane_res.scl_data.recout.y,
1142 pipe_ctx->plane_res.scl_data.h_active,
1143 pipe_ctx->plane_res.scl_data.v_active,
1144 plane_state->src_rect.height,
1145 plane_state->src_rect.width,
1146 plane_state->src_rect.x,
1147 plane_state->src_rect.y,
1148 plane_state->dst_rect.height,
1149 plane_state->dst_rect.width,
1150 plane_state->dst_rect.x,
1151 plane_state->dst_rect.y,
1152 plane_state->clip_rect.height,
1153 plane_state->clip_rect.width,
1154 plane_state->clip_rect.x,
1155 plane_state->clip_rect.y);
4562236b 1156
6566cae7
DL
1157 pipe_ctx->stream->dst.x -= timing->h_border_left;
1158 pipe_ctx->stream->dst.y -= timing->v_border_top;
89d07b66 1159
4562236b
HW
1160 return res;
1161}
1162
1163
1164enum dc_status resource_build_scaling_params_for_context(
fb3466a4 1165 const struct dc *dc,
608ac7bb 1166 struct dc_state *context)
4562236b
HW
1167{
1168 int i;
1169
1170 for (i = 0; i < MAX_PIPES; i++) {
3be5262e 1171 if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
4562236b 1172 context->res_ctx.pipe_ctx[i].stream != NULL)
b2d0a103 1173 if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
f84a8161 1174 return DC_FAIL_SCALING;
4562236b
HW
1175 }
1176
1177 return DC_OK;
1178}
1179
a2b8659d
TC
1180struct pipe_ctx *find_idle_secondary_pipe(
1181 struct resource_context *res_ctx,
5581192d
JL
1182 const struct resource_pool *pool,
1183 const struct pipe_ctx *primary_pipe)
4562236b
HW
1184{
1185 int i;
1186 struct pipe_ctx *secondary_pipe = NULL;
1187
1188 /*
5581192d
JL
1189 * We add a preferred pipe mapping to avoid the chance that
1190 * MPCCs already in use will need to be reassigned to other trees.
1191 * For example, if we went with the strict, assign backwards logic:
1192 *
1193 * (State 1)
1194 * Display A on, no surface, top pipe = 0
1195 * Display B on, no surface, top pipe = 1
1196 *
1197 * (State 2)
1198 * Display A on, no surface, top pipe = 0
1199 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1200 *
1201 * (State 3)
1202 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1203 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1204 *
1205 * The state 2->3 transition requires remapping MPCC 5 from display B
1206 * to display A.
1207 *
1208 * However, with the preferred pipe logic, state 2 would look like:
1209 *
1210 * (State 2)
1211 * Display A on, no surface, top pipe = 0
1212 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1213 *
1214 * This would then cause 2->3 to not require remapping any MPCCs.
4562236b 1215 */
5581192d
JL
1216 if (primary_pipe) {
1217 int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
1218 if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
1219 secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
1220 secondary_pipe->pipe_idx = preferred_pipe_idx;
4562236b
HW
1221 }
1222 }
1223
5581192d
JL
1224 /*
1225 * search backwards for the second pipe to keep pipe
1226 * assignment more consistent
1227 */
1228 if (!secondary_pipe)
1229 for (i = pool->pipe_count - 1; i >= 0; i--) {
1230 if (res_ctx->pipe_ctx[i].stream == NULL) {
1231 secondary_pipe = &res_ctx->pipe_ctx[i];
1232 secondary_pipe->pipe_idx = i;
1233 break;
1234 }
1235 }
4562236b
HW
1236
1237 return secondary_pipe;
1238}
1239
1240struct pipe_ctx *resource_get_head_pipe_for_stream(
1241 struct resource_context *res_ctx,
0971c40e 1242 struct dc_stream_state *stream)
4562236b
HW
1243{
1244 int i;
22498036 1245
a2b8659d 1246 for (i = 0; i < MAX_PIPES; i++) {
b1f6d01c
DL
1247 if (res_ctx->pipe_ctx[i].stream == stream
1248 && !res_ctx->pipe_ctx[i].top_pipe
22498036 1249 && !res_ctx->pipe_ctx[i].prev_odm_pipe)
4562236b 1250 return &res_ctx->pipe_ctx[i];
4562236b
HW
1251 }
1252 return NULL;
1253}
1254
b1f6d01c 1255static struct pipe_ctx *resource_get_tail_pipe(
19f89e23 1256 struct resource_context *res_ctx,
b1f6d01c 1257 struct pipe_ctx *head_pipe)
19f89e23 1258{
b1f6d01c 1259 struct pipe_ctx *tail_pipe;
19f89e23
AG
1260
1261 tail_pipe = head_pipe->bottom_pipe;
1262
1263 while (tail_pipe) {
1264 head_pipe = tail_pipe;
1265 tail_pipe = tail_pipe->bottom_pipe;
1266 }
1267
1268 return head_pipe;
1269}
1270
4562236b 1271/*
ab2541b6
AC
1272 * A free_pipe for a stream is defined here as a pipe
1273 * that has no surface attached yet
4562236b 1274 */
b1f6d01c 1275static struct pipe_ctx *acquire_free_pipe_for_head(
608ac7bb 1276 struct dc_state *context,
a2b8659d 1277 const struct resource_pool *pool,
b1f6d01c 1278 struct pipe_ctx *head_pipe)
4562236b
HW
1279{
1280 int i;
745cc746 1281 struct resource_context *res_ctx = &context->res_ctx;
4562236b 1282
3be5262e 1283 if (!head_pipe->plane_state)
4562236b
HW
1284 return head_pipe;
1285
1286 /* Re-use pipe already acquired for this stream if available*/
a2b8659d 1287 for (i = pool->pipe_count - 1; i >= 0; i--) {
b1f6d01c 1288 if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
3be5262e 1289 !res_ctx->pipe_ctx[i].plane_state) {
4562236b
HW
1290 return &res_ctx->pipe_ctx[i];
1291 }
1292 }
1293
1294 /*
1295 * At this point we have no re-useable pipe for this stream and we need
1296 * to acquire an idle one to satisfy the request
1297 */
1298
a2b8659d 1299 if (!pool->funcs->acquire_idle_pipe_for_layer)
4562236b
HW
1300 return NULL;
1301
b1f6d01c 1302 return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
4562236b
HW
1303}
1304
b86a1aa3 1305#if defined(CONFIG_DRM_AMD_DC_DCN)
0f9a536f
DL
1306static int acquire_first_split_pipe(
1307 struct resource_context *res_ctx,
1308 const struct resource_pool *pool,
0971c40e 1309 struct dc_stream_state *stream)
0f9a536f
DL
1310{
1311 int i;
1312
1313 for (i = 0; i < pool->pipe_count; i++) {
79592db3
DL
1314 struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
1315
b1f6d01c 1316 if (split_pipe->top_pipe &&
79592db3
DL
1317 split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
1318 split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
1319 if (split_pipe->bottom_pipe)
1320 split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
1321
1322 if (split_pipe->top_pipe->plane_state)
1323 resource_build_scaling_params(split_pipe->top_pipe);
1324
1325 memset(split_pipe, 0, sizeof(*split_pipe));
1326 split_pipe->stream_res.tg = pool->timing_generators[i];
1327 split_pipe->plane_res.hubp = pool->hubps[i];
1328 split_pipe->plane_res.ipp = pool->ipps[i];
1329 split_pipe->plane_res.dpp = pool->dpps[i];
1330 split_pipe->stream_res.opp = pool->opps[i];
1331 split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
1332 split_pipe->pipe_idx = i;
1333
1334 split_pipe->stream = stream;
0f9a536f
DL
1335 return i;
1336 }
1337 }
1338 return -1;
1339}
1340#endif
1341
19f89e23
AG
1342bool dc_add_plane_to_context(
1343 const struct dc *dc,
0971c40e 1344 struct dc_stream_state *stream,
19f89e23 1345 struct dc_plane_state *plane_state,
608ac7bb 1346 struct dc_state *context)
4562236b
HW
1347{
1348 int i;
19f89e23
AG
1349 struct resource_pool *pool = dc->res_pool;
1350 struct pipe_ctx *head_pipe, *tail_pipe, *free_pipe;
ab2541b6 1351 struct dc_stream_status *stream_status = NULL;
4562236b 1352
19f89e23
AG
1353 for (i = 0; i < context->stream_count; i++)
1354 if (context->streams[i] == stream) {
1355 stream_status = &context->stream_status[i];
1356 break;
1357 }
1358 if (stream_status == NULL) {
1359 dm_error("Existing stream not found; failed to attach surface!\n");
1360 return false;
1361 }
1362
4562236b 1363
19f89e23
AG
1364 if (stream_status->plane_count == MAX_SURFACE_NUM) {
1365 dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n",
1366 plane_state, MAX_SURFACE_NUM);
4562236b
HW
1367 return false;
1368 }
1369
19f89e23
AG
1370 head_pipe = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
1371
1372 if (!head_pipe) {
1373 dm_error("Head pipe not found for stream_state %p !\n", stream);
1374 return false;
1375 }
1376
b1f6d01c
DL
1377 /* retain new surface, but only once per stream */
1378 dc_plane_state_retain(plane_state);
00737c59 1379
b1f6d01c 1380 while (head_pipe) {
b1f6d01c 1381 free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
19f89e23 1382
b86a1aa3 1383 #if defined(CONFIG_DRM_AMD_DC_DCN)
b1f6d01c
DL
1384 if (!free_pipe) {
1385 int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
1386 if (pipe_idx >= 0)
1387 free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
1388 }
1389 #endif
1390 if (!free_pipe) {
1391 dc_plane_state_release(plane_state);
1392 return false;
1393 }
19f89e23 1394
b1f6d01c
DL
1395 free_pipe->plane_state = plane_state;
1396
1397 if (head_pipe != free_pipe) {
5b5c1777
JP
1398 tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
1399 ASSERT(tail_pipe);
b1f6d01c
DL
1400 free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
1401 free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
1402 free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
1403 free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
1404 free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
1405 free_pipe->clock_source = tail_pipe->clock_source;
1406 free_pipe->top_pipe = tail_pipe;
1407 tail_pipe->bottom_pipe = free_pipe;
2e7b43e6
DL
1408 if (!free_pipe->next_odm_pipe && tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) {
1409 free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe;
1410 tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe;
1411 }
1412 if (!free_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) {
1413 free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
1414 tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe;
1415 }
b1f6d01c
DL
1416 }
1417 head_pipe = head_pipe->next_odm_pipe;
1418 }
19f89e23
AG
1419 /* assign new surfaces*/
1420 stream_status->plane_states[stream_status->plane_count] = plane_state;
1421
1422 stream_status->plane_count++;
1423
1424 return true;
1425}
1426
1427bool dc_remove_plane_from_context(
1428 const struct dc *dc,
1429 struct dc_stream_state *stream,
1430 struct dc_plane_state *plane_state,
608ac7bb 1431 struct dc_state *context)
19f89e23
AG
1432{
1433 int i;
1434 struct dc_stream_status *stream_status = NULL;
1435 struct resource_pool *pool = dc->res_pool;
1436
ab2541b6 1437 for (i = 0; i < context->stream_count; i++)
4fa086b9 1438 if (context->streams[i] == stream) {
ab2541b6 1439 stream_status = &context->stream_status[i];
4562236b
HW
1440 break;
1441 }
19f89e23 1442
ab2541b6 1443 if (stream_status == NULL) {
19f89e23 1444 dm_error("Existing stream not found; failed to remove plane.\n");
4562236b
HW
1445 return false;
1446 }
1447
19f89e23
AG
1448 /* release pipe for plane*/
1449 for (i = pool->pipe_count - 1; i >= 0; i--) {
6ffaa6fc 1450 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
4562236b 1451
6ffaa6fc 1452 if (pipe_ctx->plane_state == plane_state) {
19f89e23
AG
1453 if (pipe_ctx->top_pipe)
1454 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
4562236b 1455
19f89e23
AG
1456 /* Second condition is to avoid setting NULL to top pipe
1457 * of tail pipe making it look like head pipe in subsequent
1458 * deletes
1459 */
1460 if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
1461 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
4562236b 1462
19f89e23
AG
1463 /*
1464 * For head pipe detach surfaces from pipe for tail
1465 * pipe just zero it out
1466 */
b1f6d01c 1467 if (!pipe_ctx->top_pipe)
19f89e23 1468 pipe_ctx->plane_state = NULL;
b1f6d01c 1469 else
19f89e23 1470 memset(pipe_ctx, 0, sizeof(*pipe_ctx));
4562236b 1471 }
19f89e23 1472 }
4562236b 1473
4562236b 1474
19f89e23
AG
1475 for (i = 0; i < stream_status->plane_count; i++) {
1476 if (stream_status->plane_states[i] == plane_state) {
1477
1478 dc_plane_state_release(stream_status->plane_states[i]);
1479 break;
4562236b 1480 }
19f89e23 1481 }
4562236b 1482
19f89e23
AG
1483 if (i == stream_status->plane_count) {
1484 dm_error("Existing plane_state not found; failed to detach it!\n");
1485 return false;
4562236b
HW
1486 }
1487
19f89e23 1488 stream_status->plane_count--;
4562236b 1489
abb4986e
AJ
1490 /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
1491 for (; i < stream_status->plane_count; i++)
19f89e23
AG
1492 stream_status->plane_states[i] = stream_status->plane_states[i + 1];
1493
1494 stream_status->plane_states[stream_status->plane_count] = NULL;
1495
1496 return true;
1497}
1498
1499bool dc_rem_all_planes_for_stream(
1500 const struct dc *dc,
1501 struct dc_stream_state *stream,
608ac7bb 1502 struct dc_state *context)
19f89e23
AG
1503{
1504 int i, old_plane_count;
1505 struct dc_stream_status *stream_status = NULL;
1506 struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
1507
1508 for (i = 0; i < context->stream_count; i++)
1509 if (context->streams[i] == stream) {
1510 stream_status = &context->stream_status[i];
1511 break;
1512 }
1513
1514 if (stream_status == NULL) {
1515 dm_error("Existing stream %p not found!\n", stream);
1516 return false;
1517 }
1518
1519 old_plane_count = stream_status->plane_count;
1520
1521 for (i = 0; i < old_plane_count; i++)
1522 del_planes[i] = stream_status->plane_states[i];
1523
1524 for (i = 0; i < old_plane_count; i++)
1525 if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context))
1526 return false;
1527
1528 return true;
1529}
1530
1531static bool add_all_planes_for_stream(
1532 const struct dc *dc,
1533 struct dc_stream_state *stream,
1534 const struct dc_validation_set set[],
1535 int set_count,
608ac7bb 1536 struct dc_state *context)
19f89e23
AG
1537{
1538 int i, j;
1539
1540 for (i = 0; i < set_count; i++)
1541 if (set[i].stream == stream)
1542 break;
1543
1544 if (i == set_count) {
1545 dm_error("Stream %p not found in set!\n", stream);
1546 return false;
1547 }
4562236b 1548
19f89e23
AG
1549 for (j = 0; j < set[i].plane_count; j++)
1550 if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context))
1551 return false;
4562236b
HW
1552
1553 return true;
1554}
1555
19f89e23
AG
1556bool dc_add_all_planes_for_stream(
1557 const struct dc *dc,
1558 struct dc_stream_state *stream,
1559 struct dc_plane_state * const *plane_states,
1560 int plane_count,
608ac7bb 1561 struct dc_state *context)
19f89e23
AG
1562{
1563 struct dc_validation_set set;
1564 int i;
1565
1566 set.stream = stream;
1567 set.plane_count = plane_count;
1568
1569 for (i = 0; i < plane_count; i++)
1570 set.plane_states[i] = plane_states[i];
1571
1572 return add_all_planes_for_stream(dc, stream, &set, 1, context);
1573}
1574
0971c40e
HW
1575static bool is_timing_changed(struct dc_stream_state *cur_stream,
1576 struct dc_stream_state *new_stream)
4562236b
HW
1577{
1578 if (cur_stream == NULL)
1579 return true;
1580
4562236b 1581 /* If output color space is changed, need to reprogram info frames */
4fa086b9 1582 if (cur_stream->output_color_space != new_stream->output_color_space)
4562236b
HW
1583 return true;
1584
1585 return memcmp(
4fa086b9
LSL
1586 &cur_stream->timing,
1587 &new_stream->timing,
4562236b
HW
1588 sizeof(struct dc_crtc_timing)) != 0;
1589}
1590
1591static bool are_stream_backends_same(
0971c40e 1592 struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
4562236b
HW
1593{
1594 if (stream_a == stream_b)
1595 return true;
1596
1597 if (stream_a == NULL || stream_b == NULL)
1598 return false;
1599
1600 if (is_timing_changed(stream_a, stream_b))
1601 return false;
1602
e82bf9da
DZ
1603 if (stream_a->signal != stream_b->signal)
1604 return false;
1605
1e7e86c4
ST
1606 if (stream_a->dpms_off != stream_b->dpms_off)
1607 return false;
1608
4562236b
HW
1609 return true;
1610}
1611
625a15bf 1612/*
2119aa17
DF
1613 * dc_is_stream_unchanged() - Compare two stream states for equivalence.
1614 *
1615 * Checks if there a difference between the two states
1616 * that would require a mode change.
1617 *
1618 * Does not compare cursor position or attributes.
1619 */
d54d29db 1620bool dc_is_stream_unchanged(
0971c40e 1621 struct dc_stream_state *old_stream, struct dc_stream_state *stream)
4562236b 1622{
4562236b 1623
ab2541b6
AC
1624 if (!are_stream_backends_same(old_stream, stream))
1625 return false;
4562236b 1626
0460f9ab
JL
1627 if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
1628 return false;
1629
c6a25011
CL
1630 /*compare audio info*/
1631 if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
a9c93b1e
MG
1632 return false;
1633
4562236b
HW
1634 return true;
1635}
1636
625a15bf 1637/*
2119aa17
DF
1638 * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
1639 */
9a5d9c48
LSL
1640bool dc_is_stream_scaling_unchanged(
1641 struct dc_stream_state *old_stream, struct dc_stream_state *stream)
1642{
1643 if (old_stream == stream)
1644 return true;
1645
1646 if (old_stream == NULL || stream == NULL)
1647 return false;
1648
1649 if (memcmp(&old_stream->src,
1650 &stream->src,
1651 sizeof(struct rect)) != 0)
1652 return false;
1653
1654 if (memcmp(&old_stream->dst,
1655 &stream->dst,
1656 sizeof(struct rect)) != 0)
1657 return false;
1658
1659 return true;
1660}
1661
1dc90497 1662static void update_stream_engine_usage(
4562236b 1663 struct resource_context *res_ctx,
a2b8659d 1664 const struct resource_pool *pool,
1dc90497
AG
1665 struct stream_encoder *stream_enc,
1666 bool acquired)
4562236b
HW
1667{
1668 int i;
1669
a2b8659d
TC
1670 for (i = 0; i < pool->stream_enc_count; i++) {
1671 if (pool->stream_enc[i] == stream_enc)
1dc90497 1672 res_ctx->is_stream_enc_acquired[i] = acquired;
4562236b
HW
1673 }
1674}
1675
1676/* TODO: release audio object */
4176664b 1677void update_audio_usage(
4562236b 1678 struct resource_context *res_ctx,
a2b8659d 1679 const struct resource_pool *pool,
1dc90497
AG
1680 struct audio *audio,
1681 bool acquired)
4562236b
HW
1682{
1683 int i;
a2b8659d
TC
1684 for (i = 0; i < pool->audio_count; i++) {
1685 if (pool->audios[i] == audio)
1dc90497 1686 res_ctx->is_audio_acquired[i] = acquired;
4562236b
HW
1687 }
1688}
1689
1690static int acquire_first_free_pipe(
1691 struct resource_context *res_ctx,
a2b8659d 1692 const struct resource_pool *pool,
0971c40e 1693 struct dc_stream_state *stream)
4562236b
HW
1694{
1695 int i;
1696
a2b8659d 1697 for (i = 0; i < pool->pipe_count; i++) {
4562236b
HW
1698 if (!res_ctx->pipe_ctx[i].stream) {
1699 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
1700
6b670fa9 1701 pipe_ctx->stream_res.tg = pool->timing_generators[i];
86a66c4e 1702 pipe_ctx->plane_res.mi = pool->mis[i];
8feabd03 1703 pipe_ctx->plane_res.hubp = pool->hubps[i];
86a66c4e
HW
1704 pipe_ctx->plane_res.ipp = pool->ipps[i];
1705 pipe_ctx->plane_res.xfm = pool->transforms[i];
d94585a0 1706 pipe_ctx->plane_res.dpp = pool->dpps[i];
a6a6cb34 1707 pipe_ctx->stream_res.opp = pool->opps[i];
bc373a89
RL
1708 if (pool->dpps[i])
1709 pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst;
4562236b
HW
1710 pipe_ctx->pipe_idx = i;
1711
ff5ef992 1712
4562236b
HW
1713 pipe_ctx->stream = stream;
1714 return i;
1715 }
1716 }
1717 return -1;
1718}
1719
a2b8659d
TC
1720static struct audio *find_first_free_audio(
1721 struct resource_context *res_ctx,
cfb071f7 1722 const struct resource_pool *pool,
f24b0522
PH
1723 enum engine_id id,
1724 enum dce_version dc_version)
4562236b 1725{
b5a41620
CL
1726 int i, available_audio_count;
1727
1728 available_audio_count = pool->audio_count;
1729
1730 for (i = 0; i < available_audio_count; i++) {
66bfd4fd 1731 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
cfb071f7
CL
1732 /*we have enough audio endpoint, find the matching inst*/
1733 if (id != i)
1734 continue;
66bfd4fd 1735 return pool->audios[i];
4562236b 1736 }
66bfd4fd 1737 }
5feb9f07 1738
b5a41620
CL
1739 /* use engine id to find free audio */
1740 if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
5feb9f07
TM
1741 return pool->audios[id];
1742 }
66bfd4fd 1743 /*not found the matching one, first come first serve*/
b5a41620 1744 for (i = 0; i < available_audio_count; i++) {
66bfd4fd
CL
1745 if (res_ctx->is_audio_acquired[i] == false) {
1746 return pool->audios[i];
4176664b
CL
1747 }
1748 }
4562236b
HW
1749 return 0;
1750}
1751
625a15bf 1752/*
2119aa17
DF
1753 * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state.
1754 */
13ab1b44 1755enum dc_status dc_add_stream_to_ctx(
1dc90497 1756 struct dc *dc,
608ac7bb 1757 struct dc_state *new_ctx,
1dc90497
AG
1758 struct dc_stream_state *stream)
1759{
1dc90497 1760 enum dc_status res;
eb9714a2 1761 DC_LOGGER_INIT(dc->ctx->logger);
1dc90497 1762
ece4147f 1763 if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) {
eb9714a2 1764 DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream);
1dc90497
AG
1765 return DC_ERROR_UNEXPECTED;
1766 }
1767
1768 new_ctx->streams[new_ctx->stream_count] = stream;
1769 dc_stream_retain(stream);
1770 new_ctx->stream_count++;
1771
1772 res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
1773 if (res != DC_OK)
eb9714a2 1774 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res);
1dc90497 1775
13ab1b44 1776 return res;
1dc90497
AG
1777}
1778
625a15bf 1779/*
2119aa17
DF
1780 * dc_remove_stream_from_ctx() - Remove a stream from a dc_state.
1781 */
62c933f9 1782enum dc_status dc_remove_stream_from_ctx(
1dc90497 1783 struct dc *dc,
608ac7bb 1784 struct dc_state *new_ctx,
1dc90497
AG
1785 struct dc_stream_state *stream)
1786{
19f89e23 1787 int i;
1dc90497 1788 struct dc_context *dc_ctx = dc->ctx;
22498036
DL
1789 struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
1790 struct pipe_ctx *odm_pipe;
1dc90497
AG
1791
1792 if (!del_pipe) {
1793 DC_ERROR("Pipe not found for stream %p !\n", stream);
1794 return DC_ERROR_UNEXPECTED;
1795 }
1796
22498036
DL
1797 odm_pipe = del_pipe->next_odm_pipe;
1798
1799 /* Release primary pipe */
1800 ASSERT(del_pipe->stream_res.stream_enc);
1801 update_stream_engine_usage(
1802 &new_ctx->res_ctx,
1803 dc->res_pool,
1804 del_pipe->stream_res.stream_enc,
1805 false);
1806
1807 if (del_pipe->stream_res.audio)
1808 update_audio_usage(
1809 &new_ctx->res_ctx,
1810 dc->res_pool,
1811 del_pipe->stream_res.audio,
1812 false);
1813
1814 resource_unreference_clock_source(&new_ctx->res_ctx,
1815 dc->res_pool,
1816 del_pipe->clock_source);
1817
1818 if (dc->res_pool->funcs->remove_stream_from_ctx)
1819 dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
1820
1821 while (odm_pipe) {
1822 struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
1823
1824 memset(odm_pipe, 0, sizeof(*odm_pipe));
1825 odm_pipe = next_odm_pipe;
1826 }
1827 memset(del_pipe, 0, sizeof(*del_pipe));
1828
1dc90497
AG
1829 for (i = 0; i < new_ctx->stream_count; i++)
1830 if (new_ctx->streams[i] == stream)
1831 break;
1832
1833 if (new_ctx->streams[i] != stream) {
1834 DC_ERROR("Context doesn't have stream %p !\n", stream);
1835 return DC_ERROR_UNEXPECTED;
1836 }
1837
1838 dc_stream_release(new_ctx->streams[i]);
1839 new_ctx->stream_count--;
1840
1dc90497
AG
1841 /* Trim back arrays */
1842 for (; i < new_ctx->stream_count; i++) {
1843 new_ctx->streams[i] = new_ctx->streams[i + 1];
1844 new_ctx->stream_status[i] = new_ctx->stream_status[i + 1];
1845 }
1846
1847 new_ctx->streams[new_ctx->stream_count] = NULL;
1848 memset(
1849 &new_ctx->stream_status[new_ctx->stream_count],
1850 0,
1851 sizeof(new_ctx->stream_status[0]));
1852
1853 return DC_OK;
1854}
1855
0971c40e
HW
1856static struct dc_stream_state *find_pll_sharable_stream(
1857 struct dc_stream_state *stream_needs_pll,
608ac7bb 1858 struct dc_state *context)
4562236b 1859{
ab2541b6 1860 int i;
4562236b 1861
ab2541b6 1862 for (i = 0; i < context->stream_count; i++) {
0971c40e 1863 struct dc_stream_state *stream_has_pll = context->streams[i];
4562236b 1864
ab2541b6
AC
1865 /* We are looking for non dp, non virtual stream */
1866 if (resource_are_streams_timing_synchronizable(
1867 stream_needs_pll, stream_has_pll)
1868 && !dc_is_dp_signal(stream_has_pll->signal)
ceb3dbb4 1869 && stream_has_pll->link->connector_signal
ab2541b6
AC
1870 != SIGNAL_TYPE_VIRTUAL)
1871 return stream_has_pll;
4562236b 1872
4562236b
HW
1873 }
1874
1875 return NULL;
1876}
1877
1878static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
1879{
380604e2 1880 uint32_t pix_clk = timing->pix_clk_100hz;
4562236b
HW
1881 uint32_t normalized_pix_clk = pix_clk;
1882
1883 if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
1884 pix_clk /= 2;
cc4d99b8
CL
1885 if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
1886 switch (timing->display_color_depth) {
8897810a 1887 case COLOR_DEPTH_666:
cc4d99b8
CL
1888 case COLOR_DEPTH_888:
1889 normalized_pix_clk = pix_clk;
1890 break;
1891 case COLOR_DEPTH_101010:
1892 normalized_pix_clk = (pix_clk * 30) / 24;
1893 break;
1894 case COLOR_DEPTH_121212:
1895 normalized_pix_clk = (pix_clk * 36) / 24;
4562236b 1896 break;
cc4d99b8
CL
1897 case COLOR_DEPTH_161616:
1898 normalized_pix_clk = (pix_clk * 48) / 24;
4562236b 1899 break;
cc4d99b8
CL
1900 default:
1901 ASSERT(0);
4562236b 1902 break;
cc4d99b8 1903 }
4562236b 1904 }
4562236b
HW
1905 return normalized_pix_clk;
1906}
1907
0971c40e 1908static void calculate_phy_pix_clks(struct dc_stream_state *stream)
4562236b 1909{
9345d987
AG
1910 /* update actual pixel clock on all streams */
1911 if (dc_is_hdmi_signal(stream->signal))
1912 stream->phy_pix_clk = get_norm_pix_clk(
380604e2 1913 &stream->timing) / 10;
9345d987
AG
1914 else
1915 stream->phy_pix_clk =
380604e2 1916 stream->timing.pix_clk_100hz / 10;
39c03e00
CL
1917
1918 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
1919 stream->phy_pix_clk *= 2;
4562236b
HW
1920}
1921
d2d7885f
AK
1922static int acquire_resource_from_hw_enabled_state(
1923 struct resource_context *res_ctx,
1924 const struct resource_pool *pool,
1925 struct dc_stream_state *stream)
1926{
1927 struct dc_link *link = stream->link;
08b66279 1928 unsigned int i, inst, tg_inst = 0;
d2d7885f
AK
1929
1930 /* Check for enabled DIG to identify enabled display */
1931 if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
1932 return -1;
1933
5ec43eda 1934 inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
d2d7885f 1935
7f7652ee 1936 if (inst == ENGINE_ID_UNKNOWN)
75441d9d 1937 return -1;
d2d7885f 1938
7f7652ee
ML
1939 for (i = 0; i < pool->stream_enc_count; i++) {
1940 if (pool->stream_enc[i]->id == inst) {
1941 tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
1942 pool->stream_enc[i]);
1943 break;
1944 }
1945 }
5ec43eda 1946
7f7652ee
ML
1947 // tg_inst not found
1948 if (i == pool->stream_enc_count)
75441d9d 1949 return -1;
5ec43eda
ML
1950
1951 if (tg_inst >= pool->timing_generator_count)
75441d9d 1952 return -1;
5ec43eda
ML
1953
1954 if (!res_ctx->pipe_ctx[tg_inst].stream) {
1955 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
1956
1957 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
1958 pipe_ctx->plane_res.mi = pool->mis[tg_inst];
1959 pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
1960 pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
1961 pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
1962 pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
1963 pipe_ctx->stream_res.opp = pool->opps[tg_inst];
d2d7885f 1964
ccce745c 1965 if (pool->dpps[tg_inst]) {
5ec43eda 1966 pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
ccce745c
ML
1967
1968 // Read DPP->MPCC->OPP Pipe from HW State
1969 if (pool->mpc->funcs->read_mpcc_state) {
1970 struct mpcc_state s = {0};
1971
1972 pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
1973
1974 if (s.dpp_id < MAX_MPCC)
1975 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = s.dpp_id;
1976
1977 if (s.bot_mpcc_id < MAX_MPCC)
1978 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
1979 &pool->mpc->mpcc_array[s.bot_mpcc_id];
1980
1981 if (s.opp_id < MAX_OPP)
1982 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
1983 }
1984 }
5ec43eda 1985 pipe_ctx->pipe_idx = tg_inst;
d2d7885f
AK
1986
1987 pipe_ctx->stream = stream;
5ec43eda 1988 return tg_inst;
d2d7885f
AK
1989 }
1990
1991 return -1;
1992}
1993
96b5e3e1
RY
1994static void mark_seamless_boot_stream(
1995 const struct dc *dc,
1996 struct dc_stream_state *stream)
1997{
1998 struct dc_bios *dcb = dc->ctx->dc_bios;
1999
2000 /* TODO: Check Linux */
2001 if (dc->config.allow_seamless_boot_optimization &&
2002 !dcb->funcs->is_accelerated_mode(dcb)) {
2003 if (dc_validate_seamless_boot_timing(dc, stream->sink, &stream->timing))
2004 stream->apply_seamless_boot_optimization = true;
2005 }
2006}
2007
4562236b 2008enum dc_status resource_map_pool_resources(
fb3466a4 2009 const struct dc *dc,
608ac7bb 2010 struct dc_state *context,
1dc90497 2011 struct dc_stream_state *stream)
4562236b 2012{
a2b8659d 2013 const struct resource_pool *pool = dc->res_pool;
1dc90497
AG
2014 int i;
2015 struct dc_context *dc_ctx = dc->ctx;
2016 struct pipe_ctx *pipe_ctx = NULL;
2017 int pipe_idx = -1;
4562236b 2018
08e1c28d
YMM
2019 calculate_phy_pix_clks(stream);
2020
96b5e3e1 2021 mark_seamless_boot_stream(dc, stream);
46570f09 2022
96b5e3e1 2023 if (stream->apply_seamless_boot_optimization) {
d2d7885f
AK
2024 pipe_idx = acquire_resource_from_hw_enabled_state(
2025 &context->res_ctx,
2026 pool,
2027 stream);
96b5e3e1
RY
2028 if (pipe_idx < 0)
2029 /* hw resource was assigned to other stream */
2030 stream->apply_seamless_boot_optimization = false;
2031 }
d2d7885f
AK
2032
2033 if (pipe_idx < 0)
2034 /* acquire new resources */
2035 pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
8c737fcc 2036
b86a1aa3 2037#ifdef CONFIG_DRM_AMD_DC_DCN
1dc90497 2038 if (pipe_idx < 0)
13ab1b44 2039 pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
94c6d735 2040#endif
13ab1b44 2041
c5b38aec 2042 if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL)
1dc90497
AG
2043 return DC_NO_CONTROLLER_RESOURCE;
2044
2045 pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
2046
2047 pipe_ctx->stream_res.stream_enc =
78cc70b1 2048 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
1dc90497
AG
2049 &context->res_ctx, pool, stream);
2050
2051 if (!pipe_ctx->stream_res.stream_enc)
38684e46 2052 return DC_NO_STREAM_ENC_RESOURCE;
1dc90497
AG
2053
2054 update_stream_engine_usage(
2055 &context->res_ctx, pool,
2056 pipe_ctx->stream_res.stream_enc,
2057 true);
2058
2059 /* TODO: Add check if ASIC support and EDID audio */
ceb3dbb4 2060 if (!stream->converter_disable_audio &&
1dc90497 2061 dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
ce08aad3 2062 stream->audio_info.mode_count && stream->audio_info.flags.all) {
1dc90497 2063 pipe_ctx->stream_res.audio = find_first_free_audio(
f24b0522 2064 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
1dc90497
AG
2065
2066 /*
2067 * Audio assigned in order first come first get.
2068 * There are asics which has number of audio
2069 * resources less then number of pipes
2070 */
2071 if (pipe_ctx->stream_res.audio)
2072 update_audio_usage(&context->res_ctx, pool,
2073 pipe_ctx->stream_res.audio, true);
2074 }
268cadbd 2075
9aef1a31 2076 /* Add ABM to the resource if on EDP */
5dba4991 2077 if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
20f2ffe5 2078#if defined(CONFIG_DRM_AMD_DC_DCN)
5dba4991
BL
2079 if (pool->abm)
2080 pipe_ctx->stream_res.abm = pool->abm;
2081 else
2082 pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
2083#else
9aef1a31 2084 pipe_ctx->stream_res.abm = pool->abm;
5dba4991
BL
2085#endif
2086 }
9aef1a31 2087
1dc90497
AG
2088 for (i = 0; i < context->stream_count; i++)
2089 if (context->streams[i] == stream) {
2090 context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
3f0940f8 2091 context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
5fdb7c4c
NK
2092 context->stream_status[i].audio_inst =
2093 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
2094
1dc90497
AG
2095 return DC_OK;
2096 }
4562236b 2097
1dc90497
AG
2098 DC_ERROR("Stream %p not found in new ctx!\n", stream);
2099 return DC_ERROR_UNEXPECTED;
2100}
4562236b 2101
2119aa17
DF
2102/**
2103 * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state
2104 * Is a shallow copy. Increments refcounts on existing streams and planes.
2105 * @dc: copy out of dc->current_state
2106 * @dst_ctx: copy into this
2107 */
f36cc577 2108void dc_resource_state_copy_construct_current(
1dc90497 2109 const struct dc *dc,
608ac7bb 2110 struct dc_state *dst_ctx)
1dc90497 2111{
f36cc577 2112 dc_resource_state_copy_construct(dc->current_state, dst_ctx);
1dc90497
AG
2113}
2114
ab8db3e1
AG
2115
2116void dc_resource_state_construct(
2117 const struct dc *dc,
2118 struct dc_state *dst_ctx)
2119{
dc88b4a6 2120 dst_ctx->clk_mgr = dc->clk_mgr;
6faacf90
JK
2121
2122 /* Initialise DIG link encoder resource tracking variables. */
2123 link_enc_cfg_init(dc, dst_ctx);
ab8db3e1
AG
2124}
2125
6d822156
NC
2126
2127bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
2128{
2129 return dc->res_pool->res_cap->num_dsc > 0;
2130}
2131
2132
2119aa17
DF
2133/**
2134 * dc_validate_global_state() - Determine if HW can support a given state
2135 * Checks HW resource availability and bandwidth requirement.
2136 * @dc: dc struct for this driver
2137 * @new_ctx: state to be validated
afcd526b 2138 * @fast_validate: set to true if only yes/no to support matters
2119aa17
DF
2139 *
2140 * Return: DC_OK if the result can be programmed. Otherwise, an error code.
2141 */
e750d56d 2142enum dc_status dc_validate_global_state(
1dc90497 2143 struct dc *dc,
afcd526b
JA
2144 struct dc_state *new_ctx,
2145 bool fast_validate)
4562236b 2146{
1dc90497 2147 enum dc_status result = DC_ERROR_UNEXPECTED;
1dc90497 2148 int i, j;
4562236b 2149
e41ab030
HW
2150 if (!new_ctx)
2151 return DC_ERROR_UNEXPECTED;
8fe44c08 2152#if defined(CONFIG_DRM_AMD_DC_DCN)
cbaf919f
NK
2153
2154 /*
2155 * Update link encoder to stream assignment.
2156 * TODO: Split out reason allocation from validation.
2157 */
ec7077b5 2158 if (dc->res_pool->funcs->link_encs_assign && fast_validate == false)
cbaf919f
NK
2159 dc->res_pool->funcs->link_encs_assign(
2160 dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
2161#endif
e41ab030 2162
d596e5d0 2163 if (dc->res_pool->funcs->validate_global) {
ada8ce15
HW
2164 result = dc->res_pool->funcs->validate_global(dc, new_ctx);
2165 if (result != DC_OK)
2166 return result;
d596e5d0 2167 }
4562236b 2168
e41ab030 2169 for (i = 0; i < new_ctx->stream_count; i++) {
1dc90497
AG
2170 struct dc_stream_state *stream = new_ctx->streams[i];
2171
2172 for (j = 0; j < dc->res_pool->pipe_count; j++) {
2173 struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
2174
2175 if (pipe_ctx->stream != stream)
2176 continue;
2177
8d8c82b6 2178 if (dc->res_pool->funcs->patch_unknown_plane_state &&
74eac5f3
SSC
2179 pipe_ctx->plane_state &&
2180 pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
8d8c82b6 2181 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
74eac5f3
SSC
2182 if (result != DC_OK)
2183 return result;
2184 }
2185
1dc90497
AG
2186 /* Switch to dp clock source only if there is
2187 * no non dp stream that shares the same timing
2188 * with the dp stream.
2189 */
2190 if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
2191 !find_pll_sharable_stream(stream, new_ctx)) {
2192
9d0dcecd 2193 resource_unreference_clock_source(
1dc90497
AG
2194 &new_ctx->res_ctx,
2195 dc->res_pool,
9d0dcecd 2196 pipe_ctx->clock_source);
4a629536 2197
1dc90497
AG
2198 pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
2199 resource_reference_clock_source(
2200 &new_ctx->res_ctx,
2201 dc->res_pool,
2202 pipe_ctx->clock_source);
2203 }
2204 }
2205 }
2206
1dc90497
AG
2207 result = resource_build_scaling_params_for_context(dc, new_ctx);
2208
2209 if (result == DC_OK)
afcd526b 2210 if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
1dc90497
AG
2211 result = DC_FAIL_BANDWIDTH_VALIDATE;
2212
2213 return result;
4562236b
HW
2214}
2215
6e4d6bee 2216static void patch_gamut_packet_checksum(
e09b6473 2217 struct dc_info_packet *gamut_packet)
4562236b 2218{
4562236b 2219 /* For gamut we recalc checksum */
6e4d6bee 2220 if (gamut_packet->valid) {
4562236b
HW
2221 uint8_t chk_sum = 0;
2222 uint8_t *ptr;
2223 uint8_t i;
2224
4562236b 2225 /*start of the Gamut data. */
6e4d6bee 2226 ptr = &gamut_packet->sb[3];
4562236b 2227
6e4d6bee 2228 for (i = 0; i <= gamut_packet->sb[1]; i++)
4562236b
HW
2229 chk_sum += ptr[i];
2230
6e4d6bee 2231 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
1646a6fe 2232 }
4562236b
HW
2233}
2234
2235static void set_avi_info_frame(
e09b6473 2236 struct dc_info_packet *info_packet,
4562236b
HW
2237 struct pipe_ctx *pipe_ctx)
2238{
0971c40e 2239 struct dc_stream_state *stream = pipe_ctx->stream;
4562236b 2240 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
4562236b
HW
2241 uint32_t pixel_encoding = 0;
2242 enum scanning_type scan_type = SCANNING_TYPE_NODATA;
2243 enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
2244 bool itc = false;
50e27654 2245 uint8_t itc_value = 0;
4562236b 2246 uint8_t cn0_cn1 = 0;
50e27654 2247 unsigned int cn0_cn1_value = 0;
4562236b
HW
2248 uint8_t *check_sum = NULL;
2249 uint8_t byte_index = 0;
754e3673 2250 union hdmi_info_packet hdmi_info;
50e27654 2251 union display_content_support support = {0};
4fa086b9 2252 unsigned int vic = pipe_ctx->stream->timing.vic;
15e17335 2253 enum dc_timing_3d_format format;
4562236b 2254
754e3673
AK
2255 memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
2256
4fa086b9 2257 color_space = pipe_ctx->stream->output_color_space;
e5f2038e 2258 if (color_space == COLOR_SPACE_UNKNOWN)
4fa086b9 2259 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
e5f2038e 2260 COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
4562236b
HW
2261
2262 /* Initialize header */
e09b6473 2263 hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
4562236b
HW
2264 /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
2265 * not be used in HDMI 2.0 (Section 10.1) */
e09b6473
AK
2266 hdmi_info.bits.header.version = 2;
2267 hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
4562236b
HW
2268
2269 /*
2270 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
2271 * according to HDMI 2.0 spec (Section 10.1)
2272 */
2273
4fa086b9 2274 switch (stream->timing.pixel_encoding) {
4562236b
HW
2275 case PIXEL_ENCODING_YCBCR422:
2276 pixel_encoding = 1;
2277 break;
2278
2279 case PIXEL_ENCODING_YCBCR444:
2280 pixel_encoding = 2;
2281 break;
2282 case PIXEL_ENCODING_YCBCR420:
2283 pixel_encoding = 3;
2284 break;
2285
2286 case PIXEL_ENCODING_RGB:
2287 default:
2288 pixel_encoding = 0;
2289 }
2290
2291 /* Y0_Y1_Y2 : The pixel encoding */
2292 /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
e09b6473 2293 hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding;
4562236b
HW
2294
2295 /* A0 = 1 Active Format Information valid */
e09b6473 2296 hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
4562236b
HW
2297
2298 /* B0, B1 = 3; Bar info data is valid */
e09b6473 2299 hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
4562236b 2300
e09b6473 2301 hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
4562236b
HW
2302
2303 /* S0, S1 : Underscan / Overscan */
2304 /* TODO: un-hardcode scan type */
2305 scan_type = SCANNING_TYPE_UNDERSCAN;
e09b6473 2306 hdmi_info.bits.S0_S1 = scan_type;
4562236b
HW
2307
2308 /* C0, C1 : Colorimetry */
8fde5884 2309 if (color_space == COLOR_SPACE_YCBCR709 ||
15e17335 2310 color_space == COLOR_SPACE_YCBCR709_LIMITED)
e09b6473 2311 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
8fde5884
CL
2312 else if (color_space == COLOR_SPACE_YCBCR601 ||
2313 color_space == COLOR_SPACE_YCBCR601_LIMITED)
e09b6473 2314 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
8fde5884 2315 else {
e09b6473 2316 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
8fde5884 2317 }
534db198 2318 if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE ||
8fde5884
CL
2319 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE ||
2320 color_space == COLOR_SPACE_2020_YCBCR) {
e09b6473
AK
2321 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
2322 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED;
534db198 2323 } else if (color_space == COLOR_SPACE_ADOBERGB) {
e09b6473
AK
2324 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
2325 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED;
534db198
AZ
2326 }
2327
4562236b 2328 /* TODO: un-hardcode aspect ratio */
4fa086b9 2329 aspect = stream->timing.aspect_ratio;
4562236b
HW
2330
2331 switch (aspect) {
2332 case ASPECT_RATIO_4_3:
2333 case ASPECT_RATIO_16_9:
e09b6473 2334 hdmi_info.bits.M0_M1 = aspect;
4562236b
HW
2335 break;
2336
2337 case ASPECT_RATIO_NO_DATA:
2338 case ASPECT_RATIO_64_27:
2339 case ASPECT_RATIO_256_135:
2340 default:
e09b6473 2341 hdmi_info.bits.M0_M1 = 0;
4562236b
HW
2342 }
2343
2344 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
e09b6473 2345 hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
4562236b
HW
2346
2347 /* TODO: un-hardcode cn0_cn1 and itc */
50e27654 2348
4562236b 2349 cn0_cn1 = 0;
50e27654
ZF
2350 cn0_cn1_value = 0;
2351
2352 itc = true;
2353 itc_value = 1;
2354
ceb3dbb4 2355 support = stream->content_support;
4562236b
HW
2356
2357 if (itc) {
50e27654
ZF
2358 if (!support.bits.valid_content_type) {
2359 cn0_cn1_value = 0;
2360 } else {
2361 if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) {
2362 if (support.bits.graphics_content == 1) {
2363 cn0_cn1_value = 0;
2364 }
2365 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) {
2366 if (support.bits.photo_content == 1) {
2367 cn0_cn1_value = 1;
2368 } else {
2369 cn0_cn1_value = 0;
2370 itc_value = 0;
2371 }
2372 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) {
2373 if (support.bits.cinema_content == 1) {
2374 cn0_cn1_value = 2;
2375 } else {
2376 cn0_cn1_value = 0;
2377 itc_value = 0;
2378 }
2379 } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) {
2380 if (support.bits.game_content == 1) {
2381 cn0_cn1_value = 3;
2382 } else {
2383 cn0_cn1_value = 0;
2384 itc_value = 0;
2385 }
2386 }
2387 }
e09b6473
AK
2388 hdmi_info.bits.CN0_CN1 = cn0_cn1_value;
2389 hdmi_info.bits.ITC = itc_value;
4562236b
HW
2390 }
2391
fdf7d4f5
DV
2392 if (stream->qs_bit == 1) {
2393 if (color_space == COLOR_SPACE_SRGB ||
2394 color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
2395 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE;
2396 else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
2397 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
2398 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE;
2399 else
2400 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE;
2401 } else
2402 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE;
2403
4562236b
HW
2404 /* TODO : We should handle YCC quantization */
2405 /* but we do not have matrix calculation */
fdf7d4f5 2406 if (stream->qy_bit == 1) {
50e27654 2407 if (color_space == COLOR_SPACE_SRGB ||
fdf7d4f5 2408 color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
993dca3e 2409 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
fdf7d4f5
DV
2410 else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
2411 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
e09b6473 2412 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
fdf7d4f5 2413 else
e09b6473 2414 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
fdf7d4f5
DV
2415 } else
2416 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
50e27654 2417
15e17335 2418 ///VIC
4fa086b9 2419 format = stream->timing.timing_3d_format;
15e17335
CL
2420 /*todo, add 3DStereo support*/
2421 if (format != TIMING_3D_FORMAT_NONE) {
2422 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
4fa086b9 2423 switch (pipe_ctx->stream->timing.hdmi_vic) {
15e17335
CL
2424 case 1:
2425 vic = 95;
2426 break;
2427 case 2:
2428 vic = 94;
2429 break;
2430 case 3:
2431 vic = 93;
2432 break;
2433 case 4:
2434 vic = 98;
2435 break;
2436 default:
2437 break;
2438 }
2439 }
efa02336 2440 /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
e09b6473 2441 hdmi_info.bits.VIC0_VIC7 = vic;
efa02336
CP
2442 if (vic >= 128)
2443 hdmi_info.bits.header.version = 3;
2444 /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
2445 * the Source shall use 20 AVI InfoFrame Version 4
2446 */
2447 if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
2448 hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
2449 hdmi_info.bits.header.version = 4;
2450 hdmi_info.bits.header.length = 14;
2451 }
4562236b
HW
2452
2453 /* pixel repetition
2454 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
2455 * repetition start from 1 */
e09b6473 2456 hdmi_info.bits.PR0_PR3 = 0;
4562236b
HW
2457
2458 /* Bar Info
2459 * barTop: Line Number of End of Top Bar.
2460 * barBottom: Line Number of Start of Bottom Bar.
2461 * barLeft: Pixel Number of End of Left Bar.
2462 * barRight: Pixel Number of Start of Right Bar. */
e09b6473
AK
2463 hdmi_info.bits.bar_top = stream->timing.v_border_top;
2464 hdmi_info.bits.bar_bottom = (stream->timing.v_total
4fa086b9 2465 - stream->timing.v_border_bottom + 1);
e09b6473
AK
2466 hdmi_info.bits.bar_left = stream->timing.h_border_left;
2467 hdmi_info.bits.bar_right = (stream->timing.h_total
4fa086b9 2468 - stream->timing.h_border_right + 1);
4562236b 2469
2f482c4f
CP
2470 /* Additional Colorimetry Extension
2471 * Used in conduction with C0-C1 and EC0-EC2
2472 * 0 = DCI-P3 RGB (D65)
2473 * 1 = DCI-P3 RGB (theater)
2474 */
2475 hdmi_info.bits.ACE0_ACE3 = 0;
2476
4562236b 2477 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
e09b6473 2478 check_sum = &hdmi_info.packet_raw_data.sb[0];
e8d726b7 2479
efa02336 2480 *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
4562236b 2481
efa02336 2482 for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
e09b6473 2483 *check_sum += hdmi_info.packet_raw_data.sb[byte_index];
4562236b
HW
2484
2485 /* one byte complement */
2486 *check_sum = (uint8_t) (0x100 - *check_sum);
2487
2488 /* Store in hw_path_mode */
e09b6473
AK
2489 info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
2490 info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
2491 info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
4562236b 2492
e09b6473
AK
2493 for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
2494 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
4562236b
HW
2495
2496 info_packet->valid = true;
2497}
2498
6e4d6bee 2499static void set_vendor_info_packet(
e09b6473 2500 struct dc_info_packet *info_packet,
0971c40e 2501 struct dc_stream_state *stream)
4562236b 2502{
ecd0136b 2503 /* SPD info packet for FreeSync */
4562236b 2504
ecd0136b
HT
2505 /* Check if Freesync is supported. Return if false. If true,
2506 * set the corresponding bit in the info packet
2507 */
2508 if (!stream->vsp_infopacket.valid)
4562236b
HW
2509 return;
2510
ecd0136b 2511 *info_packet = stream->vsp_infopacket;
4562236b
HW
2512}
2513
6e4d6bee 2514static void set_spd_info_packet(
e09b6473 2515 struct dc_info_packet *info_packet,
0971c40e 2516 struct dc_stream_state *stream)
4562236b
HW
2517{
2518 /* SPD info packet for FreeSync */
2519
4562236b
HW
2520 /* Check if Freesync is supported. Return if false. If true,
2521 * set the corresponding bit in the info packet
2522 */
98e6436d 2523 if (!stream->vrr_infopacket.valid)
4562236b
HW
2524 return;
2525
98e6436d 2526 *info_packet = stream->vrr_infopacket;
4562236b
HW
2527}
2528
1646a6fe 2529static void set_hdr_static_info_packet(
e09b6473 2530 struct dc_info_packet *info_packet,
0971c40e 2531 struct dc_stream_state *stream)
1646a6fe 2532{
0eeef690 2533 /* HDR Static Metadata info packet for HDR10 */
1646a6fe 2534
a10dc97a
KK
2535 if (!stream->hdr_static_metadata.valid ||
2536 stream->use_dynamic_meta)
10bff005
YS
2537 return;
2538
0eeef690 2539 *info_packet = stream->hdr_static_metadata;
1646a6fe
AW
2540}
2541
6e4d6bee 2542static void set_vsc_info_packet(
e09b6473 2543 struct dc_info_packet *info_packet,
0971c40e 2544 struct dc_stream_state *stream)
4562236b 2545{
1336926f 2546 if (!stream->vsc_infopacket.valid)
4562236b
HW
2547 return;
2548
1336926f 2549 *info_packet = stream->vsc_infopacket;
4562236b
HW
2550}
2551
f36cc577 2552void dc_resource_state_destruct(struct dc_state *context)
4562236b
HW
2553{
2554 int i, j;
2555
ab2541b6 2556 for (i = 0; i < context->stream_count; i++) {
3be5262e
HW
2557 for (j = 0; j < context->stream_status[i].plane_count; j++)
2558 dc_plane_state_release(
2559 context->stream_status[i].plane_states[j]);
4562236b 2560
3be5262e 2561 context->stream_status[i].plane_count = 0;
4fa086b9 2562 dc_stream_release(context->streams[i]);
ab2541b6 2563 context->streams[i] = NULL;
4562236b 2564 }
5728d5e5 2565 context->stream_count = 0;
4562236b
HW
2566}
2567
f36cc577 2568void dc_resource_state_copy_construct(
608ac7bb
JZ
2569 const struct dc_state *src_ctx,
2570 struct dc_state *dst_ctx)
4562236b
HW
2571{
2572 int i, j;
8ee5702a 2573 struct kref refcount = dst_ctx->refcount;
4562236b
HW
2574
2575 *dst_ctx = *src_ctx;
2576
a2b8659d 2577 for (i = 0; i < MAX_PIPES; i++) {
4562236b
HW
2578 struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i];
2579
2580 if (cur_pipe->top_pipe)
2581 cur_pipe->top_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
2582
2583 if (cur_pipe->bottom_pipe)
2584 cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
b1f6d01c
DL
2585
2586 if (cur_pipe->next_odm_pipe)
2587 cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
2588
2589 if (cur_pipe->prev_odm_pipe)
2590 cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
4562236b
HW
2591 }
2592
ab2541b6 2593 for (i = 0; i < dst_ctx->stream_count; i++) {
4fa086b9 2594 dc_stream_retain(dst_ctx->streams[i]);
3be5262e
HW
2595 for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++)
2596 dc_plane_state_retain(
2597 dst_ctx->stream_status[i].plane_states[j]);
4562236b 2598 }
9a3afbb3
AG
2599
2600 /* context refcount should not be overridden */
8ee5702a 2601 dst_ctx->refcount = refcount;
9a3afbb3 2602
4562236b
HW
2603}
2604
2605struct clock_source *dc_resource_find_first_free_pll(
a2b8659d
TC
2606 struct resource_context *res_ctx,
2607 const struct resource_pool *pool)
4562236b
HW
2608{
2609 int i;
2610
a2b8659d 2611 for (i = 0; i < pool->clk_src_count; ++i) {
4562236b 2612 if (res_ctx->clock_source_ref_count[i] == 0)
a2b8659d 2613 return pool->clock_sources[i];
4562236b
HW
2614 }
2615
2616 return NULL;
2617}
2618
2619void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
2620{
2621 enum signal_type signal = SIGNAL_TYPE_NONE;
96c50c0d 2622 struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
4562236b
HW
2623
2624 /* default all packets to invalid */
6e4d6bee
TC
2625 info->avi.valid = false;
2626 info->gamut.valid = false;
2627 info->vendor.valid = false;
630e3573 2628 info->spd.valid = false;
6e4d6bee
TC
2629 info->hdrsmd.valid = false;
2630 info->vsc.valid = false;
4562236b
HW
2631
2632 signal = pipe_ctx->stream->signal;
2633
2634 /* HDMi and DP have different info packets*/
2635 if (dc_is_hdmi_signal(signal)) {
6e4d6bee
TC
2636 set_avi_info_frame(&info->avi, pipe_ctx);
2637
2638 set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
2639
2640 set_spd_info_packet(&info->spd, pipe_ctx->stream);
2641
56ef6ed9 2642 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
6e4d6bee 2643
a33fa99d 2644 } else if (dc_is_dp_signal(signal)) {
6e4d6bee
TC
2645 set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
2646
2647 set_spd_info_packet(&info->spd, pipe_ctx->stream);
2648
56ef6ed9 2649 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
a33fa99d 2650 }
4562236b 2651
6e4d6bee 2652 patch_gamut_packet_checksum(&info->gamut);
4562236b
HW
2653}
2654
2655enum dc_status resource_map_clock_resources(
fb3466a4 2656 const struct dc *dc,
608ac7bb 2657 struct dc_state *context,
1dc90497 2658 struct dc_stream_state *stream)
4562236b 2659{
4562236b 2660 /* acquire new resources */
1dc90497
AG
2661 const struct resource_pool *pool = dc->res_pool;
2662 struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
2663 &context->res_ctx, stream);
ab2541b6 2664
1dc90497
AG
2665 if (!pipe_ctx)
2666 return DC_ERROR_UNEXPECTED;
4562236b 2667
1dc90497
AG
2668 if (dc_is_dp_signal(pipe_ctx->stream->signal)
2669 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
2670 pipe_ctx->clock_source = pool->dp_clock_source;
2671 else {
2672 pipe_ctx->clock_source = NULL;
4562236b 2673
1dc90497 2674 if (!dc->config.disable_disp_pll_sharing)
4ed4e51b 2675 pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
1dc90497
AG
2676 &context->res_ctx,
2677 pipe_ctx);
4562236b 2678
1dc90497
AG
2679 if (pipe_ctx->clock_source == NULL)
2680 pipe_ctx->clock_source =
2681 dc_resource_find_first_free_pll(
2682 &context->res_ctx,
2683 pool);
2684 }
4562236b 2685
1dc90497
AG
2686 if (pipe_ctx->clock_source == NULL)
2687 return DC_NO_CLOCK_SOURCE_RESOURCE;
4562236b 2688
1dc90497
AG
2689 resource_reference_clock_source(
2690 &context->res_ctx, pool,
2691 pipe_ctx->clock_source);
4562236b
HW
2692
2693 return DC_OK;
2694}
2695
2696/*
2697 * Note: We need to disable output if clock sources change,
2698 * since bios does optimization and doesn't apply if changing
2699 * PHY when not already disabled.
2700 */
2701bool pipe_need_reprogram(
2702 struct pipe_ctx *pipe_ctx_old,
2703 struct pipe_ctx *pipe_ctx)
2704{
cfe4645e
DL
2705 if (!pipe_ctx_old->stream)
2706 return false;
2707
4562236b
HW
2708 if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
2709 return true;
2710
2711 if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
2712 return true;
2713
afaacef4 2714 if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
4562236b
HW
2715 return true;
2716
2717 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
2718 && pipe_ctx_old->stream != pipe_ctx->stream)
2719 return true;
2720
8e9c4c8c 2721 if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
4562236b
HW
2722 return true;
2723
2724 if (is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
2725 return true;
2726
1e7e86c4
ST
2727 if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
2728 return true;
2729
eed928dc
CL
2730 if (false == pipe_ctx_old->stream->link->link_state_valid &&
2731 false == pipe_ctx_old->stream->dpms_off)
2732 return true;
2733
14e49bb3
NC
2734 if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
2735 return true;
2736
f42ef862 2737 /* DIG link encoder resource assignment for stream changed. */
6f941d4e
JK
2738 if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
2739 bool need_reprogram = false;
2740 struct dc *dc = pipe_ctx_old->stream->ctx->dc;
2741 enum link_enc_cfg_mode mode = dc->current_state->res_ctx.link_enc_cfg_ctx.mode;
2742
2743 dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
2744 if (link_enc_cfg_get_link_enc_used_by_stream(dc, pipe_ctx_old->stream) != pipe_ctx->stream->link_enc)
2745 need_reprogram = true;
2746 dc->current_state->res_ctx.link_enc_cfg_ctx.mode = mode;
2747
2748 return need_reprogram;
2749 }
f42ef862 2750
4562236b
HW
2751 return false;
2752}
529cad0f 2753
0971c40e 2754void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
529cad0f
DW
2755 struct bit_depth_reduction_params *fmt_bit_depth)
2756{
4fa086b9 2757 enum dc_dither_option option = stream->dither_option;
529cad0f 2758 enum dc_pixel_encoding pixel_encoding =
4fa086b9 2759 stream->timing.pixel_encoding;
529cad0f
DW
2760
2761 memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
2762
603767f9
TC
2763 if (option == DITHER_OPTION_DEFAULT) {
2764 switch (stream->timing.display_color_depth) {
2765 case COLOR_DEPTH_666:
2766 option = DITHER_OPTION_SPATIAL6;
2767 break;
2768 case COLOR_DEPTH_888:
2769 option = DITHER_OPTION_SPATIAL8;
2770 break;
2771 case COLOR_DEPTH_101010:
2772 option = DITHER_OPTION_SPATIAL10;
2773 break;
2774 default:
2775 option = DITHER_OPTION_DISABLE;
2776 }
2777 }
2778
529cad0f
DW
2779 if (option == DITHER_OPTION_DISABLE)
2780 return;
2781
2782 if (option == DITHER_OPTION_TRUN6) {
2783 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2784 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
2785 } else if (option == DITHER_OPTION_TRUN8 ||
2786 option == DITHER_OPTION_TRUN8_SPATIAL6 ||
2787 option == DITHER_OPTION_TRUN8_FM6) {
2788 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2789 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
2790 } else if (option == DITHER_OPTION_TRUN10 ||
2791 option == DITHER_OPTION_TRUN10_SPATIAL6 ||
2792 option == DITHER_OPTION_TRUN10_SPATIAL8 ||
2793 option == DITHER_OPTION_TRUN10_FM8 ||
2794 option == DITHER_OPTION_TRUN10_FM6 ||
2795 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
2796 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2797 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
2798 }
2799
2800 /* special case - Formatter can only reduce by 4 bits at most.
2801 * When reducing from 12 to 6 bits,
2802 * HW recommends we use trunc with round mode
2803 * (if we did nothing, trunc to 10 bits would be used)
2804 * note that any 12->10 bit reduction is ignored prior to DCE8,
2805 * as the input was 10 bits.
2806 */
2807 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
2808 option == DITHER_OPTION_SPATIAL6 ||
2809 option == DITHER_OPTION_FM6) {
2810 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
2811 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
2812 fmt_bit_depth->flags.TRUNCATE_MODE = 1;
2813 }
2814
2815 /* spatial dither
2816 * note that spatial modes 1-3 are never used
2817 */
2818 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
2819 option == DITHER_OPTION_SPATIAL6 ||
2820 option == DITHER_OPTION_TRUN10_SPATIAL6 ||
2821 option == DITHER_OPTION_TRUN8_SPATIAL6) {
2822 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
2823 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
2824 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
2825 fmt_bit_depth->flags.RGB_RANDOM =
2826 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
2827 } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM ||
2828 option == DITHER_OPTION_SPATIAL8 ||
2829 option == DITHER_OPTION_SPATIAL8_FM6 ||
2830 option == DITHER_OPTION_TRUN10_SPATIAL8 ||
2831 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
2832 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
2833 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
2834 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
2835 fmt_bit_depth->flags.RGB_RANDOM =
2836 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
2837 } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
2838 option == DITHER_OPTION_SPATIAL10 ||
2839 option == DITHER_OPTION_SPATIAL10_FM8 ||
2840 option == DITHER_OPTION_SPATIAL10_FM6) {
2841 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
2842 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
2843 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
2844 fmt_bit_depth->flags.RGB_RANDOM =
2845 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
2846 }
2847
2848 if (option == DITHER_OPTION_SPATIAL6 ||
2849 option == DITHER_OPTION_SPATIAL8 ||
2850 option == DITHER_OPTION_SPATIAL10) {
2851 fmt_bit_depth->flags.FRAME_RANDOM = 0;
2852 } else {
2853 fmt_bit_depth->flags.FRAME_RANDOM = 1;
2854 }
2855
2856 //////////////////////
2857 //// temporal dither
2858 //////////////////////
2859 if (option == DITHER_OPTION_FM6 ||
2860 option == DITHER_OPTION_SPATIAL8_FM6 ||
2861 option == DITHER_OPTION_SPATIAL10_FM6 ||
2862 option == DITHER_OPTION_TRUN10_FM6 ||
2863 option == DITHER_OPTION_TRUN8_FM6 ||
2864 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
2865 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
2866 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
2867 } else if (option == DITHER_OPTION_FM8 ||
2868 option == DITHER_OPTION_SPATIAL10_FM8 ||
2869 option == DITHER_OPTION_TRUN10_FM8) {
2870 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
2871 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
2872 } else if (option == DITHER_OPTION_FM10) {
2873 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
2874 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
2875 }
2876
2877 fmt_bit_depth->pixel_encoding = pixel_encoding;
2878}
9345d987 2879
62c933f9 2880enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
9345d987 2881{
ceb3dbb4 2882 struct dc_link *link = stream->link;
2b77dcc5 2883 struct timing_generator *tg = dc->res_pool->timing_generators[0];
9345d987
AG
2884 enum dc_status res = DC_OK;
2885
4fa086b9 2886 calculate_phy_pix_clks(stream);
9345d987 2887
4fa086b9 2888 if (!tg->funcs->validate_timing(tg, &stream->timing))
9345d987
AG
2889 res = DC_FAIL_CONTROLLER_VALIDATE;
2890
248cbed6 2891 if (res == DC_OK) {
940e084d
JK
2892 if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
2893 !link->link_enc->funcs->validate_output_with_stream(
4fa086b9 2894 link->link_enc, stream))
9345d987 2895 res = DC_FAIL_ENC_VALIDATE;
248cbed6 2896 }
9345d987
AG
2897
2898 /* TODO: validate audio ASIC caps, encoder */
2899
2900 if (res == DC_OK)
4fa086b9 2901 res = dc_link_validate_mode_timing(stream,
9345d987 2902 link,
4fa086b9 2903 &stream->timing);
9345d987 2904
62c933f9 2905 return res;
9345d987 2906}
792671d7 2907
62c933f9 2908enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
792671d7 2909{
62c933f9
YS
2910 enum dc_status res = DC_OK;
2911
792671d7 2912 /* TODO For now validates pixel format only */
8e7095b9 2913 if (dc->res_pool->funcs->validate_plane)
62c933f9 2914 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
792671d7 2915
62c933f9 2916 return res;
792671d7 2917}
74eac5f3
SSC
2918
2919unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
2920{
2921 switch (format) {
2922 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
2923 return 8;
2924 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
2925 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
2926 return 12;
2927 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
2928 case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
2929 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
2930 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
2931 return 16;
2932 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
2933 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
2934 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
2935 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
2936 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
20f2ffe5 2937#if defined(CONFIG_DRM_AMD_DC_DCN)
5dba4991
BL
2938 case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
2939 case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
2940#endif
74eac5f3
SSC
2941 return 32;
2942 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
050cd3d6 2943 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
74eac5f3
SSC
2944 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
2945 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
2946 return 64;
2947 default:
2948 ASSERT_CRITICAL(false);
2949 return -1;
2950 }
2951}
3ab4cc65
CL
2952static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
2953{
2954 if (modes) {
2955 if (modes->sample_rates.rate.RATE_192)
2956 return 192000;
2957 if (modes->sample_rates.rate.RATE_176_4)
2958 return 176400;
2959 if (modes->sample_rates.rate.RATE_96)
2960 return 96000;
2961 if (modes->sample_rates.rate.RATE_88_2)
2962 return 88200;
2963 if (modes->sample_rates.rate.RATE_48)
2964 return 48000;
2965 if (modes->sample_rates.rate.RATE_44_1)
2966 return 44100;
2967 if (modes->sample_rates.rate.RATE_32)
2968 return 32000;
2969 }
2970 /*original logic when no audio info*/
2971 return 441000;
2972}
2973
2974void get_audio_check(struct audio_info *aud_modes,
2975 struct audio_check *audio_chk)
2976{
2977 unsigned int i;
2978 unsigned int max_sample_rate = 0;
2979
2980 if (aud_modes) {
2981 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
2982
2983 audio_chk->max_audiosample_rate = 0;
2984 for (i = 0; i < aud_modes->mode_count; i++) {
2985 max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
2986 if (audio_chk->max_audiosample_rate < max_sample_rate)
2987 audio_chk->max_audiosample_rate = max_sample_rate;
2988 /*dts takes the same as type 2: AP = 0.25*/
2989 }
2990 /*check which one take more bandwidth*/
2991 if (audio_chk->max_audiosample_rate > 192000)
2992 audio_chk->audio_packet_type = 0x9;/*AP =1*/
2993 audio_chk->acat = 0;/*not support*/
2994 }
2995}
2996