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