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