Adds pixel clock programming and functionality to
power down clock sources.

Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
---
 .../drm/amd/dal/dc/dce110/dce110_clock_source.c    | 1162 ++++++++++++++++++++
 .../drm/amd/dal/dc/dce110/dce110_clock_source.h    |   64 ++
 2 files changed, 1226 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.h

diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.c
new file mode 100644
index 000000000000..e1bac1f77b79
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.c
@@ -0,0 +1,1162 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dm_services.h"
+
+/* include DCE11 register header files */
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "dc_types.h"
+#include "core_types.h"
+
+#include "include/grph_object_id.h"
+#include "include/logger_interface.h"
+
+#include "dce110_clock_source.h"
+
+#define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6
+#define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
+#define MAX_PLL_CALC_ERROR 0xFFFFFFFF
+
+static const struct spread_spectrum_data *get_ss_data_entry(
+               struct dce110_clk_src *clk_src,
+               enum signal_type signal,
+               uint32_t pix_clk_khz)
+{
+
+       uint32_t entrys_num;
+       uint32_t i;
+       struct spread_spectrum_data *ss_parm = NULL;
+       struct spread_spectrum_data *ret = NULL;
+
+       switch (signal) {
+       case SIGNAL_TYPE_DVI_SINGLE_LINK:
+       case SIGNAL_TYPE_DVI_DUAL_LINK:
+               ss_parm = clk_src->dvi_ss_params;
+               entrys_num = clk_src->dvi_ss_params_cnt;
+               break;
+
+       case SIGNAL_TYPE_HDMI_TYPE_A:
+               ss_parm = clk_src->hdmi_ss_params;
+               entrys_num = clk_src->hdmi_ss_params_cnt;
+               break;
+
+       case SIGNAL_TYPE_DISPLAY_PORT:
+       case SIGNAL_TYPE_DISPLAY_PORT_MST:
+       case SIGNAL_TYPE_EDP:
+               ss_parm = clk_src->dp_ss_params;
+               entrys_num = clk_src->dp_ss_params_cnt;
+               break;
+
+       default:
+               ss_parm = NULL;
+               entrys_num = 0;
+               break;
+       }
+
+       if (ss_parm == NULL)
+               return ret;
+
+       for (i = 0; i < entrys_num; ++i, ++ss_parm) {
+               if (ss_parm->freq_range_khz >= pix_clk_khz) {
+                       ret = ss_parm;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/**
+* Function: calculate_fb_and_fractional_fb_divider
+*
+* * DESCRIPTION: Calculates feedback and fractional feedback dividers values
+*
+*PARAMETERS:
+* targetPixelClock             Desired frequency in 10 KHz
+* ref_divider                  Reference divider (already known)
+* postDivider                  Post Divider (already known)
+* feedback_divider_param       Pointer where to store
+*                                      calculated feedback divider value
+* fract_feedback_divider_param Pointer where to store
+*                                      calculated fract feedback divider value
+*
+*RETURNS:
+* It fills the locations pointed by feedback_divider_param
+*                                      and fract_feedback_divider_param
+* It returns   - true if feedback divider not 0
+*              - false should never happen)
+*/
+static bool calculate_fb_and_fractional_fb_divider(
+               struct calc_pll_clock_source *calc_pll_cs,
+               uint32_t target_pix_clk_khz,
+               uint32_t ref_divider,
+               uint32_t post_divider,
+               uint32_t *feedback_divider_param,
+               uint32_t *fract_feedback_divider_param)
+{
+       uint64_t feedback_divider;
+
+       feedback_divider =
+               (uint64_t)(target_pix_clk_khz * ref_divider * post_divider);
+       feedback_divider *= 10;
+       /* additional factor, since we divide by 10 afterwards */
+       feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
+       feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz);
+
+/*Round to the number of precision
+ * The following code replace the old code (ullfeedbackDivider + 5)/10
+ * for example if the difference between the number
+ * of fractional feedback decimal point and the fractional FB Divider precision
+ * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
+
+       feedback_divider += (uint64_t)
+                       (5 * calc_pll_cs->fract_fb_divider_precision_factor);
+       feedback_divider =
+               div_u64(feedback_divider,
+                       calc_pll_cs->fract_fb_divider_precision_factor * 10);
+       feedback_divider *= (uint64_t)
+                       (calc_pll_cs->fract_fb_divider_precision_factor);
+
+       *feedback_divider_param =
+               div_u64_rem(
+                       feedback_divider,
+                       calc_pll_cs->fract_fb_divider_factor,
+                       fract_feedback_divider_param);
+
+       if (*feedback_divider_param != 0)
+               return true;
+       return false;
+}
+
+/**
+*calc_fb_divider_checking_tolerance
+*
+*DESCRIPTION: Calculates Feedback and Fractional Feedback divider values
+*              for passed Reference and Post divider, checking for tolerance.
+*PARAMETERS:
+* pll_settings         Pointer to structure
+* ref_divider          Reference divider (already known)
+* postDivider          Post Divider (already known)
+* tolerance            Tolerance for Calculated Pixel Clock to be within
+*
+*RETURNS:
+* It fills the PLLSettings structure with PLL Dividers values
+* if calculated values are within required tolerance
+* It returns   - true if eror is within tolerance
+*              - false if eror is not within tolerance
+*/
+static bool 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)
+{
+       uint32_t feedback_divider;
+       uint32_t fract_feedback_divider;
+       uint32_t actual_calculated_clock_khz;
+       uint32_t abs_err;
+       uint64_t actual_calc_clk_khz;
+
+       calculate_fb_and_fractional_fb_divider(
+                       calc_pll_cs,
+                       pll_settings->adjusted_pix_clk,
+                       ref_divider,
+                       post_divider,
+                       &feedback_divider,
+                       &fract_feedback_divider);
+
+       /*Actual calculated value*/
+       actual_calc_clk_khz = (uint64_t)(feedback_divider *
+                                       calc_pll_cs->fract_fb_divider_factor) +
+                                                       fract_feedback_divider;
+       actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz;
+       actual_calc_clk_khz =
+               div_u64(actual_calc_clk_khz,
+                       ref_divider * post_divider *
+                               calc_pll_cs->fract_fb_divider_factor);
+
+       actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz);
+
+       abs_err = (actual_calculated_clock_khz >
+                                       pll_settings->adjusted_pix_clk)
+                       ? actual_calculated_clock_khz -
+                                       pll_settings->adjusted_pix_clk
+                       : pll_settings->adjusted_pix_clk -
+                                               actual_calculated_clock_khz;
+
+       if (abs_err <= tolerance) {
+               /*found good values*/
+               pll_settings->reference_freq = calc_pll_cs->ref_freq_khz;
+               pll_settings->reference_divider = ref_divider;
+               pll_settings->feedback_divider = feedback_divider;
+               pll_settings->fract_feedback_divider = fract_feedback_divider;
+               pll_settings->pix_clk_post_divider = post_divider;
+               pll_settings->calculated_pix_clk =
+                       actual_calculated_clock_khz;
+               pll_settings->vco_freq =
+                       actual_calculated_clock_khz * post_divider;
+               return true;
+       }
+       return false;
+}
+
+
+static bool 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)
+{
+       uint32_t ref_divider;
+       uint32_t post_divider;
+       uint32_t tolerance;
+
+/* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
+ * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
+       tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) /
+                                                                       10000;
+       if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
+               tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
+
+       for (
+                       post_divider = max_post_divider;
+                       post_divider >= min_post_divider;
+                       --post_divider) {
+               for (
+                               ref_divider = min_ref_divider;
+                               ref_divider <= max_ref_divider;
+                               ++ref_divider) {
+                       if (calc_fb_divider_checking_tolerance(
+                                       calc_pll_cs,
+                                       pll_settings,
+                                       ref_divider,
+                                       post_divider,
+                                       tolerance)) {
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+static uint32_t calculate_pixel_clock_pll_dividers(
+               struct calc_pll_clock_source *calc_pll_cs,
+               struct pll_settings *pll_settings)
+{
+       uint32_t err_tolerance;
+       uint32_t min_post_divider;
+       uint32_t max_post_divider;
+       uint32_t min_ref_divider;
+       uint32_t max_ref_divider;
+
+       if (pll_settings->adjusted_pix_clk == 0) {
+               dal_logger_write(calc_pll_cs->ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "%s Bad requested pixel clock", __func__);
+               return MAX_PLL_CALC_ERROR;
+       }
+
+/* 1) Find Post divider ranges */
+       if (pll_settings->pix_clk_post_divider) {
+               min_post_divider = pll_settings->pix_clk_post_divider;
+               max_post_divider = pll_settings->pix_clk_post_divider;
+       } else {
+               min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
+               if (min_post_divider * pll_settings->adjusted_pix_clk <
+                                               calc_pll_cs->min_vco_khz) {
+                       min_post_divider = calc_pll_cs->min_vco_khz /
+                                       pll_settings->adjusted_pix_clk;
+                       if ((min_post_divider *
+                                       pll_settings->adjusted_pix_clk) <
+                                               calc_pll_cs->min_vco_khz)
+                               min_post_divider++;
+               }
+
+               max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
+               if (max_post_divider * pll_settings->adjusted_pix_clk
+                               > calc_pll_cs->max_vco_khz)
+                       max_post_divider = calc_pll_cs->max_vco_khz /
+                                       pll_settings->adjusted_pix_clk;
+       }
+
+/* 2) Find Reference divider ranges
+ * When SS is enabled, or for Display Port even without SS,
+ * pll_settings->referenceDivider is not zero.
+ * So calculate PPLL FB and fractional FB divider
+ * using the passed reference divider*/
+
+       if (pll_settings->reference_divider) {
+               min_ref_divider = pll_settings->reference_divider;
+               max_ref_divider = pll_settings->reference_divider;
+       } else {
+               min_ref_divider = ((calc_pll_cs->ref_freq_khz
+                               / calc_pll_cs->max_pll_input_freq_khz)
+                               > calc_pll_cs->min_pll_ref_divider)
+                       ? calc_pll_cs->ref_freq_khz
+                                       / calc_pll_cs->max_pll_input_freq_khz
+                       : calc_pll_cs->min_pll_ref_divider;
+
+               max_ref_divider = ((calc_pll_cs->ref_freq_khz
+                               / calc_pll_cs->min_pll_input_freq_khz)
+                               < calc_pll_cs->max_pll_ref_divider)
+                       ? calc_pll_cs->ref_freq_khz /
+                                       calc_pll_cs->min_pll_input_freq_khz
+                       : calc_pll_cs->max_pll_ref_divider;
+       }
+
+/* If some parameters are invalid we could have scenario when  "min">"max"
+ * which produced endless loop later.
+ * We should investigate why we get the wrong parameters.
+ * But to follow the similar logic when "adjustedPixelClock" is set to be 0
+ * it is better to return here than cause system hang/watchdog timeout later.
+ *  ## SVS Wed 15 Jul 2009 */
+
+       if (min_post_divider > max_post_divider) {
+               dal_logger_write(calc_pll_cs->ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "%s Post divider range is invalid", __func__);
+               return MAX_PLL_CALC_ERROR;
+       }
+
+       if (min_ref_divider > max_ref_divider) {
+               dal_logger_write(calc_pll_cs->ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "%s Reference divider range is invalid", __func__);
+               return MAX_PLL_CALC_ERROR;
+       }
+
+/* 3) Try to find PLL dividers given ranges
+ * starting with minimal error tolerance.
+ * Increase error tolerance until PLL dividers found*/
+       err_tolerance = MAX_PLL_CALC_ERROR;
+
+       while (!calc_pll_dividers_in_range(
+                       calc_pll_cs,
+                       pll_settings,
+                       min_ref_divider,
+                       max_ref_divider,
+                       min_post_divider,
+                       max_post_divider,
+                       err_tolerance))
+               err_tolerance += (err_tolerance > 10)
+                               ? (err_tolerance / 10)
+                               : 1;
+
+       return err_tolerance;
+}
+
+static bool pll_adjust_pix_clk(
+               struct dce110_clk_src *clk_src,
+               struct pixel_clk_params *pix_clk_params,
+               struct pll_settings *pll_settings)
+{
+       uint32_t actual_pix_clk_khz = 0;
+       uint32_t requested_clk_khz = 0;
+       struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
+                                                       0 };
+       enum bp_result bp_result;
+
+       switch (pix_clk_params->signal_type) {
+       case SIGNAL_TYPE_HDMI_TYPE_A: {
+               requested_clk_khz = pix_clk_params->requested_pix_clk;
+
+               switch (pix_clk_params->color_depth) {
+               case COLOR_DEPTH_101010:
+                       requested_clk_khz = (requested_clk_khz * 5) >> 2;
+                       break; /* x1.25*/
+               case COLOR_DEPTH_121212:
+                       requested_clk_khz = (requested_clk_khz * 6) >> 2;
+                       break; /* x1.5*/
+               case COLOR_DEPTH_161616:
+                       requested_clk_khz = requested_clk_khz * 2;
+                       break; /* x2.0*/
+               default:
+                       break;
+               }
+
+               actual_pix_clk_khz = requested_clk_khz;
+       }
+               break;
+
+       case SIGNAL_TYPE_DISPLAY_PORT:
+       case SIGNAL_TYPE_DISPLAY_PORT_MST:
+       case SIGNAL_TYPE_EDP:
+               requested_clk_khz = pix_clk_params->requested_sym_clk;
+               actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
+               break;
+
+       default:
+               requested_clk_khz = pix_clk_params->requested_pix_clk;
+               actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
+               break;
+       }
+
+       bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz;
+       bp_adjust_pixel_clock_params.
+               encoder_object_id = pix_clk_params->encoder_object_id;
+       bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
+       bp_adjust_pixel_clock_params.
+               ss_enable = pix_clk_params->flags.ENABLE_SS;
+       bp_result = clk_src->bios->funcs->adjust_pixel_clock(
+                       clk_src->bios, &bp_adjust_pixel_clock_params);
+       if (bp_result == BP_RESULT_OK) {
+               pll_settings->actual_pix_clk = actual_pix_clk_khz;
+               pll_settings->adjusted_pix_clk =
+                       bp_adjust_pixel_clock_params.adjusted_pixel_clock;
+               pll_settings->reference_divider =
+                       bp_adjust_pixel_clock_params.reference_divider;
+               pll_settings->pix_clk_post_divider =
+                       bp_adjust_pixel_clock_params.pixel_clock_post_divider;
+
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Calculate PLL Dividers for given Clock Value.
+ * First will call VBIOS Adjust Exec table to check if requested Pixel clock
+ * will be Adjusted based on usage.
+ * Then it will calculate PLL Dividers for this Adjusted clock using preferred
+ * method (Maximum VCO frequency).
+ *
+ * \return
+ *     Calculation error in units of 0.01%
+ */
+static uint32_t dce110_get_pix_clk_dividers(
+               struct clock_source *cs,
+               struct pixel_clk_params *pix_clk_params,
+               struct pll_settings *pll_settings)
+{
+       struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs);
+       uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
+       uint32_t addr = 0;
+       uint32_t value = 0;
+       uint32_t field = 0;
+
+       if (pix_clk_params == NULL || pll_settings == NULL
+                       || pix_clk_params->requested_pix_clk == 0) {
+               dal_logger_write(clk_src->base.ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "%s: Invalid parameters!!\n", __func__);
+               return pll_calc_error;
+       }
+
+       dm_memset(pll_settings, 0, sizeof(*pll_settings));
+
+       if (cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
+               pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
+               pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
+               pll_settings->actual_pix_clk =
+                                       pix_clk_params->requested_pix_clk;
+               return 0;
+       }
+       /* PLL only after this point */
+
+       /* Check if reference clock is external (not pcie/xtalin)
+       * HW Dce80 spec:
+       * 00 - PCIE_REFCLK, 01 - XTALIN,    02 - GENERICA,    03 - GENERICB
+       * 04 - HSYNCA,      05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
+       addr = clk_src->offsets.pll_cntl;
+       value = dm_read_reg(clk_src->base.ctx, addr);
+       field = get_reg_field_value(value, PLL_CNTL, PLL_REF_DIV_SRC);
+       pll_settings->use_external_clk = (field > 1);
+
+       /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
+        * (we do not care any more from SI for some older DP Sink which
+        * does not report SS support, no known issues) */
+       if ((pix_clk_params->flags.ENABLE_SS) ||
+                       (dc_is_dp_signal(pix_clk_params->signal_type))) {
+
+               const struct spread_spectrum_data *ss_data = get_ss_data_entry(
+                                       clk_src,
+                                       pix_clk_params->signal_type,
+                                       pll_settings->adjusted_pix_clk);
+
+               if (NULL != ss_data)
+                       pll_settings->ss_percentage = ss_data->percentage;
+       }
+
+       /* Check VBIOS AdjustPixelClock Exec table */
+       if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) {
+               /* Should never happen, ASSERT and fill up values to be able
+                * to continue. */
+               dal_logger_write(clk_src->base.ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "%s: Failed to adjust pixel clock!!", __func__);
+               pll_settings->actual_pix_clk =
+                               pix_clk_params->requested_pix_clk;
+               pll_settings->adjusted_pix_clk =
+                               pix_clk_params->requested_pix_clk;
+
+               if (dc_is_dp_signal(pix_clk_params->signal_type))
+                       pll_settings->adjusted_pix_clk = 100000;
+       }
+
+       /* Calculate Dividers */
+       if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
+               /*Calculate Dividers by HDMI object, no SS case or SS case */
+               pll_calc_error =
+                       calculate_pixel_clock_pll_dividers(
+                                       &clk_src->calc_pll_hdmi,
+                                       pll_settings);
+       else
+               /*Calculate Dividers by default object, no SS case or SS case */
+               pll_calc_error =
+                       calculate_pixel_clock_pll_dividers(
+                                       &clk_src->calc_pll,
+                                       pll_settings);
+
+       return pll_calc_error;
+}
+
+static bool disable_spread_spectrum(struct dce110_clk_src *clk_src)
+{
+       enum bp_result result;
+       struct bp_spread_spectrum_parameters bp_ss_params = {0};
+
+       bp_ss_params.pll_id = clk_src->base.id;
+
+       /*Call ASICControl to process ATOMBIOS Exec table*/
+       result = clk_src->bios->funcs->enable_spread_spectrum_on_ppll(
+                       clk_src->bios,
+                       &bp_ss_params,
+                       false);
+
+       return result == BP_RESULT_OK;
+}
+
+static bool calculate_ss(
+               const struct pll_settings *pll_settings,
+               const struct spread_spectrum_data *ss_data,
+               struct delta_sigma_data *ds_data)
+{
+       struct fixed32_32 fb_div;
+       struct fixed32_32 ss_amount;
+       struct fixed32_32 ss_nslip_amount;
+       struct fixed32_32 ss_ds_frac_amount;
+       struct fixed32_32 ss_step_size;
+       struct fixed32_32 modulation_time;
+
+       if (ds_data == NULL)
+               return false;
+       if (ss_data == NULL)
+               return false;
+       if (ss_data->percentage == 0)
+               return false;
+       if (pll_settings == NULL)
+               return false;
+
+
+       dm_memset(ds_data, 0, sizeof(struct delta_sigma_data));
+
+
+
+       /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
+       /* 6 decimal point support in fractional feedback divider */
+       fb_div  = dal_fixed32_32_from_fraction(
+               pll_settings->fract_feedback_divider, 1000000);
+       fb_div = dal_fixed32_32_add_int(fb_div, pll_settings->feedback_divider);
+
+       ds_data->ds_frac_amount = 0;
+       /*spreadSpectrumPercentage is in the unit of .01%,
+        * so have to divided by 100 * 100*/
+       ss_amount = dal_fixed32_32_mul(
+               fb_div, dal_fixed32_32_from_fraction(ss_data->percentage,
+                                       100 * ss_data->percentage_divider));
+       ds_data->feedback_amount = dal_fixed32_32_floor(ss_amount);
+
+       ss_nslip_amount = dal_fixed32_32_sub(ss_amount,
+               dal_fixed32_32_from_int(ds_data->feedback_amount));
+       ss_nslip_amount = dal_fixed32_32_mul_int(ss_nslip_amount, 10);
+       ds_data->nfrac_amount = dal_fixed32_32_floor(ss_nslip_amount);
+
+       ss_ds_frac_amount = dal_fixed32_32_sub(ss_nslip_amount,
+               dal_fixed32_32_from_int(ds_data->nfrac_amount));
+       ss_ds_frac_amount = dal_fixed32_32_mul_int(ss_ds_frac_amount, 65536);
+       ds_data->ds_frac_amount = dal_fixed32_32_floor(ss_ds_frac_amount);
+
+       /* compute SS_STEP_SIZE_DSFRAC */
+       modulation_time = dal_fixed32_32_from_fraction(
+               pll_settings->reference_freq * 1000,
+               pll_settings->reference_divider * ss_data->modulation_freq_hz);
+
+
+       if (ss_data->flags.CENTER_SPREAD)
+               modulation_time = dal_fixed32_32_div_int(modulation_time, 4);
+       else
+               modulation_time = dal_fixed32_32_div_int(modulation_time, 2);
+
+       ss_step_size = dal_fixed32_32_div(ss_amount, modulation_time);
+       /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
+       ss_step_size = dal_fixed32_32_mul_int(ss_step_size, 65536 * 10);
+       ds_data->ds_frac_size =  dal_fixed32_32_floor(ss_step_size);
+
+       return true;
+}
+
+static bool enable_spread_spectrum(
+               struct dce110_clk_src *clk_src,
+               enum signal_type signal, struct pll_settings *pll_settings)
+{
+       struct bp_spread_spectrum_parameters bp_params = {0};
+       struct delta_sigma_data d_s_data;
+       const struct spread_spectrum_data *ss_data = NULL;
+
+       ss_data = get_ss_data_entry(
+                       clk_src,
+                       signal,
+                       pll_settings->calculated_pix_clk);
+
+/* Pixel clock PLL has been programmed to generate desired pixel clock,
+ * now enable SS on pixel clock */
+/* TODO is it OK to return true not doing anything ??*/
+       if (ss_data != NULL && pll_settings->ss_percentage != 0) {
+               if (calculate_ss(pll_settings, ss_data, &d_s_data)) {
+                       bp_params.ds.feedback_amount =
+                                       d_s_data.feedback_amount;
+                       bp_params.ds.nfrac_amount =
+                                       d_s_data.nfrac_amount;
+                       bp_params.ds.ds_frac_size = d_s_data.ds_frac_size;
+                       bp_params.ds_frac_amount =
+                                       d_s_data.ds_frac_amount;
+                       bp_params.flags.DS_TYPE = 1;
+                       bp_params.pll_id = clk_src->base.id;
+                       bp_params.percentage = ss_data->percentage;
+                       if (ss_data->flags.CENTER_SPREAD)
+                               bp_params.flags.CENTER_SPREAD = 1;
+                       if (ss_data->flags.EXTERNAL_SS)
+                               bp_params.flags.EXTERNAL_SS = 1;
+
+                       if (BP_RESULT_OK !=
+                               clk_src->bios->funcs->
+                                       enable_spread_spectrum_on_ppll(
+                                                       clk_src->bios,
+                                                       &bp_params,
+                                                       true))
+                               return false;
+               } else
+                       return false;
+       }
+       return true;
+}
+
+static void program_pixel_clk_resync(
+               struct dce110_clk_src *clk_src,
+               enum signal_type signal_type,
+               enum dc_color_depth colordepth)
+{
+       uint32_t value = 0;
+
+       value = dm_read_reg(clk_src->base.ctx, 
clk_src->offsets.pixclk_resync_cntl);
+
+       set_reg_field_value(
+               value,
+               0,
+               PIXCLK1_RESYNC_CNTL,
+               DCCG_DEEP_COLOR_CNTL1);
+
+       /*
+        24 bit mode: TMDS clock = 1.0 x pixel clock  (1:1)
+        30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
+        36 bit mode: TMDS clock = 1.5 x pixel clock  (3:2)
+        48 bit mode: TMDS clock = 2 x pixel clock    (2:1)
+        */
+       if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
+               return;
+
+       switch (colordepth) {
+       case COLOR_DEPTH_888:
+               set_reg_field_value(
+                       value,
+                       0,
+                       PIXCLK1_RESYNC_CNTL,
+                       DCCG_DEEP_COLOR_CNTL1);
+               break;
+       case COLOR_DEPTH_101010:
+               set_reg_field_value(
+                       value,
+                       1,
+                       PIXCLK1_RESYNC_CNTL,
+                       DCCG_DEEP_COLOR_CNTL1);
+               break;
+       case COLOR_DEPTH_121212:
+               set_reg_field_value(
+                       value,
+                       2,
+                       PIXCLK1_RESYNC_CNTL,
+                       DCCG_DEEP_COLOR_CNTL1);
+               break;
+       case COLOR_DEPTH_161616:
+               set_reg_field_value(
+                       value,
+                       3,
+                       PIXCLK1_RESYNC_CNTL,
+                       DCCG_DEEP_COLOR_CNTL1);
+               break;
+       default:
+               break;
+       }
+
+       dm_write_reg(
+               clk_src->base.ctx,
+               clk_src->offsets.pixclk_resync_cntl,
+               value);
+}
+
+static bool dce110_program_pix_clk(
+               struct clock_source *clk_src,
+               struct pixel_clk_params *pix_clk_params,
+               struct pll_settings *pll_settings)
+{
+       struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src);
+       struct bp_pixel_clock_parameters bp_pc_params = {0};
+
+       /* First disable SS
+        * ATOMBIOS will enable by default SS on PLL for DP,
+        * do not disable it here
+        */
+       if (clk_src->id != CLOCK_SOURCE_ID_EXTERNAL &&
+                       !dc_is_dp_signal(pix_clk_params->signal_type))
+               disable_spread_spectrum(dce110_clk_src);
+
+       /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
+       bp_pc_params.controller_id = pix_clk_params->controller_id;
+       bp_pc_params.pll_id = clk_src->id;
+       bp_pc_params.target_pixel_clock =
+                       pll_settings->actual_pix_clk;
+       bp_pc_params.reference_divider = pll_settings->reference_divider;
+       bp_pc_params.feedback_divider = pll_settings->feedback_divider;
+       bp_pc_params.fractional_feedback_divider =
+                       pll_settings->fract_feedback_divider;
+       bp_pc_params.pixel_clock_post_divider =
+                       pll_settings->pix_clk_post_divider;
+       bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
+       bp_pc_params.signal_type = pix_clk_params->signal_type;
+       bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
+                                       pll_settings->use_external_clk;
+
+       if (dce110_clk_src->bios->funcs->set_pixel_clock(
+                       dce110_clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
+               return false;
+
+/* Enable SS
+ * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
+ * based on HW display PLL team, SS control settings should be programmed
+ * during PLL Reset, but they do not have effect
+ * until SS_EN is asserted.*/
+       if (clk_src->id != CLOCK_SOURCE_ID_EXTERNAL
+               && pix_clk_params->flags.ENABLE_SS && !dc_is_dp_signal(
+                                               pix_clk_params->signal_type))
+               if (!enable_spread_spectrum(dce110_clk_src,
+                                               pix_clk_params->signal_type,
+                                               pll_settings))
+                       return false;
+
+/* Resync deep color DTO */
+       if (clk_src->id != CLOCK_SOURCE_ID_EXTERNAL)
+               program_pixel_clk_resync(dce110_clk_src,
+                                       pix_clk_params->signal_type,
+                                       pix_clk_params->color_depth);
+
+       return true;
+}
+
+static bool dce110_clock_source_power_down(
+               struct clock_source *clk_src)
+{
+       struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src);
+       enum bp_result bp_result;
+       struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
+
+       if (clk_src->id == CLOCK_SOURCE_ID_EXTERNAL)
+               return true;
+
+       /* If Pixel Clock is 0 it means Power Down Pll*/
+       bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
+       bp_pixel_clock_params.pll_id = clk_src->id;
+       bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
+
+       /*Call ASICControl to process ATOMBIOS Exec table*/
+       bp_result = dce110_clk_src->bios->funcs->set_pixel_clock(
+                       dce110_clk_src->bios,
+                       &bp_pixel_clock_params);
+
+       return bp_result == BP_RESULT_OK;
+}
+
+/*****************************************/
+/* Constructor                           */
+/*****************************************/
+static struct clock_source_funcs dce110_clk_src_funcs = {
+       .cs_power_down = dce110_clock_source_power_down,
+       .program_pix_clk = dce110_program_pix_clk,
+       .get_pix_clk_dividers = dce110_get_pix_clk_dividers
+};
+
+
+static void 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)
+{
+       enum bp_result bp_result = BP_RESULT_FAILURE;
+       struct spread_spectrum_info *ss_info;
+       struct spread_spectrum_data *ss_data;
+       struct spread_spectrum_info *ss_info_cur;
+       struct spread_spectrum_data *ss_data_cur;
+       uint32_t i;
+
+       if (ss_entries_num == NULL) {
+               dal_logger_write(clk_src->base.ctx->logger,
+                       LOG_MAJOR_SYNC,
+                       LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
+                       "Invalid entry !!!\n");
+               return;
+       }
+       if (spread_spectrum_data == NULL) {
+               dal_logger_write(clk_src->base.ctx->logger,
+                       LOG_MAJOR_SYNC,
+                       LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
+                       "Invalid array pointer!!!\n");
+               return;
+       }
+
+       spread_spectrum_data[0] = NULL;
+       *ss_entries_num = 0;
+
+       *ss_entries_num = clk_src->bios->funcs->get_ss_entry_number(
+                       clk_src->bios,
+                       as_signal);
+
+       if (*ss_entries_num == 0)
+               return;
+
+       ss_info = dm_alloc(clk_src->base.ctx, sizeof(struct 
spread_spectrum_info)
+                               * (*ss_entries_num));
+       ss_info_cur = ss_info;
+       if (ss_info == NULL)
+               return;
+
+       ss_data = dm_alloc(clk_src->base.ctx, sizeof(struct 
spread_spectrum_data) *
+                                                       (*ss_entries_num));
+       if (ss_data == NULL)
+               goto out_free_info;
+
+       for (i = 0, ss_info_cur = ss_info;
+               i < (*ss_entries_num);
+               ++i, ++ss_info_cur) {
+
+               bp_result = clk_src->bios->funcs->get_spread_spectrum_info(
+                               clk_src->bios,
+                               as_signal,
+                               i,
+                               ss_info_cur);
+
+               if (bp_result != BP_RESULT_OK)
+                       goto out_free_data;
+       }
+
+       for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data;
+               i < (*ss_entries_num);
+               ++i, ++ss_info_cur, ++ss_data_cur) {
+
+               if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) {
+                       dal_logger_write(clk_src->base.ctx->logger,
+                               LOG_MAJOR_SYNC,
+                               LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
+                               "Invalid ATOMBIOS SS Table!!!\n");
+                       goto out_free_data;
+               }
+
+               /* for HDMI check SS percentage,
+                * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
+               if (as_signal == AS_SIGNAL_TYPE_HDMI
+                               && ss_info_cur->spread_spectrum_percentage > 6){
+                       /* invalid input, do nothing */
+                       dal_logger_write(clk_src->base.ctx->logger,
+                               LOG_MAJOR_SYNC,
+                               LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
+                               "Invalid SS percentage ");
+                       dal_logger_write(clk_src->base.ctx->logger,
+                               LOG_MAJOR_SYNC,
+                               LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
+                               "for HDMI in ATOMBIOS info Table!!!\n");
+                       continue;
+               }
+               if (ss_info_cur->spread_percentage_divider == 1000) {
+                       /* Keep previous precision from ATOMBIOS for these
+                       * in case new precision set by ATOMBIOS for these
+                       * (otherwise all code in DCE specific classes
+                       * for all previous ASICs would need
+                       * to be updated for SS calculations,
+                       * Audio SS compensation and DP DTO SS compensation
+                       * which assumes fixed SS percentage Divider = 100)*/
+                       ss_info_cur->spread_spectrum_percentage /= 10;
+                       ss_info_cur->spread_percentage_divider = 100;
+               }
+
+               ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range;
+               ss_data_cur->percentage =
+                               ss_info_cur->spread_spectrum_percentage;
+               ss_data_cur->percentage_divider =
+                               ss_info_cur->spread_percentage_divider;
+               ss_data_cur->modulation_freq_hz =
+                               ss_info_cur->spread_spectrum_range;
+
+               if (ss_info_cur->type.CENTER_MODE)
+                       ss_data_cur->flags.CENTER_SPREAD = 1;
+
+               if (ss_info_cur->type.EXTERNAL)
+                       ss_data_cur->flags.EXTERNAL_SS = 1;
+
+       }
+
+       *spread_spectrum_data = ss_data;
+       dm_free(clk_src->base.ctx, ss_info);
+       return;
+
+out_free_data:
+       dm_free(clk_src->base.ctx, ss_data);
+       *ss_entries_num = 0;
+out_free_info:
+       dm_free(clk_src->base.ctx, ss_info);
+}
+
+static void ss_info_from_atombios_create(
+       struct dce110_clk_src *clk_src)
+{
+       get_ss_info_from_atombios(
+               clk_src,
+               AS_SIGNAL_TYPE_DISPLAY_PORT,
+               &clk_src->dp_ss_params,
+               &clk_src->dp_ss_params_cnt);
+       get_ss_info_from_atombios(
+               clk_src,
+               AS_SIGNAL_TYPE_HDMI,
+               &clk_src->hdmi_ss_params,
+               &clk_src->hdmi_ss_params_cnt);
+       get_ss_info_from_atombios(
+               clk_src,
+               AS_SIGNAL_TYPE_DVI,
+               &clk_src->dvi_ss_params,
+               &clk_src->dvi_ss_params_cnt);
+}
+
+static bool calc_pll_max_vco_construct(
+                       struct calc_pll_clock_source *calc_pll_cs,
+                       struct calc_pll_clock_source_init_data *init_data)
+{
+       uint32_t i;
+       struct firmware_info fw_info = { { 0 } };
+       if (calc_pll_cs == NULL ||
+                       init_data == NULL ||
+                       init_data->bp == NULL)
+               return false;
+
+       if (init_data->bp->funcs->get_firmware_info(
+                               init_data->bp,
+                               &fw_info) != BP_RESULT_OK)
+               return false;
+
+       calc_pll_cs->ctx = init_data->ctx;
+       calc_pll_cs->ref_freq_khz = fw_info.pll_info.crystal_frequency;
+       calc_pll_cs->min_vco_khz =
+                       fw_info.pll_info.min_output_pxl_clk_pll_frequency;
+       calc_pll_cs->max_vco_khz =
+                       fw_info.pll_info.max_output_pxl_clk_pll_frequency;
+
+       if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0)
+               calc_pll_cs->max_pll_input_freq_khz =
+                       init_data->max_override_input_pxl_clk_pll_freq_khz;
+       else
+               calc_pll_cs->max_pll_input_freq_khz =
+                       fw_info.pll_info.max_input_pxl_clk_pll_frequency;
+
+       if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0)
+               calc_pll_cs->min_pll_input_freq_khz =
+                       init_data->min_override_input_pxl_clk_pll_freq_khz;
+       else
+               calc_pll_cs->min_pll_input_freq_khz =
+                       fw_info.pll_info.min_input_pxl_clk_pll_frequency;
+
+       calc_pll_cs->min_pix_clock_pll_post_divider =
+                       init_data->min_pix_clk_pll_post_divider;
+       calc_pll_cs->max_pix_clock_pll_post_divider =
+                       init_data->max_pix_clk_pll_post_divider;
+       calc_pll_cs->min_pll_ref_divider =
+                       init_data->min_pll_ref_divider;
+       calc_pll_cs->max_pll_ref_divider =
+                       init_data->max_pll_ref_divider;
+
+       if (init_data->num_fract_fb_divider_decimal_point == 0 ||
+               init_data->num_fract_fb_divider_decimal_point_precision >
+                               init_data->num_fract_fb_divider_decimal_point) {
+               dal_logger_write(calc_pll_cs->ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "The dec point num or precision is incorrect!");
+               return false;
+       }
+       if (init_data->num_fract_fb_divider_decimal_point_precision == 0) {
+               dal_logger_write(calc_pll_cs->ctx->logger,
+                       LOG_MAJOR_ERROR,
+                       LOG_MINOR_COMPONENT_GPU,
+                       "Incorrect fract feedback divider precision num!");
+               return false;
+       }
+
+       calc_pll_cs->fract_fb_divider_decimal_points_num =
+                               init_data->num_fract_fb_divider_decimal_point;
+       calc_pll_cs->fract_fb_divider_precision =
+                       init_data->num_fract_fb_divider_decimal_point_precision;
+       calc_pll_cs->fract_fb_divider_factor = 1;
+       for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i)
+               calc_pll_cs->fract_fb_divider_factor *= 10;
+
+       calc_pll_cs->fract_fb_divider_precision_factor = 1;
+       for (
+               i = 0;
+               i < (calc_pll_cs->fract_fb_divider_decimal_points_num -
+                               calc_pll_cs->fract_fb_divider_precision);
+               ++i)
+               calc_pll_cs->fract_fb_divider_precision_factor *= 10;
+
+       return true;
+}
+
+bool 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_reg_offsets *reg_offsets)
+{
+       struct firmware_info fw_info = { { 0 } };
+/* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
+       struct calc_pll_clock_source_init_data calc_pll_cs_init_data = {
+               bios,
+               1, /* minPixelClockPLLPostDivider */
+               PLL_POST_DIV__PLL_POST_DIV_PIXCLK_MASK,
+               /* maxPixelClockPLLPostDivider*/
+               1,/* minPLLRefDivider*/
+               PLL_REF_DIV__PLL_REF_DIV_MASK,/* maxPLLRefDivider*/
+               0,
+/* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
+               0,
+/* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
+               FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
+/*numberOfFractFBDividerDecimalPoints*/
+               FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
+/*number of decimal point to round off for fractional feedback divider value*/
+               ctx
+       };
+/*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
+       struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi = {
+               bios,
+               1, /* minPixelClockPLLPostDivider */
+               PLL_POST_DIV__PLL_POST_DIV_PIXCLK_MASK,
+               /* maxPixelClockPLLPostDivider*/
+               1,/* minPLLRefDivider*/
+               PLL_REF_DIV__PLL_REF_DIV_MASK,/* maxPLLRefDivider*/
+               13500,
+       /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
+               27000,
+       /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
+               FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
+               /*numberOfFractFBDividerDecimalPoints*/
+               FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
+/*number of decimal point to round off for fractional feedback divider value*/
+               ctx
+       };
+
+       clk_src->base.ctx = ctx;
+       clk_src->bios = bios;
+       clk_src->base.id = id;
+       clk_src->base.funcs = &dce110_clk_src_funcs;
+       clk_src->offsets = *reg_offsets;
+
+       if (clk_src->bios->funcs->get_firmware_info(
+                       clk_src->bios, &fw_info) != BP_RESULT_OK) {
+               ASSERT_CRITICAL(false);
+               goto unexpected_failure;
+       }
+
+       clk_src->ext_clk_khz =
+                       fw_info.external_clock_source_frequency_for_dp;
+       clk_src->ref_freq_khz = fw_info.pll_info.crystal_frequency;
+
+       if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL)
+               return true;
+
+       /* PLL only from here on */
+       ss_info_from_atombios_create(clk_src);
+
+       if (!calc_pll_max_vco_construct(
+                       &clk_src->calc_pll,
+                       &calc_pll_cs_init_data)) {
+               ASSERT_CRITICAL(false);
+               goto unexpected_failure;
+       }
+
+       if (clk_src->ref_freq_khz == 48000) {
+               calc_pll_cs_init_data_hdmi.
+                       min_override_input_pxl_clk_pll_freq_khz = 24000;
+               calc_pll_cs_init_data_hdmi.
+                       max_override_input_pxl_clk_pll_freq_khz = 48000;
+       } else if (clk_src->ref_freq_khz == 100000) {
+               calc_pll_cs_init_data_hdmi.
+                       min_override_input_pxl_clk_pll_freq_khz = 25000;
+               calc_pll_cs_init_data_hdmi.
+                       max_override_input_pxl_clk_pll_freq_khz = 50000;
+       }
+
+       if (!calc_pll_max_vco_construct(
+                       &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) {
+               ASSERT_CRITICAL(false);
+               goto unexpected_failure;
+       }
+
+       return true;
+
+unexpected_failure:
+       return false;
+}
+
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.h 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.h
new file mode 100644
index 000000000000..4fa82dad271f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_clock_source.h
@@ -0,0 +1,64 @@
+/* Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_CLOCK_SOURCE_DCE110_H__
+#define __DC_CLOCK_SOURCE_DCE110_H__
+
+#include "../inc/clock_source.h"
+
+#define TO_DCE110_CLK_SRC(clk_src)\
+       container_of(clk_src, struct dce110_clk_src, base)
+
+struct dce110_clk_src_reg_offsets {
+       uint32_t pll_cntl;
+       uint32_t pixclk_resync_cntl;
+};
+
+struct dce110_clk_src {
+       struct clock_source base;
+       struct dce110_clk_src_reg_offsets offsets;
+       struct dc_bios *bios;
+
+       struct spread_spectrum_data *dp_ss_params;
+       uint32_t dp_ss_params_cnt;
+       struct spread_spectrum_data *hdmi_ss_params;
+       uint32_t hdmi_ss_params_cnt;
+       struct spread_spectrum_data *dvi_ss_params;
+       uint32_t dvi_ss_params_cnt;
+
+       uint32_t ext_clk_khz;
+       uint32_t ref_freq_khz;
+
+       struct calc_pll_clock_source calc_pll;
+       struct calc_pll_clock_source calc_pll_hdmi;
+};
+
+bool dce110_clk_src_construct(
+       struct dce110_clk_src *clk_src,
+       struct dc_context *ctx,
+       struct dc_bios *bios,
+       enum clock_source_id,
+       const struct dce110_clk_src_reg_offsets *reg_offsets);
+
+#endif
-- 
2.1.4

Reply via email to