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