diff options
| author | Thomas Zimmermann <tzimmermann@suse.de> | 2021-11-18 09:36:39 +0100 |
|---|---|---|
| committer | Thomas Zimmermann <tzimmermann@suse.de> | 2021-11-18 09:36:39 +0100 |
| commit | a713ca234ea9d946235ac7248995c5fddfd9e523 (patch) | |
| tree | 708f72ee1c76360aa80c926f1defc8301aef1a23 /drivers/gpu/drm/amd/display/amdgpu_dm | |
| parent | drm/i915: Clarify probing order in intel_dp_aux_init_backlight_funcs() (diff) | |
| parent | Linux 5.16-rc1 (diff) | |
| download | linux-a713ca234ea9d946235ac7248995c5fddfd9e523.tar.gz linux-a713ca234ea9d946235ac7248995c5fddfd9e523.zip | |
Merge drm/drm-next into drm-misc-next
Backmerging from drm/drm-next for v5.16-rc1.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm')
5 files changed, 353 insertions, 158 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c42b7f50beb8..4130082c5873 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -217,6 +217,7 @@ static const struct drm_format_info * amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd); static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector); +static void handle_hpd_rx_irq(void *param); static bool is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, @@ -619,7 +620,7 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params) amdgpu_dm_crtc_handle_crc_window_irq(&acrtc->base); } -#endif +#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */ /** * dmub_aux_setconfig_reply_callback - Callback for AUX or SET_CONFIG command. @@ -669,10 +670,7 @@ void dmub_hpd_callback(struct amdgpu_device *adev, struct dmub_notification *not return; } - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - link_index = notify->link_index; - link = adev->dm.dc->links[link_index]; drm_connector_list_iter_begin(dev, &iter); @@ -685,10 +683,13 @@ void dmub_hpd_callback(struct amdgpu_device *adev, struct dmub_notification *not } } drm_connector_list_iter_end(&iter); - drm_modeset_unlock(&dev->mode_config.connection_mutex); - if (hpd_aconnector) - handle_hpd_irq_helper(hpd_aconnector); + if (hpd_aconnector) { + if (notify->type == DMUB_NOTIFICATION_HPD) + handle_hpd_irq_helper(hpd_aconnector); + else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) + handle_hpd_rx_irq(hpd_aconnector); + } } /** @@ -730,6 +731,8 @@ static void dm_handle_hpd_work(struct work_struct *work) dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev, dmub_hpd_wrk->dmub_notify); } + + kfree(dmub_hpd_wrk->dmub_notify); kfree(dmub_hpd_wrk); } @@ -755,12 +758,6 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) if (dc_enable_dmub_notifications(adev->dm.dc) && irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) { - dmub_hpd_wrk = kzalloc(sizeof(*dmub_hpd_wrk), GFP_ATOMIC); - if (!dmub_hpd_wrk) { - DRM_ERROR("Failed to allocate dmub_hpd_wrk"); - return; - } - INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); do { dc_stat_get_dmub_notification(adev->dm.dc, ¬ify); @@ -768,8 +765,25 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) DRM_ERROR("DM: notify type %d invalid!", notify.type); continue; } + if (!dm->dmub_callback[notify.type]) { + DRM_DEBUG_DRIVER("DMUB notification skipped, no handler: type=%d\n", notify.type); + continue; + } if (dm->dmub_thread_offload[notify.type] == true) { - dmub_hpd_wrk->dmub_notify = ¬ify; + dmub_hpd_wrk = kzalloc(sizeof(*dmub_hpd_wrk), GFP_ATOMIC); + if (!dmub_hpd_wrk) { + DRM_ERROR("Failed to allocate dmub_hpd_wrk"); + return; + } + dmub_hpd_wrk->dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_ATOMIC); + if (!dmub_hpd_wrk->dmub_notify) { + kfree(dmub_hpd_wrk); + DRM_ERROR("Failed to allocate dmub_hpd_wrk->dmub_notify"); + return; + } + INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); + if (dmub_hpd_wrk->dmub_notify) + memcpy(dmub_hpd_wrk->dmub_notify, ¬ify, sizeof(struct dmub_notification)); dmub_hpd_wrk->adev = adev; if (notify.type == DMUB_NOTIFICATION_HPD) { plink = adev->dm.dc->links[notify.link_index]; @@ -804,7 +818,7 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) if (count > DMUB_TRACE_MAX_READ) DRM_DEBUG_DRIVER("Warning : count > DMUB_TRACE_MAX_READ"); } -#endif +#endif /* CONFIG_DRM_AMD_DC_DCN */ static int dm_set_clockgating_state(void *handle, enum amd_clockgating_state state) @@ -1008,6 +1022,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) const unsigned char *fw_inst_const, *fw_bss_data; uint32_t i, fw_inst_const_size, fw_bss_data_size; bool has_hw_support; + struct dc *dc = adev->dm.dc; if (!dmub_srv) /* DMUB isn't supported on the ASIC. */ @@ -1094,6 +1109,19 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) for (i = 0; i < fb_info->num_fb; ++i) hw_params.fb[i] = &fb_info->fb[i]; + switch (adev->asic_type) { + case CHIP_YELLOW_CARP: + if (dc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_A0) { + hw_params.dpia_supported = true; +#if defined(CONFIG_DRM_AMD_DC_DCN) + hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia; +#endif + } + break; + default: + break; + } + status = dmub_srv_hw_init(dmub_srv, &hw_params); if (status != DMUB_STATUS_OK) { DRM_ERROR("Error initializing DMUB HW: %d\n", status); @@ -1295,6 +1323,37 @@ static struct hpd_rx_irq_offload_work_queue *hpd_rx_irq_create_workqueue(struct return hpd_rx_offload_wq; } +struct amdgpu_stutter_quirk { + u16 chip_vendor; + u16 chip_device; + u16 subsys_vendor; + u16 subsys_device; + u8 revision; +}; + +static const struct amdgpu_stutter_quirk amdgpu_stutter_quirk_list[] = { + /* https://bugzilla.kernel.org/show_bug.cgi?id=214417 */ + { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc8 }, + { 0, 0, 0, 0, 0 }, +}; + +static bool dm_should_disable_stutter(struct pci_dev *pdev) +{ + const struct amdgpu_stutter_quirk *p = amdgpu_stutter_quirk_list; + + while (p && p->chip_device != 0) { + if (pdev->vendor == p->chip_vendor && + pdev->device == p->chip_device && + pdev->subsystem_vendor == p->subsys_vendor && + pdev->subsystem_device == p->subsys_device && + pdev->revision == p->revision) { + return true; + } + ++p; + } + return false; +} + static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; @@ -1356,8 +1415,15 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) switch (adev->ip_versions[DCE_HWIP][0]) { case IP_VERSION(2, 1, 0): init_data.flags.gpu_vm_support = true; - if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) + switch (adev->dm.dmcub_fw_version) { + case 0: /* development */ + case 0x1: /* linux-firmware.git hash 6d9f399 */ + case 0x01000000: /* linux-firmware.git hash 9a0b0f4 */ + init_data.flags.disable_dmcu = false; + break; + default: init_data.flags.disable_dmcu = true; + } break; case IP_VERSION(1, 0, 0): case IP_VERSION(1, 0, 1): @@ -1407,6 +1473,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) if (adev->asic_type != CHIP_CARRIZO && adev->asic_type != CHIP_STONEY) adev->dm.dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; + if (dm_should_disable_stutter(adev->pdev)) + adev->dm.dc->debug.disable_stutter = true; if (amdgpu_dc_debug_mask & DC_DISABLE_STUTTER) adev->dm.dc->debug.disable_stutter = true; @@ -1501,7 +1569,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) DRM_ERROR("amdgpu: fail to register dmub hpd callback"); goto error; } -#endif + if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, dmub_hpd_callback, true)) { + DRM_ERROR("amdgpu: fail to register dmub hpd callback"); + goto error; + } +#endif /* CONFIG_DRM_AMD_DC_DCN */ } if (amdgpu_dm_initialize_drm_device(adev)) { @@ -1793,7 +1865,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) break; case IP_VERSION(3, 1, 2): case IP_VERSION(3, 1, 3): - dmub_asic = DMUB_ASIC_DCN31; + dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31; fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; break; @@ -4031,6 +4103,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) int32_t primary_planes; enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; + bool psr_feature_enabled = false; dm->display_indexes_num = dm->dc->caps.max_streams; /* Update the actual used number of crtc */ @@ -4113,6 +4186,19 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n", adev->ip_versions[DCE_HWIP][0]); } + + /* Determine whether to enable PSR support by default. */ + if (!(amdgpu_dc_debug_mask & DC_DISABLE_PSR)) { + switch (adev->ip_versions[DCE_HWIP][0]) { + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + psr_feature_enabled = true; + break; + default: + psr_feature_enabled = amdgpu_dc_feature_mask & DC_PSR_MASK; + break; + } + } #endif /* loops over all connectors on the board */ @@ -4156,7 +4242,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } else if (dc_link_detect(link, DETECT_REASON_BOOT)) { amdgpu_dm_update_connector_after_detect(aconnector); register_backlight_device(dm, link); - if (amdgpu_dc_feature_mask & DC_PSR_MASK) + + if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); } @@ -4495,7 +4582,8 @@ static void get_min_max_dc_plane_scaling(struct drm_device *dev, } -static int fill_dc_scaling_info(const struct drm_plane_state *state, +static int fill_dc_scaling_info(struct amdgpu_device *adev, + const struct drm_plane_state *state, struct dc_scaling_info *scaling_info) { int scale_w, scale_h, min_downscale, max_upscale; @@ -4509,7 +4597,8 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state, /* * For reasons we don't (yet) fully understand a non-zero * src_y coordinate into an NV12 buffer can cause a - * system hang. To avoid hangs (and maybe be overly cautious) + * system hang on DCN1x. + * To avoid hangs (and maybe be overly cautious) * let's reject both non-zero src_x and src_y. * * We currently know of only one use-case to reproduce a @@ -4517,10 +4606,10 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state, * is to gesture the YouTube Android app into full screen * on ChromeOS. */ - if (state->fb && - state->fb->format->format == DRM_FORMAT_NV12 && - (scaling_info->src_rect.x != 0 || - scaling_info->src_rect.y != 0)) + if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) || + (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) && + (state->fb && state->fb->format->format == DRM_FORMAT_NV12 && + (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0))) return -EINVAL; scaling_info->src_rect.width = state->src_w >> 16; @@ -5426,7 +5515,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, int ret; bool force_disable_dcc = false; - ret = fill_dc_scaling_info(plane_state, &scaling_info); + ret = fill_dc_scaling_info(adev, plane_state, &scaling_info); if (ret) return ret; @@ -6000,7 +6089,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; } -#endif +#endif /* CONFIG_DRM_AMD_DC_DCN */ /** * DOC: FreeSync Video @@ -7171,8 +7260,8 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, struct drm_connector_state *new_con_state; struct amdgpu_dm_connector *aconnector; struct dm_connector_state *dm_conn_state; - int i, j, clock; - int vcpi, pbn_div, pbn = 0; + int i, j; + int vcpi, pbn_div, pbn, slot_num = 0; for_each_new_connector_in_state(state, connector, new_con_state, i) { @@ -7200,17 +7289,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, if (!stream) continue; - if (stream->timing.flags.DSC != 1) { - drm_dp_mst_atomic_enable_dsc(state, - aconnector->port, - dm_conn_state->pbn, - 0, - false); - continue; - } - pbn_div = dm_mst_get_pbn_divider(stream->link); - clock = stream->timing.pix_clk_100hz / 10; /* pbn is calculated by compute_mst_dsc_configs_for_state*/ for (j = 0; j < dc_state->stream_count; j++) { if (vars[j].aconnector == aconnector) { @@ -7219,6 +7298,23 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, } } + if (j == dc_state->stream_count) + continue; + + slot_num = DIV_ROUND_UP(pbn, pbn_div); + + if (stream->timing.flags.DSC != 1) { + dm_conn_state->pbn = pbn; + dm_conn_state->vcpi_slots = slot_num; + + drm_dp_mst_atomic_enable_dsc(state, + aconnector->port, + dm_conn_state->pbn, + 0, + false); + continue; + } + vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->port, pbn, pbn_div, @@ -7482,7 +7578,7 @@ static int dm_plane_atomic_check(struct drm_plane *plane, if (ret) return ret; - ret = fill_dc_scaling_info(new_plane_state, &scaling_info); + ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info); if (ret) return ret; @@ -8930,7 +9026,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix; } - fill_dc_scaling_info(new_plane_state, + fill_dc_scaling_info(dm->adev, new_plane_state, &bundle->scaling_infos[planes_count]); bundle->surface_updates[planes_count].scaling_info = @@ -10535,18 +10631,18 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, struct drm_crtc *crtc, struct drm_crtc_state *new_crtc_state) { - struct drm_plane_state *new_cursor_state, *new_primary_state; - int cursor_scale_w, cursor_scale_h, primary_scale_w, primary_scale_h; + struct drm_plane *cursor = crtc->cursor, *underlying; + struct drm_plane_state *new_cursor_state, *new_underlying_state; + int i; + int cursor_scale_w, cursor_scale_h, underlying_scale_w, underlying_scale_h; /* On DCE and DCN there is no dedicated hardware cursor plane. We get a * cursor per pipe but it's going to inherit the scaling and * positioning from the underlying pipe. Check the cursor plane's - * blending properties match the primary plane's. */ + * blending properties match the underlying planes'. */ - new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor); - new_primary_state = drm_atomic_get_new_plane_state(state, crtc->primary); - if (!new_cursor_state || !new_primary_state || - !new_cursor_state->fb || !new_primary_state->fb) { + new_cursor_state = drm_atomic_get_new_plane_state(state, cursor); + if (!new_cursor_state || !new_cursor_state->fb) { return 0; } @@ -10555,15 +10651,34 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, cursor_scale_h = new_cursor_state->crtc_h * 1000 / (new_cursor_state->src_h >> 16); - primary_scale_w = new_primary_state->crtc_w * 1000 / - (new_primary_state->src_w >> 16); - primary_scale_h = new_primary_state->crtc_h * 1000 / - (new_primary_state->src_h >> 16); + for_each_new_plane_in_state_reverse(state, underlying, new_underlying_state, i) { + /* Narrow down to non-cursor planes on the same CRTC as the cursor */ + if (new_underlying_state->crtc != crtc || underlying == crtc->cursor) + continue; - if (cursor_scale_w != primary_scale_w || - cursor_scale_h != primary_scale_h) { - drm_dbg_atomic(crtc->dev, "Cursor plane scaling doesn't match primary plane\n"); - return -EINVAL; + /* Ignore disabled planes */ + if (!new_underlying_state->fb) + continue; + + underlying_scale_w = new_underlying_state->crtc_w * 1000 / + (new_underlying_state->src_w >> 16); + underlying_scale_h = new_underlying_state->crtc_h * 1000 / + (new_underlying_state->src_h >> 16); + + if (cursor_scale_w != underlying_scale_w || + cursor_scale_h != underlying_scale_h) { + drm_dbg_atomic(crtc->dev, + "Cursor [PLANE:%d:%s] scaling doesn't match underlying [PLANE:%d:%s]\n", + cursor->base.id, cursor->name, underlying->base.id, underlying->name); + return -EINVAL; + } + + /* If this plane covers the whole CRTC, no need to check planes underneath */ + if (new_underlying_state->crtc_x <= 0 && + new_underlying_state->crtc_y <= 0 && + new_underlying_state->crtc_x + new_underlying_state->crtc_w >= new_crtc_state->mode.hdisplay && + new_underlying_state->crtc_y + new_underlying_state->crtc_h >= new_crtc_state->mode.vdisplay) + break; } return 0; @@ -10594,53 +10709,6 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm } #endif -static int validate_overlay(struct drm_atomic_state *state) -{ - int i; - struct drm_plane *plane; - struct drm_plane_state *new_plane_state; - struct drm_plane_state *primary_state, *overlay_state = NULL; - - /* Check if primary plane is contained inside overlay */ - for_each_new_plane_in_state_reverse(state, plane, new_plane_state, i) { - if (plane->type == DRM_PLANE_TYPE_OVERLAY) { - if (drm_atomic_plane_disabling(plane->state, new_plane_state)) - return 0; - - overlay_state = new_plane_state; - continue; - } - } - - /* check if we're making changes to the overlay plane */ - if (!overlay_state) - return 0; - - /* check if overlay plane is enabled */ - if (!overlay_state->crtc) - return 0; - - /* find the primary plane for the CRTC that the overlay is enabled on */ - primary_state = drm_atomic_get_plane_state(state, overlay_state->crtc->primary); - if (IS_ERR(primary_state)) - return PTR_ERR(primary_state); - - /* check if primary plane is enabled */ - if (!primary_state->crtc) - return 0; - - /* Perform the bounds check to ensure the overlay plane covers the primary */ - if (primary_state->crtc_x < overlay_state->crtc_x || - primary_state->crtc_y < overlay_state->crtc_y || - primary_state->crtc_x + primary_state->crtc_w > overlay_state->crtc_x + overlay_state->crtc_w || - primary_state->crtc_y + primary_state->crtc_h > overlay_state->crtc_y + overlay_state->crtc_h) { - DRM_DEBUG_ATOMIC("Overlay plane is enabled with hardware cursor but does not fully cover primary plane\n"); - return -EINVAL; - } - - return 0; -} - /** * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM. * @dev: The DRM device @@ -10683,6 +10751,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, struct dm_crtc_state *dm_old_crtc_state; #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_mst_fairness_vars vars[MAX_PIPES]; + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_topology_mgr *mgr; #endif trace_amdgpu_dm_atomic_check_begin(state); @@ -10743,7 +10813,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) - return ret; + goto fail; ret = drm_atomic_add_affected_planes(state, crtc); if (ret) @@ -10822,10 +10892,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } - ret = validate_overlay(state); - if (ret) - goto fail; - /* Add new/modified planes */ for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { ret = dm_update_plane_state(dc, state, plane, @@ -10891,6 +10957,33 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, lock_and_validation_needed = true; } +#if defined(CONFIG_DRM_AMD_DC_DCN) + /* set the slot info for each mst_state based on the link encoding format */ + for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_list_iter iter; + u8 link_coding_cap; + + if (!mgr->mst_state ) + continue; + + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(connector, &iter) { + int id = connector->index; + + if (id == mst_state->mgr->conn_base_id) { + aconnector = to_amdgpu_dm_connector(connector); + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); + drm_dp_mst_update_slots(mst_state, link_coding_cap); + + break; + } + } + drm_connector_list_iter_end(&iter); + + } +#endif /** * Streams and planes are reset when there are changes that affect * bandwidth. Anything that affects bandwidth needs to go through diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index f8c8122e15ed..0277685864c5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -78,12 +78,10 @@ static int parse_write_buffer_into_params(char *wr_buf, uint32_t wr_buf_size, wr_buf_ptr = wr_buf; - r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); - - /* r is bytes not be copied */ - if (r >= wr_buf_size) { - DRM_DEBUG_DRIVER("user data not be read\n"); - return -EINVAL; + /* r is bytes not be copied */ + if (copy_from_user(wr_buf_ptr, buf, wr_buf_size)) { + DRM_DEBUG_DRIVER("user data could not be read successfully\n"); + return -EFAULT; } /* check number of parameters. isspace could not differ space and \n */ @@ -264,7 +262,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, if (!wr_buf) return -ENOSPC; - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -294,6 +292,9 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, case LINK_RATE_RBR2: case LINK_RATE_HIGH2: case LINK_RATE_HIGH3: +#if defined(CONFIG_DRM_AMD_DC_DCN) + case LINK_RATE_UHBR10: +#endif break; default: valid_input = false; @@ -488,7 +489,7 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf, if (!wr_buf) return -ENOSPC; - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -640,7 +641,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us if (!wr_buf) return -ENOSPC; - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -915,7 +916,7 @@ static ssize_t dp_dsc_passthrough_set(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, ¶m, buf, max_param_num, ¶m_nums)) { @@ -1212,7 +1213,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1397,7 +1398,7 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1582,7 +1583,7 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1767,7 +1768,7 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -1945,7 +1946,7 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { @@ -2383,7 +2384,7 @@ static ssize_t dp_max_bpc_write(struct file *f, const char __user *buf, return -ENOSPC; } - if (parse_write_buffer_into_params(wr_buf, size, + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, (long *)param, buf, max_param_num, ¶m_nums)) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index ff0f91c93ba4..8cbeeb7c986d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -219,6 +219,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( struct drm_dp_mst_topology_mgr *mst_mgr; struct drm_dp_mst_port *mst_port; bool ret; + u8 link_coding_cap = DP_8b_10b_ENCODING; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; /* Accessing the connector state is required for vcpi_slots allocation @@ -238,6 +239,10 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_port = aconnector->port; +#if defined(CONFIG_DRM_AMD_DC_DCN) + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link); +#endif + if (enable) { ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, @@ -251,7 +256,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( } /* It's OK for this to fail */ - drm_dp_update_payload_part1(mst_mgr); + drm_dp_update_payload_part1(mst_mgr, (link_coding_cap == DP_CAP_ANSI_128B132B) ? 0:1); /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or * AUX message. The sequence is slot 1-63 allocated sequence for each diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 1a99fcc27078..32a5ce09a62a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -64,6 +64,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0; payload.write = (msg->request & DP_AUX_I2C_READ) == 0; payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0; + payload.write_status_update = + (msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; payload.defer_delay = 0; result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, @@ -532,13 +534,14 @@ static int kbps_to_peak_pbn(int kbps) static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params, struct dsc_mst_fairness_vars *vars, - int count) + int count, + int k) { int i; for (i = 0; i < count; i++) { memset(¶ms[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg)); - if (vars[i].dsc_enabled && dc_dsc_compute_config( + if (vars[i + k].dsc_enabled && dc_dsc_compute_config( params[i].sink->ctx->dc->res_pool->dscs[0], ¶ms[i].sink->dsc_caps.dsc_dec_caps, params[i].sink->ctx->dc->debug.dsc_min_slice_height_override, @@ -551,7 +554,7 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p if (params[i].bpp_overwrite) params[i].timing->dsc_cfg.bits_per_pixel = params[i].bpp_overwrite; else - params[i].timing->dsc_cfg.bits_per_pixel = vars[i].bpp_x16; + params[i].timing->dsc_cfg.bits_per_pixel = vars[i + k].bpp_x16; if (params[i].num_slices_h) params[i].timing->dsc_cfg.num_slices_h = params[i].num_slices_h; @@ -584,7 +587,8 @@ static void increase_dsc_bpp(struct drm_atomic_state *state, struct dc_link *dc_link, struct dsc_mst_fairness_params *params, struct dsc_mst_fairness_vars *vars, - int count) + int count, + int k) { int i; bool bpp_increased[MAX_PIPES]; @@ -599,8 +603,9 @@ static void increase_dsc_bpp(struct drm_atomic_state *state, pbn_per_timeslot = dm_mst_get_pbn_divider(dc_link); for (i = 0; i < count; i++) { - if (vars[i].dsc_enabled) { - initial_slack[i] = kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i].pbn; + if (vars[i + k].dsc_enabled) { + initial_slack[i] = + kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i + k].pbn; bpp_increased[i] = false; remaining_to_increase += 1; } else { @@ -627,7 +632,7 @@ static void increase_dsc_bpp(struct drm_atomic_state *state, link_timeslots_used = 0; for (i = 0; i < count; i++) - link_timeslots_used += DIV_ROUND_UP(vars[i].pbn, pbn_per_timeslot); + link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, pbn_per_timeslot); fair_pbn_alloc = (63 - link_timeslots_used) / remaining_to_increase * pbn_per_timeslot; @@ -680,7 +685,8 @@ static void try_disable_dsc(struct drm_atomic_state *state, struct dc_link *dc_link, struct dsc_mst_fairness_params *params, struct dsc_mst_fairness_vars *vars, - int count) + int count, + int k) { int i; bool tried[MAX_PIPES]; @@ -690,8 +696,8 @@ static void try_disable_dsc(struct drm_atomic_state *state, int remaining_to_try = 0; for (i = 0; i < count; i++) { - if (vars[i].dsc_enabled - && vars[i].bpp_x16 == params[i].bw_range.max_target_bpp_x16 + if (vars[i + k].dsc_enabled + && vars[i + k].bpp_x16 == params[i].bw_range.max_target_bpp_x16 && params[i].clock_force_enable == DSC_CLK_FORCE_DEFAULT) { kbps_increase[i] = params[i].bw_range.stream_kbps - params[i].bw_range.max_kbps; tried[i] = false; @@ -746,9 +752,10 @@ static void try_disable_dsc(struct drm_atomic_state *state, static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, struct dc_state *dc_state, struct dc_link *dc_link, - struct dsc_mst_fairness_vars *vars) + struct dsc_mst_fairness_vars *vars, + int *link_vars_start_index) { - int i; + int i, k; struct dc_stream_state *stream; struct dsc_mst_fairness_params params[MAX_PIPES]; struct amdgpu_dm_connector *aconnector; @@ -766,11 +773,17 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (stream->link != dc_link) continue; + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + if (!aconnector) + continue; + + if (!aconnector->port) + continue; + stream->timing.flags.DSC = 0; params[count].timing = &stream->timing; params[count].sink = stream->sink; - aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; params[count].aconnector = aconnector; params[count].port = aconnector->port; params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable; @@ -792,44 +805,55 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, count++; } + + if (count == 0) { + ASSERT(0); + return true; + } + + /* k is start index of vars for current phy link used by mst hub */ + k = *link_vars_start_index; + /* set vars start index for next mst hub phy link */ + *link_vars_start_index += count; + /* Try no compression */ for (i = 0; i < count; i++) { - vars[i].aconnector = params[i].aconnector; - vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); - vars[i].dsc_enabled = false; - vars[i].bpp_x16 = 0; + vars[i + k].aconnector = params[i].aconnector; + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); + vars[i + k].dsc_enabled = false; + vars[i + k].bpp_x16 = 0; if (drm_dp_atomic_find_vcpi_slots(state, params[i].port->mgr, params[i].port, - vars[i].pbn, + vars[i + k].pbn, dm_mst_get_pbn_divider(dc_link)) < 0) return false; } if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) { - set_dsc_configs_from_fairness_vars(params, vars, count); + set_dsc_configs_from_fairness_vars(params, vars, count, k); return true; } /* Try max compression */ for (i = 0; i < count; i++) { if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) { - vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps); - vars[i].dsc_enabled = true; - vars[i].bpp_x16 = params[i].bw_range.min_target_bpp_x16; + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps); + vars[i + k].dsc_enabled = true; + vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16; if (drm_dp_atomic_find_vcpi_slots(state, params[i].port->mgr, params[i].port, - vars[i].pbn, + vars[i + k].pbn, dm_mst_get_pbn_divider(dc_link)) < 0) return false; } else { - vars[i].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); - vars[i].dsc_enabled = false; - vars[i].bpp_x16 = 0; + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); + vars[i + k].dsc_enabled = false; + vars[i + k].bpp_x16 = 0; if (drm_dp_atomic_find_vcpi_slots(state, params[i].port->mgr, params[i].port, - vars[i].pbn, + vars[i + k].pbn, dm_mst_get_pbn_divider(dc_link)) < 0) return false; } @@ -838,15 +862,76 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, return false; /* Optimize degree of compression */ - increase_dsc_bpp(state, dc_link, params, vars, count); + increase_dsc_bpp(state, dc_link, params, vars, count, k); - try_disable_dsc(state, dc_link, params, vars, count); + try_disable_dsc(state, dc_link, params, vars, count, k); - set_dsc_configs_from_fairness_vars(params, vars, count); + set_dsc_configs_from_fairness_vars(params, vars, count, k); return true; } +static bool is_dsc_need_re_compute( + struct drm_atomic_state *state, + struct dc_state *dc_state, + struct dc_link *dc_link) +{ + int i; + bool is_dsc_need_re_compute = false; + + /* only check phy used by mst branch */ + if (dc_link->type != dc_connection_mst_branch) + return false; + + /* check if there is mode change in new request */ + for (i = 0; i < dc_state->stream_count; i++) { + struct amdgpu_dm_connector *aconnector; + struct dc_stream_state *stream; + struct drm_crtc_state *new_crtc_state; + struct drm_connector_state *new_conn_state; + + stream = dc_state->streams[i]; + + if (!stream) + continue; + + /* check if stream using the same link for mst */ + if (stream->link != dc_link) + continue; + + aconnector = (struct amdgpu_dm_connector *) stream->dm_stream_context; + if (!aconnector) + continue; + + new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base); + + if (!new_conn_state) + continue; + + if (IS_ERR(new_conn_state)) + continue; + + if (!new_conn_state->crtc) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + + if (!new_crtc_state) + continue; + + if (IS_ERR(new_crtc_state)) + continue; + + if (new_crtc_state->enable && new_crtc_state->active) { + if (new_crtc_state->mode_changed || new_crtc_state->active_changed || + new_crtc_state->connectors_changed) + is_dsc_need_re_compute = true; + } + } + + return is_dsc_need_re_compute; +} + bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, struct dc_state *dc_state, struct dsc_mst_fairness_vars *vars) @@ -855,6 +940,7 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, struct dc_stream_state *stream; bool computed_streams[MAX_PIPES]; struct amdgpu_dm_connector *aconnector; + int link_vars_start_index = 0; for (i = 0; i < dc_state->stream_count; i++) computed_streams[i] = false; @@ -879,8 +965,12 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, if (dcn20_remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK) return false; + if (!is_dsc_need_re_compute(state, dc_state, stream->link)) + continue; + mutex_lock(&aconnector->mst_mgr.lock); - if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars)) { + if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, + vars, &link_vars_start_index)) { mutex_unlock(&aconnector->mst_mgr.lock); return false; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index 70a554f1e725..c022e56f9459 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -107,6 +107,8 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) */ // Init fail safe of 2 frames static unsigned int num_frames_static = 2; + unsigned int power_opt = 0; + bool psr_enable = true; DRM_DEBUG_DRIVER("Enabling psr...\n"); @@ -133,7 +135,9 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) &stream, 1, ¶ms); - return dc_link_set_psr_allow_active(link, true, false, false); + power_opt |= psr_power_opt_z10_static_screen; + + return dc_link_set_psr_allow_active(link, &psr_enable, false, false, &power_opt); } /* @@ -144,10 +148,12 @@ bool amdgpu_dm_psr_enable(struct dc_stream_state *stream) */ bool amdgpu_dm_psr_disable(struct dc_stream_state *stream) { + unsigned int power_opt = 0; + bool psr_enable = false; DRM_DEBUG_DRIVER("Disabling psr...\n"); - return dc_link_set_psr_allow_active(stream->link, false, true, false); + return dc_link_set_psr_allow_active(stream->link, &psr_enable, true, false, &power_opt); } /* |
