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 "dm_services.h"
27
28 #include "resource.h"
29 #include "include/irq_service_interface.h"
30 #include "link_encoder.h"
31 #include "stream_encoder.h"
32 #include "opp.h"
33 #include "timing_generator.h"
34 #include "transform.h"
35 #include "dccg.h"
36 #include "dchubbub.h"
37 #include "dpp.h"
38 #include "core_types.h"
39 #include "set_mode_types.h"
40 #include "virtual/virtual_stream_encoder.h"
41 #include "dpcd_defs.h"
42 #include "link_enc_cfg.h"
43 #include "link.h"
44 #include "clk_mgr.h"
45 #include "dc_state_priv.h"
46 #include "virtual/virtual_link_hwss.h"
47 #include "link/hwss/link_hwss_dio.h"
48 #include "link/hwss/link_hwss_dpia.h"
49 #include "link/hwss/link_hwss_hpo_dp.h"
50 #include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h"
51 #include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h"
52
53 #if defined(CONFIG_DRM_AMD_DC_SI)
54 #include "dce60/dce60_resource.h"
55 #endif
56 #include "dce80/dce80_resource.h"
57 #include "dce100/dce100_resource.h"
58 #include "dce110/dce110_resource.h"
59 #include "dce112/dce112_resource.h"
60 #include "dce120/dce120_resource.h"
61 #include "dcn10/dcn10_resource.h"
62 #include "dcn20/dcn20_resource.h"
63 #include "dcn21/dcn21_resource.h"
64 #include "dcn201/dcn201_resource.h"
65 #include "dcn30/dcn30_resource.h"
66 #include "dcn301/dcn301_resource.h"
67 #include "dcn302/dcn302_resource.h"
68 #include "dcn303/dcn303_resource.h"
69 #include "dcn31/dcn31_resource.h"
70 #include "dcn314/dcn314_resource.h"
71 #include "dcn315/dcn315_resource.h"
72 #include "dcn316/dcn316_resource.h"
73 #include "dcn32/dcn32_resource.h"
74 #include "dcn321/dcn321_resource.h"
75 #include "dcn35/dcn35_resource.h"
76 #include "dcn351/dcn351_resource.h"
77
78 #define VISUAL_CONFIRM_BASE_DEFAULT 3
79 #define VISUAL_CONFIRM_BASE_MIN 1
80 #define VISUAL_CONFIRM_BASE_MAX 10
81 /* we choose 240 because it is a common denominator of common v addressable
82 * such as 2160, 1440, 1200, 960. So we take 1/240 portion of v addressable as
83 * the visual confirm dpp offset height. So visual confirm height can stay
84 * relatively the same independent from timing used.
85 */
86 #define VISUAL_CONFIRM_DPP_OFFSET_DENO 240
87
88 #define DC_LOGGER \
89 dc->ctx->logger
90 #define DC_LOGGER_INIT(logger)
91
92 #include "dml2/dml2_wrapper.h"
93
94 #define UNABLE_TO_SPLIT -1
95
resource_parse_asic_id(struct hw_asic_id asic_id)96 enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
97 {
98 enum dce_version dc_version = DCE_VERSION_UNKNOWN;
99
100 switch (asic_id.chip_family) {
101
102 #if defined(CONFIG_DRM_AMD_DC_SI)
103 case FAMILY_SI:
104 if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
105 ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
106 ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
107 dc_version = DCE_VERSION_6_0;
108 else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
109 dc_version = DCE_VERSION_6_4;
110 else
111 dc_version = DCE_VERSION_6_1;
112 break;
113 #endif
114 case FAMILY_CI:
115 dc_version = DCE_VERSION_8_0;
116 break;
117 case FAMILY_KV:
118 if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
119 ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
120 ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
121 dc_version = DCE_VERSION_8_3;
122 else
123 dc_version = DCE_VERSION_8_1;
124 break;
125 case FAMILY_CZ:
126 dc_version = DCE_VERSION_11_0;
127 break;
128
129 case FAMILY_VI:
130 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
131 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
132 dc_version = DCE_VERSION_10_0;
133 break;
134 }
135 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
136 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
137 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
138 dc_version = DCE_VERSION_11_2;
139 }
140 if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
141 dc_version = DCE_VERSION_11_22;
142 break;
143 case FAMILY_AI:
144 if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
145 dc_version = DCE_VERSION_12_1;
146 else
147 dc_version = DCE_VERSION_12_0;
148 break;
149 case FAMILY_RV:
150 dc_version = DCN_VERSION_1_0;
151 if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
152 dc_version = DCN_VERSION_1_01;
153 if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
154 dc_version = DCN_VERSION_2_1;
155 if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
156 dc_version = DCN_VERSION_2_1;
157 break;
158
159 case FAMILY_NV:
160 dc_version = DCN_VERSION_2_0;
161 if (asic_id.chip_id == DEVICE_ID_NV_13FE || asic_id.chip_id == DEVICE_ID_NV_143F) {
162 dc_version = DCN_VERSION_2_01;
163 break;
164 }
165 if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
166 dc_version = DCN_VERSION_3_0;
167 if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
168 dc_version = DCN_VERSION_3_02;
169 if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
170 dc_version = DCN_VERSION_3_03;
171 break;
172
173 case FAMILY_VGH:
174 dc_version = DCN_VERSION_3_01;
175 break;
176
177 case FAMILY_YELLOW_CARP:
178 if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
179 dc_version = DCN_VERSION_3_1;
180 break;
181 case AMDGPU_FAMILY_GC_10_3_6:
182 if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
183 dc_version = DCN_VERSION_3_15;
184 break;
185 case AMDGPU_FAMILY_GC_10_3_7:
186 if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
187 dc_version = DCN_VERSION_3_16;
188 break;
189 case AMDGPU_FAMILY_GC_11_0_0:
190 dc_version = DCN_VERSION_3_2;
191 if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
192 dc_version = DCN_VERSION_3_21;
193 break;
194 case AMDGPU_FAMILY_GC_11_0_1:
195 dc_version = DCN_VERSION_3_14;
196 break;
197 case AMDGPU_FAMILY_GC_11_5_0:
198 dc_version = DCN_VERSION_3_5;
199 if (ASICREV_IS_GC_11_0_4(asic_id.hw_internal_rev))
200 dc_version = DCN_VERSION_3_51;
201 break;
202 default:
203 dc_version = DCE_VERSION_UNKNOWN;
204 break;
205 }
206 return dc_version;
207 }
208
dc_create_resource_pool(struct dc * dc,const struct dc_init_data * init_data,enum dce_version dc_version)209 struct resource_pool *dc_create_resource_pool(struct dc *dc,
210 const struct dc_init_data *init_data,
211 enum dce_version dc_version)
212 {
213 struct resource_pool *res_pool = NULL;
214
215 switch (dc_version) {
216 #if defined(CONFIG_DRM_AMD_DC_SI)
217 case DCE_VERSION_6_0:
218 res_pool = dce60_create_resource_pool(
219 init_data->num_virtual_links, dc);
220 break;
221 case DCE_VERSION_6_1:
222 res_pool = dce61_create_resource_pool(
223 init_data->num_virtual_links, dc);
224 break;
225 case DCE_VERSION_6_4:
226 res_pool = dce64_create_resource_pool(
227 init_data->num_virtual_links, dc);
228 break;
229 #endif
230 case DCE_VERSION_8_0:
231 res_pool = dce80_create_resource_pool(
232 init_data->num_virtual_links, dc);
233 break;
234 case DCE_VERSION_8_1:
235 res_pool = dce81_create_resource_pool(
236 init_data->num_virtual_links, dc);
237 break;
238 case DCE_VERSION_8_3:
239 res_pool = dce83_create_resource_pool(
240 init_data->num_virtual_links, dc);
241 break;
242 case DCE_VERSION_10_0:
243 res_pool = dce100_create_resource_pool(
244 init_data->num_virtual_links, dc);
245 break;
246 case DCE_VERSION_11_0:
247 res_pool = dce110_create_resource_pool(
248 init_data->num_virtual_links, dc,
249 init_data->asic_id);
250 break;
251 case DCE_VERSION_11_2:
252 case DCE_VERSION_11_22:
253 res_pool = dce112_create_resource_pool(
254 init_data->num_virtual_links, dc);
255 break;
256 case DCE_VERSION_12_0:
257 case DCE_VERSION_12_1:
258 res_pool = dce120_create_resource_pool(
259 init_data->num_virtual_links, dc);
260 break;
261
262 #if defined(CONFIG_DRM_AMD_DC_FP)
263 case DCN_VERSION_1_0:
264 case DCN_VERSION_1_01:
265 res_pool = dcn10_create_resource_pool(init_data, dc);
266 break;
267 case DCN_VERSION_2_0:
268 res_pool = dcn20_create_resource_pool(init_data, dc);
269 break;
270 case DCN_VERSION_2_1:
271 res_pool = dcn21_create_resource_pool(init_data, dc);
272 break;
273 case DCN_VERSION_2_01:
274 res_pool = dcn201_create_resource_pool(init_data, dc);
275 break;
276 case DCN_VERSION_3_0:
277 res_pool = dcn30_create_resource_pool(init_data, dc);
278 break;
279 case DCN_VERSION_3_01:
280 res_pool = dcn301_create_resource_pool(init_data, dc);
281 break;
282 case DCN_VERSION_3_02:
283 res_pool = dcn302_create_resource_pool(init_data, dc);
284 break;
285 case DCN_VERSION_3_03:
286 res_pool = dcn303_create_resource_pool(init_data, dc);
287 break;
288 case DCN_VERSION_3_1:
289 res_pool = dcn31_create_resource_pool(init_data, dc);
290 break;
291 case DCN_VERSION_3_14:
292 res_pool = dcn314_create_resource_pool(init_data, dc);
293 break;
294 case DCN_VERSION_3_15:
295 res_pool = dcn315_create_resource_pool(init_data, dc);
296 break;
297 case DCN_VERSION_3_16:
298 res_pool = dcn316_create_resource_pool(init_data, dc);
299 break;
300 case DCN_VERSION_3_2:
301 res_pool = dcn32_create_resource_pool(init_data, dc);
302 break;
303 case DCN_VERSION_3_21:
304 res_pool = dcn321_create_resource_pool(init_data, dc);
305 break;
306 case DCN_VERSION_3_5:
307 res_pool = dcn35_create_resource_pool(init_data, dc);
308 break;
309 case DCN_VERSION_3_51:
310 res_pool = dcn351_create_resource_pool(init_data, dc);
311 break;
312 #endif /* CONFIG_DRM_AMD_DC_FP */
313 default:
314 break;
315 }
316
317 if (res_pool != NULL) {
318 if (dc->ctx->dc_bios->fw_info_valid) {
319 res_pool->ref_clocks.xtalin_clock_inKhz =
320 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
321 /* initialize with firmware data first, no all
322 * ASIC have DCCG SW component. FPGA or
323 * simulation need initialization of
324 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
325 * with xtalin_clock_inKhz
326 */
327 res_pool->ref_clocks.dccg_ref_clock_inKhz =
328 res_pool->ref_clocks.xtalin_clock_inKhz;
329 res_pool->ref_clocks.dchub_ref_clock_inKhz =
330 res_pool->ref_clocks.xtalin_clock_inKhz;
331 if (dc->debug.using_dml2)
332 if (res_pool->hubbub && res_pool->hubbub->funcs->get_dchub_ref_freq)
333 res_pool->hubbub->funcs->get_dchub_ref_freq(res_pool->hubbub,
334 res_pool->ref_clocks.dccg_ref_clock_inKhz,
335 &res_pool->ref_clocks.dchub_ref_clock_inKhz);
336 } else
337 ASSERT_CRITICAL(false);
338 }
339
340 return res_pool;
341 }
342
dc_destroy_resource_pool(struct dc * dc)343 void dc_destroy_resource_pool(struct dc *dc)
344 {
345 if (dc) {
346 if (dc->res_pool)
347 dc->res_pool->funcs->destroy(&dc->res_pool);
348
349 kfree(dc->hwseq);
350 }
351 }
352
update_num_audio(const struct resource_straps * straps,unsigned int * num_audio,struct audio_support * aud_support)353 static void update_num_audio(
354 const struct resource_straps *straps,
355 unsigned int *num_audio,
356 struct audio_support *aud_support)
357 {
358 aud_support->dp_audio = true;
359 aud_support->hdmi_audio_native = false;
360 aud_support->hdmi_audio_on_dongle = false;
361
362 if (straps->hdmi_disable == 0) {
363 if (straps->dc_pinstraps_audio & 0x2) {
364 aud_support->hdmi_audio_on_dongle = true;
365 aud_support->hdmi_audio_native = true;
366 }
367 }
368
369 switch (straps->audio_stream_number) {
370 case 0: /* multi streams supported */
371 break;
372 case 1: /* multi streams not supported */
373 *num_audio = 1;
374 break;
375 default:
376 DC_ERR("DC: unexpected audio fuse!\n");
377 }
378 }
379
resource_construct(unsigned int num_virtual_links,struct dc * dc,struct resource_pool * pool,const struct resource_create_funcs * create_funcs)380 bool resource_construct(
381 unsigned int num_virtual_links,
382 struct dc *dc,
383 struct resource_pool *pool,
384 const struct resource_create_funcs *create_funcs)
385 {
386 struct dc_context *ctx = dc->ctx;
387 const struct resource_caps *caps = pool->res_cap;
388 int i;
389 unsigned int num_audio = caps->num_audio;
390 struct resource_straps straps = {0};
391
392 if (create_funcs->read_dce_straps)
393 create_funcs->read_dce_straps(dc->ctx, &straps);
394
395 pool->audio_count = 0;
396 if (create_funcs->create_audio) {
397 /* find the total number of streams available via the
398 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
399 * registers (one for each pin) starting from pin 1
400 * up to the max number of audio pins.
401 * We stop on the first pin where
402 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
403 */
404 update_num_audio(&straps, &num_audio, &pool->audio_support);
405 for (i = 0; i < caps->num_audio; i++) {
406 struct audio *aud = create_funcs->create_audio(ctx, i);
407
408 if (aud == NULL) {
409 DC_ERR("DC: failed to create audio!\n");
410 return false;
411 }
412 if (!aud->funcs->endpoint_valid(aud)) {
413 aud->funcs->destroy(&aud);
414 break;
415 }
416 pool->audios[i] = aud;
417 pool->audio_count++;
418 }
419 }
420
421 pool->stream_enc_count = 0;
422 if (create_funcs->create_stream_encoder) {
423 for (i = 0; i < caps->num_stream_encoder; i++) {
424 pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
425 if (pool->stream_enc[i] == NULL)
426 DC_ERR("DC: failed to create stream_encoder!\n");
427 pool->stream_enc_count++;
428 }
429 }
430
431 pool->hpo_dp_stream_enc_count = 0;
432 if (create_funcs->create_hpo_dp_stream_encoder) {
433 for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
434 pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
435 if (pool->hpo_dp_stream_enc[i] == NULL)
436 DC_ERR("DC: failed to create HPO DP stream encoder!\n");
437 pool->hpo_dp_stream_enc_count++;
438
439 }
440 }
441
442 pool->hpo_dp_link_enc_count = 0;
443 if (create_funcs->create_hpo_dp_link_encoder) {
444 for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
445 pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
446 if (pool->hpo_dp_link_enc[i] == NULL)
447 DC_ERR("DC: failed to create HPO DP link encoder!\n");
448 pool->hpo_dp_link_enc_count++;
449 }
450 }
451
452 for (i = 0; i < caps->num_mpc_3dlut; i++) {
453 pool->mpc_lut[i] = dc_create_3dlut_func();
454 if (pool->mpc_lut[i] == NULL)
455 DC_ERR("DC: failed to create MPC 3dlut!\n");
456 pool->mpc_shaper[i] = dc_create_transfer_func();
457 if (pool->mpc_shaper[i] == NULL)
458 DC_ERR("DC: failed to create MPC shaper!\n");
459 }
460
461 dc->caps.dynamic_audio = false;
462 if (pool->audio_count < pool->stream_enc_count) {
463 dc->caps.dynamic_audio = true;
464 }
465 for (i = 0; i < num_virtual_links; i++) {
466 pool->stream_enc[pool->stream_enc_count] =
467 virtual_stream_encoder_create(
468 ctx, ctx->dc_bios);
469 if (pool->stream_enc[pool->stream_enc_count] == NULL) {
470 DC_ERR("DC: failed to create stream_encoder!\n");
471 return false;
472 }
473 pool->stream_enc_count++;
474 }
475
476 dc->hwseq = create_funcs->create_hwseq(ctx);
477
478 return true;
479 }
find_matching_clock_source(const struct resource_pool * pool,struct clock_source * clock_source)480 static int find_matching_clock_source(
481 const struct resource_pool *pool,
482 struct clock_source *clock_source)
483 {
484
485 int i;
486
487 for (i = 0; i < pool->clk_src_count; i++) {
488 if (pool->clock_sources[i] == clock_source)
489 return i;
490 }
491 return -1;
492 }
493
resource_unreference_clock_source(struct resource_context * res_ctx,const struct resource_pool * pool,struct clock_source * clock_source)494 void resource_unreference_clock_source(
495 struct resource_context *res_ctx,
496 const struct resource_pool *pool,
497 struct clock_source *clock_source)
498 {
499 int i = find_matching_clock_source(pool, clock_source);
500
501 if (i > -1)
502 res_ctx->clock_source_ref_count[i]--;
503
504 if (pool->dp_clock_source == clock_source)
505 res_ctx->dp_clock_source_ref_count--;
506 }
507
resource_reference_clock_source(struct resource_context * res_ctx,const struct resource_pool * pool,struct clock_source * clock_source)508 void resource_reference_clock_source(
509 struct resource_context *res_ctx,
510 const struct resource_pool *pool,
511 struct clock_source *clock_source)
512 {
513 int i = find_matching_clock_source(pool, clock_source);
514
515 if (i > -1)
516 res_ctx->clock_source_ref_count[i]++;
517
518 if (pool->dp_clock_source == clock_source)
519 res_ctx->dp_clock_source_ref_count++;
520 }
521
resource_get_clock_source_reference(struct resource_context * res_ctx,const struct resource_pool * pool,struct clock_source * clock_source)522 int resource_get_clock_source_reference(
523 struct resource_context *res_ctx,
524 const struct resource_pool *pool,
525 struct clock_source *clock_source)
526 {
527 int i = find_matching_clock_source(pool, clock_source);
528
529 if (i > -1)
530 return res_ctx->clock_source_ref_count[i];
531
532 if (pool->dp_clock_source == clock_source)
533 return res_ctx->dp_clock_source_ref_count;
534
535 return -1;
536 }
537
resource_are_vblanks_synchronizable(struct dc_stream_state * stream1,struct dc_stream_state * stream2)538 bool resource_are_vblanks_synchronizable(
539 struct dc_stream_state *stream1,
540 struct dc_stream_state *stream2)
541 {
542 uint32_t base60_refresh_rates[] = {10, 20, 5};
543 uint8_t i;
544 uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
545 uint64_t frame_time_diff;
546
547 if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
548 stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
549 dc_is_dp_signal(stream1->signal) &&
550 dc_is_dp_signal(stream2->signal) &&
551 false == stream1->has_non_synchronizable_pclk &&
552 false == stream2->has_non_synchronizable_pclk &&
553 stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
554 stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
555 /* disable refresh rates higher than 60Hz for now */
556 if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
557 stream1->timing.v_total > 60)
558 return false;
559 if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
560 stream2->timing.v_total > 60)
561 return false;
562 frame_time_diff = (uint64_t)10000 *
563 stream1->timing.h_total *
564 stream1->timing.v_total *
565 stream2->timing.pix_clk_100hz;
566 frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
567 frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
568 frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
569 for (i = 0; i < rr_count; i++) {
570 int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;
571
572 if (diff < 0)
573 diff = -diff;
574 if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
575 return true;
576 }
577 }
578 return false;
579 }
580
resource_are_streams_timing_synchronizable(struct dc_stream_state * stream1,struct dc_stream_state * stream2)581 bool resource_are_streams_timing_synchronizable(
582 struct dc_stream_state *stream1,
583 struct dc_stream_state *stream2)
584 {
585 if (stream1->timing.h_total != stream2->timing.h_total)
586 return false;
587
588 if (stream1->timing.v_total != stream2->timing.v_total)
589 return false;
590
591 if (stream1->timing.h_addressable
592 != stream2->timing.h_addressable)
593 return false;
594
595 if (stream1->timing.v_addressable
596 != stream2->timing.v_addressable)
597 return false;
598
599 if (stream1->timing.v_front_porch
600 != stream2->timing.v_front_porch)
601 return false;
602
603 if (stream1->timing.pix_clk_100hz
604 != stream2->timing.pix_clk_100hz)
605 return false;
606
607 if (stream1->clamping.c_depth != stream2->clamping.c_depth)
608 return false;
609
610 if (stream1->phy_pix_clk != stream2->phy_pix_clk
611 && (!dc_is_dp_signal(stream1->signal)
612 || !dc_is_dp_signal(stream2->signal)))
613 return false;
614
615 if (stream1->view_format != stream2->view_format)
616 return false;
617
618 if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
619 return false;
620
621 return true;
622 }
is_dp_and_hdmi_sharable(struct dc_stream_state * stream1,struct dc_stream_state * stream2)623 static bool is_dp_and_hdmi_sharable(
624 struct dc_stream_state *stream1,
625 struct dc_stream_state *stream2)
626 {
627 if (stream1->ctx->dc->caps.disable_dp_clk_share)
628 return false;
629
630 if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
631 stream2->clamping.c_depth != COLOR_DEPTH_888)
632 return false;
633
634 return true;
635
636 }
637
is_sharable_clk_src(const struct pipe_ctx * pipe_with_clk_src,const struct pipe_ctx * pipe)638 static bool is_sharable_clk_src(
639 const struct pipe_ctx *pipe_with_clk_src,
640 const struct pipe_ctx *pipe)
641 {
642 if (pipe_with_clk_src->clock_source == NULL)
643 return false;
644
645 if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
646 return false;
647
648 if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
649 (dc_is_dp_signal(pipe->stream->signal) &&
650 !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
651 pipe->stream)))
652 return false;
653
654 if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
655 && dc_is_dual_link_signal(pipe->stream->signal))
656 return false;
657
658 if (dc_is_hdmi_signal(pipe->stream->signal)
659 && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
660 return false;
661
662 if (!resource_are_streams_timing_synchronizable(
663 pipe_with_clk_src->stream, pipe->stream))
664 return false;
665
666 return true;
667 }
668
resource_find_used_clk_src_for_sharing(struct resource_context * res_ctx,struct pipe_ctx * pipe_ctx)669 struct clock_source *resource_find_used_clk_src_for_sharing(
670 struct resource_context *res_ctx,
671 struct pipe_ctx *pipe_ctx)
672 {
673 int i;
674
675 for (i = 0; i < MAX_PIPES; i++) {
676 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
677 return res_ctx->pipe_ctx[i].clock_source;
678 }
679
680 return NULL;
681 }
682
convert_pixel_format_to_dalsurface(enum surface_pixel_format surface_pixel_format)683 static enum pixel_format convert_pixel_format_to_dalsurface(
684 enum surface_pixel_format surface_pixel_format)
685 {
686 enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
687
688 switch (surface_pixel_format) {
689 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
690 dal_pixel_format = PIXEL_FORMAT_INDEX8;
691 break;
692 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
693 dal_pixel_format = PIXEL_FORMAT_RGB565;
694 break;
695 case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
696 dal_pixel_format = PIXEL_FORMAT_RGB565;
697 break;
698 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
699 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
700 break;
701 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
702 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
703 break;
704 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
705 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
706 break;
707 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
708 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
709 break;
710 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
711 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
712 break;
713 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
714 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
715 dal_pixel_format = PIXEL_FORMAT_FP16;
716 break;
717 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
718 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
719 dal_pixel_format = PIXEL_FORMAT_420BPP8;
720 break;
721 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
722 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
723 dal_pixel_format = PIXEL_FORMAT_420BPP10;
724 break;
725 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
726 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
727 default:
728 dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
729 break;
730 }
731 return dal_pixel_format;
732 }
733
get_vp_scan_direction(enum dc_rotation_angle rotation,bool horizontal_mirror,bool * orthogonal_rotation,bool * flip_vert_scan_dir,bool * flip_horz_scan_dir)734 static inline void get_vp_scan_direction(
735 enum dc_rotation_angle rotation,
736 bool horizontal_mirror,
737 bool *orthogonal_rotation,
738 bool *flip_vert_scan_dir,
739 bool *flip_horz_scan_dir)
740 {
741 *orthogonal_rotation = false;
742 *flip_vert_scan_dir = false;
743 *flip_horz_scan_dir = false;
744 if (rotation == ROTATION_ANGLE_180) {
745 *flip_vert_scan_dir = true;
746 *flip_horz_scan_dir = true;
747 } else if (rotation == ROTATION_ANGLE_90) {
748 *orthogonal_rotation = true;
749 *flip_horz_scan_dir = true;
750 } else if (rotation == ROTATION_ANGLE_270) {
751 *orthogonal_rotation = true;
752 *flip_vert_scan_dir = true;
753 }
754
755 if (horizontal_mirror)
756 *flip_horz_scan_dir = !*flip_horz_scan_dir;
757 }
758
759 /*
760 * This is a preliminary vp size calculation to allow us to check taps support.
761 * The result is completely overridden afterwards.
762 */
calculate_viewport_size(struct pipe_ctx * pipe_ctx)763 static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
764 {
765 struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
766
767 data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width));
768 data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height));
769 data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width));
770 data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height));
771 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
772 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
773 swap(data->viewport.width, data->viewport.height);
774 swap(data->viewport_c.width, data->viewport_c.height);
775 }
776 }
777
intersect_rec(const struct rect * r0,const struct rect * r1)778 static struct rect intersect_rec(const struct rect *r0, const struct rect *r1)
779 {
780 struct rect rec;
781 int r0_x_end = r0->x + r0->width;
782 int r1_x_end = r1->x + r1->width;
783 int r0_y_end = r0->y + r0->height;
784 int r1_y_end = r1->y + r1->height;
785
786 rec.x = r0->x > r1->x ? r0->x : r1->x;
787 rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;
788 rec.y = r0->y > r1->y ? r0->y : r1->y;
789 rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;
790
791 /* in case that there is no intersection */
792 if (rec.width < 0 || rec.height < 0)
793 memset(&rec, 0, sizeof(rec));
794
795 return rec;
796 }
797
shift_rec(const struct rect * rec_in,int x,int y)798 static struct rect shift_rec(const struct rect *rec_in, int x, int y)
799 {
800 struct rect rec_out = *rec_in;
801
802 rec_out.x += x;
803 rec_out.y += y;
804
805 return rec_out;
806 }
807
calculate_odm_slice_in_timing_active(struct pipe_ctx * pipe_ctx)808 static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx)
809 {
810 const struct dc_stream_state *stream = pipe_ctx->stream;
811 int odm_slice_count = resource_get_odm_slice_count(pipe_ctx);
812 int odm_slice_idx = resource_get_odm_slice_index(pipe_ctx);
813 bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
814 int h_active = stream->timing.h_addressable +
815 stream->timing.h_border_left +
816 stream->timing.h_border_right;
817 int odm_slice_width = h_active / odm_slice_count;
818 struct rect odm_rec;
819
820 odm_rec.x = odm_slice_width * odm_slice_idx;
821 odm_rec.width = is_last_odm_slice ?
822 /* last slice width is the reminder of h_active */
823 h_active - odm_slice_width * (odm_slice_count - 1) :
824 /* odm slice width is the floor of h_active / count */
825 odm_slice_width;
826 odm_rec.y = 0;
827 odm_rec.height = stream->timing.v_addressable +
828 stream->timing.v_border_bottom +
829 stream->timing.v_border_top;
830
831 return odm_rec;
832 }
833
calculate_plane_rec_in_timing_active(struct pipe_ctx * pipe_ctx,const struct rect * rec_in)834 static struct rect calculate_plane_rec_in_timing_active(
835 struct pipe_ctx *pipe_ctx,
836 const struct rect *rec_in)
837 {
838 /*
839 * The following diagram shows an example where we map a 1920x1200
840 * desktop to a 2560x1440 timing with a plane rect in the middle
841 * of the screen. To map a plane rect from Stream Source to Timing
842 * Active space, we first multiply stream scaling ratios (i.e 2304/1920
843 * horizontal and 1440/1200 vertical) to the plane's x and y, then
844 * we add stream destination offsets (i.e 128 horizontal, 0 vertical).
845 * This will give us a plane rect's position in Timing Active. However
846 * we have to remove the fractional. The rule is that we find left/right
847 * and top/bottom positions and round the value to the adjacent integer.
848 *
849 * Stream Source Space
850 * ------------
851 * __________________________________________________
852 * |Stream Source (1920 x 1200) ^ |
853 * | y |
854 * | <------- w --------|> |
855 * | __________________V |
856 * |<-- x -->|Plane//////////////| ^ |
857 * | |(pre scale)////////| | |
858 * | |///////////////////| | |
859 * | |///////////////////| h |
860 * | |///////////////////| | |
861 * | |///////////////////| | |
862 * | |///////////////////| V |
863 * | |
864 * | |
865 * |__________________________________________________|
866 *
867 *
868 * Timing Active Space
869 * ---------------------------------
870 *
871 * Timing Active (2560 x 1440)
872 * __________________________________________________
873 * |*****| Stteam Destination (2304 x 1440) |*****|
874 * |*****| |*****|
875 * |<128>| |*****|
876 * |*****| __________________ |*****|
877 * |*****| |Plane/////////////| |*****|
878 * |*****| |(post scale)//////| |*****|
879 * |*****| |//////////////////| |*****|
880 * |*****| |//////////////////| |*****|
881 * |*****| |//////////////////| |*****|
882 * |*****| |//////////////////| |*****|
883 * |*****| |*****|
884 * |*****| |*****|
885 * |*****| |*****|
886 * |*****|______________________________________|*****|
887 *
888 * So the resulting formulas are shown below:
889 *
890 * recout_x = 128 + round(plane_x * 2304 / 1920)
891 * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x
892 * recout_y = 0 + round(plane_y * 1440 / 1280)
893 * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y
894 *
895 * NOTE: fixed point division is not error free. To reduce errors
896 * introduced by fixed point division, we divide only after
897 * multiplication is complete.
898 */
899 const struct dc_stream_state *stream = pipe_ctx->stream;
900 struct rect rec_out = {0};
901 struct fixed31_32 temp;
902
903 temp = dc_fixpt_from_fraction(rec_in->x * stream->dst.width,
904 stream->src.width);
905 rec_out.x = stream->dst.x + dc_fixpt_round(temp);
906
907 temp = dc_fixpt_from_fraction(
908 (rec_in->x + rec_in->width) * stream->dst.width,
909 stream->src.width);
910 rec_out.width = stream->dst.x + dc_fixpt_round(temp) - rec_out.x;
911
912 temp = dc_fixpt_from_fraction(rec_in->y * stream->dst.height,
913 stream->src.height);
914 rec_out.y = stream->dst.y + dc_fixpt_round(temp);
915
916 temp = dc_fixpt_from_fraction(
917 (rec_in->y + rec_in->height) * stream->dst.height,
918 stream->src.height);
919 rec_out.height = stream->dst.y + dc_fixpt_round(temp) - rec_out.y;
920
921 return rec_out;
922 }
923
calculate_mpc_slice_in_timing_active(struct pipe_ctx * pipe_ctx,struct rect * plane_clip_rec)924 static struct rect calculate_mpc_slice_in_timing_active(
925 struct pipe_ctx *pipe_ctx,
926 struct rect *plane_clip_rec)
927 {
928 const struct dc_stream_state *stream = pipe_ctx->stream;
929 int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx);
930 int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx);
931 int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
932 struct rect mpc_rec;
933
934 mpc_rec.width = plane_clip_rec->width / mpc_slice_count;
935 mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
936 mpc_rec.height = plane_clip_rec->height;
937 mpc_rec.y = plane_clip_rec->y;
938 ASSERT(mpc_slice_count == 1 ||
939 stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE ||
940 mpc_rec.width % 2 == 0);
941
942 /* extra pixels in the division remainder need to go to pipes after
943 * the extra pixel index minus one(epimo) defined here as:
944 */
945 if (mpc_slice_idx > epimo) {
946 mpc_rec.x += mpc_slice_idx - epimo - 1;
947 mpc_rec.width += 1;
948 }
949
950 if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
951 ASSERT(mpc_rec.height % 2 == 0);
952 mpc_rec.height /= 2;
953 }
954 return mpc_rec;
955 }
956
adjust_recout_for_visual_confirm(struct rect * recout,struct pipe_ctx * pipe_ctx)957 static void adjust_recout_for_visual_confirm(struct rect *recout,
958 struct pipe_ctx *pipe_ctx)
959 {
960 struct dc *dc = pipe_ctx->stream->ctx->dc;
961 int dpp_offset, base_offset;
962
963 if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE || !pipe_ctx->plane_res.dpp)
964 return;
965
966 dpp_offset = pipe_ctx->stream->timing.v_addressable / VISUAL_CONFIRM_DPP_OFFSET_DENO;
967 dpp_offset *= pipe_ctx->plane_res.dpp->inst;
968
969 if ((dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_BASE_MIN) &&
970 dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_BASE_MAX)
971 base_offset = dc->debug.visual_confirm_rect_height;
972 else
973 base_offset = VISUAL_CONFIRM_BASE_DEFAULT;
974
975 recout->height -= base_offset;
976 recout->height -= dpp_offset;
977 }
978
979 /*
980 * The function maps a plane clip from Stream Source Space to ODM Slice Space
981 * and calculates the rec of the overlapping area of MPC slice of the plane
982 * clip, ODM slice associated with the pipe context and stream destination rec.
983 */
calculate_recout(struct pipe_ctx * pipe_ctx)984 static void calculate_recout(struct pipe_ctx *pipe_ctx)
985 {
986 /*
987 * A plane clip represents the desired plane size and position in Stream
988 * Source Space. Stream Source is the destination where all planes are
989 * blended (i.e. positioned, scaled and overlaid). It is a canvas where
990 * all planes associated with the current stream are drawn together.
991 * After Stream Source is completed, we will further scale and
992 * reposition the entire canvas of the stream source to Stream
993 * Destination in Timing Active Space. This could be due to display
994 * overscan adjustment where we will need to rescale and reposition all
995 * the planes so they can fit into a TV with overscan or downscale
996 * upscale features such as GPU scaling or VSR.
997 *
998 * This two step blending is a virtual procedure in software. In
999 * hardware there is no such thing as Stream Source. all planes are
1000 * blended once in Timing Active Space. Software virtualizes a Stream
1001 * Source space to decouple the math complicity so scaling param
1002 * calculation focuses on one step at a time.
1003 *
1004 * In the following two diagrams, user applied 10% overscan adjustment
1005 * so the Stream Source needs to be scaled down a little before mapping
1006 * to Timing Active Space. As a result the Plane Clip is also scaled
1007 * down by the same ratio, Plane Clip position (i.e. x and y) with
1008 * respect to Stream Source is also scaled down. To map it in Timing
1009 * Active Space additional x and y offsets from Stream Destination are
1010 * added to Plane Clip as well.
1011 *
1012 * Stream Source Space
1013 * ------------
1014 * __________________________________________________
1015 * |Stream Source (3840 x 2160) ^ |
1016 * | y |
1017 * | | |
1018 * | __________________V |
1019 * |<-- x -->|Plane Clip/////////| |
1020 * | |(pre scale)////////| |
1021 * | |///////////////////| |
1022 * | |///////////////////| |
1023 * | |///////////////////| |
1024 * | |///////////////////| |
1025 * | |///////////////////| |
1026 * | |
1027 * | |
1028 * |__________________________________________________|
1029 *
1030 *
1031 * Timing Active Space (3840 x 2160)
1032 * ---------------------------------
1033 *
1034 * Timing Active
1035 * __________________________________________________
1036 * | y_____________________________________________ |
1037 * |x |Stream Destination (3456 x 1944) | |
1038 * | | | |
1039 * | | __________________ | |
1040 * | | |Plane Clip////////| | |
1041 * | | |(post scale)//////| | |
1042 * | | |//////////////////| | |
1043 * | | |//////////////////| | |
1044 * | | |//////////////////| | |
1045 * | | |//////////////////| | |
1046 * | | | |
1047 * | | | |
1048 * | |____________________________________________| |
1049 * |__________________________________________________|
1050 *
1051 *
1052 * In Timing Active Space a plane clip could be further sliced into
1053 * pieces called MPC slices. Each Pipe Context is responsible for
1054 * processing only one MPC slice so the plane processing workload can be
1055 * distributed to multiple DPP Pipes. MPC slices could be blended
1056 * together to a single ODM slice. Each ODM slice is responsible for
1057 * processing a portion of Timing Active divided horizontally so the
1058 * output pixel processing workload can be distributed to multiple OPP
1059 * pipes. All ODM slices are mapped together in ODM block so all MPC
1060 * slices belong to different ODM slices could be pieced together to
1061 * form a single image in Timing Active. MPC slices must belong to
1062 * single ODM slice. If an MPC slice goes across ODM slice boundary, it
1063 * needs to be divided into two MPC slices one for each ODM slice.
1064 *
1065 * In the following diagram the output pixel processing workload is
1066 * divided horizontally into two ODM slices one for each OPP blend tree.
1067 * OPP0 blend tree is responsible for processing left half of Timing
1068 * Active, while OPP2 blend tree is responsible for processing right
1069 * half.
1070 *
1071 * The plane has two MPC slices. However since the right MPC slice goes
1072 * across ODM boundary, two DPP pipes are needed one for each OPP blend
1073 * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).
1074 *
1075 * Assuming that we have a Pipe Context associated with OPP0 and DPP1
1076 * working on processing the plane in the diagram. We want to know the
1077 * width and height of the shaded rectangle and its relative position
1078 * with respect to the ODM slice0. This is called the recout of the pipe
1079 * context.
1080 *
1081 * Planes can be at arbitrary size and position and there could be an
1082 * arbitrary number of MPC and ODM slices. The algorithm needs to take
1083 * all scenarios into account.
1084 *
1085 * Timing Active Space (3840 x 2160)
1086 * ---------------------------------
1087 *
1088 * Timing Active
1089 * __________________________________________________
1090 * |OPP0(ODM slice0)^ |OPP2(ODM slice1) |
1091 * | y | |
1092 * | | <- w -> |
1093 * | _____V________|____ |
1094 * | |DPP0 ^ |DPP1 |DPP2| |
1095 * |<------ x |-----|->|/////| | |
1096 * | | | |/////| | |
1097 * | | h |/////| | |
1098 * | | | |/////| | |
1099 * | |_____V__|/////|____| |
1100 * | | |
1101 * | | |
1102 * | | |
1103 * |_________________________|________________________|
1104 *
1105 *
1106 */
1107 struct rect plane_clip;
1108 struct rect mpc_slice_of_plane_clip;
1109 struct rect odm_slice;
1110 struct rect overlapping_area;
1111
1112 plane_clip = calculate_plane_rec_in_timing_active(pipe_ctx,
1113 &pipe_ctx->plane_state->clip_rect);
1114 /* guard plane clip from drawing beyond stream dst here */
1115 plane_clip = intersect_rec(&plane_clip,
1116 &pipe_ctx->stream->dst);
1117 mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(
1118 pipe_ctx, &plane_clip);
1119 odm_slice = calculate_odm_slice_in_timing_active(pipe_ctx);
1120 overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice);
1121 if (overlapping_area.height > 0 &&
1122 overlapping_area.width > 0) {
1123 /* shift the overlapping area so it is with respect to current
1124 * ODM slice's position
1125 */
1126 pipe_ctx->plane_res.scl_data.recout = shift_rec(
1127 &overlapping_area,
1128 -odm_slice.x, -odm_slice.y);
1129 adjust_recout_for_visual_confirm(
1130 &pipe_ctx->plane_res.scl_data.recout,
1131 pipe_ctx);
1132 } else {
1133 /* if there is no overlap, zero recout */
1134 memset(&pipe_ctx->plane_res.scl_data.recout, 0,
1135 sizeof(struct rect));
1136 }
1137
1138 }
1139
calculate_scaling_ratios(struct pipe_ctx * pipe_ctx)1140 static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
1141 {
1142 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1143 const struct dc_stream_state *stream = pipe_ctx->stream;
1144 struct rect surf_src = plane_state->src_rect;
1145 const int in_w = stream->src.width;
1146 const int in_h = stream->src.height;
1147 const int out_w = stream->dst.width;
1148 const int out_h = stream->dst.height;
1149
1150 /*Swap surf_src height and width since scaling ratios are in recout rotation*/
1151 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
1152 pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
1153 swap(surf_src.height, surf_src.width);
1154
1155 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
1156 surf_src.width,
1157 plane_state->dst_rect.width);
1158 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
1159 surf_src.height,
1160 plane_state->dst_rect.height);
1161
1162 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1163 pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
1164 else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1165 pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;
1166
1167 pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
1168 pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
1169 pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
1170 pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);
1171
1172 pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
1173 pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;
1174
1175 if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
1176 || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
1177 pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
1178 pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
1179 }
1180 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
1181 pipe_ctx->plane_res.scl_data.ratios.horz, 19);
1182 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
1183 pipe_ctx->plane_res.scl_data.ratios.vert, 19);
1184 pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
1185 pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
1186 pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
1187 pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
1188 }
1189
1190
1191 /*
1192 * We completely calculate vp offset, size and inits here based entirely on scaling
1193 * ratios and recout for pixel perfect pipe combine.
1194 */
calculate_init_and_vp(bool flip_scan_dir,int recout_offset_within_recout_full,int recout_size,int src_size,int taps,struct fixed31_32 ratio,struct fixed31_32 * init,int * vp_offset,int * vp_size)1195 static void calculate_init_and_vp(
1196 bool flip_scan_dir,
1197 int recout_offset_within_recout_full,
1198 int recout_size,
1199 int src_size,
1200 int taps,
1201 struct fixed31_32 ratio,
1202 struct fixed31_32 *init,
1203 int *vp_offset,
1204 int *vp_size)
1205 {
1206 struct fixed31_32 temp;
1207 int int_part;
1208
1209 /*
1210 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
1211 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
1212 * All following calculations are based on this logic.
1213 *
1214 * Init calculated according to formula:
1215 * init = (scaling_ratio + number_of_taps + 1) / 2
1216 * init_bot = init + scaling_ratio
1217 * to get pixel perfect combine add the fraction from calculating vp offset
1218 */
1219 temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
1220 *vp_offset = dc_fixpt_floor(temp);
1221 temp.value &= 0xffffffff;
1222 *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
1223 dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
1224 /*
1225 * If viewport has non 0 offset and there are more taps than covered by init then
1226 * we should decrease the offset and increase init so we are never sampling
1227 * outside of viewport.
1228 */
1229 int_part = dc_fixpt_floor(*init);
1230 if (int_part < taps) {
1231 int_part = taps - int_part;
1232 if (int_part > *vp_offset)
1233 int_part = *vp_offset;
1234 *vp_offset -= int_part;
1235 *init = dc_fixpt_add_int(*init, int_part);
1236 }
1237 /*
1238 * If taps are sampling outside of viewport at end of recout and there are more pixels
1239 * available in the surface we should increase the viewport size, regardless set vp to
1240 * only what is used.
1241 */
1242 temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
1243 *vp_size = dc_fixpt_floor(temp);
1244 if (*vp_size + *vp_offset > src_size)
1245 *vp_size = src_size - *vp_offset;
1246
1247 /* We did all the math assuming we are scanning same direction as display does,
1248 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
1249 * is flipped we simply need to calculate offset from the other side of plane.
1250 * Note that outside of viewport all scaling hardware works in recout space.
1251 */
1252 if (flip_scan_dir)
1253 *vp_offset = src_size - *vp_offset - *vp_size;
1254 }
1255
calculate_inits_and_viewports(struct pipe_ctx * pipe_ctx)1256 static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
1257 {
1258 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1259 struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
1260 struct rect src = plane_state->src_rect;
1261 struct rect recout_dst_in_active_timing;
1262 struct rect recout_clip_in_active_timing;
1263 struct rect recout_clip_in_recout_dst;
1264 struct rect overlap_in_active_timing;
1265 struct rect odm_slice = calculate_odm_slice_in_timing_active(pipe_ctx);
1266 int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
1267 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
1268 bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
1269
1270 recout_clip_in_active_timing = shift_rec(
1271 &data->recout, odm_slice.x, odm_slice.y);
1272 recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(
1273 pipe_ctx, &plane_state->dst_rect);
1274 overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing,
1275 &recout_dst_in_active_timing);
1276 if (overlap_in_active_timing.width > 0 &&
1277 overlap_in_active_timing.height > 0)
1278 recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing,
1279 -recout_dst_in_active_timing.x,
1280 -recout_dst_in_active_timing.y);
1281 else
1282 memset(&recout_clip_in_recout_dst, 0, sizeof(struct rect));
1283
1284 /*
1285 * Work in recout rotation since that requires less transformations
1286 */
1287 get_vp_scan_direction(
1288 plane_state->rotation,
1289 plane_state->horizontal_mirror,
1290 &orthogonal_rotation,
1291 &flip_vert_scan_dir,
1292 &flip_horz_scan_dir);
1293
1294 if (orthogonal_rotation) {
1295 swap(src.width, src.height);
1296 swap(flip_vert_scan_dir, flip_horz_scan_dir);
1297 }
1298
1299 calculate_init_and_vp(
1300 flip_horz_scan_dir,
1301 recout_clip_in_recout_dst.x,
1302 data->recout.width,
1303 src.width,
1304 data->taps.h_taps,
1305 data->ratios.horz,
1306 &data->inits.h,
1307 &data->viewport.x,
1308 &data->viewport.width);
1309 calculate_init_and_vp(
1310 flip_horz_scan_dir,
1311 recout_clip_in_recout_dst.x,
1312 data->recout.width,
1313 src.width / vpc_div,
1314 data->taps.h_taps_c,
1315 data->ratios.horz_c,
1316 &data->inits.h_c,
1317 &data->viewport_c.x,
1318 &data->viewport_c.width);
1319 calculate_init_and_vp(
1320 flip_vert_scan_dir,
1321 recout_clip_in_recout_dst.y,
1322 data->recout.height,
1323 src.height,
1324 data->taps.v_taps,
1325 data->ratios.vert,
1326 &data->inits.v,
1327 &data->viewport.y,
1328 &data->viewport.height);
1329 calculate_init_and_vp(
1330 flip_vert_scan_dir,
1331 recout_clip_in_recout_dst.y,
1332 data->recout.height,
1333 src.height / vpc_div,
1334 data->taps.v_taps_c,
1335 data->ratios.vert_c,
1336 &data->inits.v_c,
1337 &data->viewport_c.y,
1338 &data->viewport_c.height);
1339 if (orthogonal_rotation) {
1340 swap(data->viewport.x, data->viewport.y);
1341 swap(data->viewport.width, data->viewport.height);
1342 swap(data->viewport_c.x, data->viewport_c.y);
1343 swap(data->viewport_c.width, data->viewport_c.height);
1344 }
1345 data->viewport.x += src.x;
1346 data->viewport.y += src.y;
1347 ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
1348 data->viewport_c.x += src.x / vpc_div;
1349 data->viewport_c.y += src.y / vpc_div;
1350 }
1351
is_subvp_high_refresh_candidate(struct dc_stream_state * stream)1352 static bool is_subvp_high_refresh_candidate(struct dc_stream_state *stream)
1353 {
1354 uint32_t refresh_rate;
1355 struct dc *dc = stream->ctx->dc;
1356
1357 refresh_rate = (stream->timing.pix_clk_100hz * (uint64_t)100 +
1358 stream->timing.v_total * stream->timing.h_total - (uint64_t)1);
1359 refresh_rate = div_u64(refresh_rate, stream->timing.v_total);
1360 refresh_rate = div_u64(refresh_rate, stream->timing.h_total);
1361
1362 /* If there's any stream that fits the SubVP high refresh criteria,
1363 * we must return true. This is because cursor updates are asynchronous
1364 * with full updates, so we could transition into a SubVP config and
1365 * remain in HW cursor mode if there's no cursor update which will
1366 * then cause corruption.
1367 */
1368 if ((refresh_rate >= 120 && refresh_rate <= 175 &&
1369 stream->timing.v_addressable >= 1080 &&
1370 stream->timing.v_addressable <= 2160) &&
1371 (dc->current_state->stream_count > 1 ||
1372 (dc->current_state->stream_count == 1 && !stream->allow_freesync)))
1373 return true;
1374
1375 return false;
1376 }
1377
convert_dp_to_controller_test_pattern(enum dp_test_pattern test_pattern)1378 static enum controller_dp_test_pattern convert_dp_to_controller_test_pattern(
1379 enum dp_test_pattern test_pattern)
1380 {
1381 enum controller_dp_test_pattern controller_test_pattern;
1382
1383 switch (test_pattern) {
1384 case DP_TEST_PATTERN_COLOR_SQUARES:
1385 controller_test_pattern =
1386 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
1387 break;
1388 case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
1389 controller_test_pattern =
1390 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
1391 break;
1392 case DP_TEST_PATTERN_VERTICAL_BARS:
1393 controller_test_pattern =
1394 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
1395 break;
1396 case DP_TEST_PATTERN_HORIZONTAL_BARS:
1397 controller_test_pattern =
1398 CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
1399 break;
1400 case DP_TEST_PATTERN_COLOR_RAMP:
1401 controller_test_pattern =
1402 CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
1403 break;
1404 default:
1405 controller_test_pattern =
1406 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
1407 break;
1408 }
1409
1410 return controller_test_pattern;
1411 }
1412
convert_dp_to_controller_color_space(enum dp_test_pattern_color_space color_space)1413 static enum controller_dp_color_space convert_dp_to_controller_color_space(
1414 enum dp_test_pattern_color_space color_space)
1415 {
1416 enum controller_dp_color_space controller_color_space;
1417
1418 switch (color_space) {
1419 case DP_TEST_PATTERN_COLOR_SPACE_RGB:
1420 controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
1421 break;
1422 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
1423 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
1424 break;
1425 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
1426 controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
1427 break;
1428 case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
1429 default:
1430 controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
1431 break;
1432 }
1433
1434 return controller_color_space;
1435 }
1436
resource_build_test_pattern_params(struct resource_context * res_ctx,struct pipe_ctx * otg_master)1437 void resource_build_test_pattern_params(struct resource_context *res_ctx,
1438 struct pipe_ctx *otg_master)
1439 {
1440 int odm_slice_width, last_odm_slice_width, offset = 0;
1441 struct pipe_ctx *opp_heads[MAX_PIPES];
1442 struct test_pattern_params *params;
1443 int odm_cnt = 1;
1444 enum controller_dp_test_pattern controller_test_pattern;
1445 enum controller_dp_color_space controller_color_space;
1446 enum dc_color_depth color_depth = otg_master->stream->timing.display_color_depth;
1447 int h_active = otg_master->stream->timing.h_addressable +
1448 otg_master->stream->timing.h_border_left +
1449 otg_master->stream->timing.h_border_right;
1450 int v_active = otg_master->stream->timing.v_addressable +
1451 otg_master->stream->timing.v_border_bottom +
1452 otg_master->stream->timing.v_border_top;
1453 int i;
1454
1455 controller_test_pattern = convert_dp_to_controller_test_pattern(
1456 otg_master->stream->test_pattern.type);
1457 controller_color_space = convert_dp_to_controller_color_space(
1458 otg_master->stream->test_pattern.color_space);
1459
1460 if (controller_test_pattern == CONTROLLER_DP_TEST_PATTERN_VIDEOMODE)
1461 return;
1462
1463 odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads);
1464
1465 odm_slice_width = h_active / odm_cnt;
1466 last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1);
1467
1468 for (i = 0; i < odm_cnt; i++) {
1469 params = &opp_heads[i]->stream_res.test_pattern_params;
1470 params->test_pattern = controller_test_pattern;
1471 params->color_space = controller_color_space;
1472 params->color_depth = color_depth;
1473 params->height = v_active;
1474 params->offset = offset;
1475
1476 if (i < odm_cnt - 1)
1477 params->width = odm_slice_width;
1478 else
1479 params->width = last_odm_slice_width;
1480
1481 offset += odm_slice_width;
1482 }
1483 }
1484
resource_build_scaling_params(struct pipe_ctx * pipe_ctx)1485 bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
1486 {
1487 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1488 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
1489 const struct rect odm_slice_rec = calculate_odm_slice_in_timing_active(pipe_ctx);
1490 bool res = false;
1491
1492 DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
1493
1494 /* Invalid input */
1495 if (!plane_state->dst_rect.width ||
1496 !plane_state->dst_rect.height ||
1497 !plane_state->src_rect.width ||
1498 !plane_state->src_rect.height) {
1499 ASSERT(0);
1500 return false;
1501 }
1502
1503 /* Timing borders are part of vactive that we are also supposed to skip in addition
1504 * to any stream dst offset. Since dm logic assumes dst is in addressable
1505 * space we need to add the left and top borders to dst offsets temporarily.
1506 * TODO: fix in DM, stream dst is supposed to be in vactive
1507 */
1508 pipe_ctx->stream->dst.x += timing->h_border_left;
1509 pipe_ctx->stream->dst.y += timing->v_border_top;
1510
1511 /* Calculate H and V active size */
1512 pipe_ctx->plane_res.scl_data.h_active = odm_slice_rec.width;
1513 pipe_ctx->plane_res.scl_data.v_active = odm_slice_rec.height;
1514 pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
1515 pipe_ctx->plane_state->format);
1516
1517 /* depends on h_active */
1518 calculate_recout(pipe_ctx);
1519 /* depends on pixel format */
1520 calculate_scaling_ratios(pipe_ctx);
1521 /* depends on scaling ratios and recout, does not calculate offset yet */
1522 calculate_viewport_size(pipe_ctx);
1523
1524 /*
1525 * LB calculations depend on vp size, h/v_active and scaling ratios
1526 * Setting line buffer pixel depth to 24bpp yields banding
1527 * on certain displays, such as the Sharp 4k. 36bpp is needed
1528 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
1529 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
1530 * precision on DCN display engines, but apparently not for DCE, as
1531 * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
1532 * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
1533 * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
1534 * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
1535 */
1536 if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
1537 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
1538 else
1539 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1540
1541 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
1542
1543 if (pipe_ctx->plane_res.xfm != NULL)
1544 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1545 pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1546
1547 if (pipe_ctx->plane_res.dpp != NULL)
1548 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1549 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
1550
1551
1552 if (!res) {
1553 /* Try 24 bpp linebuffer */
1554 pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
1555
1556 if (pipe_ctx->plane_res.xfm != NULL)
1557 res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
1558 pipe_ctx->plane_res.xfm,
1559 &pipe_ctx->plane_res.scl_data,
1560 &plane_state->scaling_quality);
1561
1562 if (pipe_ctx->plane_res.dpp != NULL)
1563 res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
1564 pipe_ctx->plane_res.dpp,
1565 &pipe_ctx->plane_res.scl_data,
1566 &plane_state->scaling_quality);
1567 }
1568
1569 /*
1570 * Depends on recout, scaling ratios, h_active and taps
1571 * May need to re-check lb size after this in some obscure scenario
1572 */
1573 if (res)
1574 calculate_inits_and_viewports(pipe_ctx);
1575
1576 /*
1577 * Handle side by side and top bottom 3d recout offsets after vp calculation
1578 * since 3d is special and needs to calculate vp as if there is no recout offset
1579 * This may break with rotation, good thing we aren't mixing hw rotation and 3d
1580 */
1581 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
1582 ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
1583 (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
1584 pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
1585 if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
1586 pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
1587 else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
1588 pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
1589 }
1590
1591 /* Clamp minimum viewport size */
1592 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE)
1593 pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
1594 if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
1595 pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
1596
1597
1598 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"
1599 "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",
1600 __func__,
1601 pipe_ctx->pipe_idx,
1602 pipe_ctx->plane_res.scl_data.viewport.height,
1603 pipe_ctx->plane_res.scl_data.viewport.width,
1604 pipe_ctx->plane_res.scl_data.viewport.x,
1605 pipe_ctx->plane_res.scl_data.viewport.y,
1606 pipe_ctx->plane_res.scl_data.recout.height,
1607 pipe_ctx->plane_res.scl_data.recout.width,
1608 pipe_ctx->plane_res.scl_data.recout.x,
1609 pipe_ctx->plane_res.scl_data.recout.y,
1610 pipe_ctx->plane_res.scl_data.h_active,
1611 pipe_ctx->plane_res.scl_data.v_active,
1612 plane_state->src_rect.height,
1613 plane_state->src_rect.width,
1614 plane_state->src_rect.x,
1615 plane_state->src_rect.y,
1616 plane_state->dst_rect.height,
1617 plane_state->dst_rect.width,
1618 plane_state->dst_rect.x,
1619 plane_state->dst_rect.y,
1620 plane_state->clip_rect.height,
1621 plane_state->clip_rect.width,
1622 plane_state->clip_rect.x,
1623 plane_state->clip_rect.y);
1624
1625 pipe_ctx->stream->dst.x -= timing->h_border_left;
1626 pipe_ctx->stream->dst.y -= timing->v_border_top;
1627
1628 return res;
1629 }
1630
1631
resource_build_scaling_params_for_context(const struct dc * dc,struct dc_state * context)1632 enum dc_status resource_build_scaling_params_for_context(
1633 const struct dc *dc,
1634 struct dc_state *context)
1635 {
1636 int i;
1637
1638 for (i = 0; i < MAX_PIPES; i++) {
1639 if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
1640 context->res_ctx.pipe_ctx[i].stream != NULL)
1641 if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
1642 return DC_FAIL_SCALING;
1643 }
1644
1645 return DC_OK;
1646 }
1647
resource_find_free_secondary_pipe_legacy(struct resource_context * res_ctx,const struct resource_pool * pool,const struct pipe_ctx * primary_pipe)1648 struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
1649 struct resource_context *res_ctx,
1650 const struct resource_pool *pool,
1651 const struct pipe_ctx *primary_pipe)
1652 {
1653 int i;
1654 struct pipe_ctx *secondary_pipe = NULL;
1655
1656 /*
1657 * We add a preferred pipe mapping to avoid the chance that
1658 * MPCCs already in use will need to be reassigned to other trees.
1659 * For example, if we went with the strict, assign backwards logic:
1660 *
1661 * (State 1)
1662 * Display A on, no surface, top pipe = 0
1663 * Display B on, no surface, top pipe = 1
1664 *
1665 * (State 2)
1666 * Display A on, no surface, top pipe = 0
1667 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
1668 *
1669 * (State 3)
1670 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
1671 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1672 *
1673 * The state 2->3 transition requires remapping MPCC 5 from display B
1674 * to display A.
1675 *
1676 * However, with the preferred pipe logic, state 2 would look like:
1677 *
1678 * (State 2)
1679 * Display A on, no surface, top pipe = 0
1680 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
1681 *
1682 * This would then cause 2->3 to not require remapping any MPCCs.
1683 */
1684 if (primary_pipe) {
1685 int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
1686 if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
1687 secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
1688 secondary_pipe->pipe_idx = preferred_pipe_idx;
1689 }
1690 }
1691
1692 /*
1693 * search backwards for the second pipe to keep pipe
1694 * assignment more consistent
1695 */
1696 if (!secondary_pipe)
1697 for (i = pool->pipe_count - 1; i >= 0; i--) {
1698 if (res_ctx->pipe_ctx[i].stream == NULL) {
1699 secondary_pipe = &res_ctx->pipe_ctx[i];
1700 secondary_pipe->pipe_idx = i;
1701 break;
1702 }
1703 }
1704
1705 return secondary_pipe;
1706 }
1707
resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(const struct resource_context * cur_res_ctx,struct resource_context * new_res_ctx,const struct pipe_ctx * cur_otg_master)1708 int resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(
1709 const struct resource_context *cur_res_ctx,
1710 struct resource_context *new_res_ctx,
1711 const struct pipe_ctx *cur_otg_master)
1712 {
1713 const struct pipe_ctx *cur_sec_opp_head = cur_otg_master->next_odm_pipe;
1714 struct pipe_ctx *new_pipe;
1715 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1716
1717 while (cur_sec_opp_head) {
1718 new_pipe = &new_res_ctx->pipe_ctx[cur_sec_opp_head->pipe_idx];
1719 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1720 free_pipe_idx = cur_sec_opp_head->pipe_idx;
1721 break;
1722 }
1723 cur_sec_opp_head = cur_sec_opp_head->next_odm_pipe;
1724 }
1725
1726 return free_pipe_idx;
1727 }
1728
resource_find_free_pipe_used_in_cur_mpc_blending_tree(const struct resource_context * cur_res_ctx,struct resource_context * new_res_ctx,const struct pipe_ctx * cur_opp_head)1729 int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
1730 const struct resource_context *cur_res_ctx,
1731 struct resource_context *new_res_ctx,
1732 const struct pipe_ctx *cur_opp_head)
1733 {
1734 const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
1735 struct pipe_ctx *new_pipe;
1736 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1737
1738 while (cur_sec_dpp) {
1739 /* find a free pipe used in current opp blend tree,
1740 * this is to avoid MPO pipe switching to different opp blending
1741 * tree
1742 */
1743 new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
1744 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1745 free_pipe_idx = cur_sec_dpp->pipe_idx;
1746 break;
1747 }
1748 cur_sec_dpp = cur_sec_dpp->bottom_pipe;
1749 }
1750
1751 return free_pipe_idx;
1752 }
1753
recource_find_free_pipe_not_used_in_cur_res_ctx(const struct resource_context * cur_res_ctx,struct resource_context * new_res_ctx,const struct resource_pool * pool)1754 int recource_find_free_pipe_not_used_in_cur_res_ctx(
1755 const struct resource_context *cur_res_ctx,
1756 struct resource_context *new_res_ctx,
1757 const struct resource_pool *pool)
1758 {
1759 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1760 const struct pipe_ctx *new_pipe, *cur_pipe;
1761 int i;
1762
1763 for (i = 0; i < pool->pipe_count; i++) {
1764 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1765 new_pipe = &new_res_ctx->pipe_ctx[i];
1766
1767 if (resource_is_pipe_type(cur_pipe, FREE_PIPE) &&
1768 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1769 free_pipe_idx = i;
1770 break;
1771 }
1772 }
1773
1774 return free_pipe_idx;
1775 }
1776
recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(const struct resource_context * cur_res_ctx,struct resource_context * new_res_ctx,const struct resource_pool * pool)1777 int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
1778 const struct resource_context *cur_res_ctx,
1779 struct resource_context *new_res_ctx,
1780 const struct resource_pool *pool)
1781 {
1782 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1783 const struct pipe_ctx *new_pipe, *cur_pipe;
1784 int i;
1785
1786 for (i = 0; i < pool->pipe_count; i++) {
1787 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1788 new_pipe = &new_res_ctx->pipe_ctx[i];
1789
1790 if (resource_is_pipe_type(cur_pipe, OTG_MASTER) &&
1791 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1792 free_pipe_idx = i;
1793 break;
1794 }
1795 }
1796
1797 return free_pipe_idx;
1798 }
1799
resource_find_free_pipe_used_as_cur_sec_dpp(const struct resource_context * cur_res_ctx,struct resource_context * new_res_ctx,const struct resource_pool * pool)1800 int resource_find_free_pipe_used_as_cur_sec_dpp(
1801 const struct resource_context *cur_res_ctx,
1802 struct resource_context *new_res_ctx,
1803 const struct resource_pool *pool)
1804 {
1805 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1806 const struct pipe_ctx *new_pipe, *cur_pipe;
1807 int i;
1808
1809 for (i = 0; i < pool->pipe_count; i++) {
1810 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1811 new_pipe = &new_res_ctx->pipe_ctx[i];
1812
1813 if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
1814 !resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
1815 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1816 free_pipe_idx = i;
1817 break;
1818 }
1819 }
1820
1821 return free_pipe_idx;
1822 }
1823
resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(const struct resource_context * cur_res_ctx,struct resource_context * new_res_ctx,const struct resource_pool * pool)1824 int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
1825 const struct resource_context *cur_res_ctx,
1826 struct resource_context *new_res_ctx,
1827 const struct resource_pool *pool)
1828 {
1829 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1830 const struct pipe_ctx *new_pipe, *cur_pipe;
1831 int i;
1832
1833 for (i = 0; i < pool->pipe_count; i++) {
1834 cur_pipe = &cur_res_ctx->pipe_ctx[i];
1835 new_pipe = &new_res_ctx->pipe_ctx[i];
1836
1837 if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
1838 !resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
1839 resource_get_mpc_slice_index(cur_pipe) > 0 &&
1840 resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1841 free_pipe_idx = i;
1842 break;
1843 }
1844 }
1845
1846 return free_pipe_idx;
1847 }
1848
resource_find_any_free_pipe(struct resource_context * new_res_ctx,const struct resource_pool * pool)1849 int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
1850 const struct resource_pool *pool)
1851 {
1852 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
1853 const struct pipe_ctx *new_pipe;
1854 int i;
1855
1856 for (i = 0; i < pool->pipe_count; i++) {
1857 new_pipe = &new_res_ctx->pipe_ctx[i];
1858
1859 if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
1860 free_pipe_idx = i;
1861 break;
1862 }
1863 }
1864
1865 return free_pipe_idx;
1866 }
1867
resource_is_pipe_type(const struct pipe_ctx * pipe_ctx,enum pipe_type type)1868 bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
1869 {
1870 switch (type) {
1871 case OTG_MASTER:
1872 return !pipe_ctx->prev_odm_pipe &&
1873 !pipe_ctx->top_pipe &&
1874 pipe_ctx->stream;
1875 case OPP_HEAD:
1876 return !pipe_ctx->top_pipe && pipe_ctx->stream;
1877 case DPP_PIPE:
1878 return pipe_ctx->plane_state && pipe_ctx->stream;
1879 case FREE_PIPE:
1880 return !pipe_ctx->plane_state && !pipe_ctx->stream;
1881 default:
1882 return false;
1883 }
1884 }
1885
resource_get_otg_master_for_stream(struct resource_context * res_ctx,const struct dc_stream_state * stream)1886 struct pipe_ctx *resource_get_otg_master_for_stream(
1887 struct resource_context *res_ctx,
1888 const struct dc_stream_state *stream)
1889 {
1890 int i;
1891
1892 for (i = 0; i < MAX_PIPES; i++) {
1893 if (res_ctx->pipe_ctx[i].stream == stream &&
1894 resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER))
1895 return &res_ctx->pipe_ctx[i];
1896 }
1897 return NULL;
1898 }
1899
resource_get_opp_heads_for_otg_master(const struct pipe_ctx * otg_master,struct resource_context * res_ctx,struct pipe_ctx * opp_heads[MAX_PIPES])1900 int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master,
1901 struct resource_context *res_ctx,
1902 struct pipe_ctx *opp_heads[MAX_PIPES])
1903 {
1904 struct pipe_ctx *opp_head = &res_ctx->pipe_ctx[otg_master->pipe_idx];
1905 int i = 0;
1906
1907 if (!resource_is_pipe_type(otg_master, OTG_MASTER)) {
1908 ASSERT(0);
1909 return 0;
1910 }
1911 while (opp_head) {
1912 ASSERT(i < MAX_PIPES);
1913 opp_heads[i++] = opp_head;
1914 opp_head = opp_head->next_odm_pipe;
1915 }
1916 return i;
1917 }
1918
resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx * opp_head,struct resource_context * res_ctx,struct pipe_ctx * dpp_pipes[MAX_PIPES])1919 int resource_get_dpp_pipes_for_opp_head(const struct pipe_ctx *opp_head,
1920 struct resource_context *res_ctx,
1921 struct pipe_ctx *dpp_pipes[MAX_PIPES])
1922 {
1923 struct pipe_ctx *pipe = &res_ctx->pipe_ctx[opp_head->pipe_idx];
1924 int i = 0;
1925
1926 if (!resource_is_pipe_type(opp_head, OPP_HEAD)) {
1927 ASSERT(0);
1928 return 0;
1929 }
1930 while (pipe && resource_is_pipe_type(pipe, DPP_PIPE)) {
1931 ASSERT(i < MAX_PIPES);
1932 dpp_pipes[i++] = pipe;
1933 pipe = pipe->bottom_pipe;
1934 }
1935 return i;
1936 }
1937
resource_get_dpp_pipes_for_plane(const struct dc_plane_state * plane,struct resource_context * res_ctx,struct pipe_ctx * dpp_pipes[MAX_PIPES])1938 int resource_get_dpp_pipes_for_plane(const struct dc_plane_state *plane,
1939 struct resource_context *res_ctx,
1940 struct pipe_ctx *dpp_pipes[MAX_PIPES])
1941 {
1942 int i = 0, j;
1943 struct pipe_ctx *pipe;
1944
1945 for (j = 0; j < MAX_PIPES; j++) {
1946 pipe = &res_ctx->pipe_ctx[j];
1947 if (pipe->plane_state == plane && pipe->prev_odm_pipe == NULL) {
1948 if (resource_is_pipe_type(pipe, OPP_HEAD) ||
1949 pipe->top_pipe->plane_state != plane)
1950 break;
1951 }
1952 }
1953
1954 if (j < MAX_PIPES) {
1955 if (pipe->next_odm_pipe)
1956 while (pipe) {
1957 dpp_pipes[i++] = pipe;
1958 pipe = pipe->next_odm_pipe;
1959 }
1960 else
1961 while (pipe && pipe->plane_state == plane) {
1962 dpp_pipes[i++] = pipe;
1963 pipe = pipe->bottom_pipe;
1964 }
1965 }
1966 return i;
1967 }
1968
resource_get_otg_master(const struct pipe_ctx * pipe_ctx)1969 struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx)
1970 {
1971 struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx);
1972
1973 while (otg_master->prev_odm_pipe)
1974 otg_master = otg_master->prev_odm_pipe;
1975 return otg_master;
1976 }
1977
resource_get_opp_head(const struct pipe_ctx * pipe_ctx)1978 struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx)
1979 {
1980 struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx;
1981
1982 ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE));
1983 while (opp_head->top_pipe)
1984 opp_head = opp_head->top_pipe;
1985 return opp_head;
1986 }
1987
resource_get_primary_dpp_pipe(const struct pipe_ctx * dpp_pipe)1988 struct pipe_ctx *resource_get_primary_dpp_pipe(const struct pipe_ctx *dpp_pipe)
1989 {
1990 struct pipe_ctx *pri_dpp_pipe = (struct pipe_ctx *) dpp_pipe;
1991
1992 ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE));
1993 while (pri_dpp_pipe->prev_odm_pipe)
1994 pri_dpp_pipe = pri_dpp_pipe->prev_odm_pipe;
1995 while (pri_dpp_pipe->top_pipe &&
1996 pri_dpp_pipe->top_pipe->plane_state == pri_dpp_pipe->plane_state)
1997 pri_dpp_pipe = pri_dpp_pipe->top_pipe;
1998 return pri_dpp_pipe;
1999 }
2000
2001
resource_get_mpc_slice_index(const struct pipe_ctx * pipe_ctx)2002 int resource_get_mpc_slice_index(const struct pipe_ctx *pipe_ctx)
2003 {
2004 struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
2005 int index = 0;
2006
2007 while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
2008 index++;
2009 split_pipe = split_pipe->top_pipe;
2010 }
2011
2012 return index;
2013 }
2014
resource_get_mpc_slice_count(const struct pipe_ctx * pipe)2015 int resource_get_mpc_slice_count(const struct pipe_ctx *pipe)
2016 {
2017 int mpc_split_count = 1;
2018 const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
2019
2020 while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
2021 mpc_split_count++;
2022 other_pipe = other_pipe->bottom_pipe;
2023 }
2024 other_pipe = pipe->top_pipe;
2025 while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
2026 mpc_split_count++;
2027 other_pipe = other_pipe->top_pipe;
2028 }
2029
2030 return mpc_split_count;
2031 }
2032
resource_get_odm_slice_count(const struct pipe_ctx * pipe)2033 int resource_get_odm_slice_count(const struct pipe_ctx *pipe)
2034 {
2035 int odm_split_count = 1;
2036
2037 pipe = resource_get_otg_master(pipe);
2038
2039 while (pipe->next_odm_pipe) {
2040 odm_split_count++;
2041 pipe = pipe->next_odm_pipe;
2042 }
2043 return odm_split_count;
2044 }
2045
resource_get_odm_slice_index(const struct pipe_ctx * pipe_ctx)2046 int resource_get_odm_slice_index(const struct pipe_ctx *pipe_ctx)
2047 {
2048 int index = 0;
2049
2050 pipe_ctx = resource_get_opp_head(pipe_ctx);
2051 if (!pipe_ctx)
2052 return 0;
2053
2054 while (pipe_ctx->prev_odm_pipe) {
2055 index++;
2056 pipe_ctx = pipe_ctx->prev_odm_pipe;
2057 }
2058
2059 return index;
2060 }
2061
resource_is_pipe_topology_changed(const struct dc_state * state_a,const struct dc_state * state_b)2062 bool resource_is_pipe_topology_changed(const struct dc_state *state_a,
2063 const struct dc_state *state_b)
2064 {
2065 int i;
2066 const struct pipe_ctx *pipe_a, *pipe_b;
2067
2068 if (state_a->stream_count != state_b->stream_count)
2069 return true;
2070
2071 for (i = 0; i < MAX_PIPES; i++) {
2072 pipe_a = &state_a->res_ctx.pipe_ctx[i];
2073 pipe_b = &state_b->res_ctx.pipe_ctx[i];
2074
2075 if (pipe_a->stream && !pipe_b->stream)
2076 return true;
2077 else if (!pipe_a->stream && pipe_b->stream)
2078 return true;
2079
2080 if (pipe_a->plane_state && !pipe_b->plane_state)
2081 return true;
2082 else if (!pipe_a->plane_state && pipe_b->plane_state)
2083 return true;
2084
2085 if (pipe_a->bottom_pipe && pipe_b->bottom_pipe) {
2086 if (pipe_a->bottom_pipe->pipe_idx != pipe_b->bottom_pipe->pipe_idx)
2087 return true;
2088 if ((pipe_a->bottom_pipe->plane_state == pipe_a->plane_state) &&
2089 (pipe_b->bottom_pipe->plane_state != pipe_b->plane_state))
2090 return true;
2091 else if ((pipe_a->bottom_pipe->plane_state != pipe_a->plane_state) &&
2092 (pipe_b->bottom_pipe->plane_state == pipe_b->plane_state))
2093 return true;
2094 } else if (pipe_a->bottom_pipe || pipe_b->bottom_pipe) {
2095 return true;
2096 }
2097
2098 if (pipe_a->next_odm_pipe && pipe_b->next_odm_pipe) {
2099 if (pipe_a->next_odm_pipe->pipe_idx != pipe_b->next_odm_pipe->pipe_idx)
2100 return true;
2101 } else if (pipe_a->next_odm_pipe || pipe_b->next_odm_pipe) {
2102 return true;
2103 }
2104 }
2105 return false;
2106 }
2107
resource_is_odm_topology_changed(const struct pipe_ctx * otg_master_a,const struct pipe_ctx * otg_master_b)2108 bool resource_is_odm_topology_changed(const struct pipe_ctx *otg_master_a,
2109 const struct pipe_ctx *otg_master_b)
2110 {
2111 const struct pipe_ctx *opp_head_a = otg_master_a;
2112 const struct pipe_ctx *opp_head_b = otg_master_b;
2113
2114 if (!resource_is_pipe_type(otg_master_a, OTG_MASTER) ||
2115 !resource_is_pipe_type(otg_master_b, OTG_MASTER))
2116 return true;
2117
2118 while (opp_head_a && opp_head_b) {
2119 if (opp_head_a->stream_res.opp != opp_head_b->stream_res.opp)
2120 return true;
2121 if ((opp_head_a->next_odm_pipe && !opp_head_b->next_odm_pipe) ||
2122 (!opp_head_a->next_odm_pipe && opp_head_b->next_odm_pipe))
2123 return true;
2124 opp_head_a = opp_head_a->next_odm_pipe;
2125 opp_head_b = opp_head_b->next_odm_pipe;
2126 }
2127
2128 return false;
2129 }
2130
2131 /*
2132 * Sample log:
2133 * pipe topology update
2134 * ________________________
2135 * | plane0 slice0 stream0|
2136 * |DPP0----OPP0----OTG0----| <--- case 0 (OTG master pipe with plane)
2137 * | plane1 | | |
2138 * |DPP1----| | | <--- case 5 (DPP pipe not in last slice)
2139 * | plane0 slice1 | |
2140 * |DPP2----OPP2----| | <--- case 2 (OPP head pipe with plane)
2141 * | plane1 | |
2142 * |DPP3----| | <--- case 4 (DPP pipe in last slice)
2143 * | slice0 stream1|
2144 * |DPG4----OPP4----OTG4----| <--- case 1 (OTG master pipe without plane)
2145 * | slice1 | |
2146 * |DPG5----OPP5----| | <--- case 3 (OPP head pipe without plane)
2147 * |________________________|
2148 */
2149
resource_log_pipe(struct dc * dc,struct pipe_ctx * pipe,int stream_idx,int slice_idx,int plane_idx,int slice_count,bool is_primary)2150 static void resource_log_pipe(struct dc *dc, struct pipe_ctx *pipe,
2151 int stream_idx, int slice_idx, int plane_idx, int slice_count,
2152 bool is_primary)
2153 {
2154 DC_LOGGER_INIT(dc->ctx->logger);
2155
2156 if (slice_idx == 0 && plane_idx == 0 && is_primary) {
2157 /* case 0 (OTG master pipe with plane) */
2158 DC_LOG_DC(" | plane%d slice%d stream%d|",
2159 plane_idx, slice_idx, stream_idx);
2160 DC_LOG_DC(" |DPP%d----OPP%d----OTG%d----|",
2161 pipe->plane_res.dpp->inst,
2162 pipe->stream_res.opp->inst,
2163 pipe->stream_res.tg->inst);
2164 } else if (slice_idx == 0 && plane_idx == -1) {
2165 /* case 1 (OTG master pipe without plane) */
2166 DC_LOG_DC(" | slice%d stream%d|",
2167 slice_idx, stream_idx);
2168 DC_LOG_DC(" |DPG%d----OPP%d----OTG%d----|",
2169 pipe->stream_res.opp->inst,
2170 pipe->stream_res.opp->inst,
2171 pipe->stream_res.tg->inst);
2172 } else if (slice_idx != 0 && plane_idx == 0 && is_primary) {
2173 /* case 2 (OPP head pipe with plane) */
2174 DC_LOG_DC(" | plane%d slice%d | |",
2175 plane_idx, slice_idx);
2176 DC_LOG_DC(" |DPP%d----OPP%d----| |",
2177 pipe->plane_res.dpp->inst,
2178 pipe->stream_res.opp->inst);
2179 } else if (slice_idx != 0 && plane_idx == -1) {
2180 /* case 3 (OPP head pipe without plane) */
2181 DC_LOG_DC(" | slice%d | |", slice_idx);
2182 DC_LOG_DC(" |DPG%d----OPP%d----| |",
2183 pipe->plane_res.dpp->inst,
2184 pipe->stream_res.opp->inst);
2185 } else if (slice_idx == slice_count - 1) {
2186 /* case 4 (DPP pipe in last slice) */
2187 DC_LOG_DC(" | plane%d | |", plane_idx);
2188 DC_LOG_DC(" |DPP%d----| |",
2189 pipe->plane_res.dpp->inst);
2190 } else {
2191 /* case 5 (DPP pipe not in last slice) */
2192 DC_LOG_DC(" | plane%d | | |", plane_idx);
2193 DC_LOG_DC(" |DPP%d----| | |",
2194 pipe->plane_res.dpp->inst);
2195 }
2196 }
2197
resource_log_pipe_for_stream(struct dc * dc,struct dc_state * state,struct pipe_ctx * otg_master,int stream_idx)2198 static void resource_log_pipe_for_stream(struct dc *dc, struct dc_state *state,
2199 struct pipe_ctx *otg_master, int stream_idx)
2200 {
2201 struct pipe_ctx *opp_heads[MAX_PIPES];
2202 struct pipe_ctx *dpp_pipes[MAX_PIPES];
2203
2204 int slice_idx, dpp_idx, plane_idx, slice_count, dpp_count;
2205 bool is_primary;
2206 DC_LOGGER_INIT(dc->ctx->logger);
2207
2208 slice_count = resource_get_opp_heads_for_otg_master(otg_master,
2209 &state->res_ctx, opp_heads);
2210 for (slice_idx = 0; slice_idx < slice_count; slice_idx++) {
2211 plane_idx = -1;
2212 if (opp_heads[slice_idx]->plane_state) {
2213 dpp_count = resource_get_dpp_pipes_for_opp_head(
2214 opp_heads[slice_idx],
2215 &state->res_ctx,
2216 dpp_pipes);
2217 for (dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) {
2218 is_primary = !dpp_pipes[dpp_idx]->top_pipe ||
2219 dpp_pipes[dpp_idx]->top_pipe->plane_state != dpp_pipes[dpp_idx]->plane_state;
2220 if (is_primary)
2221 plane_idx++;
2222 resource_log_pipe(dc, dpp_pipes[dpp_idx],
2223 stream_idx, slice_idx,
2224 plane_idx, slice_count,
2225 is_primary);
2226 }
2227 } else {
2228 resource_log_pipe(dc, opp_heads[slice_idx],
2229 stream_idx, slice_idx, plane_idx,
2230 slice_count, true);
2231 }
2232
2233 }
2234 }
2235
resource_stream_to_stream_idx(struct dc_state * state,struct dc_stream_state * stream)2236 static int resource_stream_to_stream_idx(struct dc_state *state,
2237 struct dc_stream_state *stream)
2238 {
2239 int i, stream_idx = -1;
2240
2241 for (i = 0; i < state->stream_count; i++)
2242 if (state->streams[i] == stream) {
2243 stream_idx = i;
2244 break;
2245 }
2246
2247 /* never return negative array index */
2248 if (stream_idx == -1) {
2249 ASSERT(0);
2250 return 0;
2251 }
2252
2253 return stream_idx;
2254 }
2255
resource_log_pipe_topology_update(struct dc * dc,struct dc_state * state)2256 void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state)
2257 {
2258 struct pipe_ctx *otg_master;
2259 int stream_idx, phantom_stream_idx;
2260 DC_LOGGER_INIT(dc->ctx->logger);
2261
2262 DC_LOG_DC(" pipe topology update");
2263 DC_LOG_DC(" ________________________");
2264 for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) {
2265 if (state->streams[stream_idx]->is_phantom)
2266 continue;
2267
2268 otg_master = resource_get_otg_master_for_stream(
2269 &state->res_ctx, state->streams[stream_idx]);
2270 resource_log_pipe_for_stream(dc, state, otg_master, stream_idx);
2271 }
2272 if (state->phantom_stream_count > 0) {
2273 DC_LOG_DC(" | (phantom pipes) |");
2274 for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) {
2275 if (state->stream_status[stream_idx].mall_stream_config.type != SUBVP_MAIN)
2276 continue;
2277
2278 phantom_stream_idx = resource_stream_to_stream_idx(state,
2279 state->stream_status[stream_idx].mall_stream_config.paired_stream);
2280 otg_master = resource_get_otg_master_for_stream(
2281 &state->res_ctx, state->streams[phantom_stream_idx]);
2282 resource_log_pipe_for_stream(dc, state, otg_master, stream_idx);
2283 }
2284 }
2285 DC_LOG_DC(" |________________________|\n");
2286 }
2287
get_tail_pipe(struct pipe_ctx * head_pipe)2288 static struct pipe_ctx *get_tail_pipe(
2289 struct pipe_ctx *head_pipe)
2290 {
2291 struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe;
2292
2293 while (tail_pipe) {
2294 head_pipe = tail_pipe;
2295 tail_pipe = tail_pipe->bottom_pipe;
2296 }
2297
2298 return head_pipe;
2299 }
2300
get_last_opp_head(struct pipe_ctx * opp_head)2301 static struct pipe_ctx *get_last_opp_head(
2302 struct pipe_ctx *opp_head)
2303 {
2304 ASSERT(resource_is_pipe_type(opp_head, OPP_HEAD));
2305 while (opp_head->next_odm_pipe)
2306 opp_head = opp_head->next_odm_pipe;
2307 return opp_head;
2308 }
2309
get_last_dpp_pipe_in_mpcc_combine(struct pipe_ctx * dpp_pipe)2310 static struct pipe_ctx *get_last_dpp_pipe_in_mpcc_combine(
2311 struct pipe_ctx *dpp_pipe)
2312 {
2313 ASSERT(resource_is_pipe_type(dpp_pipe, DPP_PIPE));
2314 while (dpp_pipe->bottom_pipe &&
2315 dpp_pipe->plane_state == dpp_pipe->bottom_pipe->plane_state)
2316 dpp_pipe = dpp_pipe->bottom_pipe;
2317 return dpp_pipe;
2318 }
2319
update_pipe_params_after_odm_slice_count_change(struct pipe_ctx * otg_master,struct dc_state * context,const struct resource_pool * pool)2320 static bool update_pipe_params_after_odm_slice_count_change(
2321 struct pipe_ctx *otg_master,
2322 struct dc_state *context,
2323 const struct resource_pool *pool)
2324 {
2325 int i;
2326 struct pipe_ctx *pipe;
2327 bool result = true;
2328
2329 for (i = 0; i < pool->pipe_count && result; i++) {
2330 pipe = &context->res_ctx.pipe_ctx[i];
2331 if (pipe->stream == otg_master->stream && pipe->plane_state)
2332 result = resource_build_scaling_params(pipe);
2333 }
2334
2335 if (pool->funcs->build_pipe_pix_clk_params)
2336 pool->funcs->build_pipe_pix_clk_params(otg_master);
2337
2338 resource_build_test_pattern_params(&context->res_ctx, otg_master);
2339
2340 return result;
2341 }
2342
update_pipe_params_after_mpc_slice_count_change(const struct dc_plane_state * plane,struct dc_state * context,const struct resource_pool * pool)2343 static bool update_pipe_params_after_mpc_slice_count_change(
2344 const struct dc_plane_state *plane,
2345 struct dc_state *context,
2346 const struct resource_pool *pool)
2347 {
2348 int i;
2349 struct pipe_ctx *pipe;
2350 bool result = true;
2351
2352 for (i = 0; i < pool->pipe_count && result; i++) {
2353 pipe = &context->res_ctx.pipe_ctx[i];
2354 if (pipe->plane_state == plane)
2355 result = resource_build_scaling_params(pipe);
2356 }
2357 return result;
2358 }
2359
acquire_first_split_pipe(struct resource_context * res_ctx,const struct resource_pool * pool,struct dc_stream_state * stream)2360 static int acquire_first_split_pipe(
2361 struct resource_context *res_ctx,
2362 const struct resource_pool *pool,
2363 struct dc_stream_state *stream)
2364 {
2365 int i;
2366
2367 for (i = 0; i < pool->pipe_count; i++) {
2368 struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
2369
2370 if (split_pipe->top_pipe &&
2371 split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
2372 split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
2373 if (split_pipe->bottom_pipe)
2374 split_pipe->bottom_pipe->top_pipe = split_pipe->top_pipe;
2375
2376 if (split_pipe->top_pipe->plane_state)
2377 resource_build_scaling_params(split_pipe->top_pipe);
2378
2379 memset(split_pipe, 0, sizeof(*split_pipe));
2380 split_pipe->stream_res.tg = pool->timing_generators[i];
2381 split_pipe->plane_res.hubp = pool->hubps[i];
2382 split_pipe->plane_res.ipp = pool->ipps[i];
2383 split_pipe->plane_res.dpp = pool->dpps[i];
2384 split_pipe->stream_res.opp = pool->opps[i];
2385 split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
2386 split_pipe->pipe_idx = i;
2387
2388 split_pipe->stream = stream;
2389 return i;
2390 }
2391 }
2392 return FREE_PIPE_INDEX_NOT_FOUND;
2393 }
2394
update_stream_engine_usage(struct resource_context * res_ctx,const struct resource_pool * pool,struct stream_encoder * stream_enc,bool acquired)2395 static void update_stream_engine_usage(
2396 struct resource_context *res_ctx,
2397 const struct resource_pool *pool,
2398 struct stream_encoder *stream_enc,
2399 bool acquired)
2400 {
2401 int i;
2402
2403 for (i = 0; i < pool->stream_enc_count; i++) {
2404 if (pool->stream_enc[i] == stream_enc)
2405 res_ctx->is_stream_enc_acquired[i] = acquired;
2406 }
2407 }
2408
update_hpo_dp_stream_engine_usage(struct resource_context * res_ctx,const struct resource_pool * pool,struct hpo_dp_stream_encoder * hpo_dp_stream_enc,bool acquired)2409 static void update_hpo_dp_stream_engine_usage(
2410 struct resource_context *res_ctx,
2411 const struct resource_pool *pool,
2412 struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
2413 bool acquired)
2414 {
2415 int i;
2416
2417 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
2418 if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
2419 res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
2420 }
2421 }
2422
find_acquired_hpo_dp_link_enc_for_link(const struct resource_context * res_ctx,const struct dc_link * link)2423 static inline int find_acquired_hpo_dp_link_enc_for_link(
2424 const struct resource_context *res_ctx,
2425 const struct dc_link *link)
2426 {
2427 int i;
2428
2429 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
2430 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
2431 res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
2432 return i;
2433
2434 return -1;
2435 }
2436
find_free_hpo_dp_link_enc(const struct resource_context * res_ctx,const struct resource_pool * pool)2437 static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
2438 const struct resource_pool *pool)
2439 {
2440 int i;
2441
2442 for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
2443 if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
2444 break;
2445
2446 return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
2447 i < pool->hpo_dp_link_enc_count) ? i : -1;
2448 }
2449
acquire_hpo_dp_link_enc(struct resource_context * res_ctx,unsigned int link_index,int enc_index)2450 static inline void acquire_hpo_dp_link_enc(
2451 struct resource_context *res_ctx,
2452 unsigned int link_index,
2453 int enc_index)
2454 {
2455 res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
2456 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
2457 }
2458
retain_hpo_dp_link_enc(struct resource_context * res_ctx,int enc_index)2459 static inline void retain_hpo_dp_link_enc(
2460 struct resource_context *res_ctx,
2461 int enc_index)
2462 {
2463 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
2464 }
2465
release_hpo_dp_link_enc(struct resource_context * res_ctx,int enc_index)2466 static inline void release_hpo_dp_link_enc(
2467 struct resource_context *res_ctx,
2468 int enc_index)
2469 {
2470 ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
2471 res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
2472 }
2473
add_hpo_dp_link_enc_to_ctx(struct resource_context * res_ctx,const struct resource_pool * pool,struct pipe_ctx * pipe_ctx,struct dc_stream_state * stream)2474 static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
2475 const struct resource_pool *pool,
2476 struct pipe_ctx *pipe_ctx,
2477 struct dc_stream_state *stream)
2478 {
2479 int enc_index;
2480
2481 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2482
2483 if (enc_index >= 0) {
2484 retain_hpo_dp_link_enc(res_ctx, enc_index);
2485 } else {
2486 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
2487 if (enc_index >= 0)
2488 acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
2489 }
2490
2491 if (enc_index >= 0)
2492 pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
2493
2494 return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
2495 }
2496
remove_hpo_dp_link_enc_from_ctx(struct resource_context * res_ctx,struct pipe_ctx * pipe_ctx,struct dc_stream_state * stream)2497 static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
2498 struct pipe_ctx *pipe_ctx,
2499 struct dc_stream_state *stream)
2500 {
2501 int enc_index;
2502
2503 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
2504
2505 if (enc_index >= 0) {
2506 release_hpo_dp_link_enc(res_ctx, enc_index);
2507 pipe_ctx->link_res.hpo_dp_link_enc = NULL;
2508 }
2509 }
2510
resource_add_otg_master_for_stream_output(struct dc_state * new_ctx,const struct resource_pool * pool,struct dc_stream_state * stream)2511 enum dc_status resource_add_otg_master_for_stream_output(struct dc_state *new_ctx,
2512 const struct resource_pool *pool,
2513 struct dc_stream_state *stream)
2514 {
2515 struct dc *dc = stream->ctx->dc;
2516
2517 return dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream);
2518 }
2519
resource_remove_otg_master_for_stream_output(struct dc_state * context,const struct resource_pool * pool,struct dc_stream_state * stream)2520 void resource_remove_otg_master_for_stream_output(struct dc_state *context,
2521 const struct resource_pool *pool,
2522 struct dc_stream_state *stream)
2523 {
2524 struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
2525 &context->res_ctx, stream);
2526
2527 if (!otg_master)
2528 return;
2529
2530 ASSERT(resource_get_odm_slice_count(otg_master) == 1);
2531 ASSERT(otg_master->plane_state == NULL);
2532 ASSERT(otg_master->stream_res.stream_enc);
2533 update_stream_engine_usage(
2534 &context->res_ctx,
2535 pool,
2536 otg_master->stream_res.stream_enc,
2537 false);
2538
2539 if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master)) {
2540 update_hpo_dp_stream_engine_usage(
2541 &context->res_ctx, pool,
2542 otg_master->stream_res.hpo_dp_stream_enc,
2543 false);
2544 remove_hpo_dp_link_enc_from_ctx(
2545 &context->res_ctx, otg_master, stream);
2546 }
2547 if (otg_master->stream_res.audio)
2548 update_audio_usage(
2549 &context->res_ctx,
2550 pool,
2551 otg_master->stream_res.audio,
2552 false);
2553
2554 resource_unreference_clock_source(&context->res_ctx,
2555 pool,
2556 otg_master->clock_source);
2557
2558 if (pool->funcs->remove_stream_from_ctx)
2559 pool->funcs->remove_stream_from_ctx(
2560 stream->ctx->dc, context, stream);
2561 memset(otg_master, 0, sizeof(*otg_master));
2562 }
2563
2564 /* For each OPP head of an OTG master, add top plane at plane index 0.
2565 *
2566 * In the following example, the stream has 2 ODM slices without a top plane.
2567 * By adding a plane 0 to OPP heads, we are configuring our hardware to render
2568 * plane 0 by using each OPP head's DPP.
2569 *
2570 * Inter-pipe Relation (Before Adding Plane)
2571 * __________________________________________________
2572 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2573 * | | | slice 0 | |
2574 * | 0 | |blank ----ODM----------- |
2575 * | | | slice 1 | | |
2576 * | 1 | |blank ---- | |
2577 * |________|_______________|___________|_____________|
2578 *
2579 * Inter-pipe Relation (After Adding Plane)
2580 * __________________________________________________
2581 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2582 * | | plane 0 | slice 0 | |
2583 * | 0 | -------------------------ODM----------- |
2584 * | | plane 0 | slice 1 | | |
2585 * | 1 | ------------------------- | |
2586 * |________|_______________|___________|_____________|
2587 */
add_plane_to_opp_head_pipes(struct pipe_ctx * otg_master_pipe,struct dc_plane_state * plane_state,struct dc_state * context)2588 static bool add_plane_to_opp_head_pipes(struct pipe_ctx *otg_master_pipe,
2589 struct dc_plane_state *plane_state,
2590 struct dc_state *context)
2591 {
2592 struct pipe_ctx *opp_head_pipe = otg_master_pipe;
2593
2594 while (opp_head_pipe) {
2595 if (opp_head_pipe->plane_state) {
2596 ASSERT(0);
2597 return false;
2598 }
2599 opp_head_pipe->plane_state = plane_state;
2600 opp_head_pipe = opp_head_pipe->next_odm_pipe;
2601 }
2602
2603 return true;
2604 }
2605
2606 /* For each OPP head of an OTG master, acquire a secondary DPP pipe and add
2607 * the plane. So the plane is added to all ODM slices associated with the OTG
2608 * master pipe in the bottom layer.
2609 *
2610 * In the following example, the stream has 2 ODM slices and a top plane 0.
2611 * By acquiring secondary DPP pipes and adding a plane 1, we are configuring our
2612 * hardware to render the plane 1 by acquiring a new pipe for each ODM slice and
2613 * render plane 1 using new pipes' DPP in the Z axis below plane 0.
2614 *
2615 * Inter-pipe Relation (Before Adding Plane)
2616 * __________________________________________________
2617 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2618 * | | plane 0 | slice 0 | |
2619 * | 0 | -------------------------ODM----------- |
2620 * | | plane 0 | slice 1 | | |
2621 * | 1 | ------------------------- | |
2622 * |________|_______________|___________|_____________|
2623 *
2624 * Inter-pipe Relation (After Acquiring and Adding Plane)
2625 * __________________________________________________
2626 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2627 * | | plane 0 | slice 0 | |
2628 * | 0 | -------------MPC---------ODM----------- |
2629 * | | plane 1 | | | | |
2630 * | 2 | ------------- | | | |
2631 * | | plane 0 | slice 1 | | |
2632 * | 1 | -------------MPC--------- | |
2633 * | | plane 1 | | | |
2634 * | 3 | ------------- | | |
2635 * |________|_______________|___________|_____________|
2636 */
acquire_secondary_dpp_pipes_and_add_plane(struct pipe_ctx * otg_master_pipe,struct dc_plane_state * plane_state,struct dc_state * new_ctx,struct dc_state * cur_ctx,struct resource_pool * pool)2637 static bool acquire_secondary_dpp_pipes_and_add_plane(
2638 struct pipe_ctx *otg_master_pipe,
2639 struct dc_plane_state *plane_state,
2640 struct dc_state *new_ctx,
2641 struct dc_state *cur_ctx,
2642 struct resource_pool *pool)
2643 {
2644 struct pipe_ctx *opp_head_pipe, *sec_pipe, *tail_pipe;
2645
2646 if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
2647 ASSERT(0);
2648 return false;
2649 }
2650
2651 opp_head_pipe = otg_master_pipe;
2652 while (opp_head_pipe) {
2653 sec_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
2654 cur_ctx,
2655 new_ctx,
2656 pool,
2657 opp_head_pipe);
2658 if (!sec_pipe) {
2659 /* try tearing down MPCC combine */
2660 int pipe_idx = acquire_first_split_pipe(
2661 &new_ctx->res_ctx, pool,
2662 otg_master_pipe->stream);
2663
2664 if (pipe_idx >= 0)
2665 sec_pipe = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
2666 }
2667
2668 if (!sec_pipe)
2669 return false;
2670
2671 sec_pipe->plane_state = plane_state;
2672
2673 /* establish pipe relationship */
2674 tail_pipe = get_tail_pipe(opp_head_pipe);
2675 tail_pipe->bottom_pipe = sec_pipe;
2676 sec_pipe->top_pipe = tail_pipe;
2677 sec_pipe->bottom_pipe = NULL;
2678 if (tail_pipe->prev_odm_pipe) {
2679 ASSERT(tail_pipe->prev_odm_pipe->bottom_pipe);
2680 sec_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe;
2681 tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = sec_pipe;
2682 } else {
2683 sec_pipe->prev_odm_pipe = NULL;
2684 }
2685
2686 opp_head_pipe = opp_head_pipe->next_odm_pipe;
2687 }
2688 return true;
2689 }
2690
resource_append_dpp_pipes_for_plane_composition(struct dc_state * new_ctx,struct dc_state * cur_ctx,struct resource_pool * pool,struct pipe_ctx * otg_master_pipe,struct dc_plane_state * plane_state)2691 bool resource_append_dpp_pipes_for_plane_composition(
2692 struct dc_state *new_ctx,
2693 struct dc_state *cur_ctx,
2694 struct resource_pool *pool,
2695 struct pipe_ctx *otg_master_pipe,
2696 struct dc_plane_state *plane_state)
2697 {
2698 bool success;
2699 if (otg_master_pipe->plane_state == NULL)
2700 success = add_plane_to_opp_head_pipes(otg_master_pipe,
2701 plane_state, new_ctx);
2702 else
2703 success = acquire_secondary_dpp_pipes_and_add_plane(
2704 otg_master_pipe, plane_state, new_ctx,
2705 cur_ctx, pool);
2706 if (success)
2707 /* when appending a plane mpc slice count changes from 0 to 1 */
2708 success = update_pipe_params_after_mpc_slice_count_change(
2709 plane_state, new_ctx, pool);
2710 return success;
2711 }
2712
resource_remove_dpp_pipes_for_plane_composition(struct dc_state * context,const struct resource_pool * pool,const struct dc_plane_state * plane_state)2713 void resource_remove_dpp_pipes_for_plane_composition(
2714 struct dc_state *context,
2715 const struct resource_pool *pool,
2716 const struct dc_plane_state *plane_state)
2717 {
2718 int i;
2719 for (i = pool->pipe_count - 1; i >= 0; i--) {
2720 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2721
2722 if (pipe_ctx->plane_state == plane_state) {
2723 if (pipe_ctx->top_pipe)
2724 pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
2725
2726 /* Second condition is to avoid setting NULL to top pipe
2727 * of tail pipe making it look like head pipe in subsequent
2728 * deletes
2729 */
2730 if (pipe_ctx->bottom_pipe && pipe_ctx->top_pipe)
2731 pipe_ctx->bottom_pipe->top_pipe = pipe_ctx->top_pipe;
2732
2733 /*
2734 * For head pipe detach surfaces from pipe for tail
2735 * pipe just zero it out
2736 */
2737 if (!pipe_ctx->top_pipe)
2738 pipe_ctx->plane_state = NULL;
2739 else
2740 memset(pipe_ctx, 0, sizeof(*pipe_ctx));
2741 }
2742 }
2743 }
2744
2745 /*
2746 * Increase ODM slice count by 1 by acquiring pipes and adding a new ODM slice
2747 * at the last index.
2748 * return - true if a new ODM slice is added and required pipes are acquired.
2749 * false if new_ctx is no longer a valid state after new ODM slice is added.
2750 *
2751 * This is achieved by duplicating MPC blending tree from previous ODM slice.
2752 * In the following example, we have a single MPC tree and 1 ODM slice 0. We
2753 * want to add a new odm slice by duplicating the MPC blending tree and add
2754 * ODM slice 1.
2755 *
2756 * Inter-pipe Relation (Before Acquiring and Adding ODM Slice)
2757 * __________________________________________________
2758 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2759 * | | plane 0 | slice 0 | |
2760 * | 0 | -------------MPC---------ODM----------- |
2761 * | | plane 1 | | | |
2762 * | 1 | ------------- | | |
2763 * |________|_______________|___________|_____________|
2764 *
2765 * Inter-pipe Relation (After Acquiring and Adding ODM Slice)
2766 * __________________________________________________
2767 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2768 * | | plane 0 | slice 0 | |
2769 * | 0 | -------------MPC---------ODM----------- |
2770 * | | plane 1 | | | | |
2771 * | 1 | ------------- | | | |
2772 * | | plane 0 | slice 1 | | |
2773 * | 2 | -------------MPC--------- | |
2774 * | | plane 1 | | | |
2775 * | 3 | ------------- | | |
2776 * |________|_______________|___________|_____________|
2777 */
acquire_pipes_and_add_odm_slice(struct pipe_ctx * otg_master_pipe,struct dc_state * new_ctx,const struct dc_state * cur_ctx,const struct resource_pool * pool)2778 static bool acquire_pipes_and_add_odm_slice(
2779 struct pipe_ctx *otg_master_pipe,
2780 struct dc_state *new_ctx,
2781 const struct dc_state *cur_ctx,
2782 const struct resource_pool *pool)
2783 {
2784 struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
2785 struct pipe_ctx *new_opp_head;
2786 struct pipe_ctx *last_top_dpp_pipe, *last_bottom_dpp_pipe,
2787 *new_top_dpp_pipe, *new_bottom_dpp_pipe;
2788
2789 if (!pool->funcs->acquire_free_pipe_as_secondary_opp_head) {
2790 ASSERT(0);
2791 return false;
2792 }
2793 new_opp_head = pool->funcs->acquire_free_pipe_as_secondary_opp_head(
2794 cur_ctx, new_ctx, pool,
2795 otg_master_pipe);
2796 if (!new_opp_head)
2797 return false;
2798
2799 last_opp_head->next_odm_pipe = new_opp_head;
2800 new_opp_head->prev_odm_pipe = last_opp_head;
2801 new_opp_head->next_odm_pipe = NULL;
2802 new_opp_head->plane_state = last_opp_head->plane_state;
2803 last_top_dpp_pipe = last_opp_head;
2804 new_top_dpp_pipe = new_opp_head;
2805
2806 while (last_top_dpp_pipe->bottom_pipe) {
2807 last_bottom_dpp_pipe = last_top_dpp_pipe->bottom_pipe;
2808 new_bottom_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
2809 cur_ctx, new_ctx, pool,
2810 new_opp_head);
2811 if (!new_bottom_dpp_pipe)
2812 return false;
2813
2814 new_bottom_dpp_pipe->plane_state = last_bottom_dpp_pipe->plane_state;
2815 new_top_dpp_pipe->bottom_pipe = new_bottom_dpp_pipe;
2816 new_bottom_dpp_pipe->top_pipe = new_top_dpp_pipe;
2817 last_bottom_dpp_pipe->next_odm_pipe = new_bottom_dpp_pipe;
2818 new_bottom_dpp_pipe->prev_odm_pipe = last_bottom_dpp_pipe;
2819 new_bottom_dpp_pipe->next_odm_pipe = NULL;
2820 last_top_dpp_pipe = last_bottom_dpp_pipe;
2821 }
2822
2823 return true;
2824 }
2825
2826 /*
2827 * Decrease ODM slice count by 1 by releasing pipes and removing the ODM slice
2828 * at the last index.
2829 * return - true if the last ODM slice is removed and related pipes are
2830 * released. false if there is no removable ODM slice.
2831 *
2832 * In the following example, we have 2 MPC trees and ODM slice 0 and slice 1.
2833 * We want to remove the last ODM i.e slice 1. We are releasing secondary DPP
2834 * pipe 3 and OPP head pipe 2.
2835 *
2836 * Inter-pipe Relation (Before Releasing and Removing ODM Slice)
2837 * __________________________________________________
2838 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2839 * | | plane 0 | slice 0 | |
2840 * | 0 | -------------MPC---------ODM----------- |
2841 * | | plane 1 | | | | |
2842 * | 1 | ------------- | | | |
2843 * | | plane 0 | slice 1 | | |
2844 * | 2 | -------------MPC--------- | |
2845 * | | plane 1 | | | |
2846 * | 3 | ------------- | | |
2847 * |________|_______________|___________|_____________|
2848 *
2849 * Inter-pipe Relation (After Releasing and Removing ODM Slice)
2850 * __________________________________________________
2851 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2852 * | | plane 0 | slice 0 | |
2853 * | 0 | -------------MPC---------ODM----------- |
2854 * | | plane 1 | | | |
2855 * | 1 | ------------- | | |
2856 * |________|_______________|___________|_____________|
2857 */
release_pipes_and_remove_odm_slice(struct pipe_ctx * otg_master_pipe,struct dc_state * context,const struct resource_pool * pool)2858 static bool release_pipes_and_remove_odm_slice(
2859 struct pipe_ctx *otg_master_pipe,
2860 struct dc_state *context,
2861 const struct resource_pool *pool)
2862 {
2863 struct pipe_ctx *last_opp_head = get_last_opp_head(otg_master_pipe);
2864 struct pipe_ctx *tail_pipe = get_tail_pipe(last_opp_head);
2865
2866 if (!pool->funcs->release_pipe) {
2867 ASSERT(0);
2868 return false;
2869 }
2870
2871 if (resource_is_pipe_type(last_opp_head, OTG_MASTER))
2872 return false;
2873
2874 while (tail_pipe->top_pipe) {
2875 tail_pipe->prev_odm_pipe->next_odm_pipe = NULL;
2876 tail_pipe = tail_pipe->top_pipe;
2877 pool->funcs->release_pipe(context, tail_pipe->bottom_pipe, pool);
2878 tail_pipe->bottom_pipe = NULL;
2879 }
2880 last_opp_head->prev_odm_pipe->next_odm_pipe = NULL;
2881 pool->funcs->release_pipe(context, last_opp_head, pool);
2882
2883 return true;
2884 }
2885
2886 /*
2887 * Increase MPC slice count by 1 by acquiring a new DPP pipe and add it as the
2888 * last MPC slice of the plane associated with dpp_pipe.
2889 *
2890 * return - true if a new MPC slice is added and required pipes are acquired.
2891 * false if new_ctx is no longer a valid state after new MPC slice is added.
2892 *
2893 * In the following example, we add a new MPC slice for plane 0 into the
2894 * new_ctx. To do so we pass pipe 0 as dpp_pipe. The function acquires a new DPP
2895 * pipe 2 for plane 0 as the bottom most pipe for plane 0.
2896 *
2897 * Inter-pipe Relation (Before Acquiring and Adding MPC Slice)
2898 * __________________________________________________
2899 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2900 * | | plane 0 | | |
2901 * | 0 | -------------MPC----------------------- |
2902 * | | plane 1 | | | |
2903 * | 1 | ------------- | | |
2904 * |________|_______________|___________|_____________|
2905 *
2906 * Inter-pipe Relation (After Acquiring and Adding MPC Slice)
2907 * __________________________________________________
2908 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2909 * | | plane 0 | | |
2910 * | 0 | -------------MPC----------------------- |
2911 * | | plane 0 | | | |
2912 * | 2 | ------------- | | |
2913 * | | plane 1 | | | |
2914 * | 1 | ------------- | | |
2915 * |________|_______________|___________|_____________|
2916 */
acquire_dpp_pipe_and_add_mpc_slice(struct pipe_ctx * dpp_pipe,struct dc_state * new_ctx,const struct dc_state * cur_ctx,const struct resource_pool * pool)2917 static bool acquire_dpp_pipe_and_add_mpc_slice(
2918 struct pipe_ctx *dpp_pipe,
2919 struct dc_state *new_ctx,
2920 const struct dc_state *cur_ctx,
2921 const struct resource_pool *pool)
2922 {
2923 struct pipe_ctx *last_dpp_pipe =
2924 get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
2925 struct pipe_ctx *opp_head = resource_get_opp_head(dpp_pipe);
2926 struct pipe_ctx *new_dpp_pipe;
2927
2928 if (!pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe) {
2929 ASSERT(0);
2930 return false;
2931 }
2932 new_dpp_pipe = pool->funcs->acquire_free_pipe_as_secondary_dpp_pipe(
2933 cur_ctx, new_ctx, pool, opp_head);
2934 if (!new_dpp_pipe || resource_get_odm_slice_count(dpp_pipe) > 1)
2935 return false;
2936
2937 new_dpp_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
2938 if (new_dpp_pipe->bottom_pipe)
2939 new_dpp_pipe->bottom_pipe->top_pipe = new_dpp_pipe;
2940 new_dpp_pipe->top_pipe = last_dpp_pipe;
2941 last_dpp_pipe->bottom_pipe = new_dpp_pipe;
2942 new_dpp_pipe->plane_state = last_dpp_pipe->plane_state;
2943
2944 return true;
2945 }
2946
2947 /*
2948 * Reduce MPC slice count by 1 by releasing the bottom DPP pipe in MPCC combine
2949 * with dpp_pipe and removing last MPC slice of the plane associated with
2950 * dpp_pipe.
2951 *
2952 * return - true if the last MPC slice of the plane associated with dpp_pipe is
2953 * removed and last DPP pipe in MPCC combine with dpp_pipe is released.
2954 * false if there is no removable MPC slice.
2955 *
2956 * In the following example, we remove an MPC slice for plane 0 from the
2957 * context. To do so we pass pipe 0 as dpp_pipe. The function releases pipe 1 as
2958 * it is the last pipe for plane 0.
2959 *
2960 * Inter-pipe Relation (Before Releasing and Removing MPC Slice)
2961 * __________________________________________________
2962 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2963 * | | plane 0 | | |
2964 * | 0 | -------------MPC----------------------- |
2965 * | | plane 0 | | | |
2966 * | 1 | ------------- | | |
2967 * | | plane 1 | | | |
2968 * | 2 | ------------- | | |
2969 * |________|_______________|___________|_____________|
2970 *
2971 * Inter-pipe Relation (After Releasing and Removing MPC Slice)
2972 * __________________________________________________
2973 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
2974 * | | plane 0 | | |
2975 * | 0 | -------------MPC----------------------- |
2976 * | | plane 1 | | | |
2977 * | 2 | ------------- | | |
2978 * |________|_______________|___________|_____________|
2979 */
release_dpp_pipe_and_remove_mpc_slice(struct pipe_ctx * dpp_pipe,struct dc_state * context,const struct resource_pool * pool)2980 static bool release_dpp_pipe_and_remove_mpc_slice(
2981 struct pipe_ctx *dpp_pipe,
2982 struct dc_state *context,
2983 const struct resource_pool *pool)
2984 {
2985 struct pipe_ctx *last_dpp_pipe =
2986 get_last_dpp_pipe_in_mpcc_combine(dpp_pipe);
2987
2988 if (!pool->funcs->release_pipe) {
2989 ASSERT(0);
2990 return false;
2991 }
2992
2993 if (resource_is_pipe_type(last_dpp_pipe, OPP_HEAD) ||
2994 resource_get_odm_slice_count(dpp_pipe) > 1)
2995 return false;
2996
2997 last_dpp_pipe->top_pipe->bottom_pipe = last_dpp_pipe->bottom_pipe;
2998 if (last_dpp_pipe->bottom_pipe)
2999 last_dpp_pipe->bottom_pipe->top_pipe = last_dpp_pipe->top_pipe;
3000 pool->funcs->release_pipe(context, last_dpp_pipe, pool);
3001
3002 return true;
3003 }
3004
resource_update_pipes_for_stream_with_slice_count(struct dc_state * new_ctx,const struct dc_state * cur_ctx,const struct resource_pool * pool,const struct dc_stream_state * stream,int new_slice_count)3005 bool resource_update_pipes_for_stream_with_slice_count(
3006 struct dc_state *new_ctx,
3007 const struct dc_state *cur_ctx,
3008 const struct resource_pool *pool,
3009 const struct dc_stream_state *stream,
3010 int new_slice_count)
3011 {
3012 int i;
3013 struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(
3014 &new_ctx->res_ctx, stream);
3015 int cur_slice_count = resource_get_odm_slice_count(otg_master);
3016 bool result = true;
3017
3018 if (new_slice_count == cur_slice_count)
3019 return result;
3020
3021 if (new_slice_count > cur_slice_count)
3022 for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
3023 result = acquire_pipes_and_add_odm_slice(
3024 otg_master, new_ctx, cur_ctx, pool);
3025 else
3026 for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
3027 result = release_pipes_and_remove_odm_slice(
3028 otg_master, new_ctx, pool);
3029 if (result)
3030 result = update_pipe_params_after_odm_slice_count_change(
3031 otg_master, new_ctx, pool);
3032 return result;
3033 }
3034
resource_update_pipes_for_plane_with_slice_count(struct dc_state * new_ctx,const struct dc_state * cur_ctx,const struct resource_pool * pool,const struct dc_plane_state * plane,int new_slice_count)3035 bool resource_update_pipes_for_plane_with_slice_count(
3036 struct dc_state *new_ctx,
3037 const struct dc_state *cur_ctx,
3038 const struct resource_pool *pool,
3039 const struct dc_plane_state *plane,
3040 int new_slice_count)
3041 {
3042 int i;
3043 int dpp_pipe_count;
3044 int cur_slice_count;
3045 struct pipe_ctx *dpp_pipes[MAX_PIPES] = {0};
3046 bool result = true;
3047
3048 dpp_pipe_count = resource_get_dpp_pipes_for_plane(plane,
3049 &new_ctx->res_ctx, dpp_pipes);
3050 ASSERT(dpp_pipe_count > 0);
3051 cur_slice_count = resource_get_mpc_slice_count(dpp_pipes[0]);
3052
3053 if (new_slice_count == cur_slice_count)
3054 return result;
3055
3056 if (new_slice_count > cur_slice_count)
3057 for (i = 0; i < new_slice_count - cur_slice_count && result; i++)
3058 result = acquire_dpp_pipe_and_add_mpc_slice(
3059 dpp_pipes[0], new_ctx, cur_ctx, pool);
3060 else
3061 for (i = 0; i < cur_slice_count - new_slice_count && result; i++)
3062 result = release_dpp_pipe_and_remove_mpc_slice(
3063 dpp_pipes[0], new_ctx, pool);
3064 if (result)
3065 result = update_pipe_params_after_mpc_slice_count_change(
3066 dpp_pipes[0]->plane_state, new_ctx, pool);
3067 return result;
3068 }
3069
dc_is_timing_changed(struct dc_stream_state * cur_stream,struct dc_stream_state * new_stream)3070 bool dc_is_timing_changed(struct dc_stream_state *cur_stream,
3071 struct dc_stream_state *new_stream)
3072 {
3073 if (cur_stream == NULL)
3074 return true;
3075
3076 /* If output color space is changed, need to reprogram info frames */
3077 if (cur_stream->output_color_space != new_stream->output_color_space)
3078 return true;
3079
3080 return memcmp(
3081 &cur_stream->timing,
3082 &new_stream->timing,
3083 sizeof(struct dc_crtc_timing)) != 0;
3084 }
3085
are_stream_backends_same(struct dc_stream_state * stream_a,struct dc_stream_state * stream_b)3086 static bool are_stream_backends_same(
3087 struct dc_stream_state *stream_a, struct dc_stream_state *stream_b)
3088 {
3089 if (stream_a == stream_b)
3090 return true;
3091
3092 if (stream_a == NULL || stream_b == NULL)
3093 return false;
3094
3095 if (dc_is_timing_changed(stream_a, stream_b))
3096 return false;
3097
3098 if (stream_a->signal != stream_b->signal)
3099 return false;
3100
3101 if (stream_a->dpms_off != stream_b->dpms_off)
3102 return false;
3103
3104 return true;
3105 }
3106
3107 /*
3108 * dc_is_stream_unchanged() - Compare two stream states for equivalence.
3109 *
3110 * Checks if there a difference between the two states
3111 * that would require a mode change.
3112 *
3113 * Does not compare cursor position or attributes.
3114 */
dc_is_stream_unchanged(struct dc_stream_state * old_stream,struct dc_stream_state * stream)3115 bool dc_is_stream_unchanged(
3116 struct dc_stream_state *old_stream, struct dc_stream_state *stream)
3117 {
3118
3119 if (!are_stream_backends_same(old_stream, stream))
3120 return false;
3121
3122 if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
3123 return false;
3124
3125 /*compare audio info*/
3126 if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
3127 return false;
3128
3129 return true;
3130 }
3131
3132 /*
3133 * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
3134 */
dc_is_stream_scaling_unchanged(struct dc_stream_state * old_stream,struct dc_stream_state * stream)3135 bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
3136 struct dc_stream_state *stream)
3137 {
3138 if (old_stream == stream)
3139 return true;
3140
3141 if (old_stream == NULL || stream == NULL)
3142 return false;
3143
3144 if (memcmp(&old_stream->src,
3145 &stream->src,
3146 sizeof(struct rect)) != 0)
3147 return false;
3148
3149 if (memcmp(&old_stream->dst,
3150 &stream->dst,
3151 sizeof(struct rect)) != 0)
3152 return false;
3153
3154 return true;
3155 }
3156
3157 /* TODO: release audio object */
update_audio_usage(struct resource_context * res_ctx,const struct resource_pool * pool,struct audio * audio,bool acquired)3158 void update_audio_usage(
3159 struct resource_context *res_ctx,
3160 const struct resource_pool *pool,
3161 struct audio *audio,
3162 bool acquired)
3163 {
3164 int i;
3165 for (i = 0; i < pool->audio_count; i++) {
3166 if (pool->audios[i] == audio)
3167 res_ctx->is_audio_acquired[i] = acquired;
3168 }
3169 }
3170
find_first_free_match_hpo_dp_stream_enc_for_link(struct resource_context * res_ctx,const struct resource_pool * pool,struct dc_stream_state * stream)3171 static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
3172 struct resource_context *res_ctx,
3173 const struct resource_pool *pool,
3174 struct dc_stream_state *stream)
3175 {
3176 int i;
3177
3178 for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
3179 if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
3180 pool->hpo_dp_stream_enc[i]) {
3181
3182 return pool->hpo_dp_stream_enc[i];
3183 }
3184 }
3185
3186 return NULL;
3187 }
3188
find_first_free_audio(struct resource_context * res_ctx,const struct resource_pool * pool,enum engine_id id,enum dce_version dc_version)3189 static struct audio *find_first_free_audio(
3190 struct resource_context *res_ctx,
3191 const struct resource_pool *pool,
3192 enum engine_id id,
3193 enum dce_version dc_version)
3194 {
3195 int i, available_audio_count;
3196
3197 if (id == ENGINE_ID_UNKNOWN)
3198 return NULL;
3199
3200 available_audio_count = pool->audio_count;
3201
3202 for (i = 0; i < available_audio_count; i++) {
3203 if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
3204 /*we have enough audio endpoint, find the matching inst*/
3205 if (id != i)
3206 continue;
3207 return pool->audios[i];
3208 }
3209 }
3210
3211 /* use engine id to find free audio */
3212 if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) {
3213 return pool->audios[id];
3214 }
3215 /*not found the matching one, first come first serve*/
3216 for (i = 0; i < available_audio_count; i++) {
3217 if (res_ctx->is_audio_acquired[i] == false) {
3218 return pool->audios[i];
3219 }
3220 }
3221 return NULL;
3222 }
3223
find_pll_sharable_stream(struct dc_stream_state * stream_needs_pll,struct dc_state * context)3224 static struct dc_stream_state *find_pll_sharable_stream(
3225 struct dc_stream_state *stream_needs_pll,
3226 struct dc_state *context)
3227 {
3228 int i;
3229
3230 for (i = 0; i < context->stream_count; i++) {
3231 struct dc_stream_state *stream_has_pll = context->streams[i];
3232
3233 /* We are looking for non dp, non virtual stream */
3234 if (resource_are_streams_timing_synchronizable(
3235 stream_needs_pll, stream_has_pll)
3236 && !dc_is_dp_signal(stream_has_pll->signal)
3237 && stream_has_pll->link->connector_signal
3238 != SIGNAL_TYPE_VIRTUAL)
3239 return stream_has_pll;
3240
3241 }
3242
3243 return NULL;
3244 }
3245
get_norm_pix_clk(const struct dc_crtc_timing * timing)3246 static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
3247 {
3248 uint32_t pix_clk = timing->pix_clk_100hz;
3249 uint32_t normalized_pix_clk = pix_clk;
3250
3251 if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
3252 pix_clk /= 2;
3253 if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
3254 switch (timing->display_color_depth) {
3255 case COLOR_DEPTH_666:
3256 case COLOR_DEPTH_888:
3257 normalized_pix_clk = pix_clk;
3258 break;
3259 case COLOR_DEPTH_101010:
3260 normalized_pix_clk = (pix_clk * 30) / 24;
3261 break;
3262 case COLOR_DEPTH_121212:
3263 normalized_pix_clk = (pix_clk * 36) / 24;
3264 break;
3265 case COLOR_DEPTH_161616:
3266 normalized_pix_clk = (pix_clk * 48) / 24;
3267 break;
3268 default:
3269 ASSERT(0);
3270 break;
3271 }
3272 }
3273 return normalized_pix_clk;
3274 }
3275
calculate_phy_pix_clks(struct dc_stream_state * stream)3276 static void calculate_phy_pix_clks(struct dc_stream_state *stream)
3277 {
3278 /* update actual pixel clock on all streams */
3279 if (dc_is_hdmi_signal(stream->signal))
3280 stream->phy_pix_clk = get_norm_pix_clk(
3281 &stream->timing) / 10;
3282 else
3283 stream->phy_pix_clk =
3284 stream->timing.pix_clk_100hz / 10;
3285
3286 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
3287 stream->phy_pix_clk *= 2;
3288 }
3289
acquire_resource_from_hw_enabled_state(struct resource_context * res_ctx,const struct resource_pool * pool,struct dc_stream_state * stream)3290 static int acquire_resource_from_hw_enabled_state(
3291 struct resource_context *res_ctx,
3292 const struct resource_pool *pool,
3293 struct dc_stream_state *stream)
3294 {
3295 struct dc_link *link = stream->link;
3296 unsigned int i, inst, tg_inst = 0;
3297 uint32_t numPipes = 1;
3298 uint32_t id_src[4] = {0};
3299
3300 /* Check for enabled DIG to identify enabled display */
3301 if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
3302 return -1;
3303
3304 inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
3305
3306 if (inst == ENGINE_ID_UNKNOWN)
3307 return -1;
3308
3309 for (i = 0; i < pool->stream_enc_count; i++) {
3310 if (pool->stream_enc[i]->id == inst) {
3311 tg_inst = pool->stream_enc[i]->funcs->dig_source_otg(
3312 pool->stream_enc[i]);
3313 break;
3314 }
3315 }
3316
3317 // tg_inst not found
3318 if (i == pool->stream_enc_count)
3319 return -1;
3320
3321 if (tg_inst >= pool->timing_generator_count)
3322 return -1;
3323
3324 if (!res_ctx->pipe_ctx[tg_inst].stream) {
3325 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
3326
3327 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
3328 id_src[0] = tg_inst;
3329
3330 if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
3331 pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
3332 &numPipes, &id_src[0], &id_src[1]);
3333
3334 if (id_src[0] == 0xf && id_src[1] == 0xf) {
3335 id_src[0] = tg_inst;
3336 numPipes = 1;
3337 }
3338
3339 for (i = 0; i < numPipes; i++) {
3340 //Check if src id invalid
3341 if (id_src[i] == 0xf)
3342 return -1;
3343
3344 pipe_ctx = &res_ctx->pipe_ctx[id_src[i]];
3345
3346 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
3347 pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
3348 pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
3349 pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
3350 pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
3351 pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
3352 pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
3353
3354 if (pool->dpps[id_src[i]]) {
3355 pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;
3356
3357 if (pool->mpc->funcs->read_mpcc_state) {
3358 struct mpcc_state s = {0};
3359
3360 pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
3361
3362 if (s.dpp_id < MAX_MPCC)
3363 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
3364 s.dpp_id;
3365
3366 if (s.bot_mpcc_id < MAX_MPCC)
3367 pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
3368 &pool->mpc->mpcc_array[s.bot_mpcc_id];
3369
3370 if (s.opp_id < MAX_OPP)
3371 pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
3372 }
3373 }
3374 pipe_ctx->pipe_idx = id_src[i];
3375
3376 if (id_src[i] >= pool->timing_generator_count) {
3377 id_src[i] = pool->timing_generator_count - 1;
3378
3379 pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
3380 pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
3381 }
3382
3383 pipe_ctx->stream = stream;
3384 }
3385
3386 if (numPipes == 2) {
3387 stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
3388 res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
3389 res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
3390 res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
3391 res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
3392 } else
3393 stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
3394
3395 return id_src[0];
3396 }
3397
3398 return -1;
3399 }
3400
mark_seamless_boot_stream(const struct dc * dc,struct dc_stream_state * stream)3401 static void mark_seamless_boot_stream(
3402 const struct dc *dc,
3403 struct dc_stream_state *stream)
3404 {
3405 struct dc_bios *dcb = dc->ctx->dc_bios;
3406
3407 if (dc->config.allow_seamless_boot_optimization &&
3408 !dcb->funcs->is_accelerated_mode(dcb)) {
3409 if (dc_validate_boot_timing(dc, stream->sink, &stream->timing))
3410 stream->apply_seamless_boot_optimization = true;
3411 }
3412 }
3413
3414 /*
3415 * Acquire a pipe as OTG master and assign to the stream in new dc context.
3416 * return - true if OTG master pipe is acquired and new dc context is updated.
3417 * false if it fails to acquire an OTG master pipe for this stream.
3418 *
3419 * In the example below, we acquired pipe 0 as OTG master pipe for the stream.
3420 * After the function its Inter-pipe Relation is represented by the diagram
3421 * below.
3422 *
3423 * Inter-pipe Relation
3424 * __________________________________________________
3425 * |PIPE IDX| DPP PIPES | OPP HEADS | OTG MASTER |
3426 * | | | | |
3427 * | 0 | |blank ------------------ |
3428 * |________|_______________|___________|_____________|
3429 */
acquire_otg_master_pipe_for_stream(const struct dc_state * cur_ctx,struct dc_state * new_ctx,const struct resource_pool * pool,struct dc_stream_state * stream)3430 static bool acquire_otg_master_pipe_for_stream(
3431 const struct dc_state *cur_ctx,
3432 struct dc_state *new_ctx,
3433 const struct resource_pool *pool,
3434 struct dc_stream_state *stream)
3435 {
3436 /* TODO: Move this function to DCN specific resource file and acquire
3437 * DSC resource here. The reason is that the function should have the
3438 * same level of responsibility as when we acquire secondary OPP head.
3439 * We acquire DSC when we acquire secondary OPP head, so we should
3440 * acquire DSC when we acquire OTG master.
3441 */
3442 int pipe_idx;
3443 struct pipe_ctx *pipe_ctx = NULL;
3444
3445 /*
3446 * Upper level code is responsible to optimize unnecessary addition and
3447 * removal for unchanged streams. So unchanged stream will keep the same
3448 * OTG master instance allocated. When current stream is removed and a
3449 * new stream is added, we want to reuse the OTG instance made available
3450 * by the removed stream first. If not found, we try to avoid of using
3451 * any free pipes already used in current context as this could tear
3452 * down exiting ODM/MPC/MPO configuration unnecessarily.
3453 */
3454
3455 /*
3456 * Try to acquire the same OTG master already in use. This is not
3457 * optimal because resetting an enabled OTG master pipe for a new stream
3458 * requires an extra frame of wait. However there are test automation
3459 * and eDP assumptions that rely on reusing the same OTG master pipe
3460 * during mode change. We have to keep this logic as is for now.
3461 */
3462 pipe_idx = recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
3463 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
3464 /*
3465 * Try to acquire a pipe not used in current resource context to avoid
3466 * pipe swapping.
3467 */
3468 if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
3469 pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx(
3470 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
3471 /*
3472 * If pipe swapping is unavoidable, try to acquire pipe used as
3473 * secondary DPP pipe in current state as we prioritize to support more
3474 * streams over supporting MPO planes.
3475 */
3476 if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
3477 pipe_idx = resource_find_free_pipe_used_as_cur_sec_dpp(
3478 &cur_ctx->res_ctx, &new_ctx->res_ctx, pool);
3479 if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND)
3480 pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool);
3481 if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) {
3482 pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx];
3483 memset(pipe_ctx, 0, sizeof(*pipe_ctx));
3484 pipe_ctx->pipe_idx = pipe_idx;
3485 pipe_ctx->stream_res.tg = pool->timing_generators[pipe_idx];
3486 pipe_ctx->plane_res.mi = pool->mis[pipe_idx];
3487 pipe_ctx->plane_res.hubp = pool->hubps[pipe_idx];
3488 pipe_ctx->plane_res.ipp = pool->ipps[pipe_idx];
3489 pipe_ctx->plane_res.xfm = pool->transforms[pipe_idx];
3490 pipe_ctx->plane_res.dpp = pool->dpps[pipe_idx];
3491 pipe_ctx->stream_res.opp = pool->opps[pipe_idx];
3492 if (pool->dpps[pipe_idx])
3493 pipe_ctx->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
3494
3495 if (pipe_idx >= pool->timing_generator_count) {
3496 int tg_inst = pool->timing_generator_count - 1;
3497
3498 pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
3499 pipe_ctx->stream_res.opp = pool->opps[tg_inst];
3500 }
3501
3502 pipe_ctx->stream = stream;
3503 } else {
3504 pipe_idx = acquire_first_split_pipe(&new_ctx->res_ctx, pool, stream);
3505 }
3506
3507 return pipe_idx != FREE_PIPE_INDEX_NOT_FOUND;
3508 }
3509
resource_map_pool_resources(const struct dc * dc,struct dc_state * context,struct dc_stream_state * stream)3510 enum dc_status resource_map_pool_resources(
3511 const struct dc *dc,
3512 struct dc_state *context,
3513 struct dc_stream_state *stream)
3514 {
3515 const struct resource_pool *pool = dc->res_pool;
3516 int i;
3517 struct dc_context *dc_ctx = dc->ctx;
3518 struct pipe_ctx *pipe_ctx = NULL;
3519 int pipe_idx = -1;
3520 bool acquired = false;
3521
3522 calculate_phy_pix_clks(stream);
3523
3524 mark_seamless_boot_stream(dc, stream);
3525
3526 if (stream->apply_seamless_boot_optimization) {
3527 pipe_idx = acquire_resource_from_hw_enabled_state(
3528 &context->res_ctx,
3529 pool,
3530 stream);
3531 if (pipe_idx < 0)
3532 /* hw resource was assigned to other stream */
3533 stream->apply_seamless_boot_optimization = false;
3534 else
3535 acquired = true;
3536 }
3537
3538 if (!acquired)
3539 /* acquire new resources */
3540 acquired = acquire_otg_master_pipe_for_stream(dc->current_state,
3541 context, pool, stream);
3542
3543 pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
3544
3545 if (!pipe_ctx || pipe_ctx->stream_res.tg == NULL)
3546 return DC_NO_CONTROLLER_RESOURCE;
3547
3548 pipe_ctx->stream_res.stream_enc =
3549 dc->res_pool->funcs->find_first_free_match_stream_enc_for_link(
3550 &context->res_ctx, pool, stream);
3551
3552 if (!pipe_ctx->stream_res.stream_enc)
3553 return DC_NO_STREAM_ENC_RESOURCE;
3554
3555 update_stream_engine_usage(
3556 &context->res_ctx, pool,
3557 pipe_ctx->stream_res.stream_enc,
3558 true);
3559
3560 /* Allocate DP HPO Stream Encoder based on signal, hw capabilities
3561 * and link settings
3562 */
3563 if (dc_is_dp_signal(stream->signal)) {
3564 if (!dc->link_srv->dp_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings))
3565 return DC_FAIL_DP_LINK_BANDWIDTH;
3566 if (dc->link_srv->dp_get_encoding_format(
3567 &pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
3568 pipe_ctx->stream_res.hpo_dp_stream_enc =
3569 find_first_free_match_hpo_dp_stream_enc_for_link(
3570 &context->res_ctx, pool, stream);
3571
3572 if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
3573 return DC_NO_STREAM_ENC_RESOURCE;
3574
3575 update_hpo_dp_stream_engine_usage(
3576 &context->res_ctx, pool,
3577 pipe_ctx->stream_res.hpo_dp_stream_enc,
3578 true);
3579 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
3580 return DC_NO_LINK_ENC_RESOURCE;
3581 }
3582 }
3583
3584 /* TODO: Add check if ASIC support and EDID audio */
3585 if (!stream->converter_disable_audio &&
3586 dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
3587 stream->audio_info.mode_count && stream->audio_info.flags.all) {
3588 pipe_ctx->stream_res.audio = find_first_free_audio(
3589 &context->res_ctx, pool, pipe_ctx->stream_res.stream_enc->id, dc_ctx->dce_version);
3590
3591 /*
3592 * Audio assigned in order first come first get.
3593 * There are asics which has number of audio
3594 * resources less then number of pipes
3595 */
3596 if (pipe_ctx->stream_res.audio)
3597 update_audio_usage(&context->res_ctx, pool,
3598 pipe_ctx->stream_res.audio, true);
3599 }
3600
3601 /* Add ABM to the resource if on EDP */
3602 if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
3603 if (pool->abm)
3604 pipe_ctx->stream_res.abm = pool->abm;
3605 else
3606 pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
3607 }
3608
3609 for (i = 0; i < context->stream_count; i++)
3610 if (context->streams[i] == stream) {
3611 context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst;
3612 context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->stream_enc_inst;
3613 context->stream_status[i].audio_inst =
3614 pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1;
3615
3616 return DC_OK;
3617 }
3618
3619 DC_ERROR("Stream %p not found in new ctx!\n", stream);
3620 return DC_ERROR_UNEXPECTED;
3621 }
3622
dc_resource_is_dsc_encoding_supported(const struct dc * dc)3623 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
3624 {
3625 if (dc->res_pool == NULL)
3626 return false;
3627
3628 return dc->res_pool->res_cap->num_dsc > 0;
3629 }
3630
planes_changed_for_existing_stream(struct dc_state * context,struct dc_stream_state * stream,const struct dc_validation_set set[],int set_count)3631 static bool planes_changed_for_existing_stream(struct dc_state *context,
3632 struct dc_stream_state *stream,
3633 const struct dc_validation_set set[],
3634 int set_count)
3635 {
3636 int i, j;
3637 struct dc_stream_status *stream_status = NULL;
3638
3639 for (i = 0; i < context->stream_count; i++) {
3640 if (context->streams[i] == stream) {
3641 stream_status = &context->stream_status[i];
3642 break;
3643 }
3644 }
3645
3646 if (!stream_status)
3647 ASSERT(0);
3648
3649 for (i = 0; i < set_count; i++)
3650 if (set[i].stream == stream)
3651 break;
3652
3653 if (i == set_count)
3654 ASSERT(0);
3655
3656 if (set[i].plane_count != stream_status->plane_count)
3657 return true;
3658
3659 for (j = 0; j < set[i].plane_count; j++)
3660 if (set[i].plane_states[j] != stream_status->plane_states[j])
3661 return true;
3662
3663 return false;
3664 }
3665
add_all_planes_for_stream(const struct dc * dc,struct dc_stream_state * stream,const struct dc_validation_set set[],int set_count,struct dc_state * state)3666 static bool add_all_planes_for_stream(
3667 const struct dc *dc,
3668 struct dc_stream_state *stream,
3669 const struct dc_validation_set set[],
3670 int set_count,
3671 struct dc_state *state)
3672 {
3673 int i, j;
3674
3675 for (i = 0; i < set_count; i++)
3676 if (set[i].stream == stream)
3677 break;
3678
3679 if (i == set_count) {
3680 dm_error("Stream %p not found in set!\n", stream);
3681 return false;
3682 }
3683
3684 for (j = 0; j < set[i].plane_count; j++)
3685 if (!dc_state_add_plane(dc, stream, set[i].plane_states[j], state))
3686 return false;
3687
3688 return true;
3689 }
3690
3691 /**
3692 * dc_validate_with_context - Validate and update the potential new stream in the context object
3693 *
3694 * @dc: Used to get the current state status
3695 * @set: An array of dc_validation_set with all the current streams reference
3696 * @set_count: Total of streams
3697 * @context: New context
3698 * @fast_validate: Enable or disable fast validation
3699 *
3700 * This function updates the potential new stream in the context object. It
3701 * creates multiple lists for the add, remove, and unchanged streams. In
3702 * particular, if the unchanged streams have a plane that changed, it is
3703 * necessary to remove all planes from the unchanged streams. In summary, this
3704 * function is responsible for validating the new context.
3705 *
3706 * Return:
3707 * In case of success, return DC_OK (1), otherwise, return a DC error.
3708 */
dc_validate_with_context(struct dc * dc,const struct dc_validation_set set[],int set_count,struct dc_state * context,bool fast_validate)3709 enum dc_status dc_validate_with_context(struct dc *dc,
3710 const struct dc_validation_set set[],
3711 int set_count,
3712 struct dc_state *context,
3713 bool fast_validate)
3714 {
3715 struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 };
3716 struct dc_stream_state *del_streams[MAX_PIPES] = { 0 };
3717 struct dc_stream_state *add_streams[MAX_PIPES] = { 0 };
3718 int old_stream_count = context->stream_count;
3719 enum dc_status res = DC_ERROR_UNEXPECTED;
3720 int unchanged_streams_count = 0;
3721 int del_streams_count = 0;
3722 int add_streams_count = 0;
3723 bool found = false;
3724 int i, j, k;
3725
3726 DC_LOGGER_INIT(dc->ctx->logger);
3727
3728 /* First build a list of streams to be remove from current context */
3729 for (i = 0; i < old_stream_count; i++) {
3730 struct dc_stream_state *stream = context->streams[i];
3731
3732 for (j = 0; j < set_count; j++) {
3733 if (stream == set[j].stream) {
3734 found = true;
3735 break;
3736 }
3737 }
3738
3739 if (!found)
3740 del_streams[del_streams_count++] = stream;
3741
3742 found = false;
3743 }
3744
3745 /* Second, build a list of new streams */
3746 for (i = 0; i < set_count; i++) {
3747 struct dc_stream_state *stream = set[i].stream;
3748
3749 for (j = 0; j < old_stream_count; j++) {
3750 if (stream == context->streams[j]) {
3751 found = true;
3752 break;
3753 }
3754 }
3755
3756 if (!found)
3757 add_streams[add_streams_count++] = stream;
3758
3759 found = false;
3760 }
3761
3762 /* Build a list of unchanged streams which is necessary for handling
3763 * planes change such as added, removed, and updated.
3764 */
3765 for (i = 0; i < set_count; i++) {
3766 /* Check if stream is part of the delete list */
3767 for (j = 0; j < del_streams_count; j++) {
3768 if (set[i].stream == del_streams[j]) {
3769 found = true;
3770 break;
3771 }
3772 }
3773
3774 if (!found) {
3775 /* Check if stream is part of the add list */
3776 for (j = 0; j < add_streams_count; j++) {
3777 if (set[i].stream == add_streams[j]) {
3778 found = true;
3779 break;
3780 }
3781 }
3782 }
3783
3784 if (!found)
3785 unchanged_streams[unchanged_streams_count++] = set[i].stream;
3786
3787 found = false;
3788 }
3789
3790 /* Remove all planes for unchanged streams if planes changed */
3791 for (i = 0; i < unchanged_streams_count; i++) {
3792 if (planes_changed_for_existing_stream(context,
3793 unchanged_streams[i],
3794 set,
3795 set_count)) {
3796
3797 if (!dc_state_rem_all_planes_for_stream(dc,
3798 unchanged_streams[i],
3799 context)) {
3800 res = DC_FAIL_DETACH_SURFACES;
3801 goto fail;
3802 }
3803 }
3804 }
3805
3806 /* Remove all planes for removed streams and then remove the streams */
3807 for (i = 0; i < del_streams_count; i++) {
3808 /* Need to cpy the dwb data from the old stream in order to efc to work */
3809 if (del_streams[i]->num_wb_info > 0) {
3810 for (j = 0; j < add_streams_count; j++) {
3811 if (del_streams[i]->sink == add_streams[j]->sink) {
3812 add_streams[j]->num_wb_info = del_streams[i]->num_wb_info;
3813 for (k = 0; k < del_streams[i]->num_wb_info; k++)
3814 add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k];
3815 }
3816 }
3817 }
3818
3819 if (dc_state_get_stream_subvp_type(context, del_streams[i]) == SUBVP_PHANTOM) {
3820 /* remove phantoms specifically */
3821 if (!dc_state_rem_all_phantom_planes_for_stream(dc, del_streams[i], context, true)) {
3822 res = DC_FAIL_DETACH_SURFACES;
3823 goto fail;
3824 }
3825
3826 res = dc_state_remove_phantom_stream(dc, context, del_streams[i]);
3827 dc_state_release_phantom_stream(dc, context, del_streams[i]);
3828 } else {
3829 if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) {
3830 res = DC_FAIL_DETACH_SURFACES;
3831 goto fail;
3832 }
3833
3834 res = dc_state_remove_stream(dc, context, del_streams[i]);
3835 }
3836
3837 if (res != DC_OK)
3838 goto fail;
3839 }
3840
3841 /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx
3842 * matches. This may change in the future if seamless_boot_stream can be
3843 * multiple.
3844 */
3845 for (i = 0; i < add_streams_count; i++) {
3846 mark_seamless_boot_stream(dc, add_streams[i]);
3847 if (add_streams[i]->apply_seamless_boot_optimization && i != 0) {
3848 struct dc_stream_state *temp = add_streams[0];
3849
3850 add_streams[0] = add_streams[i];
3851 add_streams[i] = temp;
3852 break;
3853 }
3854 }
3855
3856 /* Add new streams and then add all planes for the new stream */
3857 for (i = 0; i < add_streams_count; i++) {
3858 calculate_phy_pix_clks(add_streams[i]);
3859 res = dc_state_add_stream(dc, context, add_streams[i]);
3860 if (res != DC_OK)
3861 goto fail;
3862
3863 if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
3864 res = DC_FAIL_ATTACH_SURFACES;
3865 goto fail;
3866 }
3867 }
3868
3869 /* Add all planes for unchanged streams if planes changed */
3870 for (i = 0; i < unchanged_streams_count; i++) {
3871 if (planes_changed_for_existing_stream(context,
3872 unchanged_streams[i],
3873 set,
3874 set_count)) {
3875 if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
3876 res = DC_FAIL_ATTACH_SURFACES;
3877 goto fail;
3878 }
3879 }
3880 }
3881
3882 res = dc_validate_global_state(dc, context, fast_validate);
3883
3884 fail:
3885 if (res != DC_OK)
3886 DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
3887 __func__,
3888 res);
3889
3890 return res;
3891 }
3892
3893 /**
3894 * dc_validate_global_state() - Determine if hardware can support a given state
3895 *
3896 * @dc: dc struct for this driver
3897 * @new_ctx: state to be validated
3898 * @fast_validate: set to true if only yes/no to support matters
3899 *
3900 * Checks hardware resource availability and bandwidth requirement.
3901 *
3902 * Return:
3903 * DC_OK if the result can be programmed. Otherwise, an error code.
3904 */
dc_validate_global_state(struct dc * dc,struct dc_state * new_ctx,bool fast_validate)3905 enum dc_status dc_validate_global_state(
3906 struct dc *dc,
3907 struct dc_state *new_ctx,
3908 bool fast_validate)
3909 {
3910 enum dc_status result = DC_ERROR_UNEXPECTED;
3911 int i, j;
3912
3913 if (!new_ctx)
3914 return DC_ERROR_UNEXPECTED;
3915
3916 if (dc->res_pool->funcs->validate_global) {
3917 result = dc->res_pool->funcs->validate_global(dc, new_ctx);
3918 if (result != DC_OK)
3919 return result;
3920 }
3921
3922 for (i = 0; i < new_ctx->stream_count; i++) {
3923 struct dc_stream_state *stream = new_ctx->streams[i];
3924
3925 for (j = 0; j < dc->res_pool->pipe_count; j++) {
3926 struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[j];
3927
3928 if (pipe_ctx->stream != stream)
3929 continue;
3930
3931 if (dc->res_pool->funcs->patch_unknown_plane_state &&
3932 pipe_ctx->plane_state &&
3933 pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) {
3934 result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state);
3935 if (result != DC_OK)
3936 return result;
3937 }
3938
3939 /* Switch to dp clock source only if there is
3940 * no non dp stream that shares the same timing
3941 * with the dp stream.
3942 */
3943 if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
3944 !find_pll_sharable_stream(stream, new_ctx)) {
3945
3946 resource_unreference_clock_source(
3947 &new_ctx->res_ctx,
3948 dc->res_pool,
3949 pipe_ctx->clock_source);
3950
3951 pipe_ctx->clock_source = dc->res_pool->dp_clock_source;
3952 resource_reference_clock_source(
3953 &new_ctx->res_ctx,
3954 dc->res_pool,
3955 pipe_ctx->clock_source);
3956 }
3957 }
3958 }
3959
3960 result = resource_build_scaling_params_for_context(dc, new_ctx);
3961
3962 if (result == DC_OK)
3963 if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
3964 result = DC_FAIL_BANDWIDTH_VALIDATE;
3965
3966 /*
3967 * Only update link encoder to stream assignment after bandwidth validation passed.
3968 * TODO: Split out assignment and validation.
3969 */
3970 if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false)
3971 dc->res_pool->funcs->link_encs_assign(
3972 dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
3973
3974 return result;
3975 }
3976
patch_gamut_packet_checksum(struct dc_info_packet * gamut_packet)3977 static void patch_gamut_packet_checksum(
3978 struct dc_info_packet *gamut_packet)
3979 {
3980 /* For gamut we recalc checksum */
3981 if (gamut_packet->valid) {
3982 uint8_t chk_sum = 0;
3983 uint8_t *ptr;
3984 uint8_t i;
3985
3986 /*start of the Gamut data. */
3987 ptr = &gamut_packet->sb[3];
3988
3989 for (i = 0; i <= gamut_packet->sb[1]; i++)
3990 chk_sum += ptr[i];
3991
3992 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
3993 }
3994 }
3995
set_avi_info_frame(struct dc_info_packet * info_packet,struct pipe_ctx * pipe_ctx)3996 static void set_avi_info_frame(
3997 struct dc_info_packet *info_packet,
3998 struct pipe_ctx *pipe_ctx)
3999 {
4000 struct dc_stream_state *stream = pipe_ctx->stream;
4001 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
4002 uint32_t pixel_encoding = 0;
4003 enum scanning_type scan_type = SCANNING_TYPE_NODATA;
4004 enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
4005 uint8_t *check_sum = NULL;
4006 uint8_t byte_index = 0;
4007 union hdmi_info_packet hdmi_info;
4008 unsigned int vic = pipe_ctx->stream->timing.vic;
4009 unsigned int rid = pipe_ctx->stream->timing.rid;
4010 unsigned int fr_ind = pipe_ctx->stream->timing.fr_index;
4011 enum dc_timing_3d_format format;
4012
4013 memset(&hdmi_info, 0, sizeof(union hdmi_info_packet));
4014
4015 color_space = pipe_ctx->stream->output_color_space;
4016 if (color_space == COLOR_SPACE_UNKNOWN)
4017 color_space = (stream->timing.pixel_encoding == PIXEL_ENCODING_RGB) ?
4018 COLOR_SPACE_SRGB:COLOR_SPACE_YCBCR709;
4019
4020 /* Initialize header */
4021 hdmi_info.bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
4022 /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
4023 * not be used in HDMI 2.0 (Section 10.1) */
4024 hdmi_info.bits.header.version = 2;
4025 hdmi_info.bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
4026
4027 /*
4028 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
4029 * according to HDMI 2.0 spec (Section 10.1)
4030 */
4031
4032 switch (stream->timing.pixel_encoding) {
4033 case PIXEL_ENCODING_YCBCR422:
4034 pixel_encoding = 1;
4035 break;
4036
4037 case PIXEL_ENCODING_YCBCR444:
4038 pixel_encoding = 2;
4039 break;
4040 case PIXEL_ENCODING_YCBCR420:
4041 pixel_encoding = 3;
4042 break;
4043
4044 case PIXEL_ENCODING_RGB:
4045 default:
4046 pixel_encoding = 0;
4047 }
4048
4049 /* Y0_Y1_Y2 : The pixel encoding */
4050 /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
4051 hdmi_info.bits.Y0_Y1_Y2 = pixel_encoding;
4052
4053 /* A0 = 1 Active Format Information valid */
4054 hdmi_info.bits.A0 = ACTIVE_FORMAT_VALID;
4055
4056 /* B0, B1 = 3; Bar info data is valid */
4057 hdmi_info.bits.B0_B1 = BAR_INFO_BOTH_VALID;
4058
4059 hdmi_info.bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
4060
4061 /* S0, S1 : Underscan / Overscan */
4062 /* TODO: un-hardcode scan type */
4063 scan_type = SCANNING_TYPE_UNDERSCAN;
4064 hdmi_info.bits.S0_S1 = scan_type;
4065
4066 /* C0, C1 : Colorimetry */
4067 switch (color_space) {
4068 case COLOR_SPACE_YCBCR709:
4069 case COLOR_SPACE_YCBCR709_LIMITED:
4070 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
4071 break;
4072 case COLOR_SPACE_YCBCR601:
4073 case COLOR_SPACE_YCBCR601_LIMITED:
4074 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601;
4075 break;
4076 case COLOR_SPACE_2020_RGB_FULLRANGE:
4077 case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
4078 case COLOR_SPACE_2020_YCBCR:
4079 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
4080 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED;
4081 break;
4082 case COLOR_SPACE_ADOBERGB:
4083 hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
4084 hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED;
4085 break;
4086 case COLOR_SPACE_SRGB:
4087 default:
4088 hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA;
4089 break;
4090 }
4091
4092 if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR &&
4093 stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22) {
4094 hdmi_info.bits.EC0_EC2 = 0;
4095 hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709;
4096 }
4097
4098 /* TODO: un-hardcode aspect ratio */
4099 aspect = stream->timing.aspect_ratio;
4100
4101 switch (aspect) {
4102 case ASPECT_RATIO_4_3:
4103 case ASPECT_RATIO_16_9:
4104 hdmi_info.bits.M0_M1 = aspect;
4105 break;
4106
4107 case ASPECT_RATIO_NO_DATA:
4108 case ASPECT_RATIO_64_27:
4109 case ASPECT_RATIO_256_135:
4110 default:
4111 hdmi_info.bits.M0_M1 = 0;
4112 }
4113
4114 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
4115 hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
4116
4117 switch (stream->content_type) {
4118 case DISPLAY_CONTENT_TYPE_NO_DATA:
4119 hdmi_info.bits.CN0_CN1 = 0;
4120 hdmi_info.bits.ITC = 1;
4121 break;
4122 case DISPLAY_CONTENT_TYPE_GRAPHICS:
4123 hdmi_info.bits.CN0_CN1 = 0;
4124 hdmi_info.bits.ITC = 1;
4125 break;
4126 case DISPLAY_CONTENT_TYPE_PHOTO:
4127 hdmi_info.bits.CN0_CN1 = 1;
4128 hdmi_info.bits.ITC = 1;
4129 break;
4130 case DISPLAY_CONTENT_TYPE_CINEMA:
4131 hdmi_info.bits.CN0_CN1 = 2;
4132 hdmi_info.bits.ITC = 1;
4133 break;
4134 case DISPLAY_CONTENT_TYPE_GAME:
4135 hdmi_info.bits.CN0_CN1 = 3;
4136 hdmi_info.bits.ITC = 1;
4137 break;
4138 }
4139
4140 if (stream->qs_bit == 1) {
4141 if (color_space == COLOR_SPACE_SRGB ||
4142 color_space == COLOR_SPACE_2020_RGB_FULLRANGE)
4143 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE;
4144 else if (color_space == COLOR_SPACE_SRGB_LIMITED ||
4145 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)
4146 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE;
4147 else
4148 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE;
4149 } else
4150 hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE;
4151
4152 /* TODO : We should handle YCC quantization */
4153 /* but we do not have matrix calculation */
4154 hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
4155
4156 ///VIC
4157 if (pipe_ctx->stream->timing.hdmi_vic != 0)
4158 vic = 0;
4159 format = stream->timing.timing_3d_format;
4160 /*todo, add 3DStereo support*/
4161 if (format != TIMING_3D_FORMAT_NONE) {
4162 // Based on HDMI specs hdmi vic needs to be converted to cea vic when 3D is enabled
4163 switch (pipe_ctx->stream->timing.hdmi_vic) {
4164 case 1:
4165 vic = 95;
4166 break;
4167 case 2:
4168 vic = 94;
4169 break;
4170 case 3:
4171 vic = 93;
4172 break;
4173 case 4:
4174 vic = 98;
4175 break;
4176 default:
4177 break;
4178 }
4179 }
4180 /* If VIC >= 128, the Source shall use AVI InfoFrame Version 3*/
4181 hdmi_info.bits.VIC0_VIC7 = vic;
4182 if (vic >= 128)
4183 hdmi_info.bits.header.version = 3;
4184 /* If (C1, C0)=(1, 1) and (EC2, EC1, EC0)=(1, 1, 1),
4185 * the Source shall use 20 AVI InfoFrame Version 4
4186 */
4187 if (hdmi_info.bits.C0_C1 == COLORIMETRY_EXTENDED &&
4188 hdmi_info.bits.EC0_EC2 == COLORIMETRYEX_RESERVED) {
4189 hdmi_info.bits.header.version = 4;
4190 hdmi_info.bits.header.length = 14;
4191 }
4192
4193 if (rid != 0 && fr_ind != 0) {
4194 hdmi_info.bits.header.version = 5;
4195 hdmi_info.bits.header.length = 15;
4196
4197 hdmi_info.bits.FR0_FR3 = fr_ind & 0xF;
4198 hdmi_info.bits.FR4 = (fr_ind >> 4) & 0x1;
4199 hdmi_info.bits.RID0_RID5 = rid;
4200 }
4201
4202 /* pixel repetition
4203 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
4204 * repetition start from 1 */
4205 hdmi_info.bits.PR0_PR3 = 0;
4206
4207 /* Bar Info
4208 * barTop: Line Number of End of Top Bar.
4209 * barBottom: Line Number of Start of Bottom Bar.
4210 * barLeft: Pixel Number of End of Left Bar.
4211 * barRight: Pixel Number of Start of Right Bar. */
4212 hdmi_info.bits.bar_top = stream->timing.v_border_top;
4213 hdmi_info.bits.bar_bottom = (stream->timing.v_total
4214 - stream->timing.v_border_bottom + 1);
4215 hdmi_info.bits.bar_left = stream->timing.h_border_left;
4216 hdmi_info.bits.bar_right = (stream->timing.h_total
4217 - stream->timing.h_border_right + 1);
4218
4219 /* Additional Colorimetry Extension
4220 * Used in conduction with C0-C1 and EC0-EC2
4221 * 0 = DCI-P3 RGB (D65)
4222 * 1 = DCI-P3 RGB (theater)
4223 */
4224 hdmi_info.bits.ACE0_ACE3 = 0;
4225
4226 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
4227 check_sum = &hdmi_info.packet_raw_data.sb[0];
4228
4229 *check_sum = HDMI_INFOFRAME_TYPE_AVI + hdmi_info.bits.header.length + hdmi_info.bits.header.version;
4230
4231 for (byte_index = 1; byte_index <= hdmi_info.bits.header.length; byte_index++)
4232 *check_sum += hdmi_info.packet_raw_data.sb[byte_index];
4233
4234 /* one byte complement */
4235 *check_sum = (uint8_t) (0x100 - *check_sum);
4236
4237 /* Store in hw_path_mode */
4238 info_packet->hb0 = hdmi_info.packet_raw_data.hb0;
4239 info_packet->hb1 = hdmi_info.packet_raw_data.hb1;
4240 info_packet->hb2 = hdmi_info.packet_raw_data.hb2;
4241
4242 for (byte_index = 0; byte_index < sizeof(hdmi_info.packet_raw_data.sb); byte_index++)
4243 info_packet->sb[byte_index] = hdmi_info.packet_raw_data.sb[byte_index];
4244
4245 info_packet->valid = true;
4246 }
4247
set_vendor_info_packet(struct dc_info_packet * info_packet,struct dc_stream_state * stream)4248 static void set_vendor_info_packet(
4249 struct dc_info_packet *info_packet,
4250 struct dc_stream_state *stream)
4251 {
4252 /* SPD info packet for FreeSync */
4253
4254 /* Check if Freesync is supported. Return if false. If true,
4255 * set the corresponding bit in the info packet
4256 */
4257 if (!stream->vsp_infopacket.valid)
4258 return;
4259
4260 *info_packet = stream->vsp_infopacket;
4261 }
4262
set_spd_info_packet(struct dc_info_packet * info_packet,struct dc_stream_state * stream)4263 static void set_spd_info_packet(
4264 struct dc_info_packet *info_packet,
4265 struct dc_stream_state *stream)
4266 {
4267 /* SPD info packet for FreeSync */
4268
4269 /* Check if Freesync is supported. Return if false. If true,
4270 * set the corresponding bit in the info packet
4271 */
4272 if (!stream->vrr_infopacket.valid)
4273 return;
4274
4275 *info_packet = stream->vrr_infopacket;
4276 }
4277
set_hdr_static_info_packet(struct dc_info_packet * info_packet,struct dc_stream_state * stream)4278 static void set_hdr_static_info_packet(
4279 struct dc_info_packet *info_packet,
4280 struct dc_stream_state *stream)
4281 {
4282 /* HDR Static Metadata info packet for HDR10 */
4283
4284 if (!stream->hdr_static_metadata.valid ||
4285 stream->use_dynamic_meta)
4286 return;
4287
4288 *info_packet = stream->hdr_static_metadata;
4289 }
4290
set_vsc_info_packet(struct dc_info_packet * info_packet,struct dc_stream_state * stream)4291 static void set_vsc_info_packet(
4292 struct dc_info_packet *info_packet,
4293 struct dc_stream_state *stream)
4294 {
4295 if (!stream->vsc_infopacket.valid)
4296 return;
4297
4298 *info_packet = stream->vsc_infopacket;
4299 }
set_hfvs_info_packet(struct dc_info_packet * info_packet,struct dc_stream_state * stream)4300 static void set_hfvs_info_packet(
4301 struct dc_info_packet *info_packet,
4302 struct dc_stream_state *stream)
4303 {
4304 if (!stream->hfvsif_infopacket.valid)
4305 return;
4306
4307 *info_packet = stream->hfvsif_infopacket;
4308 }
4309
adaptive_sync_override_dp_info_packets_sdp_line_num(const struct dc_crtc_timing * timing,struct enc_sdp_line_num * sdp_line_num,struct _vcs_dpi_display_pipe_dest_params_st * pipe_dlg_param)4310 static void adaptive_sync_override_dp_info_packets_sdp_line_num(
4311 const struct dc_crtc_timing *timing,
4312 struct enc_sdp_line_num *sdp_line_num,
4313 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
4314 {
4315 uint32_t asic_blank_start = 0;
4316 uint32_t asic_blank_end = 0;
4317 uint32_t v_update = 0;
4318
4319 const struct dc_crtc_timing *tg = timing;
4320
4321 /* blank_start = frame end - front porch */
4322 asic_blank_start = tg->v_total - tg->v_front_porch;
4323
4324 /* blank_end = blank_start - active */
4325 asic_blank_end = (asic_blank_start - tg->v_border_bottom -
4326 tg->v_addressable - tg->v_border_top);
4327
4328 if (pipe_dlg_param->vstartup_start > asic_blank_end) {
4329 v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end));
4330 sdp_line_num->adaptive_sync_line_num_valid = true;
4331 sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
4332 } else {
4333 sdp_line_num->adaptive_sync_line_num_valid = false;
4334 sdp_line_num->adaptive_sync_line_num = 0;
4335 }
4336 }
4337
set_adaptive_sync_info_packet(struct dc_info_packet * info_packet,const struct dc_stream_state * stream,struct encoder_info_frame * info_frame,struct _vcs_dpi_display_pipe_dest_params_st * pipe_dlg_param)4338 static void set_adaptive_sync_info_packet(
4339 struct dc_info_packet *info_packet,
4340 const struct dc_stream_state *stream,
4341 struct encoder_info_frame *info_frame,
4342 struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
4343 {
4344 if (!stream->adaptive_sync_infopacket.valid)
4345 return;
4346
4347 adaptive_sync_override_dp_info_packets_sdp_line_num(
4348 &stream->timing,
4349 &info_frame->sdp_line_num,
4350 pipe_dlg_param);
4351
4352 *info_packet = stream->adaptive_sync_infopacket;
4353 }
4354
set_vtem_info_packet(struct dc_info_packet * info_packet,struct dc_stream_state * stream)4355 static void set_vtem_info_packet(
4356 struct dc_info_packet *info_packet,
4357 struct dc_stream_state *stream)
4358 {
4359 if (!stream->vtem_infopacket.valid)
4360 return;
4361
4362 *info_packet = stream->vtem_infopacket;
4363 }
4364
dc_resource_find_first_free_pll(struct resource_context * res_ctx,const struct resource_pool * pool)4365 struct clock_source *dc_resource_find_first_free_pll(
4366 struct resource_context *res_ctx,
4367 const struct resource_pool *pool)
4368 {
4369 int i;
4370
4371 for (i = 0; i < pool->clk_src_count; ++i) {
4372 if (res_ctx->clock_source_ref_count[i] == 0)
4373 return pool->clock_sources[i];
4374 }
4375
4376 return NULL;
4377 }
4378
resource_build_info_frame(struct pipe_ctx * pipe_ctx)4379 void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
4380 {
4381 enum signal_type signal = SIGNAL_TYPE_NONE;
4382 struct encoder_info_frame *info = &pipe_ctx->stream_res.encoder_info_frame;
4383
4384 /* default all packets to invalid */
4385 info->avi.valid = false;
4386 info->gamut.valid = false;
4387 info->vendor.valid = false;
4388 info->spd.valid = false;
4389 info->hdrsmd.valid = false;
4390 info->vsc.valid = false;
4391 info->hfvsif.valid = false;
4392 info->vtem.valid = false;
4393 info->adaptive_sync.valid = false;
4394 signal = pipe_ctx->stream->signal;
4395
4396 /* HDMi and DP have different info packets*/
4397 if (dc_is_hdmi_signal(signal)) {
4398 set_avi_info_frame(&info->avi, pipe_ctx);
4399
4400 set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
4401 set_hfvs_info_packet(&info->hfvsif, pipe_ctx->stream);
4402 set_vtem_info_packet(&info->vtem, pipe_ctx->stream);
4403
4404 set_spd_info_packet(&info->spd, pipe_ctx->stream);
4405
4406 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
4407
4408 } else if (dc_is_dp_signal(signal)) {
4409 set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
4410
4411 set_spd_info_packet(&info->spd, pipe_ctx->stream);
4412
4413 set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
4414 set_adaptive_sync_info_packet(&info->adaptive_sync,
4415 pipe_ctx->stream,
4416 info,
4417 &pipe_ctx->pipe_dlg_param);
4418 }
4419
4420 patch_gamut_packet_checksum(&info->gamut);
4421 }
4422
resource_map_clock_resources(const struct dc * dc,struct dc_state * context,struct dc_stream_state * stream)4423 enum dc_status resource_map_clock_resources(
4424 const struct dc *dc,
4425 struct dc_state *context,
4426 struct dc_stream_state *stream)
4427 {
4428 /* acquire new resources */
4429 const struct resource_pool *pool = dc->res_pool;
4430 struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
4431 &context->res_ctx, stream);
4432
4433 if (!pipe_ctx)
4434 return DC_ERROR_UNEXPECTED;
4435
4436 if (dc_is_dp_signal(pipe_ctx->stream->signal)
4437 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
4438 pipe_ctx->clock_source = pool->dp_clock_source;
4439 else {
4440 pipe_ctx->clock_source = NULL;
4441
4442 if (!dc->config.disable_disp_pll_sharing)
4443 pipe_ctx->clock_source = resource_find_used_clk_src_for_sharing(
4444 &context->res_ctx,
4445 pipe_ctx);
4446
4447 if (pipe_ctx->clock_source == NULL)
4448 pipe_ctx->clock_source =
4449 dc_resource_find_first_free_pll(
4450 &context->res_ctx,
4451 pool);
4452 }
4453
4454 if (pipe_ctx->clock_source == NULL)
4455 return DC_NO_CLOCK_SOURCE_RESOURCE;
4456
4457 resource_reference_clock_source(
4458 &context->res_ctx, pool,
4459 pipe_ctx->clock_source);
4460
4461 return DC_OK;
4462 }
4463
4464 /*
4465 * Note: We need to disable output if clock sources change,
4466 * since bios does optimization and doesn't apply if changing
4467 * PHY when not already disabled.
4468 */
pipe_need_reprogram(struct pipe_ctx * pipe_ctx_old,struct pipe_ctx * pipe_ctx)4469 bool pipe_need_reprogram(
4470 struct pipe_ctx *pipe_ctx_old,
4471 struct pipe_ctx *pipe_ctx)
4472 {
4473 if (!pipe_ctx_old->stream)
4474 return false;
4475
4476 if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
4477 return true;
4478
4479 if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
4480 return true;
4481
4482 if (pipe_ctx_old->stream_res.audio != pipe_ctx->stream_res.audio)
4483 return true;
4484
4485 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
4486 && pipe_ctx_old->stream != pipe_ctx->stream)
4487 return true;
4488
4489 if (pipe_ctx_old->stream_res.stream_enc != pipe_ctx->stream_res.stream_enc)
4490 return true;
4491
4492 if (dc_is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
4493 return true;
4494
4495 if (pipe_ctx_old->stream->dpms_off != pipe_ctx->stream->dpms_off)
4496 return true;
4497
4498 if (false == pipe_ctx_old->stream->link->link_state_valid &&
4499 false == pipe_ctx_old->stream->dpms_off)
4500 return true;
4501
4502 if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
4503 return true;
4504
4505 if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
4506 return true;
4507 if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
4508 return true;
4509
4510 /* DIG link encoder resource assignment for stream changed. */
4511 if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
4512 bool need_reprogram = false;
4513 struct dc *dc = pipe_ctx_old->stream->ctx->dc;
4514 struct link_encoder *link_enc_prev =
4515 link_enc_cfg_get_link_enc_used_by_stream_current(dc, pipe_ctx_old->stream);
4516
4517 if (link_enc_prev != pipe_ctx->stream->link_enc)
4518 need_reprogram = true;
4519
4520 return need_reprogram;
4521 }
4522
4523 return false;
4524 }
4525
resource_build_bit_depth_reduction_params(struct dc_stream_state * stream,struct bit_depth_reduction_params * fmt_bit_depth)4526 void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
4527 struct bit_depth_reduction_params *fmt_bit_depth)
4528 {
4529 enum dc_dither_option option = stream->dither_option;
4530 enum dc_pixel_encoding pixel_encoding =
4531 stream->timing.pixel_encoding;
4532
4533 memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
4534
4535 if (option == DITHER_OPTION_DEFAULT) {
4536 switch (stream->timing.display_color_depth) {
4537 case COLOR_DEPTH_666:
4538 option = DITHER_OPTION_SPATIAL6;
4539 break;
4540 case COLOR_DEPTH_888:
4541 option = DITHER_OPTION_SPATIAL8;
4542 break;
4543 case COLOR_DEPTH_101010:
4544 option = DITHER_OPTION_TRUN10;
4545 break;
4546 default:
4547 option = DITHER_OPTION_DISABLE;
4548 }
4549 }
4550
4551 if (option == DITHER_OPTION_DISABLE)
4552 return;
4553
4554 if (option == DITHER_OPTION_TRUN6) {
4555 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4556 fmt_bit_depth->flags.TRUNCATE_DEPTH = 0;
4557 } else if (option == DITHER_OPTION_TRUN8 ||
4558 option == DITHER_OPTION_TRUN8_SPATIAL6 ||
4559 option == DITHER_OPTION_TRUN8_FM6) {
4560 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4561 fmt_bit_depth->flags.TRUNCATE_DEPTH = 1;
4562 } else if (option == DITHER_OPTION_TRUN10 ||
4563 option == DITHER_OPTION_TRUN10_SPATIAL6 ||
4564 option == DITHER_OPTION_TRUN10_SPATIAL8 ||
4565 option == DITHER_OPTION_TRUN10_FM8 ||
4566 option == DITHER_OPTION_TRUN10_FM6 ||
4567 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
4568 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4569 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
4570 if (option == DITHER_OPTION_TRUN10)
4571 fmt_bit_depth->flags.TRUNCATE_MODE = 1;
4572 }
4573
4574 /* special case - Formatter can only reduce by 4 bits at most.
4575 * When reducing from 12 to 6 bits,
4576 * HW recommends we use trunc with round mode
4577 * (if we did nothing, trunc to 10 bits would be used)
4578 * note that any 12->10 bit reduction is ignored prior to DCE8,
4579 * as the input was 10 bits.
4580 */
4581 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
4582 option == DITHER_OPTION_SPATIAL6 ||
4583 option == DITHER_OPTION_FM6) {
4584 fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
4585 fmt_bit_depth->flags.TRUNCATE_DEPTH = 2;
4586 fmt_bit_depth->flags.TRUNCATE_MODE = 1;
4587 }
4588
4589 /* spatial dither
4590 * note that spatial modes 1-3 are never used
4591 */
4592 if (option == DITHER_OPTION_SPATIAL6_FRAME_RANDOM ||
4593 option == DITHER_OPTION_SPATIAL6 ||
4594 option == DITHER_OPTION_TRUN10_SPATIAL6 ||
4595 option == DITHER_OPTION_TRUN8_SPATIAL6) {
4596 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
4597 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 0;
4598 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
4599 fmt_bit_depth->flags.RGB_RANDOM =
4600 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
4601 } else if (option == DITHER_OPTION_SPATIAL8_FRAME_RANDOM ||
4602 option == DITHER_OPTION_SPATIAL8 ||
4603 option == DITHER_OPTION_SPATIAL8_FM6 ||
4604 option == DITHER_OPTION_TRUN10_SPATIAL8 ||
4605 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
4606 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
4607 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
4608 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
4609 fmt_bit_depth->flags.RGB_RANDOM =
4610 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
4611 } else if (option == DITHER_OPTION_SPATIAL10_FRAME_RANDOM ||
4612 option == DITHER_OPTION_SPATIAL10 ||
4613 option == DITHER_OPTION_SPATIAL10_FM8 ||
4614 option == DITHER_OPTION_SPATIAL10_FM6) {
4615 fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
4616 fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 2;
4617 fmt_bit_depth->flags.HIGHPASS_RANDOM = 1;
4618 fmt_bit_depth->flags.RGB_RANDOM =
4619 (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
4620 }
4621
4622 if (option == DITHER_OPTION_SPATIAL6 ||
4623 option == DITHER_OPTION_SPATIAL8 ||
4624 option == DITHER_OPTION_SPATIAL10) {
4625 fmt_bit_depth->flags.FRAME_RANDOM = 0;
4626 } else {
4627 fmt_bit_depth->flags.FRAME_RANDOM = 1;
4628 }
4629
4630 //////////////////////
4631 //// temporal dither
4632 //////////////////////
4633 if (option == DITHER_OPTION_FM6 ||
4634 option == DITHER_OPTION_SPATIAL8_FM6 ||
4635 option == DITHER_OPTION_SPATIAL10_FM6 ||
4636 option == DITHER_OPTION_TRUN10_FM6 ||
4637 option == DITHER_OPTION_TRUN8_FM6 ||
4638 option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) {
4639 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
4640 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 0;
4641 } else if (option == DITHER_OPTION_FM8 ||
4642 option == DITHER_OPTION_SPATIAL10_FM8 ||
4643 option == DITHER_OPTION_TRUN10_FM8) {
4644 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
4645 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 1;
4646 } else if (option == DITHER_OPTION_FM10) {
4647 fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 1;
4648 fmt_bit_depth->flags.FRAME_MODULATION_DEPTH = 2;
4649 }
4650
4651 fmt_bit_depth->pixel_encoding = pixel_encoding;
4652 }
4653
dc_validate_stream(struct dc * dc,struct dc_stream_state * stream)4654 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
4655 {
4656 struct dc_link *link = stream->link;
4657 struct timing_generator *tg = dc->res_pool->timing_generators[0];
4658 enum dc_status res = DC_OK;
4659
4660 calculate_phy_pix_clks(stream);
4661
4662 if (!tg->funcs->validate_timing(tg, &stream->timing))
4663 res = DC_FAIL_CONTROLLER_VALIDATE;
4664
4665 if (res == DC_OK) {
4666 if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
4667 !link->link_enc->funcs->validate_output_with_stream(
4668 link->link_enc, stream))
4669 res = DC_FAIL_ENC_VALIDATE;
4670 }
4671
4672 /* TODO: validate audio ASIC caps, encoder */
4673
4674 if (res == DC_OK)
4675 res = dc->link_srv->validate_mode_timing(stream,
4676 link,
4677 &stream->timing);
4678
4679 return res;
4680 }
4681
dc_validate_plane(struct dc * dc,const struct dc_plane_state * plane_state)4682 enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
4683 {
4684 enum dc_status res = DC_OK;
4685
4686 /* check if surface has invalid dimensions */
4687 if (plane_state->src_rect.width == 0 || plane_state->src_rect.height == 0 ||
4688 plane_state->dst_rect.width == 0 || plane_state->dst_rect.height == 0)
4689 return DC_FAIL_SURFACE_VALIDATE;
4690
4691 /* TODO For now validates pixel format only */
4692 if (dc->res_pool->funcs->validate_plane)
4693 return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
4694
4695 return res;
4696 }
4697
resource_pixel_format_to_bpp(enum surface_pixel_format format)4698 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
4699 {
4700 switch (format) {
4701 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
4702 return 8;
4703 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
4704 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
4705 return 12;
4706 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
4707 case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
4708 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
4709 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
4710 return 16;
4711 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
4712 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
4713 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
4714 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
4715 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
4716 case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
4717 case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
4718 return 32;
4719 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
4720 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
4721 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
4722 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
4723 return 64;
4724 default:
4725 ASSERT_CRITICAL(false);
4726 return -1;
4727 }
4728 }
get_max_audio_sample_rate(struct audio_mode * modes)4729 static unsigned int get_max_audio_sample_rate(struct audio_mode *modes)
4730 {
4731 if (modes) {
4732 if (modes->sample_rates.rate.RATE_192)
4733 return 192000;
4734 if (modes->sample_rates.rate.RATE_176_4)
4735 return 176400;
4736 if (modes->sample_rates.rate.RATE_96)
4737 return 96000;
4738 if (modes->sample_rates.rate.RATE_88_2)
4739 return 88200;
4740 if (modes->sample_rates.rate.RATE_48)
4741 return 48000;
4742 if (modes->sample_rates.rate.RATE_44_1)
4743 return 44100;
4744 if (modes->sample_rates.rate.RATE_32)
4745 return 32000;
4746 }
4747 /*original logic when no audio info*/
4748 return 441000;
4749 }
4750
get_audio_check(struct audio_info * aud_modes,struct audio_check * audio_chk)4751 void get_audio_check(struct audio_info *aud_modes,
4752 struct audio_check *audio_chk)
4753 {
4754 unsigned int i;
4755 unsigned int max_sample_rate = 0;
4756
4757 if (aud_modes) {
4758 audio_chk->audio_packet_type = 0x2;/*audio sample packet AP = .25 for layout0, 1 for layout1*/
4759
4760 audio_chk->max_audiosample_rate = 0;
4761 for (i = 0; i < aud_modes->mode_count; i++) {
4762 max_sample_rate = get_max_audio_sample_rate(&aud_modes->modes[i]);
4763 if (audio_chk->max_audiosample_rate < max_sample_rate)
4764 audio_chk->max_audiosample_rate = max_sample_rate;
4765 /*dts takes the same as type 2: AP = 0.25*/
4766 }
4767 /*check which one take more bandwidth*/
4768 if (audio_chk->max_audiosample_rate > 192000)
4769 audio_chk->audio_packet_type = 0x9;/*AP =1*/
4770 audio_chk->acat = 0;/*not support*/
4771 }
4772 }
4773
get_temp_hpo_dp_link_enc(const struct resource_context * res_ctx,const struct resource_pool * const pool,const struct dc_link * link)4774 static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc(
4775 const struct resource_context *res_ctx,
4776 const struct resource_pool *const pool,
4777 const struct dc_link *link)
4778 {
4779 struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
4780 int enc_index;
4781
4782 enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link);
4783
4784 if (enc_index < 0)
4785 enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
4786
4787 if (enc_index >= 0)
4788 hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
4789
4790 return hpo_dp_link_enc;
4791 }
4792
get_temp_dp_link_res(struct dc_link * link,struct link_resource * link_res,struct dc_link_settings * link_settings)4793 bool get_temp_dp_link_res(struct dc_link *link,
4794 struct link_resource *link_res,
4795 struct dc_link_settings *link_settings)
4796 {
4797 const struct dc *dc = link->dc;
4798 const struct resource_context *res_ctx = &dc->current_state->res_ctx;
4799
4800 memset(link_res, 0, sizeof(*link_res));
4801
4802 if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
4803 link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx,
4804 dc->res_pool, link);
4805 if (!link_res->hpo_dp_link_enc)
4806 return false;
4807 }
4808 return true;
4809 }
4810
reset_syncd_pipes_from_disabled_pipes(struct dc * dc,struct dc_state * context)4811 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
4812 struct dc_state *context)
4813 {
4814 int i, j;
4815 struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
4816
4817 /* If pipe backend is reset, need to reset pipe syncd status */
4818 for (i = 0; i < dc->res_pool->pipe_count; i++) {
4819 pipe_ctx_old = &dc->current_state->res_ctx.pipe_ctx[i];
4820 pipe_ctx = &context->res_ctx.pipe_ctx[i];
4821
4822 if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER))
4823 continue;
4824
4825 if (!pipe_ctx->stream ||
4826 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
4827
4828 /* Reset all the syncd pipes from the disabled pipe */
4829 for (j = 0; j < dc->res_pool->pipe_count; j++) {
4830 pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
4831 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
4832 !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
4833 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
4834 }
4835 }
4836 }
4837 }
4838
check_syncd_pipes_for_disabled_master_pipe(struct dc * dc,struct dc_state * context,uint8_t disabled_master_pipe_idx)4839 void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
4840 struct dc_state *context,
4841 uint8_t disabled_master_pipe_idx)
4842 {
4843 int i;
4844 struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
4845
4846 pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
4847 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
4848 !IS_PIPE_SYNCD_VALID(pipe_ctx))
4849 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
4850
4851 /* for the pipe disabled, check if any slave pipe exists and assert */
4852 for (i = 0; i < dc->res_pool->pipe_count; i++) {
4853 pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
4854
4855 if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
4856 IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) {
4857 struct pipe_ctx *first_pipe = pipe_ctx_check;
4858
4859 while (first_pipe->prev_odm_pipe)
4860 first_pipe = first_pipe->prev_odm_pipe;
4861 /* When ODM combine is enabled, this case is expected. If the disabled pipe
4862 * is part of the ODM tree, then we should not print an error.
4863 * */
4864 if (first_pipe->pipe_idx == disabled_master_pipe_idx)
4865 continue;
4866
4867 DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
4868 i, disabled_master_pipe_idx);
4869 }
4870 }
4871 }
4872
reset_sync_context_for_pipe(const struct dc * dc,struct dc_state * context,uint8_t pipe_idx)4873 void reset_sync_context_for_pipe(const struct dc *dc,
4874 struct dc_state *context,
4875 uint8_t pipe_idx)
4876 {
4877 int i;
4878 struct pipe_ctx *pipe_ctx_reset;
4879
4880 /* reset the otg sync context for the pipe and its slave pipes if any */
4881 for (i = 0; i < dc->res_pool->pipe_count; i++) {
4882 pipe_ctx_reset = &context->res_ctx.pipe_ctx[i];
4883
4884 if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) &&
4885 IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx))
4886 SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i);
4887 }
4888 }
4889
resource_transmitter_to_phy_idx(const struct dc * dc,enum transmitter transmitter)4890 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
4891 {
4892 /* TODO - get transmitter to phy idx mapping from DMUB */
4893 uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A;
4894
4895 if (dc->ctx->dce_version == DCN_VERSION_3_1 &&
4896 dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
4897 switch (transmitter) {
4898 case TRANSMITTER_UNIPHY_A:
4899 phy_idx = 0;
4900 break;
4901 case TRANSMITTER_UNIPHY_B:
4902 phy_idx = 1;
4903 break;
4904 case TRANSMITTER_UNIPHY_C:
4905 phy_idx = 5;
4906 break;
4907 case TRANSMITTER_UNIPHY_D:
4908 phy_idx = 6;
4909 break;
4910 case TRANSMITTER_UNIPHY_E:
4911 phy_idx = 4;
4912 break;
4913 default:
4914 phy_idx = 0;
4915 break;
4916 }
4917 }
4918
4919 return phy_idx;
4920 }
4921
get_link_hwss(const struct dc_link * link,const struct link_resource * link_res)4922 const struct link_hwss *get_link_hwss(const struct dc_link *link,
4923 const struct link_resource *link_res)
4924 {
4925 /* Link_hwss is only accessible by getter function instead of accessing
4926 * by pointers in dc with the intent to protect against breaking polymorphism.
4927 */
4928 if (can_use_hpo_dp_link_hwss(link, link_res))
4929 /* TODO: some assumes that if decided link settings is 128b/132b
4930 * channel coding format hpo_dp_link_enc should be used.
4931 * Others believe that if hpo_dp_link_enc is available in link
4932 * resource then hpo_dp_link_enc must be used. This bound between
4933 * hpo_dp_link_enc != NULL and decided link settings is loosely coupled
4934 * with a premise that both hpo_dp_link_enc pointer and decided link
4935 * settings are determined based on single policy function like
4936 * "decide_link_settings" from upper layer. This "convention"
4937 * cannot be maintained and enforced at current level.
4938 * Therefore a refactor is due so we can enforce a strong bound
4939 * between those two parameters at this level.
4940 *
4941 * To put it simple, we want to make enforcement at low level so that
4942 * we will not return link hwss if caller plans to do 8b/10b
4943 * with an hpo encoder. Or we can return a very dummy one that doesn't
4944 * do work for all functions
4945 */
4946 return (requires_fixed_vs_pe_retimer_hpo_link_hwss(link) ?
4947 get_hpo_fixed_vs_pe_retimer_dp_link_hwss() : get_hpo_dp_link_hwss());
4948 else if (can_use_dpia_link_hwss(link, link_res))
4949 return get_dpia_link_hwss();
4950 else if (can_use_dio_link_hwss(link, link_res))
4951 return (requires_fixed_vs_pe_retimer_dio_link_hwss(link)) ?
4952 get_dio_fixed_vs_pe_retimer_link_hwss() : get_dio_link_hwss();
4953 else
4954 return get_virtual_link_hwss();
4955 }
4956
is_h_timing_divisible_by_2(struct dc_stream_state * stream)4957 bool is_h_timing_divisible_by_2(struct dc_stream_state *stream)
4958 {
4959 bool divisible = false;
4960 uint16_t h_blank_start = 0;
4961 uint16_t h_blank_end = 0;
4962
4963 if (stream) {
4964 h_blank_start = stream->timing.h_total - stream->timing.h_front_porch;
4965 h_blank_end = h_blank_start - stream->timing.h_addressable;
4966
4967 /* HTOTAL, Hblank start/end, and Hsync start/end all must be
4968 * divisible by 2 in order for the horizontal timing params
4969 * to be considered divisible by 2. Hsync start is always 0.
4970 */
4971 divisible = (stream->timing.h_total % 2 == 0) &&
4972 (h_blank_start % 2 == 0) &&
4973 (h_blank_end % 2 == 0) &&
4974 (stream->timing.h_sync_width % 2 == 0);
4975 }
4976 return divisible;
4977 }
4978
4979 /* This interface is deprecated for new DCNs. It is replaced by the following
4980 * new interfaces. These two interfaces encapsulate pipe selection priority
4981 * with DCN specific minimum hardware transition optimization algorithm. With
4982 * the new interfaces caller no longer needs to know the implementation detail
4983 * of a pipe topology.
4984 *
4985 * resource_update_pipes_with_odm_slice_count
4986 * resource_update_pipes_with_mpc_slice_count
4987 *
4988 */
dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy(const struct dc * dc,struct dc_state * state,struct pipe_ctx * pri_pipe,struct pipe_ctx * sec_pipe,bool odm)4989 bool dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy(
4990 const struct dc *dc,
4991 struct dc_state *state,
4992 struct pipe_ctx *pri_pipe,
4993 struct pipe_ctx *sec_pipe,
4994 bool odm)
4995 {
4996 int pipe_idx = sec_pipe->pipe_idx;
4997 struct pipe_ctx *sec_top, *sec_bottom, *sec_next, *sec_prev;
4998 const struct resource_pool *pool = dc->res_pool;
4999
5000 sec_top = sec_pipe->top_pipe;
5001 sec_bottom = sec_pipe->bottom_pipe;
5002 sec_next = sec_pipe->next_odm_pipe;
5003 sec_prev = sec_pipe->prev_odm_pipe;
5004
5005 if (pri_pipe == NULL)
5006 return false;
5007
5008 *sec_pipe = *pri_pipe;
5009
5010 sec_pipe->top_pipe = sec_top;
5011 sec_pipe->bottom_pipe = sec_bottom;
5012 sec_pipe->next_odm_pipe = sec_next;
5013 sec_pipe->prev_odm_pipe = sec_prev;
5014
5015 sec_pipe->pipe_idx = pipe_idx;
5016 sec_pipe->plane_res.mi = pool->mis[pipe_idx];
5017 sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
5018 sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
5019 sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
5020 sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
5021 sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
5022 sec_pipe->stream_res.dsc = NULL;
5023 if (odm) {
5024 if (!sec_pipe->top_pipe)
5025 sec_pipe->stream_res.opp = pool->opps[pipe_idx];
5026 else
5027 sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
5028 if (sec_pipe->stream->timing.flags.DSC == 1) {
5029 #if defined(CONFIG_DRM_AMD_DC_FP)
5030 dcn20_acquire_dsc(dc, &state->res_ctx, &sec_pipe->stream_res.dsc, pipe_idx);
5031 #endif
5032 ASSERT(sec_pipe->stream_res.dsc);
5033 if (sec_pipe->stream_res.dsc == NULL)
5034 return false;
5035 }
5036 #if defined(CONFIG_DRM_AMD_DC_FP)
5037 dcn20_build_mapped_resource(dc, state, sec_pipe->stream);
5038 #endif
5039 }
5040
5041 return true;
5042 }
5043
update_dp_encoder_resources_for_test_harness(const struct dc * dc,struct dc_state * context,struct pipe_ctx * pipe_ctx)5044 enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
5045 struct dc_state *context,
5046 struct pipe_ctx *pipe_ctx)
5047 {
5048 if (dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
5049 if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) {
5050 pipe_ctx->stream_res.hpo_dp_stream_enc =
5051 find_first_free_match_hpo_dp_stream_enc_for_link(
5052 &context->res_ctx, dc->res_pool, pipe_ctx->stream);
5053
5054 if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
5055 return DC_NO_STREAM_ENC_RESOURCE;
5056
5057 update_hpo_dp_stream_engine_usage(
5058 &context->res_ctx, dc->res_pool,
5059 pipe_ctx->stream_res.hpo_dp_stream_enc,
5060 true);
5061 }
5062
5063 if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) {
5064 if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream))
5065 return DC_NO_LINK_ENC_RESOURCE;
5066 }
5067 } else {
5068 if (pipe_ctx->stream_res.hpo_dp_stream_enc) {
5069 update_hpo_dp_stream_engine_usage(
5070 &context->res_ctx, dc->res_pool,
5071 pipe_ctx->stream_res.hpo_dp_stream_enc,
5072 false);
5073 pipe_ctx->stream_res.hpo_dp_stream_enc = NULL;
5074 }
5075 if (pipe_ctx->link_res.hpo_dp_link_enc)
5076 remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream);
5077 }
5078
5079 return DC_OK;
5080 }
5081
check_subvp_sw_cursor_fallback_req(const struct dc * dc,struct dc_stream_state * stream)5082 bool check_subvp_sw_cursor_fallback_req(const struct dc *dc, struct dc_stream_state *stream)
5083 {
5084 if (!dc->debug.disable_subvp_high_refresh && is_subvp_high_refresh_candidate(stream))
5085 return true;
5086 if (dc->current_state->stream_count == 1 && stream->timing.v_addressable >= 2880 &&
5087 ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120)
5088 return true;
5089 else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 1080 &&
5090 ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120)
5091 return true;
5092
5093 return false;
5094 }
5095
resource_init_common_dml2_callbacks(struct dc * dc,struct dml2_configuration_options * dml2_options)5096 void resource_init_common_dml2_callbacks(struct dc *dc, struct dml2_configuration_options *dml2_options)
5097 {
5098 dml2_options->callbacks.dc = dc;
5099 dml2_options->callbacks.build_scaling_params = &resource_build_scaling_params;
5100 dml2_options->callbacks.build_test_pattern_params = &resource_build_test_pattern_params;
5101 dml2_options->callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy;
5102 dml2_options->callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count;
5103 dml2_options->callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count;
5104 dml2_options->callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index;
5105 dml2_options->callbacks.get_mpc_slice_count = &resource_get_mpc_slice_count;
5106 dml2_options->callbacks.get_odm_slice_index = &resource_get_odm_slice_index;
5107 dml2_options->callbacks.get_odm_slice_count = &resource_get_odm_slice_count;
5108 dml2_options->callbacks.get_opp_head = &resource_get_opp_head;
5109 dml2_options->callbacks.get_otg_master_for_stream = &resource_get_otg_master_for_stream;
5110 dml2_options->callbacks.get_opp_heads_for_otg_master = &resource_get_opp_heads_for_otg_master;
5111 dml2_options->callbacks.get_dpp_pipes_for_plane = &resource_get_dpp_pipes_for_plane;
5112 dml2_options->callbacks.get_stream_status = &dc_state_get_stream_status;
5113 dml2_options->callbacks.get_stream_from_id = &dc_state_get_stream_from_id;
5114
5115 dml2_options->svp_pstate.callbacks.dc = dc;
5116 dml2_options->svp_pstate.callbacks.add_phantom_plane = &dc_state_add_phantom_plane;
5117 dml2_options->svp_pstate.callbacks.add_phantom_stream = &dc_state_add_phantom_stream;
5118 dml2_options->svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params;
5119 dml2_options->svp_pstate.callbacks.create_phantom_plane = &dc_state_create_phantom_plane;
5120 dml2_options->svp_pstate.callbacks.remove_phantom_plane = &dc_state_remove_phantom_plane;
5121 dml2_options->svp_pstate.callbacks.remove_phantom_stream = &dc_state_remove_phantom_stream;
5122 dml2_options->svp_pstate.callbacks.create_phantom_stream = &dc_state_create_phantom_stream;
5123 dml2_options->svp_pstate.callbacks.release_phantom_plane = &dc_state_release_phantom_plane;
5124 dml2_options->svp_pstate.callbacks.release_phantom_stream = &dc_state_release_phantom_stream;
5125 dml2_options->svp_pstate.callbacks.get_pipe_subvp_type = &dc_state_get_pipe_subvp_type;
5126 dml2_options->svp_pstate.callbacks.get_stream_subvp_type = &dc_state_get_stream_subvp_type;
5127 dml2_options->svp_pstate.callbacks.get_paired_subvp_stream = &dc_state_get_paired_subvp_stream;
5128 dml2_options->svp_pstate.callbacks.remove_phantom_streams_and_planes = &dc_state_remove_phantom_streams_and_planes;
5129 dml2_options->svp_pstate.callbacks.release_phantom_streams_and_planes = &dc_state_release_phantom_streams_and_planes;
5130 }
5131