diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
51 files changed, 1016 insertions, 583 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 5b0f708dd8c5..d8224156460e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -978,6 +978,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) /* Update the actual used number of crtc */ adev->mode_info.num_crtc = adev->dm.display_indexes_num; + /* create fake encoders for MST */ + dm_dp_create_fake_mst_encoders(adev); + /* TODO: Add_display_info? */ /* TODO use dynamic cursor width */ @@ -1001,6 +1004,12 @@ error: static void amdgpu_dm_fini(struct amdgpu_device *adev) { + int i; + + for (i = 0; i < adev->dm.display_indexes_num; i++) { + drm_encoder_cleanup(&adev->dm.mst_encoders[i].base); + } + amdgpu_dm_audio_fini(adev); amdgpu_dm_destroy_drm_device(&adev->dm); @@ -1076,6 +1085,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) case CHIP_RENOIR: #if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: #endif return 0; case CHIP_NAVI12: @@ -1175,6 +1185,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) break; #if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: dmub_asic = DMUB_ASIC_DCN30; fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB; break; @@ -2019,6 +2030,7 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) struct amdgpu_display_manager *dm; struct drm_connector *conn_base; struct amdgpu_device *adev; + struct dc_link *link = NULL; static const u8 pre_computed_values[] = { 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 77, 79, 81, 82, 84, 86, 88, 90, 92, 94, 96, 98}; @@ -2026,6 +2038,10 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) if (!aconnector || !aconnector->dc_link) return; + link = aconnector->dc_link; + if (link->connector_signal != SIGNAL_TYPE_EDP) + return; + conn_base = &aconnector->base; adev = conn_base->dev->dev_private; dm = &adev->dm; @@ -3216,6 +3232,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case CHIP_RENOIR: #if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: #endif if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); @@ -3373,6 +3390,7 @@ static int dm_early_init(void *handle) case CHIP_NAVI12: #if defined(CONFIG_DRM_AMD_DC_DCN3_0) case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: #endif adev->mode_info.num_crtc = 6; adev->mode_info.num_hpd = 6; @@ -3696,6 +3714,7 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, adev->asic_type == CHIP_NAVI12 || #if defined(CONFIG_DRM_AMD_DC_DCN3_0) adev->asic_type == CHIP_SIENNA_CICHLID || + adev->asic_type == CHIP_NAVY_FLOUNDER || #endif adev->asic_type == CHIP_RENOIR || adev->asic_type == CHIP_RAVEN) { @@ -3717,9 +3736,9 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, tiling_info->gfx9.shaderEnable = 1; #ifdef CONFIG_DRM_AMD_DC_DCN3_0 - if (adev->asic_type == CHIP_SIENNA_CICHLID) + if (adev->asic_type == CHIP_SIENNA_CICHLID || + adev->asic_type == CHIP_NAVY_FLOUNDER) tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; - #endif ret = fill_plane_dcc_attributes(adev, afb, format, rotation, plane_size, tiling_info, @@ -4556,24 +4575,20 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false); - if (stream->link->psr_settings.psr_feature_enabled) { - struct dc *core_dc = stream->link->ctx->dc; - - if (dc_is_dmcu_initialized(core_dc)) { - // - // should decide stream support vsc sdp colorimetry capability - // before building vsc info packet - // - stream->use_vsc_sdp_for_colorimetry = false; - if (aconnector->dc_sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - stream->use_vsc_sdp_for_colorimetry = - aconnector->dc_sink->is_vsc_sdp_colorimetry_supported; - } else { - if (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED) - stream->use_vsc_sdp_for_colorimetry = true; - } - mod_build_vsc_infopacket(stream, &stream->vsc_infopacket); + if (stream->link->psr_settings.psr_feature_enabled) { + // + // should decide stream support vsc sdp colorimetry capability + // before building vsc info packet + // + stream->use_vsc_sdp_for_colorimetry = false; + if (aconnector->dc_sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + stream->use_vsc_sdp_for_colorimetry = + aconnector->dc_sink->is_vsc_sdp_colorimetry_supported; + } else { + if (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED) + stream->use_vsc_sdp_for_colorimetry = true; } + mod_build_vsc_infopacket(stream, &stream->vsc_infopacket); } finish: dc_sink_release(sink); @@ -4639,7 +4654,6 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) } state->active_planes = cur->active_planes; - state->interrupts_enabled = cur->interrupts_enabled; state->vrr_params = cur->vrr_params; state->vrr_infopacket = cur->vrr_infopacket; state->abm_level = cur->abm_level; @@ -5300,29 +5314,19 @@ static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state) return num_active; } -/* - * Sets whether interrupts should be enabled on a specific CRTC. - * We require that the stream be enabled and that there exist active - * DC planes on the stream. - */ -static void -dm_update_crtc_interrupt_state(struct drm_crtc *crtc, - struct drm_crtc_state *new_crtc_state) +static void dm_update_crtc_active_planes(struct drm_crtc *crtc, + struct drm_crtc_state *new_crtc_state) { struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_new_crtc_state->active_planes = 0; - dm_new_crtc_state->interrupts_enabled = false; if (!dm_new_crtc_state->stream) return; dm_new_crtc_state->active_planes = count_crtc_active_planes(new_crtc_state); - - dm_new_crtc_state->interrupts_enabled = - dm_new_crtc_state->active_planes > 0; } static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, @@ -5333,13 +5337,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state); int ret = -EINVAL; - /* - * Update interrupt state for the CRTC. This needs to happen whenever - * the CRTC has changed or whenever any of its planes have changed. - * Atomic check satisfies both of these requirements since the CRTC - * is added to the state by DRM during drm_atomic_helper_check_planes. - */ - dm_update_crtc_interrupt_state(crtc, state); + dm_update_crtc_active_planes(crtc, state); if (unlikely(!dm_crtc_state->stream && modeset_required(state, NULL, dm_crtc_state->stream))) { @@ -5864,6 +5862,7 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, uint32_t formats[32]; int num_formats; int res = -EPERM; + unsigned int supported_rotations; num_formats = get_plane_formats(plane, plane_cap, formats, ARRAY_SIZE(formats)); @@ -5898,6 +5897,13 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE); } + supported_rotations = + DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; + + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, + supported_rotations); + drm_plane_helper_add(plane, &dm_plane_helper_funcs); /* Create (reset) the plane state */ @@ -6442,8 +6448,10 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, bool enable) { /* - * this is not correct translation but will work as soon as VBLANK - * constant is the same as PFLIP + * We have no guarantee that the frontend index maps to the same + * backend index - some even map to more than one. + * + * TODO: Use a different interrupt or check DC itself for the mapping. */ int irq_type = amdgpu_display_crtc_idx_to_irq_type( @@ -6466,6 +6474,19 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, } } +static void dm_update_pflip_irq_state(struct amdgpu_device *adev, + struct amdgpu_crtc *acrtc) +{ + int irq_type = + amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id); + + /** + * This reads the current state for the IRQ and force reapplies + * the setting to hardware. + */ + amdgpu_irq_update(adev, &adev->pageflip_irq, irq_type); +} + static bool is_scaling_state_different(const struct dm_connector_state *dm_state, const struct dm_connector_state *old_dm_state) @@ -7050,7 +7071,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, usleep_range(1000, 1100); } - if (acrtc_attach->base.state->event) { + /** + * Prepare the flip event for the pageflip interrupt to handle. + * + * This only works in the case where we've already turned on the + * appropriate hardware blocks (eg. HUBP) so in the transition case + * from 0 -> n planes we have to skip a hardware generated event + * and rely on sending it from software. + */ + if (acrtc_attach->base.state->event && + acrtc_state->active_planes > 0) { drm_crtc_vblank_get(pcrtc); spin_lock_irqsave(&pcrtc->dev->event_lock, flags); @@ -7119,6 +7149,24 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, &bundle->stream_update, dc_state); + /** + * Enable or disable the interrupts on the backend. + * + * Most pipes are put into power gating when unused. + * + * When power gating is enabled on a pipe we lose the + * interrupt enablement state when power gating is disabled. + * + * So we need to update the IRQ control state in hardware + * whenever the pipe turns on (since it could be previously + * power gated) or off (since some pipes can't be power gated + * on some ASICs). + */ + if (dm_old_crtc_state->active_planes != acrtc_state->active_planes) + dm_update_pflip_irq_state( + (struct amdgpu_device *)dev->dev_private, + acrtc_attach); + if ((acrtc_state->update_type > UPDATE_TYPE_FAST) && acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED && !acrtc_state->stream->link->psr_settings.psr_feature_enabled) @@ -7220,64 +7268,6 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev, } /* - * Enable interrupts on CRTCs that are newly active, undergone - * a modeset, or have active planes again. - * - * Done in two passes, based on the for_modeset flag: - * Pass 1: For CRTCs going through modeset - * Pass 2: For CRTCs going from 0 to n active planes - * - * Interrupts can only be enabled after the planes are programmed, - * so this requires a two-pass approach since we don't want to - * just defer the interrupts until after commit planes every time. - */ -static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev, - struct drm_atomic_state *state, - bool for_modeset) -{ - struct amdgpu_device *adev = dev->dev_private; - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state, *new_crtc_state; - int i; -#ifdef CONFIG_DEBUG_FS - enum amdgpu_dm_pipe_crc_source source; -#endif - - for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, - new_crtc_state, i) { - struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); - struct dm_crtc_state *dm_new_crtc_state = - to_dm_crtc_state(new_crtc_state); - struct dm_crtc_state *dm_old_crtc_state = - to_dm_crtc_state(old_crtc_state); - bool modeset = drm_atomic_crtc_needs_modeset(new_crtc_state); - bool run_pass; - - run_pass = (for_modeset && modeset) || - (!for_modeset && !modeset && - !dm_old_crtc_state->interrupts_enabled); - - if (!run_pass) - continue; - - if (!dm_new_crtc_state->interrupts_enabled) - continue; - - manage_dm_interrupts(adev, acrtc, true); - -#ifdef CONFIG_DEBUG_FS - /* The stream has changed so CRC capture needs to re-enabled. */ - source = dm_new_crtc_state->crc_src; - if (amdgpu_dm_is_valid_crc_source(source)) { - amdgpu_dm_crtc_configure_crc_source( - crtc, dm_new_crtc_state, - dm_new_crtc_state->crc_src); - } -#endif - } -} - -/* * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC * @crtc_state: the DRM CRTC state * @stream_state: the DC stream state. @@ -7316,12 +7306,10 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev, * in atomic check. */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); - if (dm_old_crtc_state->interrupts_enabled && - (!dm_new_crtc_state->interrupts_enabled || + if (old_crtc_state->active && + (!new_crtc_state->active || drm_atomic_crtc_needs_modeset(new_crtc_state))) manage_dm_interrupts(adev, acrtc, false); } @@ -7600,8 +7588,34 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) dm_new_crtc_state); } - /* Enable interrupts for CRTCs going through a modeset. */ - amdgpu_dm_enable_crtc_interrupts(dev, state, true); + /** + * Enable interrupts for CRTCs that are newly enabled or went through + * a modeset. It was intentionally deferred until after the front end + * state was modified to wait until the OTG was on and so the IRQ + * handlers didn't access stale or invalid state. + */ + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + + if (new_crtc_state->active && + (!old_crtc_state->active || + drm_atomic_crtc_needs_modeset(new_crtc_state))) { + manage_dm_interrupts(adev, acrtc, true); +#ifdef CONFIG_DEBUG_FS + /** + * Frontend may have changed so reapply the CRC capture + * settings for the stream. + */ + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + + if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) { + amdgpu_dm_crtc_configure_crc_source( + crtc, dm_new_crtc_state, + dm_new_crtc_state->crc_src); + } +#endif + } + } for_each_new_crtc_in_state(state, crtc, new_crtc_state, j) if (new_crtc_state->async_flip) @@ -7616,9 +7630,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) dm, crtc, wait_for_vblank); } - /* Enable interrupts for CRTCs going from 0 to n active planes. */ - amdgpu_dm_enable_crtc_interrupts(dev, state, false); - /* Update audio instances for each connector. */ amdgpu_dm_commit_audio(dev, state); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 86c132ddc452..dd1559c743c2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -43,6 +43,9 @@ */ #define AMDGPU_DM_MAX_DISPLAY_INDEX 31 + +#define AMDGPU_DM_MAX_CRTC 6 + /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h" @@ -330,6 +333,13 @@ struct amdgpu_display_manager { * available in FW */ const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; + + /** + * @mst_encoders: + * + * fake encoders used for DP MST. + */ + struct amdgpu_encoder mst_encoders[AMDGPU_DM_MAX_CRTC]; }; struct amdgpu_dm_connector { @@ -358,7 +368,6 @@ struct amdgpu_dm_connector { struct amdgpu_dm_dp_aux dm_dp_aux; struct drm_dp_mst_port *port; struct amdgpu_dm_connector *mst_port; - struct amdgpu_encoder *mst_encoder; struct drm_dp_aux *dsc_aux; /* TODO see if we can merge with ddc_bus or make a dm_connector */ @@ -405,7 +414,6 @@ struct dm_crtc_state { int update_type; int active_planes; - bool interrupts_enabled; int crc_skip_count; enum amdgpu_dm_pipe_crc_source crc_src; 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 db4fab10a0c4..caf3beaf4b7b 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 @@ -46,6 +46,89 @@ struct dmub_debugfs_trace_entry { uint32_t param1; }; + +/* parse_write_buffer_into_params - Helper function to parse debugfs write buffer into an array + * + * Function takes in attributes passed to debugfs write entry + * and writes into param array. + * The user passes max_param_num to identify maximum number of + * parameters that could be parsed. + * + */ +static int parse_write_buffer_into_params(char *wr_buf, uint32_t wr_buf_size, + long *param, const char __user *buf, + int max_param_num, + uint8_t *param_nums) +{ + char *wr_buf_ptr = NULL; + uint32_t wr_buf_count = 0; + int r; + char *sub_str = NULL; + const char delimiter[3] = {' ', '\n', '\0'}; + uint8_t param_index = 0; + + *param_nums = 0; + + 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; + } + + /* check number of parameters. isspace could not differ space and \n */ + while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) { + /* skip space*/ + while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { + wr_buf_ptr++; + wr_buf_count++; + } + + if (wr_buf_count == wr_buf_size) + break; + + /* skip non-space*/ + while ((!isspace(*wr_buf_ptr)) && (wr_buf_count < wr_buf_size)) { + wr_buf_ptr++; + wr_buf_count++; + } + + (*param_nums)++; + + if (wr_buf_count == wr_buf_size) + break; + } + + if (*param_nums > max_param_num) + *param_nums = max_param_num; +; + + wr_buf_ptr = wr_buf; /* reset buf pointer */ + wr_buf_count = 0; /* number of char already checked */ + + while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { + wr_buf_ptr++; + wr_buf_count++; + } + + while (param_index < *param_nums) { + /* after strsep, wr_buf_ptr will be moved to after space */ + sub_str = strsep(&wr_buf_ptr, delimiter); + + r = kstrtol(sub_str, 16, &(param[param_index])); + + if (r) + DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); + + param_index++; + } + + return 0; +} + /* function description * get/ set DP configuration: lane_count, link_rate, spread_spectrum * @@ -161,15 +244,11 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, struct dc *dc = (struct dc *)link->dc; struct dc_link_settings prefer_link_settings; char *wr_buf = NULL; - char *wr_buf_ptr = NULL; const uint32_t wr_buf_size = 40; - int r; - int bytes_from_user; - char *sub_str; /* 0: lane_count; 1: link_rate */ - uint8_t param_index = 0; + int max_param_num = 2; + uint8_t param_nums = 0; long param[2]; - const char delimiter[3] = {' ', '\n', '\0'}; bool valid_input = false; if (size == 0) @@ -177,35 +256,20 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); if (!wr_buf) - return -EINVAL; - wr_buf_ptr = wr_buf; + return -ENOSPC; - r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); - - /* r is bytes not be copied */ - if (r >= wr_buf_size) { + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { kfree(wr_buf); - DRM_DEBUG_DRIVER("user data not read\n"); return -EINVAL; } - bytes_from_user = wr_buf_size - r; - - while (isspace(*wr_buf_ptr)) - wr_buf_ptr++; - - while ((*wr_buf_ptr != '\0') && (param_index < 2)) { - - sub_str = strsep(&wr_buf_ptr, delimiter); - - r = kstrtol(sub_str, 16, ¶m[param_index]); - - if (r) - DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); - - param_index++; - while (isspace(*wr_buf_ptr)) - wr_buf_ptr++; + if (param_nums <= 0) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not be read\n"); + return -EINVAL; } switch (param[0]) { @@ -233,7 +297,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, if (!valid_input) { kfree(wr_buf); DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n"); - return bytes_from_user; + return size; } /* save user force lane_count, link_rate to preferred settings @@ -246,7 +310,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, dc_link_set_preferred_link_settings(dc, &prefer_link_settings, link); kfree(wr_buf); - return bytes_from_user; + return size; } /* function: get current DP PHY settings: voltage swing, pre-emphasis, @@ -337,51 +401,34 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf, struct dc_link *link = connector->dc_link; struct dc *dc = (struct dc *)link->dc; char *wr_buf = NULL; - char *wr_buf_ptr = NULL; uint32_t wr_buf_size = 40; - int r; - int bytes_from_user; - char *sub_str; - uint8_t param_index = 0; long param[3]; - const char delimiter[3] = {' ', '\n', '\0'}; bool use_prefer_link_setting; struct link_training_settings link_lane_settings; + int max_param_num = 3; + uint8_t param_nums = 0; + int r = 0; + if (size == 0) - return 0; + return -EINVAL; wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); if (!wr_buf) - return 0; - wr_buf_ptr = wr_buf; + return -ENOSPC; - r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); - - /* r is bytes not be copied */ - if (r >= wr_buf_size) { + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { kfree(wr_buf); - DRM_DEBUG_DRIVER("user data not be read\n"); - return 0; + return -EINVAL; } - bytes_from_user = wr_buf_size - r; - - while (isspace(*wr_buf_ptr)) - wr_buf_ptr++; - - while ((*wr_buf_ptr != '\0') && (param_index < 3)) { - - sub_str = strsep(&wr_buf_ptr, delimiter); - - r = kstrtol(sub_str, 16, ¶m[param_index]); - - if (r) - DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); - - param_index++; - while (isspace(*wr_buf_ptr)) - wr_buf_ptr++; + if (param_nums <= 0) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not be read\n"); + return -EINVAL; } if ((param[0] > VOLTAGE_SWING_MAX_LEVEL) || @@ -389,7 +436,7 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf, (param[2] > POST_CURSOR2_MAX_LEVEL)) { kfree(wr_buf); DRM_DEBUG_DRIVER("Invalid Input No HW will be programmed\n"); - return bytes_from_user; + return size; } /* get link settings: lane count, link rate */ @@ -429,7 +476,7 @@ static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf, dc_link_set_drive_settings(dc, &link_lane_settings, link); kfree(wr_buf); - return bytes_from_user; + return size; } /* function description @@ -496,19 +543,13 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us struct amdgpu_dm_connector *connector = file_inode(f)->i_private; struct dc_link *link = connector->dc_link; char *wr_buf = NULL; - char *wr_buf_ptr = NULL; uint32_t wr_buf_size = 100; - uint32_t wr_buf_count = 0; - int r; - int bytes_from_user; - char *sub_str = NULL; - uint8_t param_index = 0; - uint8_t param_nums = 0; long param[11] = {0x0}; - const char delimiter[3] = {' ', '\n', '\0'}; + int max_param_num = 11; enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; bool disable_hpd = false; bool valid_test_pattern = false; + uint8_t param_nums = 0; /* init with defalut 80bit custom pattern */ uint8_t custom_pattern[10] = { 0x1f, 0x7c, 0xf0, 0xc1, 0x07, @@ -522,70 +563,26 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us int i; if (size == 0) - return 0; + return -EINVAL; wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); if (!wr_buf) - return 0; - wr_buf_ptr = wr_buf; + return -ENOSPC; - r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); - - /* r is bytes not be copied */ - if (r >= wr_buf_size) { + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { kfree(wr_buf); - DRM_DEBUG_DRIVER("user data not be read\n"); - return 0; - } - - bytes_from_user = wr_buf_size - r; - - /* check number of parameters. isspace could not differ space and \n */ - while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) { - /* skip space*/ - while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { - wr_buf_ptr++; - wr_buf_count++; - } - - if (wr_buf_count == wr_buf_size) - break; - - /* skip non-space*/ - while ((!isspace(*wr_buf_ptr)) && (wr_buf_count < wr_buf_size)) { - wr_buf_ptr++; - wr_buf_count++; - } - - param_nums++; - - if (wr_buf_count == wr_buf_size) - break; + return -EINVAL; } - /* max 11 parameters */ - if (param_nums > 11) - param_nums = 11; - - wr_buf_ptr = wr_buf; /* reset buf pinter */ - wr_buf_count = 0; /* number of char already checked */ - - while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { - wr_buf_ptr++; - wr_buf_count++; + if (param_nums <= 0) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not be read\n"); + return -EINVAL; } - while (param_index < param_nums) { - /* after strsep, wr_buf_ptr will be moved to after space */ - sub_str = strsep(&wr_buf_ptr, delimiter); - - r = kstrtol(sub_str, 16, ¶m[param_index]); - - if (r) - DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); - - param_index++; - } test_pattern = param[0]; @@ -618,7 +615,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us if (!valid_test_pattern) { kfree(wr_buf); DRM_DEBUG_DRIVER("Invalid Test Pattern Parameters\n"); - return bytes_from_user; + return size; } if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { @@ -685,7 +682,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us kfree(wr_buf); - return bytes_from_user; + return size; } /** 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 cf15248739f7..0affd1997fe7 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 @@ -95,7 +95,6 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - struct amdgpu_encoder *amdgpu_encoder = aconnector->mst_encoder; if (aconnector->dc_sink) { dc_link_remove_remote_sink(aconnector->dc_link, @@ -105,8 +104,6 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector) kfree(aconnector->edid); - drm_encoder_cleanup(&amdgpu_encoder->base); - kfree(amdgpu_encoder); drm_connector_cleanup(connector); drm_dp_mst_put_port_malloc(aconnector->port); kfree(aconnector); @@ -243,7 +240,11 @@ static struct drm_encoder * dm_mst_atomic_best_encoder(struct drm_connector *connector, struct drm_connector_state *connector_state) { - return &to_amdgpu_dm_connector(connector)->mst_encoder->base; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc); + + return &adev->dm.mst_encoders[acrtc->crtc_id].base; } static int @@ -306,31 +307,27 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { .destroy = amdgpu_dm_encoder_destroy, }; -static struct amdgpu_encoder * -dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector) +void +dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev) { - struct drm_device *dev = connector->base.dev; - struct amdgpu_device *adev = dev->dev_private; - struct amdgpu_encoder *amdgpu_encoder; - struct drm_encoder *encoder; - - amdgpu_encoder = kzalloc(sizeof(*amdgpu_encoder), GFP_KERNEL); - if (!amdgpu_encoder) - return NULL; + struct drm_device *dev = adev->ddev; + int i; - encoder = &amdgpu_encoder->base; - encoder->possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev); + for (i = 0; i < adev->dm.display_indexes_num; i++) { + struct amdgpu_encoder *amdgpu_encoder = &adev->dm.mst_encoders[i]; + struct drm_encoder *encoder = &amdgpu_encoder->base; - drm_encoder_init( - dev, - &amdgpu_encoder->base, - &amdgpu_dm_encoder_funcs, - DRM_MODE_ENCODER_DPMST, - NULL); + encoder->possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev); - drm_encoder_helper_add(encoder, &amdgpu_dm_encoder_helper_funcs); + drm_encoder_init( + dev, + &amdgpu_encoder->base, + &amdgpu_dm_encoder_funcs, + DRM_MODE_ENCODER_DPMST, + NULL); - return amdgpu_encoder; + drm_encoder_helper_add(encoder, &amdgpu_dm_encoder_helper_funcs); + } } static struct drm_connector * @@ -343,6 +340,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct amdgpu_device *adev = dev->dev_private; struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; + int i; aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL); if (!aconnector) @@ -369,9 +367,10 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, master->dc_link, master->connector_id); - aconnector->mst_encoder = dm_dp_create_fake_mst_encoder(master); - drm_connector_attach_encoder(&aconnector->base, - &aconnector->mst_encoder->base); + for (i = 0; i < adev->dm.display_indexes_num; i++) { + drm_connector_attach_encoder(&aconnector->base, + &adev->dm.mst_encoders[i].base); + } connector->max_bpc_property = master->base.max_bpc_property; if (connector->max_bpc_property) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index d2c56579a2cc..b38bd68121ce 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -35,6 +35,9 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, struct amdgpu_dm_connector *aconnector, int link_index); +void +dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev); + #if defined(CONFIG_DRM_AMD_DC_DCN) bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state, struct dc_state *dc_state); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index f376058b5df6..6a345d43028c 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -174,9 +174,6 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p case FAMILY_NV: #if defined(CONFIG_DRM_AMD_DC_DCN3_0) if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev)) { - /* TODO: to add SIENNA_CICHLID clk_mgr support, once CLK IP header files are available, - * for now use DCN3AG clk mgr. - */ dcn3_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); break; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c index c320b7af7d34..dbc7cde00433 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c @@ -26,6 +26,7 @@ #include "core_types.h" #include "clk_mgr_internal.h" #include "reg_helper.h" +#include <linux/delay.h> #define MAX_INSTANCE 5 #define MAX_SEGMENT 5 @@ -68,10 +69,42 @@ static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, #define VBIOSSMC_MSG_SetDispclkFreq 0x4 #define VBIOSSMC_MSG_SetDprefclkFreq 0x5 +#define VBIOSSMC_Status_BUSY 0x0 +#define VBIOSSMC_Result_OK 0x1 +#define VBIOSSMC_Result_Failed 0xFF +#define VBIOSSMC_Result_UnknownCmd 0xFE +#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD +#define VBIOSSMC_Result_CmdRejectedBusy 0xFC + +/* + * Function to be used instead of REG_WAIT macro because the wait ends when + * the register is NOT EQUAL to zero, and because the translation in msg_if.h + * won't work with REG_WAIT. + */ +static uint32_t rv1_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries) +{ + uint32_t res_val = VBIOSSMC_Status_BUSY; + + do { + res_val = REG_READ(MP1_SMN_C2PMSG_91); + if (res_val != VBIOSSMC_Status_BUSY) + break; + + if (delay_us >= 1000) + msleep(delay_us/1000); + else if (delay_us > 0) + udelay(delay_us); + } while (max_retries--); + + return res_val; +} + int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param) { + uint32_t result; + /* First clear response register */ - REG_WRITE(MP1_SMN_C2PMSG_91, 0); + REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY); /* Set the parameter register for the SMU message, unit is Mhz */ REG_WRITE(MP1_SMN_C2PMSG_83, param); @@ -79,7 +112,9 @@ int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned /* Trigger the message transaction by writing the message ID */ REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); - REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000); + result = rv1_smu_wait_for_response(clk_mgr, 10, 1000); + + ASSERT(result == VBIOSSMC_Result_OK); /* Actual dispclk set is returned in the parameter register */ return REG_READ(MP1_SMN_C2PMSG_83); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c index c63ec960e116..f2114bc910bf 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c @@ -184,13 +184,6 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, pp_smu->set_display_count(&pp_smu->pp_smu, display_count); } - if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) { - clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz; - if (pp_smu && pp_smu->set_voltage_by_freq) - pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PHYCLK, clk_mgr_base->clks.phyclk_khz / 1000); - } - - if (dc->debug.force_min_dcfclk_mhz > 0) new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); @@ -417,8 +410,6 @@ static bool dcn2_are_clock_states_equal(struct dc_clocks *a, return false; else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) return false; - else if (a->phyclk_khz != b->phyclk_khz) - return false; else if (a->dramclk_khz != b->dramclk_khz) return false; else if (a->p_state_change_support != b->p_state_change_support) @@ -427,6 +418,31 @@ static bool dcn2_are_clock_states_equal(struct dc_clocks *a, return true; } +/* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */ +static void dcn2_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_link *link) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + unsigned int i, max_phyclk_req = 0; + struct pp_smu_funcs_nv *pp_smu = NULL; + + if (!clk_mgr->pp_smu || !clk_mgr->pp_smu->nv_funcs.set_voltage_by_freq) + return; + + pp_smu = &clk_mgr->pp_smu->nv_funcs; + + clk_mgr->cur_phyclk_req_table[link->link_index] = link->cur_link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ; + + for (i = 0; i < MAX_PIPES * 2; i++) { + if (clk_mgr->cur_phyclk_req_table[i] > max_phyclk_req) + max_phyclk_req = clk_mgr->cur_phyclk_req_table[i]; + } + + if (max_phyclk_req != clk_mgr_base->clks.phyclk_khz) { + clk_mgr_base->clks.phyclk_khz = max_phyclk_req; + pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PHYCLK, clk_mgr_base->clks.phyclk_khz / 1000); + } +} + static struct clk_mgr_funcs dcn2_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = dcn2_update_clocks, @@ -434,6 +450,7 @@ static struct clk_mgr_funcs dcn2_funcs = { .enable_pme_wa = dcn2_enable_pme_wa, .get_clock = dcn2_get_clock, .are_clock_states_equal = dcn2_are_clock_states_equal, + .notify_link_rate_change = dcn2_notify_link_rate_change, }; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c index 39788a7bd003..c664404a75d4 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c @@ -136,11 +136,6 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base, } } - if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) { - clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz; - rn_vbios_smu_set_phyclk(clk_mgr, clk_mgr_base->clks.phyclk_khz); - } - if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; rn_vbios_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); @@ -496,13 +491,33 @@ static bool rn_are_clock_states_equal(struct dc_clocks *a, } +/* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */ +static void rn_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_link *link) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + unsigned int i, max_phyclk_req = 0; + + clk_mgr->cur_phyclk_req_table[link->link_index] = link->cur_link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ; + + for (i = 0; i < MAX_PIPES * 2; i++) { + if (clk_mgr->cur_phyclk_req_table[i] > max_phyclk_req) + max_phyclk_req = clk_mgr->cur_phyclk_req_table[i]; + } + + if (max_phyclk_req != clk_mgr_base->clks.phyclk_khz) { + clk_mgr_base->clks.phyclk_khz = max_phyclk_req; + rn_vbios_smu_set_phyclk(clk_mgr, clk_mgr_base->clks.phyclk_khz); + } +} + static struct clk_mgr_funcs dcn21_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = rn_update_clocks, .init_clocks = rn_init_clocks, .enable_pme_wa = rn_enable_pme_wa, .are_clock_states_equal = rn_are_clock_states_equal, - .notify_wm_ranges = rn_notify_wm_ranges + .notify_wm_ranges = rn_notify_wm_ranges, + .notify_link_rate_change = rn_notify_link_rate_change, }; static struct clk_bw_params rn_bw_params = { @@ -619,6 +634,42 @@ static struct wm_table lpddr4_wm_table = { } }; +static struct wm_table lpddr4_wm_table_with_disabled_ppt = { + .entries = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 8.32, + .sr_enter_plus_exit_time_us = 9.38, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.82, + .sr_enter_plus_exit_time_us = 11.196, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.89, + .sr_enter_plus_exit_time_us = 11.24, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.748, + .sr_enter_plus_exit_time_us = 11.102, + .valid = true, + }, + } +}; static unsigned int find_dcfclk_for_voltage(struct dpm_clocks *clock_table, unsigned int voltage) { @@ -723,6 +774,7 @@ void rn_clk_mgr_construct( struct clk_log_info log_info = {0}; clk_mgr->smu_ver = rn_vbios_smu_get_smu_version(clk_mgr); + clk_mgr->periodic_retraining_disabled = rn_vbios_smu_is_periodic_retraining_disabled(clk_mgr); /* SMU Version 55.51.0 and up no longer have an issue * that needs to limit minimum dispclk */ @@ -737,7 +789,11 @@ void rn_clk_mgr_construct( clk_mgr->base.dentist_vco_freq_khz = 3600000; if (ctx->dc_bios->integrated_info->memory_type == LpDdr4MemType) { - rn_bw_params.wm_table = lpddr4_wm_table; + if (clk_mgr->periodic_retraining_disabled) { + rn_bw_params.wm_table = lpddr4_wm_table_with_disabled_ppt; + } else { + rn_bw_params.wm_table = lpddr4_wm_table; + } } else { rn_bw_params.wm_table = ddr4_wm_table; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c index 6878aedf1d3e..9a374522e963 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c @@ -26,6 +26,7 @@ #include "core_types.h" #include "clk_mgr_internal.h" #include "reg_helper.h" +#include <linux/delay.h> #include "renoir_ip_offset.h" @@ -51,12 +52,46 @@ #define VBIOSSMC_MSG_GetFclkFrequency 0xB #define VBIOSSMC_MSG_SetDisplayCount 0xC #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD -#define VBIOSSMC_MSG_UpdatePmeRestore 0xE +#define VBIOSSMC_MSG_UpdatePmeRestore 0xE +#define VBIOSSMC_MSG_IsPeriodicRetrainingDisabled 0xF + +#define VBIOSSMC_Status_BUSY 0x0 +#define VBIOSSMC_Result_OK 0x1 +#define VBIOSSMC_Result_Failed 0xFF +#define VBIOSSMC_Result_UnknownCmd 0xFE +#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD +#define VBIOSSMC_Result_CmdRejectedBusy 0xFC + +/* + * Function to be used instead of REG_WAIT macro because the wait ends when + * the register is NOT EQUAL to zero, and because the translation in msg_if.h + * won't work with REG_WAIT. + */ +static uint32_t rn_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries) +{ + uint32_t res_val = VBIOSSMC_Status_BUSY; + + do { + res_val = REG_READ(MP1_SMN_C2PMSG_91); + if (res_val != VBIOSSMC_Status_BUSY) + break; + + if (delay_us >= 1000) + msleep(delay_us/1000); + else if (delay_us > 0) + udelay(delay_us); + } while (max_retries--); + + return res_val; +} + int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param) { + uint32_t result; + /* First clear response register */ - REG_WRITE(MP1_SMN_C2PMSG_91, 0); + REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY); /* Set the parameter register for the SMU message, unit is Mhz */ REG_WRITE(MP1_SMN_C2PMSG_83, param); @@ -64,7 +99,9 @@ int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned /* Trigger the message transaction by writing the message ID */ REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); - REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000); + result = rn_smu_wait_for_response(clk_mgr, 10, 1000); + + ASSERT(result == VBIOSSMC_Result_OK || result == VBIOSSMC_Result_UnknownCmd); /* Actual dispclk set is returned in the parameter register */ return REG_READ(MP1_SMN_C2PMSG_83); @@ -196,3 +233,11 @@ void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) VBIOSSMC_MSG_UpdatePmeRestore, 0); } + +int rn_vbios_smu_is_periodic_retraining_disabled(struct clk_mgr_internal *clk_mgr) +{ + return rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_IsPeriodicRetrainingDisabled, + 0); +} diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h index ccc01879c9d4..3e5df27aa96f 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h @@ -36,5 +36,6 @@ int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_ void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, int display_count); void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable); void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr); +int rn_vbios_smu_is_periodic_retraining_disabled(struct clk_mgr_internal *clk_mgr); #endif /* DAL_DC_DCN10_RV1_CLK_MGR_VBIOS_SMU_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c index b27cb52903f5..d94fdc52be37 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c @@ -260,11 +260,6 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base, if (enter_display_off == safe_to_lower) dcn30_smu_set_num_of_displays(clk_mgr, display_count); - if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) { - clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz; - dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_PHYCLK, clk_mgr_base->clks.phyclk_khz / 1000); - } - if (dc->debug.force_min_dcfclk_mhz > 0) new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); @@ -344,16 +339,12 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base, static void dcn3_notify_wm_ranges(struct clk_mgr *clk_mgr_base) { unsigned int i; - long long table_addr; - WatermarksExternal_t *table; struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + WatermarksExternal_t *table = (WatermarksExternal_t *) clk_mgr->wm_range_table; if (!clk_mgr->smu_present) return; - /* need physical address of table to give to PMFW */ - table = (WatermarksExternal_t *) dm_helpers_allocate_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, sizeof(WatermarksExternal_t), &table_addr); - if (!table) // should log failure return; @@ -371,11 +362,9 @@ static void dcn3_notify_wm_ranges(struct clk_mgr *clk_mgr_base) table->Watermarks.WatermarkRow[WM_DCEFCLK][i].Flags = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.wm_type; } - dcn30_smu_set_dram_addr_high(clk_mgr, table_addr >> 32); - dcn30_smu_set_dram_addr_low(clk_mgr, table_addr & 0xFFFFFFFF); + dcn30_smu_set_dram_addr_high(clk_mgr, clk_mgr->wm_range_table_addr >> 32); + dcn30_smu_set_dram_addr_low(clk_mgr, clk_mgr->wm_range_table_addr & 0xFFFFFFFF); dcn30_smu_transfer_wm_table_dram_2_smu(clk_mgr); - - dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, table); } /* Set min memclk to minimum, either constrained by the current mode or DPM0 */ @@ -437,8 +426,6 @@ static bool dcn3_are_clock_states_equal(struct dc_clocks *a, return false; else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) return false; - else if (a->phyclk_khz != b->phyclk_khz) - return false; else if (a->dramclk_khz != b->dramclk_khz) return false; else if (a->p_state_change_support != b->p_state_change_support) @@ -457,6 +444,28 @@ static void dcn3_enable_pme_wa(struct clk_mgr *clk_mgr_base) dcn30_smu_set_pme_workaround(clk_mgr); } +/* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */ +static void dcn30_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_link *link) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + unsigned int i, max_phyclk_req = clk_mgr_base->bw_params->clk_table.entries[0].phyclk_mhz * 1000; + + if (!clk_mgr->smu_present) + return; + + clk_mgr->cur_phyclk_req_table[link->link_index] = link->cur_link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ; + + for (i = 0; i < MAX_PIPES * 2; i++) { + if (clk_mgr->cur_phyclk_req_table[i] > max_phyclk_req) + max_phyclk_req = clk_mgr->cur_phyclk_req_table[i]; + } + + if (max_phyclk_req != clk_mgr_base->clks.phyclk_khz) { + clk_mgr_base->clks.phyclk_khz = max_phyclk_req; + dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_PHYCLK, clk_mgr_base->clks.phyclk_khz / 1000); + } +} + static struct clk_mgr_funcs dcn3_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = dcn3_update_clocks, @@ -466,7 +475,8 @@ static struct clk_mgr_funcs dcn3_funcs = { .set_hard_max_memclk = dcn3_set_hard_max_memclk, .get_memclk_states_from_smu = dcn3_get_memclk_states_from_smu, .are_clock_states_equal = dcn3_are_clock_states_equal, - .enable_pme_wa = dcn3_enable_pme_wa + .enable_pme_wa = dcn3_enable_pme_wa, + .notify_link_rate_change = dcn30_notify_link_rate_change, }; static void dcn3_init_clocks_fpga(struct clk_mgr *clk_mgr) @@ -534,10 +544,19 @@ void dcn3_clk_mgr_construct( dce_clock_read_ss_info(clk_mgr); clk_mgr->base.bw_params = kzalloc(sizeof(*clk_mgr->base.bw_params), GFP_KERNEL); + + /* need physical address of table to give to PMFW */ + clk_mgr->wm_range_table = dm_helpers_allocate_gpu_mem(clk_mgr->base.ctx, + DC_MEM_ALLOC_TYPE_GART, sizeof(WatermarksExternal_t), + &clk_mgr->wm_range_table_addr); } void dcn3_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr) { if (clk_mgr->base.bw_params) kfree(clk_mgr->base.bw_params); + + if (clk_mgr->wm_range_table) + dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, + clk_mgr->wm_range_table); } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c index 986c53a3b6a8..7ee3ec5a8af8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c @@ -37,6 +37,13 @@ #define REG(reg_name) \ mm ## reg_name +#include "logger_types.h" +#undef DC_LOGGER +#define DC_LOGGER \ + CTX->logger +#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); } + + /* * Function to be used instead of REG_WAIT macro because the wait ends when * the register is NOT EQUAL to zero, and because the translation in msg_if.h @@ -94,6 +101,8 @@ bool dcn30_smu_test_message(struct clk_mgr_internal *clk_mgr, uint32_t input) { uint32_t response = 0; + smu_print("SMU Test message: %d\n", input); + if (dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_TestMessage, input, &response)) if (response == input + 1) @@ -104,9 +113,15 @@ bool dcn30_smu_test_message(struct clk_mgr_internal *clk_mgr, uint32_t input) bool dcn30_smu_get_smu_version(struct clk_mgr_internal *clk_mgr, unsigned int *version) { + smu_print("SMU Get SMU version\n"); + if (dcn30_smu_send_msg_with_param(clk_mgr, - DALSMC_MSG_GetSmuVersion, 0, version)) + DALSMC_MSG_GetSmuVersion, 0, version)) { + + smu_print("SMU version: %d\n", *version); + return true; + } return false; } @@ -116,10 +131,16 @@ bool dcn30_smu_check_driver_if_version(struct clk_mgr_internal *clk_mgr) { uint32_t response = 0; + smu_print("SMU Check driver if version\n"); + if (dcn30_smu_send_msg_with_param(clk_mgr, - DALSMC_MSG_GetDriverIfVersion, 0, &response)) + DALSMC_MSG_GetDriverIfVersion, 0, &response)) { + + smu_print("SMU driver if version: %d\n", response); + if (response == SMU11_DRIVER_IF_VERSION) return true; + } return false; } @@ -129,34 +150,48 @@ bool dcn30_smu_check_msg_header_version(struct clk_mgr_internal *clk_mgr) { uint32_t response = 0; + smu_print("SMU Check msg header version\n"); + if (dcn30_smu_send_msg_with_param(clk_mgr, - DALSMC_MSG_GetMsgHeaderVersion, 0, &response)) + DALSMC_MSG_GetMsgHeaderVersion, 0, &response)) { + + smu_print("SMU msg header version: %d\n", response); + if (response == DALSMC_VERSION) return true; + } return false; } void dcn30_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high) { + smu_print("SMU Set DRAM addr high: %d\n", addr_high); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetDalDramAddrHigh, addr_high, NULL); } void dcn30_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low) { + smu_print("SMU Set DRAM addr low: %d\n", addr_low); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetDalDramAddrLow, addr_low, NULL); } void dcn30_smu_transfer_wm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr) { + smu_print("SMU Transfer WM table SMU 2 DRAM\n"); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_TransferTableSmu2Dram, TABLE_WATERMARKS, NULL); } void dcn30_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr) { + smu_print("SMU Transfer WM table DRAM 2 SMU\n"); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS, NULL); } @@ -169,9 +204,13 @@ unsigned int dcn30_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, PP /* bits 23:16 for clock type, lower 16 bits for frequency in MHz */ uint32_t param = (clk << 16) | freq_mhz; + smu_print("SMU Set hard min by freq: clk = %d, freq_mhz = %d MHz\n", clk, freq_mhz); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetHardMinByFreq, param, &response); + smu_print("SMU Frequency set = %d MHz\n", response); + return response; } @@ -183,9 +222,13 @@ unsigned int dcn30_smu_set_hard_max_by_freq(struct clk_mgr_internal *clk_mgr, PP /* bits 23:16 for clock type, lower 16 bits for frequency in MHz */ uint32_t param = (clk << 16) | freq_mhz; + smu_print("SMU Set hard max by freq: clk = %d, freq_mhz = %d MHz\n", clk, freq_mhz); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetHardMaxByFreq, param, &response); + smu_print("SMU Frequency set = %d MHz\n", response); + return response; } @@ -210,9 +253,13 @@ unsigned int dcn30_smu_get_dpm_freq_by_index(struct clk_mgr_internal *clk_mgr, P /* bits 23:16 for clock type, lower 8 bits for DPM level */ uint32_t param = (clk << 16) | dpm_level; + smu_print("SMU Get dpm freq by index: clk = %d, dpm_level = %d\n", clk, dpm_level); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_GetDpmFreqByIndex, param, &response); + smu_print("SMU dpm freq: %d MHz\n", response); + return response; } @@ -224,32 +271,44 @@ unsigned int dcn30_smu_get_dc_mode_max_dpm_freq(struct clk_mgr_internal *clk_mgr /* bits 23:16 for clock type */ uint32_t param = clk << 16; + smu_print("SMU Get DC mode max DPM freq: clk = %d\n", clk); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_GetDcModeMaxDpmFreq, param, &response); + smu_print("SMU DC mode max DMP freq: %d MHz\n", response); + return response; } void dcn30_smu_set_min_deep_sleep_dcef_clk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz) { + smu_print("SMU Set min deep sleep dcef clk: freq_mhz = %d MHz\n", freq_mhz); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetMinDeepSleepDcefclk, freq_mhz, NULL); } void dcn30_smu_set_num_of_displays(struct clk_mgr_internal *clk_mgr, uint32_t num_displays) { + smu_print("SMU Set num of displays: num_displays = %d\n", num_displays); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_NumOfDisplays, num_displays, NULL); } void dcn30_smu_set_external_client_df_cstate_allow(struct clk_mgr_internal *clk_mgr, bool enable) { + smu_print("SMU Set external client df cstate allow: enable = %d\n", enable); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetExternalClientDfCstateAllow, enable ? 1 : 0, NULL); } void dcn30_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr) { + smu_print("SMU Set PME workaround\n"); + dcn30_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_BacoAudioD3PME, 0, NULL); } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 67402d75e67e..ef0b5941bc50 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2324,7 +2324,7 @@ static void commit_planes_for_stream(struct dc *dc, if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { - if (stream && should_use_dmub_lock(stream->link)) { + if (should_use_dmub_lock(stream->link)) { union dmub_hw_lock_flags hw_locks = { 0 }; struct dmub_hw_lock_inst_flags inst_flags = { 0 }; @@ -2607,10 +2607,12 @@ void dc_commit_updates_for_stream(struct dc *dc, copy_stream_update_to_stream(dc, context, stream, stream_update); - if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { - DC_ERROR("Mode validation failed for stream update!\n"); - dc_release_state(context); - return; + if (update_type > UPDATE_TYPE_FAST) { + if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { + DC_ERROR("Mode validation failed for stream update!\n"); + dc_release_state(context); + return; + } } commit_planes_for_stream( @@ -2681,6 +2683,12 @@ void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) dal_irq_service_ack(dc->res_pool->irqs, src); } +void dc_power_down_on_boot(struct dc *dc) +{ + if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW && + dc->hwss.power_down_on_boot) + dc->hwss.power_down_on_boot(dc); +} void dc_set_power_state( struct dc *dc, @@ -2693,6 +2701,9 @@ void dc_set_power_state( case DC_ACPI_CM_POWER_STATE_D0: dc_resource_state_construct(dc, dc->current_state); + if (dc->ctx->dmub_srv) + dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv); + dc->hwss.init_hw(dc); if (dc->hwss.init_sys_ctx != NULL && diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 3d969f83b3cc..1f94591ce5fb 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -3097,62 +3097,63 @@ static void get_active_converter_info( uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/ union dwnstream_port_caps_byte0 *port_caps = (union dwnstream_port_caps_byte0 *)det_caps; - core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0, - det_caps, sizeof(det_caps)); + if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0, + det_caps, sizeof(det_caps)) == DC_OK) { - switch (port_caps->bits.DWN_STRM_PORTX_TYPE) { - /*Handle DP case as DONGLE_NONE*/ - case DOWN_STREAM_DETAILED_DP: - link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; - break; - case DOWN_STREAM_DETAILED_VGA: - link->dpcd_caps.dongle_type = - DISPLAY_DONGLE_DP_VGA_CONVERTER; - break; - case DOWN_STREAM_DETAILED_DVI: - link->dpcd_caps.dongle_type = - DISPLAY_DONGLE_DP_DVI_CONVERTER; - break; - case DOWN_STREAM_DETAILED_HDMI: - case DOWN_STREAM_DETAILED_DP_PLUS_PLUS: - /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/ - link->dpcd_caps.dongle_type = - DISPLAY_DONGLE_DP_HDMI_CONVERTER; - - link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type; - if (ds_port.fields.DETAILED_CAPS) { - - union dwnstream_port_caps_byte3_hdmi - hdmi_caps = {.raw = det_caps[3] }; - union dwnstream_port_caps_byte2 - hdmi_color_caps = {.raw = det_caps[2] }; - link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz = - det_caps[1] * 2500; - - link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter = - hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK; - /*YCBCR capability only for HDMI case*/ - if (port_caps->bits.DWN_STRM_PORTX_TYPE - == DOWN_STREAM_DETAILED_HDMI) { - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through = - hdmi_caps.bits.YCrCr422_PASS_THROUGH; - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through = - hdmi_caps.bits.YCrCr420_PASS_THROUGH; - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter = - hdmi_caps.bits.YCrCr422_CONVERSION; - link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter = - hdmi_caps.bits.YCrCr420_CONVERSION; + switch (port_caps->bits.DWN_STRM_PORTX_TYPE) { + /*Handle DP case as DONGLE_NONE*/ + case DOWN_STREAM_DETAILED_DP: + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; + break; + case DOWN_STREAM_DETAILED_VGA: + link->dpcd_caps.dongle_type = + DISPLAY_DONGLE_DP_VGA_CONVERTER; + break; + case DOWN_STREAM_DETAILED_DVI: + link->dpcd_caps.dongle_type = + DISPLAY_DONGLE_DP_DVI_CONVERTER; + break; + case DOWN_STREAM_DETAILED_HDMI: + case DOWN_STREAM_DETAILED_DP_PLUS_PLUS: + /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/ + link->dpcd_caps.dongle_type = + DISPLAY_DONGLE_DP_HDMI_CONVERTER; + + link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type; + if (ds_port.fields.DETAILED_CAPS) { + + union dwnstream_port_caps_byte3_hdmi + hdmi_caps = {.raw = det_caps[3] }; + union dwnstream_port_caps_byte2 + hdmi_color_caps = {.raw = det_caps[2] }; + link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz = + det_caps[1] * 2500; + + link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter = + hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK; + /*YCBCR capability only for HDMI case*/ + if (port_caps->bits.DWN_STRM_PORTX_TYPE + == DOWN_STREAM_DETAILED_HDMI) { + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through = + hdmi_caps.bits.YCrCr422_PASS_THROUGH; + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through = + hdmi_caps.bits.YCrCr420_PASS_THROUGH; + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter = + hdmi_caps.bits.YCrCr422_CONVERSION; + link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter = + hdmi_caps.bits.YCrCr420_CONVERSION; + } + + link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc = + translate_dpcd_max_bpc( + hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT); + + if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0) + link->dpcd_caps.dongle_caps.extendedCapValid = true; } - link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc = - translate_dpcd_max_bpc( - hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT); - - if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0) - link->dpcd_caps.dongle_caps.extendedCapValid = true; + break; } - - break; } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 1b3474aa380d..dd88eb348dfa 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -14,6 +14,7 @@ #include "dpcd_defs.h" #include "dsc.h" #include "resource.h" +#include "clk_mgr.h" static uint8_t convert_to_count(uint8_t lttpr_repeater_count) { @@ -123,6 +124,11 @@ void dp_enable_link_phy( } } + link->cur_link_settings = *link_settings; + + if (dc->clk_mgr->funcs->notify_link_rate_change) + dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); + if (dmcu != NULL && dmcu->funcs->lock_phy) dmcu->funcs->lock_phy(dmcu); @@ -141,8 +147,6 @@ void dp_enable_link_phy( if (dmcu != NULL && dmcu->funcs->unlock_phy) dmcu->funcs->unlock_phy(dmcu); - link->cur_link_settings = *link_settings; - dp_receiver_power_ctrl(link, true); } @@ -151,7 +155,8 @@ bool edp_receiver_ready_T9(struct dc_link *link) unsigned int tries = 0; unsigned char sinkstatus = 0; unsigned char edpRev = 0; - enum dc_status result = DC_OK; + enum dc_status result; + result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev)); /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ @@ -177,7 +182,7 @@ bool edp_receiver_ready_T7(struct dc_link *link) { unsigned char sinkstatus = 0; unsigned char edpRev = 0; - enum dc_status result = DC_OK; + enum dc_status result; /* use absolute time stamp to constrain max T7*/ unsigned long long enter_timestamp = 0; @@ -233,6 +238,9 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) /* Clear current link setting.*/ memset(&link->cur_link_settings, 0, sizeof(link->cur_link_settings)); + + if (dc->clk_mgr->funcs->notify_link_rate_change) + dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); } void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 1000dc6daf72..7b5f90ebb133 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1162,19 +1162,32 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) /* May need to re-check lb size after this in some obscure scenario */ calculate_inits_and_adj_vp(pipe_ctx); - DC_LOG_SCALER( - "%s: Viewport:\nheight:%d width:%d x:%d " - "y:%d\n dst_rect:\nheight:%d width:%d x:%d " - "y:%d\n", - __func__, - pipe_ctx->plane_res.scl_data.viewport.height, - pipe_ctx->plane_res.scl_data.viewport.width, - pipe_ctx->plane_res.scl_data.viewport.x, - pipe_ctx->plane_res.scl_data.viewport.y, - plane_state->dst_rect.height, - plane_state->dst_rect.width, - plane_state->dst_rect.x, - plane_state->dst_rect.y); + DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n" + "src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n", + __func__, + pipe_ctx->pipe_idx, + pipe_ctx->plane_res.scl_data.viewport.height, + pipe_ctx->plane_res.scl_data.viewport.width, + pipe_ctx->plane_res.scl_data.viewport.x, + pipe_ctx->plane_res.scl_data.viewport.y, + pipe_ctx->plane_res.scl_data.recout.height, + pipe_ctx->plane_res.scl_data.recout.width, + pipe_ctx->plane_res.scl_data.recout.x, + pipe_ctx->plane_res.scl_data.recout.y, + pipe_ctx->plane_res.scl_data.h_active, + pipe_ctx->plane_res.scl_data.v_active, + plane_state->src_rect.height, + plane_state->src_rect.width, + plane_state->src_rect.x, + plane_state->src_rect.y, + plane_state->dst_rect.height, + plane_state->dst_rect.width, + plane_state->dst_rect.x, + plane_state->dst_rect.y, + plane_state->clip_rect.height, + plane_state->clip_rect.width, + plane_state->clip_rect.x, + plane_state->clip_rect.y); if (store_h_border_left) restore_border_left_from_dst(pipe_ctx, store_h_border_left); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 3b897372ed27..d6989d115c5c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -56,7 +56,7 @@ void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink) } } -static void dc_stream_construct(struct dc_stream_state *stream, +static bool dc_stream_construct(struct dc_stream_state *stream, struct dc_sink *dc_sink_data) { uint32_t i = 0; @@ -118,11 +118,17 @@ static void dc_stream_construct(struct dc_stream_state *stream, update_stream_signal(stream, dc_sink_data); stream->out_transfer_func = dc_create_transfer_func(); + if (stream->out_transfer_func == NULL) { + dc_sink_release(dc_sink_data); + return false; + } stream->out_transfer_func->type = TF_TYPE_BYPASS; stream->out_transfer_func->ctx = stream->ctx; stream->stream_id = stream->ctx->dc_stream_id_count; stream->ctx->dc_stream_id_count++; + + return true; } static void dc_stream_destruct(struct dc_stream_state *stream) @@ -164,13 +170,20 @@ struct dc_stream_state *dc_create_stream_for_sink( stream = kzalloc(sizeof(struct dc_stream_state), GFP_KERNEL); if (stream == NULL) - return NULL; + goto alloc_fail; - dc_stream_construct(stream, sink); + if (dc_stream_construct(stream, sink) == false) + goto construct_fail; kref_init(&stream->refcount); return stream; + +construct_fail: + kfree(stream); + +alloc_fail: + return NULL; } struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f7cb1354a635..e5a1a9eb6217 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -42,7 +42,7 @@ #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.91" +#define DC_VER "3.2.94" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -466,6 +466,7 @@ struct dc_debug_options { bool scl_reset_length10; bool hdmi20_disable; bool skip_detection_link_training; + bool edid_read_retry_times; bool remove_disconnect_edp; unsigned int force_odm_combine; //bit vector based on otg inst #if defined(CONFIG_DRM_AMD_DC_DCN3_0) @@ -1028,6 +1029,7 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc); */ bool dc_commit_state(struct dc *dc, struct dc_state *context); +void dc_power_down_on_boot(struct dc *dc); struct dc_state *dc_create_state(struct dc *dc); struct dc_state *dc_copy_state(struct dc_state *src_ctx); @@ -1228,6 +1230,8 @@ void dc_set_power_state( enum dc_acpi_cm_power_state power_state); void dc_resume(struct dc *dc); +void dc_power_down_on_boot(struct dc *dc); + #if defined(CONFIG_DRM_AMD_DC_HDCP) /* * HDCP Interfaces diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 96532f7ba480..eea2429ac67d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -106,17 +106,29 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); } -bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv) +void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) { - struct dmub_srv *dmub; - union dmub_fw_boot_status status; + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; - if (!dc_dmub_srv || !dc_dmub_srv->dmub) - return false; + for (;;) { + /* Wait up to a second for PHY init. */ + status = dmub_srv_wait_for_phy_init(dmub, 1000000); + if (status == DMUB_STATUS_OK) + /* Initialization OK */ + break; - dmub = dc_dmub_srv->dmub; + DC_ERROR("DMCUB PHY init failed: status=%d\n", status); + ASSERT(0); - status = dmub->hw_funcs.get_fw_status(dmub); + if (status != DMUB_STATUS_TIMEOUT) + /* + * Server likely initialized or we don't have + * DMCUB HW support - this won't end. + */ + break; - return status.bits.optimized_init_done; + /* Continue spinning so we don't hang the ASIC. */ + } } diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index 8bd20d0d7689..a3a09ccb6d26 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -56,6 +56,4 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv); void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv); -bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv); - #endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index d64241433548..29fe5389f973 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -177,6 +177,7 @@ enum dc_edid_status { EDID_NO_RESPONSE, EDID_BAD_CHECKSUM, EDID_THE_SAME, + EDID_FALL_BACK, }; enum act_return_status { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index 916d305d3022..82e67bd81f2d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -234,6 +234,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, copy_settings_data->debug.bitfields.visual_confirm = dc->dc->debug.visual_confirm == VISUAL_CONFIRM_PSR ? true : false; copy_settings_data->init_sdp_deadline = psr_context->sdpTransmitLineNumDeadline; + copy_settings_data->debug.bitfields.use_hw_lock_mgr = 0; dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); dc_dmub_srv_cmd_execute(dc->dmub_srv); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index cb45f05a0319..da0897fe3b54 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1255,6 +1255,7 @@ void dcn10_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + bool is_optimized_init_done = false; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -1288,8 +1289,7 @@ void dcn10_init_hw(struct dc *dc) if (!dcb->funcs->is_accelerated_mode(dcb)) hws->funcs.disable_vga(dc->hwseq); - if (!dc_dmub_srv_optimized_init_done(dc->ctx->dmub_srv)) - hws->funcs.bios_golden_init(dc); + hws->funcs.bios_golden_init(dc); if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = @@ -1323,7 +1323,8 @@ void dcn10_init_hw(struct dc *dc) */ struct dc_link *link = dc->links[i]; - link->link_enc->funcs->hw_init(link->link_enc); + if (!is_optimized_init_done) + link->link_enc->funcs->hw_init(link->link_enc); /* Check for enabled DIG to identify enabled display */ if (link->link_enc->funcs->is_dig_enabled && @@ -1332,9 +1333,11 @@ void dcn10_init_hw(struct dc *dc) } /* Power gate DSCs */ - for (i = 0; i < res_pool->res_cap->num_dsc; i++) - if (hws->funcs.dsc_pg_control != NULL) - hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); + if (!is_optimized_init_done) { + for (i = 0; i < res_pool->res_cap->num_dsc; i++) + if (hws->funcs.dsc_pg_control != NULL) + hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); + } /* we want to turn off all dp displays before doing detection */ if (dc->config.power_down_display_on_boot) { @@ -1379,68 +1382,42 @@ void dcn10_init_hw(struct dc *dc) * everything down. */ if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + if (!is_optimized_init_done) { + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } } - /* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on and seamless boot not enabled - */ - if (dc->config.power_down_display_on_boot) { - struct dc_link *edp_link = get_edp_link(dc); + if (!is_optimized_init_done) { - if (edp_link && - edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwseq->funcs.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwseq->funcs.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } + audio->funcs->hw_init(audio); } - } - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; - audio->funcs->hw_init(audio); - } + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; + if (abm != NULL) + abm->funcs->abm_init(abm, backlight); - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + if (dmcu != NULL && !dmcu->auto_load_dmcu) + dmcu->funcs->dmcu_init(dmcu); } - if (abm != NULL) - abm->funcs->abm_init(abm, backlight); - - if (dmcu != NULL && !dmcu->auto_load_dmcu) - dmcu->funcs->dmcu_init(dmcu); - if (abm != NULL && dmcu != NULL) abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (!is_optimized_init_done) + REG_WRITE(DIO_MEM_PWR_CTRL, 0); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ @@ -1463,6 +1440,43 @@ void dcn10_init_hw(struct dc *dc) } +/* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on and seamless boot not enabled + */ +void dcn10_power_down_on_boot(struct dc *dc) +{ + int i = 0; + + if (dc->config.power_down_display_on_boot) { + struct dc_link *edp_link = get_edp_link(dc); + + if (edp_link && + edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwseq->funcs.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwseq->funcs.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + } +} + void dcn10_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context) @@ -2445,14 +2459,46 @@ static void dcn10_update_dchubp_dpp( struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct plane_size size = plane_state->plane_size; unsigned int compat_level = 0; + bool should_divided_by_2 = false; /* depends on DML calculation, DPP clock value may change dynamically */ /* If request max dpp clk is lower than current dispclk, no need to * divided by 2 */ if (plane_state->update_flags.bits.full_update) { - bool should_divided_by_2 = context->bw_ctx.bw.dcn.clk.dppclk_khz <= - dc->clk_mgr->clks.dispclk_khz / 2; + + /* new calculated dispclk, dppclk are stored in + * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current + * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. + * dcn_validate_bandwidth compute new dispclk, dppclk. + * dispclk will put in use after optimize_bandwidth when + * ramp_up_dispclk_with_dpp is called. + * there are two places for dppclk be put in use. One location + * is the same as the location as dispclk. Another is within + * update_dchubp_dpp which happens between pre_bandwidth and + * optimize_bandwidth. + * dppclk updated within update_dchubp_dpp will cause new + * clock values of dispclk and dppclk not be in use at the same + * time. when clocks are decreased, this may cause dppclk is + * lower than previous configuration and let pipe stuck. + * for example, eDP + external dp, change resolution of DP from + * 1920x1080x144hz to 1280x960x60hz. + * before change: dispclk = 337889 dppclk = 337889 + * change mode, dcn_validate_bandwidth calculate + * dispclk = 143122 dppclk = 143122 + * update_dchubp_dpp be executed before dispclk be updated, + * dispclk = 337889, but dppclk use new value dispclk /2 = + * 168944. this will cause pipe pstate warning issue. + * solution: between pre_bandwidth and optimize_bandwidth, while + * dispclk is going to be decreased, keep dppclk = dispclk + **/ + if (context->bw_ctx.bw.dcn.clk.dispclk_khz < + dc->clk_mgr->clks.dispclk_khz) + should_divided_by_2 = false; + else + should_divided_by_2 = + context->bw_ctx.bw.dcn.clk.dppclk_khz <= + dc->clk_mgr->clks.dispclk_khz / 2; dpp->funcs->dpp_dppclk_control( dpp, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 42b6e016d71e..6d891166da8a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -109,6 +109,7 @@ void dcn10_program_pipe( void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx); void dcn10_init_hw(struct dc *dc); void dcn10_init_pipes(struct dc *dc, struct dc_state *context); +void dcn10_power_down_on_boot(struct dc *dc); enum dc_status dce110_apply_ctx_to_hw( struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index f6a790c49321..5c98b71c1d47 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -30,6 +30,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .program_gamut_remap = dcn10_program_gamut_remap, .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 5621c95177d2..7725a406c16e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1482,22 +1482,23 @@ static void dcn20_update_dchubp_dpp( memset(&adjust, 0, sizeof(adjust)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - /* save the enablement of gamut remap for dpp*/ + + /* save the enablement of gamut remap for dpp */ enable_remap_dpp = pipe_ctx->stream->gamut_remap_matrix.enable_remap; - /*force bypass gamut remap for dpp/cm*/ + + /* force bypass gamut remap for dpp/cm */ pipe_ctx->stream->gamut_remap_matrix.enable_remap = false; dc->hwss.program_gamut_remap(pipe_ctx); - /*restore gamut remap flag for the top plane and use this remap into mpc*/ - if (pipe_ctx->top_pipe == NULL) - pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp; - else - pipe_ctx->stream->gamut_remap_matrix.enable_remap = false; - - if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - adjust.temperature_matrix[i] = - pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + + /* restore gamut remap flag and use this remap into mpc */ + pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp; + + /* build remap matrix for top plane if enabled */ + if (enable_remap_dpp && pipe_ctx->top_pipe == NULL) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; } mpc->funcs->set_gamut_remap(mpc, mpcc_id, &adjust); } else diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c index bb9e9bec2f28..2380392b916e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -30,6 +30,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = { .program_gamut_remap = dcn10_program_gamut_remap, .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = NULL, .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 0983bcc25117..e226647088b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -2102,11 +2102,20 @@ int dcn20_populate_dml_pipes_from_context( if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == res_ctx->pipe_ctx[i].plane_state) { struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].top_pipe; + int split_idx = 0; while (first_pipe->top_pipe && first_pipe->top_pipe->plane_state - == res_ctx->pipe_ctx[i].plane_state) + == res_ctx->pipe_ctx[i].plane_state) { first_pipe = first_pipe->top_pipe; - pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx; + split_idx++; + } + /* Treat 4to1 mpc combine as an mpo of 2 2-to-1 combines */ + if (split_idx == 0) + pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx; + else if (split_idx == 1) + pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx; + else if (split_idx == 2) + pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].top_pipe->pipe_idx; } else if (res_ctx->pipe_ctx[i].prev_odm_pipe) { struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].prev_odm_pipe; @@ -2258,7 +2267,7 @@ int dcn20_populate_dml_pipes_from_context( || (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln) || pipes[pipe_cnt].pipe.dest.odm_combine != dm_odm_combine_mode_disabled; - /* stereo is never split, nor odm combine */ + /* stereo is not split */ if (pln->stereo_format == PLANE_STEREO_FORMAT_SIDE_BY_SIDE || pln->stereo_format == PLANE_STEREO_FORMAT_TOP_AND_BOTTOM) { pipes[pipe_cnt].pipe.src.is_hsplit = false; @@ -2721,12 +2730,11 @@ int dcn20_validate_apply_pipe_split_flags( if (!context->res_ctx.pipe_ctx[i].stream) continue; - if (force_split || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] > 1) { - if (split4mpc) - split[i] = 4; - else + if (split4mpc || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] == 4) + split[i] = 4; + else if (force_split || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] == 2) split[i] = 2; - } + if ((pipe->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE || pipe->stream->view_format == diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c index 8575de1a8ad2..177d0dc8927a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -31,6 +31,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = { .program_gamut_remap = dcn10_program_gamut_remap, .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = NULL, .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h index 8db6d76a1131..0b1755f1dea8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h @@ -248,6 +248,7 @@ SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\ SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\ SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh),\ + SE_SF(DIG0_DIG_FE_CNTL, DOLBY_VISION_EN, mask_sh),\ SE_SF(DP0_DP_PIXEL_FORMAT, DP_PIXEL_COMBINE, mask_sh),\ SE_SF(DP0_DP_SEC_FRAMING4, DP_SST_SDP_SPLITTING, mask_sh),\ SE_SF(DIG0_DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, mask_sh) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h index d4106dd5a9b0..33f13c1e7520 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h @@ -98,6 +98,7 @@ SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ @@ -248,6 +249,10 @@ SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ @@ -280,6 +285,10 @@ SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index d7ba895de765..653a571e366d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -1870,12 +1870,14 @@ static bool dcn30_split_stream_for_mpc_or_odm( return true; } -static bool dcn30_fast_validate_bw( + +static bool dcn30_internal_validate_bw( struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, int *pipe_cnt_out, - int *vlevel_out) + int *vlevel_out, + bool fast_validate) { bool out = false; bool repopulate_pipes = false; @@ -1898,7 +1900,38 @@ static bool dcn30_fast_validate_bw( dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt); - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (!fast_validate) { + /* + * DML favors voltage over p-state, but we're more interested in + * supporting p-state over voltage. We can't support p-state in + * prefetch mode > 0 so try capping the prefetch mode to start. + */ + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh_and_mclk_switch; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + /* This may adjust vlevel and maxMpcComb */ + if (vlevel < context->bw_ctx.dml.soc.num_states) + vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); + } + if (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states || + vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) { + /* + * If mode is unsupported or there's still no p-state support then + * fall back to favoring voltage. + * + * We don't actually support prefetch mode 2, so require that we + * at least support prefetch mode 1. + */ + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh; + + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel < context->bw_ctx.dml.soc.num_states) { + memset(split, 0, sizeof(split)); + memset(merge, 0, sizeof(merge)); + vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); + } + } dml_log_mode_support_params(&context->bw_ctx.dml); @@ -1938,8 +1971,6 @@ static bool dcn30_fast_validate_bw( pipe_idx++; } - vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); - /* merge pipes if necessary */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; @@ -2187,7 +2218,8 @@ static void dcn30_calculate_wm( } } -bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context, +bool dcn30_validate_bandwidth(struct dc *dc, + struct dc_state *context, bool fast_validate) { bool out = false; @@ -2201,7 +2233,7 @@ bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context, BW_VAL_TRACE_COUNT(); - out = dcn30_fast_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel); + out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate); if (pipe_cnt == 0) goto validate_out; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 75dc4fe41731..b54814f11b74 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -2567,7 +2567,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman &v->VRatioPrefetchC[k], &v->RequiredPrefetchPixDataBWLuma[k], &v->RequiredPrefetchPixDataBWChroma[k], - &v->NotEnoughTimeForDynamicMetadata, + &v->NotEnoughTimeForDynamicMetadata[k], &v->Tno_bw[k], &v->prefetch_vmrow_bw[k], &v->Tdmdl_vm[k], @@ -2686,7 +2686,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->FractionOfUrgentBandwidth = MaxTotalRDBandwidthNoUrgentBurst / v->ReturnBW; - if (MaxTotalRDBandwidth <= v->ReturnBW && v->NotEnoughUrgentLatencyHiding == 0 && v->NotEnoughUrgentLatencyHidingPre == 0 && v->NotEnoughTimeForDynamicMetadata == 0 && !VRatioPrefetchMoreThan4 + if (MaxTotalRDBandwidth <= v->ReturnBW && v->NotEnoughUrgentLatencyHiding == 0 && v->NotEnoughUrgentLatencyHidingPre == 0 && !VRatioPrefetchMoreThan4 && !DestinationLineTimesForPrefetchLessThan2) v->PrefetchModeSupported = true; else { @@ -2695,8 +2695,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman dml_print("DML: MaxTotalRDBandwidth:%f AvailReturnBandwidth:%f\n", MaxTotalRDBandwidth, v->ReturnBW); dml_print("DML: VRatioPrefetch %s more than 4\n", (VRatioPrefetchMoreThan4) ? "is" : "is not"); dml_print("DML: DestinationLines for Prefetch %s less than 2\n", (DestinationLineTimesForPrefetchLessThan2) ? "is" : "is not"); - dml_print("DML: Not enough lines for dynamic meta is %s\n", (v->NotEnoughTimeForDynamicMetadata) ? "true" : "false"); - } if (v->PrefetchModeSupported == true && v->ImmediateFlipSupport == true) { @@ -2786,7 +2784,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman } for (k = 0; k < v->NumberOfActivePlanes; ++k) { - if (v->ErrorResult[k]) { + if (v->ErrorResult[k] || v->NotEnoughTimeForDynamicMetadata[k]) { v->PrefetchModeSupported = false; dml_print("DML: CalculatePrefetchSchedule ***failed***. Prefetch schedule violation. Results are NOT valid\n"); } diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 0fac7f754604..6ab74640c0da 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -24,6 +24,7 @@ */ #include "dc_features.h" +#include "display_mode_enums.h" #ifndef __DISPLAY_MODE_STRUCTS_H__ #define __DISPLAY_MODE_STRUCTS_H__ @@ -120,6 +121,7 @@ struct _vcs_dpi_soc_bounding_box_st { double urgent_latency_adjustment_fabric_clock_reference_mhz; bool disable_dram_clock_change_vactive_support; bool allow_dram_clock_one_display_vactive; + enum self_refresh_affinity allow_dram_self_refresh_or_dram_clock_change_in_vblank; }; struct _vcs_dpi_ip_params_st { diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h index f615815c73bd..756d8eb1221c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -802,7 +802,7 @@ struct vba_vars_st { unsigned int DCCCMaxCompressedBlock[DC__NUM_DPP__MAX]; unsigned int DCCCIndependent64ByteBlock[DC__NUM_DPP__MAX]; double VStartupMargin; - bool NotEnoughTimeForDynamicMetadata; + bool NotEnoughTimeForDynamicMetadata[DC__NUM_DPP__MAX]; /* Missing from VBA */ unsigned int MaximumMaxVStartupLines; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index 505357597603..5994d2a33c40 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -241,6 +241,9 @@ struct clk_mgr_funcs { bool (*are_clock_states_equal) (struct dc_clocks *a, struct dc_clocks *b); void (*notify_wm_ranges)(struct clk_mgr *clk_mgr); + + /* Notify clk_mgr of a change in link rate, update phyclk frequency if necessary */ + void (*notify_link_rate_change)(struct clk_mgr *clk_mgr, struct dc_link *link); #ifdef CONFIG_DRM_AMD_DC_DCN3_0 /* * Send message to PMFW to set hard min memclk frequency diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h index c3c151be7d03..4e6e18bbef5d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h @@ -270,9 +270,14 @@ struct clk_mgr_internal { enum dm_pp_clocks_state max_clks_state; enum dm_pp_clocks_state cur_min_clks_state; + bool periodic_retraining_disabled; + + unsigned int cur_phyclk_req_table[MAX_PIPES * 2]; #ifdef CONFIG_DRM_AMD_DC_DCN3_0 bool smu_present; + void *wm_range_table; + long long wm_range_table_addr; #endif }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 066a2a723c12..720ce5e458d8 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -56,6 +56,7 @@ struct hw_sequencer_funcs { /* Pipe Programming Related */ void (*init_hw)(struct dc *dc); + void (*power_down_on_boot)(struct dc *dc); void (*enable_accelerated_mode)(struct dc *dc, struct dc_state *context); enum dc_status (*apply_ctx_to_hw)(struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c index dd4d7a1dc3b6..49689f71f4f1 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c @@ -169,6 +169,11 @@ static const struct irq_source_info_funcs pflip_irq_info_funcs = { .ack = NULL }; +static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + static const struct irq_source_info_funcs vblank_irq_info_funcs = { .set = NULL, .ack = NULL @@ -228,12 +233,15 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { .funcs = &pflip_irq_info_funcs\ } -#define vupdate_int_entry(reg_num)\ +/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic + * of DCE's DC_IRQ_SOURCE_VUPDATEx. + */ +#define vupdate_no_lock_int_entry(reg_num)\ [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ IRQ_REG_ENTRY(OTG, reg_num,\ - OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\ - OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\ - .funcs = &vblank_irq_info_funcs\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\ + .funcs = &vupdate_no_lock_irq_info_funcs\ } #define vblank_int_entry(reg_num)\ @@ -340,12 +348,12 @@ irq_source_info_dcn30[DAL_IRQ_SOURCES_NUMBER] = { dc_underflow_int_entry(6), [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), - vupdate_int_entry(0), - vupdate_int_entry(1), - vupdate_int_entry(2), - vupdate_int_entry(3), - vupdate_int_entry(4), - vupdate_int_entry(5), + vupdate_no_lock_int_entry(0), + vupdate_no_lock_int_entry(1), + vupdate_no_lock_int_entry(2), + vupdate_no_lock_int_entry(3), + vupdate_no_lock_int_entry(4), + vupdate_no_lock_int_entry(5), vblank_int_entry(0), vblank_int_entry(1), vblank_int_entry(2), diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 3cac170312fc..c6a8d6c54621 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -264,10 +264,9 @@ struct dmub_srv_hw_funcs { bool (*is_hw_init)(struct dmub_srv *dmub); - void (*enable_dmub_boot_options)(struct dmub_srv *dmub); - - union dmub_fw_boot_status (*get_fw_status)(struct dmub_srv *dmub); + bool (*is_phy_init)(struct dmub_srv *dmub); + bool (*is_auto_load_done)(struct dmub_srv *dmub); void (*set_gpint)(struct dmub_srv *dmub, union dmub_gpint_data_register reg); diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 68b5fd811d26..513a5f8f817e 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -36,10 +36,10 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0xf87bb940b -#define DMUB_FW_VERSION_MAJOR 1 +#define DMUB_FW_VERSION_GIT_HASH 0xf675c6448 +#define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 19 +#define DMUB_FW_VERSION_REVISION 24 #define DMUB_FW_VERSION_UCODE ((DMUB_FW_VERSION_MAJOR << 24) | (DMUB_FW_VERSION_MINOR << 16) | DMUB_FW_VERSION_REVISION) #endif @@ -123,12 +123,15 @@ union dmub_psr_debug_flags { * @fw_region_size: size of the firmware state region * @trace_buffer_size: size of the tracebuffer region * @fw_version: the firmware version information + * @dal_fw: 1 if the firmware is DAL */ struct dmub_fw_meta_info { uint32_t magic_value; uint32_t fw_region_size; uint32_t trace_buffer_size; uint32_t fw_version; + uint8_t dal_fw; + uint8_t reserved[3]; }; /* Ensure that the structure remains 64 bytes. */ @@ -151,15 +154,6 @@ union dmub_fw_meta { * SCRATCH15: FW Boot Options register */ -/** - * DMCUB firmware status bits for SCRATCH2. - */ -enum dmub_fw_status_bit { - DMUB_FW_STATUS_BIT_DAL_FIRMWARE = (1 << 0), - DMUB_FW_STATUS_BIT_COMMAND_TABLE_READY = (1 << 1), -}; - - /* Register bit definition for SCRATCH0 */ union dmub_fw_boot_status { struct { @@ -260,6 +254,11 @@ enum dmub_gpint_command { DMUB_GPINT__GET_FW_VERSION = 1, DMUB_GPINT__STOP_FW = 2, DMUB_GPINT__GET_PSR_STATE = 7, + /** + * DESC: Notifies DMCUB of the currently active streams. + * ARGS: Stream mask, 1 bit per active stream index. + */ + DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK = 8, }; //============================================================================== diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c index 0cd78e745e7e..2c4a2fe9311d 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -312,18 +312,3 @@ uint32_t dmub_dcn20_get_gpint_response(struct dmub_srv *dmub) { return REG_READ(DMCUB_SCRATCH7); } - -union dmub_fw_boot_status dmub_dcn20_get_fw_boot_status(struct dmub_srv *dmub) -{ - union dmub_fw_boot_status status; - - status.all = REG_READ(DMCUB_SCRATCH0); - return status; -} - -void dmub_dcn20_enable_dmub_boot_options(struct dmub_srv *dmub) -{ - union dmub_fw_boot_options boot_options = {0}; - - REG_WRITE(DMCUB_SCRATCH14, boot_options.all); -} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h index a27b509cd6fd..a316f260f6ac 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h @@ -192,8 +192,4 @@ bool dmub_dcn20_is_gpint_acked(struct dmub_srv *dmub, uint32_t dmub_dcn20_get_gpint_response(struct dmub_srv *dmub); -void dmub_dcn20_enable_dmub_boot_options(struct dmub_srv *dmub); - -union dmub_fw_boot_status dmub_dcn20_get_fw_boot_status(struct dmub_srv *dmub); - #endif /* _DMUB_DCN20_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c index a6047673c3f5..e8f488232e34 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c @@ -51,4 +51,14 @@ const struct dmub_srv_common_regs dmub_srv_dcn21_regs = { #undef DMUB_SF }; +/* Shared functions. */ +bool dmub_dcn21_is_auto_load_done(struct dmub_srv *dmub) +{ + return (REG_READ(DMCUB_SCRATCH0) == 3); +} + +bool dmub_dcn21_is_phy_init(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_SCRATCH10) == 0; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h index 8c4033ae4007..2bbea237137b 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h @@ -32,4 +32,10 @@ extern const struct dmub_srv_common_regs dmub_srv_dcn21_regs; +/* Hardware functions. */ + +bool dmub_dcn21_is_auto_load_done(struct dmub_srv *dmub); + +bool dmub_dcn21_is_phy_init(struct dmub_srv *dmub); + #endif /* _DMUB_DCN21_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c index ba8d0bfb5522..215178b8d415 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c @@ -153,11 +153,22 @@ void dmub_dcn30_setup_windows(struct dmub_srv *dmub, offset = cw4->offset; - REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part); - REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part); - REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, DMCUB_REGION4_TOP_ADDRESS, - cw4->region.top - cw4->region.base - 1, DMCUB_REGION4_ENABLE, - 1); + /* New firmware can support CW4. */ + if (dmub->fw_version > DMUB_FW_VERSION(1, 0, 10)) { + REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base); + REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0, + DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top, + DMCUB_REGION3_CW4_ENABLE, 1); + } else { + REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, + DMCUB_REGION4_TOP_ADDRESS, + cw4->region.top - cw4->region.base - 1, + DMCUB_REGION4_ENABLE, 1); + } offset = cw5->offset; diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index aa41dfa23020..08da423b24a1 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -153,16 +153,18 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) funcs->set_gpint = dmub_dcn20_set_gpint; funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked; funcs->get_gpint_response = dmub_dcn20_get_gpint_response; - funcs->get_fw_status = dmub_dcn20_get_fw_boot_status; - funcs->enable_dmub_boot_options = dmub_dcn20_enable_dmub_boot_options; - if (asic == DMUB_ASIC_DCN21) + if (asic == DMUB_ASIC_DCN21) { dmub->regs = &dmub_srv_dcn21_regs; + funcs->is_auto_load_done = dmub_dcn21_is_auto_load_done; + funcs->is_phy_init = dmub_dcn21_is_phy_init; + } #ifdef CONFIG_DRM_AMD_DC_DCN3_0 if (asic == DMUB_ASIC_DCN30) { dmub->regs = &dmub_srv_dcn30_regs; + funcs->is_auto_load_done = dmub_dcn30_is_auto_load_done; funcs->backdoor_load = dmub_dcn30_backdoor_load; funcs->setup_windows = dmub_dcn30_setup_windows; } @@ -462,10 +464,6 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, dmub_rb_init(&dmub->inbox1_rb, &rb_params); } - /* Report to DMUB what features are supported by current driver */ - if (dmub->hw_funcs.enable_dmub_boot_options) - dmub->hw_funcs.enable_dmub_boot_options(dmub); - if (dmub->hw_funcs.reset_release) dmub->hw_funcs.reset_release(dmub); @@ -526,10 +524,11 @@ enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, if (!dmub->hw_init) return DMUB_STATUS_INVALID; - for (i = 0; i <= timeout_us; i += 100) { - union dmub_fw_boot_status status = dmub->hw_funcs.get_fw_status(dmub); + if (!dmub->hw_funcs.is_auto_load_done) + return DMUB_STATUS_OK; - if (status.bits.dal_fw && status.bits.mailbox_rdy) + for (i = 0; i <= timeout_us; i += 100) { + if (dmub->hw_funcs.is_auto_load_done(dmub)) return DMUB_STATUS_OK; udelay(100); @@ -538,6 +537,27 @@ enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, return DMUB_STATUS_TIMEOUT; } +enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i = 0; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (!dmub->hw_funcs.is_phy_init) + return DMUB_STATUS_OK; + + for (i = 0; i <= timeout_us; i += 10) { + if (dmub->hw_funcs.is_phy_init(dmub)) + return DMUB_STATUS_OK; + + udelay(10); + } + + return DMUB_STATUS_TIMEOUT; +} + enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, uint32_t timeout_us) { diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index d66f9d8eefb4..21bbee17c527 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -67,6 +67,7 @@ #define DC_LOG_ALL_GAMMA(...) pr_debug("[GAMMA]:"__VA_ARGS__) #define DC_LOG_ALL_TF_CHANNELS(...) pr_debug("[GAMMA]:"__VA_ARGS__) #define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__) +#define DC_LOG_SMU(...) pr_debug("[SMU_MSG]:"__VA_ARGS__) #define DC_LOG_DWB(...) DRM_DEBUG_KMS(__VA_ARGS__) struct dal_logger; @@ -113,6 +114,7 @@ enum dc_log_type { LOG_DISPLAYSTATS, LOG_HDMI_RETIMER_REDRIVER, LOG_DSC, + LOG_SMU_MSG, LOG_DWB, LOG_GAMMA_DEBUG, LOG_MAX_HW_POINTS, @@ -147,11 +149,11 @@ enum dc_log_type { (1ULL << LOG_I2C_AUX) | \ (1ULL << LOG_IF_TRACE) | \ (1ULL << LOG_HDMI_FRL) | \ + (1ULL << LOG_SCALER) | \ (1ULL << LOG_DTN) /* | \ (1ULL << LOG_DEBUG) | \ (1ULL << LOG_BIOS) | \ (1ULL << LOG_SURFACE) | \ - (1ULL << LOG_SCALER) | \ (1ULL << LOG_DML) | \ (1ULL << LOG_HW_LINK_TRAINING) | \ (1ULL << LOG_HW_AUDIO)| \ diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index eb7421e83b86..d3a5ba9ee782 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -32,7 +32,7 @@ #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32 -#define MIN_REFRESH_RANGE_IN_US 10000000 +#define MIN_REFRESH_RANGE 10 /* Refresh rate ramp at a fixed rate of 65 Hz/second */ #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) /* Number of elements in the render times cache array */ @@ -790,7 +790,7 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, * Check if Freesync is supported. Return if false. If true, * set the corresponding bit in the info packet */ - if (!vrr->supported || (!vrr->send_info_frame)) + if (!vrr->send_info_frame) return; switch (packet_type) { @@ -878,8 +878,8 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, else in_out_vrr->fixed_refresh_in_uhz = 0; - refresh_range = in_out_vrr->max_refresh_in_uhz - - in_out_vrr->min_refresh_in_uhz; + refresh_range = div_u64(in_out_vrr->max_refresh_in_uhz + 500000, 1000000) - ++ div_u64(in_out_vrr->min_refresh_in_uhz + 500000, 1000000); in_out_vrr->supported = true; } @@ -918,7 +918,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, in_out_vrr->adjust.v_total_min = stream->timing.v_total; in_out_vrr->adjust.v_total_max = stream->timing.v_total; } else if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE && - refresh_range >= MIN_REFRESH_RANGE_IN_US) { + refresh_range >= MIN_REFRESH_RANGE) { in_out_vrr->adjust.v_total_min = calc_v_total_from_refresh(stream, @@ -1105,16 +1105,10 @@ unsigned long long mod_freesync_calc_nominal_field_rate( return nominal_field_rate_in_uhz; } -bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, - const struct dc_stream_state *stream, - uint32_t min_refresh_cap_in_uhz, +bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz, uint32_t max_refresh_cap_in_uhz, - uint32_t min_refresh_request_in_uhz, - uint32_t max_refresh_request_in_uhz) + uint32_t nominal_field_rate_in_uhz) { - /* Calculate nominal field rate for stream */ - unsigned long long nominal_field_rate_in_uhz = - mod_freesync_calc_nominal_field_rate(stream); /* Typically nominal refresh calculated can have some fractional part. * Allow for some rounding error of actual video timing by taking floor @@ -1153,8 +1147,6 @@ bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, div_u64(nominal_field_rate_in_uhz + 500000, 1000000); min_refresh_cap_in_uhz /= 1000000; max_refresh_cap_in_uhz /= 1000000; - min_refresh_request_in_uhz /= 1000000; - max_refresh_request_in_uhz /= 1000000; // Check nominal is within range if (nominal_field_rate_in_uhz > max_refresh_cap_in_uhz || @@ -1165,23 +1157,12 @@ bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, if (nominal_field_rate_in_uhz < max_refresh_cap_in_uhz) max_refresh_cap_in_uhz = nominal_field_rate_in_uhz; - // Don't allow min > max - if (min_refresh_request_in_uhz > max_refresh_request_in_uhz) - return false; - // Check min is within range - if (min_refresh_request_in_uhz > max_refresh_cap_in_uhz || - min_refresh_request_in_uhz < min_refresh_cap_in_uhz) - return false; - - // Check max is within range - if (max_refresh_request_in_uhz > max_refresh_cap_in_uhz || - max_refresh_request_in_uhz < min_refresh_cap_in_uhz) + if (min_refresh_cap_in_uhz > max_refresh_cap_in_uhz) return false; // For variable range, check for at least 10 Hz range - if ((max_refresh_request_in_uhz != min_refresh_request_in_uhz) && - (max_refresh_request_in_uhz - min_refresh_request_in_uhz < 10)) + if (nominal_field_rate_in_uhz - min_refresh_cap_in_uhz < 10) return false; return true; diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index 0ba3cf7f336a..c80fc10d732c 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -170,12 +170,9 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, unsigned long long mod_freesync_calc_nominal_field_rate( const struct dc_stream_state *stream); -bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, - const struct dc_stream_state *stream, - uint32_t min_refresh_cap_in_uhz, +bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz, uint32_t max_refresh_cap_in_uhz, - uint32_t min_refresh_request_in_uhz, - uint32_t max_refresh_request_in_uhz); + uint32_t nominal_field_rate_in_uhz); |