All of lore.kernel.org
 help / color / mirror / Atom feed
From: Harry Wentland <harry.wentland@amd.com>
To: dri-devel@lists.freedesktop.org
Subject: [PATCH 10/29] drm/amd/dal: GPU
Date: Thu, 11 Feb 2016 12:19:50 -0500	[thread overview]
Message-ID: <1455211209-26733-11-git-send-email-harry.wentland@amd.com> (raw)
In-Reply-To: <1455211209-26733-1-git-send-email-harry.wentland@amd.com>

Encapsulates programming for HW blocks which are shared between display
paths, such as clock sources.

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/amd/dal/dc/gpu/Makefile            |  22 +
 .../gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c    |  92 ++
 .../gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h    |  63 ++
 .../amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c |  90 ++
 .../amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h |  33 +
 .../amd/dal/dc/gpu/dce110/display_clock_dce110.c   | 968 +++++++++++++++++++++
 .../amd/dal/dc/gpu/dce110/display_clock_dce110.h   |  53 ++
 drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c     | 205 +++++
 drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h     |  82 ++
 drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c     | 127 +++
 drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h     |  63 ++
 11 files changed, 1798 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/Makefile
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h

diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
new file mode 100644
index 000000000000..b481a6d5c6bb
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the 'gpu' sub-component of DAL.
+# It provides the control and status of HW adapter resources,
+# that are global for the ASIC and sharable between pipes.
+
+GPU = dc_clock_generator.o display_clock.o divider_range.o
+
+AMD_DAL_GPU = $(addprefix $(AMDDALPATH)/dc/gpu/,$(GPU))
+
+AMD_DAL_FILES += $(AMD_DAL_GPU)
+
+
+###############################################################################
+# DCE 110 family
+###############################################################################
+ifdef CONFIG_DRM_AMD_DAL_DCE11_0
+GPU_DCE110 = display_clock_dce110.o dc_clock_gating_dce110.o
+
+AMD_DAL_GPU_DCE110 = $(addprefix $(AMDDALPATH)/dc/gpu/dce110/,$(GPU_DCE110))
+
+AMD_DAL_FILES += $(AMD_DAL_GPU_DCE110)
+endif
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c
new file mode 100644
index 000000000000..b3b0f99933f7
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c
@@ -0,0 +1,92 @@
+/*
+ * 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 "dc_clock_generator.h"
+
+void dal_dc_clock_generator_destroy(struct dc_clock_generator **dc)
+{
+	if (dc == NULL || *dc == NULL) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	(*dc)->funcs->destroy(dc);
+
+	*dc = NULL;
+}
+
+void dal_dc_clock_generator_set_display_pipe_mapping(
+	struct dc_clock_generator *dc_clk_gen,
+	struct dccg_mapping_params *params)
+{
+	dc_clk_gen->funcs->set_display_pipe_mapping(dc_clk_gen, params);
+}
+
+bool dal_dc_clock_generator_get_dp_ref_clk_ds_params(
+	struct dc_clock_generator *dc_clk_gen,
+	struct dccg_dp_ref_clk_ds_params *params)
+{
+	return dc_clk_gen->funcs->get_dp_ref_clk_ds_params(dc_clk_gen, params);
+}
+
+bool dal_dc_clock_generator_enable_gtc_counter(
+	struct dc_clock_generator *dc_clk_gen,
+	uint32_t dprefclk)
+{
+	return dc_clk_gen->funcs->enable_gtc_counter(dc_clk_gen, dprefclk);
+}
+
+void dal_dc_clock_generator_disable_gtc_counter(
+	struct dc_clock_generator *dc_clk_gen)
+{
+	dc_clk_gen->funcs->disable_gtc_counter(dc_clk_gen);
+}
+
+void dal_dc_clock_generator_set_gtc_group_offset(
+	struct dc_clock_generator *dc_clk_gen,
+	enum gtc_group group_num,
+	uint32_t offset)
+{
+	dc_clk_gen->funcs->set_gtc_group_offset(dc_clk_gen, group_num, offset);
+}
+
+void dal_dc_clock_generator_base_set_display_pipe_mapping(
+	struct dc_clock_generator *base,
+	struct dccg_mapping_params *params)
+{
+
+}
+
+bool dal_dc_clock_generator_construct_base(
+	struct dc_clock_generator *base,
+	struct dc_context *ctx
+)
+{
+	base->ctx = ctx;
+	return true;
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h
new file mode 100644
index 000000000000..d1bf1af0500a
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h
@@ -0,0 +1,63 @@
+/*
+ * 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 __DAL_DC_CLOCK_GENERATOR_H__
+#define __DAL_DC_CLOCK_GENERATOR_H__
+
+#include "include/dc_clock_generator_interface.h"
+
+struct dc_clock_generator_funcs {
+	void (*destroy)(struct dc_clock_generator **to_destroy);
+
+	void (*set_display_pipe_mapping)(
+		struct dc_clock_generator *dc_clk_gen,
+		struct dccg_mapping_params *params);
+
+	bool (*get_dp_ref_clk_ds_params)(
+		struct dc_clock_generator *dc_clk_gen,
+		struct dccg_dp_ref_clk_ds_params *params);
+	bool (*enable_gtc_counter)(
+		struct dc_clock_generator *dc_clk_gen,
+		uint32_t dprefclk);
+	void (*disable_gtc_counter)(
+		struct dc_clock_generator *dc_clk_gen);
+	void (*set_gtc_group_offset)(
+		struct dc_clock_generator *dc_clk_gen,
+		enum gtc_group group_num,
+		uint32_t offset);
+};
+struct dc_clock_generator {
+	const struct dc_clock_generator_funcs *funcs;
+	struct dc_context *ctx;
+};
+bool dal_dc_clock_generator_construct_base(
+	struct dc_clock_generator *base,
+	struct dc_context *ctx
+);
+void dal_dc_clock_generator_base_set_display_pipe_mapping(
+	struct dc_clock_generator *base,
+	struct dccg_mapping_params *params);
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c
new file mode 100644
index 000000000000..4c307f6baf5a
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c
@@ -0,0 +1,90 @@
+/*
+ * 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 "include/logger_interface.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+#include "dc_clock_gating_dce110.h"
+
+/******************************************************************************
+ * Macro definitions
+ *****************************************************************************/
+
+#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_GPU, \
+		"%s:%s()\n", __FILE__, __func__)
+
+/******************************************************************************
+ * static functions
+ *****************************************************************************/
+static void force_hw_base_light_sleep(struct dc_context *ctx)
+{
+	uint32_t addr = 0;
+	uint32_t value = 0;
+
+
+	addr = mmDC_MEM_GLOBAL_PWR_REQ_CNTL;
+	/* Read the mmDC_MEM_GLOBAL_PWR_REQ_CNTL to get the currently
+	 * programmed DC_MEM_GLOBAL_PWR_REQ_DIS*/
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+			value,
+			1,
+			DC_MEM_GLOBAL_PWR_REQ_CNTL,
+			DC_MEM_GLOBAL_PWR_REQ_DIS);
+
+	dm_write_reg(ctx, addr, value);
+
+}
+
+static void enable_hw_base_light_sleep(struct dc_context *ctx)
+{
+	NOT_IMPLEMENTED();
+}
+
+static void disable_sw_manual_control_light_sleep(
+		struct dc_context *ctx)
+{
+	NOT_IMPLEMENTED();
+}
+
+/******************************************************************************
+ * public functions
+ *****************************************************************************/
+
+void dal_dc_clock_gating_dce110_power_up(
+		struct dc_context *ctx,
+		bool enable)
+{
+	if (enable) {
+		enable_hw_base_light_sleep(ctx);
+		disable_sw_manual_control_light_sleep(ctx);
+	} else {
+		force_hw_base_light_sleep(ctx);
+	}
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h
new file mode 100644
index 000000000000..1bfd75a1fb51
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h
@@ -0,0 +1,33 @@
+/*
+ * 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 __DAL_DC_CLOCK_GATING_DCE110_H__
+#define __DAL_DC_CLOCK_GATING_DCE110_H__
+
+void dal_dc_clock_gating_dce110_power_up(
+		struct dc_context *ctx,
+		bool enable);
+
+#endif /* __DAL_DC_CLOCK_GATING_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c
new file mode 100644
index 000000000000..15243dea3290
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c
@@ -0,0 +1,968 @@
+/*
+ * 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 "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#include "include/adapter_service_interface.h"
+#include "include/bios_parser_interface.h"
+#include "include/fixed32_32.h"
+#include "include/logger_interface.h"
+
+#include "../divider_range.h"
+
+#include "display_clock_dce110.h"
+
+#define FROM_DISPLAY_CLOCK(base) \
+	container_of(base, struct display_clock_dce110, disp_clk_base)
+
+static struct state_dependent_clocks max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
+
+
+/* Starting point for each divider range.*/
+enum divider_range_start {
+	DIVIDER_RANGE_01_START = 200, /* 2.00*/
+	DIVIDER_RANGE_02_START = 1600, /* 16.00*/
+	DIVIDER_RANGE_03_START = 3200, /* 32.00*/
+	DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/
+};
+
+/* Array identifiers and count for the divider ranges.*/
+enum divider_range_count {
+	DIVIDER_RANGE_01 = 0,
+	DIVIDER_RANGE_02,
+	DIVIDER_RANGE_03,
+	DIVIDER_RANGE_MAX /* == 3*/
+};
+
+/* Ranges for divider identifiers (Divider ID or DID)
+ mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/
+enum divider_id_register_setting {
+	DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08,
+	DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40,
+	DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60,
+	DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80
+};
+
+/* Step size between each divider within a range.
+ Incrementing the DENTIST_DISPCLK_WDIVIDER by one
+ will increment the divider by this much.*/
+enum divider_range_step_size {
+	DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/
+	DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/
+	DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */
+};
+
+static struct divider_range divider_ranges[DIVIDER_RANGE_MAX];
+
+#define DCE110_DFS_BYPASS_THRESHOLD_KHZ 400000
+/*****************************************************************************
+ * static functions
+ *****************************************************************************/
+
+/*
+ * store_max_clocks_state
+ *
+ * @brief
+ * Cache the clock state
+ *
+ * @param
+ * struct display_clock *base - [out] cach the state in this structure
+ * enum clocks_state max_clocks_state - [in] state to be stored
+ */
+static void store_max_clocks_state(
+	struct display_clock *base,
+	enum clocks_state max_clocks_state)
+{
+	struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
+
+	switch (max_clocks_state) {
+	case CLOCKS_STATE_LOW:
+	case CLOCKS_STATE_NOMINAL:
+	case CLOCKS_STATE_PERFORMANCE:
+	case CLOCKS_STATE_ULTRA_LOW:
+		dc->max_clks_state = max_clocks_state;
+		break;
+
+	case CLOCKS_STATE_INVALID:
+	default:
+		/*Invalid Clocks State!*/
+		ASSERT_CRITICAL(false);
+		break;
+	}
+}
+
+static enum clocks_state get_min_clocks_state(struct display_clock *base)
+{
+	return base->cur_min_clks_state;
+}
+
+static bool set_min_clocks_state(
+	struct display_clock *base,
+	enum clocks_state clocks_state)
+{
+	struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
+
+	if (clocks_state > dc->max_clks_state) {
+		/*Requested state exceeds max supported state.*/
+		dal_logger_write(base->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Requested state exceeds max supported state");
+		return false;
+	} else if (clocks_state == base->cur_min_clks_state) {
+		/*if we're trying to set the same state, we can just return
+		 * since nothing needs to be done*/
+		return true;
+	}
+
+	base->cur_min_clks_state = clocks_state;
+
+	return true;
+}
+
+static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc)
+{
+	uint32_t dispclk_cntl_value;
+	uint32_t dp_ref_clk_cntl_value;
+	uint32_t dp_ref_clk_cntl_src_sel_value;
+	uint32_t dp_ref_clk_khz = 600000;
+	uint32_t target_div = INVALID_DIVIDER;
+	struct display_clock_dce110 *disp_clk = FROM_DISPLAY_CLOCK(dc);
+
+	/* ASSERT DP Reference Clock source is from DFS*/
+	dp_ref_clk_cntl_value = dm_read_reg(dc->ctx,
+			mmDPREFCLK_CNTL);
+
+	dp_ref_clk_cntl_src_sel_value =
+			get_reg_field_value(
+				dp_ref_clk_cntl_value,
+				DPREFCLK_CNTL, DPREFCLK_SRC_SEL);
+
+	ASSERT(dp_ref_clk_cntl_src_sel_value == 0);
+
+	/* Read the mmDENTIST_DISPCLK_CNTL to get the currently
+	 * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
+	dispclk_cntl_value = dm_read_reg(dc->ctx,
+			mmDENTIST_DISPCLK_CNTL);
+
+	/* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
+	target_div = dal_divider_range_get_divider(
+		divider_ranges,
+		DIVIDER_RANGE_MAX,
+		get_reg_field_value(dispclk_cntl_value,
+			DENTIST_DISPCLK_CNTL,
+			DENTIST_DPREFCLK_WDIVIDER));
+
+
+	if (target_div != INVALID_DIVIDER) {
+		/* Calculate the current DFS clock, in kHz.*/
+		dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR
+			* disp_clk->dentist_vco_freq_khz) / target_div;
+	}
+
+	/* SW will adjust DP REF Clock average value for all purposes
+	 * (DP DTO / DP Audio DTO and DP GTC)
+	 if clock is spread for all cases:
+	 -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
+	 calculations for DS_INCR/DS_MODULO (this is planned to be default case)
+	 -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
+	 calculations (not planned to be used, but average clock should still
+	 be valid)
+	 -if SS enabled on DP Ref clock and HW de-spreading disabled
+	 (should not be case with CIK) then SW should program all rates
+	 generated according to average value (case as with previous ASICs)
+	  */
+	if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) {
+		struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
+				dal_fixed32_32_from_fraction(
+					disp_clk->gpu_pll_ss_percentage,
+					disp_clk->gpu_pll_ss_divider), 200);
+		struct fixed32_32 adj_dp_ref_clk_khz;
+
+		ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
+								ss_percentage);
+		adj_dp_ref_clk_khz =
+			dal_fixed32_32_mul_int(
+				ss_percentage,
+				dp_ref_clk_khz);
+		dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
+	}
+
+	return dp_ref_clk_khz;
+}
+
+
+static void destroy(struct display_clock **base)
+{
+	struct display_clock_dce110 *dc110;
+
+	dc110 = DCLCK110_FROM_BASE(*base);
+
+	dm_free((*base)->ctx, dc110);
+
+	*base = NULL;
+}
+
+static uint32_t get_validation_clock(struct display_clock *dc)
+{
+	uint32_t clk = 0;
+	struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
+
+	switch (disp_clk->max_clks_state) {
+	case CLOCKS_STATE_ULTRA_LOW:
+		/*Currently not supported, it has 0 in table entry*/
+	case CLOCKS_STATE_LOW:
+		clk = max_clks_by_state[CLOCKS_STATE_LOW].
+						display_clk_khz;
+		break;
+
+	case CLOCKS_STATE_NOMINAL:
+		clk = max_clks_by_state[CLOCKS_STATE_NOMINAL].
+						display_clk_khz;
+		break;
+
+	case CLOCKS_STATE_PERFORMANCE:
+		clk = max_clks_by_state[CLOCKS_STATE_PERFORMANCE].
+						display_clk_khz;
+		break;
+
+	case CLOCKS_STATE_INVALID:
+	default:
+		/*Invalid Clocks State*/
+		dal_logger_write(dc->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Invalid clock state");
+		/* just return the display engine clock for
+		 * lowest supported state*/
+		clk = max_clks_by_state[CLOCKS_STATE_LOW].
+						display_clk_khz;
+		break;
+	}
+	return clk;
+}
+
+static struct fixed32_32 get_deep_color_factor(struct min_clock_params *params)
+{
+	/* DeepColorFactor = IF (HDMI = True, bpp / 24, 1)*/
+	struct fixed32_32 deep_color_factor = dal_fixed32_32_from_int(1);
+
+	if (params->signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
+		return deep_color_factor;
+
+	switch (params->deep_color_depth) {
+	case COLOR_DEPTH_101010:
+		/*deep color ratio for 30bpp is 30/24 = 1.25*/
+		deep_color_factor = dal_fixed32_32_from_fraction(30, 24);
+		break;
+
+	case COLOR_DEPTH_121212:
+		/* deep color ratio for 36bpp is 36/24 = 1.5*/
+		deep_color_factor = dal_fixed32_32_from_fraction(36, 24);
+		break;
+
+	case COLOR_DEPTH_161616:
+		/* deep color ratio for 48bpp is 48/24 = 2.0 */
+		deep_color_factor = dal_fixed32_32_from_fraction(48, 24);
+		break;
+	default:
+		break;
+	}
+	return deep_color_factor;
+}
+
+static struct fixed32_32 get_scaler_efficiency(
+	struct dc_context *ctx,
+	struct min_clock_params *params)
+{
+	struct fixed32_32 scaler_efficiency = dal_fixed32_32_from_int(3);
+
+	if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB18BPP) {
+		scaler_efficiency =
+			dal_fixed32_32_add(
+				dal_fixed32_32_from_fraction(35555, 10000),
+				dal_fixed32_32_from_fraction(
+					55556,
+					100000 * 10000));
+	} else if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB24BPP) {
+		scaler_efficiency =
+			dal_fixed32_32_add(
+				dal_fixed32_32_from_fraction(34285, 10000),
+				dal_fixed32_32_from_fraction(
+					71429,
+					100000 * 10000));
+	} else if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB30BPP)
+		scaler_efficiency = dal_fixed32_32_from_fraction(32, 10);
+
+	return scaler_efficiency;
+}
+
+static struct fixed32_32 get_lb_lines_in_per_line_out(
+		struct min_clock_params *params,
+		struct fixed32_32 v_scale_ratio)
+{
+	struct fixed32_32 two = dal_fixed32_32_from_int(2);
+	struct fixed32_32 four = dal_fixed32_32_from_int(4);
+	struct fixed32_32 f4_to_3 = dal_fixed32_32_from_fraction(4, 3);
+	struct fixed32_32 f6_to_4 = dal_fixed32_32_from_fraction(6, 4);
+
+	if (params->line_buffer_prefetch_enabled)
+		return dal_fixed32_32_max(v_scale_ratio, dal_fixed32_32_one);
+	else if (dal_fixed32_32_le(v_scale_ratio, dal_fixed32_32_one))
+		return dal_fixed32_32_one;
+	else if (dal_fixed32_32_le(v_scale_ratio, f4_to_3))
+		return f4_to_3;
+	else if (dal_fixed32_32_le(v_scale_ratio, f6_to_4))
+		return f6_to_4;
+	else if (dal_fixed32_32_le(v_scale_ratio, two))
+		return two;
+	else if (dal_fixed32_32_le(v_scale_ratio, dal_fixed32_32_from_int(3)))
+		return four;
+	else
+		return dal_fixed32_32_zero;
+}
+
+static uint32_t get_actual_required_display_clk(
+	struct display_clock_dce110 *disp_clk,
+	uint32_t target_clk_khz)
+{
+	uint32_t disp_clk_khz = target_clk_khz;
+	uint32_t div = INVALID_DIVIDER;
+	uint32_t did = INVALID_DID;
+	uint32_t scaled_vco =
+		disp_clk->dentist_vco_freq_khz * DIVIDER_RANGE_SCALE_FACTOR;
+
+	ASSERT_CRITICAL(!!disp_clk_khz);
+
+	if (disp_clk_khz)
+		div = scaled_vco / disp_clk_khz;
+
+	did = dal_divider_range_get_did(divider_ranges, DIVIDER_RANGE_MAX, div);
+
+	if (did != INVALID_DID) {
+		div = dal_divider_range_get_divider(
+			divider_ranges, DIVIDER_RANGE_MAX, did);
+
+		if ((div != INVALID_DIVIDER) &&
+			(did > DIVIDER_RANGE_01_BASE_DIVIDER_ID))
+			if (disp_clk_khz > (scaled_vco / div))
+				div = dal_divider_range_get_divider(
+					divider_ranges, DIVIDER_RANGE_MAX,
+					did - 1);
+
+		if (div != INVALID_DIVIDER)
+			disp_clk_khz = scaled_vco / div;
+
+	}
+	/* We need to add 10KHz to this value because the accuracy in VBIOS is
+	 in 10KHz units. So we need to always round the last digit up in order
+	 to reach the next div level.*/
+	return disp_clk_khz + 10;
+}
+
+static uint32_t calc_single_display_min_clks(
+	struct display_clock *base,
+	struct min_clock_params *params,
+	bool set_clk)
+{
+	struct fixed32_32 h_scale_ratio = dal_fixed32_32_one;
+	struct fixed32_32 v_scale_ratio = dal_fixed32_32_one;
+	uint32_t pix_clk_khz = 0;
+	uint32_t lb_source_width = 0;
+	struct fixed32_32 deep_color_factor;
+	struct fixed32_32 scaler_efficiency;
+	struct fixed32_32 v_filter_init;
+	uint32_t v_filter_init_trunc;
+	uint32_t num_lines_at_frame_start = 3;
+	struct fixed32_32 v_filter_init_ceil;
+	struct fixed32_32 lines_per_lines_out_at_frame_start;
+	struct fixed32_32 lb_lines_in_per_line_out; /* in middle of the frame*/
+	uint32_t src_wdth_rnd_to_chunks;
+	struct fixed32_32 scaling_coeff;
+	struct fixed32_32 h_blank_granularity_factor =
+			dal_fixed32_32_one;
+	struct fixed32_32 fx_disp_clk_mhz;
+	struct fixed32_32 line_time;
+	struct fixed32_32 disp_pipe_pix_throughput;
+	struct fixed32_32 fx_alt_disp_clk_mhz;
+	uint32_t disp_clk_khz;
+	uint32_t alt_disp_clk_khz;
+	struct display_clock_dce110 *disp_clk_110 = DCLCK110_FROM_BASE(base);
+	uint32_t max_clk_khz = get_validation_clock(base);
+	bool panning_allowed = false; /* TODO: receive this value from AS */
+
+	if (params == NULL) {
+		dal_logger_write(base->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Invalid input parameter in %s",
+				__func__);
+		return 0;
+	}
+
+	deep_color_factor = get_deep_color_factor(params);
+	scaler_efficiency = get_scaler_efficiency(base->ctx, params);
+	pix_clk_khz = params->requested_pixel_clock;
+	lb_source_width = params->source_view.width;
+
+	if (0 != params->dest_view.height && 0 != params->dest_view.width) {
+
+		h_scale_ratio = dal_fixed32_32_from_fraction(
+			params->source_view.width,
+			params->dest_view.width);
+		v_scale_ratio = dal_fixed32_32_from_fraction(
+			params->source_view.height,
+			params->dest_view.height);
+	} else {
+		dal_logger_write(base->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"Destination height or width is 0!\n");
+	}
+
+	v_filter_init =
+		dal_fixed32_32_add(
+			v_scale_ratio,
+			dal_fixed32_32_add_int(
+				dal_fixed32_32_div_int(
+					dal_fixed32_32_mul_int(
+						v_scale_ratio,
+						params->timing_info.INTERLACED),
+					2),
+				params->scaling_info.v_taps + 1));
+	v_filter_init = dal_fixed32_32_div_int(v_filter_init, 2);
+
+	v_filter_init_trunc = dal_fixed32_32_floor(v_filter_init);
+
+	v_filter_init_ceil = dal_fixed32_32_from_fraction(
+						v_filter_init_trunc, 2);
+	v_filter_init_ceil = dal_fixed32_32_from_int(
+		dal_fixed32_32_ceil(v_filter_init_ceil));
+	v_filter_init_ceil = dal_fixed32_32_mul_int(v_filter_init_ceil, 2);
+
+	lines_per_lines_out_at_frame_start =
+			dal_fixed32_32_div_int(v_filter_init_ceil,
+					num_lines_at_frame_start);
+	lb_lines_in_per_line_out =
+			get_lb_lines_in_per_line_out(params, v_scale_ratio);
+
+	if (panning_allowed)
+		src_wdth_rnd_to_chunks =
+			((lb_source_width - 1) / 128) * 128 + 256;
+	else
+		src_wdth_rnd_to_chunks =
+			((lb_source_width + 127) / 128) * 128;
+
+	scaling_coeff =
+		dal_fixed32_32_div(
+			dal_fixed32_32_from_int(params->scaling_info.v_taps),
+			scaler_efficiency);
+
+	if (dal_fixed32_32_le(h_scale_ratio, dal_fixed32_32_one))
+		scaling_coeff = dal_fixed32_32_max(
+			dal_fixed32_32_from_int(
+				dal_fixed32_32_ceil(
+					dal_fixed32_32_from_fraction(
+						params->scaling_info.h_taps,
+						4))),
+			dal_fixed32_32_max(
+				dal_fixed32_32_mul(
+					scaling_coeff,
+					h_scale_ratio),
+				dal_fixed32_32_one));
+
+	if (!params->line_buffer_prefetch_enabled &&
+		dal_fixed32_32_floor(lb_lines_in_per_line_out) != 2 &&
+		dal_fixed32_32_floor(lb_lines_in_per_line_out) != 4) {
+		uint32_t line_total_pixel =
+			params->timing_info.h_total + lb_source_width - 256;
+		h_blank_granularity_factor = dal_fixed32_32_div(
+			dal_fixed32_32_from_int(params->timing_info.h_total),
+			dal_fixed32_32_div(
+			dal_fixed32_32_from_fraction(
+				line_total_pixel, 2),
+				h_scale_ratio));
+	}
+
+	/* Calculate display clock with ramping. Ramping factor is 1.1*/
+	fx_disp_clk_mhz =
+		dal_fixed32_32_div_int(
+			dal_fixed32_32_mul_int(scaling_coeff, 11),
+			10);
+	line_time = dal_fixed32_32_from_fraction(
+			params->timing_info.h_total * 1000, pix_clk_khz);
+
+	disp_pipe_pix_throughput = dal_fixed32_32_mul(
+			lb_lines_in_per_line_out, h_blank_granularity_factor);
+	disp_pipe_pix_throughput = dal_fixed32_32_max(
+			disp_pipe_pix_throughput,
+			lines_per_lines_out_at_frame_start);
+	disp_pipe_pix_throughput = dal_fixed32_32_div(dal_fixed32_32_mul_int(
+			disp_pipe_pix_throughput, src_wdth_rnd_to_chunks),
+			line_time);
+
+	if (0 != params->timing_info.h_total) {
+		fx_disp_clk_mhz =
+			dal_fixed32_32_max(
+				dal_fixed32_32_div_int(
+					dal_fixed32_32_mul_int(
+						scaling_coeff, pix_clk_khz),
+						1000),
+				disp_pipe_pix_throughput);
+		fx_disp_clk_mhz =
+			dal_fixed32_32_mul(
+				fx_disp_clk_mhz,
+				dal_fixed32_32_from_fraction(11, 10));
+	}
+
+	fx_disp_clk_mhz = dal_fixed32_32_max(fx_disp_clk_mhz,
+		dal_fixed32_32_mul(deep_color_factor,
+		dal_fixed32_32_from_fraction(11, 10)));
+
+	/* Calculate display clock without ramping */
+	fx_alt_disp_clk_mhz = scaling_coeff;
+
+	if (0 != params->timing_info.h_total) {
+		fx_alt_disp_clk_mhz = dal_fixed32_32_max(
+				dal_fixed32_32_div_int(dal_fixed32_32_mul_int(
+						scaling_coeff, pix_clk_khz),
+						1000),
+				dal_fixed32_32_div_int(dal_fixed32_32_mul_int(
+						disp_pipe_pix_throughput, 105),
+						100));
+	}
+
+	if (set_clk && disp_clk_110->ss_on_gpu_pll &&
+			disp_clk_110->gpu_pll_ss_divider)
+		fx_alt_disp_clk_mhz = dal_fixed32_32_mul(fx_alt_disp_clk_mhz,
+				dal_fixed32_32_add_int(
+				dal_fixed32_32_div_int(
+				dal_fixed32_32_div_int(
+				dal_fixed32_32_from_fraction(
+				disp_clk_110->gpu_pll_ss_percentage,
+				disp_clk_110->gpu_pll_ss_divider), 100),
+				2),
+				1));
+
+	/* convert to integer */
+	disp_clk_khz = dal_fixed32_32_round(
+			dal_fixed32_32_mul_int(fx_disp_clk_mhz, 1000));
+	alt_disp_clk_khz = dal_fixed32_32_round(
+			dal_fixed32_32_mul_int(fx_alt_disp_clk_mhz, 1000));
+
+	if ((disp_clk_khz > max_clk_khz) && (alt_disp_clk_khz <= max_clk_khz))
+		disp_clk_khz = alt_disp_clk_khz;
+
+	if (set_clk) { /* only compensate clock if we are going to set it.*/
+		disp_clk_khz = get_actual_required_display_clk(
+			disp_clk_110, disp_clk_khz);
+	}
+
+	disp_clk_khz = disp_clk_khz > max_clk_khz ? max_clk_khz : disp_clk_khz;
+
+	return disp_clk_khz;
+}
+
+static uint32_t calculate_min_clock(
+	struct display_clock *base,
+	uint32_t path_num,
+	struct min_clock_params *params)
+{
+	uint32_t i;
+	uint32_t validation_clk_khz =
+			get_validation_clock(base);
+	uint32_t min_clk_khz = validation_clk_khz;
+	uint32_t max_clk_khz = 0;
+	struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
+
+	if (dc->use_max_disp_clk)
+		return min_clk_khz;
+
+	if (params != NULL) {
+		uint32_t disp_clk_khz = 0;
+
+		for (i = 0; i < path_num; ++i) {
+
+			disp_clk_khz = calc_single_display_min_clks(
+							base, params, true);
+
+			/* update the max required clock found*/
+			if (disp_clk_khz > max_clk_khz)
+				max_clk_khz = disp_clk_khz;
+
+			params++;
+		}
+	}
+
+	min_clk_khz = max_clk_khz;
+
+	if (min_clk_khz > validation_clk_khz)
+		min_clk_khz = validation_clk_khz;
+	else if (min_clk_khz < base->min_display_clk_threshold_khz)
+		min_clk_khz = base->min_display_clk_threshold_khz;
+
+	if (dc->use_max_disp_clk)
+		min_clk_khz = get_validation_clock(base);
+
+	return min_clk_khz;
+}
+
+static bool display_clock_integrated_info_construct(
+	struct display_clock_dce110 *disp_clk,
+	struct adapter_service *as)
+{
+	struct integrated_info info;
+	struct firmware_info fw_info;
+	uint32_t i;
+	struct display_clock *base = &disp_clk->disp_clk_base;
+	bool res;
+
+	dm_memset(&info, 0, sizeof(struct integrated_info));
+	dm_memset(&fw_info, 0, sizeof(struct firmware_info));
+
+	res = dal_adapter_service_get_integrated_info(as, &info);
+
+	disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq;
+	if (disp_clk->dentist_vco_freq_khz == 0) {
+		dal_adapter_service_get_firmware_info(as, &fw_info);
+		disp_clk->dentist_vco_freq_khz =
+			fw_info.smu_gpu_pll_output_freq;
+		if (disp_clk->dentist_vco_freq_khz == 0)
+			disp_clk->dentist_vco_freq_khz = 3600000;
+	}
+
+	base->min_display_clk_threshold_khz =
+		disp_clk->dentist_vco_freq_khz / 64;
+
+	if (!res)
+		return false;
+
+	/*update the maximum display clock for each power state*/
+	for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
+		enum clocks_state clk_state = CLOCKS_STATE_INVALID;
+
+		switch (i) {
+		case 0:
+			clk_state = CLOCKS_STATE_ULTRA_LOW;
+			break;
+
+		case 1:
+			clk_state = CLOCKS_STATE_LOW;
+			break;
+
+		case 2:
+			clk_state = CLOCKS_STATE_NOMINAL;
+			break;
+
+		case 3:
+			clk_state = CLOCKS_STATE_PERFORMANCE;
+			break;
+
+		default:
+			clk_state = CLOCKS_STATE_INVALID;
+			break;
+		}
+
+		/*Do not allow bad VBIOS/SBIOS to override with invalid values,
+		 * check for > 100MHz*/
+		if (info.disp_clk_voltage[i].max_supported_clk >= 100000) {
+			max_clks_by_state[clk_state].display_clk_khz =
+				info.disp_clk_voltage[i].max_supported_clk;
+		}
+	}
+	disp_clk->dfs_bypass_enabled =
+		dal_adapter_service_is_dfs_bypass_enabled(as);
+	disp_clk->use_max_disp_clk =
+		dal_adapter_service_is_feature_supported(
+			FEATURE_USE_MAX_DISPLAY_CLK);
+
+	return true;
+}
+
+static uint32_t get_clock(struct display_clock *dc)
+{
+	uint32_t disp_clock = get_validation_clock(dc);
+	uint32_t target_div = INVALID_DIVIDER;
+	uint32_t addr = mmDENTIST_DISPCLK_CNTL;
+	uint32_t value = 0;
+	uint32_t field = 0;
+	struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
+
+	if (disp_clk->dfs_bypass_enabled && disp_clk->dfs_bypass_disp_clk)
+		return disp_clk->dfs_bypass_disp_clk;
+
+	/* Read the mmDENTIST_DISPCLK_CNTL to get the currently programmed
+	 DID DENTIST_DISPCLK_WDIVIDER.*/
+	value = dm_read_reg(dc->ctx, addr);
+	field = get_reg_field_value(
+			value, DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER);
+
+	/* Convert DENTIST_DISPCLK_WDIVIDER to actual divider*/
+	target_div = dal_divider_range_get_divider(
+		divider_ranges,
+		DIVIDER_RANGE_MAX,
+		field);
+
+	if (target_div != INVALID_DIVIDER)
+		/* Calculate the current DFS clock in KHz.
+		 Should be okay up to 42.9 THz before overflowing.*/
+		disp_clock = (DIVIDER_RANGE_SCALE_FACTOR
+			* disp_clk->dentist_vco_freq_khz) / target_div;
+	return disp_clock;
+}
+
+static enum clocks_state get_required_clocks_state(
+		struct display_clock *dc,
+		struct state_dependent_clocks *req_clocks)
+{
+	int32_t i;
+	struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
+	enum clocks_state low_req_clk = disp_clk->max_clks_state;
+
+	if (!req_clocks) {
+		/* NULL pointer*/
+		dal_logger_write(dc->ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_GPU,
+				"%s: Invalid parameter",
+				__func__);
+		return CLOCKS_STATE_INVALID;
+	}
+
+	/* Iterate from highest supported to lowest valid state, and update
+	 * lowest RequiredState with the lowest state that satisfies
+	 * all required clocks
+	 */
+	for (i = disp_clk->max_clks_state; i >= CLOCKS_STATE_ULTRA_LOW; --i) {
+		if ((req_clocks->display_clk_khz <=
+			max_clks_by_state[i].display_clk_khz) &&
+			(req_clocks->pixel_clk_khz <=
+				max_clks_by_state[i].pixel_clk_khz))
+			low_req_clk = i;
+	}
+	return low_req_clk;
+}
+
+static void set_clock(
+	struct display_clock *base,
+	uint32_t requested_clk_khz)
+{
+	struct bp_pixel_clock_parameters pxl_clk_params;
+	struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
+	struct dc_bios *bp = dal_adapter_service_get_bios_parser(base->as);
+
+	/* Prepare to program display clock*/
+	dm_memset(&pxl_clk_params, 0, sizeof(pxl_clk_params));
+
+	pxl_clk_params.target_pixel_clock = requested_clk_khz;
+	pxl_clk_params.pll_id = base->id;
+
+	bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
+
+	if (dc->dfs_bypass_enabled) {
+
+		/* Cache the fixed display clock*/
+		dc->dfs_bypass_disp_clk =
+			pxl_clk_params.dfs_bypass_display_clock;
+	}
+
+	/* from power down, we need mark the clock state as ClocksStateNominal
+	 * from HWReset, so when resume we will call pplib voltage regulator.*/
+	if (requested_clk_khz == 0)
+		base->cur_min_clks_state = CLOCKS_STATE_NOMINAL;
+}
+
+static void set_clock_state(
+	struct display_clock *dc,
+	struct display_clock_state clk_state)
+{
+	struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
+
+	disp_clk->clock_state = clk_state;
+}
+
+static struct display_clock_state get_clock_state(
+	struct display_clock *dc)
+{
+	struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
+
+	return disp_clk->clock_state;
+}
+
+static uint32_t get_dfs_bypass_threshold(struct display_clock *dc)
+{
+	return DCE110_DFS_BYPASS_THRESHOLD_KHZ;
+}
+
+static const struct display_clock_funcs funcs = {
+	.destroy = destroy,
+	.calculate_min_clock = calculate_min_clock,
+	.get_clock = get_clock,
+	.get_clock_state = get_clock_state,
+	.get_dfs_bypass_threshold = get_dfs_bypass_threshold,
+	.get_dp_ref_clk_frequency = get_dp_ref_clk_frequency,
+	.get_min_clocks_state = get_min_clocks_state,
+	.get_required_clocks_state = get_required_clocks_state,
+	.get_validation_clock = get_validation_clock,
+	.set_clock = set_clock,
+	.set_clock_state = set_clock_state,
+	.set_dp_ref_clock_source = NULL,
+	.set_min_clocks_state = set_min_clocks_state,
+	.store_max_clocks_state = store_max_clocks_state,
+	.validate = NULL,
+};
+
+static bool dal_display_clock_dce110_construct(
+	struct display_clock_dce110 *dc110,
+	struct dc_context *ctx,
+	struct adapter_service *as)
+{
+	struct display_clock *dc_base = &dc110->disp_clk_base;
+
+	if (NULL == as)
+		return false;
+
+	if (!dal_display_clock_construct_base(dc_base, ctx, as))
+		return false;
+
+	dc_base->funcs = &funcs;
+
+	dc110->dfs_bypass_disp_clk = 0;
+
+	if (!display_clock_integrated_info_construct(dc110, as))
+		dal_logger_write(dc_base->ctx->logger,
+			LOG_MAJOR_WARNING,
+			LOG_MINOR_COMPONENT_GPU,
+			"Cannot obtain VBIOS integrated info\n");
+
+	dc110->gpu_pll_ss_percentage = 0;
+	dc110->gpu_pll_ss_divider = 1000;
+	dc110->ss_on_gpu_pll = false;
+
+	dc_base->id = CLOCK_SOURCE_ID_DFS;
+/* Initially set max clocks state to nominal.  This should be updated by
+ * via a pplib call to DAL IRI eventually calling a
+ * DisplayEngineClock_Dce110::StoreMaxClocksState().  This call will come in
+ * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/
+	dc110->max_clks_state = CLOCKS_STATE_NOMINAL;
+
+	dal_divider_range_construct(
+		&divider_ranges[DIVIDER_RANGE_01],
+		DIVIDER_RANGE_01_START,
+		DIVIDER_RANGE_01_STEP_SIZE,
+		DIVIDER_RANGE_01_BASE_DIVIDER_ID,
+		DIVIDER_RANGE_02_BASE_DIVIDER_ID);
+	dal_divider_range_construct(
+		&divider_ranges[DIVIDER_RANGE_02],
+		DIVIDER_RANGE_02_START,
+		DIVIDER_RANGE_02_STEP_SIZE,
+		DIVIDER_RANGE_02_BASE_DIVIDER_ID,
+		DIVIDER_RANGE_03_BASE_DIVIDER_ID);
+	dal_divider_range_construct(
+		&divider_ranges[DIVIDER_RANGE_03],
+		DIVIDER_RANGE_03_START,
+		DIVIDER_RANGE_03_STEP_SIZE,
+		DIVIDER_RANGE_03_BASE_DIVIDER_ID,
+		DIVIDER_RANGE_MAX_DIVIDER_ID);
+
+	{
+		uint32_t ss_info_num =
+			dal_adapter_service_get_ss_info_num(
+				as,
+				AS_SIGNAL_TYPE_GPU_PLL);
+
+		if (ss_info_num) {
+			struct spread_spectrum_info info;
+			bool result;
+
+			dm_memset(&info, 0, sizeof(info));
+
+			result =
+				dal_adapter_service_get_ss_info(
+					as,
+					AS_SIGNAL_TYPE_GPU_PLL,
+					0,
+					&info);
+
+			/* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
+			 * even if SS not enabled and in that case
+			 * SSInfo.spreadSpectrumPercentage !=0 would be sign
+			 * that SS is enabled
+			 */
+			if (result && info.spread_spectrum_percentage != 0) {
+				dc110->ss_on_gpu_pll = true;
+				dc110->gpu_pll_ss_divider =
+					info.spread_percentage_divider;
+
+				if (info.type.CENTER_MODE == 0) {
+					/* Currently for DP Reference clock we
+					 * need only SS percentage for
+					 * downspread */
+					dc110->gpu_pll_ss_percentage =
+						info.spread_spectrum_percentage;
+				}
+			}
+
+		}
+	}
+
+	return true;
+}
+
+/*****************************************************************************
+ * public functions
+ *****************************************************************************/
+
+struct display_clock *dal_display_clock_dce110_create(
+	struct dc_context *ctx,
+	struct adapter_service *as)
+{
+	struct display_clock_dce110 *dc110;
+
+	dc110 = dm_alloc(ctx, sizeof(struct display_clock_dce110));
+
+	if (dc110 == NULL)
+		return NULL;
+
+	if (dal_display_clock_dce110_construct(dc110, ctx, as))
+		return &dc110->disp_clk_base;
+
+	dm_free(ctx, dc110);
+
+	return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h
new file mode 100644
index 000000000000..0cdc7b52a09f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h
@@ -0,0 +1,53 @@
+/*
+ * 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 __DAL_DISPLAY_CLOCK_DCE110_H__
+#define __DAL_DISPLAY_CLOCK_DCE110_H__
+
+#include "gpu/display_clock.h"
+
+struct display_clock_dce110 {
+	struct display_clock disp_clk_base;
+	/* Max display block clocks state*/
+	enum clocks_state max_clks_state;
+	bool use_max_disp_clk;
+	uint32_t dentist_vco_freq_khz;
+	/* Cache the status of DFS-bypass feature*/
+	bool dfs_bypass_enabled;
+	/* GPU PLL SS percentage (if down-spread enabled) */
+	uint32_t gpu_pll_ss_percentage;
+	/* GPU PLL SS percentage Divider (100 or 1000) */
+	uint32_t gpu_pll_ss_divider;
+	/* Flag for Enabled SS on GPU PLL */
+	bool ss_on_gpu_pll;
+	/* Cache the display clock returned by VBIOS if DFS-bypass is enabled.
+	 * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
+	uint32_t dfs_bypass_disp_clk;
+	struct display_clock_state clock_state;
+};
+
+#define DCLCK110_FROM_BASE(dc_base) \
+	container_of(dc_base, struct display_clock_dce110, disp_clk_base)
+
+#endif /* __DAL_DISPLAY_CLOCK_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c
new file mode 100644
index 000000000000..13192484a3ba
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c
@@ -0,0 +1,205 @@
+/*
+ * 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 "display_clock.h"
+
+#include "adapter_service_interface.h"
+
+void dal_display_clock_base_set_dp_ref_clock_source(
+	struct display_clock *disp_clk,
+	enum clock_source_id clk_src)
+{/*must be implemented in derived*/
+
+}
+
+void dal_display_clock_base_set_clock_state(struct display_clock *disp_clk,
+	struct display_clock_state clk_state)
+{
+	/*Implemented only in DCE81*/
+}
+struct display_clock_state dal_display_clock_base_get_clock_state(
+	struct display_clock *disp_clk)
+{
+	/*Implemented only in DCE81*/
+	struct display_clock_state state = {0};
+	return state;
+}
+uint32_t dal_display_clock_base_get_dfs_bypass_threshold(
+	struct display_clock *disp_clk)
+{
+	/*Implemented only in DCE81*/
+	return 0;
+}
+
+bool dal_display_clock_construct_base(
+	struct display_clock *base,
+	struct dc_context *ctx,
+	struct adapter_service *as)
+{
+	base->ctx = ctx;
+	base->id = CLOCK_SOURCE_ID_DCPLL;
+	base->min_display_clk_threshold_khz = 0;
+	base->as = as;
+
+/* Initially set current min clocks state to invalid since we
+ * cannot make any assumption about PPLIB's initial state. This will be updated
+ * by HWSS via SetMinClocksState() on first mode set prior to programming
+ * state dependent clocks.*/
+	base->cur_min_clks_state = CLOCKS_STATE_INVALID;
+
+	return true;
+}
+
+void dal_display_clock_destroy(struct display_clock **disp_clk)
+{
+	if (!disp_clk || !*disp_clk) {
+		BREAK_TO_DEBUGGER();
+		return;
+	}
+
+	(*disp_clk)->funcs->destroy(disp_clk);
+
+	*disp_clk = NULL;
+}
+
+bool dal_display_clock_validate(
+	struct display_clock *disp_clk,
+	struct min_clock_params *params)
+{
+	return disp_clk->funcs->validate(disp_clk, params);
+}
+
+uint32_t dal_display_clock_calculate_min_clock(
+	struct display_clock *disp_clk,
+	uint32_t path_num,
+	struct min_clock_params *params)
+{
+	return disp_clk->funcs->calculate_min_clock(disp_clk, path_num, params);
+}
+
+uint32_t dal_display_clock_get_validation_clock(struct display_clock *disp_clk)
+{
+	return disp_clk->funcs->get_validation_clock(disp_clk);
+}
+
+void dal_display_clock_set_clock(
+	struct display_clock *disp_clk,
+	uint32_t requested_clock_khz)
+{
+	disp_clk->funcs->set_clock(disp_clk, requested_clock_khz);
+}
+
+uint32_t dal_display_clock_get_clock(struct display_clock *disp_clk)
+{
+	return disp_clk->funcs->get_clock(disp_clk);
+}
+
+enum clocks_state dal_display_clock_get_min_clocks_state(
+	struct display_clock *disp_clk)
+{
+	return disp_clk->funcs->get_min_clocks_state(disp_clk);
+}
+
+enum clocks_state dal_display_clock_get_required_clocks_state(
+	struct display_clock *disp_clk,
+	struct state_dependent_clocks *req_clocks)
+{
+	return disp_clk->funcs->get_required_clocks_state(disp_clk, req_clocks);
+}
+
+bool dal_display_clock_set_min_clocks_state(
+	struct display_clock *disp_clk,
+	enum clocks_state clocks_state)
+{
+	return disp_clk->funcs->set_min_clocks_state(disp_clk, clocks_state);
+}
+
+uint32_t dal_display_clock_get_dp_ref_clk_frequency(
+	struct display_clock *disp_clk)
+{
+	return disp_clk->funcs->get_dp_ref_clk_frequency(disp_clk);
+}
+
+/*the second parameter of "switchreferenceclock" is
+ * a dummy argument for all pre dce 6.0 versions*/
+
+void dal_display_clock_switch_reference_clock(
+	struct display_clock *disp_clk,
+	bool use_external_ref_clk,
+	uint32_t requested_clk_khz)
+{
+	/* TODO: requires Asic Control*/
+	/*
+	struct ac_pixel_clk_params params;
+	struct asic_control *ac =
+		dal_adapter_service_get_asic_control(disp_clk->as);
+	dc_service_memset(&params, 0, sizeof(struct ac_pixel_clk_params));
+
+	params.tgt_pixel_clk_khz = requested_clk_khz;
+	params.flags.SET_EXTERNAL_REF_DIV_SRC = use_external_ref_clk;
+	params.pll_id = disp_clk->id;
+	dal_asic_control_program_display_engine_pll(ac, &params);
+	*/
+}
+
+void dal_display_clock_set_dp_ref_clock_source(
+	struct display_clock *disp_clk,
+	enum clock_source_id clk_src)
+{
+	disp_clk->funcs->set_dp_ref_clock_source(disp_clk, clk_src);
+}
+
+void dal_display_clock_store_max_clocks_state(
+	struct display_clock *disp_clk,
+	enum clocks_state max_clocks_state)
+{
+	disp_clk->funcs->store_max_clocks_state(disp_clk, max_clocks_state);
+}
+
+void dal_display_clock_set_clock_state(
+	struct display_clock *disp_clk,
+	struct display_clock_state clk_state)
+{
+	disp_clk->funcs->set_clock_state(disp_clk, clk_state);
+}
+
+struct display_clock_state dal_display_clock_get_clock_state(
+	struct display_clock *disp_clk)
+{
+	return disp_clk->funcs->get_clock_state(disp_clk);
+}
+
+uint32_t dal_display_clock_get_dfs_bypass_threshold(
+	struct display_clock *disp_clk)
+{
+	return disp_clk->funcs->get_dfs_bypass_threshold(disp_clk);
+}
+
+void dal_display_clock_invalid_clock_state(
+	struct display_clock *disp_clk)
+{
+	disp_clk->cur_min_clks_state = CLOCKS_STATE_INVALID;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h
new file mode 100644
index 000000000000..845393b7ecb6
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h
@@ -0,0 +1,82 @@
+/*
+ * 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 __DAL_DISPLAY_CLOCK_H__
+#define __DAL_DISPLAY_CLOCK_H__
+
+#include "include/display_clock_interface.h"
+
+struct display_clock_funcs {
+	void (*destroy)(struct display_clock **to_destroy);
+	bool (*validate)(struct display_clock *disp_clk,
+		struct min_clock_params *params);
+	uint32_t (*calculate_min_clock)(struct display_clock *disp_clk,
+		uint32_t path_num, struct min_clock_params *params);
+	uint32_t (*get_validation_clock)(struct display_clock *disp_clk);
+	void (*set_clock)(struct display_clock *disp_clk,
+		uint32_t requested_clock_khz);
+	uint32_t (*get_clock)(struct display_clock *disp_clk);
+	enum clocks_state (*get_min_clocks_state)(
+		struct display_clock *disp_clk);
+	enum clocks_state (*get_required_clocks_state)(
+		struct display_clock *disp_clk,
+		struct state_dependent_clocks *req_clocks);
+	bool (*set_min_clocks_state)(struct display_clock *disp_clk,
+		enum clocks_state clocks_state);
+	uint32_t (*get_dp_ref_clk_frequency)(struct display_clock *disp_clk);
+	void (*set_dp_ref_clock_source)(struct display_clock *disp_clk,
+		enum clock_source_id clk_src);
+	void (*store_max_clocks_state)(struct display_clock *disp_clk,
+		enum clocks_state max_clocks_state);
+	void (*set_clock_state)(struct display_clock *disp_clk,
+		struct display_clock_state clk_state);
+	struct display_clock_state (*get_clock_state)(
+		struct display_clock *disp_clk);
+	uint32_t (*get_dfs_bypass_threshold)(struct display_clock *disp_clk);
+};
+
+struct display_clock {
+	struct dc_context *ctx;
+	const struct display_clock_funcs *funcs;
+	uint32_t min_display_clk_threshold_khz;
+	enum clock_source_id id;
+	struct adapter_service *as;
+
+	enum clocks_state cur_min_clks_state;
+};
+void dal_display_clock_base_set_dp_ref_clock_source(
+	struct display_clock *disp_clk,
+	enum clock_source_id clk_src);
+struct display_clock_state dal_display_clock_base_get_clock_state(
+	struct display_clock *disp_clk);
+uint32_t dal_display_clock_base_get_dfs_bypass_threshold(
+	struct display_clock *disp_clk);
+void dal_display_clock_base_set_clock_state(struct display_clock *disp_clk,
+	struct display_clock_state clk_state);
+bool dal_display_clock_construct_base(
+	struct display_clock *base,
+	struct dc_context *ctx,
+	struct adapter_service *as);
+#endif /* __DAL_DISPLAY_CLOCK_H__*/
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c
new file mode 100644
index 000000000000..59d44004411b
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c
@@ -0,0 +1,127 @@
+/*
+ * 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 "divider_range.h"
+
+bool dal_divider_range_construct(
+	struct divider_range *div_range,
+	uint32_t range_start,
+	uint32_t range_step,
+	uint32_t did_min,
+	uint32_t did_max)
+{
+	div_range->div_range_start = range_start;
+	div_range->div_range_step = range_step;
+	div_range->did_min = did_min;
+	div_range->did_max = did_max;
+
+	if (div_range->div_range_step == 0) {
+		div_range->div_range_step = 1;
+		/*div_range_step cannot be zero*/
+		BREAK_TO_DEBUGGER();
+	}
+	/* Calculate this based on the other inputs.*/
+	/* See DividerRange.h for explanation of */
+	/* the relationship between divider id (DID) and a divider.*/
+	/* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/
+	/* Maximum divider identified in this range =
+	 * (Number of Divider IDs)*Step size between dividers
+	 *  + The start of this range.*/
+	div_range->div_range_end = (did_max - did_min) * range_step
+		+ range_start;
+	return true;
+}
+
+static uint32_t dal_divider_range_calc_divider(
+	struct divider_range *div_range,
+	uint32_t did)
+{
+	/* Is this DID within our range?*/
+	if ((did < div_range->did_min) || (did >= div_range->did_max))
+		return INVALID_DIVIDER;
+
+	return ((did - div_range->did_min) * div_range->div_range_step)
+			+ div_range->div_range_start;
+
+}
+
+static uint32_t dal_divider_range_calc_did(
+	struct divider_range *div_range,
+	uint32_t div)
+{
+	uint32_t did;
+	/* Check before dividing.*/
+	if (div_range->div_range_step == 0) {
+		div_range->div_range_step = 1;
+		/*div_range_step cannot be zero*/
+		BREAK_TO_DEBUGGER();
+	}
+	/* Is this divider within our range?*/
+	if ((div < div_range->div_range_start)
+		|| (div >= div_range->div_range_end))
+		return INVALID_DID;
+/* did = (divider - range_start + (range_step-1)) / range_step) + did_min*/
+	did = div - div_range->div_range_start;
+	did += div_range->div_range_step - 1;
+	did /= div_range->div_range_step;
+	did += div_range->did_min;
+	return did;
+}
+
+uint32_t dal_divider_range_get_divider(
+	struct divider_range *div_range,
+	uint32_t ranges_num,
+	uint32_t did)
+{
+	uint32_t div = INVALID_DIVIDER;
+	uint32_t i;
+
+	for (i = 0; i < ranges_num; i++) {
+		/* Calculate divider with given divider ID*/
+		div = dal_divider_range_calc_divider(&div_range[i], did);
+		/* Found a valid return divider*/
+		if (div != INVALID_DIVIDER)
+			break;
+	}
+	return div;
+}
+uint32_t dal_divider_range_get_did(
+	struct divider_range *div_range,
+	uint32_t ranges_num,
+	uint32_t divider)
+{
+	uint32_t did = INVALID_DID;
+	uint32_t i;
+
+	for (i = 0; i < ranges_num; i++) {
+		/*  CalcDid returns InvalidDid if a divider ID isn't found*/
+		did = dal_divider_range_calc_did(&div_range[i], divider);
+		/* Found a valid return did*/
+		if (did != INVALID_DID)
+			break;
+	}
+	return did;
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h
new file mode 100644
index 000000000000..2ec1034035ad
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h
@@ -0,0 +1,63 @@
+/*
+ * 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 __DAL_DIVIDER_RANGE_H__
+#define __DAL_DIVIDER_RANGE_H__
+
+enum divider_error_types {
+	INVALID_DID = 0,
+	INVALID_DIVIDER = 1
+};
+
+struct divider_range {
+	uint32_t div_range_start;
+	/* The end of this range of dividers.*/
+	uint32_t div_range_end;
+	/* The distance between each divider in this range.*/
+	uint32_t div_range_step;
+	/* The divider id for the lowest divider.*/
+	uint32_t did_min;
+	/* The divider id for the highest divider.*/
+	uint32_t did_max;
+};
+
+bool dal_divider_range_construct(
+	struct divider_range *div_range,
+	uint32_t range_start,
+	uint32_t range_step,
+	uint32_t did_min,
+	uint32_t did_max);
+
+uint32_t dal_divider_range_get_divider(
+	struct divider_range *div_range,
+	uint32_t ranges_num,
+	uint32_t did);
+uint32_t dal_divider_range_get_did(
+	struct divider_range *div_range,
+	uint32_t ranges_num,
+	uint32_t divider);
+
+
+#endif /* __DAL_DIVIDER_RANGE_H__ */
-- 
2.1.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2016-02-11 17:20 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-11 17:19 [PATCH 00/29] Enabling new DAL display driver for amdgpu on Carrizo and Tonga Harry Wentland
2016-02-11 17:19 ` [PATCH 01/29] drm/amd/dal: Add dal headers Harry Wentland
2016-02-11 17:19 ` [PATCH 02/29] drm/amd/dal: Add DAL Basic Types and Logger Harry Wentland
2016-02-11 17:19 ` [PATCH 03/29] drm/amd/dal: Fixed point arithmetic Harry Wentland
2016-02-11 17:19 ` [PATCH 04/29] drm/amd/dal: Asic Capabilities Harry Wentland
2016-02-11 17:19 ` [PATCH 05/29] drm/amd/dal: GPIO (General Purpose IO) Harry Wentland
2016-02-11 17:19 ` [PATCH 06/29] drm/amd/dal: Adapter Service Harry Wentland
2016-02-12  0:26   ` Dave Airlie
2016-02-12 14:30     ` Wentland, Harry
2016-02-11 17:19 ` [PATCH 07/29] drm/amd/dal: BIOS Parser Harry Wentland
2016-02-11 17:19 ` [PATCH 08/29] drm/amd/dal: I2C Aux Manager Harry Wentland
2016-02-11 20:19   ` Rob Clark
2016-02-11 20:52     ` Daniel Vetter
2016-02-17  3:23     ` Harry Wentland
2016-02-11 17:19 ` [PATCH 09/29] drm/amd/dal: IRQ Service Harry Wentland
2016-02-11 17:19 ` Harry Wentland [this message]
2016-02-11 17:19 ` [PATCH 11/29] drm/amd/dal: Audio Harry Wentland
2016-02-11 17:19 ` [PATCH 12/29] drm/amd/dal: Bandwidth calculations Harry Wentland
2016-02-11 17:19 ` [PATCH 13/29] drm/amd/dal: Add encoder HW programming Harry Wentland
2016-02-11 17:19 ` [PATCH 14/29] drm/amd/dal: Add clock source " Harry Wentland
2016-02-11 17:19 ` [PATCH 15/29] drm/amd/dal: Add timing generator " Harry Wentland
2016-02-11 17:19 ` [PATCH 16/29] drm/amd/dal: Add surface " Harry Wentland
2016-02-11 17:19 ` [PATCH 17/29] drm/amd/dal: Add framebuffer compression " Harry Wentland
2016-02-11 17:19 ` [PATCH 18/29] drm/amd/dal: Add input pixel processing " Harry Wentland
2016-02-11 17:19 ` [PATCH 19/29] drm/amd/dal: Add output " Harry Wentland
2016-02-11 17:20 ` [PATCH 20/29] drm/amd/dal: Add transform & scaler " Harry Wentland
2016-02-11 17:20 ` [PATCH 21/29] drm/amd/dal: Add Carrizo HW sequencer and resource Harry Wentland
2016-02-11 17:20 ` [PATCH 22/29] drm/amd/dal: Add Tonga/Fiji " Harry Wentland
2016-02-11 17:20 ` [PATCH 23/29] drm/amd/dal: Add empty encoder programming for virtual HW Harry Wentland
2016-02-11 17:20 ` [PATCH 24/29] drm/amd/dal: Add display core Harry Wentland
2016-02-11 17:20 ` [PATCH 25/29] drm/amd/dal: Adding amdgpu_dm for dal Harry Wentland
2016-02-11 17:20 ` [PATCH 26/29] drm/amdgpu: Use dal driver for Carrizo, Tonga, and Fiji Harry Wentland
2016-02-11 17:20 ` [PATCH 27/29] drm/amd/dal: Correctly interpret rotation as bit set Harry Wentland
2016-02-11 21:00   ` Oded Gabbay
2016-02-16 16:46     ` Harry Wentland
2016-02-11 17:20 ` [PATCH 28/29] drm/amd/dal: fix flip clean-up state Harry Wentland
2016-02-11 17:20 ` [PATCH 29/29] drm/amd/dal: Force bw programming for DCE 10 until we start calculate BW Harry Wentland
2016-02-11 20:02 ` [PATCH 00/29] Enabling new DAL display driver for amdgpu on Carrizo and Tonga Mike Lothian
2016-02-11 20:05   ` Wentland, Harry
2016-02-11 20:52 ` Dave Airlie
2016-02-11 21:06   ` Daniel Vetter
2016-02-12  0:57     ` Dave Airlie
2016-02-12  5:34     ` Daniel Vetter
2016-02-13  0:05       ` Wentland, Harry
2016-02-14 11:22         ` Jerome Glisse
2016-02-14 13:23           ` Daniel Vetter
2016-02-17  3:28           ` Harry Wentland
2016-02-14 13:32         ` Rob Clark
2016-02-14 13:51           ` Daniel Vetter
2016-02-17  3:26           ` Harry Wentland
2016-02-14 14:01         ` Daniel Vetter
2016-02-17  3:32           ` Harry Wentland
2016-02-14 21:44         ` Daniel Stone
2016-02-16 22:27 ` [PATCH v2 00/26] " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 01/26] drm/amd/dal: Add dal headers Harry Wentland
2016-02-16 22:27   ` [PATCH v2 02/26] drm/amd/dal: Add DAL Basic Types and Logger Harry Wentland
2016-02-16 22:27   ` [PATCH v2 03/26] drm/amd/dal: Fixed point arithmetic Harry Wentland
2016-02-16 22:27   ` [PATCH v2 04/26] drm/amd/dal: Asic Capabilities Harry Wentland
2016-02-16 22:27   ` [PATCH v2 05/26] drm/amd/dal: GPIO (General Purpose IO) Harry Wentland
2016-02-16 22:27   ` [PATCH v2 06/26] drm/amd/dal: Adapter Service Harry Wentland
2016-02-16 22:27   ` [PATCH v2 07/26] drm/amd/dal: BIOS Parser Harry Wentland
2016-02-16 22:27   ` [PATCH v2 08/26] drm/amd/dal: I2C Aux Manager Harry Wentland
2016-02-16 22:27   ` [PATCH v2 09/26] drm/amd/dal: IRQ Service Harry Wentland
2016-02-16 22:27   ` [PATCH v2 10/26] drm/amd/dal: GPU Harry Wentland
2016-02-16 22:27   ` [PATCH v2 11/26] drm/amd/dal: Audio Harry Wentland
2016-02-16 22:27   ` [PATCH v2 12/26] drm/amd/dal: Bandwidth calculations Harry Wentland
2016-02-16 22:27   ` [PATCH v2 13/26] drm/amd/dal: Add encoder HW programming Harry Wentland
2016-02-16 22:27   ` [PATCH v2 14/26] drm/amd/dal: Add clock source " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 15/26] drm/amd/dal: Add timing generator " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 16/26] drm/amd/dal: Add surface " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 17/26] drm/amd/dal: Add framebuffer compression " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 18/26] drm/amd/dal: Add input pixel processing " Harry Wentland
2016-02-16 22:27   ` [PATCH v2 19/26] drm/amd/dal: Add output " Harry Wentland
2016-02-16 22:28   ` [PATCH v2 20/26] drm/amd/dal: Add transform & scaler " Harry Wentland
2016-02-16 22:28   ` [PATCH v2 21/26] drm/amd/dal: Add Carrizo HW sequencer and resource Harry Wentland
2016-02-16 22:28   ` [PATCH v2 22/26] drm/amd/dal: Add Tonga/Fiji " Harry Wentland
2016-02-16 22:28   ` [PATCH v2 23/26] drm/amd/dal: Add empty encoder programming for virtual HW Harry Wentland
2016-02-16 22:28   ` [PATCH v2 24/26] drm/amd/dal: Add display core Harry Wentland
2016-02-16 22:28   ` [PATCH v2 25/26] drm/amd/dal: Adding amdgpu_dm for dal Harry Wentland
2016-02-16 22:28   ` [PATCH v2 26/26] drm/amdgpu: Use dal driver for Carrizo, Tonga, and Fiji Harry Wentland
2016-02-29 21:56 ` [PATCH v3 00/26] Enabling new DAL display driver for amdgpu on Carrizo and Tonga Harry Wentland
2016-02-29 21:56   ` [PATCH v3 01/26] drm/amd/dal: Add dal headers Harry Wentland
2016-02-29 21:56   ` [PATCH v3 05/26] drm/amd/dal: GPIO (General Purpose IO) Harry Wentland
2016-02-29 21:56   ` [PATCH v3 07/26] drm/amd/dal: BIOS Parser Harry Wentland
2016-02-29 21:56   ` [PATCH v3 24/26] drm/amd/dal: Add display core Harry Wentland
2016-02-29 21:56   ` [PATCH v3 25/26] drm/amd/dal: Adding amdgpu_dm for dal Harry Wentland
2016-02-29 21:56   ` [PATCH v3 26/26] drm/amdgpu: Use dal driver for Carrizo, Tonga, and Fiji Harry Wentland

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1455211209-26733-11-git-send-email-harry.wentland@amd.com \
    --to=harry.wentland@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.