xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/display/dc/dce/amdgpu_dce_clock_source.c (revision 7e2fc62e3ca81c7bfa1d3c8d0691ddccf389ac4a)
1 /*	$NetBSD: amdgpu_dce_clock_source.c,v 1.4 2021/12/19 11:23:26 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2012-15 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: amdgpu_dce_clock_source.c,v 1.4 2021/12/19 11:23:26 riastradh Exp $");
30 
31 #include <linux/slab.h>
32 
33 #include "dm_services.h"
34 
35 
36 #include "dc_types.h"
37 #include "core_types.h"
38 
39 #include "include/grph_object_id.h"
40 #include "include/logger_interface.h"
41 
42 #include "dce_clock_source.h"
43 #include "clk_mgr.h"
44 
45 #include "reg_helper.h"
46 
47 #define REG(reg)\
48 	(clk_src->regs->reg)
49 
50 #define CTX \
51 	clk_src->base.ctx
52 
53 #define DC_LOGGER_INIT()
54 
55 #undef FN
56 #define FN(reg_name, field_name) \
57 	clk_src->cs_shift->field_name, clk_src->cs_mask->field_name
58 
59 #define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
60 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
61 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF
62 
63 #define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
64 
get_ss_data_entry(struct dce110_clk_src * clk_src,enum signal_type signal,uint32_t pix_clk_khz)65 static const struct spread_spectrum_data *get_ss_data_entry(
66 		struct dce110_clk_src *clk_src,
67 		enum signal_type signal,
68 		uint32_t pix_clk_khz)
69 {
70 
71 	uint32_t entrys_num;
72 	uint32_t i;
73 	struct spread_spectrum_data *ss_parm = NULL;
74 	struct spread_spectrum_data *ret = NULL;
75 
76 	switch (signal) {
77 	case SIGNAL_TYPE_DVI_SINGLE_LINK:
78 	case SIGNAL_TYPE_DVI_DUAL_LINK:
79 		ss_parm = clk_src->dvi_ss_params;
80 		entrys_num = clk_src->dvi_ss_params_cnt;
81 		break;
82 
83 	case SIGNAL_TYPE_HDMI_TYPE_A:
84 		ss_parm = clk_src->hdmi_ss_params;
85 		entrys_num = clk_src->hdmi_ss_params_cnt;
86 		break;
87 
88 	case SIGNAL_TYPE_LVDS:
89 		ss_parm = clk_src->lvds_ss_params;
90 		entrys_num = clk_src->lvds_ss_params_cnt;
91 		break;
92 
93 	case SIGNAL_TYPE_DISPLAY_PORT:
94 	case SIGNAL_TYPE_DISPLAY_PORT_MST:
95 	case SIGNAL_TYPE_EDP:
96 	case SIGNAL_TYPE_VIRTUAL:
97 		ss_parm = clk_src->dp_ss_params;
98 		entrys_num = clk_src->dp_ss_params_cnt;
99 		break;
100 
101 	default:
102 		ss_parm = NULL;
103 		entrys_num = 0;
104 		break;
105 	}
106 
107 	if (ss_parm == NULL)
108 		return ret;
109 
110 	for (i = 0; i < entrys_num; ++i, ++ss_parm) {
111 		if (ss_parm->freq_range_khz >= pix_clk_khz) {
112 			ret = ss_parm;
113 			break;
114 		}
115 	}
116 
117 	return ret;
118 }
119 
120 /**
121  * Function: calculate_fb_and_fractional_fb_divider
122  *
123  * * DESCRIPTION: Calculates feedback and fractional feedback dividers values
124  *
125  *PARAMETERS:
126  * targetPixelClock             Desired frequency in 100 Hz
127  * ref_divider                  Reference divider (already known)
128  * postDivider                  Post Divider (already known)
129  * feedback_divider_param       Pointer where to store
130  *					calculated feedback divider value
131  * fract_feedback_divider_param Pointer where to store
132  *					calculated fract feedback divider value
133  *
134  *RETURNS:
135  * It fills the locations pointed by feedback_divider_param
136  *					and fract_feedback_divider_param
137  * It returns	- true if feedback divider not 0
138  *		- false should never happen)
139  */
calculate_fb_and_fractional_fb_divider(struct calc_pll_clock_source * calc_pll_cs,uint32_t target_pix_clk_100hz,uint32_t ref_divider,uint32_t post_divider,uint32_t * feedback_divider_param,uint32_t * fract_feedback_divider_param)140 static bool calculate_fb_and_fractional_fb_divider(
141 		struct calc_pll_clock_source *calc_pll_cs,
142 		uint32_t target_pix_clk_100hz,
143 		uint32_t ref_divider,
144 		uint32_t post_divider,
145 		uint32_t *feedback_divider_param,
146 		uint32_t *fract_feedback_divider_param)
147 {
148 	uint64_t feedback_divider;
149 
150 	feedback_divider =
151 		(uint64_t)target_pix_clk_100hz * ref_divider * post_divider;
152 	feedback_divider *= 10;
153 	/* additional factor, since we divide by 10 afterwards */
154 	feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
155 	feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz * 10ull);
156 
157 /*Round to the number of precision
158  * The following code replace the old code (ullfeedbackDivider + 5)/10
159  * for example if the difference between the number
160  * of fractional feedback decimal point and the fractional FB Divider precision
161  * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
162 
163 	feedback_divider += 5ULL *
164 			    calc_pll_cs->fract_fb_divider_precision_factor;
165 	feedback_divider =
166 		div_u64(feedback_divider,
167 			calc_pll_cs->fract_fb_divider_precision_factor * 10);
168 	feedback_divider *= (uint64_t)
169 			(calc_pll_cs->fract_fb_divider_precision_factor);
170 
171 	*feedback_divider_param =
172 		div_u64_rem(
173 			feedback_divider,
174 			calc_pll_cs->fract_fb_divider_factor,
175 			fract_feedback_divider_param);
176 
177 	if (*feedback_divider_param != 0)
178 		return true;
179 	return false;
180 }
181 
182 /**
183 *calc_fb_divider_checking_tolerance
184 *
185 *DESCRIPTION: Calculates Feedback and Fractional Feedback divider values
186 *		for passed Reference and Post divider, checking for tolerance.
187 *PARAMETERS:
188 * pll_settings		Pointer to structure
189 * ref_divider		Reference divider (already known)
190 * postDivider		Post Divider (already known)
191 * tolerance		Tolerance for Calculated Pixel Clock to be within
192 *
193 *RETURNS:
194 * It fills the PLLSettings structure with PLL Dividers values
195 * if calculated values are within required tolerance
196 * It returns	- true if error is within tolerance
197 *		- false if error is not within tolerance
198 */
calc_fb_divider_checking_tolerance(struct calc_pll_clock_source * calc_pll_cs,struct pll_settings * pll_settings,uint32_t ref_divider,uint32_t post_divider,uint32_t tolerance)199 static bool calc_fb_divider_checking_tolerance(
200 		struct calc_pll_clock_source *calc_pll_cs,
201 		struct pll_settings *pll_settings,
202 		uint32_t ref_divider,
203 		uint32_t post_divider,
204 		uint32_t tolerance)
205 {
206 	uint32_t feedback_divider;
207 	uint32_t fract_feedback_divider;
208 	uint32_t actual_calculated_clock_100hz;
209 	uint32_t abs_err;
210 	uint64_t actual_calc_clk_100hz;
211 
212 	calculate_fb_and_fractional_fb_divider(
213 			calc_pll_cs,
214 			pll_settings->adjusted_pix_clk_100hz,
215 			ref_divider,
216 			post_divider,
217 			&feedback_divider,
218 			&fract_feedback_divider);
219 
220 	/*Actual calculated value*/
221 	actual_calc_clk_100hz = (uint64_t)feedback_divider *
222 					calc_pll_cs->fract_fb_divider_factor +
223 							fract_feedback_divider;
224 	actual_calc_clk_100hz *= calc_pll_cs->ref_freq_khz * 10;
225 	actual_calc_clk_100hz =
226 		div_u64(actual_calc_clk_100hz,
227 			ref_divider * post_divider *
228 				calc_pll_cs->fract_fb_divider_factor);
229 
230 	actual_calculated_clock_100hz = (uint32_t)(actual_calc_clk_100hz);
231 
232 	abs_err = (actual_calculated_clock_100hz >
233 					pll_settings->adjusted_pix_clk_100hz)
234 			? actual_calculated_clock_100hz -
235 					pll_settings->adjusted_pix_clk_100hz
236 			: pll_settings->adjusted_pix_clk_100hz -
237 						actual_calculated_clock_100hz;
238 
239 	if (abs_err <= tolerance) {
240 		/*found good values*/
241 		pll_settings->reference_freq = calc_pll_cs->ref_freq_khz;
242 		pll_settings->reference_divider = ref_divider;
243 		pll_settings->feedback_divider = feedback_divider;
244 		pll_settings->fract_feedback_divider = fract_feedback_divider;
245 		pll_settings->pix_clk_post_divider = post_divider;
246 		pll_settings->calculated_pix_clk_100hz =
247 			actual_calculated_clock_100hz;
248 		pll_settings->vco_freq =
249 			actual_calculated_clock_100hz * post_divider / 10;
250 		return true;
251 	}
252 	return false;
253 }
254 
calc_pll_dividers_in_range(struct calc_pll_clock_source * calc_pll_cs,struct pll_settings * pll_settings,uint32_t min_ref_divider,uint32_t max_ref_divider,uint32_t min_post_divider,uint32_t max_post_divider,uint32_t err_tolerance)255 static bool calc_pll_dividers_in_range(
256 		struct calc_pll_clock_source *calc_pll_cs,
257 		struct pll_settings *pll_settings,
258 		uint32_t min_ref_divider,
259 		uint32_t max_ref_divider,
260 		uint32_t min_post_divider,
261 		uint32_t max_post_divider,
262 		uint32_t err_tolerance)
263 {
264 	uint32_t ref_divider;
265 	uint32_t post_divider;
266 	uint32_t tolerance;
267 
268 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
269  * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
270 	tolerance = (pll_settings->adjusted_pix_clk_100hz * err_tolerance) /
271 									100000;
272 	if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
273 		tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
274 
275 	for (
276 			post_divider = max_post_divider;
277 			post_divider >= min_post_divider;
278 			--post_divider) {
279 		for (
280 				ref_divider = min_ref_divider;
281 				ref_divider <= max_ref_divider;
282 				++ref_divider) {
283 			if (calc_fb_divider_checking_tolerance(
284 					calc_pll_cs,
285 					pll_settings,
286 					ref_divider,
287 					post_divider,
288 					tolerance)) {
289 				return true;
290 			}
291 		}
292 	}
293 
294 	return false;
295 }
296 
calculate_pixel_clock_pll_dividers(struct calc_pll_clock_source * calc_pll_cs,struct pll_settings * pll_settings)297 static uint32_t calculate_pixel_clock_pll_dividers(
298 		struct calc_pll_clock_source *calc_pll_cs,
299 		struct pll_settings *pll_settings)
300 {
301 	uint32_t err_tolerance;
302 	uint32_t min_post_divider;
303 	uint32_t max_post_divider;
304 	uint32_t min_ref_divider;
305 	uint32_t max_ref_divider;
306 
307 	if (pll_settings->adjusted_pix_clk_100hz == 0) {
308 		DC_LOG_ERROR(
309 			"%s Bad requested pixel clock", __func__);
310 		return MAX_PLL_CALC_ERROR;
311 	}
312 
313 /* 1) Find Post divider ranges */
314 	if (pll_settings->pix_clk_post_divider) {
315 		min_post_divider = pll_settings->pix_clk_post_divider;
316 		max_post_divider = pll_settings->pix_clk_post_divider;
317 	} else {
318 		min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
319 		if (min_post_divider * pll_settings->adjusted_pix_clk_100hz <
320 						calc_pll_cs->min_vco_khz * 10) {
321 			min_post_divider = calc_pll_cs->min_vco_khz * 10 /
322 					pll_settings->adjusted_pix_clk_100hz;
323 			if ((min_post_divider *
324 					pll_settings->adjusted_pix_clk_100hz) <
325 						calc_pll_cs->min_vco_khz * 10)
326 				min_post_divider++;
327 		}
328 
329 		max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
330 		if (max_post_divider * pll_settings->adjusted_pix_clk_100hz
331 				> calc_pll_cs->max_vco_khz * 10)
332 			max_post_divider = calc_pll_cs->max_vco_khz * 10 /
333 					pll_settings->adjusted_pix_clk_100hz;
334 	}
335 
336 /* 2) Find Reference divider ranges
337  * When SS is enabled, or for Display Port even without SS,
338  * pll_settings->referenceDivider is not zero.
339  * So calculate PPLL FB and fractional FB divider
340  * using the passed reference divider*/
341 
342 	if (pll_settings->reference_divider) {
343 		min_ref_divider = pll_settings->reference_divider;
344 		max_ref_divider = pll_settings->reference_divider;
345 	} else {
346 		min_ref_divider = ((calc_pll_cs->ref_freq_khz
347 				/ calc_pll_cs->max_pll_input_freq_khz)
348 				> calc_pll_cs->min_pll_ref_divider)
349 			? calc_pll_cs->ref_freq_khz
350 					/ calc_pll_cs->max_pll_input_freq_khz
351 			: calc_pll_cs->min_pll_ref_divider;
352 
353 		max_ref_divider = ((calc_pll_cs->ref_freq_khz
354 				/ calc_pll_cs->min_pll_input_freq_khz)
355 				< calc_pll_cs->max_pll_ref_divider)
356 			? calc_pll_cs->ref_freq_khz /
357 					calc_pll_cs->min_pll_input_freq_khz
358 			: calc_pll_cs->max_pll_ref_divider;
359 	}
360 
361 /* If some parameters are invalid we could have scenario when  "min">"max"
362  * which produced endless loop later.
363  * We should investigate why we get the wrong parameters.
364  * But to follow the similar logic when "adjustedPixelClock" is set to be 0
365  * it is better to return here than cause system hang/watchdog timeout later.
366  *  ## SVS Wed 15 Jul 2009 */
367 
368 	if (min_post_divider > max_post_divider) {
369 		DC_LOG_ERROR(
370 			"%s Post divider range is invalid", __func__);
371 		return MAX_PLL_CALC_ERROR;
372 	}
373 
374 	if (min_ref_divider > max_ref_divider) {
375 		DC_LOG_ERROR(
376 			"%s Reference divider range is invalid", __func__);
377 		return MAX_PLL_CALC_ERROR;
378 	}
379 
380 /* 3) Try to find PLL dividers given ranges
381  * starting with minimal error tolerance.
382  * Increase error tolerance until PLL dividers found*/
383 	err_tolerance = MAX_PLL_CALC_ERROR;
384 
385 	while (!calc_pll_dividers_in_range(
386 			calc_pll_cs,
387 			pll_settings,
388 			min_ref_divider,
389 			max_ref_divider,
390 			min_post_divider,
391 			max_post_divider,
392 			err_tolerance))
393 		err_tolerance += (err_tolerance > 10)
394 				? (err_tolerance / 10)
395 				: 1;
396 
397 	return err_tolerance;
398 }
399 
pll_adjust_pix_clk(struct dce110_clk_src * clk_src,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)400 static bool pll_adjust_pix_clk(
401 		struct dce110_clk_src *clk_src,
402 		struct pixel_clk_params *pix_clk_params,
403 		struct pll_settings *pll_settings)
404 {
405 	uint32_t actual_pix_clk_100hz = 0;
406 	uint32_t requested_clk_100hz = 0;
407 	struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
408 							0 };
409 	enum bp_result bp_result;
410 	switch (pix_clk_params->signal_type) {
411 	case SIGNAL_TYPE_HDMI_TYPE_A: {
412 		requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
413 		if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
414 			switch (pix_clk_params->color_depth) {
415 			case COLOR_DEPTH_101010:
416 				requested_clk_100hz = (requested_clk_100hz * 5) >> 2;
417 				break; /* x1.25*/
418 			case COLOR_DEPTH_121212:
419 				requested_clk_100hz = (requested_clk_100hz * 6) >> 2;
420 				break; /* x1.5*/
421 			case COLOR_DEPTH_161616:
422 				requested_clk_100hz = requested_clk_100hz * 2;
423 				break; /* x2.0*/
424 			default:
425 				break;
426 			}
427 		}
428 		actual_pix_clk_100hz = requested_clk_100hz;
429 	}
430 		break;
431 
432 	case SIGNAL_TYPE_DISPLAY_PORT:
433 	case SIGNAL_TYPE_DISPLAY_PORT_MST:
434 	case SIGNAL_TYPE_EDP:
435 		requested_clk_100hz = pix_clk_params->requested_sym_clk * 10;
436 		actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
437 		break;
438 
439 	default:
440 		requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
441 		actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
442 		break;
443 	}
444 
445 	bp_adjust_pixel_clock_params.pixel_clock = requested_clk_100hz / 10;
446 	bp_adjust_pixel_clock_params.
447 		encoder_object_id = pix_clk_params->encoder_object_id;
448 	bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
449 	bp_adjust_pixel_clock_params.
450 		ss_enable = pix_clk_params->flags.ENABLE_SS;
451 	bp_result = clk_src->bios->funcs->adjust_pixel_clock(
452 			clk_src->bios, &bp_adjust_pixel_clock_params);
453 	if (bp_result == BP_RESULT_OK) {
454 		pll_settings->actual_pix_clk_100hz = actual_pix_clk_100hz;
455 		pll_settings->adjusted_pix_clk_100hz =
456 			bp_adjust_pixel_clock_params.adjusted_pixel_clock * 10;
457 		pll_settings->reference_divider =
458 			bp_adjust_pixel_clock_params.reference_divider;
459 		pll_settings->pix_clk_post_divider =
460 			bp_adjust_pixel_clock_params.pixel_clock_post_divider;
461 
462 		return true;
463 	}
464 
465 	return false;
466 }
467 
468 /**
469  * Calculate PLL Dividers for given Clock Value.
470  * First will call VBIOS Adjust Exec table to check if requested Pixel clock
471  * will be Adjusted based on usage.
472  * Then it will calculate PLL Dividers for this Adjusted clock using preferred
473  * method (Maximum VCO frequency).
474  *
475  * \return
476  *     Calculation error in units of 0.01%
477  */
478 
dce110_get_pix_clk_dividers_helper(struct dce110_clk_src * clk_src,struct pll_settings * pll_settings,struct pixel_clk_params * pix_clk_params)479 static uint32_t dce110_get_pix_clk_dividers_helper (
480 		struct dce110_clk_src *clk_src,
481 		struct pll_settings *pll_settings,
482 		struct pixel_clk_params *pix_clk_params)
483 {
484 	uint32_t field = 0;
485 	uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
486 	DC_LOGGER_INIT();
487 	/* Check if reference clock is external (not pcie/xtalin)
488 	* HW Dce80 spec:
489 	* 00 - PCIE_REFCLK, 01 - XTALIN,    02 - GENERICA,    03 - GENERICB
490 	* 04 - HSYNCA,      05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
491 	REG_GET(PLL_CNTL, PLL_REF_DIV_SRC, &field);
492 	pll_settings->use_external_clk = (field > 1);
493 
494 	/* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
495 	 * (we do not care any more from SI for some older DP Sink which
496 	 * does not report SS support, no known issues) */
497 	if ((pix_clk_params->flags.ENABLE_SS) ||
498 			(dc_is_dp_signal(pix_clk_params->signal_type))) {
499 
500 		const struct spread_spectrum_data *ss_data = get_ss_data_entry(
501 					clk_src,
502 					pix_clk_params->signal_type,
503 					pll_settings->adjusted_pix_clk_100hz / 10);
504 
505 		if (NULL != ss_data)
506 			pll_settings->ss_percentage = ss_data->percentage;
507 	}
508 
509 	/* Check VBIOS AdjustPixelClock Exec table */
510 	if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) {
511 		/* Should never happen, ASSERT and fill up values to be able
512 		 * to continue. */
513 		DC_LOG_ERROR(
514 			"%s: Failed to adjust pixel clock!!", __func__);
515 		pll_settings->actual_pix_clk_100hz =
516 				pix_clk_params->requested_pix_clk_100hz;
517 		pll_settings->adjusted_pix_clk_100hz =
518 				pix_clk_params->requested_pix_clk_100hz;
519 
520 		if (dc_is_dp_signal(pix_clk_params->signal_type))
521 			pll_settings->adjusted_pix_clk_100hz = 1000000;
522 	}
523 
524 	/* Calculate Dividers */
525 	if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
526 		/*Calculate Dividers by HDMI object, no SS case or SS case */
527 		pll_calc_error =
528 			calculate_pixel_clock_pll_dividers(
529 					&clk_src->calc_pll_hdmi,
530 					pll_settings);
531 	else
532 		/*Calculate Dividers by default object, no SS case or SS case */
533 		pll_calc_error =
534 			calculate_pixel_clock_pll_dividers(
535 					&clk_src->calc_pll,
536 					pll_settings);
537 
538 	return pll_calc_error;
539 }
540 
dce112_get_pix_clk_dividers_helper(struct dce110_clk_src * clk_src,struct pll_settings * pll_settings,struct pixel_clk_params * pix_clk_params)541 static void dce112_get_pix_clk_dividers_helper (
542 		struct dce110_clk_src *clk_src,
543 		struct pll_settings *pll_settings,
544 		struct pixel_clk_params *pix_clk_params)
545 {
546 	uint32_t actual_pixel_clock_100hz;
547 
548 	actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz;
549 	/* Calculate Dividers */
550 	if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
551 		switch (pix_clk_params->color_depth) {
552 		case COLOR_DEPTH_101010:
553 			actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
554 			break;
555 		case COLOR_DEPTH_121212:
556 			actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
557 			break;
558 		case COLOR_DEPTH_161616:
559 			actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
560 			break;
561 		default:
562 			break;
563 		}
564 	}
565 	pll_settings->actual_pix_clk_100hz = actual_pixel_clock_100hz;
566 	pll_settings->adjusted_pix_clk_100hz = actual_pixel_clock_100hz;
567 	pll_settings->calculated_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
568 }
569 
dce110_get_pix_clk_dividers(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)570 static uint32_t dce110_get_pix_clk_dividers(
571 		struct clock_source *cs,
572 		struct pixel_clk_params *pix_clk_params,
573 		struct pll_settings *pll_settings)
574 {
575 	struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
576 	uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
577 	DC_LOGGER_INIT();
578 
579 	if (pix_clk_params == NULL || pll_settings == NULL
580 			|| pix_clk_params->requested_pix_clk_100hz == 0) {
581 		DC_LOG_ERROR(
582 			"%s: Invalid parameters!!\n", __func__);
583 		return pll_calc_error;
584 	}
585 
586 	memset(pll_settings, 0, sizeof(*pll_settings));
587 
588 	if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
589 			cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
590 		pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
591 		pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
592 		pll_settings->actual_pix_clk_100hz =
593 					pix_clk_params->requested_pix_clk_100hz;
594 		return 0;
595 	}
596 
597 	pll_calc_error = dce110_get_pix_clk_dividers_helper(clk_src,
598 			pll_settings, pix_clk_params);
599 
600 	return pll_calc_error;
601 }
602 
dce112_get_pix_clk_dividers(struct clock_source * cs,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)603 static uint32_t dce112_get_pix_clk_dividers(
604 		struct clock_source *cs,
605 		struct pixel_clk_params *pix_clk_params,
606 		struct pll_settings *pll_settings)
607 {
608 	struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
609 	DC_LOGGER_INIT();
610 
611 	if (pix_clk_params == NULL || pll_settings == NULL
612 			|| pix_clk_params->requested_pix_clk_100hz == 0) {
613 		DC_LOG_ERROR(
614 			"%s: Invalid parameters!!\n", __func__);
615 		return -1;
616 	}
617 
618 	memset(pll_settings, 0, sizeof(*pll_settings));
619 
620 	if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
621 			cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
622 		pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
623 		pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
624 		pll_settings->actual_pix_clk_100hz =
625 					pix_clk_params->requested_pix_clk_100hz;
626 		return -1;
627 	}
628 
629 	dce112_get_pix_clk_dividers_helper(clk_src,
630 			pll_settings, pix_clk_params);
631 
632 	return 0;
633 }
634 
disable_spread_spectrum(struct dce110_clk_src * clk_src)635 static bool disable_spread_spectrum(struct dce110_clk_src *clk_src)
636 {
637 	enum bp_result result;
638 	struct bp_spread_spectrum_parameters bp_ss_params = {0};
639 
640 	bp_ss_params.pll_id = clk_src->base.id;
641 
642 	/*Call ASICControl to process ATOMBIOS Exec table*/
643 	result = clk_src->bios->funcs->enable_spread_spectrum_on_ppll(
644 			clk_src->bios,
645 			&bp_ss_params,
646 			false);
647 
648 	return result == BP_RESULT_OK;
649 }
650 
calculate_ss(const struct pll_settings * pll_settings,const struct spread_spectrum_data * ss_data,struct delta_sigma_data * ds_data)651 static bool calculate_ss(
652 		const struct pll_settings *pll_settings,
653 		const struct spread_spectrum_data *ss_data,
654 		struct delta_sigma_data *ds_data)
655 {
656 	struct fixed31_32 fb_div;
657 	struct fixed31_32 ss_amount;
658 	struct fixed31_32 ss_nslip_amount;
659 	struct fixed31_32 ss_ds_frac_amount;
660 	struct fixed31_32 ss_step_size;
661 	struct fixed31_32 modulation_time;
662 
663 	if (ds_data == NULL)
664 		return false;
665 	if (ss_data == NULL)
666 		return false;
667 	if (ss_data->percentage == 0)
668 		return false;
669 	if (pll_settings == NULL)
670 		return false;
671 
672 	memset(ds_data, 0, sizeof(struct delta_sigma_data));
673 
674 	/* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
675 	/* 6 decimal point support in fractional feedback divider */
676 	fb_div  = dc_fixpt_from_fraction(
677 		pll_settings->fract_feedback_divider, 1000000);
678 	fb_div = dc_fixpt_add_int(fb_div, pll_settings->feedback_divider);
679 
680 	ds_data->ds_frac_amount = 0;
681 	/*spreadSpectrumPercentage is in the unit of .01%,
682 	 * so have to divided by 100 * 100*/
683 	ss_amount = dc_fixpt_mul(
684 		fb_div, dc_fixpt_from_fraction(ss_data->percentage,
685 					100 * ss_data->percentage_divider));
686 	ds_data->feedback_amount = dc_fixpt_floor(ss_amount);
687 
688 	ss_nslip_amount = dc_fixpt_sub(ss_amount,
689 		dc_fixpt_from_int(ds_data->feedback_amount));
690 	ss_nslip_amount = dc_fixpt_mul_int(ss_nslip_amount, 10);
691 	ds_data->nfrac_amount = dc_fixpt_floor(ss_nslip_amount);
692 
693 	ss_ds_frac_amount = dc_fixpt_sub(ss_nslip_amount,
694 		dc_fixpt_from_int(ds_data->nfrac_amount));
695 	ss_ds_frac_amount = dc_fixpt_mul_int(ss_ds_frac_amount, 65536);
696 	ds_data->ds_frac_amount = dc_fixpt_floor(ss_ds_frac_amount);
697 
698 	/* compute SS_STEP_SIZE_DSFRAC */
699 	modulation_time = dc_fixpt_from_fraction(
700 		pll_settings->reference_freq * 1000,
701 		pll_settings->reference_divider * ss_data->modulation_freq_hz);
702 
703 	if (ss_data->flags.CENTER_SPREAD)
704 		modulation_time = dc_fixpt_div_int(modulation_time, 4);
705 	else
706 		modulation_time = dc_fixpt_div_int(modulation_time, 2);
707 
708 	ss_step_size = dc_fixpt_div(ss_amount, modulation_time);
709 	/* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
710 	ss_step_size = dc_fixpt_mul_int(ss_step_size, 65536 * 10);
711 	ds_data->ds_frac_size =  dc_fixpt_floor(ss_step_size);
712 
713 	return true;
714 }
715 
enable_spread_spectrum(struct dce110_clk_src * clk_src,enum signal_type signal,struct pll_settings * pll_settings)716 static bool enable_spread_spectrum(
717 		struct dce110_clk_src *clk_src,
718 		enum signal_type signal, struct pll_settings *pll_settings)
719 {
720 	struct bp_spread_spectrum_parameters bp_params = {0};
721 	struct delta_sigma_data d_s_data;
722 	const struct spread_spectrum_data *ss_data = NULL;
723 
724 	ss_data = get_ss_data_entry(
725 			clk_src,
726 			signal,
727 			pll_settings->calculated_pix_clk_100hz / 10);
728 
729 /* Pixel clock PLL has been programmed to generate desired pixel clock,
730  * now enable SS on pixel clock */
731 /* TODO is it OK to return true not doing anything ??*/
732 	if (ss_data != NULL && pll_settings->ss_percentage != 0) {
733 		if (calculate_ss(pll_settings, ss_data, &d_s_data)) {
734 			bp_params.ds.feedback_amount =
735 					d_s_data.feedback_amount;
736 			bp_params.ds.nfrac_amount =
737 					d_s_data.nfrac_amount;
738 			bp_params.ds.ds_frac_size = d_s_data.ds_frac_size;
739 			bp_params.ds_frac_amount =
740 					d_s_data.ds_frac_amount;
741 			bp_params.flags.DS_TYPE = 1;
742 			bp_params.pll_id = clk_src->base.id;
743 			bp_params.percentage = ss_data->percentage;
744 			if (ss_data->flags.CENTER_SPREAD)
745 				bp_params.flags.CENTER_SPREAD = 1;
746 			if (ss_data->flags.EXTERNAL_SS)
747 				bp_params.flags.EXTERNAL_SS = 1;
748 
749 			if (BP_RESULT_OK !=
750 				clk_src->bios->funcs->
751 					enable_spread_spectrum_on_ppll(
752 							clk_src->bios,
753 							&bp_params,
754 							true))
755 				return false;
756 		} else
757 			return false;
758 	}
759 	return true;
760 }
761 
dce110_program_pixel_clk_resync(struct dce110_clk_src * clk_src,enum signal_type signal_type,enum dc_color_depth colordepth)762 static void dce110_program_pixel_clk_resync(
763 		struct dce110_clk_src *clk_src,
764 		enum signal_type signal_type,
765 		enum dc_color_depth colordepth)
766 {
767 	REG_UPDATE(RESYNC_CNTL,
768 			DCCG_DEEP_COLOR_CNTL1, 0);
769 	/*
770 	 24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
771 	 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
772 	 36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
773 	 48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
774 	 */
775 	if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
776 		return;
777 
778 	switch (colordepth) {
779 	case COLOR_DEPTH_888:
780 		REG_UPDATE(RESYNC_CNTL,
781 				DCCG_DEEP_COLOR_CNTL1, 0);
782 		break;
783 	case COLOR_DEPTH_101010:
784 		REG_UPDATE(RESYNC_CNTL,
785 				DCCG_DEEP_COLOR_CNTL1, 1);
786 		break;
787 	case COLOR_DEPTH_121212:
788 		REG_UPDATE(RESYNC_CNTL,
789 				DCCG_DEEP_COLOR_CNTL1, 2);
790 		break;
791 	case COLOR_DEPTH_161616:
792 		REG_UPDATE(RESYNC_CNTL,
793 				DCCG_DEEP_COLOR_CNTL1, 3);
794 		break;
795 	default:
796 		break;
797 	}
798 }
799 
dce112_program_pixel_clk_resync(struct dce110_clk_src * clk_src,enum signal_type signal_type,enum dc_color_depth colordepth,bool enable_ycbcr420)800 static void dce112_program_pixel_clk_resync(
801 		struct dce110_clk_src *clk_src,
802 		enum signal_type signal_type,
803 		enum dc_color_depth colordepth,
804 		bool enable_ycbcr420)
805 {
806 	uint32_t deep_color_cntl = 0;
807 	uint32_t double_rate_enable = 0;
808 
809 	/*
810 	 24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
811 	 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
812 	 36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
813 	 48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
814 	 */
815 	if (signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
816 		double_rate_enable = enable_ycbcr420 ? 1 : 0;
817 
818 		switch (colordepth) {
819 		case COLOR_DEPTH_888:
820 			deep_color_cntl = 0;
821 			break;
822 		case COLOR_DEPTH_101010:
823 			deep_color_cntl = 1;
824 			break;
825 		case COLOR_DEPTH_121212:
826 			deep_color_cntl = 2;
827 			break;
828 		case COLOR_DEPTH_161616:
829 			deep_color_cntl = 3;
830 			break;
831 		default:
832 			break;
833 		}
834 	}
835 
836 	if (clk_src->cs_mask->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE)
837 		REG_UPDATE_2(PIXCLK_RESYNC_CNTL,
838 				PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl,
839 				PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, double_rate_enable);
840 	else
841 		REG_UPDATE(PIXCLK_RESYNC_CNTL,
842 				PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl);
843 
844 }
845 
dce110_program_pix_clk(struct clock_source * clock_source,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)846 static bool dce110_program_pix_clk(
847 		struct clock_source *clock_source,
848 		struct pixel_clk_params *pix_clk_params,
849 		struct pll_settings *pll_settings)
850 {
851 	struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
852 	struct bp_pixel_clock_parameters bp_pc_params = {0};
853 
854 	/* First disable SS
855 	 * ATOMBIOS will enable by default SS on PLL for DP,
856 	 * do not disable it here
857 	 */
858 	if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL &&
859 			!dc_is_dp_signal(pix_clk_params->signal_type) &&
860 			clock_source->ctx->dce_version <= DCE_VERSION_11_0)
861 		disable_spread_spectrum(clk_src);
862 
863 	/*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
864 	bp_pc_params.controller_id = pix_clk_params->controller_id;
865 	bp_pc_params.pll_id = clock_source->id;
866 	bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
867 	bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
868 	bp_pc_params.signal_type = pix_clk_params->signal_type;
869 
870 	bp_pc_params.reference_divider = pll_settings->reference_divider;
871 	bp_pc_params.feedback_divider = pll_settings->feedback_divider;
872 	bp_pc_params.fractional_feedback_divider =
873 			pll_settings->fract_feedback_divider;
874 	bp_pc_params.pixel_clock_post_divider =
875 			pll_settings->pix_clk_post_divider;
876 	bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
877 					pll_settings->use_external_clk;
878 
879 	if (clk_src->bios->funcs->set_pixel_clock(
880 			clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
881 		return false;
882 	/* Enable SS
883 	 * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
884 	 * based on HW display PLL team, SS control settings should be programmed
885 	 * during PLL Reset, but they do not have effect
886 	 * until SS_EN is asserted.*/
887 	if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL
888 			&& !dc_is_dp_signal(pix_clk_params->signal_type)) {
889 
890 		if (pix_clk_params->flags.ENABLE_SS)
891 			if (!enable_spread_spectrum(clk_src,
892 							pix_clk_params->signal_type,
893 							pll_settings))
894 				return false;
895 
896 		/* Resync deep color DTO */
897 		dce110_program_pixel_clk_resync(clk_src,
898 					pix_clk_params->signal_type,
899 					pix_clk_params->color_depth);
900 	}
901 
902 	return true;
903 }
904 
dce112_program_pix_clk(struct clock_source * clock_source,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)905 static bool dce112_program_pix_clk(
906 		struct clock_source *clock_source,
907 		struct pixel_clk_params *pix_clk_params,
908 		struct pll_settings *pll_settings)
909 {
910 	struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
911 	struct bp_pixel_clock_parameters bp_pc_params = {0};
912 
913 #if defined(CONFIG_DRM_AMD_DC_DCN)
914 	if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
915 		unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
916 		unsigned dp_dto_ref_100hz = 7000000;
917 		unsigned clock_100hz = pll_settings->actual_pix_clk_100hz;
918 
919 		/* Set DTO values: phase = target clock, modulo = reference clock */
920 		REG_WRITE(PHASE[inst], clock_100hz);
921 		REG_WRITE(MODULO[inst], dp_dto_ref_100hz);
922 
923 		/* Enable DTO */
924 		REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
925 		return true;
926 	}
927 #endif
928 	/* First disable SS
929 	 * ATOMBIOS will enable by default SS on PLL for DP,
930 	 * do not disable it here
931 	 */
932 	if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL &&
933 			!dc_is_dp_signal(pix_clk_params->signal_type) &&
934 			clock_source->ctx->dce_version <= DCE_VERSION_11_0)
935 		disable_spread_spectrum(clk_src);
936 
937 	/*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
938 	bp_pc_params.controller_id = pix_clk_params->controller_id;
939 	bp_pc_params.pll_id = clock_source->id;
940 	bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
941 	bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
942 	bp_pc_params.signal_type = pix_clk_params->signal_type;
943 
944 	if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
945 		bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
946 						pll_settings->use_external_clk;
947 		bp_pc_params.flags.SET_XTALIN_REF_SRC =
948 						!pll_settings->use_external_clk;
949 		if (pix_clk_params->flags.SUPPORT_YCBCR420) {
950 			bp_pc_params.flags.SUPPORT_YUV_420 = 1;
951 		}
952 	}
953 	if (clk_src->bios->funcs->set_pixel_clock(
954 			clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
955 		return false;
956 	/* Resync deep color DTO */
957 	if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
958 		dce112_program_pixel_clk_resync(clk_src,
959 					pix_clk_params->signal_type,
960 					pix_clk_params->color_depth,
961 					pix_clk_params->flags.SUPPORT_YCBCR420);
962 
963 	return true;
964 }
965 
966 
dce110_clock_source_power_down(struct clock_source * clk_src)967 static bool dce110_clock_source_power_down(
968 		struct clock_source *clk_src)
969 {
970 	struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src);
971 	enum bp_result bp_result;
972 	struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
973 
974 	if (clk_src->dp_clk_src)
975 		return true;
976 
977 	/* If Pixel Clock is 0 it means Power Down Pll*/
978 	bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
979 	bp_pixel_clock_params.pll_id = clk_src->id;
980 	bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
981 
982 	/*Call ASICControl to process ATOMBIOS Exec table*/
983 	bp_result = dce110_clk_src->bios->funcs->set_pixel_clock(
984 			dce110_clk_src->bios,
985 			&bp_pixel_clock_params);
986 
987 	return bp_result == BP_RESULT_OK;
988 }
989 
get_pixel_clk_frequency_100hz(struct clock_source * clock_source,unsigned int inst,unsigned int * pixel_clk_khz)990 static bool get_pixel_clk_frequency_100hz(
991 		struct clock_source *clock_source,
992 		unsigned int inst,
993 		unsigned int *pixel_clk_khz)
994 {
995 	struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
996 	unsigned int clock_hz = 0;
997 
998 	if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
999 		clock_hz = REG_READ(PHASE[inst]);
1000 
1001 		/* NOTE: There is agreement with VBIOS here that MODULO is
1002 		 * programmed equal to DPREFCLK, in which case PHASE will be
1003 		 * equivalent to pixel clock.
1004 		 */
1005 		*pixel_clk_khz = clock_hz / 100;
1006 		return true;
1007 	}
1008 
1009 	return false;
1010 }
1011 
1012 
1013 /* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
1014 struct pixel_rate_range_table_entry {
1015 	unsigned int range_min_khz;
1016 	unsigned int range_max_khz;
1017 	unsigned int target_pixel_rate_khz;
1018 	unsigned short mult_factor;
1019 	unsigned short div_factor;
1020 };
1021 
1022 static const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] __unused = {
1023 	// /1.001 rates
1024 	{25170, 25180, 25200, 1000, 1001},	//25.2MHz   ->   25.17
1025 	{59340, 59350, 59400, 1000, 1001},	//59.4Mhz   ->   59.340
1026 	{74170, 74180, 74250, 1000, 1001},	//74.25Mhz  ->   74.1758
1027 	{125870, 125880, 126000, 1000, 1001},	//126Mhz    ->  125.87
1028 	{148350, 148360, 148500, 1000, 1001},	//148.5Mhz  ->  148.3516
1029 	{167830, 167840, 168000, 1000, 1001},	//168Mhz    ->  167.83
1030 	{222520, 222530, 222750, 1000, 1001},	//222.75Mhz ->  222.527
1031 	{257140, 257150, 257400, 1000, 1001},	//257.4Mhz  ->  257.1429
1032 	{296700, 296710, 297000, 1000, 1001},	//297Mhz    ->  296.7033
1033 	{342850, 342860, 343200, 1000, 1001},	//343.2Mhz  ->  342.857
1034 	{395600, 395610, 396000, 1000, 1001},	//396Mhz    ->  395.6
1035 	{409090, 409100, 409500, 1000, 1001},	//409.5Mhz  ->  409.091
1036 	{445050, 445060, 445500, 1000, 1001},	//445.5Mhz  ->  445.055
1037 	{467530, 467540, 468000, 1000, 1001},	//468Mhz    ->  467.5325
1038 	{519230, 519240, 519750, 1000, 1001},	//519.75Mhz ->  519.231
1039 	{525970, 525980, 526500, 1000, 1001},	//526.5Mhz  ->  525.974
1040 	{545450, 545460, 546000, 1000, 1001},	//546Mhz    ->  545.455
1041 	{593400, 593410, 594000, 1000, 1001},	//594Mhz    ->  593.4066
1042 	{623370, 623380, 624000, 1000, 1001},	//624Mhz    ->  623.377
1043 	{692300, 692310, 693000, 1000, 1001},	//693Mhz    ->  692.308
1044 	{701290, 701300, 702000, 1000, 1001},	//702Mhz    ->  701.2987
1045 	{791200, 791210, 792000, 1000, 1001},	//792Mhz    ->  791.209
1046 	{890100, 890110, 891000, 1000, 1001},	//891Mhz    ->  890.1099
1047 	{1186810, 1186820, 1188000, 1000, 1001},//1188Mhz   -> 1186.8131
1048 
1049 	// *1.001 rates
1050 	{27020, 27030, 27000, 1001, 1000}, //27Mhz
1051 	{54050, 54060, 54000, 1001, 1000}, //54Mhz
1052 	{108100, 108110, 108000, 1001, 1000},//108Mhz
1053 };
1054 
dcn20_program_pix_clk(struct clock_source * clock_source,struct pixel_clk_params * pix_clk_params,struct pll_settings * pll_settings)1055 static bool dcn20_program_pix_clk(
1056 		struct clock_source *clock_source,
1057 		struct pixel_clk_params *pix_clk_params,
1058 		struct pll_settings *pll_settings)
1059 {
1060 	dce112_program_pix_clk(clock_source, pix_clk_params, pll_settings);
1061 
1062 	return true;
1063 }
1064 
1065 static const struct clock_source_funcs dcn20_clk_src_funcs = {
1066 	.cs_power_down = dce110_clock_source_power_down,
1067 	.program_pix_clk = dcn20_program_pix_clk,
1068 	.get_pix_clk_dividers = dce112_get_pix_clk_dividers,
1069 	.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1070 };
1071 
1072 /*****************************************/
1073 /* Constructor                           */
1074 /*****************************************/
1075 
1076 static const struct clock_source_funcs dce112_clk_src_funcs = {
1077 	.cs_power_down = dce110_clock_source_power_down,
1078 	.program_pix_clk = dce112_program_pix_clk,
1079 	.get_pix_clk_dividers = dce112_get_pix_clk_dividers,
1080 	.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1081 };
1082 static const struct clock_source_funcs dce110_clk_src_funcs = {
1083 	.cs_power_down = dce110_clock_source_power_down,
1084 	.program_pix_clk = dce110_program_pix_clk,
1085 	.get_pix_clk_dividers = dce110_get_pix_clk_dividers,
1086 	.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
1087 };
1088 
1089 
get_ss_info_from_atombios(struct dce110_clk_src * clk_src,enum as_signal_type as_signal,struct spread_spectrum_data * spread_spectrum_data[],uint32_t * ss_entries_num)1090 static void get_ss_info_from_atombios(
1091 		struct dce110_clk_src *clk_src,
1092 		enum as_signal_type as_signal,
1093 		struct spread_spectrum_data *spread_spectrum_data[],
1094 		uint32_t *ss_entries_num)
1095 {
1096 	enum bp_result bp_result = BP_RESULT_FAILURE;
1097 	struct spread_spectrum_info *ss_info;
1098 	struct spread_spectrum_data *ss_data;
1099 	struct spread_spectrum_info *ss_info_cur;
1100 	struct spread_spectrum_data *ss_data_cur;
1101 	uint32_t i;
1102 	DC_LOGGER_INIT();
1103 	if (ss_entries_num == NULL) {
1104 		DC_LOG_SYNC(
1105 			"Invalid entry !!!\n");
1106 		return;
1107 	}
1108 	if (spread_spectrum_data == NULL) {
1109 		DC_LOG_SYNC(
1110 			"Invalid array pointer!!!\n");
1111 		return;
1112 	}
1113 
1114 	spread_spectrum_data[0] = NULL;
1115 	*ss_entries_num = 0;
1116 
1117 	*ss_entries_num = clk_src->bios->funcs->get_ss_entry_number(
1118 			clk_src->bios,
1119 			as_signal);
1120 
1121 	if (*ss_entries_num == 0)
1122 		return;
1123 
1124 	ss_info = kcalloc(*ss_entries_num,
1125 			  sizeof(struct spread_spectrum_info),
1126 			  GFP_KERNEL);
1127 	ss_info_cur = ss_info;
1128 	if (ss_info == NULL)
1129 		return;
1130 
1131 	ss_data = kcalloc(*ss_entries_num,
1132 			  sizeof(struct spread_spectrum_data),
1133 			  GFP_KERNEL);
1134 	if (ss_data == NULL)
1135 		goto out_free_info;
1136 
1137 	for (i = 0, ss_info_cur = ss_info;
1138 		i < (*ss_entries_num);
1139 		++i, ++ss_info_cur) {
1140 
1141 		bp_result = clk_src->bios->funcs->get_spread_spectrum_info(
1142 				clk_src->bios,
1143 				as_signal,
1144 				i,
1145 				ss_info_cur);
1146 
1147 		if (bp_result != BP_RESULT_OK)
1148 			goto out_free_data;
1149 	}
1150 
1151 	for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data;
1152 		i < (*ss_entries_num);
1153 		++i, ++ss_info_cur, ++ss_data_cur) {
1154 
1155 		if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) {
1156 			DC_LOG_SYNC(
1157 				"Invalid ATOMBIOS SS Table!!!\n");
1158 			goto out_free_data;
1159 		}
1160 
1161 		/* for HDMI check SS percentage,
1162 		 * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
1163 		if (as_signal == AS_SIGNAL_TYPE_HDMI
1164 				&& ss_info_cur->spread_spectrum_percentage > 6){
1165 			/* invalid input, do nothing */
1166 			DC_LOG_SYNC(
1167 				"Invalid SS percentage ");
1168 			DC_LOG_SYNC(
1169 				"for HDMI in ATOMBIOS info Table!!!\n");
1170 			continue;
1171 		}
1172 		if (ss_info_cur->spread_percentage_divider == 1000) {
1173 			/* Keep previous precision from ATOMBIOS for these
1174 			* in case new precision set by ATOMBIOS for these
1175 			* (otherwise all code in DCE specific classes
1176 			* for all previous ASICs would need
1177 			* to be updated for SS calculations,
1178 			* Audio SS compensation and DP DTO SS compensation
1179 			* which assumes fixed SS percentage Divider = 100)*/
1180 			ss_info_cur->spread_spectrum_percentage /= 10;
1181 			ss_info_cur->spread_percentage_divider = 100;
1182 		}
1183 
1184 		ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range;
1185 		ss_data_cur->percentage =
1186 				ss_info_cur->spread_spectrum_percentage;
1187 		ss_data_cur->percentage_divider =
1188 				ss_info_cur->spread_percentage_divider;
1189 		ss_data_cur->modulation_freq_hz =
1190 				ss_info_cur->spread_spectrum_range;
1191 
1192 		if (ss_info_cur->type.CENTER_MODE)
1193 			ss_data_cur->flags.CENTER_SPREAD = 1;
1194 
1195 		if (ss_info_cur->type.EXTERNAL)
1196 			ss_data_cur->flags.EXTERNAL_SS = 1;
1197 
1198 	}
1199 
1200 	*spread_spectrum_data = ss_data;
1201 	kfree(ss_info);
1202 	return;
1203 
1204 out_free_data:
1205 	kfree(ss_data);
1206 	*ss_entries_num = 0;
1207 out_free_info:
1208 	kfree(ss_info);
1209 }
1210 
ss_info_from_atombios_create(struct dce110_clk_src * clk_src)1211 static void ss_info_from_atombios_create(
1212 	struct dce110_clk_src *clk_src)
1213 {
1214 	get_ss_info_from_atombios(
1215 		clk_src,
1216 		AS_SIGNAL_TYPE_DISPLAY_PORT,
1217 		&clk_src->dp_ss_params,
1218 		&clk_src->dp_ss_params_cnt);
1219 	get_ss_info_from_atombios(
1220 		clk_src,
1221 		AS_SIGNAL_TYPE_HDMI,
1222 		&clk_src->hdmi_ss_params,
1223 		&clk_src->hdmi_ss_params_cnt);
1224 	get_ss_info_from_atombios(
1225 		clk_src,
1226 		AS_SIGNAL_TYPE_DVI,
1227 		&clk_src->dvi_ss_params,
1228 		&clk_src->dvi_ss_params_cnt);
1229 	get_ss_info_from_atombios(
1230 		clk_src,
1231 		AS_SIGNAL_TYPE_LVDS,
1232 		&clk_src->lvds_ss_params,
1233 		&clk_src->lvds_ss_params_cnt);
1234 }
1235 
calc_pll_max_vco_construct(struct calc_pll_clock_source * calc_pll_cs,struct calc_pll_clock_source_init_data * init_data)1236 static bool calc_pll_max_vco_construct(
1237 			struct calc_pll_clock_source *calc_pll_cs,
1238 			struct calc_pll_clock_source_init_data *init_data)
1239 {
1240 	uint32_t i;
1241 	struct dc_firmware_info *fw_info;
1242 	if (calc_pll_cs == NULL ||
1243 			init_data == NULL ||
1244 			init_data->bp == NULL)
1245 		return false;
1246 
1247 	if (!init_data->bp->fw_info_valid)
1248 		return false;
1249 
1250 	fw_info = &init_data->bp->fw_info;
1251 	calc_pll_cs->ctx = init_data->ctx;
1252 	calc_pll_cs->ref_freq_khz = fw_info->pll_info.crystal_frequency;
1253 	calc_pll_cs->min_vco_khz =
1254 			fw_info->pll_info.min_output_pxl_clk_pll_frequency;
1255 	calc_pll_cs->max_vco_khz =
1256 			fw_info->pll_info.max_output_pxl_clk_pll_frequency;
1257 
1258 	if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0)
1259 		calc_pll_cs->max_pll_input_freq_khz =
1260 			init_data->max_override_input_pxl_clk_pll_freq_khz;
1261 	else
1262 		calc_pll_cs->max_pll_input_freq_khz =
1263 			fw_info->pll_info.max_input_pxl_clk_pll_frequency;
1264 
1265 	if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0)
1266 		calc_pll_cs->min_pll_input_freq_khz =
1267 			init_data->min_override_input_pxl_clk_pll_freq_khz;
1268 	else
1269 		calc_pll_cs->min_pll_input_freq_khz =
1270 			fw_info->pll_info.min_input_pxl_clk_pll_frequency;
1271 
1272 	calc_pll_cs->min_pix_clock_pll_post_divider =
1273 			init_data->min_pix_clk_pll_post_divider;
1274 	calc_pll_cs->max_pix_clock_pll_post_divider =
1275 			init_data->max_pix_clk_pll_post_divider;
1276 	calc_pll_cs->min_pll_ref_divider =
1277 			init_data->min_pll_ref_divider;
1278 	calc_pll_cs->max_pll_ref_divider =
1279 			init_data->max_pll_ref_divider;
1280 
1281 	if (init_data->num_fract_fb_divider_decimal_point == 0 ||
1282 		init_data->num_fract_fb_divider_decimal_point_precision >
1283 				init_data->num_fract_fb_divider_decimal_point) {
1284 		DC_LOG_ERROR(
1285 			"The dec point num or precision is incorrect!");
1286 		return false;
1287 	}
1288 	if (init_data->num_fract_fb_divider_decimal_point_precision == 0) {
1289 		DC_LOG_ERROR(
1290 			"Incorrect fract feedback divider precision num!");
1291 		return false;
1292 	}
1293 
1294 	calc_pll_cs->fract_fb_divider_decimal_points_num =
1295 				init_data->num_fract_fb_divider_decimal_point;
1296 	calc_pll_cs->fract_fb_divider_precision =
1297 			init_data->num_fract_fb_divider_decimal_point_precision;
1298 	calc_pll_cs->fract_fb_divider_factor = 1;
1299 	for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i)
1300 		calc_pll_cs->fract_fb_divider_factor *= 10;
1301 
1302 	calc_pll_cs->fract_fb_divider_precision_factor = 1;
1303 	for (
1304 		i = 0;
1305 		i < (calc_pll_cs->fract_fb_divider_decimal_points_num -
1306 				calc_pll_cs->fract_fb_divider_precision);
1307 		++i)
1308 		calc_pll_cs->fract_fb_divider_precision_factor *= 10;
1309 
1310 	return true;
1311 }
1312 
dce110_clk_src_construct(struct dce110_clk_src * clk_src,struct dc_context * ctx,struct dc_bios * bios,enum clock_source_id id,const struct dce110_clk_src_regs * regs,const struct dce110_clk_src_shift * cs_shift,const struct dce110_clk_src_mask * cs_mask)1313 bool dce110_clk_src_construct(
1314 	struct dce110_clk_src *clk_src,
1315 	struct dc_context *ctx,
1316 	struct dc_bios *bios,
1317 	enum clock_source_id id,
1318 	const struct dce110_clk_src_regs *regs,
1319 	const struct dce110_clk_src_shift *cs_shift,
1320 	const struct dce110_clk_src_mask *cs_mask)
1321 {
1322 	struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi;
1323 	struct calc_pll_clock_source_init_data calc_pll_cs_init_data;
1324 
1325 	clk_src->base.ctx = ctx;
1326 	clk_src->bios = bios;
1327 	clk_src->base.id = id;
1328 	clk_src->base.funcs = &dce110_clk_src_funcs;
1329 
1330 	clk_src->regs = regs;
1331 	clk_src->cs_shift = cs_shift;
1332 	clk_src->cs_mask = cs_mask;
1333 
1334 	if (!clk_src->bios->fw_info_valid) {
1335 		ASSERT_CRITICAL(false);
1336 		goto unexpected_failure;
1337 	}
1338 
1339 	clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp;
1340 
1341 	/* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
1342 	calc_pll_cs_init_data.bp = bios;
1343 	calc_pll_cs_init_data.min_pix_clk_pll_post_divider = 1;
1344 	calc_pll_cs_init_data.max_pix_clk_pll_post_divider =
1345 			clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1346 	calc_pll_cs_init_data.min_pll_ref_divider =	1;
1347 	calc_pll_cs_init_data.max_pll_ref_divider =	clk_src->cs_mask->PLL_REF_DIV;
1348 	/* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1349 	calc_pll_cs_init_data.min_override_input_pxl_clk_pll_freq_khz =	0;
1350 	/* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1351 	calc_pll_cs_init_data.max_override_input_pxl_clk_pll_freq_khz =	0;
1352 	/*numberOfFractFBDividerDecimalPoints*/
1353 	calc_pll_cs_init_data.num_fract_fb_divider_decimal_point =
1354 			FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1355 	/*number of decimal point to round off for fractional feedback divider value*/
1356 	calc_pll_cs_init_data.num_fract_fb_divider_decimal_point_precision =
1357 			FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1358 	calc_pll_cs_init_data.ctx =	ctx;
1359 
1360 	/*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
1361 	calc_pll_cs_init_data_hdmi.bp = bios;
1362 	calc_pll_cs_init_data_hdmi.min_pix_clk_pll_post_divider = 1;
1363 	calc_pll_cs_init_data_hdmi.max_pix_clk_pll_post_divider =
1364 			clk_src->cs_mask->PLL_POST_DIV_PIXCLK;
1365 	calc_pll_cs_init_data_hdmi.min_pll_ref_divider = 1;
1366 	calc_pll_cs_init_data_hdmi.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV;
1367 	/* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1368 	calc_pll_cs_init_data_hdmi.min_override_input_pxl_clk_pll_freq_khz = 13500;
1369 	/* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
1370 	calc_pll_cs_init_data_hdmi.max_override_input_pxl_clk_pll_freq_khz = 27000;
1371 	/*numberOfFractFBDividerDecimalPoints*/
1372 	calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point =
1373 			FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1374 	/*number of decimal point to round off for fractional feedback divider value*/
1375 	calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point_precision =
1376 			FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM;
1377 	calc_pll_cs_init_data_hdmi.ctx = ctx;
1378 
1379 	clk_src->ref_freq_khz = clk_src->bios->fw_info.pll_info.crystal_frequency;
1380 
1381 	if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL)
1382 		return true;
1383 
1384 	/* PLL only from here on */
1385 	ss_info_from_atombios_create(clk_src);
1386 
1387 	if (!calc_pll_max_vco_construct(
1388 			&clk_src->calc_pll,
1389 			&calc_pll_cs_init_data)) {
1390 		ASSERT_CRITICAL(false);
1391 		goto unexpected_failure;
1392 	}
1393 
1394 
1395 	calc_pll_cs_init_data_hdmi.
1396 			min_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz/2;
1397 	calc_pll_cs_init_data_hdmi.
1398 			max_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz;
1399 
1400 
1401 	if (!calc_pll_max_vco_construct(
1402 			&clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
1403 		ASSERT_CRITICAL(false);
1404 		goto unexpected_failure;
1405 	}
1406 
1407 	return true;
1408 
1409 unexpected_failure:
1410 	return false;
1411 }
1412 
dce112_clk_src_construct(struct dce110_clk_src * clk_src,struct dc_context * ctx,struct dc_bios * bios,enum clock_source_id id,const struct dce110_clk_src_regs * regs,const struct dce110_clk_src_shift * cs_shift,const struct dce110_clk_src_mask * cs_mask)1413 bool dce112_clk_src_construct(
1414 	struct dce110_clk_src *clk_src,
1415 	struct dc_context *ctx,
1416 	struct dc_bios *bios,
1417 	enum clock_source_id id,
1418 	const struct dce110_clk_src_regs *regs,
1419 	const struct dce110_clk_src_shift *cs_shift,
1420 	const struct dce110_clk_src_mask *cs_mask)
1421 {
1422 	clk_src->base.ctx = ctx;
1423 	clk_src->bios = bios;
1424 	clk_src->base.id = id;
1425 	clk_src->base.funcs = &dce112_clk_src_funcs;
1426 
1427 	clk_src->regs = regs;
1428 	clk_src->cs_shift = cs_shift;
1429 	clk_src->cs_mask = cs_mask;
1430 
1431 	if (!clk_src->bios->fw_info_valid) {
1432 		ASSERT_CRITICAL(false);
1433 		return false;
1434 	}
1435 
1436 	clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp;
1437 
1438 	return true;
1439 }
1440 
dcn20_clk_src_construct(struct dce110_clk_src * clk_src,struct dc_context * ctx,struct dc_bios * bios,enum clock_source_id id,const struct dce110_clk_src_regs * regs,const struct dce110_clk_src_shift * cs_shift,const struct dce110_clk_src_mask * cs_mask)1441 bool dcn20_clk_src_construct(
1442 	struct dce110_clk_src *clk_src,
1443 	struct dc_context *ctx,
1444 	struct dc_bios *bios,
1445 	enum clock_source_id id,
1446 	const struct dce110_clk_src_regs *regs,
1447 	const struct dce110_clk_src_shift *cs_shift,
1448 	const struct dce110_clk_src_mask *cs_mask)
1449 {
1450 	bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
1451 
1452 	clk_src->base.funcs = &dcn20_clk_src_funcs;
1453 
1454 	return ret;
1455 }
1456