diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
53 files changed, 2326 insertions, 1747 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index af16973f2c412..94911871eb9b5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -28,11 +28,11 @@ AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o ifneq ($(CONFIG_DRM_AMD_DC),) -AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o +AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o endif ifneq ($(CONFIG_DEBUG_FS),) -AMDGPUDM += amdgpu_dm_crc.o +AMDGPUDM += amdgpu_dm_crc.o amdgpu_dm_debugfs.o endif subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc 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 66bd3cc3e3875..ca017c1dd4dab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -39,6 +39,9 @@ #include "dm_helpers.h" #include "dm_services_types.h" #include "amdgpu_dm_mst_types.h" +#if defined(CONFIG_DEBUG_FS) +#include "amdgpu_dm_debugfs.h" +#endif #include "ivsrcid/ivsrcid_vislands30.h" @@ -1532,7 +1535,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* * Temporary disable until pplib/smu interaction is implemented */ - dm->dc->debug.disable_stutter = true; + dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; break; #endif default: @@ -2173,6 +2176,46 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing) return color_space; } +static void reduce_mode_colour_depth(struct dc_crtc_timing *timing_out) +{ + if (timing_out->display_color_depth <= COLOR_DEPTH_888) + return; + + timing_out->display_color_depth--; +} + +static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out, + const struct drm_display_info *info) +{ + int normalized_clk; + if (timing_out->display_color_depth <= COLOR_DEPTH_888) + return; + do { + normalized_clk = timing_out->pix_clk_khz; + /* YCbCr 4:2:0 requires additional adjustment of 1/2 */ + if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420) + normalized_clk /= 2; + /* Adjusting pix clock following on HDMI spec based on colour depth */ + switch (timing_out->display_color_depth) { + case COLOR_DEPTH_101010: + normalized_clk = (normalized_clk * 30) / 24; + break; + case COLOR_DEPTH_121212: + normalized_clk = (normalized_clk * 36) / 24; + break; + case COLOR_DEPTH_161616: + normalized_clk = (normalized_clk * 48) / 24; + break; + default: + return; + } + if (normalized_clk <= info->max_tmds_clock) + return; + reduce_mode_colour_depth(timing_out); + + } while (timing_out->display_color_depth > COLOR_DEPTH_888); + +} /*****************************************************************************/ static void @@ -2181,6 +2224,7 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, const struct drm_connector *connector) { struct dc_crtc_timing *timing_out = &stream->timing; + const struct drm_display_info *info = &connector->display_info; memset(timing_out, 0, sizeof(struct dc_crtc_timing)); @@ -2189,8 +2233,10 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, timing_out->v_border_top = 0; timing_out->v_border_bottom = 0; /* TODO: un-hardcode */ - - if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) + if (drm_mode_is_420_only(info, mode_in) + && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; else @@ -2226,6 +2272,8 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, stream->out_transfer_func->type = TF_TYPE_PREDEFINED; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + if (stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + adjust_colour_depth_from_display_info(timing_out, info); } static void fill_audio_info(struct audio_info *audio_info, @@ -3619,6 +3667,13 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, &aconnector->base, &aencoder->base); drm_connector_register(&aconnector->base); +#if defined(CONFIG_DEBUG_FS) + res = connector_debugfs_init(aconnector); + if (res) { + DRM_ERROR("Failed to create debugfs for connector"); + goto out_free; + } +#endif if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector_type == DRM_MODE_CONNECTOR_eDP) 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 new file mode 100644 index 0000000000000..cf5ea69e46ad3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include <linux/debugfs.h> + +#include "dc.h" +#include "dc_link.h" + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_debugfs.h" + +static ssize_t dp_link_rate_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read link rate */ + return 1; +} + +static ssize_t dp_link_rate_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write link rate */ + return 1; +} + +static ssize_t dp_lane_count_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read lane count */ + return 1; +} + +static ssize_t dp_lane_count_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write lane count */ + return 1; +} + +static ssize_t dp_voltage_swing_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read voltage swing */ + return 1; +} + +static ssize_t dp_voltage_swing_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write voltage swing */ + return 1; +} + +static ssize_t dp_pre_emphasis_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read pre-emphasis */ + return 1; +} + +static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write pre-emphasis */ + return 1; +} + +static ssize_t dp_phy_test_pattern_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read PHY test pattern */ + return 1; +} + +static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write PHY test pattern */ + return 1; +} + +static const struct file_operations dp_link_rate_fops = { + .owner = THIS_MODULE, + .read = dp_link_rate_debugfs_read, + .write = dp_link_rate_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_lane_count_fops = { + .owner = THIS_MODULE, + .read = dp_lane_count_debugfs_read, + .write = dp_lane_count_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_voltage_swing_fops = { + .owner = THIS_MODULE, + .read = dp_voltage_swing_debugfs_read, + .write = dp_voltage_swing_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_pre_emphasis_fops = { + .owner = THIS_MODULE, + .read = dp_pre_emphasis_debugfs_read, + .write = dp_pre_emphasis_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_phy_test_pattern_fops = { + .owner = THIS_MODULE, + .read = dp_phy_test_pattern_debugfs_read, + .write = dp_phy_test_pattern_debugfs_write, + .llseek = default_llseek +}; + +static const struct { + char *name; + const struct file_operations *fops; +} dp_debugfs_entries[] = { + {"link_rate", &dp_link_rate_fops}, + {"lane_count", &dp_lane_count_fops}, + {"voltage_swing", &dp_voltage_swing_fops}, + {"pre_emphasis", &dp_pre_emphasis_fops}, + {"phy_test_pattern", &dp_phy_test_pattern_fops} +}; + +int connector_debugfs_init(struct amdgpu_dm_connector *connector) +{ + int i; + struct dentry *ent, *dir = connector->base.debugfs_entry; + + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + for (i = 0; i < ARRAY_SIZE(dp_debugfs_entries); i++) { + ent = debugfs_create_file(dp_debugfs_entries[i].name, + 0644, + dir, + connector, + dp_debugfs_entries[i].fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + } + } + + return 0; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h index 7a65206a6d21a..d9ed1b2aa8115 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Advanced Micro Devices, Inc. + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,13 +23,12 @@ * */ -#ifndef __SOC_BOUNDING_BOX_H__ -#define __SOC_BOUNDING_BOX_H__ +#ifndef __AMDGPU_DM_DEBUGFS_H__ +#define __AMDGPU_DM_DEBUGFS_H__ -#include "dml_common_defs.h" +#include "amdgpu.h" +#include "amdgpu_dm.h" -void dml_socbb_set_latencies(soc_bounding_box_st *to_box, soc_bounding_box_st *from_box); -voltage_scaling_st dml_socbb_voltage_scaling(const soc_bounding_box_st *box, enum voltage_state voltage); -double dml_socbb_return_bw_mhz(soc_bounding_box_st *box, enum voltage_state voltage); +int connector_debugfs_init(struct amdgpu_dm_connector *connector); #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c new file mode 100644 index 0000000000000..50e863024f585 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -0,0 +1,535 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + */ +#include <linux/string.h> +#include <linux/acpi.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/amdgpu_drm.h> +#include "dm_services.h" +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_irq.h" +#include "amdgpu_pm.h" +#include "dm_pp_smu.h" + + +bool dm_pp_apply_display_requirements( + const struct dc_context *ctx, + const struct dm_pp_display_configuration *pp_display_cfg) +{ + struct amdgpu_device *adev = ctx->driver_context; + int i; + + if (adev->pm.dpm_enabled) { + + memset(&adev->pm.pm_display_cfg, 0, + sizeof(adev->pm.pm_display_cfg)); + + adev->pm.pm_display_cfg.cpu_cc6_disable = + pp_display_cfg->cpu_cc6_disable; + + adev->pm.pm_display_cfg.cpu_pstate_disable = + pp_display_cfg->cpu_pstate_disable; + + adev->pm.pm_display_cfg.cpu_pstate_separation_time = + pp_display_cfg->cpu_pstate_separation_time; + + adev->pm.pm_display_cfg.nb_pstate_switch_disable = + pp_display_cfg->nb_pstate_switch_disable; + + adev->pm.pm_display_cfg.num_display = + pp_display_cfg->display_count; + adev->pm.pm_display_cfg.num_path_including_non_display = + pp_display_cfg->display_count; + + adev->pm.pm_display_cfg.min_core_set_clock = + pp_display_cfg->min_engine_clock_khz/10; + adev->pm.pm_display_cfg.min_core_set_clock_in_sr = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + adev->pm.pm_display_cfg.min_mem_set_clock = + pp_display_cfg->min_memory_clock_khz/10; + + adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + adev->pm.pm_display_cfg.min_dcef_set_clk = + pp_display_cfg->min_dcfclock_khz/10; + + adev->pm.pm_display_cfg.multi_monitor_in_sync = + pp_display_cfg->all_displays_in_sync; + adev->pm.pm_display_cfg.min_vblank_time = + pp_display_cfg->avail_mclk_switch_time_us; + + adev->pm.pm_display_cfg.display_clk = + pp_display_cfg->disp_clk_khz/10; + + adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = + pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; + + adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; + adev->pm.pm_display_cfg.line_time_in_us = + pp_display_cfg->line_time_in_us; + + adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; + adev->pm.pm_display_cfg.crossfire_display_index = -1; + adev->pm.pm_display_cfg.min_bus_bandwidth = 0; + + for (i = 0; i < pp_display_cfg->display_count; i++) { + const struct dm_pp_single_disp_config *dc_cfg = + &pp_display_cfg->disp_configs[i]; + adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; + } + + /* TODO: complete implementation of + * pp_display_configuration_change(). + * Follow example of: + * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c + * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ + if (adev->powerplay.pp_funcs->display_configuration_change) + adev->powerplay.pp_funcs->display_configuration_change( + adev->powerplay.pp_handle, + &adev->pm.pm_display_cfg); + + /* TODO: replace by a separate call to 'apply display cfg'? */ + amdgpu_pm_compute_clocks(adev); + } + + return true; +} + +static void get_default_clock_levels( + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels *clks) +{ + uint32_t disp_clks_in_khz[6] = { + 300000, 400000, 496560, 626090, 685720, 757900 }; + uint32_t sclks_in_khz[6] = { + 300000, 360000, 423530, 514290, 626090, 720000 }; + uint32_t mclks_in_khz[2] = { 333000, 800000 }; + + switch (clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + clks->num_levels = 6; + memmove(clks->clocks_in_khz, disp_clks_in_khz, + sizeof(disp_clks_in_khz)); + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + clks->num_levels = 6; + memmove(clks->clocks_in_khz, sclks_in_khz, + sizeof(sclks_in_khz)); + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + clks->num_levels = 2; + memmove(clks->clocks_in_khz, mclks_in_khz, + sizeof(mclks_in_khz)); + break; + default: + clks->num_levels = 0; + break; + } +} + +static enum amd_pp_clock_type dc_to_pp_clock_type( + enum dm_pp_clock_type dm_pp_clk_type) +{ + enum amd_pp_clock_type amd_pp_clk_type = 0; + + switch (dm_pp_clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + amd_pp_clk_type = amd_pp_disp_clock; + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + amd_pp_clk_type = amd_pp_sys_clock; + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + amd_pp_clk_type = amd_pp_mem_clock; + break; + case DM_PP_CLOCK_TYPE_DCEFCLK: + amd_pp_clk_type = amd_pp_dcef_clock; + break; + case DM_PP_CLOCK_TYPE_DCFCLK: + amd_pp_clk_type = amd_pp_dcf_clock; + break; + case DM_PP_CLOCK_TYPE_PIXELCLK: + amd_pp_clk_type = amd_pp_pixel_clock; + break; + case DM_PP_CLOCK_TYPE_FCLK: + amd_pp_clk_type = amd_pp_f_clock; + break; + case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: + amd_pp_clk_type = amd_pp_phy_clock; + break; + case DM_PP_CLOCK_TYPE_DPPCLK: + amd_pp_clk_type = amd_pp_dpp_clock; + break; + default: + DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", + dm_pp_clk_type); + break; + } + + return amd_pp_clk_type; +} + +static void pp_to_dc_clock_levels( + const struct amd_pp_clocks *pp_clks, + struct dm_pp_clock_levels *dc_clks, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->count, + DM_PP_MAX_CLOCK_LEVELS); + + dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + dc_clks->num_levels = pp_clks->count; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < dc_clks->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); + dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; + } +} + +static void pp_to_dc_clock_levels_with_latency( + const struct pp_clock_levels_with_latency *pp_clks, + struct dm_pp_clock_levels_with_latency *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_DEBUG("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; + } +} + +static void pp_to_dc_clock_levels_with_voltage( + const struct pp_clock_levels_with_voltage *pp_clks, + struct dm_pp_clock_levels_with_voltage *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; + } +} + +bool dm_pp_get_clock_levels_by_type( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels *dc_clks) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct amd_pp_clocks pp_clks = { 0 }; + struct amd_pp_simple_clock_info validation_clks = { 0 }; + uint32_t i; + + if (adev->powerplay.pp_funcs->get_clock_by_type) { + if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, + dc_to_pp_clock_type(clk_type), &pp_clks)) { + /* Error in pplib. Provide default values. */ + get_default_clock_levels(clk_type, dc_clks); + return true; + } + } + + pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); + + if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { + if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( + pp_handle, &validation_clks)) { + /* Error in pplib. Provide default values. */ + DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); + validation_clks.engine_max_clock = 72000; + validation_clks.memory_max_clock = 80000; + validation_clks.level = 0; + } + } + + DRM_INFO("DM_PPLIB: Validation clocks:\n"); + DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", + validation_clks.engine_max_clock); + DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", + validation_clks.memory_max_clock); + DRM_INFO("DM_PPLIB: level : %d\n", + validation_clks.level); + + /* Translate 10 kHz to kHz. */ + validation_clks.engine_max_clock *= 10; + validation_clks.memory_max_clock *= 10; + + /* Determine the highest non-boosted level from the Validation Clocks */ + if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { + /* This clock is higher the validation clock. + * Than means the previous one is the highest + * non-boosted one. */ + DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { + DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } + + return true; +} + +bool dm_pp_get_clock_levels_by_type_with_latency( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels_with_latency *clk_level_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_latency pp_clks = { 0 }; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) + return false; + + if (pp_funcs->get_clock_by_type_with_latency(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clks)) + return false; + + pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); + + return true; +} + +bool dm_pp_get_clock_levels_by_type_with_voltage( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels_with_voltage *clk_level_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_voltage pp_clk_info = {0}; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clk_info)) + return false; + + pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); + + return true; +} + +bool dm_pp_notify_wm_clock_changes( + const struct dc_context *ctx, + struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) +{ + /* TODO: to be implemented */ + return false; +} + +bool dm_pp_apply_power_level_change_request( + const struct dc_context *ctx, + struct dm_pp_power_level_change_request *level_change_req) +{ + /* TODO: to be implemented */ + return false; +} + +bool dm_pp_apply_clock_for_voltage_request( + const struct dc_context *ctx, + struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct pp_display_clock_request pp_clock_request = {0}; + int ret = 0; + + pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); + pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; + + if (!pp_clock_request.clock_type) + return false; + + if (adev->powerplay.pp_funcs->display_clock_voltage_request) + ret = adev->powerplay.pp_funcs->display_clock_voltage_request( + adev->powerplay.pp_handle, + &pp_clock_request); + if (ret) + return false; + return true; +} + +bool dm_pp_get_static_clocks( + const struct dc_context *ctx, + struct dm_pp_static_clock_info *static_clk_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct amd_pp_clock_info pp_clk_info = {0}; + int ret = 0; + + if (adev->powerplay.pp_funcs->get_current_clocks) + ret = adev->powerplay.pp_funcs->get_current_clocks( + adev->powerplay.pp_handle, + &pp_clk_info); + if (ret) + return false; + + static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; + + return true; +} + +void pp_rv_set_display_requirement(struct pp_smu *pp, + struct pp_smu_display_requirement_rv *req) +{ + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->display_configuration_changed) + return; + + amdgpu_dpm_display_configuration_changed(adev); +} + +void pp_rv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; + struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; + struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; + int32_t i; + + wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; + wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; + + for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { + if (ranges->reader_wm_sets[i].wm_inst > 3) + wm_dce_clocks[i].wm_set_id = WM_SET_A; + else + wm_dce_clocks[i].wm_set_id = + ranges->reader_wm_sets[i].wm_inst; + wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = + ranges->reader_wm_sets[i].max_drain_clk_khz; + wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = + ranges->reader_wm_sets[i].min_drain_clk_khz; + wm_dce_clocks[i].wm_max_mem_clk_in_khz = + ranges->reader_wm_sets[i].max_fill_clk_khz; + wm_dce_clocks[i].wm_min_mem_clk_in_khz = + ranges->reader_wm_sets[i].min_fill_clk_khz; + } + + for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { + if (ranges->writer_wm_sets[i].wm_inst > 3) + wm_soc_clocks[i].wm_set_id = WM_SET_A; + else + wm_soc_clocks[i].wm_set_id = + ranges->writer_wm_sets[i].wm_inst; + wm_soc_clocks[i].wm_max_socclk_clk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_khz; + wm_soc_clocks[i].wm_min_socclk_clk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_khz; + wm_soc_clocks[i].wm_max_mem_clk_in_khz = + ranges->writer_wm_sets[i].max_drain_clk_khz; + wm_soc_clocks[i].wm_min_mem_clk_in_khz = + ranges->writer_wm_sets[i].min_drain_clk_khz; + } + + pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges); +} + +void pp_rv_set_pme_wa_enable(struct pp_smu *pp) +{ + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->notify_smu_enable_pwe) + return; + + pp_funcs->notify_smu_enable_pwe(pp_handle); +} + +void dm_pp_get_funcs_rv( + struct dc_context *ctx, + struct pp_smu_funcs_rv *funcs) +{ + funcs->pp_smu.ctx = ctx; + funcs->set_display_requirement = pp_rv_set_display_requirement; + funcs->set_wm_ranges = pp_rv_set_wm_ranges; + funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index e861929dd981f..9f0a217603ad0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -35,6 +35,8 @@ #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" + + unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, unsigned long long current_time_stamp, unsigned long long last_time_stamp) @@ -72,326 +74,4 @@ bool dm_read_persistent_data(struct dc_context *ctx, /**** power component interfaces ****/ -bool dm_pp_apply_display_requirements( - const struct dc_context *ctx, - const struct dm_pp_display_configuration *pp_display_cfg) -{ - struct amdgpu_device *adev = ctx->driver_context; - - if (adev->pm.dpm_enabled) { - - memset(&adev->pm.pm_display_cfg, 0, - sizeof(adev->pm.pm_display_cfg)); - - adev->pm.pm_display_cfg.cpu_cc6_disable = - pp_display_cfg->cpu_cc6_disable; - - adev->pm.pm_display_cfg.cpu_pstate_disable = - pp_display_cfg->cpu_pstate_disable; - - adev->pm.pm_display_cfg.cpu_pstate_separation_time = - pp_display_cfg->cpu_pstate_separation_time; - - adev->pm.pm_display_cfg.nb_pstate_switch_disable = - pp_display_cfg->nb_pstate_switch_disable; - - adev->pm.pm_display_cfg.num_display = - pp_display_cfg->display_count; - adev->pm.pm_display_cfg.num_path_including_non_display = - pp_display_cfg->display_count; - - adev->pm.pm_display_cfg.min_core_set_clock = - pp_display_cfg->min_engine_clock_khz/10; - adev->pm.pm_display_cfg.min_core_set_clock_in_sr = - pp_display_cfg->min_engine_clock_deep_sleep_khz/10; - adev->pm.pm_display_cfg.min_mem_set_clock = - pp_display_cfg->min_memory_clock_khz/10; - - adev->pm.pm_display_cfg.multi_monitor_in_sync = - pp_display_cfg->all_displays_in_sync; - adev->pm.pm_display_cfg.min_vblank_time = - pp_display_cfg->avail_mclk_switch_time_us; - - adev->pm.pm_display_cfg.display_clk = - pp_display_cfg->disp_clk_khz/10; - - adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; - - adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; - adev->pm.pm_display_cfg.line_time_in_us = - pp_display_cfg->line_time_in_us; - - adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; - adev->pm.pm_display_cfg.crossfire_display_index = -1; - adev->pm.pm_display_cfg.min_bus_bandwidth = 0; - - /* TODO: complete implementation of - * pp_display_configuration_change(). - * Follow example of: - * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c - * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ - if (adev->powerplay.pp_funcs->display_configuration_change) - adev->powerplay.pp_funcs->display_configuration_change( - adev->powerplay.pp_handle, - &adev->pm.pm_display_cfg); - - /* TODO: replace by a separate call to 'apply display cfg'? */ - amdgpu_pm_compute_clocks(adev); - } - - return true; -} - -static void get_default_clock_levels( - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels *clks) -{ - uint32_t disp_clks_in_khz[6] = { - 300000, 400000, 496560, 626090, 685720, 757900 }; - uint32_t sclks_in_khz[6] = { - 300000, 360000, 423530, 514290, 626090, 720000 }; - uint32_t mclks_in_khz[2] = { 333000, 800000 }; - - switch (clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - clks->num_levels = 6; - memmove(clks->clocks_in_khz, disp_clks_in_khz, - sizeof(disp_clks_in_khz)); - break; - case DM_PP_CLOCK_TYPE_ENGINE_CLK: - clks->num_levels = 6; - memmove(clks->clocks_in_khz, sclks_in_khz, - sizeof(sclks_in_khz)); - break; - case DM_PP_CLOCK_TYPE_MEMORY_CLK: - clks->num_levels = 2; - memmove(clks->clocks_in_khz, mclks_in_khz, - sizeof(mclks_in_khz)); - break; - default: - clks->num_levels = 0; - break; - } -} - -static enum amd_pp_clock_type dc_to_pp_clock_type( - enum dm_pp_clock_type dm_pp_clk_type) -{ - enum amd_pp_clock_type amd_pp_clk_type = 0; - - switch (dm_pp_clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - amd_pp_clk_type = amd_pp_disp_clock; - break; - case DM_PP_CLOCK_TYPE_ENGINE_CLK: - amd_pp_clk_type = amd_pp_sys_clock; - break; - case DM_PP_CLOCK_TYPE_MEMORY_CLK: - amd_pp_clk_type = amd_pp_mem_clock; - break; - default: - DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", - dm_pp_clk_type); - break; - } - - return amd_pp_clk_type; -} - -static void pp_to_dc_clock_levels( - const struct amd_pp_clocks *pp_clks, - struct dm_pp_clock_levels *dc_clks, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->count, - DM_PP_MAX_CLOCK_LEVELS); - - dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - dc_clks->num_levels = pp_clks->count; - - DRM_INFO("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < dc_clks->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); - /* translate 10kHz to kHz */ - dc_clks->clocks_in_khz[i] = pp_clks->clock[i] * 10; - } -} - -static void pp_to_dc_clock_levels_with_latency( - const struct pp_clock_levels_with_latency *pp_clks, - struct dm_pp_clock_levels_with_latency *clk_level_info, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->num_levels, - DM_PP_MAX_CLOCK_LEVELS); - - clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - clk_level_info->num_levels = pp_clks->num_levels; - - DRM_DEBUG("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_DEBUG("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz); - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; - clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; - } -} - -bool dm_pp_get_clock_levels_by_type( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels *dc_clks) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct amd_pp_clocks pp_clks = { 0 }; - struct amd_pp_simple_clock_info validation_clks = { 0 }; - uint32_t i; - - if (adev->powerplay.pp_funcs->get_clock_by_type) { - if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, - dc_to_pp_clock_type(clk_type), &pp_clks)) { - /* Error in pplib. Provide default values. */ - get_default_clock_levels(clk_type, dc_clks); - return true; - } - } - - pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); - - if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { - if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( - pp_handle, &validation_clks)) { - /* Error in pplib. Provide default values. */ - DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); - validation_clks.engine_max_clock = 72000; - validation_clks.memory_max_clock = 80000; - validation_clks.level = 0; - } - } - - DRM_INFO("DM_PPLIB: Validation clocks:\n"); - DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", - validation_clks.engine_max_clock); - DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", - validation_clks.memory_max_clock); - DRM_INFO("DM_PPLIB: level : %d\n", - validation_clks.level); - - /* Translate 10 kHz to kHz. */ - validation_clks.engine_max_clock *= 10; - validation_clks.memory_max_clock *= 10; - - /* Determine the highest non-boosted level from the Validation Clocks */ - if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { - /* This clock is higher the validation clock. - * Than means the previous one is the highest - * non-boosted one. */ - DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { - DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } - - return true; -} - -bool dm_pp_get_clock_levels_by_type_with_latency( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels_with_latency *clk_level_info) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct pp_clock_levels_with_latency pp_clks = { 0 }; - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - - if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) - return false; - - if (pp_funcs->get_clock_by_type_with_latency(pp_handle, - dc_to_pp_clock_type(clk_type), - &pp_clks)) - return false; - - pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); - - return true; -} - -bool dm_pp_get_clock_levels_by_type_with_voltage( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels_with_voltage *clk_level_info) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_notify_wm_clock_changes( - const struct dc_context *ctx, - struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_apply_power_level_change_request( - const struct dc_context *ctx, - struct dm_pp_power_level_change_request *level_change_req) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_apply_clock_for_voltage_request( - const struct dc_context *ctx, - struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_get_static_clocks( - const struct dc_context *ctx, - struct dm_pp_static_clock_info *static_clk_info) -{ - /* TODO: to be implemented */ - return false; -} - -void dm_pp_get_funcs_rv( - struct dc_context *ctx, - struct pp_smu_funcs_rv *funcs) -{} -/**** end of power component interfaces ****/ diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index c7f0b27e457e4..be8a2494355a4 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -3762,6 +3762,200 @@ static struct integrated_info *bios_parser_create_integrated_info( return NULL; } +enum bp_result update_slot_layout_info( + struct dc_bios *dcb, + unsigned int i, + struct slot_layout_info *slot_layout_info, + unsigned int record_offset) +{ + unsigned int j; + struct bios_parser *bp; + ATOM_BRACKET_LAYOUT_RECORD *record; + ATOM_COMMON_RECORD_HEADER *record_header; + enum bp_result result = BP_RESULT_NORECORD; + + bp = BP_FROM_DCB(dcb); + record = NULL; + record_header = NULL; + + for (;;) { + + record_header = (ATOM_COMMON_RECORD_HEADER *) + GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset); + if (record_header == NULL) { + result = BP_RESULT_BADBIOSTABLE; + break; + } + + /* the end of the list */ + if (record_header->ucRecordType == 0xff || + record_header->ucRecordSize == 0) { + break; + } + + if (record_header->ucRecordType == + ATOM_BRACKET_LAYOUT_RECORD_TYPE && + sizeof(ATOM_BRACKET_LAYOUT_RECORD) + <= record_header->ucRecordSize) { + record = (ATOM_BRACKET_LAYOUT_RECORD *) + (record_header); + result = BP_RESULT_OK; + break; + } + + record_offset += record_header->ucRecordSize; + } + + /* return if the record not found */ + if (result != BP_RESULT_OK) + return result; + + /* get slot sizes */ + slot_layout_info->length = record->ucLength; + slot_layout_info->width = record->ucWidth; + + /* get info for each connector in the slot */ + slot_layout_info->num_of_connectors = record->ucConnNum; + for (j = 0; j < slot_layout_info->num_of_connectors; ++j) { + slot_layout_info->connectors[j].connector_type = + (enum connector_layout_type) + (record->asConnInfo[j].ucConnectorType); + switch (record->asConnInfo[j].ucConnectorType) { + case CONNECTOR_TYPE_DVI_D: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DVI_D; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DVI; + break; + + case CONNECTOR_TYPE_HDMI: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_HDMI; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_HDMI; + break; + + case CONNECTOR_TYPE_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DP; + break; + + case CONNECTOR_TYPE_MINI_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_MINI_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_MINI_DP; + break; + + default: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_UNKNOWN; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_UNKNOWN; + } + + slot_layout_info->connectors[j].position = + record->asConnInfo[j].ucPosition; + slot_layout_info->connectors[j].connector_id = + object_id_from_bios_object_id( + record->asConnInfo[j].usConnectorObjectId); + } + return result; +} + + +enum bp_result get_bracket_layout_record( + struct dc_bios *dcb, + unsigned int bracket_layout_id, + struct slot_layout_info *slot_layout_info) +{ + unsigned int i; + unsigned int record_offset; + struct bios_parser *bp; + enum bp_result result; + ATOM_OBJECT *object; + ATOM_OBJECT_TABLE *object_table; + unsigned int genericTableOffset; + + bp = BP_FROM_DCB(dcb); + object = NULL; + if (slot_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + + genericTableOffset = bp->object_info_tbl_offset + + bp->object_info_tbl.v1_3->usMiscObjectTableOffset; + object_table = (ATOM_OBJECT_TABLE *) + GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset); + if (!object_table) + return BP_RESULT_FAILURE; + + result = BP_RESULT_NORECORD; + for (i = 0; i < object_table->ucNumberOfObjects; ++i) { + + if (bracket_layout_id == + object_table->asObjects[i].usObjectID) { + + object = &object_table->asObjects[i]; + record_offset = object->usRecordOffset + + bp->object_info_tbl_offset; + + result = update_slot_layout_info(dcb, i, + slot_layout_info, record_offset); + break; + } + } + return result; +} + +static enum bp_result bios_get_board_layout_info( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info) +{ + unsigned int i; + struct bios_parser *bp; + enum bp_result record_result; + + const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2, + 0, 0 + }; + + bp = BP_FROM_DCB(dcb); + if (board_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + board_layout_info->num_of_slots = 0; + + for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + record_result = get_bracket_layout_record(dcb, + slot_index_to_vbios_id[i], + &board_layout_info->slots[i]); + + if (record_result == BP_RESULT_NORECORD && i > 0) + break; /* no more slots present in bios */ + else if (record_result != BP_RESULT_OK) + return record_result; /* fail */ + + ++board_layout_info->num_of_slots; + } + + /* all data is valid */ + board_layout_info->is_number_of_slots_valid = 1; + board_layout_info->is_slots_size_valid = 1; + board_layout_info->is_connector_offsets_valid = 1; + board_layout_info->is_connector_lengths_valid = 1; + + return BP_RESULT_OK; +} + /******************************************************************************/ static const struct dc_vbios_funcs vbios_funcs = { @@ -3836,6 +4030,8 @@ static const struct dc_vbios_funcs vbios_funcs = { .post_init = bios_parser_post_init, /* patch vbios table for mxm module by reading i2c */ .bios_parser_destroy = bios_parser_destroy, + + .get_board_layout_info = bios_get_board_layout_info, }; static bool bios_parser_construct( diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index b8cef7af3c4af..aeb56e402cccf 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -43,6 +43,29 @@ #include "bios_parser_interface.h" #include "bios_parser_common.h" + +/* Temporarily add in defines until ObjectID.h patch is updated in a few days */ +#ifndef GENERIC_OBJECT_ID_BRACKET_LAYOUT +#define GENERIC_OBJECT_ID_BRACKET_LAYOUT 0x05 +#endif /* GENERIC_OBJECT_ID_BRACKET_LAYOUT */ + +#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) +#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 */ + +#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) +#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 */ + +#define DC_LOGGER \ + bp->base.ctx->logger + #define LAST_RECORD_TYPE 0xff #define SMU9_SYSPLL0_ID 0 @@ -86,7 +109,6 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( #define DATA_TABLES(table) (bp->master_data_tbl->listOfdatatables.table) - static void destruct(struct bios_parser *bp) { kfree(bp->base.bios_local_image); @@ -1854,6 +1876,198 @@ static struct integrated_info *bios_parser_create_integrated_info( return NULL; } +static enum bp_result update_slot_layout_info( + struct dc_bios *dcb, + unsigned int i, + struct slot_layout_info *slot_layout_info) +{ + unsigned int record_offset; + unsigned int j; + struct atom_display_object_path_v2 *object; + struct atom_bracket_layout_record *record; + struct atom_common_record_header *record_header; + enum bp_result result; + struct bios_parser *bp; + struct object_info_table *tbl; + struct display_object_info_table_v1_4 *v1_4; + + record = NULL; + record_header = NULL; + result = BP_RESULT_NORECORD; + + bp = BP_FROM_DCB(dcb); + tbl = &bp->object_info_tbl; + v1_4 = tbl->v1_4; + + object = &v1_4->display_path[i]; + record_offset = (unsigned int) + (object->disp_recordoffset) + + (unsigned int)(bp->object_info_tbl_offset); + + for (;;) { + + record_header = (struct atom_common_record_header *) + GET_IMAGE(struct atom_common_record_header, + record_offset); + if (record_header == NULL) { + result = BP_RESULT_BADBIOSTABLE; + break; + } + + /* the end of the list */ + if (record_header->record_type == 0xff || + record_header->record_size == 0) { + break; + } + + if (record_header->record_type == + ATOM_BRACKET_LAYOUT_RECORD_TYPE && + sizeof(struct atom_bracket_layout_record) + <= record_header->record_size) { + record = (struct atom_bracket_layout_record *) + (record_header); + result = BP_RESULT_OK; + break; + } + + record_offset += record_header->record_size; + } + + /* return if the record not found */ + if (result != BP_RESULT_OK) + return result; + + /* get slot sizes */ + slot_layout_info->length = record->bracketlen; + slot_layout_info->width = record->bracketwidth; + + /* get info for each connector in the slot */ + slot_layout_info->num_of_connectors = record->conn_num; + for (j = 0; j < slot_layout_info->num_of_connectors; ++j) { + slot_layout_info->connectors[j].connector_type = + (enum connector_layout_type) + (record->conn_info[j].connector_type); + switch (record->conn_info[j].connector_type) { + case CONNECTOR_TYPE_DVI_D: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DVI_D; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DVI; + break; + + case CONNECTOR_TYPE_HDMI: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_HDMI; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_HDMI; + break; + + case CONNECTOR_TYPE_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DP; + break; + + case CONNECTOR_TYPE_MINI_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_MINI_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_MINI_DP; + break; + + default: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_UNKNOWN; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_UNKNOWN; + } + + slot_layout_info->connectors[j].position = + record->conn_info[j].position; + slot_layout_info->connectors[j].connector_id = + object_id_from_bios_object_id( + record->conn_info[j].connectorobjid); + } + return result; +} + + +static enum bp_result get_bracket_layout_record( + struct dc_bios *dcb, + unsigned int bracket_layout_id, + struct slot_layout_info *slot_layout_info) +{ + unsigned int i; + struct bios_parser *bp = BP_FROM_DCB(dcb); + enum bp_result result; + struct object_info_table *tbl; + struct display_object_info_table_v1_4 *v1_4; + + if (slot_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); + return BP_RESULT_BADINPUT; + } + tbl = &bp->object_info_tbl; + v1_4 = tbl->v1_4; + + result = BP_RESULT_NORECORD; + for (i = 0; i < v1_4->number_of_path; ++i) { + + if (bracket_layout_id == + v1_4->display_path[i].display_objid) { + result = update_slot_layout_info(dcb, i, + slot_layout_info); + break; + } + } + return result; +} + +static enum bp_result bios_get_board_layout_info( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info) +{ + unsigned int i; + struct bios_parser *bp; + enum bp_result record_result; + + const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2, + 0, 0 + }; + + bp = BP_FROM_DCB(dcb); + if (board_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + board_layout_info->num_of_slots = 0; + + for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + record_result = get_bracket_layout_record(dcb, + slot_index_to_vbios_id[i], + &board_layout_info->slots[i]); + + if (record_result == BP_RESULT_NORECORD && i > 0) + break; /* no more slots present in bios */ + else if (record_result != BP_RESULT_OK) + return record_result; /* fail */ + + ++board_layout_info->num_of_slots; + } + + /* all data is valid */ + board_layout_info->is_number_of_slots_valid = 1; + board_layout_info->is_slots_size_valid = 1; + board_layout_info->is_connector_offsets_valid = 1; + board_layout_info->is_connector_lengths_valid = 1; + + return BP_RESULT_OK; +} + static const struct dc_vbios_funcs vbios_funcs = { .get_connectors_number = bios_parser_get_connectors_number, @@ -1925,6 +2139,8 @@ static const struct dc_vbios_funcs vbios_funcs = { .bios_parser_destroy = firmware_parser_destroy, .get_smu_clock_info = bios_parser_get_smu_clock_info, + + .get_board_layout_info = bios_get_board_layout_info, }; static bool bios_parser_construct( diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 752b08a42d3ec..2b5dc499a35ed 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -59,36 +59,7 @@ bios_cmd_table_para_revision(bp->base.ctx->driver_context, \ GET_INDEX_INTO_MASTER_TABLE(command, fname)) -static void init_dig_encoder_control(struct bios_parser *bp); -static void init_transmitter_control(struct bios_parser *bp); -static void init_set_pixel_clock(struct bios_parser *bp); -static void init_set_crtc_timing(struct bios_parser *bp); - -static void init_select_crtc_source(struct bios_parser *bp); -static void init_enable_crtc(struct bios_parser *bp); - -static void init_external_encoder_control(struct bios_parser *bp); -static void init_enable_disp_power_gating(struct bios_parser *bp); -static void init_set_dce_clock(struct bios_parser *bp); -static void init_get_smu_clock_info(struct bios_parser *bp); - -void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) -{ - init_dig_encoder_control(bp); - init_transmitter_control(bp); - init_set_pixel_clock(bp); - - init_set_crtc_timing(bp); - - init_select_crtc_source(bp); - init_enable_crtc(bp); - - init_external_encoder_control(bp); - init_enable_disp_power_gating(bp); - init_set_dce_clock(bp); - init_get_smu_clock_info(bp); -} static uint32_t bios_cmd_table_para_revision(void *dev, uint32_t index) @@ -829,3 +800,20 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) return 0; } +void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) +{ + init_dig_encoder_control(bp); + init_transmitter_control(bp); + init_set_pixel_clock(bp); + + init_set_crtc_timing(bp); + + init_select_crtc_source(bp); + init_enable_crtc(bp); + + init_external_encoder_control(bp); + init_enable_disp_power_gating(bp); + init_set_dce_clock(bp); + init_get_smu_clock_info(bp); + +} diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 49a4ea45466d3..e44b8d3d68910 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -31,6 +31,8 @@ #include "resource.h" #include "dcn10/dcn10_resource.h" +#include "dcn10/dcn10_hubbub.h" + #include "dcn_calc_math.h" #define DC_LOGGER \ @@ -423,6 +425,10 @@ static void dcn_bw_calc_rq_dlg_ttu( int total_flip_bytes = 0; int i; + memset(dlg_regs, 0, sizeof(*dlg_regs)); + memset(ttu_regs, 0, sizeof(*ttu_regs)); + memset(rq_regs, 0, sizeof(*rq_regs)); + for (i = 0; i < number_of_planes; i++) { total_active_bw += v->read_bandwidth[i]; total_prefetch_bw += v->prefetch_bandwidth[i]; @@ -501,6 +507,7 @@ static void split_stream_across_pipes( resource_build_scaling_params(secondary_pipe); } +#if 0 static void calc_wm_sets_and_perf_params( struct dc_state *context, struct dcn_bw_internal_vars *v) @@ -582,6 +589,7 @@ static void calc_wm_sets_and_perf_params( if (v->voltage_level >= 3) context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a; } +#endif static bool dcn_bw_apply_registry_override(struct dc *dc) { @@ -883,7 +891,26 @@ bool dcn_validate_bandwidth( ASSERT(pipe->plane_res.scl_data.ratios.vert.value != dc_fixpt_one.value || v->scaler_rec_out_width[input_idx] == v->viewport_height[input_idx]); } - v->dcc_enable[input_idx] = pipe->plane_state->dcc.enable ? dcn_bw_yes : dcn_bw_no; + + if (dc->debug.optimized_watermark) { + /* + * this method requires us to always re-calculate watermark when dcc change + * between flip. + */ + v->dcc_enable[input_idx] = pipe->plane_state->dcc.enable ? dcn_bw_yes : dcn_bw_no; + } else { + /* + * allow us to disable dcc on the fly without re-calculating WM + * + * extra overhead for DCC is quite small. for 1080p WM without + * DCC is only 0.417us lower (urgent goes from 6.979us to 6.562us) + */ + unsigned int bpe; + + v->dcc_enable[input_idx] = dc->res_pool->hubbub->funcs->dcc_support_pixel_format( + pipe->plane_state->format, &bpe) ? dcn_bw_yes : dcn_bw_no; + } + v->source_pixel_format[input_idx] = tl_pixel_format_to_bw_defs( pipe->plane_state->format); v->source_surface_mode[input_idx] = tl_sw_mode_to_bw_defs( @@ -976,43 +1003,60 @@ bool dcn_validate_bandwidth( bw_consumed = v->fabric_and_dram_bandwidth; display_pipe_configuration(v); - calc_wm_sets_and_perf_params(context, v); - context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / + /*calc_wm_sets_and_perf_params(context, v);*/ + /* Only 1 set is used by dcn since no noticeable + * performance improvement was measured and due to hw bug DEGVIDCN10-254 + */ + dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v); + + context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = + v->stutter_exit_watermark * 1000; + context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + v->stutter_enter_plus_exit_watermark * 1000; + context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = + v->dram_clock_change_watermark * 1000; + context->bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000; + context->bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000; + context->bw.dcn.watermarks.b = context->bw.dcn.watermarks.a; + context->bw.dcn.watermarks.c = context->bw.dcn.watermarks.a; + context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a; + + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / (ddr4_dram_factor_single_Channel * v->number_of_channels)); if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) { - context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); } - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); - context->bw.dcn.calc_clk.dcfclk_khz = (int)(v->dcfclk * 1000); + context->bw.dcn.clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); + context->bw.dcn.clk.dcfclk_khz = (int)(v->dcfclk * 1000); - context->bw.dcn.calc_clk.dispclk_khz = (int)(v->dispclk * 1000); + context->bw.dcn.clk.dispclk_khz = (int)(v->dispclk * 1000); if (dc->debug.max_disp_clk == true) - context->bw.dcn.calc_clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000); + context->bw.dcn.clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000); - if (context->bw.dcn.calc_clk.dispclk_khz < + if (context->bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz) { - context->bw.dcn.calc_clk.dispclk_khz = + context->bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; - + context->bw.dcn.clk.dppclk_khz = context->bw.dcn.clk.dispclk_khz / v->dispclk_dppclk_ratio; + context->bw.dcn.clk.phyclk_khz = v->phyclk_per_state[v->voltage_level]; switch (v->voltage_level) { case 0: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmin0p65 * 1000); break; case 1: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmid0p72 * 1000); break; case 2: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vnom0p8 * 1000); break; default: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmax0p9 * 1000); break; } @@ -1225,27 +1269,27 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( unsigned int dcn_find_dcfclk_suits_all( const struct dc *dc, - struct clocks_value *clocks) + struct dc_clocks *clocks) { unsigned vdd_level, vdd_level_temp; unsigned dcf_clk; /*find a common supported voltage level*/ vdd_level = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DISPLAY_CLK, clocks->dispclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DISPLAY_CLK, clocks->dispclk_khz); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, clocks->phyclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, clocks->phyclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DPPCLK, clocks->dppclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DPPCLK, clocks->dppclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_MEMORY_CLK, clocks->dcfclock_in_khz); + dc, DM_PP_CLOCK_TYPE_MEMORY_CLK, clocks->fclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DCFCLK, clocks->dcfclock_in_khz); + dc, DM_PP_CLOCK_TYPE_DCFCLK, clocks->dcfclk_khz); /*find that level conresponding dcfclk*/ vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); @@ -1331,21 +1375,14 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) { struct pp_smu_funcs_rv *pp = dc->res_pool->pp_smu; struct pp_smu_wm_range_sets ranges = {0}; - int max_fclk_khz, nom_fclk_khz, mid_fclk_khz, min_fclk_khz; - int max_dcfclk_khz, min_dcfclk_khz; - int socclk_khz; + int min_fclk_khz, min_dcfclk_khz, socclk_khz; const int overdrive = 5000000; /* 5 GHz to cover Overdrive */ - unsigned factor = (ddr4_dram_factor_single_Channel * dc->dcn_soc->number_of_channels); if (!pp->set_wm_ranges) return; kernel_fpu_begin(); - max_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 * 1000000 / factor; - nom_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 * 1000000 / factor; - mid_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 * 1000000 / factor; min_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 * 1000000 / 32; - max_dcfclk_khz = dc->dcn_soc->dcfclkv_max0p9 * 1000; min_dcfclk_khz = dc->dcn_soc->dcfclkv_min0p65 * 1000; socclk_khz = dc->dcn_soc->socclk * 1000; kernel_fpu_end(); @@ -1353,105 +1390,46 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) /* Now notify PPLib/SMU about which Watermarks sets they should select * depending on DPM state they are in. And update BW MGR GFX Engine and * Memory clock member variables for Watermarks calculations for each - * Watermark Set + * Watermark Set. Only one watermark set for dcn1 due to hw bug DEGVIDCN10-254. */ /* SOCCLK does not affect anytihng but writeback for DCN so for now we dont * care what the value is, hence min to overdrive level */ - ranges.num_reader_wm_sets = WM_COUNT; - ranges.num_writer_wm_sets = WM_COUNT; + ranges.num_reader_wm_sets = WM_SET_COUNT; + ranges.num_writer_wm_sets = WM_SET_COUNT; ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz; - ranges.reader_wm_sets[0].max_drain_clk_khz = max_dcfclk_khz; + ranges.reader_wm_sets[0].max_drain_clk_khz = overdrive; ranges.reader_wm_sets[0].min_fill_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[0].max_fill_clk_khz = min_fclk_khz; + ranges.reader_wm_sets[0].max_fill_clk_khz = overdrive; ranges.writer_wm_sets[0].wm_inst = WM_A; ranges.writer_wm_sets[0].min_fill_clk_khz = socclk_khz; ranges.writer_wm_sets[0].max_fill_clk_khz = overdrive; ranges.writer_wm_sets[0].min_drain_clk_khz = min_fclk_khz; - ranges.writer_wm_sets[0].max_drain_clk_khz = min_fclk_khz; - - ranges.reader_wm_sets[1].wm_inst = WM_B; - ranges.reader_wm_sets[1].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[1].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[1].min_fill_clk_khz = mid_fclk_khz; - ranges.reader_wm_sets[1].max_fill_clk_khz = mid_fclk_khz; - ranges.writer_wm_sets[1].wm_inst = WM_B; - ranges.writer_wm_sets[1].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[1].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[1].min_drain_clk_khz = mid_fclk_khz; - ranges.writer_wm_sets[1].max_drain_clk_khz = mid_fclk_khz; - - - ranges.reader_wm_sets[2].wm_inst = WM_C; - ranges.reader_wm_sets[2].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[2].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[2].min_fill_clk_khz = nom_fclk_khz; - ranges.reader_wm_sets[2].max_fill_clk_khz = nom_fclk_khz; - ranges.writer_wm_sets[2].wm_inst = WM_C; - ranges.writer_wm_sets[2].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[2].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[2].min_drain_clk_khz = nom_fclk_khz; - ranges.writer_wm_sets[2].max_drain_clk_khz = nom_fclk_khz; - - ranges.reader_wm_sets[3].wm_inst = WM_D; - ranges.reader_wm_sets[3].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[3].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[3].min_fill_clk_khz = max_fclk_khz; - ranges.reader_wm_sets[3].max_fill_clk_khz = max_fclk_khz; - ranges.writer_wm_sets[3].wm_inst = WM_D; - ranges.writer_wm_sets[3].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[3].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[3].min_drain_clk_khz = max_fclk_khz; - ranges.writer_wm_sets[3].max_drain_clk_khz = max_fclk_khz; + ranges.writer_wm_sets[0].max_drain_clk_khz = overdrive; if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[0].max_drain_clk_khz = 654000; + ranges.reader_wm_sets[0].max_drain_clk_khz = 5000000; ranges.reader_wm_sets[0].min_fill_clk_khz = 800000; - ranges.reader_wm_sets[0].max_fill_clk_khz = 800000; + ranges.reader_wm_sets[0].max_fill_clk_khz = 5000000; ranges.writer_wm_sets[0].wm_inst = WM_A; ranges.writer_wm_sets[0].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[0].max_fill_clk_khz = 757000; + ranges.writer_wm_sets[0].max_fill_clk_khz = 5000000; ranges.writer_wm_sets[0].min_drain_clk_khz = 800000; - ranges.writer_wm_sets[0].max_drain_clk_khz = 800000; - - ranges.reader_wm_sets[1].wm_inst = WM_B; - ranges.reader_wm_sets[1].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[1].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[1].min_fill_clk_khz = 933000; - ranges.reader_wm_sets[1].max_fill_clk_khz = 933000; - ranges.writer_wm_sets[1].wm_inst = WM_B; - ranges.writer_wm_sets[1].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[1].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[1].min_drain_clk_khz = 933000; - ranges.writer_wm_sets[1].max_drain_clk_khz = 933000; - - - ranges.reader_wm_sets[2].wm_inst = WM_C; - ranges.reader_wm_sets[2].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[2].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[2].min_fill_clk_khz = 1067000; - ranges.reader_wm_sets[2].max_fill_clk_khz = 1067000; - ranges.writer_wm_sets[2].wm_inst = WM_C; - ranges.writer_wm_sets[2].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[2].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[2].min_drain_clk_khz = 1067000; - ranges.writer_wm_sets[2].max_drain_clk_khz = 1067000; - - ranges.reader_wm_sets[3].wm_inst = WM_D; - ranges.reader_wm_sets[3].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[3].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[3].min_fill_clk_khz = 1200000; - ranges.reader_wm_sets[3].max_fill_clk_khz = 1200000; - ranges.writer_wm_sets[3].wm_inst = WM_D; - ranges.writer_wm_sets[3].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[3].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[3].min_drain_clk_khz = 1200000; - ranges.writer_wm_sets[3].max_drain_clk_khz = 1200000; + ranges.writer_wm_sets[0].max_drain_clk_khz = 5000000; } + ranges.reader_wm_sets[1] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[1].wm_inst = WM_B; + + ranges.reader_wm_sets[2] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[2].wm_inst = WM_C; + + ranges.reader_wm_sets[3] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[3].wm_inst = WM_D; + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ pp->set_wm_ranges(&pp->pp_smu, &ranges); } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 53ce7fa864b4f..2a785bbf2b8f1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -944,12 +944,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc) dc->optimized_required = false; - /* 3rd param should be true, temp w/a for RV*/ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - dc->hwss.set_bandwidth(dc, context, dc->ctx->dce_version < DCN_VERSION_1_0); -#else dc->hwss.set_bandwidth(dc, context, true); -#endif return true; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 267c76766deae..e1ebdf7b5eaf3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -352,19 +352,19 @@ void context_clock_trace( DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", - context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_khz, - context->bw.dcn.calc_clk.dcfclk_khz, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz); + context->bw.dcn.clk.dispclk_khz, + context->bw.dcn.clk.dppclk_khz, + context->bw.dcn.clk.dcfclk_khz, + context->bw.dcn.clk.dcfclk_deep_sleep_khz, + context->bw.dcn.clk.fclk_khz, + context->bw.dcn.clk.socclk_khz); CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", - context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_khz, - context->bw.dcn.calc_clk.dcfclk_khz, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz); + context->bw.dcn.clk.dispclk_khz, + context->bw.dcn.clk.dppclk_khz, + context->bw.dcn.clk.dcfclk_khz, + context->bw.dcn.clk.dcfclk_deep_sleep_khz, + context->bw.dcn.clk.fclk_khz, + context->bw.dcn.clk.socclk_khz); #endif } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 08b7ee526f0fe..fa56c0fc02bf5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -33,6 +33,7 @@ #include "dc_link_dp.h" #include "dc_link_ddc.h" #include "link_hwss.h" +#include "opp.h" #include "link_encoder.h" #include "hw_sequencer.h" @@ -1284,29 +1285,15 @@ static enum dc_status enable_link_dp( max_link_rate = LINK_RATE_HIGH3; if (link_settings.link_rate == max_link_rate) { - if (state->dis_clk->funcs->set_min_clocks_state) { - if (state->dis_clk->cur_min_clks_state < DM_PP_CLOCKS_STATE_NOMINAL) - state->dis_clk->funcs->set_min_clocks_state( - state->dis_clk, DM_PP_CLOCKS_STATE_NOMINAL); - } else { - uint32_t dp_phyclk_in_khz; - const struct clocks_value clocks_value = - state->dis_clk->cur_clocks_value; - - /* 27mhz = 27000000hz= 27000khz */ - dp_phyclk_in_khz = link_settings.link_rate * 27000; - - if (((clocks_value.max_non_dp_phyclk_in_khz != 0) && - (dp_phyclk_in_khz > clocks_value.max_non_dp_phyclk_in_khz)) || - (dp_phyclk_in_khz > clocks_value.max_dp_phyclk_in_khz)) { - state->dis_clk->funcs->apply_clock_voltage_request( - state->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - dp_phyclk_in_khz, - false, - true); - } - } + struct dc_clocks clocks = state->bw.dcn.clk; + + /* dce/dcn compat, do not update dispclk */ + clocks.dispclk_khz = 0; + /* 27mhz = 27000000hz= 27000khz */ + clocks.phyclk_khz = link_settings.link_rate * 27000; + + state->dis_clk->funcs->update_clocks( + state->dis_clk, &clocks, false); } dp_enable_link_phy( @@ -2396,9 +2383,10 @@ void core_link_enable_stream( core_dc->hwss.enable_audio_stream(pipe_ctx); /* turn off otg test pattern if enable */ - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, - COLOR_DEPTH_UNDEFINED); + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + COLOR_DEPTH_UNDEFINED); core_dc->hwss.enable_stream(pipe_ctx); 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 509f265663d27..84586b679d73e 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 @@ -3,6 +3,7 @@ #include "dc.h" #include "dc_link_dp.h" #include "dm_helpers.h" +#include "opp.h" #include "inc/core_types.h" #include "link_hwss.h" @@ -1999,7 +2000,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd { union hpd_irq_data hpd_irq_dpcd_data = {{{{0}}}}; union device_service_irq device_service_clear = { { 0 } }; - enum dc_status result = DDC_RESULT_UNKNOWN; + enum dc_status result; bool status = false; /* For use cases related to down stream connection status change, * PSR and device auto test, refer to function handle_sst_hpd_irq @@ -2511,8 +2512,8 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream->bit_depth_params = params; pipe_ctx->stream_res.opp->funcs-> opp_program_bit_depth_reduction(pipe_ctx->stream_res.opp, ¶ms); - - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, controller_test_pattern, color_depth); } break; @@ -2524,8 +2525,8 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream->bit_depth_params = params; pipe_ctx->stream_res.opp->funcs-> opp_program_bit_depth_reduction(pipe_ctx->stream_res.opp, ¶ms); - - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, color_depth); } 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 fca22550417a9..c5fc5250e2bfc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1948,7 +1948,7 @@ void dc_resource_state_construct( const struct dc *dc, struct dc_state *dst_ctx) { - dst_ctx->dis_clk = dc->res_pool->display_clock; + dst_ctx->dis_clk = dc->res_pool->dccg; } enum dc_status dc_validate_global_state( diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7ebce7669eea5..0cb7e10d2505b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.47" +#define DC_VER "3.1.52" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -186,6 +186,10 @@ enum wm_report_mode { WM_REPORT_OVERRIDE = 1, }; +/* + * For any clocks that may differ per pipe + * only the max is stored in this structure + */ struct dc_clocks { int dispclk_khz; int max_supported_dppclk_khz; @@ -194,6 +198,7 @@ struct dc_clocks { int socclk_khz; int dcfclk_deep_sleep_khz; int fclk_khz; + int phyclk_khz; }; struct dc_debug { @@ -228,6 +233,7 @@ struct dc_debug { int urgent_latency_ns; int percent_of_ideal_drambw; int dram_clock_change_latency_ns; + bool optimized_watermark; int always_scale; bool disable_pplib_clock_request; bool disable_clock_gate; diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index d9b84ec7954c5..90082bab71f07 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -198,6 +198,10 @@ struct dc_vbios_funcs { void (*post_init)(struct dc_bios *bios); void (*bios_parser_destroy)(struct dc_bios **dcb); + + enum bp_result (*get_board_layout_info)( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info); }; struct bios_registers { diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index d31023d57b58a..14afbc5c0a621 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -199,6 +199,7 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb, + SURFACE_PIXEL_FORMAT_SUBSAMPLE_END, SURFACE_PIXEL_FORMAT_INVALID /*grow 444 video here if necessary */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 88b09dd758baa..ca137757a69e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -133,7 +133,7 @@ static bool calculate_fb_and_fractional_fb_divider( uint64_t feedback_divider; feedback_divider = - (uint64_t)(target_pix_clk_khz * ref_divider * post_divider); + (uint64_t)target_pix_clk_khz * ref_divider * post_divider; feedback_divider *= 10; /* additional factor, since we divide by 10 afterwards */ feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor); @@ -145,8 +145,8 @@ static bool calculate_fb_and_fractional_fb_divider( * of fractional feedback decimal point and the fractional FB Divider precision * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/ - feedback_divider += (uint64_t) - (5 * calc_pll_cs->fract_fb_divider_precision_factor); + feedback_divider += 5ULL * + calc_pll_cs->fract_fb_divider_precision_factor; feedback_divider = div_u64(feedback_divider, calc_pll_cs->fract_fb_divider_precision_factor * 10); @@ -203,8 +203,8 @@ static bool calc_fb_divider_checking_tolerance( &fract_feedback_divider); /*Actual calculated value*/ - actual_calc_clk_khz = (uint64_t)(feedback_divider * - calc_pll_cs->fract_fb_divider_factor) + + actual_calc_clk_khz = (uint64_t)feedback_divider * + calc_pll_cs->fract_fb_divider_factor + fract_feedback_divider; actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz; actual_calc_clk_khz = diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 8a581c67bf2d1..6882dc953a2c2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -38,7 +38,7 @@ #include "dal_asic_id.h" #define TO_DCE_CLOCKS(clocks)\ - container_of(clocks, struct dce_disp_clk, base) + container_of(clocks, struct dce_dccg, base) #define REG(reg) \ (clk_dce->regs->reg) @@ -101,99 +101,78 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStatePerformance*/ { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } }; -/* Starting point for each divider range.*/ -enum dce_divider_range_start { - DIVIDER_RANGE_01_START = 200, /* 2.00*/ - DIVIDER_RANGE_02_START = 1600, /* 16.00*/ - DIVIDER_RANGE_03_START = 3200, /* 32.00*/ - DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ +/* Starting DID for each range */ +enum dentist_base_divider_id { + DENTIST_BASE_DID_1 = 0x08, + DENTIST_BASE_DID_2 = 0x40, + DENTIST_BASE_DID_3 = 0x60, + DENTIST_MAX_DID = 0x80 }; -/* Ranges for divider identifiers (Divider ID or DID) - mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/ -enum dce_divider_id_register_setting { - DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08, - DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40, - DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60, - DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80 +/* Starting point and step size for each divider range.*/ +enum dentist_divider_range { + DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */ + DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */ + DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */ + DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ + DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ + DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ + DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 }; -/* Step size between each divider within a range. - Incrementing the DENTIST_DISPCLK_WDIVIDER by one - will increment the divider by this much.*/ -enum dce_divider_range_step_size { - DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/ - DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/ - DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */ -}; - -static bool dce_divider_range_construct( - struct dce_divider_range *div_range, - int range_start, - int range_step, - int did_min, - int did_max) +static int dentist_get_divider_from_did(int did) { - div_range->div_range_start = range_start; - div_range->div_range_step = range_step; - div_range->did_min = did_min; - div_range->did_max = did_max; - - if (div_range->div_range_step == 0) { - div_range->div_range_step = 1; - /*div_range_step cannot be zero*/ - BREAK_TO_DEBUGGER(); + if (did < DENTIST_BASE_DID_1) + did = DENTIST_BASE_DID_1; + if (did > DENTIST_MAX_DID) + did = DENTIST_MAX_DID; + + if (did < DENTIST_BASE_DID_2) { + return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP + * (did - DENTIST_BASE_DID_1); + } else if (did < DENTIST_BASE_DID_3) { + return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP + * (did - DENTIST_BASE_DID_2); + } else { + return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP + * (did - DENTIST_BASE_DID_3); } - /* Calculate this based on the other inputs.*/ - /* See DividerRange.h for explanation of */ - /* the relationship between divider id (DID) and a divider.*/ - /* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/ - /* Maximum divider identified in this range = - * (Number of Divider IDs)*Step size between dividers - * + The start of this range.*/ - div_range->div_range_end = (did_max - did_min) * range_step - + range_start; - return true; -} - -static int dce_divider_range_calc_divider( - struct dce_divider_range *div_range, - int did) -{ - /* Is this DID within our range?*/ - if ((did < div_range->did_min) || (did >= div_range->did_max)) - return INVALID_DIVIDER; - - return ((did - div_range->did_min) * div_range->div_range_step) - + div_range->div_range_start; - } -static int dce_divider_range_get_divider( - struct dce_divider_range *div_range, - int ranges_num, - int did) +/* SW will adjust DP REF Clock average value for all purposes + * (DP DTO / DP Audio DTO and DP GTC) + if clock is spread for all cases: + -if SS enabled on DP Ref clock and HW de-spreading enabled with SW + calculations for DS_INCR/DS_MODULO (this is planned to be default case) + -if SS enabled on DP Ref clock and HW de-spreading enabled with HW + calculations (not planned to be used, but average clock should still + be valid) + -if SS enabled on DP Ref clock and HW de-spreading disabled + (should not be case with CIK) then SW should program all rates + generated according to average value (case as with previous ASICs) + */ +static int dccg_adjust_dp_ref_freq_for_ss(struct dce_dccg *clk_dce, int dp_ref_clk_khz) { - int div = INVALID_DIVIDER; - int i; + if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { + struct fixed31_32 ss_percentage = dc_fixpt_div_int( + dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, + clk_dce->dprefclk_ss_divider), 200); + struct fixed31_32 adj_dp_ref_clk_khz; - for (i = 0; i < ranges_num; i++) { - /* Calculate divider with given divider ID*/ - div = dce_divider_range_calc_divider(&div_range[i], did); - /* Found a valid return divider*/ - if (div != INVALID_DIVIDER) - break; + ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); + adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); + dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); } - return div; + return dp_ref_clk_khz; } -static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) +static int dce_get_dp_ref_freq_khz(struct dccg *clk) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int dprefclk_wdivider; int dprefclk_src_sel; int dp_ref_clk_khz = 600000; - int target_div = INVALID_DIVIDER; + int target_div; /* ASSERT DP Reference Clock source is from DFS*/ REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel); @@ -204,80 +183,27 @@ static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ - target_div = dce_divider_range_get_divider( - clk_dce->divider_ranges, - DIVIDER_RANGE_MAX, - dprefclk_wdivider); - - if (target_div != INVALID_DIVIDER) { - /* Calculate the current DFS clock, in kHz.*/ - dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR - * clk_dce->dentist_vco_freq_khz) / target_div; - } + target_div = dentist_get_divider_from_did(dprefclk_wdivider); - /* SW will adjust DP REF Clock average value for all purposes - * (DP DTO / DP Audio DTO and DP GTC) - if clock is spread for all cases: - -if SS enabled on DP Ref clock and HW de-spreading enabled with SW - calculations for DS_INCR/DS_MODULO (this is planned to be default case) - -if SS enabled on DP Ref clock and HW de-spreading enabled with HW - calculations (not planned to be used, but average clock should still - be valid) - -if SS enabled on DP Ref clock and HW de-spreading disabled - (should not be case with CIK) then SW should program all rates - generated according to average value (case as with previous ASICs) - */ - if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { - struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction( - clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); - struct fixed31_32 adj_dp_ref_clk_khz; + /* Calculate the current DFS clock, in kHz.*/ + dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_dce->dentist_vco_freq_khz) / target_div; - ss_percentage = dc_fixpt_sub(dc_fixpt_one, - ss_percentage); - adj_dp_ref_clk_khz = - dc_fixpt_mul_int( - ss_percentage, - dp_ref_clk_khz); - dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); - } - - return dp_ref_clk_khz; + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, dp_ref_clk_khz); } -/* TODO: This is DCN DPREFCLK: it could be program by DENTIST by VBIOS - * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit - * clock implementation - */ -static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk) +static int dce12_get_dp_ref_freq_khz(struct dccg *clk) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); - int dp_ref_clk_khz = 600000; - - if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { - struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction( - clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); - struct fixed31_32 adj_dp_ref_clk_khz; + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); - ss_percentage = dc_fixpt_sub(dc_fixpt_one, - ss_percentage); - adj_dp_ref_clk_khz = - dc_fixpt_mul_int( - ss_percentage, - dp_ref_clk_khz); - dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); - } - - return dp_ref_clk_khz; + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, 600000); } + static enum dm_pp_clocks_state dce_get_required_clocks_state( - struct display_clock *clk, - struct state_dependent_clocks *req_clocks) + struct dccg *clk, + struct dc_clocks *req_clocks) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int i; enum dm_pp_clocks_state low_req_clk; @@ -286,53 +212,30 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( * all required clocks */ for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--) - if (req_clocks->display_clk_khz > + if (req_clocks->dispclk_khz > clk_dce->max_clks_by_state[i].display_clk_khz - || req_clocks->pixel_clk_khz > + || req_clocks->phyclk_khz > clk_dce->max_clks_by_state[i].pixel_clk_khz) break; low_req_clk = i + 1; if (low_req_clk > clk->max_clks_state) { - DC_LOG_WARNING("%s: clocks unsupported disp_clk %d pix_clk %d", - __func__, - req_clocks->display_clk_khz, - req_clocks->pixel_clk_khz); - low_req_clk = DM_PP_CLOCKS_STATE_INVALID; + /* set max clock state for high phyclock, invalid on exceeding display clock */ + if (clk_dce->max_clks_by_state[clk->max_clks_state].display_clk_khz + < req_clocks->dispclk_khz) + low_req_clk = DM_PP_CLOCKS_STATE_INVALID; + else + low_req_clk = clk->max_clks_state; } return low_req_clk; } -static bool dce_clock_set_min_clocks_state( - struct display_clock *clk, - enum dm_pp_clocks_state clocks_state) -{ - struct dm_pp_power_level_change_request level_change_req = { - clocks_state }; - - if (clocks_state > clk->max_clks_state) { - /*Requested state exceeds max supported state.*/ - DC_LOG_WARNING("Requested state exceeds max supported state"); - return false; - } else if (clocks_state == clk->cur_min_clks_state) { - /*if we're trying to set the same state, we can just return - * since nothing needs to be done*/ - return true; - } - - /* get max clock state from PPLIB */ - if (dm_pp_apply_power_level_change_request(clk->ctx, &level_change_req)) - clk->cur_min_clks_state = clocks_state; - - return true; -} - static int dce_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct bp_pixel_clock_parameters pxl_clk_params = { 0 }; struct dc_bios *bp = clk->ctx->dc_bios; int actual_clock = requested_clk_khz; @@ -364,10 +267,10 @@ static int dce_set_clock( } static int dce_psr_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct dc_context *ctx = clk_dce->base.ctx; struct dc *core_dc = ctx->dc; struct dmcu *dmcu = core_dc->res_pool->dmcu; @@ -380,10 +283,10 @@ static int dce_psr_set_clock( } static int dce112_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct bp_set_dce_clock_parameters dce_clk_params; struct dc_bios *bp = clk->ctx->dc_bios; struct dc *core_dc = clk->ctx->dc; @@ -432,7 +335,7 @@ static int dce112_set_clock( return actual_clock; } -static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) +static void dce_clock_read_integrated_info(struct dce_dccg *clk_dce) { struct dc_debug *debug = &clk_dce->base.ctx->dc->debug; struct dc_bios *bp = clk_dce->base.ctx->dc_bios; @@ -488,11 +391,9 @@ static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) if (!debug->disable_dfs_bypass && bp->integrated_info) if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) clk_dce->dfs_bypass_enabled = true; - - clk_dce->use_max_disp_clk = debug->max_disp_clk; } -static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) +static void dce_clock_read_ss_info(struct dce_dccg *clk_dce) { struct dc_bios *bp = clk_dce->base.ctx->dc_bios; int ss_info_num = bp->funcs->get_ss_entry_number( @@ -548,139 +449,263 @@ static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) } } -static bool dce_apply_clock_voltage_request( - struct display_clock *clk, - enum dm_pp_clock_type clocks_type, - int clocks_in_khz, - bool pre_mode_set, - bool update_dp_phyclk) +static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) +{ + return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); +} + +static void dce12_update_clocks(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) { - bool send_request = false; struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - case DM_PP_CLOCK_TYPE_PIXELCLK: - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - break; - default: - BREAK_TO_DEBUGGER(); - return false; + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; + clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } - clock_voltage_req.clk_type = clocks_type; - clock_voltage_req.clocks_in_khz = clocks_in_khz; - - /* to pplib */ - if (pre_mode_set) { - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (clocks_in_khz > clk->cur_clocks_value.dispclk_in_khz) { - clk->cur_clocks_value.dispclk_notify_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.dispclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.dispclk_in_khz = clocks_in_khz; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - if (clocks_in_khz > clk->cur_clocks_value.max_pixelclk_in_khz) { - clk->cur_clocks_value.pixelclk_notify_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.pixelclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.max_pixelclk_in_khz = clocks_in_khz; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (clocks_in_khz > clk->cur_clocks_value.max_non_dp_phyclk_in_khz) { - clk->cur_clocks_value.phyclk_notigy_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.phyclk_notigy_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.max_non_dp_phyclk_in_khz = clocks_in_khz; - break; - default: - ASSERT(0); - break; - } + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; + clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + } +} + +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) +{ + bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; + bool dispclk_increase = new_clocks->dispclk_khz > dccg->clks.dispclk_khz; + int disp_clk_threshold = new_clocks->max_supported_dppclk_khz; + bool cur_dpp_div = dccg->clks.dispclk_khz > dccg->clks.dppclk_khz; + + /* increase clock, looking for div is 0 for current, request div is 1*/ + if (dispclk_increase) { + /* already divided by 2, no need to reach target clk with 2 steps*/ + if (cur_dpp_div) + return new_clocks->dispclk_khz; + + /* request disp clk is lower than maximum supported dpp clk, + * no need to reach target clk with two steps. + */ + if (new_clocks->dispclk_khz <= disp_clk_threshold) + return new_clocks->dispclk_khz; + + /* target dpp clk not request divided by 2, still within threshold */ + if (!request_dpp_div) + return new_clocks->dispclk_khz; } else { - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (!clk->cur_clocks_value.dispclk_notify_pplib_done) - send_request = true; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - if (!clk->cur_clocks_value.pixelclk_notify_pplib_done) - send_request = true; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (!clk->cur_clocks_value.phyclk_notigy_pplib_done) - send_request = true; - break; - default: - ASSERT(0); - break; - } + /* decrease clock, looking for current dppclk divided by 2, + * request dppclk not divided by 2. + */ + + /* current dpp clk not divided by 2, no need to ramp*/ + if (!cur_dpp_div) + return new_clocks->dispclk_khz; + + /* current disp clk is lower than current maximum dpp clk, + * no need to ramp + */ + if (dccg->clks.dispclk_khz <= disp_clk_threshold) + return new_clocks->dispclk_khz; + + /* request dpp clk need to be divided by 2 */ + if (request_dpp_div) + return new_clocks->dispclk_khz; } - if (send_request) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (clk->ctx->dce_version >= DCN_VERSION_1_0) { - struct dc *core_dc = clk->ctx->dc; - /*use dcfclk request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = - dcn_find_dcfclk_suits_all(core_dc, &clk->cur_clocks_value); - } + + return disp_clk_threshold; +} + +static void dcn1_ramp_up_dispclk_with_dpp(struct dccg *dccg, struct dc_clocks *new_clocks) +{ + struct dc *dc = dccg->ctx->dc; + int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(dccg, new_clocks); + bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; + int i; + + /* set disp clk to dpp clk threshold */ + dccg->funcs->set_dispclk(dccg, dispclk_to_dpp_threshold); + + /* update request dpp clk division option */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state) + continue; + + pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( + pipe_ctx->plane_res.dpp, + request_dpp_div, + true); + } + + /* If target clk not same as dppclk threshold, set to target clock */ + if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz) + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + dccg->clks.dppclk_khz = new_clocks->dppclk_khz; + dccg->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz; +} + +static void dcn1_update_clocks(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) +{ + struct dc *dc = dccg->ctx->dc; + struct pp_smu_display_requirement_rv *smu_req_cur = + &dc->res_pool->pp_smu_req; + struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; + struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; + struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; + bool send_request_to_increase = false; + bool send_request_to_lower = false; + + if (new_clocks->phyclk_khz) + smu_req.display_count = 1; + else + smu_req.display_count = 0; + + if (new_clocks->dispclk_khz > dccg->clks.dispclk_khz + || new_clocks->phyclk_khz > dccg->clks.phyclk_khz + || new_clocks->fclk_khz > dccg->clks.fclk_khz + || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) + send_request_to_increase = true; + + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; + + send_request_to_lower = true; + } + + if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, dccg->clks.fclk_khz)) { + dccg->clks.fclk_khz = new_clocks->fclk_khz; + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK; + clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz; + smu_req.hard_min_fclk_khz = new_clocks->fclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + send_request_to_lower = true; + } + + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) { + dccg->clks.dcfclk_khz = new_clocks->dcfclk_khz; + smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz; + + send_request_to_lower = true; + } + + if (should_set_clock(safe_to_lower, + new_clocks->dcfclk_deep_sleep_khz, dccg->clks.dcfclk_deep_sleep_khz)) { + dccg->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; + smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz; + + send_request_to_lower = true; + } + + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ + if (send_request_to_increase) { + /*use dcfclk to request voltage*/ + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; + clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + } + + /* dcn1 dppclk is tied to dispclk */ + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + send_request_to_lower = true; + } + + if (!send_request_to_increase && send_request_to_lower) { + /*use dcfclk to request voltage*/ + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; + clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + } + + + *smu_req_cur = smu_req; +} #endif - dm_pp_apply_clock_for_voltage_request( - clk->ctx, &clock_voltage_req); + +static void dce_update_clocks(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) +{ + struct dm_pp_power_level_change_request level_change_req; + + level_change_req.power_level = dce_get_required_clocks_state(dccg, new_clocks); + /* get max clock state from PPLIB */ + if ((level_change_req.power_level < dccg->cur_min_clks_state && safe_to_lower) + || level_change_req.power_level > dccg->cur_min_clks_state) { + if (dm_pp_apply_power_level_change_request(dccg->ctx, &level_change_req)) + dccg->cur_min_clks_state = level_change_req.power_level; } - if (update_dp_phyclk && (clocks_in_khz > - clk->cur_clocks_value.max_dp_phyclk_in_khz)) - clk->cur_clocks_value.max_dp_phyclk_in_khz = clocks_in_khz; - return true; + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + } } +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +static const struct display_clock_funcs dcn1_funcs = { + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .set_dispclk = dce112_set_clock, + .update_clocks = dcn1_update_clocks +}; +#endif static const struct display_clock_funcs dce120_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, - .apply_clock_voltage_request = dce_apply_clock_voltage_request, - .set_clock = dce112_set_clock + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .set_dispclk = dce112_set_clock, + .update_clocks = dce12_update_clocks }; static const struct display_clock_funcs dce112_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce112_set_clock + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, + .set_dispclk = dce112_set_clock, + .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce110_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce_psr_set_clock + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, + .set_dispclk = dce_psr_set_clock, + .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce_set_clock + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, + .set_dispclk = dce_set_clock, + .update_clocks = dce_update_clocks }; -static void dce_disp_clk_construct( - struct dce_disp_clk *clk_dce, +static void dce_dccg_construct( + struct dce_dccg *clk_dce, struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct display_clock *base = &clk_dce->base; + struct dccg *base = &clk_dce->base; base->ctx = ctx; base->funcs = &dce_funcs; @@ -700,34 +725,15 @@ static void dce_disp_clk_construct( dce_clock_read_integrated_info(clk_dce); dce_clock_read_ss_info(clk_dce); - - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_01], - DIVIDER_RANGE_01_START, - DIVIDER_RANGE_01_STEP_SIZE, - DIVIDER_RANGE_01_BASE_DIVIDER_ID, - DIVIDER_RANGE_02_BASE_DIVIDER_ID); - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_02], - DIVIDER_RANGE_02_START, - DIVIDER_RANGE_02_STEP_SIZE, - DIVIDER_RANGE_02_BASE_DIVIDER_ID, - DIVIDER_RANGE_03_BASE_DIVIDER_ID); - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_03], - DIVIDER_RANGE_03_START, - DIVIDER_RANGE_03_STEP_SIZE, - DIVIDER_RANGE_03_BASE_DIVIDER_ID, - DIVIDER_RANGE_MAX_DIVIDER_ID); } -struct display_clock *dce_disp_clk_create( +struct dccg *dce_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -738,19 +744,19 @@ struct display_clock *dce_disp_clk_create( dce80_max_clks_by_state, sizeof(dce80_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); return &clk_dce->base; } -struct display_clock *dce110_disp_clk_create( +struct dccg *dce110_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -761,7 +767,7 @@ struct display_clock *dce110_disp_clk_create( dce110_max_clks_by_state, sizeof(dce110_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); clk_dce->base.funcs = &dce110_funcs; @@ -769,13 +775,13 @@ struct display_clock *dce110_disp_clk_create( return &clk_dce->base; } -struct display_clock *dce112_disp_clk_create( +struct dccg *dce112_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -786,7 +792,7 @@ struct display_clock *dce112_disp_clk_create( dce112_max_clks_by_state, sizeof(dce112_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); clk_dce->base.funcs = &dce112_funcs; @@ -794,10 +800,9 @@ struct display_clock *dce112_disp_clk_create( return &clk_dce->base; } -struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) +struct dccg *dce120_dccg_create(struct dc_context *ctx) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); - struct dm_pp_clock_levels_with_voltage clk_level_info = {0}; + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -808,28 +813,59 @@ struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) dce120_max_clks_by_state, sizeof(dce120_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, NULL, NULL, NULL); clk_dce->base.funcs = &dce120_funcs; - /* new in dce120 */ - if (!ctx->dc->debug.disable_pplib_clock_request && - dm_pp_get_clock_levels_by_type_with_voltage( - ctx, DM_PP_CLOCK_TYPE_DISPLAY_CLK, &clk_level_info) - && clk_level_info.num_levels) - clk_dce->max_displ_clk_in_khz = - clk_level_info.data[clk_level_info.num_levels - 1].clocks_in_khz; - else - clk_dce->max_displ_clk_in_khz = 1133000; + return &clk_dce->base; +} + +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +struct dccg *dcn1_dccg_create(struct dc_context *ctx) +{ + struct dc_debug *debug = &ctx->dc->debug; + struct dc_bios *bp = ctx->dc_bios; + struct dc_firmware_info fw_info = { { 0 } }; + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + + if (clk_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + clk_dce->base.ctx = ctx; + clk_dce->base.funcs = &dcn1_funcs; + + clk_dce->dfs_bypass_disp_clk = 0; + + clk_dce->dprefclk_ss_percentage = 0; + clk_dce->dprefclk_ss_divider = 1000; + clk_dce->ss_on_dprefclk = false; + + if (bp->integrated_info) + clk_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; + if (clk_dce->dentist_vco_freq_khz == 0) { + bp->funcs->get_firmware_info(bp, &fw_info); + clk_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq; + if (clk_dce->dentist_vco_freq_khz == 0) + clk_dce->dentist_vco_freq_khz = 3600000; + } + + if (!debug->disable_dfs_bypass && bp->integrated_info) + if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) + clk_dce->dfs_bypass_enabled = true; + + dce_clock_read_ss_info(clk_dce); return &clk_dce->base; } +#endif -void dce_disp_clk_destroy(struct display_clock **disp_clk) +void dce_dccg_destroy(struct dccg **dccg) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(*disp_clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(*dccg); kfree(clk_dce); - *disp_clk = NULL; + *dccg = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 0e717e0dc8f02..7ce0a54e548f4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -33,6 +33,9 @@ .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \ .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL +#define CLK_COMMON_REG_LIST_DCN_BASE() \ + SR(DENTIST_DISPCLK_CNTL) + #define CLK_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -40,58 +43,41 @@ CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh) +#define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh) + #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ - type DENTIST_DPREFCLK_WDIVIDER; + type DENTIST_DPREFCLK_WDIVIDER; \ + type DENTIST_DISPCLK_WDIVIDER; \ + type DENTIST_DPPCLK_WDIVIDER; \ + type DENTIST_DISPCLK_CHG_DONE; \ + type DENTIST_DPPCLK_CHG_DONE; -struct dce_disp_clk_shift { +struct dccg_shift { CLK_REG_FIELD_LIST(uint8_t) }; -struct dce_disp_clk_mask { +struct dccg_mask { CLK_REG_FIELD_LIST(uint32_t) }; -struct dce_disp_clk_registers { +struct dccg_registers { uint32_t DPREFCLK_CNTL; uint32_t DENTIST_DISPCLK_CNTL; }; -/* Array identifiers and count for the divider ranges.*/ -enum dce_divider_range_count { - DIVIDER_RANGE_01 = 0, - DIVIDER_RANGE_02, - DIVIDER_RANGE_03, - DIVIDER_RANGE_MAX /* == 3*/ -}; - -enum dce_divider_error_types { - INVALID_DID = 0, - INVALID_DIVIDER = 1 -}; - -struct dce_divider_range { - int div_range_start; - /* The end of this range of dividers.*/ - int div_range_end; - /* The distance between each divider in this range.*/ - int div_range_step; - /* The divider id for the lowest divider.*/ - int did_min; - /* The divider id for the highest divider.*/ - int did_max; -}; - -struct dce_disp_clk { - struct display_clock base; - const struct dce_disp_clk_registers *regs; - const struct dce_disp_clk_shift *clk_shift; - const struct dce_disp_clk_mask *clk_mask; +struct dce_dccg { + struct dccg base; + const struct dccg_registers *regs; + const struct dccg_shift *clk_shift; + const struct dccg_mask *clk_mask; struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; - struct dce_divider_range divider_ranges[DIVIDER_RANGE_MAX]; - bool use_max_disp_clk; int dentist_vco_freq_khz; /* Cache the status of DFS-bypass feature*/ @@ -106,32 +92,33 @@ struct dce_disp_clk { int dprefclk_ss_percentage; /* DPREFCLK SS percentage Divider (100 or 1000) */ int dprefclk_ss_divider; - - /* max disp_clk from PPLIB for max validation display clock*/ - int max_displ_clk_in_khz; }; -struct display_clock *dce_disp_clk_create( +struct dccg *dce_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); -struct display_clock *dce110_disp_clk_create( +struct dccg *dce110_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); -struct display_clock *dce112_disp_clk_create( +struct dccg *dce112_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); + +struct dccg *dce120_dccg_create(struct dc_context *ctx); -struct display_clock *dce120_disp_clk_create(struct dc_context *ctx); +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +struct dccg *dcn1_dccg_create(struct dc_context *ctx); +#endif -void dce_disp_clk_destroy(struct display_clock **disp_clk); +void dce_dccg_destroy(struct dccg **dccg); #endif /* _DCE_CLOCKS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 057b8afd74bcc..0574078926184 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -249,7 +249,6 @@ struct dce_hwseq_registers { uint32_t DISPCLK_FREQ_CHANGE_CNTL; uint32_t RBBMIF_TIMEOUT_DIS; uint32_t RBBMIF_TIMEOUT_DIS_2; - uint32_t DENTIST_DISPCLK_CNTL; uint32_t DCHUBBUB_CRC_CTRL; uint32_t DPP_TOP0_DPP_CRC_CTRL; uint32_t DPP_TOP0_DPP_CRC_VAL_R_G; @@ -496,8 +495,6 @@ struct dce_hwseq_registers { type DOMAIN7_PGFSM_PWR_STATUS; \ type DCFCLK_GATE_DIS; \ type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ - type DENTIST_DPPCLK_WDIVIDER; \ - type DENTIST_DISPCLK_WDIVIDER; \ type VGA_TEST_ENABLE; \ type VGA_TEST_RENDER_START; \ type D1VGA_MODE_ENABLE; \ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index 41f83ecd7469b..ec3221333011b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -125,17 +125,54 @@ static void dce100_pplib_apply_display_requirements( dc->prev_display_config = *pp_display_cfg; } +/* unit: in_khz before mode set, get pixel clock from context. ASIC register + * may not be programmed yet + */ +static uint32_t get_max_pixel_clock_for_all_paths( + struct dc *dc, + struct dc_state *context) +{ + uint32_t max_pix_clk = 0; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + /* do not check under lay */ + if (pipe_ctx->top_pipe) + continue; + + if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk) + max_pix_clk = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; + } + + if (max_pix_clk == 0) + ASSERT(0); + + return max_pix_clk; +} + void dce100_set_bandwidth( struct dc *dc, struct dc_state *context, bool decrease_allowed) { - if (decrease_allowed || context->bw.dce.dispclk_khz > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - dc->current_state->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz; - } + struct dc_clocks req_clks; + + req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); + + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &req_clks, + decrease_allowed); + dce100_pplib_apply_display_requirements(dc, context); } diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 38ec0d609297f..8ed8eace42be5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -135,15 +135,15 @@ static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -644,8 +644,8 @@ static void destruct(struct dce110_resource_pool *pool) dce_aud_destroy(&pool->base.audios[i]); } - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.abm != NULL) dce_abm_destroy(&pool->base.abm); @@ -817,11 +817,11 @@ static bool construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -851,7 +851,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { struct irq_service_init_data init_data; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index df027013e50c4..1f7f25013217d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -143,7 +143,7 @@ static void wait_for_fbc_state_changed( struct dce110_compressor *cp110, bool enabled) { - uint16_t counter = 0; + uint32_t counter = 0; uint32_t addr = mmFBC_STATUS; uint32_t value; @@ -158,7 +158,7 @@ static void wait_for_fbc_state_changed( counter++; } - if (counter == 10) { + if (counter == 1000) { DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", __func__); } else { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 353ffcbdf5ba6..9cbd5036db079 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1475,7 +1475,7 @@ static void power_down_controllers(struct dc *dc) { int i; - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { dc->res_pool->timing_generators[i]->funcs->disable_crtc( dc->res_pool->timing_generators[i]); } @@ -1515,12 +1515,13 @@ static void disable_vga_and_power_gate_all_controllers( struct timing_generator *tg; struct dc_context *ctx = dc->ctx; - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { tg = dc->res_pool->timing_generators[i]; if (tg->funcs->disable_vga) tg->funcs->disable_vga(tg); - + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { /* Enable CLOCK gating for each pipe BEFORE controller * powergating. */ enable_display_pipe_clock_gating(ctx, @@ -1663,7 +1664,7 @@ static void dce110_set_displaymarks( } } -static void set_safe_displaymarks( +void dce110_set_safe_displaymarks( struct resource_context *res_ctx, const struct resource_pool *pool) { @@ -1755,23 +1756,15 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, } /* unit: in_khz before mode set, get pixel clock from context. ASIC register - * may not be programmed yet. - * TODO: after mode set, pre_mode_set = false, - * may read PLL register to get pixel clock + * may not be programmed yet */ static uint32_t get_max_pixel_clock_for_all_paths( struct dc *dc, - struct dc_state *context, - bool pre_mode_set) + struct dc_state *context) { uint32_t max_pix_clk = 0; int i; - if (!pre_mode_set) { - /* TODO: read ASIC register to get pixel clock */ - ASSERT(0); - } - for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -1787,95 +1780,10 @@ static uint32_t get_max_pixel_clock_for_all_paths( pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; } - if (max_pix_clk == 0) - ASSERT(0); - return max_pix_clk; } /* - * Find clock state based on clock requested. if clock value is 0, simply - * set clock state as requested without finding clock state by clock value - */ - -static void apply_min_clocks( - struct dc *dc, - struct dc_state *context, - enum dm_pp_clocks_state *clocks_state, - bool pre_mode_set) -{ - struct state_dependent_clocks req_clocks = {0}; - - if (!pre_mode_set) { - /* set clock_state without verification */ - if (context->dis_clk->funcs->set_min_clocks_state) { - context->dis_clk->funcs->set_min_clocks_state( - context->dis_clk, *clocks_state); - return; - } - - /* TODO: This is incorrect. Figure out how to fix. */ - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - context->dis_clk->cur_clocks_value.dispclk_in_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_PIXELCLK, - context->dis_clk->cur_clocks_value.max_pixelclk_in_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - context->dis_clk->cur_clocks_value.max_non_dp_phyclk_in_khz, - pre_mode_set, - false); - return; - } - - /* get the required state based on state dependent clocks: - * display clock and pixel clock - */ - req_clocks.display_clk_khz = context->bw.dce.dispclk_khz; - - req_clocks.pixel_clk_khz = get_max_pixel_clock_for_all_paths( - dc, context, true); - - if (context->dis_clk->funcs->get_required_clocks_state) { - *clocks_state = context->dis_clk->funcs->get_required_clocks_state( - context->dis_clk, &req_clocks); - context->dis_clk->funcs->set_min_clocks_state( - context->dis_clk, *clocks_state); - } else { - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - req_clocks.display_clk_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_PIXELCLK, - req_clocks.pixel_clk_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - req_clocks.pixel_clk_khz, - pre_mode_set, - false); - } -} - -/* * Check if FBC can be enabled */ static bool should_enable_fbc(struct dc *dc, @@ -2093,7 +2001,6 @@ enum dc_status dce110_apply_ctx_to_hw( struct dc_bios *dcb = dc->ctx->dc_bios; enum dc_status status; int i; - enum dm_pp_clocks_state clocks_state = DM_PP_CLOCKS_STATE_INVALID; /* Reset old context */ /* look up the targets that have been removed since last commit */ @@ -2127,55 +2034,9 @@ enum dc_status dce110_apply_ctx_to_hw( PIPE_GATING_CONTROL_DISABLE); } - set_safe_displaymarks(&context->res_ctx, dc->res_pool); - if (dc->fbc_compressor) dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - /*TODO: when pplib works*/ - apply_min_clocks(dc, context, &clocks_state, true); - -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (dc->ctx->dce_version >= DCN_VERSION_1_0) { - if (context->bw.dcn.calc_clk.fclk_khz - > dc->current_state->bw.dcn.cur_clk.fclk_khz) { - struct dm_pp_clock_for_voltage_req clock; - - clock.clk_type = DM_PP_CLOCK_TYPE_FCLK; - clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz; - dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock); - dc->current_state->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz; - context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz; - } - if (context->bw.dcn.calc_clk.dcfclk_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { - struct dm_pp_clock_for_voltage_req clock; - - clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz; - dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock); - dc->current_state->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz; - context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz; - } - if (context->bw.dcn.calc_clk.dispclk_khz - > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - dc->current_state->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - } - } else -#endif - if (context->bw.dce.dispclk_khz - > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - } - dce110_setup_audio_dto(dc, context); for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -2204,9 +2065,6 @@ enum dc_status dce110_apply_ctx_to_hw( return status; } - /* to save power */ - apply_min_clocks(dc, context, &clocks_state, false); - dcb->funcs->set_scratch_critical_state(dcb, false); if (dc->fbc_compressor) @@ -2694,15 +2552,20 @@ static void dce110_set_bandwidth( struct dc_state *context, bool decrease_allowed) { - dce110_set_displaymarks(dc, context); + struct dc_clocks req_clks; - if (decrease_allowed || context->bw.dce.dispclk_khz > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - dc->current_state->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz; - } + req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); + + if (decrease_allowed) + dce110_set_displaymarks(dc, context); + else + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &req_clks, + decrease_allowed); pplib_apply_display_requirements(dc, context); } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index f48d5a68d2386..d6db3dbd90153 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -60,6 +60,10 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); void dce110_power_down(struct dc *dc); +void dce110_set_safe_displaymarks( + struct resource_context *res_ctx, + const struct resource_pool *pool); + void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 20c0290895515..3edaa006bd576 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -146,15 +146,15 @@ static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { #define SRI(reg_name, block, id)\ .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -679,8 +679,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -1179,11 +1179,11 @@ static bool construct( } } - pool->base.display_clock = dce110_disp_clk_create(ctx, + pool->base.dccg = dce110_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1213,7 +1213,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 00c0a1ef15ebd..9e1afb11e6ad0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -146,15 +146,15 @@ static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -668,8 +668,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -1000,7 +1000,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -1010,7 +1010,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -1020,7 +1020,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; @@ -1030,7 +1030,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; @@ -1124,11 +1124,11 @@ static bool construct( } } - pool->base.display_clock = dce112_disp_clk_create(ctx, + pool->base.dccg = dce112_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1158,7 +1158,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 2d58daccc0056..8381f27a23612 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -494,8 +494,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); } static void read_dce_straps( @@ -775,7 +775,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -785,7 +785,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -795,7 +795,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; @@ -805,7 +805,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; @@ -894,11 +894,11 @@ static bool construct( } } - pool->base.display_clock = dce120_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { + pool->base.dccg = dce120_dccg_create(ctx); + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); - goto disp_clk_create_fail; + goto dccg_create_fail; } pool->base.dmcu = dce_dmcu_create(ctx, @@ -1011,7 +1011,7 @@ static bool construct( irqs_create_fail: controller_create_fail: -disp_clk_create_fail: +dccg_create_fail: clk_src_create_fail: res_create_fail: diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 48a0689647225..2ac95ec2bf963 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -153,15 +153,15 @@ static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; @@ -683,8 +683,8 @@ static void destruct(struct dce110_resource_pool *pool) } } - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -822,11 +822,11 @@ static bool dce80_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -852,7 +852,7 @@ static bool dce80_construct( goto res_create_fail; } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { @@ -1006,11 +1006,11 @@ static bool dce81_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1037,7 +1037,7 @@ static bool dce81_construct( } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { @@ -1187,11 +1187,11 @@ static bool dce83_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1218,7 +1218,7 @@ static bool dce83_construct( } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index c69fa4bfab0af..742fd497ed006 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -145,10 +145,10 @@ static bool dpp_get_optimal_number_of_taps( pixel_width = scl_data->viewport.width; /* Some ASICs does not support FP16 scaling, so we reject modes require this*/ - if (scl_data->viewport.width != scl_data->h_active && - scl_data->viewport.height != scl_data->v_active && + if (scl_data->format == PIXEL_FORMAT_FP16 && dpp->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT && - scl_data->format == PIXEL_FORMAT_FP16) + scl_data->ratios.horz.value != dc_fixpt_one.value && + scl_data->ratios.vert.value != dc_fixpt_one.value) return false; if (scl_data->viewport.width > scl_data->h_active && diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index 943143efbb823..1ea91e153d3a6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -190,10 +190,17 @@ static uint32_t convert_and_clamp( } +void hubbub1_wm_change_req_wa(struct hubbub *hubbub) +{ + REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1); +} + void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, - unsigned int refclk_mhz) + unsigned int refclk_mhz, + bool safe_to_lower) { uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0; /* @@ -202,191 +209,259 @@ void hubbub1_program_watermarks( */ uint32_t prog_wm_value; - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, - DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0); /* Repeat for water mark set A, B, C and D. */ /* clock state A */ - prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) { + hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.pte_meta_urgent_ns, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) { + hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->a.pte_meta_urgent_ns, prog_wm_value); + } + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.a.cstate_pstate.cstate_exit_ns = + watermarks->a.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns + > hubbub->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.a.cstate_pstate.pstate_change_ns = + watermarks->a.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_exit_ns, + watermarks->a.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); - - /* clock state B */ - prog_wm_value = convert_and_clamp( - watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.urgent_ns, prog_wm_value); - - - prog_wm_value = convert_and_clamp( - watermarks->b.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) { + hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) { + hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_B calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->b.pte_meta_urgent_ns, prog_wm_value); + } + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.b.cstate_pstate.cstate_exit_ns = + watermarks->b.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns + > hubbub->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.b.cstate_pstate.pstate_change_ns = + watermarks->b.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_exit_ns, + watermarks->b.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); - /* clock state C */ - prog_wm_value = convert_and_clamp( - watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.urgent_ns, prog_wm_value); - - - prog_wm_value = convert_and_clamp( - watermarks->c.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) { + hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) { + hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_C calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->c.pte_meta_urgent_ns, prog_wm_value); + } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.c.cstate_pstate.cstate_exit_ns = + watermarks->c.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns + > hubbub->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.c.cstate_pstate.pstate_change_ns = + watermarks->c.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_exit_ns, + watermarks->c.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); - /* clock state D */ - prog_wm_value = convert_and_clamp( - watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.urgent_ns, prog_wm_value); - - prog_wm_value = convert_and_clamp( - watermarks->d.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.pte_meta_urgent_ns, prog_wm_value); - - - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) { + hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.urgent_ns, prog_wm_value); + } - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_exit_ns, + if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) { + hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + watermarks->d.pte_meta_urgent_ns, prog_wm_value); } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.d.cstate_pstate.cstate_exit_ns = + watermarks->d.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, - DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); + if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns + > hubbub->watermarks.d.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.d.cstate_pstate.pstate_change_ns = + watermarks->d.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + } REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); @@ -408,6 +483,11 @@ void hubbub1_update_dchub( struct hubbub *hubbub, struct dchub_init_data *dh_data) { + if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { + ASSERT(false); + /*should not come here*/ + return; + } /* TODO: port code from dal2 */ switch (dh_data->fb_mode) { case FRAME_BUFFER_MODE_ZFB_ONLY: diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 6315a0e6b0d69..d6e596eef4c55 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -185,6 +185,7 @@ struct hubbub { const struct dcn_hubbub_shift *shifts; const struct dcn_hubbub_mask *masks; unsigned int debug_test_index_pstate; + struct dcn_watermark_set watermarks; }; void hubbub1_update_dchub( @@ -194,10 +195,13 @@ void hubbub1_update_dchub( bool hubbub1_verify_allow_pstate_change_high( struct hubbub *hubbub); +void hubbub1_wm_change_req_wa(struct hubbub *hubbub); + void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, - unsigned int refclk_mhz); + unsigned int refclk_mhz, + bool safe_to_lower); void hubbub1_toggle_watermark_change_req( struct hubbub *hubbub); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index c28085be39ff9..93f52c58bc695 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -166,7 +166,7 @@ void hubp1_program_size_and_rotation( /* Program data and meta surface pitch (calculation from addrlib) * 444 or 420 luma */ - if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) { ASSERT(plane_size->video.chroma_pitch != 0); /* Chroma pitch zero can cause system hang! */ 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 03eb736a312ff..3b2cb2d3b8a61 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 @@ -337,13 +337,13 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", - dc->current_state->bw.dcn.calc_clk.dcfclk_khz, - dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - dc->current_state->bw.dcn.calc_clk.dispclk_khz, - dc->current_state->bw.dcn.calc_clk.dppclk_khz, - dc->current_state->bw.dcn.calc_clk.max_supported_dppclk_khz, - dc->current_state->bw.dcn.calc_clk.fclk_khz, - dc->current_state->bw.dcn.calc_clk.socclk_khz); + dc->current_state->bw.dcn.clk.dcfclk_khz, + dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz, + dc->current_state->bw.dcn.clk.dispclk_khz, + dc->current_state->bw.dcn.clk.dppclk_khz, + dc->current_state->bw.dcn.clk.max_supported_dppclk_khz, + dc->current_state->bw.dcn.clk.fclk_khz, + dc->current_state->bw.dcn.clk.socclk_khz); log_mpc_crc(dc); @@ -415,6 +415,8 @@ static void dpp_pg_control( if (hws->ctx->dc->debug.disable_dpp_power_gate) return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; switch (dpp_inst) { case 0: /* DPP0 */ @@ -465,6 +467,8 @@ static void hubp_pg_control( if (hws->ctx->dc->debug.disable_hubp_power_gate) return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; switch (hubp_inst) { case 0: /* DCHUBP0 */ @@ -865,7 +869,8 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) return; mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + if (opp != NULL) + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; dc->optimized_required = true; @@ -1010,7 +1015,7 @@ static void dcn10_init_hw(struct dc *dc) /* Reset all MPCC muxes */ dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; @@ -1343,10 +1348,11 @@ static void dcn10_enable_per_frame_crtc_position_reset( DC_SYNC_INFO("Setting up\n"); for (i = 0; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( - grouped_pipes[i]->stream_res.tg, - grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, - &grouped_pipes[i]->stream->triggered_crtc_reset); + if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) + grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( + grouped_pipes[i]->stream_res.tg, + grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, + &grouped_pipes[i]->stream->triggered_crtc_reset); DC_SYNC_INFO("Waiting for trigger\n"); @@ -1952,18 +1958,17 @@ static void update_dchubp_dpp( * divided by 2 */ if (plane_state->update_flags.bits.full_update) { - bool should_divided_by_2 = context->bw.dcn.calc_clk.dppclk_khz <= - context->bw.dcn.cur_clk.dispclk_khz / 2; + bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <= + dc->res_pool->dccg->clks.dispclk_khz / 2; dpp->funcs->dpp_dppclk_control( dpp, should_divided_by_2, true); - dc->current_state->bw.dcn.cur_clk.dppclk_khz = - should_divided_by_2 ? - context->bw.dcn.cur_clk.dispclk_khz / 2 : - context->bw.dcn.cur_clk.dispclk_khz; + dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ? + dc->res_pool->dccg->clks.dispclk_khz / 2 : + dc->res_pool->dccg->clks.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -2153,12 +2158,12 @@ static void dcn10_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; - pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; - pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; - pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; + pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz; + pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz; + pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz; + pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof( @@ -2220,8 +2225,6 @@ static void dcn10_apply_ctx_for_surface( int i; struct timing_generator *tg; bool removed_pipe[4] = { false }; - unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; - bool program_water_mark = false; struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); DC_LOGGER_INIT(dc->ctx->logger); @@ -2269,8 +2272,7 @@ static void dcn10_apply_ctx_for_surface( hwss1_plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; - DC_LOG_DC( - "Reset mpcc for pipe %d\n", + DC_LOG_DC("Reset mpcc for pipe %d\n", old_pipe_ctx->pipe_idx); } } @@ -2283,248 +2285,41 @@ static void dcn10_apply_ctx_for_surface( if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *old_pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == stream && - pipe_ctx->plane_state && - pipe_ctx->plane_state->update_flags.bits.full_update) - program_water_mark = true; - + for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) - dcn10_disable_plane(dc, old_pipe_ctx); - } - - if (program_water_mark) { - if (dc->debug.sanity_checks) { - /* pstate stuck check after watermark update */ - dcn10_verify_allow_pstate_change_high(dc); - } + dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - /* watermark is for all pipes */ - hubbub1_program_watermarks(dc->res_pool->hubbub, - &context->bw.dcn.watermarks, ref_clk_mhz); - - if (dc->debug.sanity_checks) { - /* pstate stuck check after watermark update */ - dcn10_verify_allow_pstate_change_high(dc); - } - } -/* DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\n============== Watermark parameters ==============\n" - "a.urgent_ns: %d \n" - "a.cstate_enter_plus_exit: %d \n" - "a.cstate_exit: %d \n" - "a.pstate_change: %d \n" - "a.pte_meta_urgent: %d \n" - "b.urgent_ns: %d \n" - "b.cstate_enter_plus_exit: %d \n" - "b.cstate_exit: %d \n" - "b.pstate_change: %d \n" - "b.pte_meta_urgent: %d \n", - context->bw.dcn.watermarks.a.urgent_ns, - context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.a.pte_meta_urgent_ns, - context->bw.dcn.watermarks.b.urgent_ns, - context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.b.pte_meta_urgent_ns - ); - DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\nc.urgent_ns: %d \n" - "c.cstate_enter_plus_exit: %d \n" - "c.cstate_exit: %d \n" - "c.pstate_change: %d \n" - "c.pte_meta_urgent: %d \n" - "d.urgent_ns: %d \n" - "d.cstate_enter_plus_exit: %d \n" - "d.cstate_exit: %d \n" - "d.pstate_change: %d \n" - "d.pte_meta_urgent: %d \n" - "========================================================\n", - context->bw.dcn.watermarks.c.urgent_ns, - context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.c.pte_meta_urgent_ns, - context->bw.dcn.watermarks.d.urgent_ns, - context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.d.pte_meta_urgent_ns - ); -*/ -} - -static inline bool should_set_clock(bool decrease_allowed, int calc_clk, int cur_clk) -{ - return ((decrease_allowed && calc_clk < cur_clk) || calc_clk > cur_clk); -} - -static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) -{ - bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.calc_clk.dppclk_khz; - bool dispclk_increase = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.cur_clk.dispclk_khz; - int disp_clk_threshold = context->bw.dcn.calc_clk.max_supported_dppclk_khz; - bool cur_dpp_div = context->bw.dcn.cur_clk.dispclk_khz > - context->bw.dcn.cur_clk.dppclk_khz; - - /* increase clock, looking for div is 0 for current, request div is 1*/ - if (dispclk_increase) { - /* already divided by 2, no need to reach target clk with 2 steps*/ - if (cur_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* request disp clk is lower than maximum supported dpp clk, - * no need to reach target clk with two steps. - */ - if (context->bw.dcn.calc_clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* target dpp clk not request divided by 2, still within threshold */ - if (!request_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - - } else { - /* decrease clock, looking for current dppclk divided by 2, - * request dppclk not divided by 2. - */ - - /* current dpp clk not divided by 2, no need to ramp*/ - if (!cur_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* current disp clk is lower than current maximum dpp clk, - * no need to ramp - */ - if (context->bw.dcn.cur_clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.calc_clk.dispclk_khz; - - /* request dpp clk need to be divided by 2 */ - if (request_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; - } - - return disp_clk_threshold; -} - -static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) -{ - int i; - bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.calc_clk.dppclk_khz; - - int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); - - /* set disp clk to dpp clk threshold */ - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - dispclk_to_dpp_threshold); - - /* update request dpp clk division option */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->plane_state) - continue; - - pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( - pipe_ctx->plane_res.dpp, - request_dpp_div, - true); - } - - /* If target clk not same as dppclk threshold, set to target clock */ - if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - } - - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - context->bw.dcn.cur_clk.dppclk_khz = - context->bw.dcn.calc_clk.dppclk_khz; - context->bw.dcn.cur_clk.max_supported_dppclk_khz = - context->bw.dcn.calc_clk.max_supported_dppclk_khz; + if (dc->hwseq->wa.DEGVIDCN10_254) + hubbub1_wm_change_req_wa(dc->res_pool->hubbub); } static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, - bool decrease_allowed) + bool safe_to_lower) { - struct pp_smu_display_requirement_rv *smu_req_cur = - &dc->res_pool->pp_smu_req; - struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; - struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; - - if (dc->debug.sanity_checks) { + if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - } - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - return; - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dcfclk_khz, - dc->current_state->bw.dcn.cur_clk.dcfclk_khz)) { - context->bw.dcn.cur_clk.dcfclk_khz = - context->bw.dcn.calc_clk.dcfclk_khz; - smu_req.hard_min_dcefclk_khz = - context->bw.dcn.calc_clk.dcfclk_khz; - } - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz)) { - context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; - } - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.fclk_khz, - dc->current_state->bw.dcn.cur_clk.fclk_khz)) { - context->bw.dcn.cur_clk.fclk_khz = - context->bw.dcn.calc_clk.fclk_khz; - smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; - } - - smu_req.display_count = context->stream_count; - - if (pp_smu->set_display_requirement) - pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); - *smu_req_cur = smu_req; + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (context->stream_count == 0) + context->bw.dcn.clk.phyclk_khz = 0; - /* make sure dcf clk is before dpp clk to - * make sure we have enough voltage to run dpp clk - */ - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dispclk_khz, - dc->current_state->bw.dcn.cur_clk.dispclk_khz)) { + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &context->bw.dcn.clk, + safe_to_lower); - ramp_up_dispclk_with_dpp(dc, context); + dcn10_pplib_apply_display_requirements(dc, context); } - dcn10_pplib_apply_display_requirements(dc, context); + hubbub1_program_watermarks(dc->res_pool->hubbub, + &context->bw.dcn.watermarks, + dc->res_pool->ref_clock_inKhz / 1000, + true); - if (dc->debug.sanity_checks) { + if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - } - - /* need to fix this function. not doing the right thing here */ } static void set_drr(struct pipe_ctx **pipe_ctx, @@ -2707,8 +2502,14 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { - if (hws->ctx->dc->res_pool->hubbub != NULL) - hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + if (hws->ctx->dc->res_pool->hubbub != NULL) { + struct hubp *hubp = hws->ctx->dc->res_pool->hubps[0]; + + if (hubp->funcs->hubp_update_dchub) + hubp->funcs->hubp_update_dchub(hubp, dh_data); + else + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + } } static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 21fa40ac0786b..fd9dc70190a88 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -995,6 +995,8 @@ void dcn10_link_encoder_disable_output( if (!dcn10_is_dig_enabled(enc)) { /* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */ + /*in DP_Alt_No_Connect case, we turn off the dig already, + after excuation the PHY w/a sequence, not allow touch PHY any more*/ return; } /* Power-down RX and disable GPU PHY should be paired. diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 2da325ce781bc..771e0cf29bbaa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -65,6 +65,68 @@ #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +const struct _vcs_dpi_ip_params_st dcn1_0_ip = { + .rob_buffer_size_kbytes = 64, + .det_buffer_size_kbytes = 164, + .dpte_buffer_size_in_pte_reqs = 42, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .pte_enable = 1, + .pte_chunk_size_kbytes = 2, + .meta_chunk_size_kbytes = 2, + .writeback_chunk_size_kbytes = 2, + .line_buffer_size_bits = 589824, + .max_line_buffer_lines = 12, + .IsLineBufferBppFixed = 0, + .LineBufferFixedBpp = -1, + .writeback_luma_buffer_size_kbytes = 12, + .writeback_chroma_buffer_size_kbytes = 8, + .max_num_dpp = 4, + .max_num_wb = 2, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 4, + .max_vscl_ratio = 4, + .hscl_mults = 4, + .vscl_mults = 4, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dispclk_ramp_margin_percent = 1, + .underscan_factor = 1.10, + .min_vblank_lines = 14, + .dppclk_delay_subtotal = 90, + .dispclk_delay_subtotal = 42, + .dcfclk_cstate_latency = 10, + .max_inter_dcn_tile_repeaters = 8, + .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0, + .bug_forcing_LC_req_same_size_fixed = 0, +}; + +const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .urgent_latency_us = 4.0, + .writeback_latency_us = 12.0, + .ideal_dram_bw_after_urgent_percent = 80.0, + .max_request_size_bytes = 256, + .downspread_percent = 0.5, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 128, + .urgent_out_of_order_return_per_channel_bytes = 256, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 2, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 17.0, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, +}; + #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 @@ -437,7 +499,7 @@ static const struct dc_debug debug_defaults_drv = { */ .min_disp_clk_khz = 100000, - .disable_pplib_clock_request = true, + .disable_pplib_clock_request = false, .disable_pplib_wm_range = false, .pplib_wm_report_mode = WM_REPORT_DEFAULT, .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, @@ -681,6 +743,7 @@ static struct dce_hwseq *dcn10_hwseq_create( hws->masks = &hwseq_mask; hws->wa.DEGVIDCN10_253 = true; hws->wa.false_optc_underflow = true; + hws->wa.DEGVIDCN10_254 = true; } return hws; } @@ -791,8 +854,8 @@ static void destruct(struct dcn10_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); kfree(pool->base.pp_smu); } @@ -1005,8 +1068,7 @@ static bool construct( ctx->dc_bios->regs = &bios_regs; - pool->base.res_cap = &res_cap; - + pool->base.res_cap = &res_cap; pool->base.funcs = &dcn10_res_pool_funcs; /* @@ -1072,8 +1134,8 @@ static bool construct( } } - pool->base.display_clock = dce120_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { + pool->base.dccg = dcn1_dccg_create(ctx); + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto fail; diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index eac4bfe122576..58ed2055ef9f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -40,7 +40,7 @@ enum wm_set_id { WM_B, WM_C, WM_D, - WM_COUNT, + WM_SET_COUNT, }; struct pp_smu_wm_set_range { @@ -53,10 +53,10 @@ struct pp_smu_wm_set_range { struct pp_smu_wm_range_sets { uint32_t num_reader_wm_sets; - struct pp_smu_wm_set_range reader_wm_sets[WM_COUNT]; + struct pp_smu_wm_set_range reader_wm_sets[WM_SET_COUNT]; uint32_t num_writer_wm_sets; - struct pp_smu_wm_set_range writer_wm_sets[WM_COUNT]; + struct pp_smu_wm_set_range writer_wm_sets[WM_SET_COUNT]; }; struct pp_smu_display_requirement_rv { diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h index ab8c77d4e6dfe..2b83f922ac026 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h @@ -137,7 +137,7 @@ struct dm_pp_clock_range_for_wm_set { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_eng_clk_in_khz; uint32_t wm_max_eng_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; @@ -150,7 +150,7 @@ struct dm_pp_clock_range_for_dmif_wm_set_soc15 { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_dcfclk_clk_in_khz; uint32_t wm_max_dcfclk_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; @@ -158,7 +158,7 @@ struct dm_pp_clock_range_for_mcif_wm_set_soc15 { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_socclk_clk_in_khz; uint32_t wm_max_socclk_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index f83a608f93e94..d97ca6528f9d9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -36,11 +36,10 @@ CFLAGS_display_mode_lib.o := $(dml_ccflags) CFLAGS_display_pipe_clocks.o := $(dml_ccflags) CFLAGS_dml1_display_rq_dlg_calc.o := $(dml_ccflags) CFLAGS_display_rq_dlg_helpers.o := $(dml_ccflags) -CFLAGS_soc_bounding_box.o := $(dml_ccflags) CFLAGS_dml_common_defs.o := $(dml_ccflags) DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ - soc_bounding_box.o dml_common_defs.o + dml_common_defs.o AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index fd9d97aab0715..dddeb0d4db8f3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -26,67 +26,8 @@ #include "display_mode_lib.h" #include "dc_features.h" -static const struct _vcs_dpi_ip_params_st dcn1_0_ip = { - .rob_buffer_size_kbytes = 64, - .det_buffer_size_kbytes = 164, - .dpte_buffer_size_in_pte_reqs = 42, - .dpp_output_buffer_pixels = 2560, - .opp_output_buffer_lines = 1, - .pixel_chunk_size_kbytes = 8, - .pte_enable = 1, - .pte_chunk_size_kbytes = 2, - .meta_chunk_size_kbytes = 2, - .writeback_chunk_size_kbytes = 2, - .line_buffer_size_bits = 589824, - .max_line_buffer_lines = 12, - .IsLineBufferBppFixed = 0, - .LineBufferFixedBpp = -1, - .writeback_luma_buffer_size_kbytes = 12, - .writeback_chroma_buffer_size_kbytes = 8, - .max_num_dpp = 4, - .max_num_wb = 2, - .max_dchub_pscl_bw_pix_per_clk = 4, - .max_pscl_lb_bw_pix_per_clk = 2, - .max_lb_vscl_bw_pix_per_clk = 4, - .max_vscl_hscl_bw_pix_per_clk = 4, - .max_hscl_ratio = 4, - .max_vscl_ratio = 4, - .hscl_mults = 4, - .vscl_mults = 4, - .max_hscl_taps = 8, - .max_vscl_taps = 8, - .dispclk_ramp_margin_percent = 1, - .underscan_factor = 1.10, - .min_vblank_lines = 14, - .dppclk_delay_subtotal = 90, - .dispclk_delay_subtotal = 42, - .dcfclk_cstate_latency = 10, - .max_inter_dcn_tile_repeaters = 8, - .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0, - .bug_forcing_LC_req_same_size_fixed = 0, -}; - -static const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { - .sr_exit_time_us = 9.0, - .sr_enter_plus_exit_time_us = 11.0, - .urgent_latency_us = 4.0, - .writeback_latency_us = 12.0, - .ideal_dram_bw_after_urgent_percent = 80.0, - .max_request_size_bytes = 256, - .downspread_percent = 0.5, - .dram_page_open_time_ns = 50.0, - .dram_rw_turnaround_time_ns = 17.5, - .dram_return_buffer_per_channel_bytes = 8192, - .round_trip_ping_latency_dcfclk_cycles = 128, - .urgent_out_of_order_return_per_channel_bytes = 256, - .channel_interleave_bytes = 256, - .num_banks = 8, - .num_chans = 2, - .vmm_page_size_bytes = 4096, - .dram_clock_change_latency_us = 17.0, - .writeback_dram_clock_change_latency_us = 23.0, - .return_bus_width_bytes = 64, -}; +extern const struct _vcs_dpi_ip_params_st dcn1_0_ip; +extern const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc; static void set_soc_bounding_box(struct _vcs_dpi_soc_bounding_box_st *soc, enum dml_project project) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index 3c2abcb8a1b0c..6352062488898 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -27,7 +27,6 @@ #include "dml_common_defs.h" -#include "soc_bounding_box.h" #include "dml1_display_rq_dlg_calc.h" enum dml_project { 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 7fa0375939aec..6943801c5fd3f 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 @@ -64,10 +64,9 @@ struct _vcs_dpi_voltage_scaling_st { double dscclk_mhz; double dcfclk_mhz; double socclk_mhz; - double dram_speed_mhz; + double dram_speed_mts; double fabricclk_mhz; double dispclk_mhz; - double dram_bw_per_chan_gbps; double phyclk_mhz; double dppclk_mhz; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c b/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c deleted file mode 100644 index 324239c779583..0000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include "soc_bounding_box.h" -#include "display_mode_lib.h" -#include "dc_features.h" - -#include "dml_inline_defs.h" - -/* - * NOTE: - * This file is gcc-parseable HW gospel, coming straight from HW engineers. - * - * It doesn't adhere to Linux kernel style and sometimes will do things in odd - * ways. Unless there is something clearly wrong with it the code should - * remain as-is as it provides us with a guarantee from HW that it is correct. - */ - -void dml_socbb_set_latencies(soc_bounding_box_st *to_box, soc_bounding_box_st *from_box) -{ - to_box->dram_clock_change_latency_us = from_box->dram_clock_change_latency_us; - to_box->sr_exit_time_us = from_box->sr_exit_time_us; - to_box->sr_enter_plus_exit_time_us = from_box->sr_enter_plus_exit_time_us; - to_box->urgent_latency_us = from_box->urgent_latency_us; - to_box->writeback_latency_us = from_box->writeback_latency_us; -} - -voltage_scaling_st dml_socbb_voltage_scaling( - const soc_bounding_box_st *soc, - enum voltage_state voltage) -{ - const voltage_scaling_st *voltage_state; - const voltage_scaling_st * const voltage_end = soc->clock_limits + DC__VOLTAGE_STATES; - - for (voltage_state = soc->clock_limits; - voltage_state < voltage_end && voltage_state->state != voltage; - voltage_state++) { - } - - if (voltage_state < voltage_end) - return *voltage_state; - return soc->clock_limits[DC__VOLTAGE_STATES - 1]; -} - -double dml_socbb_return_bw_mhz(soc_bounding_box_st *box, enum voltage_state voltage) -{ - double return_bw; - - voltage_scaling_st state = dml_socbb_voltage_scaling(box, voltage); - - return_bw = dml_min((double) box->return_bus_width_bytes * state.dcfclk_mhz, - state.dram_bw_per_chan_gbps * 1000.0 * (double) box->num_chans - * box->ideal_dram_bw_after_urgent_percent / 100.0); - - return_bw = dml_min((double) box->return_bus_width_bytes * state.fabricclk_mhz, return_bw); - - return return_bw; -} diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 4beddca0180c3..00d728e629fa6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -163,7 +163,7 @@ struct resource_pool { unsigned int audio_count; struct audio_support audio_support; - struct display_clock *display_clock; + struct dccg *dccg; struct irq_service *irqs; struct abm *abm; @@ -256,8 +256,7 @@ struct dce_bw_output { }; struct dcn_bw_output { - struct dc_clocks cur_clk; - struct dc_clocks calc_clk; + struct dc_clocks clk; struct dcn_watermark_set watermarks; }; @@ -282,7 +281,7 @@ struct dc_state { struct dcn_bw_internal_vars dcn_bw_vars; #endif - struct display_clock *dis_clk; + struct dccg *dis_clk; struct kref refcount; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h index 132d18d4b2938..ddbb673caa08e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h @@ -625,7 +625,7 @@ bool dcn_validate_bandwidth( unsigned int dcn_find_dcfclk_suits_all( const struct dc *dc, - struct clocks_value *clocks); + struct dc_clocks *clocks); void dcn_bw_update_from_pplib(struct dc *dc); void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h index f5f69cd81f6fd..3c7ccb68ecdb5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h @@ -27,23 +27,7 @@ #define __DISPLAY_CLOCK_H__ #include "dm_services_types.h" - - -struct clocks_value { - int dispclk_in_khz; - int max_pixelclk_in_khz; - int max_non_dp_phyclk_in_khz; - int max_dp_phyclk_in_khz; - bool dispclk_notify_pplib_done; - bool pixelclk_notify_pplib_done; - bool phyclk_notigy_pplib_done; - int dcfclock_in_khz; - int dppclk_in_khz; - int mclk_in_khz; - int phyclk_in_khz; - int common_vdd_level; -}; - +#include "dc.h" /* Structure containing all state-dependent clocks * (dependent on "enum clocks_state") */ @@ -52,34 +36,23 @@ struct state_dependent_clocks { int pixel_clk_khz; }; -struct display_clock { +struct dccg { struct dc_context *ctx; const struct display_clock_funcs *funcs; enum dm_pp_clocks_state max_clks_state; enum dm_pp_clocks_state cur_min_clks_state; - struct clocks_value cur_clocks_value; + struct dc_clocks clks; }; struct display_clock_funcs { - int (*set_clock)(struct display_clock *disp_clk, + void (*update_clocks)(struct dccg *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower); + int (*set_dispclk)(struct dccg *dccg, int requested_clock_khz); - enum dm_pp_clocks_state (*get_required_clocks_state)( - struct display_clock *disp_clk, - struct state_dependent_clocks *req_clocks); - - bool (*set_min_clocks_state)(struct display_clock *disp_clk, - enum dm_pp_clocks_state dm_pp_clocks_state); - - int (*get_dp_ref_clk_frequency)(struct display_clock *disp_clk); - - bool (*apply_clock_voltage_request)( - struct display_clock *disp_clk, - enum dm_pp_clock_type clocks_type, - int clocks_in_khz, - bool pre_mode_set, - bool update_dp_phyclk); + int (*get_dp_ref_clk_frequency)(struct dccg *dccg); }; #endif /* __DISPLAY_CLOCK_H__ */ 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 a71770ed4b9f6..2506601120afa 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -44,6 +44,7 @@ struct dce_hwseq_wa { bool blnd_crtc_trigger; bool DEGVIDCN10_253; bool false_optc_underflow; + bool DEGVIDCN10_254; }; struct hwseq_wa_state { @@ -171,7 +172,7 @@ struct hw_sequencer_funcs { void (*set_bandwidth)( struct dc *dc, struct dc_state *context, - bool decrease_allowed); + bool safe_to_lower); void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, int vmin, int vmax); diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index dcdfa0f015517..604bea01fc13e 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -78,7 +78,7 @@ const struct irq_source_info *find_irq_source_info( struct irq_service *irq_service, enum dc_irq_source source) { - if (source > DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) + if (source >= DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) return NULL; return &irq_service->info[source]; diff --git a/drivers/gpu/drm/amd/display/include/grph_object_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_defs.h index 2941b882b0b6b..58bb42ed85cab 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_defs.h @@ -37,6 +37,10 @@ * ******************************************************************** */ +#define MAX_CONNECTOR_NUMBER_PER_SLOT (16) +#define MAX_BOARD_SLOTS (4) +#define INVALID_CONNECTOR_INDEX ((unsigned int)(-1)) + /* HPD unit id - HW direct translation */ enum hpd_source_id { HPD_SOURCEID1 = 0, @@ -136,5 +140,47 @@ enum sync_source { SYNC_SOURCE_DUAL_GPU_PIN }; +/* connector sizes in millimeters - from BiosParserTypes.hpp */ +#define CONNECTOR_SIZE_DVI 40 +#define CONNECTOR_SIZE_VGA 32 +#define CONNECTOR_SIZE_HDMI 16 +#define CONNECTOR_SIZE_DP 16 +#define CONNECTOR_SIZE_MINI_DP 9 +#define CONNECTOR_SIZE_UNKNOWN 30 + +enum connector_layout_type { + CONNECTOR_LAYOUT_TYPE_UNKNOWN, + CONNECTOR_LAYOUT_TYPE_DVI_D, + CONNECTOR_LAYOUT_TYPE_DVI_I, + CONNECTOR_LAYOUT_TYPE_VGA, + CONNECTOR_LAYOUT_TYPE_HDMI, + CONNECTOR_LAYOUT_TYPE_DP, + CONNECTOR_LAYOUT_TYPE_MINI_DP, +}; +struct connector_layout_info { + struct graphics_object_id connector_id; + enum connector_layout_type connector_type; + unsigned int length; + unsigned int position; /* offset in mm from right side of the board */ +}; + +/* length and width in mm */ +struct slot_layout_info { + unsigned int length; + unsigned int width; + unsigned int num_of_connectors; + struct connector_layout_info connectors[MAX_CONNECTOR_NUMBER_PER_SLOT]; +}; + +struct board_layout_info { + unsigned int num_of_slots; + /* indicates valid information in bracket layout structure. */ + unsigned int is_number_of_slots_valid : 1; + unsigned int is_slots_size_valid : 1; + unsigned int is_connector_offsets_valid : 1; + unsigned int is_connector_lengths_valid : 1; + + struct slot_layout_info slots[MAX_BOARD_SLOTS]; +}; #endif diff --git a/drivers/gpu/drm/amd/display/include/grph_object_id.h b/drivers/gpu/drm/amd/display/include/grph_object_id.h index c4197432eb7c3..33b3d755fe655 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_id.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_id.h @@ -197,6 +197,11 @@ enum transmitter_color_depth { TRANSMITTER_COLOR_DEPTH_48 /* 16 bits */ }; +enum dp_alt_mode { + DP_Alt_mode__Unknown = 0, + DP_Alt_mode__Connect, + DP_Alt_mode__NoConnect, +}; /* ***************************************************************************** * graphics_object_id struct @@ -287,4 +292,15 @@ static inline enum engine_id dal_graphics_object_id_get_engine_id( return (enum engine_id) id.id; return ENGINE_ID_UNKNOWN; } + +static inline bool dal_graphics_object_id_equal( + struct graphics_object_id id_1, + struct graphics_object_id id_2) +{ + if ((id_1.id == id_2.id) && (id_1.enum_id == id_2.enum_id) && + (id_1.type == id_2.type)) { + return true; + } + return false; +} #endif diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 98edaefa2b472..ee69c949bfbf2 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1723,8 +1723,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_regamma); } else if (trans == TRANSFER_FUNCTION_HLG || trans == TRANSFER_FUNCTION_HLG12) { - rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -1802,8 +1802,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_HLG || trans == TRANSFER_FUNCTION_HLG12) { - rgb_degamma = kvzalloc(sizeof(*rgb_degamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_degamma), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; |