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