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