Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'amd-drm-next-5.6-2020-01-10-dp-mst-dsc' of git://people.freedesktop.org/~agd5f/linux into drm-next

amd-drm-next-5.6-2020-01-10-dp-mst-dsc:

drm:
- Add MST helper for PBN calculation of DSC modes
- Parse FEC caps on MST ports
- Add MST DPCD R/W functions
- Add MST helpers for virtual DPCD aux
- Add MST HUB quirk
- Add MST DSC enablement helpers

amdgpu:
- Enable MST DSC
- Add fair share algo for DSC bandwidth calcs
- Fix for 32 bit builds

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Alex Deucher <alexdeucher@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200110214328.308549-1-alexander.deucher@amd.com

+1031 -51
+114 -7
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 4933 4933 is_y420); 4934 4934 bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; 4935 4935 clock = adjusted_mode->clock; 4936 - dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp); 4936 + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false); 4937 4937 } 4938 4938 dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_vcpi_slots(state, 4939 4939 mst_mgr, 4940 4940 mst_port, 4941 - dm_new_connector_state->pbn); 4941 + dm_new_connector_state->pbn, 4942 + 0); 4942 4943 if (dm_new_connector_state->vcpi_slots < 0) { 4943 4944 DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); 4944 4945 return dm_new_connector_state->vcpi_slots; ··· 4951 4950 .disable = dm_encoder_helper_disable, 4952 4951 .atomic_check = dm_encoder_helper_atomic_check 4953 4952 }; 4953 + 4954 + #if defined(CONFIG_DRM_AMD_DC_DCN) 4955 + static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, 4956 + struct dc_state *dc_state) 4957 + { 4958 + struct dc_stream_state *stream = NULL; 4959 + struct drm_connector *connector; 4960 + struct drm_connector_state *new_con_state, *old_con_state; 4961 + struct amdgpu_dm_connector *aconnector; 4962 + struct dm_connector_state *dm_conn_state; 4963 + int i, j, clock, bpp; 4964 + int vcpi, pbn_div, pbn = 0; 4965 + 4966 + for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { 4967 + 4968 + aconnector = to_amdgpu_dm_connector(connector); 4969 + 4970 + if (!aconnector->port) 4971 + continue; 4972 + 4973 + if (!new_con_state || !new_con_state->crtc) 4974 + continue; 4975 + 4976 + dm_conn_state = to_dm_connector_state(new_con_state); 4977 + 4978 + for (j = 0; j < dc_state->stream_count; j++) { 4979 + stream = dc_state->streams[j]; 4980 + if (!stream) 4981 + continue; 4982 + 4983 + if ((struct amdgpu_dm_connector*)stream->dm_stream_context == aconnector) 4984 + break; 4985 + 4986 + stream = NULL; 4987 + } 4988 + 4989 + if (!stream) 4990 + continue; 4991 + 4992 + if (stream->timing.flags.DSC != 1) { 4993 + drm_dp_mst_atomic_enable_dsc(state, 4994 + aconnector->port, 4995 + dm_conn_state->pbn, 4996 + 0, 4997 + false); 4998 + continue; 4999 + } 5000 + 5001 + pbn_div = dm_mst_get_pbn_divider(stream->link); 5002 + bpp = stream->timing.dsc_cfg.bits_per_pixel; 5003 + clock = stream->timing.pix_clk_100hz / 10; 5004 + pbn = drm_dp_calc_pbn_mode(clock, bpp, true); 5005 + vcpi = drm_dp_mst_atomic_enable_dsc(state, 5006 + aconnector->port, 5007 + pbn, pbn_div, 5008 + true); 5009 + if (vcpi < 0) 5010 + return vcpi; 5011 + 5012 + dm_conn_state->pbn = pbn; 5013 + dm_conn_state->vcpi_slots = vcpi; 5014 + } 5015 + return 0; 5016 + } 5017 + #endif 4954 5018 4955 5019 static void dm_drm_plane_reset(struct drm_plane *plane) 4956 5020 { ··· 7895 7829 return ret; 7896 7830 } 7897 7831 7832 + static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc) 7833 + { 7834 + struct drm_connector *connector; 7835 + struct drm_connector_state *conn_state; 7836 + struct amdgpu_dm_connector *aconnector = NULL; 7837 + int i; 7838 + for_each_new_connector_in_state(state, connector, conn_state, i) { 7839 + if (conn_state->crtc != crtc) 7840 + continue; 7841 + 7842 + aconnector = to_amdgpu_dm_connector(connector); 7843 + if (!aconnector->port || !aconnector->mst_port) 7844 + aconnector = NULL; 7845 + else 7846 + break; 7847 + } 7848 + 7849 + if (!aconnector) 7850 + return 0; 7851 + 7852 + return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_port->mst_mgr); 7853 + } 7854 + 7898 7855 /** 7899 7856 * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM. 7900 7857 * @dev: The DRM device ··· 7969 7880 ret = drm_atomic_helper_check_modeset(dev, state); 7970 7881 if (ret) 7971 7882 goto fail; 7883 + 7884 + if (adev->asic_type >= CHIP_NAVI10) { 7885 + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 7886 + if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { 7887 + ret = add_affected_mst_dsc_crtcs(state, crtc); 7888 + if (ret) 7889 + goto fail; 7890 + } 7891 + } 7892 + } 7972 7893 7973 7894 for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { 7974 7895 if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && ··· 8083 7984 if (ret) 8084 7985 goto fail; 8085 7986 8086 - /* Perform validation of MST topology in the state*/ 8087 - ret = drm_dp_mst_atomic_check(state); 8088 - if (ret) 8089 - goto fail; 8090 - 8091 7987 if (state->legacy_cursor_update) { 8092 7988 /* 8093 7989 * This is a fast cursor update coming from the plane update ··· 8151 8057 if (ret) 8152 8058 goto fail; 8153 8059 8060 + #if defined(CONFIG_DRM_AMD_DC_DCN) 8061 + if (!compute_mst_dsc_configs_for_state(state, dm_state->context)) 8062 + goto fail; 8063 + 8064 + ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context); 8065 + if (ret) 8066 + goto fail; 8067 + #endif 8068 + 8154 8069 if (dc_validate_global_state(dc, dm_state->context, false) != DC_OK) { 8155 8070 ret = -EINVAL; 8156 8071 goto fail; ··· 8188 8085 dc_retain_state(old_dm_state->context); 8189 8086 } 8190 8087 } 8088 + /* Perform validation of MST topology in the state*/ 8089 + ret = drm_dp_mst_atomic_check(state); 8090 + if (ret) 8091 + goto fail; 8191 8092 8192 8093 /* Store the overall update type for use later in atomic check. */ 8193 8094 for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
+1
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 330 330 struct drm_dp_mst_port *port; 331 331 struct amdgpu_dm_connector *mst_port; 332 332 struct amdgpu_encoder *mst_encoder; 333 + struct drm_dp_aux *dsc_aux; 333 334 334 335 /* TODO see if we can merge with ddc_bus or make a dm_connector */ 335 336 struct amdgpu_i2c_adapter *i2c;
+18 -1
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
··· 37 37 #include "dc.h" 38 38 #include "amdgpu_dm.h" 39 39 #include "amdgpu_dm_irq.h" 40 + #include "amdgpu_dm_mst_types.h" 40 41 41 42 #include "dm_helpers.h" 42 43 ··· 517 516 ) 518 517 { 519 518 uint8_t enable_dsc = enable ? 1 : 0; 519 + struct amdgpu_dm_connector *aconnector; 520 520 521 - return dm_helpers_dp_write_dpcd(ctx, stream->sink->link, DP_DSC_ENABLE, &enable_dsc, 1); 521 + if (!stream) 522 + return false; 523 + 524 + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { 525 + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; 526 + 527 + if (!aconnector->dsc_aux) 528 + return false; 529 + 530 + return (drm_dp_dpcd_write(aconnector->dsc_aux, DP_DSC_ENABLE, &enable_dsc, 1) >= 0); 531 + } 532 + 533 + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT) 534 + return dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1); 535 + 536 + return false; 522 537 } 523 538 524 539 bool dm_helpers_is_dp_sink_present(struct dc_link *link)
+419 -1
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
··· 25 25 26 26 #include <linux/version.h> 27 27 #include <drm/drm_atomic_helper.h> 28 + #include <drm/drm_dp_mst_helper.h> 28 29 #include "dm_services.h" 29 30 #include "amdgpu.h" 30 31 #include "amdgpu_dm.h" ··· 40 39 #if defined(CONFIG_DEBUG_FS) 41 40 #include "amdgpu_dm_debugfs.h" 42 41 #endif 42 + 43 + 44 + #if defined(CONFIG_DRM_AMD_DC_DCN) 45 + #include "dc/dcn20/dcn20_resource.h" 46 + #endif 47 + 43 48 /* #define TRACE_DPCD */ 44 49 45 50 #ifdef TRACE_DPCD ··· 187 180 .early_unregister = amdgpu_dm_mst_connector_early_unregister, 188 181 }; 189 182 183 + #if defined(CONFIG_DRM_AMD_DC_DCN) 184 + static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector) 185 + { 186 + struct dc_sink *dc_sink = aconnector->dc_sink; 187 + struct drm_dp_mst_port *port = aconnector->port; 188 + u8 dsc_caps[16] = { 0 }; 189 + 190 + aconnector->dsc_aux = drm_dp_mst_dsc_aux_for_port(port); 191 + 192 + if (!aconnector->dsc_aux) 193 + return false; 194 + 195 + if (drm_dp_dpcd_read(aconnector->dsc_aux, DP_DSC_SUPPORT, dsc_caps, 16) < 0) 196 + return false; 197 + 198 + if (!dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, 199 + dsc_caps, NULL, 200 + &dc_sink->sink_dsc_caps.dsc_dec_caps)) 201 + return false; 202 + 203 + return true; 204 + } 205 + #endif 206 + 190 207 static int dm_dp_mst_get_modes(struct drm_connector *connector) 191 208 { 192 209 struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); ··· 253 222 /* dc_link_add_remote_sink returns a new reference */ 254 223 aconnector->dc_sink = dc_sink; 255 224 256 - if (aconnector->dc_sink) 225 + if (aconnector->dc_sink) { 257 226 amdgpu_dm_update_freesync_caps( 258 227 connector, aconnector->edid); 259 228 229 + #if defined(CONFIG_DRM_AMD_DC_DCN) 230 + if (!validate_dsc_caps_on_connector(aconnector)) 231 + memset(&aconnector->dc_sink->sink_dsc_caps, 232 + 0, sizeof(aconnector->dc_sink->sink_dsc_caps)); 233 + #endif 234 + } 260 235 } 261 236 262 237 drm_connector_update_edid_property( ··· 503 466 aconnector->connector_id); 504 467 } 505 468 469 + int dm_mst_get_pbn_divider(struct dc_link *link) 470 + { 471 + if (!link) 472 + return 0; 473 + 474 + return dc_link_bandwidth_kbps(link, 475 + dc_link_get_link_cap(link)) / (8 * 1000 * 54); 476 + } 477 + 478 + #if defined(CONFIG_DRM_AMD_DC_DCN) 479 + 480 + struct dsc_mst_fairness_params { 481 + struct dc_crtc_timing *timing; 482 + struct dc_sink *sink; 483 + struct dc_dsc_bw_range bw_range; 484 + bool compression_possible; 485 + struct drm_dp_mst_port *port; 486 + }; 487 + 488 + struct dsc_mst_fairness_vars { 489 + int pbn; 490 + bool dsc_enabled; 491 + int bpp_x16; 492 + }; 493 + 494 + static int kbps_to_peak_pbn(int kbps) 495 + { 496 + u64 peak_kbps = kbps; 497 + 498 + peak_kbps *= 1006; 499 + peak_kbps = div_u64(peak_kbps, 1000); 500 + return (int) DIV_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000)); 501 + } 502 + 503 + static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params, 504 + struct dsc_mst_fairness_vars *vars, 505 + int count) 506 + { 507 + int i; 508 + 509 + for (i = 0; i < count; i++) { 510 + memset(&params[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg)); 511 + if (vars[i].dsc_enabled && dc_dsc_compute_config( 512 + params[i].sink->ctx->dc->res_pool->dscs[0], 513 + &params[i].sink->sink_dsc_caps.dsc_dec_caps, 514 + params[i].sink->ctx->dc->debug.dsc_min_slice_height_override, 515 + 0, 516 + params[i].timing, 517 + &params[i].timing->dsc_cfg)) { 518 + params[i].timing->flags.DSC = 1; 519 + params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16; 520 + } else { 521 + params[i].timing->flags.DSC = 0; 522 + } 523 + } 524 + } 525 + 526 + static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) 527 + { 528 + struct dc_dsc_config dsc_config; 529 + u64 kbps; 530 + 531 + kbps = div_u64((u64)pbn * 994 * 8 * 54, 64); 532 + dc_dsc_compute_config( 533 + param.sink->ctx->dc->res_pool->dscs[0], 534 + &param.sink->sink_dsc_caps.dsc_dec_caps, 535 + param.sink->ctx->dc->debug.dsc_min_slice_height_override, 536 + (int) kbps, param.timing, &dsc_config); 537 + 538 + return dsc_config.bits_per_pixel; 539 + } 540 + 541 + static void increase_dsc_bpp(struct drm_atomic_state *state, 542 + struct dc_link *dc_link, 543 + struct dsc_mst_fairness_params *params, 544 + struct dsc_mst_fairness_vars *vars, 545 + int count) 546 + { 547 + int i; 548 + bool bpp_increased[MAX_PIPES]; 549 + int initial_slack[MAX_PIPES]; 550 + int min_initial_slack; 551 + int next_index; 552 + int remaining_to_increase = 0; 553 + int pbn_per_timeslot; 554 + int link_timeslots_used; 555 + int fair_pbn_alloc; 556 + 557 + for (i = 0; i < count; i++) { 558 + if (vars[i].dsc_enabled) { 559 + initial_slack[i] = kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i].pbn; 560 + bpp_increased[i] = false; 561 + remaining_to_increase += 1; 562 + } else { 563 + initial_slack[i] = 0; 564 + bpp_increased[i] = true; 565 + } 566 + } 567 + 568 + pbn_per_timeslot = dc_link_bandwidth_kbps(dc_link, 569 + dc_link_get_link_cap(dc_link)) / (8 * 1000 * 54); 570 + 571 + while (remaining_to_increase) { 572 + next_index = -1; 573 + min_initial_slack = -1; 574 + for (i = 0; i < count; i++) { 575 + if (!bpp_increased[i]) { 576 + if (min_initial_slack == -1 || min_initial_slack > initial_slack[i]) { 577 + min_initial_slack = initial_slack[i]; 578 + next_index = i; 579 + } 580 + } 581 + } 582 + 583 + if (next_index == -1) 584 + break; 585 + 586 + link_timeslots_used = 0; 587 + 588 + for (i = 0; i < count; i++) 589 + link_timeslots_used += DIV_ROUND_UP(vars[i].pbn, pbn_per_timeslot); 590 + 591 + fair_pbn_alloc = (63 - link_timeslots_used) / remaining_to_increase * pbn_per_timeslot; 592 + 593 + if (initial_slack[next_index] > fair_pbn_alloc) { 594 + vars[next_index].pbn += fair_pbn_alloc; 595 + if (drm_dp_atomic_find_vcpi_slots(state, 596 + params[next_index].port->mgr, 597 + params[next_index].port, 598 + vars[next_index].pbn,\ 599 + dm_mst_get_pbn_divider(dc_link)) < 0) 600 + return; 601 + if (!drm_dp_mst_atomic_check(state)) { 602 + vars[next_index].bpp_x16 = bpp_x16_from_pbn(params[next_index], vars[next_index].pbn); 603 + } else { 604 + vars[next_index].pbn -= fair_pbn_alloc; 605 + if (drm_dp_atomic_find_vcpi_slots(state, 606 + params[next_index].port->mgr, 607 + params[next_index].port, 608 + vars[next_index].pbn, 609 + dm_mst_get_pbn_divider(dc_link)) < 0) 610 + return; 611 + } 612 + } else { 613 + vars[next_index].pbn += initial_slack[next_index]; 614 + if (drm_dp_atomic_find_vcpi_slots(state, 615 + params[next_index].port->mgr, 616 + params[next_index].port, 617 + vars[next_index].pbn, 618 + dm_mst_get_pbn_divider(dc_link)) < 0) 619 + return; 620 + if (!drm_dp_mst_atomic_check(state)) { 621 + vars[next_index].bpp_x16 = params[next_index].bw_range.max_target_bpp_x16; 622 + } else { 623 + vars[next_index].pbn -= initial_slack[next_index]; 624 + if (drm_dp_atomic_find_vcpi_slots(state, 625 + params[next_index].port->mgr, 626 + params[next_index].port, 627 + vars[next_index].pbn, 628 + dm_mst_get_pbn_divider(dc_link)) < 0) 629 + return; 630 + } 631 + } 632 + 633 + bpp_increased[next_index] = true; 634 + remaining_to_increase--; 635 + } 636 + } 637 + 638 + static void try_disable_dsc(struct drm_atomic_state *state, 639 + struct dc_link *dc_link, 640 + struct dsc_mst_fairness_params *params, 641 + struct dsc_mst_fairness_vars *vars, 642 + int count) 643 + { 644 + int i; 645 + bool tried[MAX_PIPES]; 646 + int kbps_increase[MAX_PIPES]; 647 + int max_kbps_increase; 648 + int next_index; 649 + int remaining_to_try = 0; 650 + 651 + for (i = 0; i < count; i++) { 652 + if (vars[i].dsc_enabled && vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16) { 653 + kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps; 654 + tried[i] = false; 655 + remaining_to_try += 1; 656 + } else { 657 + kbps_increase[i] = 0; 658 + tried[i] = true; 659 + } 660 + } 661 + 662 + while (remaining_to_try) { 663 + next_index = -1; 664 + max_kbps_increase = -1; 665 + for (i = 0; i < count; i++) { 666 + if (!tried[i]) { 667 + if (max_kbps_increase == -1 || max_kbps_increase < kbps_increase[i]) { 668 + max_kbps_increase = kbps_increase[i]; 669 + next_index = i; 670 + } 671 + } 672 + } 673 + 674 + if (next_index == -1) 675 + break; 676 + 677 + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps); 678 + if (drm_dp_atomic_find_vcpi_slots(state, 679 + params[next_index].port->mgr, 680 + params[next_index].port, 681 + vars[next_index].pbn, 682 + 0) < 0) 683 + return; 684 + 685 + if (!drm_dp_mst_atomic_check(state)) { 686 + vars[next_index].dsc_enabled = false; 687 + vars[next_index].bpp_x16 = 0; 688 + } else { 689 + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps); 690 + if (drm_dp_atomic_find_vcpi_slots(state, 691 + params[next_index].port->mgr, 692 + params[next_index].port, 693 + vars[next_index].pbn, 694 + dm_mst_get_pbn_divider(dc_link)) < 0) 695 + return; 696 + } 697 + 698 + tried[next_index] = true; 699 + remaining_to_try--; 700 + } 701 + } 702 + 703 + static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, 704 + struct dc_state *dc_state, 705 + struct dc_link *dc_link) 706 + { 707 + int i; 708 + struct dc_stream_state *stream; 709 + struct dsc_mst_fairness_params params[MAX_PIPES]; 710 + struct dsc_mst_fairness_vars vars[MAX_PIPES]; 711 + struct amdgpu_dm_connector *aconnector; 712 + int count = 0; 713 + 714 + memset(params, 0, sizeof(params)); 715 + 716 + /* Set up params */ 717 + for (i = 0; i < dc_state->stream_count; i++) { 718 + struct dc_dsc_policy dsc_policy = {0}; 719 + 720 + stream = dc_state->streams[i]; 721 + 722 + if (stream->link != dc_link) 723 + continue; 724 + 725 + stream->timing.flags.DSC = 0; 726 + 727 + params[count].timing = &stream->timing; 728 + params[count].sink = stream->sink; 729 + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; 730 + params[count].port = aconnector->port; 731 + params[count].compression_possible = stream->sink->sink_dsc_caps.dsc_dec_caps.is_dsc_supported; 732 + dc_dsc_get_policy_for_timing(params[count].timing, &dsc_policy); 733 + if (!dc_dsc_compute_bandwidth_range( 734 + stream->sink->ctx->dc->res_pool->dscs[0], 735 + stream->sink->ctx->dc->debug.dsc_min_slice_height_override, 736 + dsc_policy.min_target_bpp, 737 + dsc_policy.max_target_bpp, 738 + &stream->sink->sink_dsc_caps.dsc_dec_caps, 739 + &stream->timing, &params[count].bw_range)) 740 + params[count].bw_range.stream_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing); 741 + 742 + count++; 743 + } 744 + /* Try no compression */ 745 + for (i = 0; i < count; i++) { 746 + vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); 747 + vars[i].dsc_enabled = false; 748 + vars[i].bpp_x16 = 0; 749 + if (drm_dp_atomic_find_vcpi_slots(state, 750 + params[i].port->mgr, 751 + params[i].port, 752 + vars[i].pbn, 753 + 0) < 0) 754 + return false; 755 + } 756 + if (!drm_dp_mst_atomic_check(state)) { 757 + set_dsc_configs_from_fairness_vars(params, vars, count); 758 + return true; 759 + } 760 + 761 + /* Try max compression */ 762 + for (i = 0; i < count; i++) { 763 + if (params[i].compression_possible) { 764 + vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps); 765 + vars[i].dsc_enabled = true; 766 + vars[i].bpp_x16 = params[i].bw_range.min_target_bpp_x16; 767 + if (drm_dp_atomic_find_vcpi_slots(state, 768 + params[i].port->mgr, 769 + params[i].port, 770 + vars[i].pbn, 771 + dm_mst_get_pbn_divider(dc_link)) < 0) 772 + return false; 773 + } else { 774 + vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); 775 + vars[i].dsc_enabled = false; 776 + vars[i].bpp_x16 = 0; 777 + if (drm_dp_atomic_find_vcpi_slots(state, 778 + params[i].port->mgr, 779 + params[i].port, 780 + vars[i].pbn, 781 + 0) < 0) 782 + return false; 783 + } 784 + } 785 + if (drm_dp_mst_atomic_check(state)) 786 + return false; 787 + 788 + /* Optimize degree of compression */ 789 + increase_dsc_bpp(state, dc_link, params, vars, count); 790 + 791 + try_disable_dsc(state, dc_link, params, vars, count); 792 + 793 + set_dsc_configs_from_fairness_vars(params, vars, count); 794 + 795 + return true; 796 + } 797 + 798 + bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, 799 + struct dc_state *dc_state) 800 + { 801 + int i, j; 802 + struct dc_stream_state *stream; 803 + bool computed_streams[MAX_PIPES]; 804 + struct amdgpu_dm_connector *aconnector; 805 + 806 + for (i = 0; i < dc_state->stream_count; i++) 807 + computed_streams[i] = false; 808 + 809 + for (i = 0; i < dc_state->stream_count; i++) { 810 + stream = dc_state->streams[i]; 811 + 812 + if (stream->signal != SIGNAL_TYPE_DISPLAY_PORT_MST) 813 + continue; 814 + 815 + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; 816 + 817 + if (!aconnector || !aconnector->dc_sink) 818 + continue; 819 + 820 + if (!aconnector->dc_sink->sink_dsc_caps.dsc_dec_caps.is_dsc_supported) 821 + continue; 822 + 823 + if (computed_streams[i]) 824 + continue; 825 + 826 + mutex_lock(&aconnector->mst_mgr.lock); 827 + if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link)) { 828 + mutex_unlock(&aconnector->mst_mgr.lock); 829 + return false; 830 + } 831 + mutex_unlock(&aconnector->mst_mgr.lock); 832 + 833 + for (j = 0; j < dc_state->stream_count; j++) { 834 + if (dc_state->streams[j]->link == stream->link) 835 + computed_streams[j] = true; 836 + } 837 + } 838 + 839 + for (i = 0; i < dc_state->stream_count; i++) { 840 + stream = dc_state->streams[i]; 841 + 842 + if (stream->timing.flags.DSC == 1) 843 + dcn20_add_dsc_to_stream_resource(stream->ctx->dc, dc_state, stream); 844 + } 845 + 846 + return true; 847 + } 848 + 849 + #endif
+7
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
··· 29 29 struct amdgpu_display_manager; 30 30 struct amdgpu_dm_connector; 31 31 32 + int dm_mst_get_pbn_divider(struct dc_link *link); 33 + 32 34 void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, 33 35 struct amdgpu_dm_connector *aconnector); 36 + 37 + #if defined(CONFIG_DRM_AMD_DC_DCN) 38 + bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, 39 + struct dc_state *dc_state); 40 + #endif 34 41 35 42 #endif
+3
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
··· 206 206 struct dsc_reg_values dsc_reg_vals; 207 207 struct dsc_optc_config dsc_optc_cfg; 208 208 209 + memset(&dsc_reg_vals, 0, sizeof(dsc_reg_vals)); 210 + memset(&dsc_optc_cfg, 0, sizeof(dsc_optc_cfg)); 211 + 209 212 DC_LOG_DSC("Getting packed DSC PPS for DSC Config:"); 210 213 dsc_config_log(dsc, dsc_cfg); 211 214 DC_LOG_DSC("DSC Picture Parameter Set (PPS):");
+5 -2
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
··· 1569 1569 1570 1570 1571 1571 1572 - static enum dc_status add_dsc_to_stream_resource(struct dc *dc, 1572 + enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, 1573 1573 struct dc_state *dc_ctx, 1574 1574 struct dc_stream_state *dc_stream) 1575 1575 { ··· 1582 1582 struct pipe_ctx *pipe_ctx = &dc_ctx->res_ctx.pipe_ctx[i]; 1583 1583 1584 1584 if (pipe_ctx->stream != dc_stream) 1585 + continue; 1586 + 1587 + if (pipe_ctx->stream_res.dsc) 1585 1588 continue; 1586 1589 1587 1590 acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc, i); ··· 1635 1632 1636 1633 /* Get a DSC if required and available */ 1637 1634 if (result == DC_OK && dc_stream->timing.flags.DSC) 1638 - result = add_dsc_to_stream_resource(dc, new_ctx, dc_stream); 1635 + result = dcn20_add_dsc_to_stream_resource(dc, new_ctx, dc_stream); 1639 1636 1640 1637 if (result == DC_OK) 1641 1638 result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream);
+1
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
··· 157 157 158 158 enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); 159 159 enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); 160 + enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, struct dc_state *dc_ctx, struct dc_stream_state *dc_stream); 160 161 enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); 161 162 enum dc_status dcn20_get_default_swizzle_mode(struct dc_plane_state *plane_state); 162 163
+2 -10
drivers/gpu/drm/drm_dp_aux_dev.c
··· 163 163 break; 164 164 } 165 165 166 - if (aux_dev->aux->is_remote) 167 - res = drm_dp_mst_dpcd_read(aux_dev->aux, pos, buf, 168 - todo); 169 - else 170 - res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); 166 + res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); 171 167 172 168 if (res <= 0) 173 169 break; ··· 211 215 break; 212 216 } 213 217 214 - if (aux_dev->aux->is_remote) 215 - res = drm_dp_mst_dpcd_write(aux_dev->aux, pos, buf, 216 - todo); 217 - else 218 - res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); 218 + res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); 219 219 220 220 if (res <= 0) 221 221 break;
+35 -10
drivers/gpu/drm/drm_dp_helper.c
··· 32 32 #include <drm/drm_dp_helper.h> 33 33 #include <drm/drm_print.h> 34 34 #include <drm/drm_vblank.h> 35 + #include <drm/drm_dp_mst_helper.h> 35 36 36 37 #include "drm_crtc_helper_internal.h" 37 38 ··· 267 266 268 267 /** 269 268 * drm_dp_dpcd_read() - read a series of bytes from the DPCD 270 - * @aux: DisplayPort AUX channel 269 + * @aux: DisplayPort AUX channel (SST or MST) 271 270 * @offset: address of the (first) register to read 272 271 * @buffer: buffer to store the register values 273 272 * @size: number of bytes in @buffer ··· 296 295 * We just have to do it before any DPCD access and hope that the 297 296 * monitor doesn't power down exactly after the throw away read. 298 297 */ 299 - ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, buffer, 300 - 1); 301 - if (ret != 1) 302 - goto out; 298 + if (!aux->is_remote) { 299 + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, 300 + buffer, 1); 301 + if (ret != 1) 302 + goto out; 303 + } 303 304 304 - ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, 305 - size); 305 + if (aux->is_remote) 306 + ret = drm_dp_mst_dpcd_read(aux, offset, buffer, size); 307 + else 308 + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, 309 + buffer, size); 306 310 307 311 out: 308 312 drm_dp_dump_access(aux, DP_AUX_NATIVE_READ, offset, buffer, ret); ··· 317 311 318 312 /** 319 313 * drm_dp_dpcd_write() - write a series of bytes to the DPCD 320 - * @aux: DisplayPort AUX channel 314 + * @aux: DisplayPort AUX channel (SST or MST) 321 315 * @offset: address of the (first) register to write 322 316 * @buffer: buffer containing the values to write 323 317 * @size: number of bytes in @buffer ··· 334 328 { 335 329 int ret; 336 330 337 - ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, 338 - size); 331 + if (aux->is_remote) 332 + ret = drm_dp_mst_dpcd_write(aux, offset, buffer, size); 333 + else 334 + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, 335 + buffer, size); 336 + 339 337 drm_dp_dump_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, ret); 340 338 return ret; 341 339 } ··· 979 969 } 980 970 981 971 /** 972 + * drm_dp_remote_aux_init() - minimally initialise a remote aux channel 973 + * @aux: DisplayPort AUX channel 974 + * 975 + * Used for remote aux channel in general. Merely initialize the crc work 976 + * struct. 977 + */ 978 + void drm_dp_remote_aux_init(struct drm_dp_aux *aux) 979 + { 980 + INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work); 981 + } 982 + EXPORT_SYMBOL(drm_dp_remote_aux_init); 983 + 984 + /** 982 985 * drm_dp_aux_init() - minimally initialise an aux channel 983 986 * @aux: DisplayPort AUX channel 984 987 * ··· 1178 1155 { OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) }, 1179 1156 /* CH7511 seems to leave SINK_COUNT zeroed */ 1180 1157 { OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) }, 1158 + /* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */ 1159 + { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) }, 1181 1160 }; 1182 1161 1183 1162 #undef OUI
+384 -8
drivers/gpu/drm/drm_dp_mst_topology.c
··· 853 853 { 854 854 int idx = 1; 855 855 repmsg->u.path_resources.port_number = (raw->msg[idx] >> 4) & 0xf; 856 + repmsg->u.path_resources.fec_capable = raw->msg[idx] & 0x1; 856 857 idx++; 857 858 if (idx > raw->curlen) 858 859 goto fail_len; ··· 2175 2174 struct drm_dp_mst_port *port) 2176 2175 { 2177 2176 mutex_lock(&mgr->lock); 2177 + port->parent->num_ports--; 2178 2178 list_del(&port->next); 2179 2179 mutex_unlock(&mgr->lock); 2180 2180 drm_dp_mst_topology_put_port(port); ··· 2199 2197 port->aux.name = "DPMST"; 2200 2198 port->aux.dev = dev->dev; 2201 2199 port->aux.is_remote = true; 2200 + 2201 + /* initialize the MST downstream port's AUX crc work queue */ 2202 + drm_dp_remote_aux_init(&port->aux); 2202 2203 2203 2204 /* 2204 2205 * Make sure the memory allocation for our parent branch stays ··· 2278 2273 mutex_lock(&mgr->lock); 2279 2274 drm_dp_mst_topology_get_port(port); 2280 2275 list_add(&port->next, &mstb->ports); 2276 + mstb->num_ports++; 2281 2277 mutex_unlock(&mgr->lock); 2282 2278 } 2283 2279 ··· 2957 2951 path_res->avail_payload_bw_number); 2958 2952 port->available_pbn = 2959 2953 path_res->avail_payload_bw_number; 2954 + port->fec_capable = path_res->fec_capable; 2960 2955 } 2961 2956 } 2962 2957 ··· 4096 4089 * @mgr: MST topology manager for the port 4097 4090 * @port: port to find vcpi slots for 4098 4091 * @pbn: bandwidth required for the mode in PBN 4092 + * @pbn_div: divider for DSC mode that takes FEC into account 4099 4093 * 4100 4094 * Allocates VCPI slots to @port, replacing any previous VCPI allocations it 4101 4095 * may have had. Any atomic drivers which support MST must call this function ··· 4123 4115 */ 4124 4116 int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, 4125 4117 struct drm_dp_mst_topology_mgr *mgr, 4126 - struct drm_dp_mst_port *port, int pbn) 4118 + struct drm_dp_mst_port *port, int pbn, 4119 + int pbn_div) 4127 4120 { 4128 4121 struct drm_dp_mst_topology_state *topology_state; 4129 4122 struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; 4130 - int prev_slots, req_slots; 4123 + int prev_slots, prev_bw, req_slots; 4131 4124 4132 4125 topology_state = drm_atomic_get_mst_topology_state(state, mgr); 4133 4126 if (IS_ERR(topology_state)) ··· 4139 4130 if (pos->port == port) { 4140 4131 vcpi = pos; 4141 4132 prev_slots = vcpi->vcpi; 4133 + prev_bw = vcpi->pbn; 4142 4134 4143 4135 /* 4144 4136 * This should never happen, unless the driver tries ··· 4155 4145 break; 4156 4146 } 4157 4147 } 4158 - if (!vcpi) 4148 + if (!vcpi) { 4159 4149 prev_slots = 0; 4150 + prev_bw = 0; 4151 + } 4160 4152 4161 - req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); 4153 + if (pbn_div <= 0) 4154 + pbn_div = mgr->pbn_div; 4155 + 4156 + req_slots = DIV_ROUND_UP(pbn, pbn_div); 4162 4157 4163 4158 DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", 4164 4159 port->connector->base.id, port->connector->name, 4165 4160 port, prev_slots, req_slots); 4161 + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] PBN %d -> %d\n", 4162 + port->connector->base.id, port->connector->name, 4163 + port, prev_bw, pbn); 4166 4164 4167 4165 /* Add the new allocation to the state */ 4168 4166 if (!vcpi) { ··· 4183 4165 list_add(&vcpi->next, &topology_state->vcpis); 4184 4166 } 4185 4167 vcpi->vcpi = req_slots; 4168 + vcpi->pbn = pbn; 4186 4169 4187 4170 return req_slots; 4188 4171 } ··· 4434 4415 * drm_dp_calc_pbn_mode() - Calculate the PBN for a mode. 4435 4416 * @clock: dot clock for the mode 4436 4417 * @bpp: bpp for the mode. 4418 + * @dsc: DSC mode. If true, bpp has units of 1/16 of a bit per pixel 4437 4419 * 4438 4420 * This uses the formula in the spec to calculate the PBN value for a mode. 4439 4421 */ 4440 - int drm_dp_calc_pbn_mode(int clock, int bpp) 4422 + int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc) 4441 4423 { 4442 4424 /* 4443 4425 * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 ··· 4449 4429 * peak_kbps *= (1006/1000) 4450 4430 * peak_kbps *= (64/54) 4451 4431 * peak_kbps *= 8 convert to bytes 4432 + * 4433 + * If the bpp is in units of 1/16, further divide by 16. Put this 4434 + * factor in the numerator rather than the denominator to avoid 4435 + * integer overflow 4452 4436 */ 4437 + 4438 + if (dsc) 4439 + return DIV_ROUND_UP_ULL(mul_u32_u32(clock * (bpp / 16), 64 * 1006), 4440 + 8 * 54 * 1000 * 1000); 4441 + 4453 4442 return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006), 4454 4443 8 * 54 * 1000 * 1000); 4455 4444 } ··· 4760 4731 kfree(mst_state); 4761 4732 } 4762 4733 4734 + static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port, 4735 + struct drm_dp_mst_branch *branch) 4736 + { 4737 + while (port->parent) { 4738 + if (port->parent == branch) 4739 + return true; 4740 + 4741 + if (port->parent->port_parent) 4742 + port = port->parent->port_parent; 4743 + else 4744 + break; 4745 + } 4746 + return false; 4747 + } 4748 + 4749 + static inline 4750 + int drm_dp_mst_atomic_check_bw_limit(struct drm_dp_mst_branch *branch, 4751 + struct drm_dp_mst_topology_state *mst_state) 4752 + { 4753 + struct drm_dp_mst_port *port; 4754 + struct drm_dp_vcpi_allocation *vcpi; 4755 + int pbn_limit = 0, pbn_used = 0; 4756 + 4757 + list_for_each_entry(port, &branch->ports, next) { 4758 + if (port->mstb) 4759 + if (drm_dp_mst_atomic_check_bw_limit(port->mstb, mst_state)) 4760 + return -ENOSPC; 4761 + 4762 + if (port->available_pbn > 0) 4763 + pbn_limit = port->available_pbn; 4764 + } 4765 + DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch has %d PBN available\n", 4766 + branch, pbn_limit); 4767 + 4768 + list_for_each_entry(vcpi, &mst_state->vcpis, next) { 4769 + if (!vcpi->pbn) 4770 + continue; 4771 + 4772 + if (drm_dp_mst_port_downstream_of_branch(vcpi->port, branch)) 4773 + pbn_used += vcpi->pbn; 4774 + } 4775 + DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch used %d PBN\n", 4776 + branch, pbn_used); 4777 + 4778 + if (pbn_used > pbn_limit) { 4779 + DRM_DEBUG_ATOMIC("[MST BRANCH:%p] No available bandwidth\n", 4780 + branch); 4781 + return -ENOSPC; 4782 + } 4783 + return 0; 4784 + } 4785 + 4763 4786 static inline int 4764 - drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, 4765 - struct drm_dp_mst_topology_state *mst_state) 4787 + drm_dp_mst_atomic_check_vcpi_alloc_limit(struct drm_dp_mst_topology_mgr *mgr, 4788 + struct drm_dp_mst_topology_state *mst_state) 4766 4789 { 4767 4790 struct drm_dp_vcpi_allocation *vcpi; 4768 4791 int avail_slots = 63, payload_count = 0; ··· 4852 4771 } 4853 4772 4854 4773 /** 4774 + * drm_dp_mst_add_affected_dsc_crtcs 4775 + * @state: Pointer to the new struct drm_dp_mst_topology_state 4776 + * @mgr: MST topology manager 4777 + * 4778 + * Whenever there is a change in mst topology 4779 + * DSC configuration would have to be recalculated 4780 + * therefore we need to trigger modeset on all affected 4781 + * CRTCs in that topology 4782 + * 4783 + * See also: 4784 + * drm_dp_mst_atomic_enable_dsc() 4785 + */ 4786 + int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr) 4787 + { 4788 + struct drm_dp_mst_topology_state *mst_state; 4789 + struct drm_dp_vcpi_allocation *pos; 4790 + struct drm_connector *connector; 4791 + struct drm_connector_state *conn_state; 4792 + struct drm_crtc *crtc; 4793 + struct drm_crtc_state *crtc_state; 4794 + 4795 + mst_state = drm_atomic_get_mst_topology_state(state, mgr); 4796 + 4797 + if (IS_ERR(mst_state)) 4798 + return -EINVAL; 4799 + 4800 + list_for_each_entry(pos, &mst_state->vcpis, next) { 4801 + 4802 + connector = pos->port->connector; 4803 + 4804 + if (!connector) 4805 + return -EINVAL; 4806 + 4807 + conn_state = drm_atomic_get_connector_state(state, connector); 4808 + 4809 + if (IS_ERR(conn_state)) 4810 + return PTR_ERR(conn_state); 4811 + 4812 + crtc = conn_state->crtc; 4813 + 4814 + if (WARN_ON(!crtc)) 4815 + return -EINVAL; 4816 + 4817 + if (!drm_dp_mst_dsc_aux_for_port(pos->port)) 4818 + continue; 4819 + 4820 + crtc_state = drm_atomic_get_crtc_state(mst_state->base.state, crtc); 4821 + 4822 + if (IS_ERR(crtc_state)) 4823 + return PTR_ERR(crtc_state); 4824 + 4825 + DRM_DEBUG_ATOMIC("[MST MGR:%p] Setting mode_changed flag on CRTC %p\n", 4826 + mgr, crtc); 4827 + 4828 + crtc_state->mode_changed = true; 4829 + } 4830 + return 0; 4831 + } 4832 + EXPORT_SYMBOL(drm_dp_mst_add_affected_dsc_crtcs); 4833 + 4834 + /** 4835 + * drm_dp_mst_atomic_enable_dsc - Set DSC Enable Flag to On/Off 4836 + * @state: Pointer to the new drm_atomic_state 4837 + * @port: Pointer to the affected MST Port 4838 + * @pbn: Newly recalculated bw required for link with DSC enabled 4839 + * @pbn_div: Divider to calculate correct number of pbn per slot 4840 + * @enable: Boolean flag to enable or disable DSC on the port 4841 + * 4842 + * This function enables DSC on the given Port 4843 + * by recalculating its vcpi from pbn provided 4844 + * and sets dsc_enable flag to keep track of which 4845 + * ports have DSC enabled 4846 + * 4847 + */ 4848 + int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, 4849 + struct drm_dp_mst_port *port, 4850 + int pbn, int pbn_div, 4851 + bool enable) 4852 + { 4853 + struct drm_dp_mst_topology_state *mst_state; 4854 + struct drm_dp_vcpi_allocation *pos; 4855 + bool found = false; 4856 + int vcpi = 0; 4857 + 4858 + mst_state = drm_atomic_get_mst_topology_state(state, port->mgr); 4859 + 4860 + if (IS_ERR(mst_state)) 4861 + return PTR_ERR(mst_state); 4862 + 4863 + list_for_each_entry(pos, &mst_state->vcpis, next) { 4864 + if (pos->port == port) { 4865 + found = true; 4866 + break; 4867 + } 4868 + } 4869 + 4870 + if (!found) { 4871 + DRM_DEBUG_ATOMIC("[MST PORT:%p] Couldn't find VCPI allocation in mst state %p\n", 4872 + port, mst_state); 4873 + return -EINVAL; 4874 + } 4875 + 4876 + if (pos->dsc_enabled == enable) { 4877 + DRM_DEBUG_ATOMIC("[MST PORT:%p] DSC flag is already set to %d, returning %d VCPI slots\n", 4878 + port, enable, pos->vcpi); 4879 + vcpi = pos->vcpi; 4880 + } 4881 + 4882 + if (enable) { 4883 + vcpi = drm_dp_atomic_find_vcpi_slots(state, port->mgr, port, pbn, pbn_div); 4884 + DRM_DEBUG_ATOMIC("[MST PORT:%p] Enabling DSC flag, reallocating %d VCPI slots on the port\n", 4885 + port, vcpi); 4886 + if (vcpi < 0) 4887 + return -EINVAL; 4888 + } 4889 + 4890 + pos->dsc_enabled = enable; 4891 + 4892 + return vcpi; 4893 + } 4894 + EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); 4895 + /** 4855 4896 * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an 4856 4897 * atomic update is valid 4857 4898 * @state: Pointer to the new &struct drm_dp_mst_topology_state ··· 5001 4798 int i, ret = 0; 5002 4799 5003 4800 for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { 5004 - ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state); 4801 + ret = drm_dp_mst_atomic_check_vcpi_alloc_limit(mgr, mst_state); 4802 + if (ret) 4803 + break; 4804 + ret = drm_dp_mst_atomic_check_bw_limit(mgr->mst_primary, mst_state); 5005 4805 if (ret) 5006 4806 break; 5007 4807 } ··· 5268 5062 { 5269 5063 i2c_del_adapter(&aux->ddc); 5270 5064 } 5065 + 5066 + /** 5067 + * drm_dp_mst_is_virtual_dpcd() - Is the given port a virtual DP Peer Device 5068 + * @port: The port to check 5069 + * 5070 + * A single physical MST hub object can be represented in the topology 5071 + * by multiple branches, with virtual ports between those branches. 5072 + * 5073 + * As of DP1.4, An MST hub with internal (virtual) ports must expose 5074 + * certain DPCD registers over those ports. See sections 2.6.1.1.1 5075 + * and 2.6.1.1.2 of Display Port specification v1.4 for details. 5076 + * 5077 + * May acquire mgr->lock 5078 + * 5079 + * Returns: 5080 + * true if the port is a virtual DP peer device, false otherwise 5081 + */ 5082 + static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port) 5083 + { 5084 + struct drm_dp_mst_port *downstream_port; 5085 + 5086 + if (!port || port->dpcd_rev < DP_DPCD_REV_14) 5087 + return false; 5088 + 5089 + /* Virtual DP Sink (Internal Display Panel) */ 5090 + if (port->port_num >= 8) 5091 + return true; 5092 + 5093 + /* DP-to-HDMI Protocol Converter */ 5094 + if (port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV && 5095 + !port->mcs && 5096 + port->ldps) 5097 + return true; 5098 + 5099 + /* DP-to-DP */ 5100 + mutex_lock(&port->mgr->lock); 5101 + if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING && 5102 + port->mstb && 5103 + port->mstb->num_ports == 2) { 5104 + list_for_each_entry(downstream_port, &port->mstb->ports, next) { 5105 + if (downstream_port->pdt == DP_PEER_DEVICE_SST_SINK && 5106 + !downstream_port->input) { 5107 + mutex_unlock(&port->mgr->lock); 5108 + return true; 5109 + } 5110 + } 5111 + } 5112 + mutex_unlock(&port->mgr->lock); 5113 + 5114 + return false; 5115 + } 5116 + 5117 + /** 5118 + * drm_dp_mst_dsc_aux_for_port() - Find the correct aux for DSC 5119 + * @port: The port to check. A leaf of the MST tree with an attached display. 5120 + * 5121 + * Depending on the situation, DSC may be enabled via the endpoint aux, 5122 + * the immediately upstream aux, or the connector's physical aux. 5123 + * 5124 + * This is both the correct aux to read DSC_CAPABILITY and the 5125 + * correct aux to write DSC_ENABLED. 5126 + * 5127 + * This operation can be expensive (up to four aux reads), so 5128 + * the caller should cache the return. 5129 + * 5130 + * Returns: 5131 + * NULL if DSC cannot be enabled on this port, otherwise the aux device 5132 + */ 5133 + struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) 5134 + { 5135 + struct drm_dp_mst_port *immediate_upstream_port; 5136 + struct drm_dp_mst_port *fec_port; 5137 + struct drm_dp_desc desc = { 0 }; 5138 + u8 endpoint_fec; 5139 + u8 endpoint_dsc; 5140 + 5141 + if (!port) 5142 + return NULL; 5143 + 5144 + if (port->parent->port_parent) 5145 + immediate_upstream_port = port->parent->port_parent; 5146 + else 5147 + immediate_upstream_port = NULL; 5148 + 5149 + fec_port = immediate_upstream_port; 5150 + while (fec_port) { 5151 + /* 5152 + * Each physical link (i.e. not a virtual port) between the 5153 + * output and the primary device must support FEC 5154 + */ 5155 + if (!drm_dp_mst_is_virtual_dpcd(fec_port) && 5156 + !fec_port->fec_capable) 5157 + return NULL; 5158 + 5159 + fec_port = fec_port->parent->port_parent; 5160 + } 5161 + 5162 + /* DP-to-DP peer device */ 5163 + if (drm_dp_mst_is_virtual_dpcd(immediate_upstream_port)) { 5164 + u8 upstream_dsc; 5165 + 5166 + if (drm_dp_dpcd_read(&port->aux, 5167 + DP_DSC_SUPPORT, &endpoint_dsc, 1) != 1) 5168 + return NULL; 5169 + if (drm_dp_dpcd_read(&port->aux, 5170 + DP_FEC_CAPABILITY, &endpoint_fec, 1) != 1) 5171 + return NULL; 5172 + if (drm_dp_dpcd_read(&immediate_upstream_port->aux, 5173 + DP_DSC_SUPPORT, &upstream_dsc, 1) != 1) 5174 + return NULL; 5175 + 5176 + /* Enpoint decompression with DP-to-DP peer device */ 5177 + if ((endpoint_dsc & DP_DSC_DECOMPRESSION_IS_SUPPORTED) && 5178 + (endpoint_fec & DP_FEC_CAPABLE) && 5179 + (upstream_dsc & 0x2) /* DSC passthrough */) 5180 + return &port->aux; 5181 + 5182 + /* Virtual DPCD decompression with DP-to-DP peer device */ 5183 + return &immediate_upstream_port->aux; 5184 + } 5185 + 5186 + /* Virtual DPCD decompression with DP-to-HDMI or Virtual DP Sink */ 5187 + if (drm_dp_mst_is_virtual_dpcd(port)) 5188 + return &port->aux; 5189 + 5190 + /* 5191 + * Synaptics quirk 5192 + * Applies to ports for which: 5193 + * - Physical aux has Synaptics OUI 5194 + * - DPv1.4 or higher 5195 + * - Port is on primary branch device 5196 + * - Not a VGA adapter (DP_DWN_STRM_PORT_TYPE_ANALOG) 5197 + */ 5198 + if (drm_dp_read_desc(port->mgr->aux, &desc, true)) 5199 + return NULL; 5200 + 5201 + if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && 5202 + port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && 5203 + port->parent == port->mgr->mst_primary) { 5204 + u8 downstreamport; 5205 + 5206 + if (drm_dp_dpcd_read(&port->aux, DP_DOWNSTREAMPORT_PRESENT, 5207 + &downstreamport, 1) < 0) 5208 + return NULL; 5209 + 5210 + if ((downstreamport & DP_DWN_STRM_PORT_PRESENT) && 5211 + ((downstreamport & DP_DWN_STRM_PORT_TYPE_MASK) 5212 + != DP_DWN_STRM_PORT_TYPE_ANALOG)) 5213 + return port->mgr->aux; 5214 + } 5215 + 5216 + /* 5217 + * The check below verifies if the MST sink 5218 + * connected to the GPU is capable of DSC - 5219 + * therefore the endpoint needs to be 5220 + * both DSC and FEC capable. 5221 + */ 5222 + if (drm_dp_dpcd_read(&port->aux, 5223 + DP_DSC_SUPPORT, &endpoint_dsc, 1) != 1) 5224 + return NULL; 5225 + if (drm_dp_dpcd_read(&port->aux, 5226 + DP_FEC_CAPABILITY, &endpoint_fec, 1) != 1) 5227 + return NULL; 5228 + if ((endpoint_dsc & DP_DSC_DECOMPRESSION_IS_SUPPORTED) && 5229 + (endpoint_fec & DP_FEC_CAPABLE)) 5230 + return &port->aux; 5231 + 5232 + return NULL; 5233 + } 5234 + EXPORT_SYMBOL(drm_dp_mst_dsc_aux_for_port);
+3 -2
drivers/gpu/drm/i915/display/intel_dp_mst.c
··· 61 61 crtc_state->pipe_bpp = bpp; 62 62 63 63 crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, 64 - crtc_state->pipe_bpp); 64 + crtc_state->pipe_bpp, 65 + false); 65 66 66 67 slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, 67 - port, crtc_state->pbn); 68 + port, crtc_state->pbn, 0); 68 69 if (slots == -EDEADLK) 69 70 return slots; 70 71 if (slots >= 0)
+2 -2
drivers/gpu/drm/nouveau/dispnv50/disp.c
··· 806 806 * topology 807 807 */ 808 808 asyh->or.bpc = min(connector->display_info.bpc, 8U); 809 - asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3); 809 + asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3, false); 810 810 } 811 811 812 812 slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port, 813 - asyh->dp.pbn); 813 + asyh->dp.pbn, 0); 814 814 if (slots < 0) 815 815 return slots; 816 816
+1 -1
drivers/gpu/drm/radeon/radeon_dp_mst.c
··· 518 518 519 519 mst_enc = radeon_encoder->enc_priv; 520 520 521 - mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp); 521 + mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp, false); 522 522 523 523 mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices; 524 524 DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
+8 -4
drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
··· 18 18 int rate; 19 19 int bpp; 20 20 int expected; 21 + bool dsc; 21 22 } test_params[] = { 22 - { 154000, 30, 689 }, 23 - { 234000, 30, 1047 }, 24 - { 297000, 24, 1063 }, 23 + { 154000, 30, 689, false }, 24 + { 234000, 30, 1047, false }, 25 + { 297000, 24, 1063, false }, 26 + { 332880, 24, 50, true }, 27 + { 324540, 24, 49, true }, 25 28 }; 26 29 27 30 for (i = 0; i < ARRAY_SIZE(test_params); i++) { 28 31 pbn = drm_dp_calc_pbn_mode(test_params[i].rate, 29 - test_params[i].bpp); 32 + test_params[i].bpp, 33 + test_params[i].dsc); 30 34 FAIL(pbn != test_params[i].expected, 31 35 "Expected PBN %d for clock %d bpp %d, got %d\n", 32 36 test_params[i].expected, test_params[i].rate,
+8
include/drm/drm_dp_helper.h
··· 1465 1465 void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], 1466 1466 const u8 port_cap[4], struct drm_dp_aux *aux); 1467 1467 1468 + void drm_dp_remote_aux_init(struct drm_dp_aux *aux); 1468 1469 void drm_dp_aux_init(struct drm_dp_aux *aux); 1469 1470 int drm_dp_aux_register(struct drm_dp_aux *aux); 1470 1471 void drm_dp_aux_unregister(struct drm_dp_aux *aux); ··· 1523 1522 * The driver should ignore SINK_COUNT during detection. 1524 1523 */ 1525 1524 DP_DPCD_QUIRK_NO_SINK_COUNT, 1525 + /** 1526 + * @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD: 1527 + * 1528 + * The device supports MST DSC despite not supporting Virtual DPCD. 1529 + * The DSC caps can be read from the physical aux instead. 1530 + */ 1531 + DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD, 1526 1532 }; 1527 1533 1528 1534 /**
+17 -3
include/drm/drm_dp_mst_helper.h
··· 156 156 * audio-capable. 157 157 */ 158 158 bool has_audio; 159 + 160 + bool fec_capable; 159 161 }; 160 162 161 163 /** ··· 385 383 386 384 struct drm_dp_enum_path_resources_ack_reply { 387 385 u8 port_number; 386 + bool fec_capable; 388 387 u16 full_payload_bw_number; 389 388 u16 avail_payload_bw_number; 390 389 }; ··· 502 499 struct drm_dp_vcpi_allocation { 503 500 struct drm_dp_mst_port *port; 504 501 int vcpi; 502 + int pbn; 503 + bool dsc_enabled; 505 504 struct list_head next; 506 505 }; 507 506 ··· 732 727 struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); 733 728 734 729 735 - int drm_dp_calc_pbn_mode(int clock, int bpp); 736 - 730 + int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); 737 731 738 732 bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, 739 733 struct drm_dp_mst_port *port, int pbn, int slots); ··· 781 777 int __must_check 782 778 drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, 783 779 struct drm_dp_mst_topology_mgr *mgr, 784 - struct drm_dp_mst_port *port, int pbn); 780 + struct drm_dp_mst_port *port, int pbn, 781 + int pbn_div); 782 + int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, 783 + struct drm_dp_mst_port *port, 784 + int pbn, int pbn_div, 785 + bool enable); 786 + int __must_check 787 + drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, 788 + struct drm_dp_mst_topology_mgr *mgr); 785 789 int __must_check 786 790 drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, 787 791 struct drm_dp_mst_topology_mgr *mgr, ··· 800 788 801 789 void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); 802 790 void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); 791 + 792 + struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port); 803 793 804 794 extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; 805 795