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