2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include <linux/slab.h>
28 #include "dm_services.h"
31 #include "include/irq_service_interface.h"
32 #include "link_encoder.h"
33 #include "stream_encoder.h"
35 #include "timing_generator.h"
36 #include "transform.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"
46 #if defined(CONFIG_DRM_AMD_DC_SI)
47 #include "dce60/dce60_resource.h"
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"
65 #define DC_LOGGER_INIT(logger)
67 enum dce_version
resource_parse_asic_id(struct hw_asic_id asic_id
)
69 enum dce_version dc_version
= DCE_VERSION_UNKNOWN
;
70 switch (asic_id
.chip_family
) {
72 #if defined(CONFIG_DRM_AMD_DC_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
;
81 dc_version
= DCE_VERSION_6_1
;
85 dc_version
= DCE_VERSION_8_0
;
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
;
93 dc_version
= DCE_VERSION_8_1
;
96 dc_version
= DCE_VERSION_11_0
;
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
;
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
;
110 if (ASIC_REV_IS_VEGAM(asic_id
.hw_internal_rev
))
111 dc_version
= DCE_VERSION_11_22
;
114 if (ASICREV_IS_VEGA20_P(asic_id
.hw_internal_rev
))
115 dc_version
= DCE_VERSION_12_1
;
117 dc_version
= DCE_VERSION_12_0
;
119 #if defined(CONFIG_DRM_AMD_DC_DCN)
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
;
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
;
141 dc_version
= DCN_VERSION_3_01
;
144 case FAMILY_YELLOW_CARP
:
145 if (ASICREV_IS_YELLOW_CARP(asic_id
.hw_internal_rev
))
146 dc_version
= DCN_VERSION_3_1
;
151 dc_version
= DCE_VERSION_UNKNOWN
;
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
)
161 struct resource_pool
*res_pool
= NULL
;
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
);
169 case DCE_VERSION_6_1
:
170 res_pool
= dce61_create_resource_pool(
171 init_data
->num_virtual_links
, dc
);
173 case DCE_VERSION_6_4
:
174 res_pool
= dce64_create_resource_pool(
175 init_data
->num_virtual_links
, dc
);
178 case DCE_VERSION_8_0
:
179 res_pool
= dce80_create_resource_pool(
180 init_data
->num_virtual_links
, dc
);
182 case DCE_VERSION_8_1
:
183 res_pool
= dce81_create_resource_pool(
184 init_data
->num_virtual_links
, dc
);
186 case DCE_VERSION_8_3
:
187 res_pool
= dce83_create_resource_pool(
188 init_data
->num_virtual_links
, dc
);
190 case DCE_VERSION_10_0
:
191 res_pool
= dce100_create_resource_pool(
192 init_data
->num_virtual_links
, dc
);
194 case DCE_VERSION_11_0
:
195 res_pool
= dce110_create_resource_pool(
196 init_data
->num_virtual_links
, dc
,
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
);
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
);
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
);
215 case DCN_VERSION_2_0
:
216 res_pool
= dcn20_create_resource_pool(init_data
, dc
);
218 case DCN_VERSION_2_1
:
219 res_pool
= dcn21_create_resource_pool(init_data
, dc
);
221 case DCN_VERSION_3_0
:
222 res_pool
= dcn30_create_resource_pool(init_data
, dc
);
224 case DCN_VERSION_3_01
:
225 res_pool
= dcn301_create_resource_pool(init_data
, dc
);
227 case DCN_VERSION_3_02
:
228 res_pool
= dcn302_create_resource_pool(init_data
, dc
);
230 case DCN_VERSION_3_03
:
231 res_pool
= dcn303_create_resource_pool(init_data
, dc
);
233 case DCN_VERSION_3_1
:
234 res_pool
= dcn31_create_resource_pool(init_data
, dc
);
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
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
;
256 ASSERT_CRITICAL(false);
262 void dc_destroy_resource_pool(struct dc
*dc
)
266 dc
->res_pool
->funcs
->destroy(&dc
->res_pool
);
272 static void update_num_audio(
273 const struct resource_straps
*straps
,
274 unsigned int *num_audio
,
275 struct audio_support
*aud_support
)
277 aud_support
->dp_audio
= true;
278 aud_support
->hdmi_audio_native
= false;
279 aud_support
->hdmi_audio_on_dongle
= false;
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;
288 switch (straps
->audio_stream_number
) {
289 case 0: /* multi streams supported */
291 case 1: /* multi streams not supported */
295 DC_ERR("DC: unexpected audio fuse!\n");
299 bool resource_construct(
300 unsigned int num_virtual_links
,
302 struct resource_pool
*pool
,
303 const struct resource_create_funcs
*create_funcs
)
305 struct dc_context
*ctx
= dc
->ctx
;
306 const struct resource_caps
*caps
= pool
->res_cap
;
308 unsigned int num_audio
= caps
->num_audio
;
309 struct resource_straps straps
= {0};
311 if (create_funcs
->read_dce_straps
)
312 create_funcs
->read_dce_straps(dc
->ctx
, &straps
);
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).
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
);
328 DC_ERR("DC: failed to create audio!\n");
331 if (!aud
->funcs
->endpoint_valid(aud
)) {
332 aud
->funcs
->destroy(&aud
);
335 pool
->audios
[i
] = aud
;
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
++;
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");
360 dc
->caps
.dynamic_audio
= false;
361 if (pool
->audio_count
< pool
->stream_enc_count
) {
362 dc
->caps
.dynamic_audio
= true;
364 for (i
= 0; i
< num_virtual_links
; i
++) {
365 pool
->stream_enc
[pool
->stream_enc_count
] =
366 virtual_stream_encoder_create(
368 if (pool
->stream_enc
[pool
->stream_enc_count
] == NULL
) {
369 DC_ERR("DC: failed to create stream_encoder!\n");
372 pool
->stream_enc_count
++;
375 dc
->hwseq
= create_funcs
->create_hwseq(ctx
);
379 static int find_matching_clock_source(
380 const struct resource_pool
*pool
,
381 struct clock_source
*clock_source
)
386 for (i
= 0; i
< pool
->clk_src_count
; i
++) {
387 if (pool
->clock_sources
[i
] == clock_source
)
393 void resource_unreference_clock_source(
394 struct resource_context
*res_ctx
,
395 const struct resource_pool
*pool
,
396 struct clock_source
*clock_source
)
398 int i
= find_matching_clock_source(pool
, clock_source
);
401 res_ctx
->clock_source_ref_count
[i
]--;
403 if (pool
->dp_clock_source
== clock_source
)
404 res_ctx
->dp_clock_source_ref_count
--;
407 void resource_reference_clock_source(
408 struct resource_context
*res_ctx
,
409 const struct resource_pool
*pool
,
410 struct clock_source
*clock_source
)
412 int i
= find_matching_clock_source(pool
, clock_source
);
415 res_ctx
->clock_source_ref_count
[i
]++;
417 if (pool
->dp_clock_source
== clock_source
)
418 res_ctx
->dp_clock_source_ref_count
++;
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
)
426 int i
= find_matching_clock_source(pool
, clock_source
);
429 return res_ctx
->clock_source_ref_count
[i
];
431 if (pool
->dp_clock_source
== clock_source
)
432 return res_ctx
->dp_clock_source_ref_count
;
437 bool resource_are_vblanks_synchronizable(
438 struct dc_stream_state
*stream1
,
439 struct dc_stream_state
*stream2
)
441 uint32_t base60_refresh_rates
[] = {10, 20, 5};
443 uint8_t rr_count
= ARRAY_SIZE(base60_refresh_rates
);
444 uint64_t frame_time_diff
;
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)
458 if (stream2
->timing
.pix_clk_100hz
*100/stream2
->timing
.h_total
/
459 stream2
->timing
.v_total
> 60)
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;
473 if (diff
< stream1
->ctx
->dc
->config
.vblank_alignment_max_frame_time_diff
)
480 bool resource_are_streams_timing_synchronizable(
481 struct dc_stream_state
*stream1
,
482 struct dc_stream_state
*stream2
)
484 if (stream1
->timing
.h_total
!= stream2
->timing
.h_total
)
487 if (stream1
->timing
.v_total
!= stream2
->timing
.v_total
)
490 if (stream1
->timing
.h_addressable
491 != stream2
->timing
.h_addressable
)
494 if (stream1
->timing
.v_addressable
495 != stream2
->timing
.v_addressable
)
498 if (stream1
->timing
.v_front_porch
499 != stream2
->timing
.v_front_porch
)
502 if (stream1
->timing
.pix_clk_100hz
503 != stream2
->timing
.pix_clk_100hz
)
506 if (stream1
->clamping
.c_depth
!= stream2
->clamping
.c_depth
)
509 if (stream1
->phy_pix_clk
!= stream2
->phy_pix_clk
510 && (!dc_is_dp_signal(stream1
->signal
)
511 || !dc_is_dp_signal(stream2
->signal
)))
514 if (stream1
->view_format
!= stream2
->view_format
)
517 if (stream1
->ignore_msa_timing_param
|| stream2
->ignore_msa_timing_param
)
522 static bool is_dp_and_hdmi_sharable(
523 struct dc_stream_state
*stream1
,
524 struct dc_stream_state
*stream2
)
526 if (stream1
->ctx
->dc
->caps
.disable_dp_clk_share
)
529 if (stream1
->clamping
.c_depth
!= COLOR_DEPTH_888
||
530 stream2
->clamping
.c_depth
!= COLOR_DEPTH_888
)
537 static bool is_sharable_clk_src(
538 const struct pipe_ctx
*pipe_with_clk_src
,
539 const struct pipe_ctx
*pipe
)
541 if (pipe_with_clk_src
->clock_source
== NULL
)
544 if (pipe_with_clk_src
->stream
->signal
== SIGNAL_TYPE_VIRTUAL
)
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
,
553 if (dc_is_hdmi_signal(pipe_with_clk_src
->stream
->signal
)
554 && dc_is_dual_link_signal(pipe
->stream
->signal
))
557 if (dc_is_hdmi_signal(pipe
->stream
->signal
)
558 && dc_is_dual_link_signal(pipe_with_clk_src
->stream
->signal
))
561 if (!resource_are_streams_timing_synchronizable(
562 pipe_with_clk_src
->stream
, pipe
->stream
))
568 struct clock_source
*resource_find_used_clk_src_for_sharing(
569 struct resource_context
*res_ctx
,
570 struct pipe_ctx
*pipe_ctx
)
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
;
582 static enum pixel_format
convert_pixel_format_to_dalsurface(
583 enum surface_pixel_format surface_pixel_format
)
585 enum pixel_format dal_pixel_format
= PIXEL_FORMAT_UNKNOWN
;
587 switch (surface_pixel_format
) {
588 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS
:
589 dal_pixel_format
= PIXEL_FORMAT_INDEX8
;
591 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555
:
592 dal_pixel_format
= PIXEL_FORMAT_RGB565
;
594 case SURFACE_PIXEL_FORMAT_GRPH_RGB565
:
595 dal_pixel_format
= PIXEL_FORMAT_RGB565
;
597 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888
:
598 dal_pixel_format
= PIXEL_FORMAT_ARGB8888
;
600 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888
:
601 dal_pixel_format
= PIXEL_FORMAT_ARGB8888
;
603 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010
:
604 dal_pixel_format
= PIXEL_FORMAT_ARGB2101010
;
606 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010
:
607 dal_pixel_format
= PIXEL_FORMAT_ARGB2101010
;
609 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS
:
610 dal_pixel_format
= PIXEL_FORMAT_ARGB2101010_XRBIAS
;
612 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F
:
613 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F
:
614 dal_pixel_format
= PIXEL_FORMAT_FP16
;
616 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr
:
617 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb
:
618 dal_pixel_format
= PIXEL_FORMAT_420BPP8
;
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
;
624 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616
:
625 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616
:
627 dal_pixel_format
= PIXEL_FORMAT_UNKNOWN
;
630 return dal_pixel_format
;
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
)
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;
654 if (horizontal_mirror
)
655 *flip_horz_scan_dir
= !*flip_horz_scan_dir
;
658 int get_num_mpc_splits(struct pipe_ctx
*pipe
)
660 int mpc_split_count
= 0;
661 struct pipe_ctx
*other_pipe
= pipe
->bottom_pipe
;
663 while (other_pipe
&& other_pipe
->plane_state
== pipe
->plane_state
) {
665 other_pipe
= other_pipe
->bottom_pipe
;
667 other_pipe
= pipe
->top_pipe
;
668 while (other_pipe
&& other_pipe
->plane_state
== pipe
->plane_state
) {
670 other_pipe
= other_pipe
->top_pipe
;
673 return mpc_split_count
;
676 int get_num_odm_splits(struct pipe_ctx
*pipe
)
678 int odm_split_count
= 0;
679 struct pipe_ctx
*next_pipe
= pipe
->next_odm_pipe
;
682 next_pipe
= next_pipe
->next_odm_pipe
;
684 pipe
= pipe
->prev_odm_pipe
;
687 pipe
= pipe
->prev_odm_pipe
;
689 return odm_split_count
;
692 static void calculate_split_count_and_index(struct pipe_ctx
*pipe_ctx
, int *split_count
, int *split_idx
)
694 *split_count
= get_num_odm_splits(pipe_ctx
);
696 if (*split_count
== 0) {
697 /*Check for mpc split*/
698 struct pipe_ctx
*split_pipe
= pipe_ctx
->top_pipe
;
700 *split_count
= get_num_mpc_splits(pipe_ctx
);
701 while (split_pipe
&& split_pipe
->plane_state
== pipe_ctx
->plane_state
) {
703 split_pipe
= split_pipe
->top_pipe
;
706 /*Get odm split index*/
707 struct pipe_ctx
*split_pipe
= pipe_ctx
->prev_odm_pipe
;
711 split_pipe
= split_pipe
->prev_odm_pipe
;
717 * This is a preliminary vp size calculation to allow us to check taps support.
718 * The result is completely overridden afterwards.
720 static void calculate_viewport_size(struct pipe_ctx
*pipe_ctx
)
722 struct scaler_data
*data
= &pipe_ctx
->plane_res
.scl_data
;
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
);
735 static void calculate_recout(struct pipe_ctx
*pipe_ctx
)
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
;
744 calculate_split_count_and_index(pipe_ctx
, &split_count
, &split_idx
);
745 if (stream
->view_format
== VIEW_3D_FORMAT_SIDE_BY_SIDE
)
749 * Only the leftmost ODM pipe should be offset by a nonzero distance
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
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
;
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
;
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
;
776 /* Handle h & v split */
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:
785 int epimo
= split_count
- data
->recout
.width
% (split_count
+ 1);
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);
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
;
798 /* ODM combine cases with MPO we can get negative widths */
799 if (data
->recout
.width
< 0)
800 data
->recout
.width
= 0;
804 data
->recout
.width
= data
->h_active
- data
->recout
.x
;
809 static void calculate_scaling_ratios(struct pipe_ctx
*pipe_ctx
)
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
;
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
);
824 pipe_ctx
->plane_res
.scl_data
.ratios
.horz
= dc_fixpt_from_fraction(
826 plane_state
->dst_rect
.width
);
827 pipe_ctx
->plane_res
.scl_data
.ratios
.vert
= dc_fixpt_from_fraction(
829 plane_state
->dst_rect
.height
);
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;
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
);
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
;
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;
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);
861 * We completely calculate vp offset, size and inits here based entirely on scaling
862 * ratios and recout for pixel perfect pipe combine.
864 static void calculate_init_and_vp(
866 int recout_offset_within_recout_full
,
870 struct fixed31_32 ratio
,
871 struct fixed31_32
*init
,
875 struct fixed31_32 temp
;
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.
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
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);
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.
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
);
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
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
;
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.
922 *vp_offset
= src_size
- *vp_offset
- *vp_size
;
925 static void calculate_inits_and_viewports(struct pipe_ctx
*pipe_ctx
)
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
;
936 calculate_split_count_and_index(pipe_ctx
, &split_count
, &split_idx
);
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.
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
;
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);
955 * Work in recout rotation since that requires less transformations
957 get_vp_scan_direction(
958 plane_state
->rotation
,
959 plane_state
->horizontal_mirror
,
960 &orthogonal_rotation
,
962 &flip_horz_scan_dir
);
964 if (orthogonal_rotation
) {
965 swap(src
.width
, src
.height
);
966 swap(flip_vert_scan_dir
, flip_horz_scan_dir
);
969 calculate_init_and_vp(
978 &data
->viewport
.width
);
979 calculate_init_and_vp(
988 &data
->viewport_c
.width
);
989 calculate_init_and_vp(
998 &data
->viewport
.height
);
999 calculate_init_and_vp(
1002 data
->recout
.height
,
1003 src
.height
/ vpc_div
,
1004 data
->taps
.v_taps_c
,
1005 data
->ratios
.vert_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
);
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
;
1022 bool resource_build_scaling_params(struct pipe_ctx
*pipe_ctx
)
1024 const struct dc_plane_state
*plane_state
= pipe_ctx
->plane_state
;
1025 struct dc_crtc_timing
*timing
= &pipe_ctx
->stream
->timing
;
1027 DC_LOGGER_INIT(pipe_ctx
->stream
->ctx
->logger
);
1029 pipe_ctx
->plane_res
.scl_data
.format
= convert_pixel_format_to_dalsurface(
1030 pipe_ctx
->plane_state
->format
);
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
1037 pipe_ctx
->stream
->dst
.x
+= timing
->h_border_left
;
1038 pipe_ctx
->stream
->dst
.y
+= timing
->v_border_top
;
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;
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
);
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)
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.
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
;
1074 pipe_ctx
->plane_res
.scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_30BPP
;
1076 pipe_ctx
->plane_res
.scl_data
.lb_params
.alpha_en
= plane_state
->per_pixel_alpha
;
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
);
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
);
1088 /* Try 24 bpp linebuffer */
1089 pipe_ctx
->plane_res
.scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_24BPP
;
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
);
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
);
1105 * Depends on recout, scaling ratios, h_active and taps
1106 * May need to re-check lb size after this in some obscure scenario
1109 calculate_inits_and_viewports(pipe_ctx
);
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
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
;
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
)
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",
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
);
1157 pipe_ctx
->stream
->dst
.x
-= timing
->h_border_left
;
1158 pipe_ctx
->stream
->dst
.y
-= timing
->v_border_top
;
1164 enum dc_status
resource_build_scaling_params_for_context(
1165 const struct dc
*dc
,
1166 struct dc_state
*context
)
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
;
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
)
1186 struct pipe_ctx
*secondary_pipe
= NULL
;
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:
1194 * Display A on, no surface, top pipe = 0
1195 * Display B on, no surface, top pipe = 1
1198 * Display A on, no surface, top pipe = 0
1199 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1202 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1203 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1205 * The state 2->3 transition requires remapping MPCC 5 from display B
1208 * However, with the preferred pipe logic, state 2 would look like:
1211 * Display A on, no surface, top pipe = 0
1212 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1214 * This would then cause 2->3 to not require remapping any MPCCs.
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
;
1225 * search backwards for the second pipe to keep pipe
1226 * assignment more consistent
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
;
1237 return secondary_pipe
;
1240 struct pipe_ctx
*resource_get_head_pipe_for_stream(
1241 struct resource_context
*res_ctx
,
1242 struct dc_stream_state
*stream
)
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
];
1255 static struct pipe_ctx
*resource_get_tail_pipe(
1256 struct resource_context
*res_ctx
,
1257 struct pipe_ctx
*head_pipe
)
1259 struct pipe_ctx
*tail_pipe
;
1261 tail_pipe
= head_pipe
->bottom_pipe
;
1264 head_pipe
= tail_pipe
;
1265 tail_pipe
= tail_pipe
->bottom_pipe
;
1272 * A free_pipe for a stream is defined here as a pipe
1273 * that has no surface attached yet
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
)
1281 struct resource_context
*res_ctx
= &context
->res_ctx
;
1283 if (!head_pipe
->plane_state
)
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
];
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
1299 if (!pool
->funcs
->acquire_idle_pipe_for_layer
)
1302 return pool
->funcs
->acquire_idle_pipe_for_layer(context
, pool
, head_pipe
->stream
);
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
)
1313 for (i
= 0; i
< pool
->pipe_count
; i
++) {
1314 struct pipe_ctx
*split_pipe
= &res_ctx
->pipe_ctx
[i
];
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
;
1322 if (split_pipe
->top_pipe
->plane_state
)
1323 resource_build_scaling_params(split_pipe
->top_pipe
);
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
;
1334 split_pipe
->stream
= stream
;
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
)
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
;
1353 for (i
= 0; i
< context
->stream_count
; i
++)
1354 if (context
->streams
[i
] == stream
) {
1355 stream_status
= &context
->stream_status
[i
];
1358 if (stream_status
== NULL
) {
1359 dm_error("Existing stream not found; failed to attach surface!\n");
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
);
1370 head_pipe
= resource_get_head_pipe_for_stream(&context
->res_ctx
, stream
);
1373 dm_error("Head pipe not found for stream_state %p !\n", stream
);
1377 /* retain new surface, but only once per stream */
1378 dc_plane_state_retain(plane_state
);
1381 free_pipe
= acquire_free_pipe_for_head(context
, pool
, head_pipe
);
1383 #if defined(CONFIG_DRM_AMD_DC_DCN)
1385 int pipe_idx
= acquire_first_split_pipe(&context
->res_ctx
, pool
, stream
);
1387 free_pipe
= &context
->res_ctx
.pipe_ctx
[pipe_idx
];
1391 dc_plane_state_release(plane_state
);
1395 free_pipe
->plane_state
= plane_state
;
1397 if (head_pipe
!= free_pipe
) {
1398 tail_pipe
= resource_get_tail_pipe(&context
->res_ctx
, head_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
;
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
;
1417 head_pipe
= head_pipe
->next_odm_pipe
;
1419 /* assign new surfaces*/
1420 stream_status
->plane_states
[stream_status
->plane_count
] = plane_state
;
1422 stream_status
->plane_count
++;
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
)
1434 struct dc_stream_status
*stream_status
= NULL
;
1435 struct resource_pool
*pool
= dc
->res_pool
;
1437 for (i
= 0; i
< context
->stream_count
; i
++)
1438 if (context
->streams
[i
] == stream
) {
1439 stream_status
= &context
->stream_status
[i
];
1443 if (stream_status
== NULL
) {
1444 dm_error("Existing stream not found; failed to remove plane.\n");
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
];
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
;
1456 /* Second condition is to avoid setting NULL to top pipe
1457 * of tail pipe making it look like head pipe in subsequent
1460 if (pipe_ctx
->bottom_pipe
&& pipe_ctx
->top_pipe
)
1461 pipe_ctx
->bottom_pipe
->top_pipe
= pipe_ctx
->top_pipe
;
1464 * For head pipe detach surfaces from pipe for tail
1465 * pipe just zero it out
1467 if (!pipe_ctx
->top_pipe
)
1468 pipe_ctx
->plane_state
= NULL
;
1470 memset(pipe_ctx
, 0, sizeof(*pipe_ctx
));
1475 for (i
= 0; i
< stream_status
->plane_count
; i
++) {
1476 if (stream_status
->plane_states
[i
] == plane_state
) {
1478 dc_plane_state_release(stream_status
->plane_states
[i
]);
1483 if (i
== stream_status
->plane_count
) {
1484 dm_error("Existing plane_state not found; failed to detach it!\n");
1488 stream_status
->plane_count
--;
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];
1494 stream_status
->plane_states
[stream_status
->plane_count
] = NULL
;
1499 bool dc_rem_all_planes_for_stream(
1500 const struct dc
*dc
,
1501 struct dc_stream_state
*stream
,
1502 struct dc_state
*context
)
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 };
1508 for (i
= 0; i
< context
->stream_count
; i
++)
1509 if (context
->streams
[i
] == stream
) {
1510 stream_status
= &context
->stream_status
[i
];
1514 if (stream_status
== NULL
) {
1515 dm_error("Existing stream %p not found!\n", stream
);
1519 old_plane_count
= stream_status
->plane_count
;
1521 for (i
= 0; i
< old_plane_count
; i
++)
1522 del_planes
[i
] = stream_status
->plane_states
[i
];
1524 for (i
= 0; i
< old_plane_count
; i
++)
1525 if (!dc_remove_plane_from_context(dc
, stream
, del_planes
[i
], context
))
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
[],
1536 struct dc_state
*context
)
1540 for (i
= 0; i
< set_count
; i
++)
1541 if (set
[i
].stream
== stream
)
1544 if (i
== set_count
) {
1545 dm_error("Stream %p not found in set!\n", stream
);
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
))
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
,
1561 struct dc_state
*context
)
1563 struct dc_validation_set set
;
1566 set
.stream
= stream
;
1567 set
.plane_count
= plane_count
;
1569 for (i
= 0; i
< plane_count
; i
++)
1570 set
.plane_states
[i
] = plane_states
[i
];
1572 return add_all_planes_for_stream(dc
, stream
, &set
, 1, context
);
1575 static bool is_timing_changed(struct dc_stream_state
*cur_stream
,
1576 struct dc_stream_state
*new_stream
)
1578 if (cur_stream
== NULL
)
1581 /* If output color space is changed, need to reprogram info frames */
1582 if (cur_stream
->output_color_space
!= new_stream
->output_color_space
)
1586 &cur_stream
->timing
,
1587 &new_stream
->timing
,
1588 sizeof(struct dc_crtc_timing
)) != 0;
1591 static bool are_stream_backends_same(
1592 struct dc_stream_state
*stream_a
, struct dc_stream_state
*stream_b
)
1594 if (stream_a
== stream_b
)
1597 if (stream_a
== NULL
|| stream_b
== NULL
)
1600 if (is_timing_changed(stream_a
, stream_b
))
1603 if (stream_a
->signal
!= stream_b
->signal
)
1606 if (stream_a
->dpms_off
!= stream_b
->dpms_off
)
1613 * dc_is_stream_unchanged() - Compare two stream states for equivalence.
1615 * Checks if there a difference between the two states
1616 * that would require a mode change.
1618 * Does not compare cursor position or attributes.
1620 bool dc_is_stream_unchanged(
1621 struct dc_stream_state
*old_stream
, struct dc_stream_state
*stream
)
1624 if (!are_stream_backends_same(old_stream
, stream
))
1627 if (old_stream
->ignore_msa_timing_param
!= stream
->ignore_msa_timing_param
)
1630 /*compare audio info*/
1631 if (memcmp(&old_stream
->audio_info
, &stream
->audio_info
, sizeof(stream
->audio_info
)) != 0)
1638 * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
1640 bool dc_is_stream_scaling_unchanged(
1641 struct dc_stream_state
*old_stream
, struct dc_stream_state
*stream
)
1643 if (old_stream
== stream
)
1646 if (old_stream
== NULL
|| stream
== NULL
)
1649 if (memcmp(&old_stream
->src
,
1651 sizeof(struct rect
)) != 0)
1654 if (memcmp(&old_stream
->dst
,
1656 sizeof(struct rect
)) != 0)
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
,
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
;
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
,
1684 for (i
= 0; i
< pool
->audio_count
; i
++) {
1685 if (pool
->audios
[i
] == audio
)
1686 res_ctx
->is_audio_acquired
[i
] = acquired
;
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
)
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
];
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
];
1709 pipe_ctx
->plane_res
.mpcc_inst
= pool
->dpps
[i
]->inst
;
1710 pipe_ctx
->pipe_idx
= i
;
1713 pipe_ctx
->stream
= stream
;
1720 static struct audio
*find_first_free_audio(
1721 struct resource_context
*res_ctx
,
1722 const struct resource_pool
*pool
,
1724 enum dce_version dc_version
)
1726 int i
, available_audio_count
;
1728 available_audio_count
= pool
->audio_count
;
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*/
1735 return pool
->audios
[i
];
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
];
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
];
1753 * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state.
1755 enum dc_status
dc_add_stream_to_ctx(
1757 struct dc_state
*new_ctx
,
1758 struct dc_stream_state
*stream
)
1761 DC_LOGGER_INIT(dc
->ctx
->logger
);
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
;
1768 new_ctx
->streams
[new_ctx
->stream_count
] = stream
;
1769 dc_stream_retain(stream
);
1770 new_ctx
->stream_count
++;
1772 res
= dc
->res_pool
->funcs
->add_stream_to_ctx(dc
, new_ctx
, stream
);
1774 DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream
, res
);
1780 * dc_remove_stream_from_ctx() - Remove a stream from a dc_state.
1782 enum dc_status
dc_remove_stream_from_ctx(
1784 struct dc_state
*new_ctx
,
1785 struct dc_stream_state
*stream
)
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
;
1793 DC_ERROR("Pipe not found for stream %p !\n", stream
);
1794 return DC_ERROR_UNEXPECTED
;
1797 odm_pipe
= del_pipe
->next_odm_pipe
;
1799 /* Release primary pipe */
1800 ASSERT(del_pipe
->stream_res
.stream_enc
);
1801 update_stream_engine_usage(
1804 del_pipe
->stream_res
.stream_enc
,
1807 if (del_pipe
->stream_res
.audio
)
1811 del_pipe
->stream_res
.audio
,
1814 resource_unreference_clock_source(&new_ctx
->res_ctx
,
1816 del_pipe
->clock_source
);
1818 if (dc
->res_pool
->funcs
->remove_stream_from_ctx
)
1819 dc
->res_pool
->funcs
->remove_stream_from_ctx(dc
, new_ctx
, stream
);
1822 struct pipe_ctx
*next_odm_pipe
= odm_pipe
->next_odm_pipe
;
1824 memset(odm_pipe
, 0, sizeof(*odm_pipe
));
1825 odm_pipe
= next_odm_pipe
;
1827 memset(del_pipe
, 0, sizeof(*del_pipe
));
1829 for (i
= 0; i
< new_ctx
->stream_count
; i
++)
1830 if (new_ctx
->streams
[i
] == stream
)
1833 if (new_ctx
->streams
[i
] != stream
) {
1834 DC_ERROR("Context doesn't have stream %p !\n", stream
);
1835 return DC_ERROR_UNEXPECTED
;
1838 dc_stream_release(new_ctx
->streams
[i
]);
1839 new_ctx
->stream_count
--;
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];
1847 new_ctx
->streams
[new_ctx
->stream_count
] = NULL
;
1849 &new_ctx
->stream_status
[new_ctx
->stream_count
],
1851 sizeof(new_ctx
->stream_status
[0]));
1856 static struct dc_stream_state
*find_pll_sharable_stream(
1857 struct dc_stream_state
*stream_needs_pll
,
1858 struct dc_state
*context
)
1862 for (i
= 0; i
< context
->stream_count
; i
++) {
1863 struct dc_stream_state
*stream_has_pll
= context
->streams
[i
];
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
;
1878 static int get_norm_pix_clk(const struct dc_crtc_timing
*timing
)
1880 uint32_t pix_clk
= timing
->pix_clk_100hz
;
1881 uint32_t normalized_pix_clk
= pix_clk
;
1883 if (timing
->pixel_encoding
== PIXEL_ENCODING_YCBCR420
)
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
;
1891 case COLOR_DEPTH_101010
:
1892 normalized_pix_clk
= (pix_clk
* 30) / 24;
1894 case COLOR_DEPTH_121212
:
1895 normalized_pix_clk
= (pix_clk
* 36) / 24;
1897 case COLOR_DEPTH_161616
:
1898 normalized_pix_clk
= (pix_clk
* 48) / 24;
1905 return normalized_pix_clk
;
1908 static void calculate_phy_pix_clks(struct dc_stream_state
*stream
)
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;
1915 stream
->phy_pix_clk
=
1916 stream
->timing
.pix_clk_100hz
/ 10;
1918 if (stream
->timing
.timing_3d_format
== TIMING_3D_FORMAT_HW_FRAME_PACKING
)
1919 stream
->phy_pix_clk
*= 2;
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
)
1927 struct dc_link
*link
= stream
->link
;
1928 unsigned int i
, inst
, tg_inst
= 0;
1930 /* Check for enabled DIG to identify enabled display */
1931 if (!link
->link_enc
->funcs
->is_dig_enabled(link
->link_enc
))
1934 inst
= link
->link_enc
->funcs
->get_dig_frontend(link
->link_enc
);
1936 if (inst
== ENGINE_ID_UNKNOWN
)
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
]);
1947 // tg_inst not found
1948 if (i
== pool
->stream_enc_count
)
1951 if (tg_inst
>= pool
->timing_generator_count
)
1954 if (!res_ctx
->pipe_ctx
[tg_inst
].stream
) {
1955 struct pipe_ctx
*pipe_ctx
= &res_ctx
->pipe_ctx
[tg_inst
];
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
];
1965 if (pool
->dpps
[tg_inst
]) {
1966 pipe_ctx
->plane_res
.mpcc_inst
= pool
->dpps
[tg_inst
]->inst
;
1968 // Read DPP->MPCC->OPP Pipe from HW State
1969 if (pool
->mpc
->funcs
->read_mpcc_state
) {
1970 struct mpcc_state s
= {0};
1972 pool
->mpc
->funcs
->read_mpcc_state(pool
->mpc
, pipe_ctx
->plane_res
.mpcc_inst
, &s
);
1974 if (s
.dpp_id
< MAX_MPCC
)
1975 pool
->mpc
->mpcc_array
[pipe_ctx
->plane_res
.mpcc_inst
].dpp_id
= s
.dpp_id
;
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
];
1981 if (s
.opp_id
< MAX_OPP
)
1982 pipe_ctx
->stream_res
.opp
->mpc_tree_params
.opp_id
= s
.opp_id
;
1985 pipe_ctx
->pipe_idx
= tg_inst
;
1987 pipe_ctx
->stream
= stream
;
1994 static void mark_seamless_boot_stream(
1995 const struct dc
*dc
,
1996 struct dc_stream_state
*stream
)
1998 struct dc_bios
*dcb
= dc
->ctx
->dc_bios
;
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;
2008 enum dc_status
resource_map_pool_resources(
2009 const struct dc
*dc
,
2010 struct dc_state
*context
,
2011 struct dc_stream_state
*stream
)
2013 const struct resource_pool
*pool
= dc
->res_pool
;
2015 struct dc_context
*dc_ctx
= dc
->ctx
;
2016 struct pipe_ctx
*pipe_ctx
= NULL
;
2019 calculate_phy_pix_clks(stream
);
2021 mark_seamless_boot_stream(dc
, stream
);
2023 if (stream
->apply_seamless_boot_optimization
) {
2024 pipe_idx
= acquire_resource_from_hw_enabled_state(
2029 /* hw resource was assigned to other stream */
2030 stream
->apply_seamless_boot_optimization
= false;
2034 /* acquire new resources */
2035 pipe_idx
= acquire_first_free_pipe(&context
->res_ctx
, pool
, stream
);
2037 #ifdef CONFIG_DRM_AMD_DC_DCN
2039 pipe_idx
= acquire_first_split_pipe(&context
->res_ctx
, pool
, stream
);
2042 if (pipe_idx
< 0 || context
->res_ctx
.pipe_ctx
[pipe_idx
].stream_res
.tg
== NULL
)
2043 return DC_NO_CONTROLLER_RESOURCE
;
2045 pipe_ctx
= &context
->res_ctx
.pipe_ctx
[pipe_idx
];
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
);
2051 if (!pipe_ctx
->stream_res
.stream_enc
)
2052 return DC_NO_STREAM_ENC_RESOURCE
;
2054 update_stream_engine_usage(
2055 &context
->res_ctx
, pool
,
2056 pipe_ctx
->stream_res
.stream_enc
,
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
);
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
2071 if (pipe_ctx
->stream_res
.audio
)
2072 update_audio_usage(&context
->res_ctx
, pool
,
2073 pipe_ctx
->stream_res
.audio
, true);
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)
2080 pipe_ctx
->stream_res
.abm
= pool
->abm
;
2082 pipe_ctx
->stream_res
.abm
= pool
->multiple_abms
[pipe_ctx
->stream_res
.tg
->inst
];
2084 pipe_ctx
->stream_res
.abm
= pool
->abm
;
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;
2098 DC_ERROR("Stream %p not found in new ctx!\n", stream
);
2099 return DC_ERROR_UNEXPECTED
;
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
2108 void dc_resource_state_copy_construct_current(
2109 const struct dc
*dc
,
2110 struct dc_state
*dst_ctx
)
2112 dc_resource_state_copy_construct(dc
->current_state
, dst_ctx
);
2116 void dc_resource_state_construct(
2117 const struct dc
*dc
,
2118 struct dc_state
*dst_ctx
)
2120 dst_ctx
->clk_mgr
= dc
->clk_mgr
;
2124 bool dc_resource_is_dsc_encoding_supported(const struct dc
*dc
)
2126 return dc
->res_pool
->res_cap
->num_dsc
> 0;
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
2137 * Return: DC_OK if the result can be programmed. Otherwise, an error code.
2139 enum dc_status
dc_validate_global_state(
2141 struct dc_state
*new_ctx
,
2144 enum dc_status result
= DC_ERROR_UNEXPECTED
;
2148 return DC_ERROR_UNEXPECTED
;
2149 #if defined(CONFIG_DRM_AMD_DC_DCN)
2152 * Update link encoder to stream assignment.
2153 * TODO: Split out reason allocation from validation.
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
);
2160 if (dc
->res_pool
->funcs
->validate_global
) {
2161 result
= dc
->res_pool
->funcs
->validate_global(dc
, new_ctx
);
2162 if (result
!= DC_OK
)
2166 for (i
= 0; i
< new_ctx
->stream_count
; i
++) {
2167 struct dc_stream_state
*stream
= new_ctx
->streams
[i
];
2169 for (j
= 0; j
< dc
->res_pool
->pipe_count
; j
++) {
2170 struct pipe_ctx
*pipe_ctx
= &new_ctx
->res_ctx
.pipe_ctx
[j
];
2172 if (pipe_ctx
->stream
!= stream
)
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
)
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.
2187 if (dc_is_dp_signal(pipe_ctx
->stream
->signal
) &&
2188 !find_pll_sharable_stream(stream
, new_ctx
)) {
2190 resource_unreference_clock_source(
2193 pipe_ctx
->clock_source
);
2195 pipe_ctx
->clock_source
= dc
->res_pool
->dp_clock_source
;
2196 resource_reference_clock_source(
2199 pipe_ctx
->clock_source
);
2204 result
= resource_build_scaling_params_for_context(dc
, new_ctx
);
2206 if (result
== DC_OK
)
2207 if (!dc
->res_pool
->funcs
->validate_bandwidth(dc
, new_ctx
, fast_validate
))
2208 result
= DC_FAIL_BANDWIDTH_VALIDATE
;
2213 static void patch_gamut_packet_checksum(
2214 struct dc_info_packet
*gamut_packet
)
2216 /* For gamut we recalc checksum */
2217 if (gamut_packet
->valid
) {
2218 uint8_t chk_sum
= 0;
2222 /*start of the Gamut data. */
2223 ptr
= &gamut_packet
->sb
[3];
2225 for (i
= 0; i
<= gamut_packet
->sb
[1]; i
++)
2228 gamut_packet
->sb
[2] = (uint8_t) (0x100 - chk_sum
);
2232 static void set_avi_info_frame(
2233 struct dc_info_packet
*info_packet
,
2234 struct pipe_ctx
*pipe_ctx
)
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
;
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
;
2252 memset(&hdmi_info
, 0, sizeof(union hdmi_info_packet
));
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
;
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
;
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)
2271 switch (stream
->timing
.pixel_encoding
) {
2272 case PIXEL_ENCODING_YCBCR422
:
2276 case PIXEL_ENCODING_YCBCR444
:
2279 case PIXEL_ENCODING_YCBCR420
:
2283 case PIXEL_ENCODING_RGB
:
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
;
2292 /* A0 = 1 Active Format Information valid */
2293 hdmi_info
.bits
.A0
= ACTIVE_FORMAT_VALID
;
2295 /* B0, B1 = 3; Bar info data is valid */
2296 hdmi_info
.bits
.B0_B1
= BAR_INFO_BOTH_VALID
;
2298 hdmi_info
.bits
.SC0_SC1
= PICTURE_SCALING_UNIFORM
;
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
;
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
;
2313 hdmi_info
.bits
.C0_C1
= COLORIMETRY_NO_DATA
;
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
;
2325 /* TODO: un-hardcode aspect ratio */
2326 aspect
= stream
->timing
.aspect_ratio
;
2329 case ASPECT_RATIO_4_3
:
2330 case ASPECT_RATIO_16_9
:
2331 hdmi_info
.bits
.M0_M1
= aspect
;
2334 case ASPECT_RATIO_NO_DATA
:
2335 case ASPECT_RATIO_64_27
:
2336 case ASPECT_RATIO_256_135
:
2338 hdmi_info
.bits
.M0_M1
= 0;
2341 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
2342 hdmi_info
.bits
.R0_R3
= ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE
;
2344 /* TODO: un-hardcode cn0_cn1 and itc */
2352 support
= stream
->content_support
;
2355 if (!support
.bits
.valid_content_type
) {
2358 if (cn0_cn1
== DISPLAY_CONTENT_TYPE_GRAPHICS
) {
2359 if (support
.bits
.graphics_content
== 1) {
2362 } else if (cn0_cn1
== DISPLAY_CONTENT_TYPE_PHOTO
) {
2363 if (support
.bits
.photo_content
== 1) {
2369 } else if (cn0_cn1
== DISPLAY_CONTENT_TYPE_CINEMA
) {
2370 if (support
.bits
.cinema_content
== 1) {
2376 } else if (cn0_cn1
== DISPLAY_CONTENT_TYPE_GAME
) {
2377 if (support
.bits
.game_content
== 1) {
2385 hdmi_info
.bits
.CN0_CN1
= cn0_cn1_value
;
2386 hdmi_info
.bits
.ITC
= itc_value
;
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
;
2397 hdmi_info
.bits
.Q0_Q1
= RGB_QUANTIZATION_DEFAULT_RANGE
;
2399 hdmi_info
.bits
.Q0_Q1
= RGB_QUANTIZATION_DEFAULT_RANGE
;
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
;
2411 hdmi_info
.bits
.YQ0_YQ1
= YYC_QUANTIZATION_LIMITED_RANGE
;
2413 hdmi_info
.bits
.YQ0_YQ1
= YYC_QUANTIZATION_LIMITED_RANGE
;
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
) {
2437 /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
2438 hdmi_info
.bits
.VIC0_VIC7
= vic
;
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
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;
2451 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
2452 * repetition start from 1 */
2453 hdmi_info
.bits
.PR0_PR3
= 0;
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);
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)
2472 hdmi_info
.bits
.ACE0_ACE3
= 0;
2474 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
2475 check_sum
= &hdmi_info
.packet_raw_data
.sb
[0];
2477 *check_sum
= HDMI_INFOFRAME_TYPE_AVI
+ hdmi_info
.bits
.header
.length
+ hdmi_info
.bits
.header
.version
;
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
];
2482 /* one byte complement */
2483 *check_sum
= (uint8_t) (0x100 - *check_sum
);
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
;
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
];
2493 info_packet
->valid
= true;
2496 static void set_vendor_info_packet(
2497 struct dc_info_packet
*info_packet
,
2498 struct dc_stream_state
*stream
)
2500 /* SPD info packet for FreeSync */
2502 /* Check if Freesync is supported. Return if false. If true,
2503 * set the corresponding bit in the info packet
2505 if (!stream
->vsp_infopacket
.valid
)
2508 *info_packet
= stream
->vsp_infopacket
;
2511 static void set_spd_info_packet(
2512 struct dc_info_packet
*info_packet
,
2513 struct dc_stream_state
*stream
)
2515 /* SPD info packet for FreeSync */
2517 /* Check if Freesync is supported. Return if false. If true,
2518 * set the corresponding bit in the info packet
2520 if (!stream
->vrr_infopacket
.valid
)
2523 *info_packet
= stream
->vrr_infopacket
;
2526 static void set_hdr_static_info_packet(
2527 struct dc_info_packet
*info_packet
,
2528 struct dc_stream_state
*stream
)
2530 /* HDR Static Metadata info packet for HDR10 */
2532 if (!stream
->hdr_static_metadata
.valid
||
2533 stream
->use_dynamic_meta
)
2536 *info_packet
= stream
->hdr_static_metadata
;
2539 static void set_vsc_info_packet(
2540 struct dc_info_packet
*info_packet
,
2541 struct dc_stream_state
*stream
)
2543 if (!stream
->vsc_infopacket
.valid
)
2546 *info_packet
= stream
->vsc_infopacket
;
2549 void dc_resource_state_destruct(struct dc_state
*context
)
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
]);
2558 context
->stream_status
[i
].plane_count
= 0;
2559 dc_stream_release(context
->streams
[i
]);
2560 context
->streams
[i
] = NULL
;
2562 context
->stream_count
= 0;
2565 void dc_resource_state_copy_construct(
2566 const struct dc_state
*src_ctx
,
2567 struct dc_state
*dst_ctx
)
2570 struct kref refcount
= dst_ctx
->refcount
;
2572 *dst_ctx
= *src_ctx
;
2574 for (i
= 0; i
< MAX_PIPES
; i
++) {
2575 struct pipe_ctx
*cur_pipe
= &dst_ctx
->res_ctx
.pipe_ctx
[i
];
2577 if (cur_pipe
->top_pipe
)
2578 cur_pipe
->top_pipe
= &dst_ctx
->res_ctx
.pipe_ctx
[cur_pipe
->top_pipe
->pipe_idx
];
2580 if (cur_pipe
->bottom_pipe
)
2581 cur_pipe
->bottom_pipe
= &dst_ctx
->res_ctx
.pipe_ctx
[cur_pipe
->bottom_pipe
->pipe_idx
];
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
];
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
];
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
]);
2597 /* context refcount should not be overridden */
2598 dst_ctx
->refcount
= refcount
;
2602 struct clock_source
*dc_resource_find_first_free_pll(
2603 struct resource_context
*res_ctx
,
2604 const struct resource_pool
*pool
)
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
];
2616 void resource_build_info_frame(struct pipe_ctx
*pipe_ctx
)
2618 enum signal_type signal
= SIGNAL_TYPE_NONE
;
2619 struct encoder_info_frame
*info
= &pipe_ctx
->stream_res
.encoder_info_frame
;
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;
2629 signal
= pipe_ctx
->stream
->signal
;
2631 /* HDMi and DP have different info packets*/
2632 if (dc_is_hdmi_signal(signal
)) {
2633 set_avi_info_frame(&info
->avi
, pipe_ctx
);
2635 set_vendor_info_packet(&info
->vendor
, pipe_ctx
->stream
);
2637 set_spd_info_packet(&info
->spd
, pipe_ctx
->stream
);
2639 set_hdr_static_info_packet(&info
->hdrsmd
, pipe_ctx
->stream
);
2641 } else if (dc_is_dp_signal(signal
)) {
2642 set_vsc_info_packet(&info
->vsc
, pipe_ctx
->stream
);
2644 set_spd_info_packet(&info
->spd
, pipe_ctx
->stream
);
2646 set_hdr_static_info_packet(&info
->hdrsmd
, pipe_ctx
->stream
);
2649 patch_gamut_packet_checksum(&info
->gamut
);
2652 enum dc_status
resource_map_clock_resources(
2653 const struct dc
*dc
,
2654 struct dc_state
*context
,
2655 struct dc_stream_state
*stream
)
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
);
2663 return DC_ERROR_UNEXPECTED
;
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
;
2669 pipe_ctx
->clock_source
= NULL
;
2671 if (!dc
->config
.disable_disp_pll_sharing
)
2672 pipe_ctx
->clock_source
= resource_find_used_clk_src_for_sharing(
2676 if (pipe_ctx
->clock_source
== NULL
)
2677 pipe_ctx
->clock_source
=
2678 dc_resource_find_first_free_pll(
2683 if (pipe_ctx
->clock_source
== NULL
)
2684 return DC_NO_CLOCK_SOURCE_RESOURCE
;
2686 resource_reference_clock_source(
2687 &context
->res_ctx
, pool
,
2688 pipe_ctx
->clock_source
);
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.
2698 bool pipe_need_reprogram(
2699 struct pipe_ctx
*pipe_ctx_old
,
2700 struct pipe_ctx
*pipe_ctx
)
2702 if (!pipe_ctx_old
->stream
)
2705 if (pipe_ctx_old
->stream
->sink
!= pipe_ctx
->stream
->sink
)
2708 if (pipe_ctx_old
->stream
->signal
!= pipe_ctx
->stream
->signal
)
2711 if (pipe_ctx_old
->stream_res
.audio
!= pipe_ctx
->stream_res
.audio
)
2714 if (pipe_ctx_old
->clock_source
!= pipe_ctx
->clock_source
2715 && pipe_ctx_old
->stream
!= pipe_ctx
->stream
)
2718 if (pipe_ctx_old
->stream_res
.stream_enc
!= pipe_ctx
->stream_res
.stream_enc
)
2721 if (is_timing_changed(pipe_ctx_old
->stream
, pipe_ctx
->stream
))
2724 if (pipe_ctx_old
->stream
->dpms_off
!= pipe_ctx
->stream
->dpms_off
)
2727 if (false == pipe_ctx_old
->stream
->link
->link_state_valid
&&
2728 false == pipe_ctx_old
->stream
->dpms_off
)
2731 if (pipe_ctx_old
->stream_res
.dsc
!= pipe_ctx
->stream_res
.dsc
)
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
;
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
;
2745 return need_reprogram
;
2751 void resource_build_bit_depth_reduction_params(struct dc_stream_state
*stream
,
2752 struct bit_depth_reduction_params
*fmt_bit_depth
)
2754 enum dc_dither_option option
= stream
->dither_option
;
2755 enum dc_pixel_encoding pixel_encoding
=
2756 stream
->timing
.pixel_encoding
;
2758 memset(fmt_bit_depth
, 0, sizeof(*fmt_bit_depth
));
2760 if (option
== DITHER_OPTION_DEFAULT
) {
2761 switch (stream
->timing
.display_color_depth
) {
2762 case COLOR_DEPTH_666
:
2763 option
= DITHER_OPTION_SPATIAL6
;
2765 case COLOR_DEPTH_888
:
2766 option
= DITHER_OPTION_SPATIAL8
;
2768 case COLOR_DEPTH_101010
:
2769 option
= DITHER_OPTION_SPATIAL10
;
2772 option
= DITHER_OPTION_DISABLE
;
2776 if (option
== DITHER_OPTION_DISABLE
)
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;
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.
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;
2813 * note that spatial modes 1-3 are never used
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;
2845 if (option
== DITHER_OPTION_SPATIAL6
||
2846 option
== DITHER_OPTION_SPATIAL8
||
2847 option
== DITHER_OPTION_SPATIAL10
) {
2848 fmt_bit_depth
->flags
.FRAME_RANDOM
= 0;
2850 fmt_bit_depth
->flags
.FRAME_RANDOM
= 1;
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;
2874 fmt_bit_depth
->pixel_encoding
= pixel_encoding
;
2877 enum dc_status
dc_validate_stream(struct dc
*dc
, struct dc_stream_state
*stream
)
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
;
2883 calculate_phy_pix_clks(stream
);
2885 if (!tg
->funcs
->validate_timing(tg
, &stream
->timing
))
2886 res
= DC_FAIL_CONTROLLER_VALIDATE
;
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
;
2895 /* TODO: validate audio ASIC caps, encoder */
2898 res
= dc_link_validate_mode_timing(stream
,
2905 enum dc_status
dc_validate_plane(struct dc
*dc
, const struct dc_plane_state
*plane_state
)
2907 enum dc_status res
= DC_OK
;
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
);
2916 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format
)
2919 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS
:
2921 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr
:
2922 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb
:
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
:
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
:
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
:
2945 ASSERT_CRITICAL(false);
2949 static unsigned int get_max_audio_sample_rate(struct audio_mode
*modes
)
2952 if (modes
->sample_rates
.rate
.RATE_192
)
2954 if (modes
->sample_rates
.rate
.RATE_176_4
)
2956 if (modes
->sample_rates
.rate
.RATE_96
)
2958 if (modes
->sample_rates
.rate
.RATE_88_2
)
2960 if (modes
->sample_rates
.rate
.RATE_48
)
2962 if (modes
->sample_rates
.rate
.RATE_44_1
)
2964 if (modes
->sample_rates
.rate
.RATE_32
)
2967 /*original logic when no audio info*/
2971 void get_audio_check(struct audio_info
*aud_modes
,
2972 struct audio_check
*audio_chk
)
2975 unsigned int max_sample_rate
= 0;
2978 audio_chk
->audio_packet_type
= 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
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*/
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*/