FILE
dce110_clk_mgr.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c
1/* 2 * Copyright 2012-16 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26#include "core_types.h" 27#include "clk_mgr_internal.h" 28 29#include "dce/dce_11_0_d.h" 30#include "dce/dce_11_0_sh_mask.h" 31#include "dce110_clk_mgr.h" 32#include "../clk_mgr/dce100/dce_clk_mgr.h" 33 34/* set register offset */ 35#define SR(reg_name)\ 36 .reg_name = mm ## reg_name 37 38/* set register offset with instance */ 39#define SRI(reg_name, block, id)\ 40 .reg_name = mm ## block ## id ## _ ## reg_name 41 42static const struct clk_mgr_registers disp_clk_regs = { 43 CLK_COMMON_REG_LIST_DCE_BASE() 44}; 45 46static const struct clk_mgr_shift disp_clk_shift = { 47 CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) 48}; 49 50static const struct clk_mgr_mask disp_clk_mask = { 51 CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) 52}; 53 54static const struct state_dependent_clocks dce110_max_clks_by_state[] = { 55/*ClocksStateInvalid - should not be used*/ 56{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, 57/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/ 58{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 }, 59/*ClocksStateLow*/ 60{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 }, 61/*ClocksStateNominal*/ 62{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 }, 63/*ClocksStatePerformance*/ 64{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } }; 65 66static int determine_sclk_from_bounding_box( 67 const struct dc *dc, 68 int required_sclk) 69{ 70 int i; 71 72 /* 73 * Some asics do not give us sclk levels, so we just report the actual 74 * required sclk 75 */ 76 if (dc->sclk_lvls.num_levels == 0) 77 return required_sclk; 78 79 for (i = 0; i < dc->sclk_lvls.num_levels; i++) { 80 if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk) 81 return dc->sclk_lvls.clocks_in_khz[i]; 82 } 83 /* 84 * even maximum level could not satisfy requirement, this 85 * is unexpected at this stage, should have been caught at 86 * validation time 87 */ 88 ASSERT(0); 89 return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1]; 90} 91 92uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context) 93{ 94 uint8_t j; 95 uint32_t min_vertical_blank_time = -1; 96 97 for (j = 0; j < context->stream_count; j++) { 98 struct dc_stream_state *stream = context->streams[j]; 99 uint32_t vertical_blank_in_pixels = 0; 100 uint32_t vertical_blank_time = 0; 101 uint32_t vertical_total_min = stream->timing.v_total; 102 struct dc_crtc_timing_adjust adjust = stream->adjust; 103 if (adjust.v_total_max != adjust.v_total_min) 104 vertical_total_min = adjust.v_total_min; 105 106 vertical_blank_in_pixels = stream->timing.h_total * 107 (vertical_total_min 108 - stream->timing.v_addressable); 109 vertical_blank_time = vertical_blank_in_pixels 110 * 10000 / stream->timing.pix_clk_100hz; 111 112 if (min_vertical_blank_time > vertical_blank_time) 113 min_vertical_blank_time = vertical_blank_time; 114 } 115 116 return min_vertical_blank_time; 117} 118 119void dce110_fill_display_configs( 120 const struct dc_state *context, 121 struct dm_pp_display_configuration *pp_display_cfg) 122{ 123 struct dc *dc = context->clk_mgr->ctx->dc; 124 int j; 125 int num_cfgs = 0; 126 127 pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context); 128 pp_display_cfg->disp_clk_khz = dc->clk_mgr->clks.dispclk_khz; 129 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0; 130 pp_display_cfg->crtc_index = dc->res_pool->res_cap->num_timing_generator; 131 132 for (j = 0; j < context->stream_count; j++) { 133 int k; 134 135 const struct dc_stream_state *stream = context->streams[j]; 136 struct dm_pp_single_disp_config *cfg = 137 &pp_display_cfg->disp_configs[num_cfgs]; 138 const struct pipe_ctx *pipe_ctx = NULL; 139 140 for (k = 0; k < MAX_PIPES; k++) 141 if (stream == context->res_ctx.pipe_ctx[k].stream) { 142 pipe_ctx = &context->res_ctx.pipe_ctx[k]; 143 break; 144 } 145 146 ASSERT(pipe_ctx != NULL); 147 148 /* only notify active stream */ 149 if (stream->dpms_off) 150 continue; 151 152 num_cfgs++; 153 cfg->signal = pipe_ctx->stream->signal; 154 cfg->pipe_idx = pipe_ctx->stream_res.tg->inst; 155 cfg->src_height = stream->src.height; 156 cfg->src_width = stream->src.width; 157 cfg->ddi_channel_mapping = 158 stream->link->ddi_channel_mapping.raw; 159 cfg->transmitter = 160 stream->link->link_enc->transmitter; 161 cfg->link_settings.lane_count = 162 stream->link->cur_link_settings.lane_count; 163 cfg->link_settings.link_rate = 164 stream->link->cur_link_settings.link_rate; 165 cfg->link_settings.link_spread = 166 stream->link->cur_link_settings.link_spread; 167 cfg->pixel_clock = stream->phy_pix_clk; 168 /* Round v_refresh*/ 169 cfg->v_refresh = stream->timing.pix_clk_100hz * 100; 170 cfg->v_refresh /= stream->timing.h_total; 171 cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2) 172 / stream->timing.v_total; 173 174 /* Find first CRTC index and calculate its line time. 175 * This is necessary for DPM on SI GPUs. 176 */ 177 if (cfg->pipe_idx < pp_display_cfg->crtc_index) { 178 const struct dc_crtc_timing *timing = 179 &context->streams[0]->timing; 180 181 pp_display_cfg->crtc_index = cfg->pipe_idx; 182 pp_display_cfg->line_time_in_us = 183 timing->h_total * 10000 / timing->pix_clk_100hz; 184 } 185 } 186 187 if (!num_cfgs) { 188 pp_display_cfg->crtc_index = 0; 189 pp_display_cfg->line_time_in_us = 0; 190 } 191 192 pp_display_cfg->display_count = num_cfgs; 193} 194 195void dce11_pplib_apply_display_requirements( 196 struct dc *dc, 197 struct dc_state *context) 198{ 199 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; 200 int memory_type_multiplier = MEMORY_TYPE_MULTIPLIER_CZ; 201 202 if (dc->bw_vbios && dc->bw_vbios->memory_type == bw_def_hbm) 203 memory_type_multiplier = MEMORY_TYPE_HBM; 204 205 pp_display_cfg->all_displays_in_sync = 206 context->bw_ctx.bw.dce.all_displays_in_sync; 207 pp_display_cfg->nb_pstate_switch_disable = 208 context->bw_ctx.bw.dce.nbp_state_change_enable == false; 209 pp_display_cfg->cpu_cc6_disable = 210 context->bw_ctx.bw.dce.cpuc_state_change_enable == false; 211 pp_display_cfg->cpu_pstate_disable = 212 context->bw_ctx.bw.dce.cpup_state_change_enable == false; 213 pp_display_cfg->cpu_pstate_separation_time = 214 context->bw_ctx.bw.dce.blackout_recovery_time_us; 215 216 /* 217 * TODO: determine whether the bandwidth has reached memory's limitation 218 * , then change minimum memory clock based on real-time bandwidth 219 * limitation. 220 */ 221 if (dc->bw_vbios && (dc->ctx->asic_id.chip_family == FAMILY_AI) && 222 ASICREV_IS_VEGA20_P(dc->ctx->asic_id.hw_internal_rev) && (context->stream_count >= 2)) { 223 pp_display_cfg->min_memory_clock_khz = max(pp_display_cfg->min_memory_clock_khz, 224 (uint32_t) div64_s64( 225 div64_s64(dc->bw_vbios->high_yclk.value, 226 memory_type_multiplier), 10000)); 227 } else { 228 pp_display_cfg->min_memory_clock_khz = context->bw_ctx.bw.dce.yclk_khz 229 / memory_type_multiplier; 230 } 231 232 pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box( 233 dc, 234 context->bw_ctx.bw.dce.sclk_khz); 235 236 /* 237 * As workaround for >4x4K lightup set dcfclock to min_engine_clock value. 238 * This is not required for less than 5 displays, 239 * thus don't request decfclk in dc to avoid impact 240 * on power saving. 241 * 242 */ 243 pp_display_cfg->min_dcfclock_khz = (context->stream_count > 4) ? 244 pp_display_cfg->min_engine_clock_khz : 0; 245 246 pp_display_cfg->min_engine_clock_deep_sleep_khz 247 = context->bw_ctx.bw.dce.sclk_deep_sleep_khz; 248 249 dce110_fill_display_configs(context, pp_display_cfg); 250 251 if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) 252 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg); 253} 254 255static void dce11_update_clocks(struct clk_mgr *clk_mgr_base, 256 struct dc_state *context, 257 bool safe_to_lower) 258{ 259 struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); 260 struct dm_pp_power_level_change_request level_change_req; 261 int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz; 262 263 /*TODO: W/A for dal3 linux, investigate why this works */ 264 if (!clk_mgr_dce->dfs_bypass_active) 265 patched_disp_clk = patched_disp_clk * 115 / 100; 266 267 level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context); 268 /* get max clock state from PPLIB */ 269 if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower) 270 || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) { 271 if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req)) 272 clk_mgr_dce->cur_min_clks_state = level_change_req.power_level; 273 } 274 275 if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) { 276 context->bw_ctx.bw.dce.dispclk_khz = dce_set_clock(clk_mgr_base, patched_disp_clk); 277 clk_mgr_base->clks.dispclk_khz = patched_disp_clk; 278 } 279 dce11_pplib_apply_display_requirements(clk_mgr_base->ctx->dc, context); 280} 281 282static struct clk_mgr_funcs dce110_funcs = { 283 .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, 284 .update_clocks = dce11_update_clocks 285}; 286 287void dce110_clk_mgr_construct( 288 struct dc_context *ctx, 289 struct clk_mgr_internal *clk_mgr) 290{ 291 dce_clk_mgr_construct(ctx, clk_mgr); 292 293 memcpy(clk_mgr->max_clks_by_state, 294 dce110_max_clks_by_state, 295 sizeof(dce110_max_clks_by_state)); 296 297 clk_mgr->regs = &disp_clk_regs; 298 clk_mgr->clk_mgr_shift = &disp_clk_shift; 299 clk_mgr->clk_mgr_mask = &disp_clk_mask; 300 clk_mgr->base.funcs = &dce110_funcs; 301 302}
~/
Read-only file preview.