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