Home | History | Annotate | Line # | Download | only in dce
      1 /*	$NetBSD: dce_clk_mgr.c,v 1.2 2021/12/18 23:45:02 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 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: dce_clk_mgr.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
     30 
     31 #include <linux/slab.h>
     32 
     33 #include "dce_clk_mgr.h"
     34 
     35 #include "reg_helper.h"
     36 #include "dmcu.h"
     37 #include "core_types.h"
     38 #include "dal_asic_id.h"
     39 
     40 #define TO_DCE_CLK_MGR(clocks)\
     41 	container_of(clocks, struct dce_clk_mgr, base)
     42 
     43 #define REG(reg) \
     44 	(clk_mgr_dce->regs->reg)
     45 
     46 #undef FN
     47 #define FN(reg_name, field_name) \
     48 	clk_mgr_dce->clk_mgr_shift->field_name, clk_mgr_dce->clk_mgr_mask->field_name
     49 
     50 #define CTX \
     51 	clk_mgr_dce->base.ctx
     52 #define DC_LOGGER \
     53 	clk_mgr->ctx->logger
     54 
     55 /* Max clock values for each state indexed by "enum clocks_state": */
     56 static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
     57 /* ClocksStateInvalid - should not be used */
     58 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     59 /* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
     60 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     61 /* ClocksStateLow */
     62 { .display_clk_khz = 352000, .pixel_clk_khz = 330000},
     63 /* ClocksStateNominal */
     64 { .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
     65 /* ClocksStatePerformance */
     66 { .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
     67 
     68 static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
     69 /*ClocksStateInvalid - should not be used*/
     70 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     71 /*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
     72 { .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
     73 /*ClocksStateLow*/
     74 { .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
     75 /*ClocksStateNominal*/
     76 { .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
     77 /*ClocksStatePerformance*/
     78 { .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
     79 
     80 static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
     81 /*ClocksStateInvalid - should not be used*/
     82 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     83 /*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
     84 { .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
     85 /*ClocksStateLow*/
     86 { .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
     87 /*ClocksStateNominal*/
     88 { .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
     89 /*ClocksStatePerformance*/
     90 { .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
     91 
     92 static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
     93 /*ClocksStateInvalid - should not be used*/
     94 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     95 /*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
     96 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
     97 /*ClocksStateLow*/
     98 { .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
     99 /*ClocksStateNominal*/
    100 { .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
    101 /*ClocksStatePerformance*/
    102 { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
    103 
    104 int dentist_get_divider_from_did(int did)
    105 {
    106 	if (did < DENTIST_BASE_DID_1)
    107 		did = DENTIST_BASE_DID_1;
    108 	if (did > DENTIST_MAX_DID)
    109 		did = DENTIST_MAX_DID;
    110 
    111 	if (did < DENTIST_BASE_DID_2) {
    112 		return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
    113 							* (did - DENTIST_BASE_DID_1);
    114 	} else if (did < DENTIST_BASE_DID_3) {
    115 		return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
    116 							* (did - DENTIST_BASE_DID_2);
    117 	} else if (did < DENTIST_BASE_DID_4) {
    118 		return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
    119 							* (did - DENTIST_BASE_DID_3);
    120 	} else {
    121 		return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
    122 							* (did - DENTIST_BASE_DID_4);
    123 	}
    124 }
    125 
    126 /* SW will adjust DP REF Clock average value for all purposes
    127  * (DP DTO / DP Audio DTO and DP GTC)
    128  if clock is spread for all cases:
    129  -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
    130  calculations for DS_INCR/DS_MODULO (this is planned to be default case)
    131  -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
    132  calculations (not planned to be used, but average clock should still
    133  be valid)
    134  -if SS enabled on DP Ref clock and HW de-spreading disabled
    135  (should not be case with CIK) then SW should program all rates
    136  generated according to average value (case as with previous ASICs)
    137   */
    138 static int clk_mgr_adjust_dp_ref_freq_for_ss(struct dce_clk_mgr *clk_mgr_dce, int dp_ref_clk_khz)
    139 {
    140 	if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
    141 		struct fixed31_32 ss_percentage = dc_fixpt_div_int(
    142 				dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
    143 							clk_mgr_dce->dprefclk_ss_divider), 200);
    144 		struct fixed31_32 adj_dp_ref_clk_khz;
    145 
    146 		ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
    147 		adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
    148 		dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
    149 	}
    150 	return dp_ref_clk_khz;
    151 }
    152 
    153 static int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr)
    154 {
    155 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    156 	int dprefclk_wdivider;
    157 	int dprefclk_src_sel;
    158 	int dp_ref_clk_khz = 600000;
    159 	int target_div;
    160 
    161 	/* ASSERT DP Reference Clock source is from DFS*/
    162 	REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
    163 	ASSERT(dprefclk_src_sel == 0);
    164 
    165 	/* Read the mmDENTIST_DISPCLK_CNTL to get the currently
    166 	 * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
    167 	REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
    168 
    169 	/* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
    170 	target_div = dentist_get_divider_from_did(dprefclk_wdivider);
    171 
    172 	/* Calculate the current DFS clock, in kHz.*/
    173 	dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
    174 		* clk_mgr_dce->dentist_vco_freq_khz) / target_div;
    175 
    176 	return clk_mgr_adjust_dp_ref_freq_for_ss(clk_mgr_dce, dp_ref_clk_khz);
    177 }
    178 
    179 int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr)
    180 {
    181 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    182 
    183 	return clk_mgr_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_dce->dprefclk_khz);
    184 }
    185 
    186 /* unit: in_khz before mode set, get pixel clock from context. ASIC register
    187  * may not be programmed yet
    188  */
    189 static uint32_t get_max_pixel_clock_for_all_paths(struct dc_state *context)
    190 {
    191 	uint32_t max_pix_clk = 0;
    192 	int i;
    193 
    194 	for (i = 0; i < MAX_PIPES; i++) {
    195 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    196 
    197 		if (pipe_ctx->stream == NULL)
    198 			continue;
    199 
    200 		/* do not check under lay */
    201 		if (pipe_ctx->top_pipe)
    202 			continue;
    203 
    204 		if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 > max_pix_clk)
    205 			max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
    206 
    207 		/* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS
    208 		 * logic for HBR3 still needs Nominal (0.8V) on VDDC rail
    209 		 */
    210 		if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
    211 				pipe_ctx->stream_res.pix_clk_params.requested_sym_clk > max_pix_clk)
    212 			max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_sym_clk;
    213 	}
    214 
    215 	return max_pix_clk;
    216 }
    217 
    218 static enum dm_pp_clocks_state dce_get_required_clocks_state(
    219 	struct clk_mgr *clk_mgr,
    220 	struct dc_state *context)
    221 {
    222 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    223 	int i;
    224 	enum dm_pp_clocks_state low_req_clk;
    225 	int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
    226 
    227 	/* Iterate from highest supported to lowest valid state, and update
    228 	 * lowest RequiredState with the lowest state that satisfies
    229 	 * all required clocks
    230 	 */
    231 	for (i = clk_mgr_dce->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
    232 		if (context->bw_ctx.bw.dce.dispclk_khz >
    233 				clk_mgr_dce->max_clks_by_state[i].display_clk_khz
    234 			|| max_pix_clk >
    235 				clk_mgr_dce->max_clks_by_state[i].pixel_clk_khz)
    236 			break;
    237 
    238 	low_req_clk = i + 1;
    239 	if (low_req_clk > clk_mgr_dce->max_clks_state) {
    240 		/* set max clock state for high phyclock, invalid on exceeding display clock */
    241 		if (clk_mgr_dce->max_clks_by_state[clk_mgr_dce->max_clks_state].display_clk_khz
    242 				< context->bw_ctx.bw.dce.dispclk_khz)
    243 			low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
    244 		else
    245 			low_req_clk = clk_mgr_dce->max_clks_state;
    246 	}
    247 
    248 	return low_req_clk;
    249 }
    250 
    251 static int dce_set_clock(
    252 	struct clk_mgr *clk_mgr,
    253 	int requested_clk_khz)
    254 {
    255 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    256 	struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
    257 	struct dc_bios *bp = clk_mgr->ctx->dc_bios;
    258 	int actual_clock = requested_clk_khz;
    259 	struct dmcu *dmcu = clk_mgr_dce->base.ctx->dc->res_pool->dmcu;
    260 
    261 	/* Make sure requested clock isn't lower than minimum threshold*/
    262 	if (requested_clk_khz > 0)
    263 		requested_clk_khz = max(requested_clk_khz,
    264 				clk_mgr_dce->dentist_vco_freq_khz / 64);
    265 
    266 	/* Prepare to program display clock*/
    267 	pxl_clk_params.target_pixel_clock_100hz = requested_clk_khz * 10;
    268 	pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
    269 
    270 	if (clk_mgr_dce->dfs_bypass_active)
    271 		pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true;
    272 
    273 	bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
    274 
    275 	if (clk_mgr_dce->dfs_bypass_active) {
    276 		/* Cache the fixed display clock*/
    277 		clk_mgr_dce->dfs_bypass_disp_clk =
    278 			pxl_clk_params.dfs_bypass_display_clock;
    279 		actual_clock = pxl_clk_params.dfs_bypass_display_clock;
    280 	}
    281 
    282 	/* from power down, we need mark the clock state as ClocksStateNominal
    283 	 * from HWReset, so when resume we will call pplib voltage regulator.*/
    284 	if (requested_clk_khz == 0)
    285 		clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
    286 
    287 	if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
    288 		dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7);
    289 
    290 	return actual_clock;
    291 }
    292 
    293 int dce112_set_clock(struct clk_mgr *clk_mgr, int requested_clk_khz)
    294 {
    295 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    296 	struct bp_set_dce_clock_parameters dce_clk_params;
    297 	struct dc_bios *bp = clk_mgr->ctx->dc_bios;
    298 	struct dc *core_dc = clk_mgr->ctx->dc;
    299 	struct dmcu *dmcu = core_dc->res_pool->dmcu;
    300 	int actual_clock = requested_clk_khz;
    301 	/* Prepare to program display clock*/
    302 	memset(&dce_clk_params, 0, sizeof(dce_clk_params));
    303 
    304 	/* Make sure requested clock isn't lower than minimum threshold*/
    305 	if (requested_clk_khz > 0)
    306 		requested_clk_khz = max(requested_clk_khz,
    307 				clk_mgr_dce->dentist_vco_freq_khz / 62);
    308 
    309 	dce_clk_params.target_clock_frequency = requested_clk_khz;
    310 	dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
    311 	dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
    312 
    313 	bp->funcs->set_dce_clock(bp, &dce_clk_params);
    314 	actual_clock = dce_clk_params.target_clock_frequency;
    315 
    316 	/* from power down, we need mark the clock state as ClocksStateNominal
    317 	 * from HWReset, so when resume we will call pplib voltage regulator.*/
    318 	if (requested_clk_khz == 0)
    319 		clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
    320 
    321 	/*Program DP ref Clock*/
    322 	/*VBIOS will determine DPREFCLK frequency, so we don't set it*/
    323 	dce_clk_params.target_clock_frequency = 0;
    324 	dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
    325 	if (!ASICREV_IS_VEGA20_P(clk_mgr->ctx->asic_id.hw_internal_rev))
    326 		dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
    327 			(dce_clk_params.pll_id ==
    328 					CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
    329 	else
    330 		dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
    331 
    332 	bp->funcs->set_dce_clock(bp, &dce_clk_params);
    333 
    334 	if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
    335 		if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
    336 			if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock)
    337 				dmcu->funcs->set_psr_wait_loop(dmcu,
    338 						actual_clock / 1000 / 7);
    339 		}
    340 	}
    341 
    342 	clk_mgr_dce->dfs_bypass_disp_clk = actual_clock;
    343 	return actual_clock;
    344 }
    345 
    346 static void dce_clock_read_integrated_info(struct dce_clk_mgr *clk_mgr_dce)
    347 {
    348 	struct dc_debug_options *debug = &clk_mgr_dce->base.ctx->dc->debug;
    349 	struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
    350 	struct integrated_info info = { { { 0 } } };
    351 	struct dc_firmware_info fw_info = { { 0 } };
    352 	int i;
    353 
    354 	if (bp->integrated_info)
    355 		info = *bp->integrated_info;
    356 
    357 	clk_mgr_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
    358 	if (clk_mgr_dce->dentist_vco_freq_khz == 0) {
    359 		bp->funcs->get_firmware_info(bp, &fw_info);
    360 		clk_mgr_dce->dentist_vco_freq_khz =
    361 			fw_info.smu_gpu_pll_output_freq;
    362 		if (clk_mgr_dce->dentist_vco_freq_khz == 0)
    363 			clk_mgr_dce->dentist_vco_freq_khz = 3600000;
    364 	}
    365 
    366 	/*update the maximum display clock for each power state*/
    367 	for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
    368 		enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
    369 
    370 		switch (i) {
    371 		case 0:
    372 			clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
    373 			break;
    374 
    375 		case 1:
    376 			clk_state = DM_PP_CLOCKS_STATE_LOW;
    377 			break;
    378 
    379 		case 2:
    380 			clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
    381 			break;
    382 
    383 		case 3:
    384 			clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
    385 			break;
    386 
    387 		default:
    388 			clk_state = DM_PP_CLOCKS_STATE_INVALID;
    389 			break;
    390 		}
    391 
    392 		/*Do not allow bad VBIOS/SBIOS to override with invalid values,
    393 		 * check for > 100MHz*/
    394 		if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
    395 			clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz =
    396 				info.disp_clk_voltage[i].max_supported_clk;
    397 	}
    398 
    399 	if (!debug->disable_dfs_bypass && bp->integrated_info)
    400 		if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
    401 			clk_mgr_dce->dfs_bypass_enabled = true;
    402 }
    403 
    404 void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce)
    405 {
    406 	struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
    407 	int ss_info_num = bp->funcs->get_ss_entry_number(
    408 			bp, AS_SIGNAL_TYPE_GPU_PLL);
    409 
    410 	if (ss_info_num) {
    411 		struct spread_spectrum_info info = { { 0 } };
    412 		enum bp_result result = bp->funcs->get_spread_spectrum_info(
    413 				bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
    414 
    415 		/* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
    416 		 * even if SS not enabled and in that case
    417 		 * SSInfo.spreadSpectrumPercentage !=0 would be sign
    418 		 * that SS is enabled
    419 		 */
    420 		if (result == BP_RESULT_OK &&
    421 				info.spread_spectrum_percentage != 0) {
    422 			clk_mgr_dce->ss_on_dprefclk = true;
    423 			clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
    424 
    425 			if (info.type.CENTER_MODE == 0) {
    426 				/* TODO: Currently for DP Reference clock we
    427 				 * need only SS percentage for
    428 				 * downspread */
    429 				clk_mgr_dce->dprefclk_ss_percentage =
    430 						info.spread_spectrum_percentage;
    431 			}
    432 
    433 			return;
    434 		}
    435 
    436 		result = bp->funcs->get_spread_spectrum_info(
    437 				bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
    438 
    439 		/* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
    440 		 * even if SS not enabled and in that case
    441 		 * SSInfo.spreadSpectrumPercentage !=0 would be sign
    442 		 * that SS is enabled
    443 		 */
    444 		if (result == BP_RESULT_OK &&
    445 				info.spread_spectrum_percentage != 0) {
    446 			clk_mgr_dce->ss_on_dprefclk = true;
    447 			clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
    448 
    449 			if (info.type.CENTER_MODE == 0) {
    450 				/* Currently for DP Reference clock we
    451 				 * need only SS percentage for
    452 				 * downspread */
    453 				clk_mgr_dce->dprefclk_ss_percentage =
    454 						info.spread_spectrum_percentage;
    455 			}
    456 		}
    457 	}
    458 }
    459 
    460 /**
    461  * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info
    462  * @clk_mgr: clock manager base structure
    463  *
    464  * Reads from VBIOS the XGMI spread spectrum info and saves it within
    465  * the dce clock manager. This operation will overwrite the existing dprefclk
    466  * SS values if the vBIOS query succeeds. Otherwise, it does nothing. It also
    467  * sets the ->xgmi_enabled flag.
    468  */
    469 void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr)
    470 {
    471 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    472 	enum bp_result result;
    473 	struct spread_spectrum_info info = { { 0 } };
    474 	struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
    475 
    476 	clk_mgr_dce->xgmi_enabled = false;
    477 
    478 	result = bp->funcs->get_spread_spectrum_info(bp, AS_SIGNAL_TYPE_XGMI,
    479 						     0, &info);
    480 	if (result == BP_RESULT_OK && info.spread_spectrum_percentage != 0) {
    481 		clk_mgr_dce->xgmi_enabled = true;
    482 		clk_mgr_dce->ss_on_dprefclk = true;
    483 		clk_mgr_dce->dprefclk_ss_divider =
    484 				info.spread_percentage_divider;
    485 
    486 		if (info.type.CENTER_MODE == 0) {
    487 			/* Currently for DP Reference clock we
    488 			 * need only SS percentage for
    489 			 * downspread */
    490 			clk_mgr_dce->dprefclk_ss_percentage =
    491 					info.spread_spectrum_percentage;
    492 		}
    493 	}
    494 }
    495 
    496 void dce110_fill_display_configs(
    497 	const struct dc_state *context,
    498 	struct dm_pp_display_configuration *pp_display_cfg)
    499 {
    500 	int j;
    501 	int num_cfgs = 0;
    502 
    503 	for (j = 0; j < context->stream_count; j++) {
    504 		int k;
    505 
    506 		const struct dc_stream_state *stream = context->streams[j];
    507 		struct dm_pp_single_disp_config *cfg =
    508 			&pp_display_cfg->disp_configs[num_cfgs];
    509 		const struct pipe_ctx *pipe_ctx = NULL;
    510 
    511 		for (k = 0; k < MAX_PIPES; k++)
    512 			if (stream == context->res_ctx.pipe_ctx[k].stream) {
    513 				pipe_ctx = &context->res_ctx.pipe_ctx[k];
    514 				break;
    515 			}
    516 
    517 		ASSERT(pipe_ctx != NULL);
    518 
    519 		/* only notify active stream */
    520 		if (stream->dpms_off)
    521 			continue;
    522 
    523 		num_cfgs++;
    524 		cfg->signal = pipe_ctx->stream->signal;
    525 		cfg->pipe_idx = pipe_ctx->stream_res.tg->inst;
    526 		cfg->src_height = stream->src.height;
    527 		cfg->src_width = stream->src.width;
    528 		cfg->ddi_channel_mapping =
    529 			stream->link->ddi_channel_mapping.raw;
    530 		cfg->transmitter =
    531 			stream->link->link_enc->transmitter;
    532 		cfg->link_settings.lane_count =
    533 			stream->link->cur_link_settings.lane_count;
    534 		cfg->link_settings.link_rate =
    535 			stream->link->cur_link_settings.link_rate;
    536 		cfg->link_settings.link_spread =
    537 			stream->link->cur_link_settings.link_spread;
    538 		cfg->sym_clock = stream->phy_pix_clk;
    539 		/* Round v_refresh*/
    540 		cfg->v_refresh = stream->timing.pix_clk_100hz * 100;
    541 		cfg->v_refresh /= stream->timing.h_total;
    542 		cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
    543 							/ stream->timing.v_total;
    544 	}
    545 
    546 	pp_display_cfg->display_count = num_cfgs;
    547 }
    548 
    549 static uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
    550 {
    551 	uint8_t j;
    552 	uint32_t min_vertical_blank_time = -1;
    553 
    554 	for (j = 0; j < context->stream_count; j++) {
    555 		struct dc_stream_state *stream = context->streams[j];
    556 		uint32_t vertical_blank_in_pixels = 0;
    557 		uint32_t vertical_blank_time = 0;
    558 
    559 		vertical_blank_in_pixels = stream->timing.h_total *
    560 			(stream->timing.v_total
    561 			 - stream->timing.v_addressable);
    562 
    563 		vertical_blank_time = vertical_blank_in_pixels
    564 			* 10000 / stream->timing.pix_clk_100hz;
    565 
    566 		if (min_vertical_blank_time > vertical_blank_time)
    567 			min_vertical_blank_time = vertical_blank_time;
    568 	}
    569 
    570 	return min_vertical_blank_time;
    571 }
    572 
    573 static int determine_sclk_from_bounding_box(
    574 		const struct dc *dc,
    575 		int required_sclk)
    576 {
    577 	int i;
    578 
    579 	/*
    580 	 * Some asics do not give us sclk levels, so we just report the actual
    581 	 * required sclk
    582 	 */
    583 	if (dc->sclk_lvls.num_levels == 0)
    584 		return required_sclk;
    585 
    586 	for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
    587 		if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
    588 			return dc->sclk_lvls.clocks_in_khz[i];
    589 	}
    590 	/*
    591 	 * even maximum level could not satisfy requirement, this
    592 	 * is unexpected at this stage, should have been caught at
    593 	 * validation time
    594 	 */
    595 	ASSERT(0);
    596 	return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
    597 }
    598 
    599 static void dce_pplib_apply_display_requirements(
    600 	struct dc *dc,
    601 	struct dc_state *context)
    602 {
    603 	struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
    604 
    605 	pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
    606 
    607 	dce110_fill_display_configs(context, pp_display_cfg);
    608 
    609 	if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) !=  0)
    610 		dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
    611 }
    612 
    613 static void dce11_pplib_apply_display_requirements(
    614 	struct dc *dc,
    615 	struct dc_state *context)
    616 {
    617 	struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
    618 
    619 	pp_display_cfg->all_displays_in_sync =
    620 		context->bw_ctx.bw.dce.all_displays_in_sync;
    621 	pp_display_cfg->nb_pstate_switch_disable =
    622 			context->bw_ctx.bw.dce.nbp_state_change_enable == false;
    623 	pp_display_cfg->cpu_cc6_disable =
    624 			context->bw_ctx.bw.dce.cpuc_state_change_enable == false;
    625 	pp_display_cfg->cpu_pstate_disable =
    626 			context->bw_ctx.bw.dce.cpup_state_change_enable == false;
    627 	pp_display_cfg->cpu_pstate_separation_time =
    628 			context->bw_ctx.bw.dce.blackout_recovery_time_us;
    629 
    630 	pp_display_cfg->min_memory_clock_khz = context->bw_ctx.bw.dce.yclk_khz
    631 		/ MEMORY_TYPE_MULTIPLIER_CZ;
    632 
    633 	pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
    634 			dc,
    635 			context->bw_ctx.bw.dce.sclk_khz);
    636 
    637 	/*
    638 	 * As workaround for >4x4K lightup set dcfclock to min_engine_clock value.
    639 	 * This is not required for less than 5 displays,
    640 	 * thus don't request decfclk in dc to avoid impact
    641 	 * on power saving.
    642 	 *
    643 	 */
    644 	pp_display_cfg->min_dcfclock_khz = (context->stream_count > 4)?
    645 			pp_display_cfg->min_engine_clock_khz : 0;
    646 
    647 	pp_display_cfg->min_engine_clock_deep_sleep_khz
    648 			= context->bw_ctx.bw.dce.sclk_deep_sleep_khz;
    649 
    650 	pp_display_cfg->avail_mclk_switch_time_us =
    651 						dce110_get_min_vblank_time_us(context);
    652 	/* TODO: dce11.2*/
    653 	pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
    654 
    655 	pp_display_cfg->disp_clk_khz = dc->res_pool->clk_mgr->clks.dispclk_khz;
    656 
    657 	dce110_fill_display_configs(context, pp_display_cfg);
    658 
    659 	/* TODO: is this still applicable?*/
    660 	if (pp_display_cfg->display_count == 1) {
    661 		const struct dc_crtc_timing *timing =
    662 			&context->streams[0]->timing;
    663 
    664 		pp_display_cfg->crtc_index =
    665 			pp_display_cfg->disp_configs[0].pipe_idx;
    666 		pp_display_cfg->line_time_in_us = timing->h_total * 10000 / timing->pix_clk_100hz;
    667 	}
    668 
    669 	if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) !=  0)
    670 		dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
    671 }
    672 
    673 static void dce_update_clocks(struct clk_mgr *clk_mgr,
    674 			struct dc_state *context,
    675 			bool safe_to_lower)
    676 {
    677 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    678 	struct dm_pp_power_level_change_request level_change_req;
    679 	int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
    680 
    681 	/*TODO: W/A for dal3 linux, investigate why this works */
    682 	if (!clk_mgr_dce->dfs_bypass_active)
    683 		patched_disp_clk = patched_disp_clk * 115 / 100;
    684 
    685 	level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
    686 	/* get max clock state from PPLIB */
    687 	if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
    688 			|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
    689 		if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
    690 			clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
    691 	}
    692 
    693 	if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
    694 		patched_disp_clk = dce_set_clock(clk_mgr, patched_disp_clk);
    695 		clk_mgr->clks.dispclk_khz = patched_disp_clk;
    696 	}
    697 	dce_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
    698 }
    699 
    700 static void dce11_update_clocks(struct clk_mgr *clk_mgr,
    701 			struct dc_state *context,
    702 			bool safe_to_lower)
    703 {
    704 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    705 	struct dm_pp_power_level_change_request level_change_req;
    706 	int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
    707 
    708 	/*TODO: W/A for dal3 linux, investigate why this works */
    709 	if (!clk_mgr_dce->dfs_bypass_active)
    710 		patched_disp_clk = patched_disp_clk * 115 / 100;
    711 
    712 	level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
    713 	/* get max clock state from PPLIB */
    714 	if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
    715 			|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
    716 		if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
    717 			clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
    718 	}
    719 
    720 	if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
    721 		context->bw_ctx.bw.dce.dispclk_khz = dce_set_clock(clk_mgr, patched_disp_clk);
    722 		clk_mgr->clks.dispclk_khz = patched_disp_clk;
    723 	}
    724 	dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
    725 }
    726 
    727 static void dce112_update_clocks(struct clk_mgr *clk_mgr,
    728 			struct dc_state *context,
    729 			bool safe_to_lower)
    730 {
    731 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    732 	struct dm_pp_power_level_change_request level_change_req;
    733 	int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
    734 
    735 	/*TODO: W/A for dal3 linux, investigate why this works */
    736 	if (!clk_mgr_dce->dfs_bypass_active)
    737 		patched_disp_clk = patched_disp_clk * 115 / 100;
    738 
    739 	level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
    740 	/* get max clock state from PPLIB */
    741 	if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
    742 			|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
    743 		if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
    744 			clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
    745 	}
    746 
    747 	if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
    748 		patched_disp_clk = dce112_set_clock(clk_mgr, patched_disp_clk);
    749 		clk_mgr->clks.dispclk_khz = patched_disp_clk;
    750 	}
    751 	dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
    752 }
    753 
    754 static void dce12_update_clocks(struct clk_mgr *clk_mgr,
    755 			struct dc_state *context,
    756 			bool safe_to_lower)
    757 {
    758 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
    759 	struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
    760 	int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
    761 	int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
    762 
    763 	/*TODO: W/A for dal3 linux, investigate why this works */
    764 	if (!clk_mgr_dce->dfs_bypass_active)
    765 		patched_disp_clk = patched_disp_clk * 115 / 100;
    766 
    767 	if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
    768 		clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
    769 		/*
    770 		 * When xGMI is enabled, the display clk needs to be adjusted
    771 		 * with the WAFL link's SS percentage.
    772 		 */
    773 		if (clk_mgr_dce->xgmi_enabled)
    774 			patched_disp_clk = clk_mgr_adjust_dp_ref_freq_for_ss(
    775 					clk_mgr_dce, patched_disp_clk);
    776 		clock_voltage_req.clocks_in_khz = patched_disp_clk;
    777 		clk_mgr->clks.dispclk_khz = dce112_set_clock(clk_mgr, patched_disp_clk);
    778 
    779 		dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
    780 	}
    781 
    782 	if (should_set_clock(safe_to_lower, max_pix_clk, clk_mgr->clks.phyclk_khz)) {
    783 		clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK;
    784 		clock_voltage_req.clocks_in_khz = max_pix_clk;
    785 		clk_mgr->clks.phyclk_khz = max_pix_clk;
    786 
    787 		dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
    788 	}
    789 	dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
    790 }
    791 
    792 static const struct clk_mgr_funcs dce120_funcs = {
    793 	.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
    794 	.update_clocks = dce12_update_clocks
    795 };
    796 
    797 static const struct clk_mgr_funcs dce112_funcs = {
    798 	.get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
    799 	.update_clocks = dce112_update_clocks
    800 };
    801 
    802 static const struct clk_mgr_funcs dce110_funcs = {
    803 	.get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
    804 	.update_clocks = dce11_update_clocks,
    805 };
    806 
    807 static const struct clk_mgr_funcs dce_funcs = {
    808 	.get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
    809 	.update_clocks = dce_update_clocks
    810 };
    811 
    812 static void dce_clk_mgr_construct(
    813 	struct dce_clk_mgr *clk_mgr_dce,
    814 	struct dc_context *ctx,
    815 	const struct clk_mgr_registers *regs,
    816 	const struct clk_mgr_shift *clk_shift,
    817 	const struct clk_mgr_mask *clk_mask)
    818 {
    819 	struct clk_mgr *base = &clk_mgr_dce->base;
    820 	struct dm_pp_static_clock_info static_clk_info = {0};
    821 
    822 	base->ctx = ctx;
    823 	base->funcs = &dce_funcs;
    824 
    825 	clk_mgr_dce->regs = regs;
    826 	clk_mgr_dce->clk_mgr_shift = clk_shift;
    827 	clk_mgr_dce->clk_mgr_mask = clk_mask;
    828 
    829 	clk_mgr_dce->dfs_bypass_disp_clk = 0;
    830 
    831 	clk_mgr_dce->dprefclk_ss_percentage = 0;
    832 	clk_mgr_dce->dprefclk_ss_divider = 1000;
    833 	clk_mgr_dce->ss_on_dprefclk = false;
    834 
    835 
    836 	if (dm_pp_get_static_clocks(ctx, &static_clk_info))
    837 		clk_mgr_dce->max_clks_state = static_clk_info.max_clocks_state;
    838 	else
    839 		clk_mgr_dce->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
    840 	clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
    841 
    842 	dce_clock_read_integrated_info(clk_mgr_dce);
    843 	dce_clock_read_ss_info(clk_mgr_dce);
    844 }
    845 
    846 struct clk_mgr *dce_clk_mgr_create(
    847 	struct dc_context *ctx,
    848 	const struct clk_mgr_registers *regs,
    849 	const struct clk_mgr_shift *clk_shift,
    850 	const struct clk_mgr_mask *clk_mask)
    851 {
    852 	struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
    853 
    854 	if (clk_mgr_dce == NULL) {
    855 		BREAK_TO_DEBUGGER();
    856 		return NULL;
    857 	}
    858 
    859 	memcpy(clk_mgr_dce->max_clks_by_state,
    860 		dce80_max_clks_by_state,
    861 		sizeof(dce80_max_clks_by_state));
    862 
    863 	dce_clk_mgr_construct(
    864 		clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
    865 
    866 	return &clk_mgr_dce->base;
    867 }
    868 
    869 struct clk_mgr *dce110_clk_mgr_create(
    870 	struct dc_context *ctx,
    871 	const struct clk_mgr_registers *regs,
    872 	const struct clk_mgr_shift *clk_shift,
    873 	const struct clk_mgr_mask *clk_mask)
    874 {
    875 	struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
    876 
    877 	if (clk_mgr_dce == NULL) {
    878 		BREAK_TO_DEBUGGER();
    879 		return NULL;
    880 	}
    881 
    882 	memcpy(clk_mgr_dce->max_clks_by_state,
    883 		dce110_max_clks_by_state,
    884 		sizeof(dce110_max_clks_by_state));
    885 
    886 	dce_clk_mgr_construct(
    887 		clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
    888 
    889 	clk_mgr_dce->base.funcs = &dce110_funcs;
    890 
    891 	return &clk_mgr_dce->base;
    892 }
    893 
    894 struct clk_mgr *dce112_clk_mgr_create(
    895 	struct dc_context *ctx,
    896 	const struct clk_mgr_registers *regs,
    897 	const struct clk_mgr_shift *clk_shift,
    898 	const struct clk_mgr_mask *clk_mask)
    899 {
    900 	struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
    901 
    902 	if (clk_mgr_dce == NULL) {
    903 		BREAK_TO_DEBUGGER();
    904 		return NULL;
    905 	}
    906 
    907 	memcpy(clk_mgr_dce->max_clks_by_state,
    908 		dce112_max_clks_by_state,
    909 		sizeof(dce112_max_clks_by_state));
    910 
    911 	dce_clk_mgr_construct(
    912 		clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
    913 
    914 	clk_mgr_dce->base.funcs = &dce112_funcs;
    915 
    916 	return &clk_mgr_dce->base;
    917 }
    918 
    919 struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx)
    920 {
    921 	struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
    922 
    923 	if (clk_mgr_dce == NULL) {
    924 		BREAK_TO_DEBUGGER();
    925 		return NULL;
    926 	}
    927 
    928 	memcpy(clk_mgr_dce->max_clks_by_state,
    929 		dce120_max_clks_by_state,
    930 		sizeof(dce120_max_clks_by_state));
    931 
    932 	dce_clk_mgr_construct(
    933 		clk_mgr_dce, ctx, NULL, NULL, NULL);
    934 
    935 	clk_mgr_dce->dprefclk_khz = 600000;
    936 	clk_mgr_dce->base.funcs = &dce120_funcs;
    937 
    938 	return &clk_mgr_dce->base;
    939 }
    940 
    941 struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx)
    942 {
    943 	struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce),
    944 						  GFP_KERNEL);
    945 
    946 	if (clk_mgr_dce == NULL) {
    947 		BREAK_TO_DEBUGGER();
    948 		return NULL;
    949 	}
    950 
    951 	memcpy(clk_mgr_dce->max_clks_by_state, dce120_max_clks_by_state,
    952 	       sizeof(dce120_max_clks_by_state));
    953 
    954 	dce_clk_mgr_construct(clk_mgr_dce, ctx, NULL, NULL, NULL);
    955 
    956 	clk_mgr_dce->dprefclk_khz = 625000;
    957 	clk_mgr_dce->base.funcs = &dce120_funcs;
    958 
    959 	return &clk_mgr_dce->base;
    960 }
    961 
    962 void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr)
    963 {
    964 	struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr);
    965 
    966 	kfree(clk_mgr_dce);
    967 	*clk_mgr = NULL;
    968 }
    969