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