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