Home | History | Annotate | Line # | Download | only in dce100
      1 /*	$NetBSD: amdgpu_dce_clk_mgr.c,v 1.2 2021/12/18 23:45:01 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012-16 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: AMD
     25  *
     26  */
     27 
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_clk_mgr.c,v 1.2 2021/12/18 23:45:01 riastradh Exp $");
     31 
     32 #include "dccg.h"
     33 #include "clk_mgr_internal.h"
     34 #include "dce_clk_mgr.h"
     35 #include "dce110/dce110_clk_mgr.h"
     36 #include "dce112/dce112_clk_mgr.h"
     37 #include "reg_helper.h"
     38 #include "dmcu.h"
     39 #include "core_types.h"
     40 #include "dal_asic_id.h"
     41 
     42 /*
     43  * Currently the register shifts and masks in this file are used for dce100 and dce80
     44  * which has identical definitions.
     45  * TODO: remove this when DPREFCLK_CNTL and dpref DENTIST_DISPCLK_CNTL
     46  * is moved to dccg, where it belongs
     47  */
     48 #include "dce/dce_8_0_d.h"
     49 #include "dce/dce_8_0_sh_mask.h"
     50 
     51 #define REG(reg) \
     52 	(clk_mgr->regs->reg)
     53 
     54 #undef FN
     55 #define FN(reg_name, field_name) \
     56 	clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name
     57 
     58 static const struct clk_mgr_registers disp_clk_regs = {
     59 		CLK_COMMON_REG_LIST_DCE_BASE()
     60 };
     61 
     62 static const struct clk_mgr_shift disp_clk_shift = {
     63 		CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
     64 };
     65 
     66 static const struct clk_mgr_mask disp_clk_mask = {
     67 		CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
     68 };
     69 
     70 
     71 /* Max clock values for each state indexed by "enum clocks_state": */
     72 static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
     73 /* ClocksStateInvalid - should not be used */
     74 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     75 /* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
     76 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     77 /* ClocksStateLow */
     78 { .display_clk_khz = 352000, .pixel_clk_khz = 330000},
     79 /* ClocksStateNominal */
     80 { .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
     81 /* ClocksStatePerformance */
     82 { .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
     83 
     84 int dentist_get_divider_from_did(int did)
     85 {
     86 	if (did < DENTIST_BASE_DID_1)
     87 		did = DENTIST_BASE_DID_1;
     88 	if (did > DENTIST_MAX_DID)
     89 		did = DENTIST_MAX_DID;
     90 
     91 	if (did < DENTIST_BASE_DID_2) {
     92 		return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
     93 							* (did - DENTIST_BASE_DID_1);
     94 	} else if (did < DENTIST_BASE_DID_3) {
     95 		return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
     96 							* (did - DENTIST_BASE_DID_2);
     97 	} else if (did < DENTIST_BASE_DID_4) {
     98 		return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
     99 							* (did - DENTIST_BASE_DID_3);
    100 	} else {
    101 		return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
    102 							* (did - DENTIST_BASE_DID_4);
    103 	}
    104 }
    105 
    106 /* SW will adjust DP REF Clock average value for all purposes
    107  * (DP DTO / DP Audio DTO and DP GTC)
    108  if clock is spread for all cases:
    109  -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
    110  calculations for DS_INCR/DS_MODULO (this is planned to be default case)
    111  -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
    112  calculations (not planned to be used, but average clock should still
    113  be valid)
    114  -if SS enabled on DP Ref clock and HW de-spreading disabled
    115  (should not be case with CIK) then SW should program all rates
    116  generated according to average value (case as with previous ASICs)
    117   */
    118 
    119 int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz)
    120 {
    121 	if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
    122 		struct fixed31_32 ss_percentage = dc_fixpt_div_int(
    123 				dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
    124 							clk_mgr_dce->dprefclk_ss_divider), 200);
    125 		struct fixed31_32 adj_dp_ref_clk_khz;
    126 
    127 		ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
    128 		adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
    129 		dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
    130 	}
    131 	return dp_ref_clk_khz;
    132 }
    133 
    134 int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
    135 {
    136 	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
    137 	int dprefclk_wdivider;
    138 	int dprefclk_src_sel;
    139 	int dp_ref_clk_khz = 600000;
    140 	int target_div;
    141 
    142 	/* ASSERT DP Reference Clock source is from DFS*/
    143 	REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
    144 	ASSERT(dprefclk_src_sel == 0);
    145 
    146 	/* Read the mmDENTIST_DISPCLK_CNTL to get the currently
    147 	 * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
    148 	REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
    149 
    150 	/* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
    151 	target_div = dentist_get_divider_from_did(dprefclk_wdivider);
    152 
    153 	/* Calculate the current DFS clock, in kHz.*/
    154 	dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
    155 		* clk_mgr->base.dentist_vco_freq_khz) / target_div;
    156 
    157 	return dce_adjust_dp_ref_freq_for_ss(clk_mgr, dp_ref_clk_khz);
    158 }
    159 
    160 int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
    161 {
    162 	struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
    163 
    164 	return dce_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_base->dprefclk_khz);
    165 }
    166 
    167 /* unit: in_khz before mode set, get pixel clock from context. ASIC register
    168  * may not be programmed yet
    169  */
    170 uint32_t dce_get_max_pixel_clock_for_all_paths(struct dc_state *context)
    171 {
    172 	uint32_t max_pix_clk = 0;
    173 	int i;
    174 
    175 	for (i = 0; i < MAX_PIPES; i++) {
    176 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    177 
    178 		if (pipe_ctx->stream == NULL)
    179 			continue;
    180 
    181 		/* do not check under lay */
    182 		if (pipe_ctx->top_pipe)
    183 			continue;
    184 
    185 		if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 > max_pix_clk)
    186 			max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
    187 
    188 		/* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS
    189 		 * logic for HBR3 still needs Nominal (0.8V) on VDDC rail
    190 		 */
    191 		if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
    192 				pipe_ctx->stream_res.pix_clk_params.requested_sym_clk > max_pix_clk)
    193 			max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_sym_clk;
    194 	}
    195 
    196 	return max_pix_clk;
    197 }
    198 
    199 enum dm_pp_clocks_state dce_get_required_clocks_state(
    200 	struct clk_mgr *clk_mgr_base,
    201 	struct dc_state *context)
    202 {
    203 	struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
    204 	int i;
    205 	enum dm_pp_clocks_state low_req_clk;
    206 	int max_pix_clk = dce_get_max_pixel_clock_for_all_paths(context);
    207 
    208 	/* Iterate from highest supported to lowest valid state, and update
    209 	 * lowest RequiredState with the lowest state that satisfies
    210 	 * all required clocks
    211 	 */
    212 	for (i = clk_mgr_dce->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
    213 		if (context->bw_ctx.bw.dce.dispclk_khz >
    214 				clk_mgr_dce->max_clks_by_state[i].display_clk_khz
    215 			|| max_pix_clk >
    216 				clk_mgr_dce->max_clks_by_state[i].pixel_clk_khz)
    217 			break;
    218 
    219 	low_req_clk = i + 1;
    220 	if (low_req_clk > clk_mgr_dce->max_clks_state) {
    221 		/* set max clock state for high phyclock, invalid on exceeding display clock */
    222 		if (clk_mgr_dce->max_clks_by_state[clk_mgr_dce->max_clks_state].display_clk_khz
    223 				< context->bw_ctx.bw.dce.dispclk_khz)
    224 			low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
    225 		else
    226 			low_req_clk = clk_mgr_dce->max_clks_state;
    227 	}
    228 
    229 	return low_req_clk;
    230 }
    231 
    232 
    233 /* TODO: remove use the two broken down functions */
    234 int dce_set_clock(
    235 	struct clk_mgr *clk_mgr_base,
    236 	int requested_clk_khz)
    237 {
    238 	struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
    239 	struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
    240 	struct dc_bios *bp = clk_mgr_base->ctx->dc_bios;
    241 	int actual_clock = requested_clk_khz;
    242 	struct dmcu *dmcu = clk_mgr_dce->base.ctx->dc->res_pool->dmcu;
    243 
    244 	/* Make sure requested clock isn't lower than minimum threshold*/
    245 	if (requested_clk_khz > 0)
    246 		requested_clk_khz = max(requested_clk_khz,
    247 				clk_mgr_dce->base.dentist_vco_freq_khz / 64);
    248 
    249 	/* Prepare to program display clock*/
    250 	pxl_clk_params.target_pixel_clock_100hz = requested_clk_khz * 10;
    251 	pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
    252 
    253 	if (clk_mgr_dce->dfs_bypass_active)
    254 		pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true;
    255 
    256 	bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
    257 
    258 	if (clk_mgr_dce->dfs_bypass_active) {
    259 		/* Cache the fixed display clock*/
    260 		clk_mgr_dce->dfs_bypass_disp_clk =
    261 			pxl_clk_params.dfs_bypass_display_clock;
    262 		actual_clock = pxl_clk_params.dfs_bypass_display_clock;
    263 	}
    264 
    265 	/* from power down, we need mark the clock state as ClocksStateNominal
    266 	 * from HWReset, so when resume we will call pplib voltage regulator.*/
    267 	if (requested_clk_khz == 0)
    268 		clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
    269 
    270 	if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
    271 		dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7);
    272 
    273 	return actual_clock;
    274 }
    275 
    276 
    277 static void dce_clock_read_integrated_info(struct clk_mgr_internal *clk_mgr_dce)
    278 {
    279 	struct dc_debug_options *debug = &clk_mgr_dce->base.ctx->dc->debug;
    280 	struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
    281 	int i;
    282 
    283 	if (bp->integrated_info)
    284 		clk_mgr_dce->base.dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq;
    285 	if (clk_mgr_dce->base.dentist_vco_freq_khz == 0) {
    286 		clk_mgr_dce->base.dentist_vco_freq_khz = bp->fw_info.smu_gpu_pll_output_freq;
    287 		if (clk_mgr_dce->base.dentist_vco_freq_khz == 0)
    288 			clk_mgr_dce->base.dentist_vco_freq_khz = 3600000;
    289 	}
    290 
    291 	/*update the maximum display clock for each power state*/
    292 	for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
    293 		enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
    294 
    295 		switch (i) {
    296 		case 0:
    297 			clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
    298 			break;
    299 
    300 		case 1:
    301 			clk_state = DM_PP_CLOCKS_STATE_LOW;
    302 			break;
    303 
    304 		case 2:
    305 			clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
    306 			break;
    307 
    308 		case 3:
    309 			clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
    310 			break;
    311 
    312 		default:
    313 			clk_state = DM_PP_CLOCKS_STATE_INVALID;
    314 			break;
    315 		}
    316 
    317 		/*Do not allow bad VBIOS/SBIOS to override with invalid values,
    318 		 * check for > 100MHz*/
    319 		if (bp->integrated_info)
    320 			if (bp->integrated_info->disp_clk_voltage[i].max_supported_clk >= 100000)
    321 				clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz =
    322 					bp->integrated_info->disp_clk_voltage[i].max_supported_clk;
    323 	}
    324 
    325 	if (!debug->disable_dfs_bypass && bp->integrated_info)
    326 		if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
    327 			clk_mgr_dce->dfs_bypass_enabled = true;
    328 }
    329 
    330 void dce_clock_read_ss_info(struct clk_mgr_internal *clk_mgr_dce)
    331 {
    332 	struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
    333 	int ss_info_num = bp->funcs->get_ss_entry_number(
    334 			bp, AS_SIGNAL_TYPE_GPU_PLL);
    335 
    336 	if (ss_info_num) {
    337 		struct spread_spectrum_info info = { { 0 } };
    338 		enum bp_result result = bp->funcs->get_spread_spectrum_info(
    339 				bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
    340 
    341 		/* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
    342 		 * even if SS not enabled and in that case
    343 		 * SSInfo.spreadSpectrumPercentage !=0 would be sign
    344 		 * that SS is enabled
    345 		 */
    346 		if (result == BP_RESULT_OK &&
    347 				info.spread_spectrum_percentage != 0) {
    348 			clk_mgr_dce->ss_on_dprefclk = true;
    349 			clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
    350 
    351 			if (info.type.CENTER_MODE == 0) {
    352 				/* TODO: Currently for DP Reference clock we
    353 				 * need only SS percentage for
    354 				 * downspread */
    355 				clk_mgr_dce->dprefclk_ss_percentage =
    356 						info.spread_spectrum_percentage;
    357 			}
    358 
    359 			return;
    360 		}
    361 
    362 		result = bp->funcs->get_spread_spectrum_info(
    363 				bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
    364 
    365 		/* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
    366 		 * even if SS not enabled and in that case
    367 		 * SSInfo.spreadSpectrumPercentage !=0 would be sign
    368 		 * that SS is enabled
    369 		 */
    370 		if (result == BP_RESULT_OK &&
    371 				info.spread_spectrum_percentage != 0) {
    372 			clk_mgr_dce->ss_on_dprefclk = true;
    373 			clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
    374 
    375 			if (info.type.CENTER_MODE == 0) {
    376 				/* Currently for DP Reference clock we
    377 				 * need only SS percentage for
    378 				 * downspread */
    379 				clk_mgr_dce->dprefclk_ss_percentage =
    380 						info.spread_spectrum_percentage;
    381 			}
    382 		}
    383 	}
    384 }
    385 
    386 static void dce_pplib_apply_display_requirements(
    387 	struct dc *dc,
    388 	struct dc_state *context)
    389 {
    390 	struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
    391 
    392 	pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
    393 
    394 	dce110_fill_display_configs(context, pp_display_cfg);
    395 
    396 	if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) !=  0)
    397 		dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
    398 }
    399 
    400 static void dce_update_clocks(struct clk_mgr *clk_mgr_base,
    401 			struct dc_state *context,
    402 			bool safe_to_lower)
    403 {
    404 	struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
    405 	struct dm_pp_power_level_change_request level_change_req;
    406 	int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
    407 
    408 	/*TODO: W/A for dal3 linux, investigate why this works */
    409 	if (!clk_mgr_dce->dfs_bypass_active)
    410 		patched_disp_clk = patched_disp_clk * 115 / 100;
    411 
    412 	level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
    413 	/* get max clock state from PPLIB */
    414 	if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
    415 			|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
    416 		if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req))
    417 			clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
    418 	}
    419 
    420 	if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) {
    421 		patched_disp_clk = dce_set_clock(clk_mgr_base, patched_disp_clk);
    422 		clk_mgr_base->clks.dispclk_khz = patched_disp_clk;
    423 	}
    424 	dce_pplib_apply_display_requirements(clk_mgr_base->ctx->dc, context);
    425 }
    426 
    427 
    428 
    429 
    430 
    431 
    432 
    433 
    434 static struct clk_mgr_funcs dce_funcs = {
    435 	.get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
    436 	.update_clocks = dce_update_clocks
    437 };
    438 
    439 void dce_clk_mgr_construct(
    440 		struct dc_context *ctx,
    441 		struct clk_mgr_internal *clk_mgr)
    442 {
    443 	struct clk_mgr *base = &clk_mgr->base;
    444 	struct dm_pp_static_clock_info static_clk_info = {0};
    445 
    446 	memcpy(clk_mgr->max_clks_by_state,
    447 		dce80_max_clks_by_state,
    448 		sizeof(dce80_max_clks_by_state));
    449 
    450 	base->ctx = ctx;
    451 	base->funcs = &dce_funcs;
    452 
    453 	clk_mgr->regs = &disp_clk_regs;
    454 	clk_mgr->clk_mgr_shift = &disp_clk_shift;
    455 	clk_mgr->clk_mgr_mask = &disp_clk_mask;
    456 	clk_mgr->dfs_bypass_disp_clk = 0;
    457 
    458 	clk_mgr->dprefclk_ss_percentage = 0;
    459 	clk_mgr->dprefclk_ss_divider = 1000;
    460 	clk_mgr->ss_on_dprefclk = false;
    461 
    462 	if (dm_pp_get_static_clocks(ctx, &static_clk_info))
    463 		clk_mgr->max_clks_state = static_clk_info.max_clocks_state;
    464 	else
    465 		clk_mgr->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
    466 	clk_mgr->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
    467 
    468 	dce_clock_read_integrated_info(clk_mgr);
    469 	dce_clock_read_ss_info(clk_mgr);
    470 }
    471 
    472