]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drm/amd/display: Check for Zero Range in FreeSync Calc
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / core / dc_resource.c
CommitLineData
4562236b
HW
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"
5ac3d3c9 34#include "core_types.h"
4562236b 35#include "set_mode_types.h"
4562236b
HW
36#include "virtual/virtual_stream_encoder.h"
37
38#include "dce80/dce80_resource.h"
39#include "dce100/dce100_resource.h"
40#include "dce110/dce110_resource.h"
41#include "dce112/dce112_resource.h"
2c8ad2d5 42#include "dce120/dce120_resource.h"
4562236b
HW
43
44enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
45{
46 enum dce_version dc_version = DCE_VERSION_UNKNOWN;
47 switch (asic_id.chip_family) {
48
49 case FAMILY_CI:
50 case FAMILY_KV:
51 dc_version = DCE_VERSION_8_0;
52 break;
53 case FAMILY_CZ:
54 dc_version = DCE_VERSION_11_0;
55 break;
56
57 case FAMILY_VI:
58 if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
59 ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
60 dc_version = DCE_VERSION_10_0;
61 break;
62 }
63 if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
b264d345
JL
64 ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
65 ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
4562236b
HW
66 dc_version = DCE_VERSION_11_2;
67 }
68 break;
2c8ad2d5
AD
69 case FAMILY_AI:
70 dc_version = DCE_VERSION_12_0;
71 break;
4562236b
HW
72 default:
73 dc_version = DCE_VERSION_UNKNOWN;
74 break;
75 }
76 return dc_version;
77}
78
79struct resource_pool *dc_create_resource_pool(
80 struct core_dc *dc,
81 int num_virtual_links,
82 enum dce_version dc_version,
83 struct hw_asic_id asic_id)
84{
5ac3d3c9 85 struct resource_pool *res_pool = NULL;
4562236b
HW
86
87 switch (dc_version) {
88 case DCE_VERSION_8_0:
5ac3d3c9 89 res_pool = dce80_create_resource_pool(
4562236b 90 num_virtual_links, dc);
5ac3d3c9 91 break;
4562236b 92 case DCE_VERSION_10_0:
5ac3d3c9 93 res_pool = dce100_create_resource_pool(
4562236b 94 num_virtual_links, dc);
5ac3d3c9 95 break;
4562236b 96 case DCE_VERSION_11_0:
5ac3d3c9 97 res_pool = dce110_create_resource_pool(
4562236b 98 num_virtual_links, dc, asic_id);
5ac3d3c9 99 break;
4562236b 100 case DCE_VERSION_11_2:
5ac3d3c9 101 res_pool = dce112_create_resource_pool(
4562236b 102 num_virtual_links, dc);
5ac3d3c9 103 break;
2c8ad2d5
AD
104 case DCE_VERSION_12_0:
105 res_pool = dce120_create_resource_pool(
106 num_virtual_links, dc);
107 break;
4562236b
HW
108 default:
109 break;
110 }
5ac3d3c9
CL
111 if (res_pool != NULL) {
112 struct firmware_info fw_info = { { 0 } };
113
114 if (dc->ctx->dc_bios->funcs->get_firmware_info(
115 dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) {
116 res_pool->ref_clock_inKhz = fw_info.pll_info.crystal_frequency;
117 } else
118 ASSERT_CRITICAL(false);
119 }
4562236b 120
5ac3d3c9 121 return res_pool;
4562236b
HW
122}
123
124void dc_destroy_resource_pool(struct core_dc *dc)
125{
126 if (dc) {
127 if (dc->res_pool)
128 dc->res_pool->funcs->destroy(&dc->res_pool);
129
130 if (dc->hwseq)
131 dm_free(dc->hwseq);
132 }
133}
134
135static void update_num_audio(
136 const struct resource_straps *straps,
137 unsigned int *num_audio,
138 struct audio_support *aud_support)
139{
140 if (straps->hdmi_disable == 0) {
141 aud_support->hdmi_audio_native = true;
142 aud_support->hdmi_audio_on_dongle = true;
143 aud_support->dp_audio = true;
144 } else {
145 if (straps->dc_pinstraps_audio & 0x2) {
146 aud_support->hdmi_audio_on_dongle = true;
147 aud_support->dp_audio = true;
148 } else {
149 aud_support->dp_audio = true;
150 }
151 }
152
153 switch (straps->audio_stream_number) {
154 case 0: /* multi streams supported */
155 break;
156 case 1: /* multi streams not supported */
157 *num_audio = 1;
158 break;
159 default:
160 DC_ERR("DC: unexpected audio fuse!\n");
17a96033 161 }
4562236b
HW
162}
163
164bool resource_construct(
165 unsigned int num_virtual_links,
166 struct core_dc *dc,
167 struct resource_pool *pool,
168 const struct resource_create_funcs *create_funcs)
169{
170 struct dc_context *ctx = dc->ctx;
171 const struct resource_caps *caps = pool->res_cap;
172 int i;
173 unsigned int num_audio = caps->num_audio;
174 struct resource_straps straps = {0};
175
176 if (create_funcs->read_dce_straps)
177 create_funcs->read_dce_straps(dc->ctx, &straps);
178
179 pool->audio_count = 0;
180 if (create_funcs->create_audio) {
181 /* find the total number of streams available via the
182 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
183 * registers (one for each pin) starting from pin 1
184 * up to the max number of audio pins.
185 * We stop on the first pin where
186 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
187 */
188 update_num_audio(&straps, &num_audio, &pool->audio_support);
189 for (i = 0; i < pool->pipe_count && i < num_audio; i++) {
190 struct audio *aud = create_funcs->create_audio(ctx, i);
191
192 if (aud == NULL) {
193 DC_ERR("DC: failed to create audio!\n");
194 return false;
195 }
196
197 if (!aud->funcs->endpoint_valid(aud)) {
198 aud->funcs->destroy(&aud);
199 break;
200 }
201
202 pool->audios[i] = aud;
203 pool->audio_count++;
204 }
205 }
206
207 pool->stream_enc_count = 0;
208 if (create_funcs->create_stream_encoder) {
209 for (i = 0; i < caps->num_stream_encoder; i++) {
210 pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
211 if (pool->stream_enc[i] == NULL)
212 DC_ERR("DC: failed to create stream_encoder!\n");
213 pool->stream_enc_count++;
214 }
215 }
216
217 for (i = 0; i < num_virtual_links; i++) {
218 pool->stream_enc[pool->stream_enc_count] =
219 virtual_stream_encoder_create(
220 ctx, ctx->dc_bios);
221 if (pool->stream_enc[pool->stream_enc_count] == NULL) {
222 DC_ERR("DC: failed to create stream_encoder!\n");
223 return false;
224 }
225 pool->stream_enc_count++;
226 }
227
228 dc->hwseq = create_funcs->create_hwseq(ctx);
229
230 return true;
231}
232
233
234void resource_unreference_clock_source(
235 struct resource_context *res_ctx,
a2b8659d 236 const struct resource_pool *pool,
8c737fcc 237 struct clock_source **clock_source)
4562236b
HW
238{
239 int i;
a2b8659d
TC
240 for (i = 0; i < pool->clk_src_count; i++) {
241 if (pool->clock_sources[i] != *clock_source)
4562236b
HW
242 continue;
243
244 res_ctx->clock_source_ref_count[i]--;
245
246 if (res_ctx->clock_source_ref_count[i] == 0)
8c737fcc 247 (*clock_source)->funcs->cs_power_down(*clock_source);
4562236b
HW
248
249 break;
250 }
251
a2b8659d 252 if (pool->dp_clock_source == *clock_source) {
4562236b
HW
253 res_ctx->dp_clock_source_ref_count--;
254
255 if (res_ctx->dp_clock_source_ref_count == 0)
8c737fcc 256 (*clock_source)->funcs->cs_power_down(*clock_source);
4562236b 257 }
8c737fcc 258 *clock_source = NULL;
4562236b
HW
259}
260
261void resource_reference_clock_source(
262 struct resource_context *res_ctx,
a2b8659d 263 const struct resource_pool *pool,
4562236b
HW
264 struct clock_source *clock_source)
265{
266 int i;
a2b8659d
TC
267 for (i = 0; i < pool->clk_src_count; i++) {
268 if (pool->clock_sources[i] != clock_source)
4562236b
HW
269 continue;
270
271 res_ctx->clock_source_ref_count[i]++;
272 break;
273 }
274
a2b8659d 275 if (pool->dp_clock_source == clock_source)
4562236b
HW
276 res_ctx->dp_clock_source_ref_count++;
277}
278
279bool resource_are_streams_timing_synchronizable(
280 const struct core_stream *stream1,
281 const struct core_stream *stream2)
282{
283 if (stream1->public.timing.h_total != stream2->public.timing.h_total)
284 return false;
285
286 if (stream1->public.timing.v_total != stream2->public.timing.v_total)
287 return false;
288
289 if (stream1->public.timing.h_addressable
290 != stream2->public.timing.h_addressable)
291 return false;
292
293 if (stream1->public.timing.v_addressable
294 != stream2->public.timing.v_addressable)
295 return false;
296
297 if (stream1->public.timing.pix_clk_khz
298 != stream2->public.timing.pix_clk_khz)
299 return false;
300
301 if (stream1->phy_pix_clk != stream2->phy_pix_clk
7e2fe319
CL
302 && (!dc_is_dp_signal(stream1->signal)
303 || !dc_is_dp_signal(stream2->signal)))
4562236b
HW
304 return false;
305
306 return true;
307}
308
309static bool is_sharable_clk_src(
310 const struct pipe_ctx *pipe_with_clk_src,
311 const struct pipe_ctx *pipe)
312{
313 if (pipe_with_clk_src->clock_source == NULL)
314 return false;
315
316 if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
317 return false;
318
319 if (dc_is_dp_signal(pipe_with_clk_src->stream->signal))
320 return false;
321
322 if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
323 && dc_is_dvi_signal(pipe->stream->signal))
324 return false;
325
326 if (dc_is_hdmi_signal(pipe->stream->signal)
327 && dc_is_dvi_signal(pipe_with_clk_src->stream->signal))
328 return false;
329
330 if (!resource_are_streams_timing_synchronizable(
331 pipe_with_clk_src->stream, pipe->stream))
332 return false;
333
334 return true;
335}
336
337struct clock_source *resource_find_used_clk_src_for_sharing(
338 struct resource_context *res_ctx,
339 struct pipe_ctx *pipe_ctx)
340{
341 int i;
342
343 for (i = 0; i < MAX_PIPES; i++) {
344 if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
345 return res_ctx->pipe_ctx[i].clock_source;
346 }
347
348 return NULL;
349}
350
351static enum pixel_format convert_pixel_format_to_dalsurface(
352 enum surface_pixel_format surface_pixel_format)
353{
354 enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
355
356 switch (surface_pixel_format) {
357 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
358 dal_pixel_format = PIXEL_FORMAT_INDEX8;
359 break;
360 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
361 dal_pixel_format = PIXEL_FORMAT_RGB565;
362 break;
363 case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
364 dal_pixel_format = PIXEL_FORMAT_RGB565;
365 break;
366 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
367 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
368 break;
8693049a 369 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
4562236b
HW
370 dal_pixel_format = PIXEL_FORMAT_ARGB8888;
371 break;
372 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
373 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
374 break;
375 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
376 dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
377 break;
378 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
379 dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
380 break;
381 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
382 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
383 dal_pixel_format = PIXEL_FORMAT_FP16;
384 break;
385 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
4562236b
HW
386 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
387 dal_pixel_format = PIXEL_FORMAT_420BPP12;
388 break;
ffbcd19a
VP
389 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
390 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
391 dal_pixel_format = PIXEL_FORMAT_420BPP15;
392 break;
4562236b
HW
393 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
394 default:
395 dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
396 break;
397 }
398 return dal_pixel_format;
399}
400
401static void rect_swap_helper(struct rect *rect)
402{
403 uint32_t temp = 0;
404
405 temp = rect->height;
406 rect->height = rect->width;
407 rect->width = temp;
408
409 temp = rect->x;
410 rect->x = rect->y;
411 rect->y = temp;
412}
413
b2d0a103 414static void calculate_viewport(struct pipe_ctx *pipe_ctx)
4562236b 415{
b2d0a103 416 const struct dc_surface *surface = &pipe_ctx->surface->public;
1fbd2cfc 417 const struct dc_stream *stream = &pipe_ctx->stream->public;
b2d0a103 418 struct scaler_data *data = &pipe_ctx->scl_data;
1fbd2cfc 419 struct rect clip = { 0 };
b2d0a103
DL
420 int vpc_div = (data->format == PIXEL_FORMAT_420BPP12
421 || data->format == PIXEL_FORMAT_420BPP15) ? 2 : 1;
1fbd2cfc
DL
422 bool pri_split = pipe_ctx->bottom_pipe &&
423 pipe_ctx->bottom_pipe->surface == pipe_ctx->surface;
424 bool sec_split = pipe_ctx->top_pipe &&
425 pipe_ctx->top_pipe->surface == pipe_ctx->surface;
4562236b 426
7b779c99
VP
427 if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
428 stream->timing.timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) {
429 pri_split = false;
430 sec_split = false;
431 }
4562236b
HW
432 /* The actual clip is an intersection between stream
433 * source and surface clip
434 */
1fbd2cfc
DL
435 clip.x = stream->src.x > surface->clip_rect.x ?
436 stream->src.x : surface->clip_rect.x;
4562236b 437
1fbd2cfc
DL
438 clip.width = stream->src.x + stream->src.width <
439 surface->clip_rect.x + surface->clip_rect.width ?
440 stream->src.x + stream->src.width - clip.x :
441 surface->clip_rect.x + surface->clip_rect.width - clip.x ;
4562236b 442
1fbd2cfc
DL
443 clip.y = stream->src.y > surface->clip_rect.y ?
444 stream->src.y : surface->clip_rect.y;
4562236b 445
1fbd2cfc
DL
446 clip.height = stream->src.y + stream->src.height <
447 surface->clip_rect.y + surface->clip_rect.height ?
448 stream->src.y + stream->src.height - clip.y :
449 surface->clip_rect.y + surface->clip_rect.height - clip.y ;
4562236b 450
1fbd2cfc 451 /* offset = src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio
4562236b
HW
452 * num_pixels = clip.num_pix * scl_ratio
453 */
1fbd2cfc
DL
454 data->viewport.x = surface->src_rect.x + (clip.x - surface->dst_rect.x) *
455 surface->src_rect.width / surface->dst_rect.width;
b2d0a103 456 data->viewport.width = clip.width *
1fbd2cfc 457 surface->src_rect.width / surface->dst_rect.width;
4562236b 458
1fbd2cfc
DL
459 data->viewport.y = surface->src_rect.y + (clip.y - surface->dst_rect.y) *
460 surface->src_rect.height / surface->dst_rect.height;
b2d0a103 461 data->viewport.height = clip.height *
1fbd2cfc 462 surface->src_rect.height / surface->dst_rect.height;
4562236b 463
b2d0a103
DL
464 /* Round down, compensate in init */
465 data->viewport_c.x = data->viewport.x / vpc_div;
466 data->viewport_c.y = data->viewport.y / vpc_div;
467 data->inits.h_c = (data->viewport.x % vpc_div) != 0 ?
468 dal_fixed31_32_half : dal_fixed31_32_zero;
469 data->inits.v_c = (data->viewport.y % vpc_div) != 0 ?
470 dal_fixed31_32_half : dal_fixed31_32_zero;
471 /* Round up, assume original video size always even dimensions */
472 data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div;
473 data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div;
474
475 /* Handle hsplit */
1fbd2cfc
DL
476 if (pri_split || sec_split) {
477 /* HMirror XOR Secondary_pipe XOR Rotation_180 */
478 bool right_view = (sec_split != surface->horizontal_mirror) !=
479 (surface->rotation == ROTATION_ANGLE_180);
480
481 if (surface->rotation == ROTATION_ANGLE_90
482 || surface->rotation == ROTATION_ANGLE_270)
483 /* Secondary_pipe XOR Rotation_270 */
484 right_view = (surface->rotation == ROTATION_ANGLE_270) != sec_split;
9e6c74ce
DL
485
486 if (right_view) {
487 data->viewport.width /= 2;
488 data->viewport_c.width /= 2;
489 data->viewport.x += data->viewport.width;
490 data->viewport_c.x += data->viewport_c.width;
491 /* Ceil offset pipe */
492 data->viewport.width += data->viewport.width % 2;
493 data->viewport_c.width += data->viewport_c.width % 2;
494 } else {
495 data->viewport.width /= 2;
496 data->viewport_c.width /= 2;
497 }
b2d0a103 498 }
1fbd2cfc
DL
499
500 if (surface->rotation == ROTATION_ANGLE_90 ||
501 surface->rotation == ROTATION_ANGLE_270) {
502 rect_swap_helper(&data->viewport_c);
503 rect_swap_helper(&data->viewport);
504 }
4562236b
HW
505}
506
b2d0a103 507static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip)
4562236b 508{
b2d0a103 509 const struct dc_surface *surface = &pipe_ctx->surface->public;
4562236b
HW
510 struct core_stream *stream = pipe_ctx->stream;
511 struct rect clip = surface->clip_rect;
c802570e 512 int recout_full_x, recout_full_y;
4562236b
HW
513
514 pipe_ctx->scl_data.recout.x = stream->public.dst.x;
515 if (stream->public.src.x < clip.x)
516 pipe_ctx->scl_data.recout.x += (clip.x
517 - stream->public.src.x) * stream->public.dst.width
518 / stream->public.src.width;
519
520 pipe_ctx->scl_data.recout.width = clip.width *
521 stream->public.dst.width / stream->public.src.width;
522 if (pipe_ctx->scl_data.recout.width + pipe_ctx->scl_data.recout.x >
523 stream->public.dst.x + stream->public.dst.width)
524 pipe_ctx->scl_data.recout.width =
525 stream->public.dst.x + stream->public.dst.width
526 - pipe_ctx->scl_data.recout.x;
527
528 pipe_ctx->scl_data.recout.y = stream->public.dst.y;
529 if (stream->public.src.y < clip.y)
530 pipe_ctx->scl_data.recout.y += (clip.y
531 - stream->public.src.y) * stream->public.dst.height
532 / stream->public.src.height;
533
534 pipe_ctx->scl_data.recout.height = clip.height *
535 stream->public.dst.height / stream->public.src.height;
536 if (pipe_ctx->scl_data.recout.height + pipe_ctx->scl_data.recout.y >
537 stream->public.dst.y + stream->public.dst.height)
538 pipe_ctx->scl_data.recout.height =
539 stream->public.dst.y + stream->public.dst.height
540 - pipe_ctx->scl_data.recout.y;
b2d0a103 541
7b779c99
VP
542 /* Handle h & vsplit */
543 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->surface ==
544 pipe_ctx->surface) {
545 if (stream->public.timing.timing_3d_format ==
546 TIMING_3D_FORMAT_TOP_AND_BOTTOM) {
547 pipe_ctx->scl_data.recout.height /= 2;
548 pipe_ctx->scl_data.recout.y += pipe_ctx->scl_data.recout.height;
549 /* Floor primary pipe, ceil 2ndary pipe */
550 pipe_ctx->scl_data.recout.height += pipe_ctx->scl_data.recout.height % 2;
551 } else {
552 pipe_ctx->scl_data.recout.width /= 2;
553 pipe_ctx->scl_data.recout.x += pipe_ctx->scl_data.recout.width;
554 pipe_ctx->scl_data.recout.width += pipe_ctx->scl_data.recout.width % 2;
555 }
556 } else if (pipe_ctx->bottom_pipe &&
557 pipe_ctx->bottom_pipe->surface == pipe_ctx->surface) {
558 if (stream->public.timing.timing_3d_format ==
559 TIMING_3D_FORMAT_TOP_AND_BOTTOM)
560 pipe_ctx->scl_data.recout.height /= 2;
561 else
562 pipe_ctx->scl_data.recout.width /= 2;
b2d0a103
DL
563 }
564
c802570e
DL
565 /* Unclipped recout offset = stream dst offset + ((surf dst offset - stream src offset)
566 * * 1/ stream scaling ratio) - (surf src offset * 1/ full scl
567 * ratio)
568 */
569 recout_full_x = stream->public.dst.x + (surface->dst_rect.x - stream->public.src.x)
570 * stream->public.dst.width / stream->public.src.width -
571 surface->src_rect.x * surface->dst_rect.width / surface->src_rect.width
572 * stream->public.dst.width / stream->public.src.width;
573 recout_full_y = stream->public.dst.y + (surface->dst_rect.y - stream->public.src.y)
574 * stream->public.dst.height / stream->public.src.height -
575 surface->src_rect.y * surface->dst_rect.height / surface->src_rect.height
576 * stream->public.dst.height / stream->public.src.height;
577
578 recout_skip->width = pipe_ctx->scl_data.recout.x - recout_full_x;
579 recout_skip->height = pipe_ctx->scl_data.recout.y - recout_full_y;
4562236b
HW
580}
581
b2d0a103 582static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
4562236b 583{
b2d0a103 584 const struct dc_surface *surface = &pipe_ctx->surface->public;
4562236b 585 struct core_stream *stream = pipe_ctx->stream;
1fbd2cfc
DL
586 const int in_w = stream->public.src.width;
587 const int in_h = stream->public.src.height;
588 const int out_w = stream->public.dst.width;
589 const int out_h = stream->public.dst.height;
4562236b
HW
590
591 pipe_ctx->scl_data.ratios.horz = dal_fixed31_32_from_fraction(
592 surface->src_rect.width,
593 surface->dst_rect.width);
594 pipe_ctx->scl_data.ratios.vert = dal_fixed31_32_from_fraction(
595 surface->src_rect.height,
596 surface->dst_rect.height);
597
598 if (surface->stereo_format == PLANE_STEREO_FORMAT_SIDE_BY_SIDE)
599 pipe_ctx->scl_data.ratios.horz.value *= 2;
600 else if (surface->stereo_format == PLANE_STEREO_FORMAT_TOP_AND_BOTTOM)
601 pipe_ctx->scl_data.ratios.vert.value *= 2;
602
603 pipe_ctx->scl_data.ratios.vert.value = div64_s64(
604 pipe_ctx->scl_data.ratios.vert.value * in_h, out_h);
605 pipe_ctx->scl_data.ratios.horz.value = div64_s64(
606 pipe_ctx->scl_data.ratios.horz.value * in_w, out_w);
607
608 pipe_ctx->scl_data.ratios.horz_c = pipe_ctx->scl_data.ratios.horz;
609 pipe_ctx->scl_data.ratios.vert_c = pipe_ctx->scl_data.ratios.vert;
610
b2d0a103
DL
611 if (pipe_ctx->scl_data.format == PIXEL_FORMAT_420BPP12
612 || pipe_ctx->scl_data.format == PIXEL_FORMAT_420BPP15) {
4562236b
HW
613 pipe_ctx->scl_data.ratios.horz_c.value /= 2;
614 pipe_ctx->scl_data.ratios.vert_c.value /= 2;
615 }
616}
617
b2d0a103
DL
618static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *recout_skip)
619{
620 struct scaler_data *data = &pipe_ctx->scl_data;
621 struct rect src = pipe_ctx->surface->public.src_rect;
622 int vpc_div = (data->format == PIXEL_FORMAT_420BPP12
623 || data->format == PIXEL_FORMAT_420BPP15) ? 2 : 1;
624
1fbd2cfc
DL
625 if (pipe_ctx->surface->public.rotation == ROTATION_ANGLE_90 ||
626 pipe_ctx->surface->public.rotation == ROTATION_ANGLE_270) {
627 rect_swap_helper(&data->viewport_c);
628 rect_swap_helper(&data->viewport);
629 }
630
b2d0a103
DL
631 /*
632 * Init calculated according to formula:
633 * init = (scaling_ratio + number_of_taps + 1) / 2
634 * init_bot = init + scaling_ratio
635 * init_c = init + truncated_vp_c_offset(from calculate viewport)
636 */
637 data->inits.h = dal_fixed31_32_div_int(
638 dal_fixed31_32_add_int(data->ratios.horz, data->taps.h_taps + 1), 2);
639
640 data->inits.h_c = dal_fixed31_32_add(data->inits.h_c, dal_fixed31_32_div_int(
641 dal_fixed31_32_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2));
642
643 data->inits.v = dal_fixed31_32_div_int(
644 dal_fixed31_32_add_int(data->ratios.vert, data->taps.v_taps + 1), 2);
645
646 data->inits.v_c = dal_fixed31_32_add(data->inits.v_c, dal_fixed31_32_div_int(
647 dal_fixed31_32_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2));
648
649
650 /* Adjust for viewport end clip-off */
651 if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) {
652 int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x;
1fbd2cfc
DL
653 int int_part = dal_fixed31_32_floor(
654 dal_fixed31_32_sub(data->inits.h, data->ratios.horz));
b2d0a103 655
1fbd2cfc 656 int_part = int_part > 0 ? int_part : 0;
b2d0a103
DL
657 data->viewport.width += int_part < vp_clip ? int_part : vp_clip;
658 }
659 if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) {
660 int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y;
1fbd2cfc
DL
661 int int_part = dal_fixed31_32_floor(
662 dal_fixed31_32_sub(data->inits.v, data->ratios.vert));
b2d0a103 663
1fbd2cfc 664 int_part = int_part > 0 ? int_part : 0;
b2d0a103
DL
665 data->viewport.height += int_part < vp_clip ? int_part : vp_clip;
666 }
667 if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) {
668 int vp_clip = (src.x + src.width) / vpc_div -
669 data->viewport_c.width - data->viewport_c.x;
1fbd2cfc
DL
670 int int_part = dal_fixed31_32_floor(
671 dal_fixed31_32_sub(data->inits.h_c, data->ratios.horz_c));
b2d0a103 672
1fbd2cfc 673 int_part = int_part > 0 ? int_part : 0;
b2d0a103
DL
674 data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip;
675 }
676 if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) {
677 int vp_clip = (src.y + src.height) / vpc_div -
678 data->viewport_c.height - data->viewport_c.y;
1fbd2cfc
DL
679 int int_part = dal_fixed31_32_floor(
680 dal_fixed31_32_sub(data->inits.v_c, data->ratios.vert_c));
b2d0a103 681
1fbd2cfc 682 int_part = int_part > 0 ? int_part : 0;
b2d0a103
DL
683 data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip;
684 }
685
686 /* Adjust for non-0 viewport offset */
687 if (data->viewport.x) {
688 int int_part;
689
690 data->inits.h = dal_fixed31_32_add(data->inits.h, dal_fixed31_32_mul_int(
691 data->ratios.horz, recout_skip->width));
692 int_part = dal_fixed31_32_floor(data->inits.h) - data->viewport.x;
693 if (int_part < data->taps.h_taps) {
694 int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ?
695 (data->taps.h_taps - int_part) : data->viewport.x;
696 data->viewport.x -= int_adj;
697 data->viewport.width += int_adj;
698 int_part += int_adj;
699 } else if (int_part > data->taps.h_taps) {
700 data->viewport.x += int_part - data->taps.h_taps;
701 data->viewport.width -= int_part - data->taps.h_taps;
702 int_part = data->taps.h_taps;
703 }
704 data->inits.h.value &= 0xffffffff;
705 data->inits.h = dal_fixed31_32_add_int(data->inits.h, int_part);
706 }
707
708 if (data->viewport_c.x) {
709 int int_part;
710
711 data->inits.h_c = dal_fixed31_32_add(data->inits.h_c, dal_fixed31_32_mul_int(
712 data->ratios.horz_c, recout_skip->width));
713 int_part = dal_fixed31_32_floor(data->inits.h_c) - data->viewport_c.x;
714 if (int_part < data->taps.h_taps_c) {
715 int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ?
716 (data->taps.h_taps_c - int_part) : data->viewport_c.x;
717 data->viewport_c.x -= int_adj;
718 data->viewport_c.width += int_adj;
719 int_part += int_adj;
720 } else if (int_part > data->taps.h_taps_c) {
721 data->viewport_c.x += int_part - data->taps.h_taps_c;
722 data->viewport_c.width -= int_part - data->taps.h_taps_c;
723 int_part = data->taps.h_taps_c;
724 }
725 data->inits.h_c.value &= 0xffffffff;
726 data->inits.h_c = dal_fixed31_32_add_int(data->inits.h_c, int_part);
727 }
728
729 if (data->viewport.y) {
730 int int_part;
731
732 data->inits.v = dal_fixed31_32_add(data->inits.v, dal_fixed31_32_mul_int(
733 data->ratios.vert, recout_skip->height));
734 int_part = dal_fixed31_32_floor(data->inits.v) - data->viewport.y;
735 if (int_part < data->taps.v_taps) {
736 int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ?
737 (data->taps.v_taps - int_part) : data->viewport.y;
738 data->viewport.y -= int_adj;
739 data->viewport.height += int_adj;
740 int_part += int_adj;
741 } else if (int_part > data->taps.v_taps) {
742 data->viewport.y += int_part - data->taps.v_taps;
743 data->viewport.height -= int_part - data->taps.v_taps;
744 int_part = data->taps.v_taps;
745 }
746 data->inits.v.value &= 0xffffffff;
747 data->inits.v = dal_fixed31_32_add_int(data->inits.v, int_part);
748 }
749
750 if (data->viewport_c.y) {
751 int int_part;
752
753 data->inits.v_c = dal_fixed31_32_add(data->inits.v_c, dal_fixed31_32_mul_int(
754 data->ratios.vert_c, recout_skip->height));
755 int_part = dal_fixed31_32_floor(data->inits.v_c) - data->viewport_c.y;
756 if (int_part < data->taps.v_taps_c) {
757 int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ?
758 (data->taps.v_taps_c - int_part) : data->viewport_c.y;
759 data->viewport_c.y -= int_adj;
760 data->viewport_c.height += int_adj;
761 int_part += int_adj;
762 } else if (int_part > data->taps.v_taps_c) {
763 data->viewport_c.y += int_part - data->taps.v_taps_c;
764 data->viewport_c.height -= int_part - data->taps.v_taps_c;
765 int_part = data->taps.v_taps_c;
766 }
767 data->inits.v_c.value &= 0xffffffff;
768 data->inits.v_c = dal_fixed31_32_add_int(data->inits.v_c, int_part);
769 }
770
771 /* Interlaced inits based on final vert inits */
772 data->inits.v_bot = dal_fixed31_32_add(data->inits.v, data->ratios.vert);
773 data->inits.v_c_bot = dal_fixed31_32_add(data->inits.v_c, data->ratios.vert_c);
1fbd2cfc
DL
774
775 if (pipe_ctx->surface->public.rotation == ROTATION_ANGLE_90 ||
776 pipe_ctx->surface->public.rotation == ROTATION_ANGLE_270) {
777 rect_swap_helper(&data->viewport_c);
778 rect_swap_helper(&data->viewport);
779 }
b2d0a103
DL
780}
781
782bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
4562236b 783{
b2d0a103 784 const struct dc_surface *surface = &pipe_ctx->surface->public;
4562236b 785 struct dc_crtc_timing *timing = &pipe_ctx->stream->public.timing;
b2d0a103
DL
786 struct view recout_skip = { 0 };
787 bool res = false;
788
4562236b
HW
789 /* Important: scaling ratio calculation requires pixel format,
790 * lb depth calculation requires recout and taps require scaling ratios.
b2d0a103 791 * Inits require viewport, taps, ratios and recout of split pipe
4562236b 792 */
b2d0a103
DL
793 pipe_ctx->scl_data.format = convert_pixel_format_to_dalsurface(
794 pipe_ctx->surface->public.format);
795
796 calculate_scaling_ratios(pipe_ctx);
4562236b 797
b2d0a103 798 calculate_viewport(pipe_ctx);
4562236b
HW
799
800 if (pipe_ctx->scl_data.viewport.height < 16 || pipe_ctx->scl_data.viewport.width < 16)
801 return false;
802
b2d0a103 803 calculate_recout(pipe_ctx, &recout_skip);
4562236b
HW
804
805 /**
806 * Setting line buffer pixel depth to 24bpp yields banding
807 * on certain displays, such as the Sharp 4k
808 */
809 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
810
811 pipe_ctx->scl_data.h_active = timing->h_addressable;
812 pipe_ctx->scl_data.v_active = timing->v_addressable;
813
814 /* Taps calculations */
815 res = pipe_ctx->xfm->funcs->transform_get_optimal_number_of_taps(
816 pipe_ctx->xfm, &pipe_ctx->scl_data, &surface->scaling_quality);
817
818 if (!res) {
819 /* Try 24 bpp linebuffer */
820 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;
821
822 res = pipe_ctx->xfm->funcs->transform_get_optimal_number_of_taps(
823 pipe_ctx->xfm, &pipe_ctx->scl_data, &surface->scaling_quality);
824 }
825
b2d0a103 826 if (res)
1fbd2cfc 827 /* May need to re-check lb size after this in some obscure scenario */
b2d0a103
DL
828 calculate_inits_and_adj_vp(pipe_ctx, &recout_skip);
829
4562236b
HW
830 dm_logger_write(pipe_ctx->stream->ctx->logger, LOG_SCALER,
831 "%s: Viewport:\nheight:%d width:%d x:%d "
832 "y:%d\n dst_rect:\nheight:%d width:%d x:%d "
833 "y:%d\n",
834 __func__,
835 pipe_ctx->scl_data.viewport.height,
836 pipe_ctx->scl_data.viewport.width,
837 pipe_ctx->scl_data.viewport.x,
838 pipe_ctx->scl_data.viewport.y,
839 surface->dst_rect.height,
840 surface->dst_rect.width,
841 surface->dst_rect.x,
842 surface->dst_rect.y);
843
844 return res;
845}
846
847
848enum dc_status resource_build_scaling_params_for_context(
849 const struct core_dc *dc,
850 struct validate_context *context)
851{
852 int i;
853
854 for (i = 0; i < MAX_PIPES; i++) {
855 if (context->res_ctx.pipe_ctx[i].surface != NULL &&
856 context->res_ctx.pipe_ctx[i].stream != NULL)
b2d0a103 857 if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
f84a8161 858 return DC_FAIL_SCALING;
4562236b
HW
859 }
860
861 return DC_OK;
862}
863
ab2541b6 864static void detach_surfaces_for_stream(
4562236b 865 struct validate_context *context,
a2b8659d 866 const struct resource_pool *pool,
ab2541b6 867 const struct dc_stream *dc_stream)
4562236b
HW
868{
869 int i;
ab2541b6 870 struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
4562236b 871
a2b8659d 872 for (i = 0; i < pool->pipe_count; i++) {
4562236b
HW
873 struct pipe_ctx *cur_pipe = &context->res_ctx.pipe_ctx[i];
874 if (cur_pipe->stream == stream) {
875 cur_pipe->surface = NULL;
876 cur_pipe->top_pipe = NULL;
877 cur_pipe->bottom_pipe = NULL;
878 }
879 }
880}
881
a2b8659d
TC
882struct pipe_ctx *find_idle_secondary_pipe(
883 struct resource_context *res_ctx,
884 const struct resource_pool *pool)
4562236b
HW
885{
886 int i;
887 struct pipe_ctx *secondary_pipe = NULL;
888
889 /*
890 * search backwards for the second pipe to keep pipe
891 * assignment more consistent
892 */
893
a2b8659d 894 for (i = pool->pipe_count - 1; i >= 0; i--) {
4562236b
HW
895 if (res_ctx->pipe_ctx[i].stream == NULL) {
896 secondary_pipe = &res_ctx->pipe_ctx[i];
897 secondary_pipe->pipe_idx = i;
898 break;
899 }
900 }
901
902
903 return secondary_pipe;
904}
905
906struct pipe_ctx *resource_get_head_pipe_for_stream(
907 struct resource_context *res_ctx,
908 const struct core_stream *stream)
909{
910 int i;
a2b8659d 911 for (i = 0; i < MAX_PIPES; i++) {
4562236b 912 if (res_ctx->pipe_ctx[i].stream == stream &&
e73c1efc 913 res_ctx->pipe_ctx[i].stream_enc) {
4562236b
HW
914 return &res_ctx->pipe_ctx[i];
915 break;
916 }
917 }
918 return NULL;
919}
920
921/*
ab2541b6
AC
922 * A free_pipe for a stream is defined here as a pipe
923 * that has no surface attached yet
4562236b 924 */
ab2541b6 925static struct pipe_ctx *acquire_free_pipe_for_stream(
745cc746 926 struct validate_context *context,
a2b8659d 927 const struct resource_pool *pool,
ab2541b6 928 const struct dc_stream *dc_stream)
4562236b
HW
929{
930 int i;
745cc746 931 struct resource_context *res_ctx = &context->res_ctx;
ab2541b6 932 struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
4562236b
HW
933
934 struct pipe_ctx *head_pipe = NULL;
935
936 /* Find head pipe, which has the back end set up*/
937
938 head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
939
940 if (!head_pipe)
941 ASSERT(0);
942
943 if (!head_pipe->surface)
944 return head_pipe;
945
946 /* Re-use pipe already acquired for this stream if available*/
a2b8659d 947 for (i = pool->pipe_count - 1; i >= 0; i--) {
4562236b
HW
948 if (res_ctx->pipe_ctx[i].stream == stream &&
949 !res_ctx->pipe_ctx[i].surface) {
950 return &res_ctx->pipe_ctx[i];
951 }
952 }
953
954 /*
955 * At this point we have no re-useable pipe for this stream and we need
956 * to acquire an idle one to satisfy the request
957 */
958
a2b8659d 959 if (!pool->funcs->acquire_idle_pipe_for_layer)
4562236b
HW
960 return NULL;
961
a2b8659d 962 return pool->funcs->acquire_idle_pipe_for_layer(context, pool, stream);
4562236b
HW
963
964}
965
ab2541b6 966static void release_free_pipes_for_stream(
4562236b 967 struct resource_context *res_ctx,
ab2541b6 968 const struct dc_stream *dc_stream)
4562236b
HW
969{
970 int i;
ab2541b6 971 struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
4562236b 972
a2b8659d 973 for (i = MAX_PIPES - 1; i >= 0; i--) {
4562236b
HW
974 if (res_ctx->pipe_ctx[i].stream == stream &&
975 !res_ctx->pipe_ctx[i].surface) {
976 res_ctx->pipe_ctx[i].stream = NULL;
977 }
978 }
979}
980
981bool resource_attach_surfaces_to_context(
982 const struct dc_surface * const *surfaces,
983 int surface_count,
ab2541b6 984 const struct dc_stream *dc_stream,
a2b8659d
TC
985 struct validate_context *context,
986 const struct resource_pool *pool)
4562236b
HW
987{
988 int i;
989 struct pipe_ctx *tail_pipe;
ab2541b6 990 struct dc_stream_status *stream_status = NULL;
4562236b
HW
991
992
993 if (surface_count > MAX_SURFACE_NUM) {
994 dm_error("Surface: can not attach %d surfaces! Maximum is: %d\n",
995 surface_count, MAX_SURFACE_NUM);
996 return false;
997 }
998
ab2541b6
AC
999 for (i = 0; i < context->stream_count; i++)
1000 if (&context->streams[i]->public == dc_stream) {
1001 stream_status = &context->stream_status[i];
4562236b
HW
1002 break;
1003 }
ab2541b6
AC
1004 if (stream_status == NULL) {
1005 dm_error("Existing stream not found; failed to attach surfaces\n");
4562236b
HW
1006 return false;
1007 }
1008
1009 /* retain new surfaces */
1010 for (i = 0; i < surface_count; i++)
1011 dc_surface_retain(surfaces[i]);
1012
a2b8659d 1013 detach_surfaces_for_stream(context, pool, dc_stream);
4562236b
HW
1014
1015 /* release existing surfaces*/
ab2541b6
AC
1016 for (i = 0; i < stream_status->surface_count; i++)
1017 dc_surface_release(stream_status->surfaces[i]);
4562236b 1018
ab2541b6
AC
1019 for (i = surface_count; i < stream_status->surface_count; i++)
1020 stream_status->surfaces[i] = NULL;
4562236b 1021
ab2541b6 1022 stream_status->surface_count = 0;
4562236b
HW
1023
1024 if (surface_count == 0)
1025 return true;
1026
1027 tail_pipe = NULL;
1028 for (i = 0; i < surface_count; i++) {
1029 struct core_surface *surface = DC_SURFACE_TO_CORE(surfaces[i]);
a2b8659d
TC
1030 struct pipe_ctx *free_pipe = acquire_free_pipe_for_stream(
1031 context, pool, dc_stream);
4562236b
HW
1032
1033 if (!free_pipe) {
ab2541b6 1034 stream_status->surfaces[i] = NULL;
4562236b
HW
1035 return false;
1036 }
1037
1038 free_pipe->surface = surface;
1039
1040 if (tail_pipe) {
1041 free_pipe->top_pipe = tail_pipe;
1042 tail_pipe->bottom_pipe = free_pipe;
1043 }
1044
1045 tail_pipe = free_pipe;
1046 }
1047
ab2541b6 1048 release_free_pipes_for_stream(&context->res_ctx, dc_stream);
4562236b
HW
1049
1050 /* assign new surfaces*/
1051 for (i = 0; i < surface_count; i++)
ab2541b6 1052 stream_status->surfaces[i] = surfaces[i];
4562236b 1053
ab2541b6 1054 stream_status->surface_count = surface_count;
4562236b
HW
1055
1056 return true;
1057}
1058
1059
1060static bool is_timing_changed(const struct core_stream *cur_stream,
1061 const struct core_stream *new_stream)
1062{
1063 if (cur_stream == NULL)
1064 return true;
1065
1066 /* If sink pointer changed, it means this is a hotplug, we should do
1067 * full hw setting.
1068 */
1069 if (cur_stream->sink != new_stream->sink)
1070 return true;
1071
1072 /* If output color space is changed, need to reprogram info frames */
1073 if (cur_stream->public.output_color_space !=
1074 new_stream->public.output_color_space)
1075 return true;
1076
1077 return memcmp(
1078 &cur_stream->public.timing,
1079 &new_stream->public.timing,
1080 sizeof(struct dc_crtc_timing)) != 0;
1081}
1082
1083static bool are_stream_backends_same(
1084 const struct core_stream *stream_a, const struct core_stream *stream_b)
1085{
1086 if (stream_a == stream_b)
1087 return true;
1088
1089 if (stream_a == NULL || stream_b == NULL)
1090 return false;
1091
1092 if (is_timing_changed(stream_a, stream_b))
1093 return false;
1094
1095 return true;
1096}
1097
ab2541b6
AC
1098bool is_stream_unchanged(
1099 const struct core_stream *old_stream, const struct core_stream *stream)
4562236b 1100{
4562236b 1101
ab2541b6
AC
1102 if (!are_stream_backends_same(old_stream, stream))
1103 return false;
4562236b
HW
1104
1105 return true;
1106}
1107
1108bool resource_validate_attach_surfaces(
1109 const struct dc_validation_set set[],
1110 int set_count,
1111 const struct validate_context *old_context,
a2b8659d
TC
1112 struct validate_context *context,
1113 const struct resource_pool *pool)
4562236b
HW
1114{
1115 int i, j;
1116
1117 for (i = 0; i < set_count; i++) {
ab2541b6
AC
1118 for (j = 0; j < old_context->stream_count; j++)
1119 if (is_stream_unchanged(
1120 old_context->streams[j],
1121 context->streams[i])) {
4562236b 1122 if (!resource_attach_surfaces_to_context(
ab2541b6
AC
1123 old_context->stream_status[j].surfaces,
1124 old_context->stream_status[j].surface_count,
1125 &context->streams[i]->public,
a2b8659d 1126 context, pool))
4562236b 1127 return false;
ab2541b6 1128 context->stream_status[i] = old_context->stream_status[j];
4562236b
HW
1129 }
1130 if (set[i].surface_count != 0)
1131 if (!resource_attach_surfaces_to_context(
1132 set[i].surfaces,
1133 set[i].surface_count,
ab2541b6 1134 &context->streams[i]->public,
a2b8659d 1135 context, pool))
4562236b
HW
1136 return false;
1137
1138 }
1139
1140 return true;
1141}
1142
1143/* Maximum TMDS single link pixel clock 165MHz */
1144#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
1145
1146static void set_stream_engine_in_use(
1147 struct resource_context *res_ctx,
a2b8659d 1148 const struct resource_pool *pool,
4562236b
HW
1149 struct stream_encoder *stream_enc)
1150{
1151 int i;
1152
a2b8659d
TC
1153 for (i = 0; i < pool->stream_enc_count; i++) {
1154 if (pool->stream_enc[i] == stream_enc)
4562236b
HW
1155 res_ctx->is_stream_enc_acquired[i] = true;
1156 }
1157}
1158
1159/* TODO: release audio object */
1160static void set_audio_in_use(
1161 struct resource_context *res_ctx,
a2b8659d 1162 const struct resource_pool *pool,
4562236b
HW
1163 struct audio *audio)
1164{
1165 int i;
a2b8659d
TC
1166 for (i = 0; i < pool->audio_count; i++) {
1167 if (pool->audios[i] == audio)
4562236b 1168 res_ctx->is_audio_acquired[i] = true;
4562236b
HW
1169 }
1170}
1171
1172static int acquire_first_free_pipe(
1173 struct resource_context *res_ctx,
a2b8659d 1174 const struct resource_pool *pool,
4562236b
HW
1175 struct core_stream *stream)
1176{
1177 int i;
1178
a2b8659d 1179 for (i = 0; i < pool->pipe_count; i++) {
4562236b
HW
1180 if (!res_ctx->pipe_ctx[i].stream) {
1181 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
1182
a2b8659d
TC
1183 pipe_ctx->tg = pool->timing_generators[i];
1184 pipe_ctx->mi = pool->mis[i];
1185 pipe_ctx->ipp = pool->ipps[i];
1186 pipe_ctx->xfm = pool->transforms[i];
1187 pipe_ctx->opp = pool->opps[i];
1188 pipe_ctx->dis_clk = pool->display_clock;
4562236b
HW
1189 pipe_ctx->pipe_idx = i;
1190
1191 pipe_ctx->stream = stream;
1192 return i;
1193 }
1194 }
1195 return -1;
1196}
1197
1198static struct stream_encoder *find_first_free_match_stream_enc_for_link(
1199 struct resource_context *res_ctx,
a2b8659d 1200 const struct resource_pool *pool,
4562236b
HW
1201 struct core_stream *stream)
1202{
1203 int i;
1204 int j = -1;
1205 struct core_link *link = stream->sink->link;
1206
a2b8659d 1207 for (i = 0; i < pool->stream_enc_count; i++) {
4562236b 1208 if (!res_ctx->is_stream_enc_acquired[i] &&
a2b8659d 1209 pool->stream_enc[i]) {
4562236b
HW
1210 /* Store first available for MST second display
1211 * in daisy chain use case */
1212 j = i;
a2b8659d 1213 if (pool->stream_enc[i]->id ==
4562236b 1214 link->link_enc->preferred_engine)
a2b8659d 1215 return pool->stream_enc[i];
4562236b
HW
1216 }
1217 }
1218
1219 /*
1220 * below can happen in cases when stream encoder is acquired:
1221 * 1) for second MST display in chain, so preferred engine already
1222 * acquired;
1223 * 2) for another link, which preferred engine already acquired by any
1224 * MST configuration.
1225 *
1226 * If signal is of DP type and preferred engine not found, return last available
1227 *
1228 * TODO - This is just a patch up and a generic solution is
1229 * required for non DP connectors.
1230 */
1231
1232 if (j >= 0 && dc_is_dp_signal(stream->signal))
a2b8659d 1233 return pool->stream_enc[j];
4562236b
HW
1234
1235 return NULL;
1236}
1237
a2b8659d
TC
1238static struct audio *find_first_free_audio(
1239 struct resource_context *res_ctx,
1240 const struct resource_pool *pool)
4562236b
HW
1241{
1242 int i;
a2b8659d 1243 for (i = 0; i < pool->audio_count; i++) {
4562236b 1244 if (res_ctx->is_audio_acquired[i] == false) {
a2b8659d 1245 return pool->audios[i];
4562236b
HW
1246 }
1247 }
1248
1249 return 0;
1250}
1251
1252static void update_stream_signal(struct core_stream *stream)
1253{
8b32076c
ST
1254 if (stream->public.output_signal == SIGNAL_TYPE_NONE) {
1255 const struct dc_sink *dc_sink = stream->public.sink;
1256
1257 if (dc_sink->sink_signal == SIGNAL_TYPE_NONE)
1258 stream->signal =
1259 stream->sink->link->
1260 public.connector_signal;
4562236b 1261 else
8b32076c
ST
1262 stream->signal = dc_sink->sink_signal;
1263 } else {
1264 stream->signal = stream->public.output_signal;
1265 }
1266
1267 if (stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK &&
1268 stream->public.timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ)
1269 stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK;
4562236b
HW
1270}
1271
1272bool resource_is_stream_unchanged(
ab2541b6 1273 const struct validate_context *old_context, const struct core_stream *stream)
4562236b 1274{
ab2541b6 1275 int i;
4562236b 1276
ab2541b6
AC
1277 for (i = 0; i < old_context->stream_count; i++) {
1278 const struct core_stream *old_stream = old_context->streams[i];
4562236b 1279
ab2541b6 1280 if (are_stream_backends_same(old_stream, stream))
4562236b 1281 return true;
4562236b
HW
1282 }
1283
1284 return false;
1285}
1286
1287static void copy_pipe_ctx(
1288 const struct pipe_ctx *from_pipe_ctx, struct pipe_ctx *to_pipe_ctx)
1289{
1290 struct core_surface *surface = to_pipe_ctx->surface;
1291 struct core_stream *stream = to_pipe_ctx->stream;
1292
1293 *to_pipe_ctx = *from_pipe_ctx;
1294 to_pipe_ctx->stream = stream;
1295 if (surface != NULL)
1296 to_pipe_ctx->surface = surface;
1297}
1298
1299static struct core_stream *find_pll_sharable_stream(
1300 const struct core_stream *stream_needs_pll,
1301 struct validate_context *context)
1302{
ab2541b6 1303 int i;
4562236b 1304
ab2541b6
AC
1305 for (i = 0; i < context->stream_count; i++) {
1306 struct core_stream *stream_has_pll = context->streams[i];
4562236b 1307
ab2541b6
AC
1308 /* We are looking for non dp, non virtual stream */
1309 if (resource_are_streams_timing_synchronizable(
1310 stream_needs_pll, stream_has_pll)
1311 && !dc_is_dp_signal(stream_has_pll->signal)
1312 && stream_has_pll->sink->link->public.connector_signal
1313 != SIGNAL_TYPE_VIRTUAL)
1314 return stream_has_pll;
4562236b 1315
4562236b
HW
1316 }
1317
1318 return NULL;
1319}
1320
1321static int get_norm_pix_clk(const struct dc_crtc_timing *timing)
1322{
1323 uint32_t pix_clk = timing->pix_clk_khz;
1324 uint32_t normalized_pix_clk = pix_clk;
1325
1326 if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
1327 pix_clk /= 2;
cc4d99b8
CL
1328 if (timing->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
1329 switch (timing->display_color_depth) {
1330 case COLOR_DEPTH_888:
1331 normalized_pix_clk = pix_clk;
1332 break;
1333 case COLOR_DEPTH_101010:
1334 normalized_pix_clk = (pix_clk * 30) / 24;
1335 break;
1336 case COLOR_DEPTH_121212:
1337 normalized_pix_clk = (pix_clk * 36) / 24;
4562236b 1338 break;
cc4d99b8
CL
1339 case COLOR_DEPTH_161616:
1340 normalized_pix_clk = (pix_clk * 48) / 24;
4562236b 1341 break;
cc4d99b8
CL
1342 default:
1343 ASSERT(0);
4562236b 1344 break;
cc4d99b8 1345 }
4562236b 1346 }
4562236b
HW
1347 return normalized_pix_clk;
1348}
1349
1350static void calculate_phy_pix_clks(
1351 const struct core_dc *dc,
1352 struct validate_context *context)
1353{
ab2541b6 1354 int i;
4562236b 1355
ab2541b6
AC
1356 for (i = 0; i < context->stream_count; i++) {
1357 struct core_stream *stream = context->streams[i];
4562236b 1358
ab2541b6 1359 update_stream_signal(stream);
4562236b 1360
ab2541b6
AC
1361 /* update actual pixel clock on all streams */
1362 if (dc_is_hdmi_signal(stream->signal))
1363 stream->phy_pix_clk = get_norm_pix_clk(
1364 &stream->public.timing);
1365 else
1366 stream->phy_pix_clk =
1367 stream->public.timing.pix_clk_khz;
4562236b
HW
1368 }
1369}
1370
1371enum dc_status resource_map_pool_resources(
1372 const struct core_dc *dc,
1373 struct validate_context *context)
1374{
a2b8659d 1375 const struct resource_pool *pool = dc->res_pool;
ab2541b6 1376 int i, j;
4562236b
HW
1377
1378 calculate_phy_pix_clks(dc, context);
1379
ab2541b6
AC
1380 for (i = 0; i < context->stream_count; i++) {
1381 struct core_stream *stream = context->streams[i];
4562236b 1382
4b679bc3
CL
1383 if (!resource_is_stream_unchanged(dc->current_context, stream)) {
1384 if (stream != NULL && dc->current_context->streams[i] != NULL) {
1385 stream->bit_depth_params =
1386 dc->current_context->streams[i]->bit_depth_params;
1387 stream->clamping = dc->current_context->streams[i]->clamping;
a2b8659d
TC
1388 continue;
1389 }
4b679bc3 1390 }
7e2fe319 1391
ab2541b6 1392 /* mark resources used for stream that is already active */
a2b8659d 1393 for (j = 0; j < pool->pipe_count; j++) {
ab2541b6
AC
1394 struct pipe_ctx *pipe_ctx =
1395 &context->res_ctx.pipe_ctx[j];
1396 const struct pipe_ctx *old_pipe_ctx =
1397 &dc->current_context->res_ctx.pipe_ctx[j];
4562236b 1398
ab2541b6
AC
1399 if (!are_stream_backends_same(old_pipe_ctx->stream, stream))
1400 continue;
8c737fcc 1401
268cadbd
YS
1402 if (old_pipe_ctx->top_pipe)
1403 continue;
1404
ab2541b6
AC
1405 pipe_ctx->stream = stream;
1406 copy_pipe_ctx(old_pipe_ctx, pipe_ctx);
4562236b 1407
ab2541b6
AC
1408 /* Split pipe resource, do not acquire back end */
1409 if (!pipe_ctx->stream_enc)
1410 continue;
4562236b 1411
ab2541b6 1412 set_stream_engine_in_use(
a2b8659d 1413 &context->res_ctx, pool,
ab2541b6
AC
1414 pipe_ctx->stream_enc);
1415
1416 /* Switch to dp clock source only if there is
1417 * no non dp stream that shares the same timing
1418 * with the dp stream.
1419 */
1420 if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
1421 !find_pll_sharable_stream(stream, context))
a2b8659d 1422 pipe_ctx->clock_source = pool->dp_clock_source;
ab2541b6
AC
1423
1424 resource_reference_clock_source(
a2b8659d 1425 &context->res_ctx, pool,
ab2541b6
AC
1426 pipe_ctx->clock_source);
1427
a2b8659d
TC
1428 set_audio_in_use(&context->res_ctx, pool,
1429 pipe_ctx->audio);
4562236b
HW
1430 }
1431 }
1432
ab2541b6
AC
1433 for (i = 0; i < context->stream_count; i++) {
1434 struct core_stream *stream = context->streams[i];
1435 struct pipe_ctx *pipe_ctx = NULL;
1436 int pipe_idx = -1;
4562236b 1437
ab2541b6
AC
1438 if (resource_is_stream_unchanged(dc->current_context, stream))
1439 continue;
1440 /* acquire new resources */
a2b8659d
TC
1441 pipe_idx = acquire_first_free_pipe(
1442 &context->res_ctx, pool, stream);
ab2541b6
AC
1443 if (pipe_idx < 0)
1444 return DC_NO_CONTROLLER_RESOURCE;
1445
ab2541b6
AC
1446 pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
1447
1448 pipe_ctx->stream_enc =
1449 find_first_free_match_stream_enc_for_link(
a2b8659d 1450 &context->res_ctx, pool, stream);
ab2541b6
AC
1451
1452 if (!pipe_ctx->stream_enc)
1453 return DC_NO_STREAM_ENG_RESOURCE;
1454
1455 set_stream_engine_in_use(
a2b8659d 1456 &context->res_ctx, pool,
ab2541b6
AC
1457 pipe_ctx->stream_enc);
1458
1459 /* TODO: Add check if ASIC support and EDID audio */
4a9a5d62 1460 if (!stream->sink->public.converter_disable_audio &&
ab2541b6
AC
1461 dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
1462 stream->public.audio_info.mode_count) {
1463 pipe_ctx->audio = find_first_free_audio(
a2b8659d 1464 &context->res_ctx, pool);
ab2541b6
AC
1465
1466 /*
1467 * Audio assigned in order first come first get.
1468 * There are asics which has number of audio
1469 * resources less then number of pipes
1470 */
1471 if (pipe_ctx->audio)
1472 set_audio_in_use(
a2b8659d 1473 &context->res_ctx, pool,
ab2541b6 1474 pipe_ctx->audio);
4562236b 1475 }
ab2541b6
AC
1476
1477 context->stream_status[i].primary_otg_inst = pipe_ctx->tg->inst;
4562236b
HW
1478 }
1479
1480 return DC_OK;
1481}
1482
ab2541b6
AC
1483/* first stream in the context is used to populate the rest */
1484void validate_guaranteed_copy_streams(
4562236b 1485 struct validate_context *context,
ab2541b6 1486 int max_streams)
4562236b
HW
1487{
1488 int i;
1489
ab2541b6
AC
1490 for (i = 1; i < max_streams; i++) {
1491 context->streams[i] = context->streams[0];
4562236b
HW
1492
1493 copy_pipe_ctx(&context->res_ctx.pipe_ctx[0],
1494 &context->res_ctx.pipe_ctx[i]);
1495 context->res_ctx.pipe_ctx[i].stream =
1496 context->res_ctx.pipe_ctx[0].stream;
1497
ab2541b6
AC
1498 dc_stream_retain(&context->streams[i]->public);
1499 context->stream_count++;
4562236b
HW
1500 }
1501}
1502
6e4d6bee
TC
1503static void patch_gamut_packet_checksum(
1504 struct encoder_info_packet *gamut_packet)
4562236b 1505{
4562236b 1506 /* For gamut we recalc checksum */
6e4d6bee 1507 if (gamut_packet->valid) {
4562236b
HW
1508 uint8_t chk_sum = 0;
1509 uint8_t *ptr;
1510 uint8_t i;
1511
4562236b 1512 /*start of the Gamut data. */
6e4d6bee 1513 ptr = &gamut_packet->sb[3];
4562236b 1514
6e4d6bee 1515 for (i = 0; i <= gamut_packet->sb[1]; i++)
4562236b
HW
1516 chk_sum += ptr[i];
1517
6e4d6bee 1518 gamut_packet->sb[2] = (uint8_t) (0x100 - chk_sum);
1646a6fe 1519 }
4562236b
HW
1520}
1521
1522static void set_avi_info_frame(
6e4d6bee 1523 struct encoder_info_packet *info_packet,
4562236b
HW
1524 struct pipe_ctx *pipe_ctx)
1525{
1526 struct core_stream *stream = pipe_ctx->stream;
1527 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
1528 struct info_frame info_frame = { {0} };
1529 uint32_t pixel_encoding = 0;
1530 enum scanning_type scan_type = SCANNING_TYPE_NODATA;
1531 enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
1532 bool itc = false;
1533 uint8_t cn0_cn1 = 0;
1534 uint8_t *check_sum = NULL;
1535 uint8_t byte_index = 0;
e8d726b7 1536 union hdmi_info_packet *hdmi_info = &info_frame.avi_info_packet.info_packet_hdmi;
4562236b 1537
4562236b
HW
1538 color_space = pipe_ctx->stream->public.output_color_space;
1539
1540 /* Initialize header */
e8d726b7 1541 hdmi_info->bits.header.info_frame_type = HDMI_INFOFRAME_TYPE_AVI;
4562236b
HW
1542 /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
1543 * not be used in HDMI 2.0 (Section 10.1) */
e8d726b7
RA
1544 hdmi_info->bits.header.version = 2;
1545 hdmi_info->bits.header.length = HDMI_AVI_INFOFRAME_SIZE;
4562236b
HW
1546
1547 /*
1548 * IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
1549 * according to HDMI 2.0 spec (Section 10.1)
1550 */
1551
1552 switch (stream->public.timing.pixel_encoding) {
1553 case PIXEL_ENCODING_YCBCR422:
1554 pixel_encoding = 1;
1555 break;
1556
1557 case PIXEL_ENCODING_YCBCR444:
1558 pixel_encoding = 2;
1559 break;
1560 case PIXEL_ENCODING_YCBCR420:
1561 pixel_encoding = 3;
1562 break;
1563
1564 case PIXEL_ENCODING_RGB:
1565 default:
1566 pixel_encoding = 0;
1567 }
1568
1569 /* Y0_Y1_Y2 : The pixel encoding */
1570 /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
e8d726b7 1571 hdmi_info->bits.Y0_Y1_Y2 = pixel_encoding;
4562236b
HW
1572
1573 /* A0 = 1 Active Format Information valid */
e8d726b7 1574 hdmi_info->bits.A0 = ACTIVE_FORMAT_VALID;
4562236b
HW
1575
1576 /* B0, B1 = 3; Bar info data is valid */
e8d726b7 1577 hdmi_info->bits.B0_B1 = BAR_INFO_BOTH_VALID;
4562236b 1578
e8d726b7 1579 hdmi_info->bits.SC0_SC1 = PICTURE_SCALING_UNIFORM;
4562236b
HW
1580
1581 /* S0, S1 : Underscan / Overscan */
1582 /* TODO: un-hardcode scan type */
1583 scan_type = SCANNING_TYPE_UNDERSCAN;
e8d726b7 1584 hdmi_info->bits.S0_S1 = scan_type;
4562236b
HW
1585
1586 /* C0, C1 : Colorimetry */
8fde5884
CL
1587 if (color_space == COLOR_SPACE_YCBCR709 ||
1588 color_space == COLOR_SPACE_YCBCR709_LIMITED)
e8d726b7 1589 hdmi_info->bits.C0_C1 = COLORIMETRY_ITU709;
8fde5884
CL
1590 else if (color_space == COLOR_SPACE_YCBCR601 ||
1591 color_space == COLOR_SPACE_YCBCR601_LIMITED)
e8d726b7 1592 hdmi_info->bits.C0_C1 = COLORIMETRY_ITU601;
8fde5884
CL
1593 else {
1594 if (stream->public.timing.pixel_encoding != PIXEL_ENCODING_RGB)
1595 BREAK_TO_DEBUGGER();
e8d726b7 1596 hdmi_info->bits.C0_C1 = COLORIMETRY_NO_DATA;
8fde5884 1597 }
534db198 1598 if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE ||
8fde5884
CL
1599 color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE ||
1600 color_space == COLOR_SPACE_2020_YCBCR) {
e8d726b7
RA
1601 hdmi_info->bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR;
1602 hdmi_info->bits.C0_C1 = COLORIMETRY_EXTENDED;
534db198 1603 } else if (color_space == COLOR_SPACE_ADOBERGB) {
e8d726b7
RA
1604 hdmi_info->bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB;
1605 hdmi_info->bits.C0_C1 = COLORIMETRY_EXTENDED;
534db198
AZ
1606 }
1607
4562236b
HW
1608 /* TODO: un-hardcode aspect ratio */
1609 aspect = stream->public.timing.aspect_ratio;
1610
1611 switch (aspect) {
1612 case ASPECT_RATIO_4_3:
1613 case ASPECT_RATIO_16_9:
e8d726b7 1614 hdmi_info->bits.M0_M1 = aspect;
4562236b
HW
1615 break;
1616
1617 case ASPECT_RATIO_NO_DATA:
1618 case ASPECT_RATIO_64_27:
1619 case ASPECT_RATIO_256_135:
1620 default:
e8d726b7 1621 hdmi_info->bits.M0_M1 = 0;
4562236b
HW
1622 }
1623
1624 /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
e8d726b7 1625 hdmi_info->bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
4562236b
HW
1626
1627 /* TODO: un-hardcode cn0_cn1 and itc */
1628 cn0_cn1 = 0;
1629 itc = false;
1630
1631 if (itc) {
e8d726b7
RA
1632 hdmi_info->bits.ITC = 1;
1633 hdmi_info->bits.CN0_CN1 = cn0_cn1;
4562236b
HW
1634 }
1635
1636 /* TODO : We should handle YCC quantization */
1637 /* but we do not have matrix calculation */
1638 if (color_space == COLOR_SPACE_SRGB) {
e8d726b7
RA
1639 hdmi_info->bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE;
1640 hdmi_info->bits.YQ0_YQ1 = YYC_QUANTIZATION_FULL_RANGE;
4562236b 1641 } else if (color_space == COLOR_SPACE_SRGB_LIMITED) {
e8d726b7
RA
1642 hdmi_info->bits.Q0_Q1 = RGB_QUANTIZATION_LIMITED_RANGE;
1643 hdmi_info->bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
4562236b 1644 } else {
e8d726b7
RA
1645 hdmi_info->bits.Q0_Q1 = RGB_QUANTIZATION_DEFAULT_RANGE;
1646 hdmi_info->bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
4562236b
HW
1647 }
1648
e8d726b7 1649 hdmi_info->bits.VIC0_VIC7 =
4562236b
HW
1650 stream->public.timing.vic;
1651
1652 /* pixel repetition
1653 * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
1654 * repetition start from 1 */
e8d726b7 1655 hdmi_info->bits.PR0_PR3 = 0;
4562236b
HW
1656
1657 /* Bar Info
1658 * barTop: Line Number of End of Top Bar.
1659 * barBottom: Line Number of Start of Bottom Bar.
1660 * barLeft: Pixel Number of End of Left Bar.
1661 * barRight: Pixel Number of Start of Right Bar. */
e8d726b7
RA
1662 hdmi_info->bits.bar_top = stream->public.timing.v_border_top;
1663 hdmi_info->bits.bar_bottom = (stream->public.timing.v_border_top
4562236b 1664 - stream->public.timing.v_border_bottom + 1);
e8d726b7
RA
1665 hdmi_info->bits.bar_left = stream->public.timing.h_border_left;
1666 hdmi_info->bits.bar_right = (stream->public.timing.h_total
4562236b
HW
1667 - stream->public.timing.h_border_right + 1);
1668
1669 /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
e8d726b7
RA
1670 check_sum = &info_frame.avi_info_packet.info_packet_hdmi.packet_raw_data.sb[0];
1671
3e183c5f 1672 *check_sum = HDMI_INFOFRAME_TYPE_AVI + HDMI_AVI_INFOFRAME_SIZE + 2;
4562236b 1673
3e183c5f 1674 for (byte_index = 1; byte_index <= HDMI_AVI_INFOFRAME_SIZE; byte_index++)
e8d726b7 1675 *check_sum += hdmi_info->packet_raw_data.sb[byte_index];
4562236b
HW
1676
1677 /* one byte complement */
1678 *check_sum = (uint8_t) (0x100 - *check_sum);
1679
1680 /* Store in hw_path_mode */
e8d726b7
RA
1681 info_packet->hb0 = hdmi_info->packet_raw_data.hb0;
1682 info_packet->hb1 = hdmi_info->packet_raw_data.hb1;
1683 info_packet->hb2 = hdmi_info->packet_raw_data.hb2;
4562236b 1684
e66e4d64
HW
1685 for (byte_index = 0; byte_index < sizeof(info_frame.avi_info_packet.
1686 info_packet_hdmi.packet_raw_data.sb); byte_index++)
4562236b 1687 info_packet->sb[byte_index] = info_frame.avi_info_packet.
e66e4d64 1688 info_packet_hdmi.packet_raw_data.sb[byte_index];
4562236b
HW
1689
1690 info_packet->valid = true;
1691}
1692
6e4d6bee
TC
1693static void set_vendor_info_packet(
1694 struct encoder_info_packet *info_packet,
1695 struct core_stream *stream)
4562236b
HW
1696{
1697 uint32_t length = 0;
1698 bool hdmi_vic_mode = false;
1699 uint8_t checksum = 0;
1700 uint32_t i = 0;
1701 enum dc_timing_3d_format format;
1702
4562236b
HW
1703 format = stream->public.timing.timing_3d_format;
1704
1705 /* Can be different depending on packet content */
1706 length = 5;
1707
1708 if (stream->public.timing.hdmi_vic != 0
1709 && stream->public.timing.h_total >= 3840
1710 && stream->public.timing.v_total >= 2160)
1711 hdmi_vic_mode = true;
1712
1713 /* According to HDMI 1.4a CTS, VSIF should be sent
1714 * for both 3D stereo and HDMI VIC modes.
1715 * For all other modes, there is no VSIF sent. */
1716
1717 if (format == TIMING_3D_FORMAT_NONE && !hdmi_vic_mode)
1718 return;
1719
1720 /* 24bit IEEE Registration identifier (0x000c03). LSB first. */
1721 info_packet->sb[1] = 0x03;
1722 info_packet->sb[2] = 0x0C;
1723 info_packet->sb[3] = 0x00;
1724
1725 /*PB4: 5 lower bytes = 0 (reserved). 3 higher bits = HDMI_Video_Format.
1726 * The value for HDMI_Video_Format are:
1727 * 0x0 (0b000) - No additional HDMI video format is presented in this
1728 * packet
1729 * 0x1 (0b001) - Extended resolution format present. 1 byte of HDMI_VIC
1730 * parameter follows
1731 * 0x2 (0b010) - 3D format indication present. 3D_Structure and
1732 * potentially 3D_Ext_Data follows
1733 * 0x3..0x7 (0b011..0b111) - reserved for future use */
1734 if (format != TIMING_3D_FORMAT_NONE)
1735 info_packet->sb[4] = (2 << 5);
1736 else if (hdmi_vic_mode)
1737 info_packet->sb[4] = (1 << 5);
1738
1739 /* PB5: If PB4 claims 3D timing (HDMI_Video_Format = 0x2):
1740 * 4 lower bites = 0 (reserved). 4 higher bits = 3D_Structure.
1741 * The value for 3D_Structure are:
1742 * 0x0 - Frame Packing
1743 * 0x1 - Field Alternative
1744 * 0x2 - Line Alternative
1745 * 0x3 - Side-by-Side (full)
1746 * 0x4 - L + depth
1747 * 0x5 - L + depth + graphics + graphics-depth
1748 * 0x6 - Top-and-Bottom
1749 * 0x7 - Reserved for future use
1750 * 0x8 - Side-by-Side (Half)
1751 * 0x9..0xE - Reserved for future use
1752 * 0xF - Not used */
1753 switch (format) {
1754 case TIMING_3D_FORMAT_HW_FRAME_PACKING:
1755 case TIMING_3D_FORMAT_SW_FRAME_PACKING:
1756 info_packet->sb[5] = (0x0 << 4);
1757 break;
1758
1759 case TIMING_3D_FORMAT_SIDE_BY_SIDE:
1760 case TIMING_3D_FORMAT_SBS_SW_PACKED:
1761 info_packet->sb[5] = (0x8 << 4);
1762 length = 6;
1763 break;
1764
1765 case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
1766 case TIMING_3D_FORMAT_TB_SW_PACKED:
1767 info_packet->sb[5] = (0x6 << 4);
1768 break;
1769
1770 default:
1771 break;
1772 }
1773
1774 /*PB5: If PB4 is set to 0x1 (extended resolution format)
1775 * fill PB5 with the correct HDMI VIC code */
1776 if (hdmi_vic_mode)
1777 info_packet->sb[5] = stream->public.timing.hdmi_vic;
1778
1779 /* Header */
3e183c5f 1780 info_packet->hb0 = HDMI_INFOFRAME_TYPE_VENDOR; /* VSIF packet type. */
4562236b
HW
1781 info_packet->hb1 = 0x01; /* Version */
1782
1783 /* 4 lower bits = Length, 4 higher bits = 0 (reserved) */
1784 info_packet->hb2 = (uint8_t) (length);
1785
1786 /* Calculate checksum */
1787 checksum = 0;
1788 checksum += info_packet->hb0;
1789 checksum += info_packet->hb1;
1790 checksum += info_packet->hb2;
1791
1792 for (i = 1; i <= length; i++)
1793 checksum += info_packet->sb[i];
1794
1795 info_packet->sb[0] = (uint8_t) (0x100 - checksum);
1796
1797 info_packet->valid = true;
1798}
1799
6e4d6bee
TC
1800static void set_spd_info_packet(
1801 struct encoder_info_packet *info_packet,
1802 struct core_stream *stream)
4562236b
HW
1803{
1804 /* SPD info packet for FreeSync */
1805
1806 unsigned char checksum = 0;
1807 unsigned int idx, payload_size = 0;
1808
1809 /* Check if Freesync is supported. Return if false. If true,
1810 * set the corresponding bit in the info packet
1811 */
1812 if (stream->public.freesync_ctx.supported == false)
1813 return;
1814
1815 if (dc_is_hdmi_signal(stream->signal)) {
1816
1817 /* HEADER */
1818
1819 /* HB0 = Packet Type = 0x83 (Source Product
1820 * Descriptor InfoFrame)
1821 */
3e183c5f 1822 info_packet->hb0 = HDMI_INFOFRAME_TYPE_SPD;
4562236b
HW
1823
1824 /* HB1 = Version = 0x01 */
1825 info_packet->hb1 = 0x01;
1826
1827 /* HB2 = [Bits 7:5 = 0] [Bits 4:0 = Length = 0x08] */
1828 info_packet->hb2 = 0x08;
1829
1830 payload_size = 0x08;
1831
1832 } else if (dc_is_dp_signal(stream->signal)) {
1833
1834 /* HEADER */
1835
1836 /* HB0 = Secondary-data Packet ID = 0 - Only non-zero
1837 * when used to associate audio related info packets
1838 */
1839 info_packet->hb0 = 0x00;
1840
1841 /* HB1 = Packet Type = 0x83 (Source Product
1842 * Descriptor InfoFrame)
1843 */
3e183c5f 1844 info_packet->hb1 = HDMI_INFOFRAME_TYPE_SPD;
4562236b
HW
1845
1846 /* HB2 = [Bits 7:0 = Least significant eight bits -
1847 * For INFOFRAME, the value must be 1Bh]
1848 */
1849 info_packet->hb2 = 0x1B;
1850
1851 /* HB3 = [Bits 7:2 = INFOFRAME SDP Version Number = 0x1]
1852 * [Bits 1:0 = Most significant two bits = 0x00]
1853 */
1854 info_packet->hb3 = 0x04;
1855
1856 payload_size = 0x1B;
1857 }
1858
1859 /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */
1860 info_packet->sb[1] = 0x1A;
1861
1862 /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */
1863 info_packet->sb[2] = 0x00;
1864
1865 /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */
1866 info_packet->sb[3] = 0x00;
1867
1868 /* PB4 = Reserved */
1869 info_packet->sb[4] = 0x00;
1870
1871 /* PB5 = Reserved */
1872 info_packet->sb[5] = 0x00;
1873
1874 /* PB6 = [Bits 7:3 = Reserved] */
1875 info_packet->sb[6] = 0x00;
1876
1877 if (stream->public.freesync_ctx.supported == true)
1878 /* PB6 = [Bit 0 = FreeSync Supported] */
1879 info_packet->sb[6] |= 0x01;
1880
1881 if (stream->public.freesync_ctx.enabled == true)
1882 /* PB6 = [Bit 1 = FreeSync Enabled] */
1883 info_packet->sb[6] |= 0x02;
1884
1885 if (stream->public.freesync_ctx.active == true)
1886 /* PB6 = [Bit 2 = FreeSync Active] */
1887 info_packet->sb[6] |= 0x04;
1888
1889 /* PB7 = FreeSync Minimum refresh rate (Hz) */
1890 info_packet->sb[7] = (unsigned char) (stream->public.freesync_ctx.
1891 min_refresh_in_micro_hz / 1000000);
1892
1893 /* PB8 = FreeSync Maximum refresh rate (Hz)
1894 *
1895 * Note: We do not use the maximum capable refresh rate
1896 * of the panel, because we should never go above the field
1897 * rate of the mode timing set.
1898 */
1899 info_packet->sb[8] = (unsigned char) (stream->public.freesync_ctx.
1900 nominal_refresh_in_micro_hz / 1000000);
1901
1902 /* PB9 - PB27 = Reserved */
1903 for (idx = 9; idx <= 27; idx++)
1904 info_packet->sb[idx] = 0x00;
1905
1906 /* Calculate checksum */
1907 checksum += info_packet->hb0;
1908 checksum += info_packet->hb1;
1909 checksum += info_packet->hb2;
1910 checksum += info_packet->hb3;
1911
1912 for (idx = 1; idx <= payload_size; idx++)
1913 checksum += info_packet->sb[idx];
1914
1915 /* PB0 = Checksum (one byte complement) */
1916 info_packet->sb[0] = (unsigned char) (0x100 - checksum);
1917
1918 info_packet->valid = true;
1919}
1920
1646a6fe 1921static void set_hdr_static_info_packet(
6e4d6bee 1922 struct encoder_info_packet *info_packet,
1646a6fe 1923 struct core_surface *surface,
6e4d6bee 1924 struct core_stream *stream)
1646a6fe 1925{
e5cf325b 1926 uint16_t i = 0;
1646a6fe 1927 enum signal_type signal = stream->signal;
e5cf325b
HW
1928 struct dc_hdr_static_metadata hdr_metadata;
1929 uint32_t data;
1646a6fe
AW
1930
1931 if (!surface)
1932 return;
1933
e5cf325b 1934 hdr_metadata = surface->public.hdr_static_ctx;
1646a6fe 1935
70063a59 1936 if (!hdr_metadata.hdr_supported)
10bff005
YS
1937 return;
1938
1646a6fe
AW
1939 if (dc_is_hdmi_signal(signal)) {
1940 info_packet->valid = true;
1941
1942 info_packet->hb0 = 0x87;
1943 info_packet->hb1 = 0x01;
1944 info_packet->hb2 = 0x1A;
1945 i = 1;
1946 } else if (dc_is_dp_signal(signal)) {
1947 info_packet->valid = true;
1948
1949 info_packet->hb0 = 0x00;
1950 info_packet->hb1 = 0x87;
1951 info_packet->hb2 = 0x1D;
1952 info_packet->hb3 = (0x13 << 2);
1953 i = 2;
1954 }
1955
1646a6fe
AW
1956 data = hdr_metadata.is_hdr;
1957 info_packet->sb[i++] = data ? 0x02 : 0x00;
1958 info_packet->sb[i++] = 0x00;
1959
1960 data = hdr_metadata.chromaticity_green_x / 2;
1961 info_packet->sb[i++] = data & 0xFF;
1962 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1963
1964 data = hdr_metadata.chromaticity_green_y / 2;
1965 info_packet->sb[i++] = data & 0xFF;
1966 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1967
1968 data = hdr_metadata.chromaticity_blue_x / 2;
1969 info_packet->sb[i++] = data & 0xFF;
1970 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1971
1972 data = hdr_metadata.chromaticity_blue_y / 2;
1973 info_packet->sb[i++] = data & 0xFF;
1974 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1975
1976 data = hdr_metadata.chromaticity_red_x / 2;
1977 info_packet->sb[i++] = data & 0xFF;
1978 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1979
1980 data = hdr_metadata.chromaticity_red_y / 2;
1981 info_packet->sb[i++] = data & 0xFF;
1982 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1983
1984 data = hdr_metadata.chromaticity_white_point_x / 2;
1985 info_packet->sb[i++] = data & 0xFF;
1986 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1987
1988 data = hdr_metadata.chromaticity_white_point_y / 2;
1989 info_packet->sb[i++] = data & 0xFF;
1990 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1991
1992 data = hdr_metadata.max_luminance;
1993 info_packet->sb[i++] = data & 0xFF;
1994 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1995
1996 data = hdr_metadata.min_luminance;
1997 info_packet->sb[i++] = data & 0xFF;
1998 info_packet->sb[i++] = (data & 0xFF00) >> 8;
1999
2000 data = hdr_metadata.maximum_content_light_level;
2001 info_packet->sb[i++] = data & 0xFF;
2002 info_packet->sb[i++] = (data & 0xFF00) >> 8;
2003
2004 data = hdr_metadata.maximum_frame_average_light_level;
2005 info_packet->sb[i++] = data & 0xFF;
2006 info_packet->sb[i++] = (data & 0xFF00) >> 8;
2007
2008 if (dc_is_hdmi_signal(signal)) {
2009 uint32_t checksum = 0;
2010
2011 checksum += info_packet->hb0;
2012 checksum += info_packet->hb1;
2013 checksum += info_packet->hb2;
2014
2015 for (i = 1; i <= info_packet->hb2; i++)
2016 checksum += info_packet->sb[i];
2017
2018 info_packet->sb[0] = 0x100 - checksum;
2019 } else if (dc_is_dp_signal(signal)) {
2020 info_packet->sb[0] = 0x01;
2021 info_packet->sb[1] = 0x1A;
2022 }
2023}
2024
6e4d6bee
TC
2025static void set_vsc_info_packet(
2026 struct encoder_info_packet *info_packet,
2027 struct core_stream *stream)
4562236b
HW
2028{
2029 unsigned int vscPacketRevision = 0;
2030 unsigned int i;
2031
94267b3d 2032 if (stream->sink->link->psr_enabled) {
4562236b
HW
2033 vscPacketRevision = 2;
2034 }
2035
2036 /* VSC packet not needed based on the features
2037 * supported by this DP display
2038 */
2039 if (vscPacketRevision == 0)
2040 return;
2041
2042 if (vscPacketRevision == 0x2) {
2043 /* Secondary-data Packet ID = 0*/
2044 info_packet->hb0 = 0x00;
2045 /* 07h - Packet Type Value indicating Video
2046 * Stream Configuration packet
2047 */
2048 info_packet->hb1 = 0x07;
2049 /* 02h = VSC SDP supporting 3D stereo and PSR
2050 * (applies to eDP v1.3 or higher).
2051 */
2052 info_packet->hb2 = 0x02;
2053 /* 08h = VSC packet supporting 3D stereo + PSR
2054 * (HB2 = 02h).
2055 */
2056 info_packet->hb3 = 0x08;
2057
2058 for (i = 0; i < 28; i++)
2059 info_packet->sb[i] = 0;
2060
2061 info_packet->valid = true;
2062 }
2063
2064 /*TODO: stereo 3D support and extend pixel encoding colorimetry*/
2065}
2066
8122a253 2067void dc_resource_validate_ctx_destruct(struct validate_context *context)
4562236b
HW
2068{
2069 int i, j;
2070
ab2541b6
AC
2071 for (i = 0; i < context->stream_count; i++) {
2072 for (j = 0; j < context->stream_status[i].surface_count; j++)
4562236b 2073 dc_surface_release(
ab2541b6 2074 context->stream_status[i].surfaces[j]);
4562236b 2075
ab2541b6
AC
2076 context->stream_status[i].surface_count = 0;
2077 dc_stream_release(&context->streams[i]->public);
2078 context->streams[i] = NULL;
4562236b
HW
2079 }
2080}
2081
2082/*
ab2541b6 2083 * Copy src_ctx into dst_ctx and retain all surfaces and streams referenced
4562236b
HW
2084 * by the src_ctx
2085 */
8122a253 2086void dc_resource_validate_ctx_copy_construct(
4562236b
HW
2087 const struct validate_context *src_ctx,
2088 struct validate_context *dst_ctx)
2089{
2090 int i, j;
2091
2092 *dst_ctx = *src_ctx;
2093
a2b8659d 2094 for (i = 0; i < MAX_PIPES; i++) {
4562236b
HW
2095 struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i];
2096
2097 if (cur_pipe->top_pipe)
2098 cur_pipe->top_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx];
2099
2100 if (cur_pipe->bottom_pipe)
2101 cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
2102
2103 }
2104
ab2541b6
AC
2105 for (i = 0; i < dst_ctx->stream_count; i++) {
2106 dc_stream_retain(&dst_ctx->streams[i]->public);
2107 for (j = 0; j < dst_ctx->stream_status[i].surface_count; j++)
4562236b 2108 dc_surface_retain(
ab2541b6 2109 dst_ctx->stream_status[i].surfaces[j]);
4562236b
HW
2110 }
2111}
2112
2113struct clock_source *dc_resource_find_first_free_pll(
a2b8659d
TC
2114 struct resource_context *res_ctx,
2115 const struct resource_pool *pool)
4562236b
HW
2116{
2117 int i;
2118
a2b8659d 2119 for (i = 0; i < pool->clk_src_count; ++i) {
4562236b 2120 if (res_ctx->clock_source_ref_count[i] == 0)
a2b8659d 2121 return pool->clock_sources[i];
4562236b
HW
2122 }
2123
2124 return NULL;
2125}
2126
2127void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
2128{
2129 enum signal_type signal = SIGNAL_TYPE_NONE;
6e4d6bee 2130 struct encoder_info_frame *info = &pipe_ctx->encoder_info_frame;
4562236b
HW
2131
2132 /* default all packets to invalid */
6e4d6bee
TC
2133 info->avi.valid = false;
2134 info->gamut.valid = false;
2135 info->vendor.valid = false;
2136 info->hdrsmd.valid = false;
2137 info->vsc.valid = false;
4562236b
HW
2138
2139 signal = pipe_ctx->stream->signal;
2140
2141 /* HDMi and DP have different info packets*/
2142 if (dc_is_hdmi_signal(signal)) {
6e4d6bee
TC
2143 set_avi_info_frame(&info->avi, pipe_ctx);
2144
2145 set_vendor_info_packet(&info->vendor, pipe_ctx->stream);
2146
2147 set_spd_info_packet(&info->spd, pipe_ctx->stream);
2148
2149 set_hdr_static_info_packet(&info->hdrsmd,
2150 pipe_ctx->surface, pipe_ctx->stream);
2151
a33fa99d 2152 } else if (dc_is_dp_signal(signal)) {
6e4d6bee
TC
2153 set_vsc_info_packet(&info->vsc, pipe_ctx->stream);
2154
2155 set_spd_info_packet(&info->spd, pipe_ctx->stream);
2156
2157 set_hdr_static_info_packet(&info->hdrsmd,
2158 pipe_ctx->surface, pipe_ctx->stream);
a33fa99d 2159 }
4562236b 2160
6e4d6bee 2161 patch_gamut_packet_checksum(&info->gamut);
4562236b
HW
2162}
2163
2164enum dc_status resource_map_clock_resources(
2165 const struct core_dc *dc,
2166 struct validate_context *context)
2167{
ab2541b6 2168 int i, j;
a2b8659d 2169 const struct resource_pool *pool = dc->res_pool;
4562236b
HW
2170
2171 /* acquire new resources */
ab2541b6
AC
2172 for (i = 0; i < context->stream_count; i++) {
2173 const struct core_stream *stream = context->streams[i];
4562236b 2174
ab2541b6
AC
2175 if (resource_is_stream_unchanged(dc->current_context, stream))
2176 continue;
2177
2178 for (j = 0; j < MAX_PIPES; j++) {
2179 struct pipe_ctx *pipe_ctx =
2180 &context->res_ctx.pipe_ctx[j];
4562236b 2181
ab2541b6 2182 if (context->res_ctx.pipe_ctx[j].stream != stream)
4562236b
HW
2183 continue;
2184
ab2541b6
AC
2185 if (dc_is_dp_signal(pipe_ctx->stream->signal)
2186 || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL)
a2b8659d 2187 pipe_ctx->clock_source = pool->dp_clock_source;
ab2541b6
AC
2188 else {
2189 pipe_ctx->clock_source = NULL;
4562236b 2190
ab2541b6
AC
2191 if (!dc->public.config.disable_disp_pll_sharing)
2192 resource_find_used_clk_src_for_sharing(
2193 &context->res_ctx,
2194 pipe_ctx);
4562236b 2195
ab2541b6 2196 if (pipe_ctx->clock_source == NULL)
4562236b 2197 pipe_ctx->clock_source =
a2b8659d
TC
2198 dc_resource_find_first_free_pll(
2199 &context->res_ctx,
2200 pool);
ab2541b6 2201 }
4562236b 2202
ab2541b6
AC
2203 if (pipe_ctx->clock_source == NULL)
2204 return DC_NO_CLOCK_SOURCE_RESOURCE;
4562236b 2205
ab2541b6 2206 resource_reference_clock_source(
a2b8659d 2207 &context->res_ctx, pool,
ab2541b6 2208 pipe_ctx->clock_source);
4562236b 2209
ab2541b6
AC
2210 /* only one cs per stream regardless of mpo */
2211 break;
4562236b
HW
2212 }
2213 }
2214
2215 return DC_OK;
2216}
2217
2218/*
2219 * Note: We need to disable output if clock sources change,
2220 * since bios does optimization and doesn't apply if changing
2221 * PHY when not already disabled.
2222 */
2223bool pipe_need_reprogram(
2224 struct pipe_ctx *pipe_ctx_old,
2225 struct pipe_ctx *pipe_ctx)
2226{
2227 if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
2228 return true;
2229
2230 if (pipe_ctx_old->stream->signal != pipe_ctx->stream->signal)
2231 return true;
2232
2233 if (pipe_ctx_old->audio != pipe_ctx->audio)
2234 return true;
2235
2236 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source
2237 && pipe_ctx_old->stream != pipe_ctx->stream)
2238 return true;
2239
2240 if (pipe_ctx_old->stream_enc != pipe_ctx->stream_enc)
2241 return true;
2242
2243 if (is_timing_changed(pipe_ctx_old->stream, pipe_ctx->stream))
2244 return true;
2245
2246
2247 return false;
2248}