[PATCH 22/29] drm/amd/dal: Add Tonga/Fiji HW sequencer and resource

Harry Wentland harry.wentland at amd.com
Thu Feb 11 17:20:02 UTC 2016


Enables HW programming on Tonga and Fiji (DCE 10) ASICs. This
mostly re-uses DCE 11 programming code with minor exceptions
and using DCE 10 register offsets.

Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
---
 drivers/gpu/drm/amd/dal/dc/dce100/Makefile         |   23 +
 .../drm/amd/dal/dc/dce100/dce100_hw_sequencer.c    |  388 +++++++
 .../drm/amd/dal/dc/dce100/dce100_hw_sequencer.h    |   36 +
 .../gpu/drm/amd/dal/dc/dce100/dce100_resource.c    | 1134 ++++++++++++++++++++
 .../gpu/drm/amd/dal/dc/dce100/dce100_resource.h    |   43 +
 5 files changed, 1624 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce100/Makefile
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.h
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.h

diff --git a/drivers/gpu/drm/amd/dal/dc/dce100/Makefile b/drivers/gpu/drm/amd/dal/dc/dce100/Makefile
new file mode 100644
index 000000000000..656c38e1b0f5
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce100/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for the 'controller' sub-component of DAL.
+# It provides the control and status of HW CRTC block.
+
+DCE100 = dce100_resource.o dce100_hw_sequencer.o
+
+AMD_DAL_DCE100 = $(addprefix $(AMDDALPATH)/dc/dce100/,$(DCE100))
+
+AMD_DAL_FILES += $(AMD_DAL_DCE100)
+
+
+###############################################################################
+# DCE 10x
+###############################################################################
+ifdef 0#CONFIG_DRM_AMD_DAL_DCE11_0
+TG_DCE100 = dce100_resource.o
+
+AMD_DAL_TG_DCE100 = $(addprefix \
+	$(AMDDALPATH)/dc/dce100/,$(TG_DCE100))
+
+AMD_DAL_FILES += $(AMD_DAL_TG_DCE100)
+endif
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.c
new file mode 100644
index 000000000000..82c5e155d91a
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2015 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.h"
+#include "core_dc.h"
+#include "core_types.h"
+#include "hw_sequencer.h"
+#include "dce100_hw_sequencer.h"
+#include "dce110/dce110_hw_sequencer.h"
+
+/* include DCE10 register header files */
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+
+struct dce100_hw_seq_reg_offsets {
+	uint32_t blnd;
+	uint32_t crtc;
+};
+
+enum pipe_lock_control {
+	PIPE_LOCK_CONTROL_GRAPHICS = 1 << 0,
+	PIPE_LOCK_CONTROL_BLENDER = 1 << 1,
+	PIPE_LOCK_CONTROL_SCL = 1 << 2,
+	PIPE_LOCK_CONTROL_SURFACE = 1 << 3,
+	PIPE_LOCK_CONTROL_MODE = 1 << 4
+};
+
+enum blender_mode {
+	BLENDER_MODE_CURRENT_PIPE = 0,/* Data from current pipe only */
+	BLENDER_MODE_OTHER_PIPE, /* Data from other pipe only */
+	BLENDER_MODE_BLENDING,/* Alpha blending - blend 'current' and 'other' */
+	BLENDER_MODE_STEREO
+};
+
+static const struct dce100_hw_seq_reg_offsets reg_offsets[] = {
+{
+	.blnd = (mmBLND0_BLND_CONTROL - mmBLND_CONTROL),
+	.crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+},
+{
+	.blnd = (mmBLND1_BLND_CONTROL - mmBLND_CONTROL),
+	.crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+},
+{
+	.blnd = (mmBLND2_BLND_CONTROL - mmBLND_CONTROL),
+	.crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+}
+};
+
+#define HW_REG_BLND(reg, id)\
+	(reg + reg_offsets[id].blnd)
+
+#define HW_REG_CRTC(reg, id)\
+	(reg + reg_offsets[id].crtc)
+
+
+/*******************************************************************************
+ * Private definitions
+ ******************************************************************************/
+/***************************PIPE_CONTROL***********************************/
+static void dce100_enable_fe_clock(
+	struct dc_context *ctx, uint8_t controller_id, bool enable)
+{
+	uint32_t value = 0;
+	uint32_t addr;
+
+	addr = HW_REG_CRTC(mmDCFE_CLOCK_CONTROL, controller_id);
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		enable,
+		DCFE_CLOCK_CONTROL,
+		DCFE_CLOCK_ENABLE);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static bool dce100_pipe_control_lock(
+	struct dc_context *ctx,
+	uint8_t controller_idx,
+	uint32_t control_mask,
+	bool lock)
+{
+	uint32_t addr = HW_REG_BLND(mmBLND_V_UPDATE_LOCK, controller_idx);
+	uint32_t value = dm_read_reg(ctx, addr);
+	bool need_to_wait = false;
+
+	if (control_mask & PIPE_LOCK_CONTROL_GRAPHICS)
+		set_reg_field_value(
+			value,
+			lock,
+			BLND_V_UPDATE_LOCK,
+			BLND_DCP_GRPH_V_UPDATE_LOCK);
+
+	if (control_mask & PIPE_LOCK_CONTROL_SCL)
+		set_reg_field_value(
+			value,
+			lock,
+			BLND_V_UPDATE_LOCK,
+			BLND_SCL_V_UPDATE_LOCK);
+
+	if (control_mask & PIPE_LOCK_CONTROL_SURFACE)
+		set_reg_field_value(
+			value,
+			lock,
+			BLND_V_UPDATE_LOCK,
+			BLND_DCP_GRPH_SURF_V_UPDATE_LOCK);
+
+	if (control_mask & PIPE_LOCK_CONTROL_BLENDER) {
+		set_reg_field_value(
+			value,
+			lock,
+			BLND_V_UPDATE_LOCK,
+			BLND_BLND_V_UPDATE_LOCK);
+		need_to_wait = true;
+	}
+
+	if (control_mask & PIPE_LOCK_CONTROL_MODE)
+		set_reg_field_value(
+			value,
+			lock,
+			BLND_V_UPDATE_LOCK,
+			BLND_V_UPDATE_LOCK_MODE);
+
+	dm_write_reg(ctx, addr, value);
+
+	if (!lock && need_to_wait) {
+		uint8_t counter = 0;
+		const uint8_t counter_limit = 100;
+		const uint16_t delay_us = 1000;
+
+		uint8_t pipe_pending;
+
+		addr = HW_REG_BLND(mmBLND_REG_UPDATE_STATUS,
+				controller_idx);
+
+		while (counter < counter_limit) {
+			value = dm_read_reg(ctx, addr);
+
+			pipe_pending = 0;
+
+			if (control_mask & PIPE_LOCK_CONTROL_BLENDER) {
+				pipe_pending |=
+					get_reg_field_value(
+						value,
+						BLND_REG_UPDATE_STATUS,
+						BLND_BLNDC_UPDATE_PENDING);
+				pipe_pending |= get_reg_field_value(
+					value,
+					BLND_REG_UPDATE_STATUS,
+					BLND_BLNDO_UPDATE_PENDING);
+			}
+
+			if (control_mask & PIPE_LOCK_CONTROL_SCL) {
+				pipe_pending |=
+					get_reg_field_value(
+						value,
+						BLND_REG_UPDATE_STATUS,
+						SCL_BLNDC_UPDATE_PENDING);
+				pipe_pending |=
+					get_reg_field_value(
+						value,
+						BLND_REG_UPDATE_STATUS,
+						SCL_BLNDO_UPDATE_PENDING);
+			}
+			if (control_mask & PIPE_LOCK_CONTROL_GRAPHICS) {
+				pipe_pending |=
+					get_reg_field_value(
+						value,
+						BLND_REG_UPDATE_STATUS,
+						DCP_BLNDC_GRPH_UPDATE_PENDING);
+				pipe_pending |=
+					get_reg_field_value(
+						value,
+						BLND_REG_UPDATE_STATUS,
+						DCP_BLNDO_GRPH_UPDATE_PENDING);
+			}
+			if (control_mask & PIPE_LOCK_CONTROL_SURFACE) {
+				pipe_pending |= get_reg_field_value(
+					value,
+					BLND_REG_UPDATE_STATUS,
+					DCP_BLNDC_GRPH_SURF_UPDATE_PENDING);
+				pipe_pending |= get_reg_field_value(
+					value,
+					BLND_REG_UPDATE_STATUS,
+					DCP_BLNDO_GRPH_SURF_UPDATE_PENDING);
+			}
+
+			if (pipe_pending == 0)
+				break;
+
+			counter++;
+			dm_delay_in_microseconds(ctx, delay_us);
+		}
+
+		if (counter == counter_limit) {
+			dal_logger_write(
+				ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_CONTROLLER,
+				"%s: wait for update exceeded (wait %d us)\n",
+				__func__,
+				counter * delay_us);
+			dal_logger_write(
+				ctx->logger,
+				LOG_MAJOR_WARNING,
+				LOG_MINOR_COMPONENT_CONTROLLER,
+				"%s: control %d, remain value %x\n",
+				__func__,
+				control_mask,
+				value);
+		} else {
+			/* OK. */
+		}
+	}
+
+	return true;
+}
+
+static void dce100_set_blender_mode(
+	struct dc_context *ctx,
+	uint8_t controller_id,
+	uint32_t mode)
+{
+	uint32_t value;
+	uint32_t addr = HW_REG_BLND(mmBLND_CONTROL, controller_id);
+	uint32_t blnd_mode;
+	uint32_t feedthrough = 0;
+
+	switch (mode) {
+	case BLENDER_MODE_OTHER_PIPE:
+		feedthrough = 0;
+		blnd_mode = 1;
+		break;
+	case BLENDER_MODE_BLENDING:
+		feedthrough = 0;
+		blnd_mode = 2;
+		break;
+	case BLENDER_MODE_CURRENT_PIPE:
+	default:
+		feedthrough = 1;
+		blnd_mode = 0;
+		break;
+	}
+
+	value = dm_read_reg(ctx, addr);
+
+	set_reg_field_value(
+		value,
+		feedthrough,
+		BLND_CONTROL,
+		BLND_FEEDTHROUGH_EN);
+
+	set_reg_field_value(
+		value,
+		blnd_mode,
+		BLND_CONTROL,
+		BLND_MODE);
+
+	dm_write_reg(ctx, addr, value);
+}
+
+static bool dce100_enable_display_power_gating(
+	struct dc_context *ctx,
+	uint8_t controller_id,
+	struct dc_bios *dcb,
+	enum pipe_gating_control power_gating)
+{
+	enum bp_result bp_result = BP_RESULT_OK;
+	enum bp_pipe_control_action cntl;
+
+	if (power_gating == PIPE_GATING_CONTROL_INIT)
+		cntl = ASIC_PIPE_INIT;
+	else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
+		cntl = ASIC_PIPE_ENABLE;
+	else
+		cntl = ASIC_PIPE_DISABLE;
+
+	if (!(power_gating == PIPE_GATING_CONTROL_INIT && controller_id != 0))
+		bp_result = dcb->funcs->enable_disp_power_gating(
+						dcb, controller_id + 1, cntl);
+
+	if (bp_result == BP_RESULT_OK)
+		return true;
+	else
+		return false;
+}
+
+static void enable_hw_base_light_sleep(void)
+{
+	/* TODO: implement */
+}
+
+static void disable_sw_manual_control_light_sleep(void)
+{
+	/* TODO: implement */
+}
+
+static void enable_sw_manual_control_light_sleep(void)
+{
+	/* TODO: implement */
+}
+
+static void dal_dc_clock_gating_dce100_power_up(struct dc_context *ctx, bool enable)
+{
+	if (enable) {
+		enable_hw_base_light_sleep();
+		disable_sw_manual_control_light_sleep();
+	} else {
+		enable_sw_manual_control_light_sleep();
+	}
+}
+
+/**
+ * Call display_engine_clock_dce80 to perform the Dclk programming.
+ */
+static void set_display_clock(struct validate_context *context)
+{
+	/* Program the display engine clock.
+	 * Check DFS bypass mode support or not. DFSbypass feature is only when
+	 * BIOS GPU info table reports support. */
+
+	if (/*dal_adapter_service_is_dfs_bypass_enabled()*/ false) {
+		/*TODO: set_display_clock_dfs_bypass(
+				hws,
+				path_set,
+				context->res_ctx.pool.display_clock,
+				context->res_ctx.min_clocks.min_dclk_khz);*/
+	} else
+		dal_display_clock_set_clock(context->res_ctx.pool.display_clock,
+				681000);
+
+	/* TODO: When changing display engine clock, DMCU WaitLoop must be
+	 * reconfigured in order to maintain the same delays within DMCU
+	 * programming sequences. */
+
+	/* TODO: Start GTC counter */
+}
+
+
+static void set_displaymarks(
+		const struct dc *dc, struct validate_context *context)
+{
+	/* Do nothing until we have proper bandwitdth calcs */
+}
+
+/**************************************************************************/
+
+bool dce100_hw_sequencer_construct(struct dc *dc)
+{
+	dce110_hw_sequencer_construct(dc);
+
+	/* TODO: dce80 is empty implementation at the moment*/
+	dc->hwss.clock_gating_power_up = dal_dc_clock_gating_dce100_power_up;
+
+	dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating;
+	dc->hwss.enable_fe_clock = dce100_enable_fe_clock;
+	dc->hwss.pipe_control_lock = dce100_pipe_control_lock;
+	dc->hwss.set_blender_mode = dce100_set_blender_mode;
+	dc->hwss.set_display_clock = set_display_clock;
+	dc->hwss.set_displaymarks = set_displaymarks;
+	return true;
+}
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.h b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.h
new file mode 100644
index 000000000000..0ce637e6bd85
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_hw_sequencer.h
@@ -0,0 +1,36 @@
+/*
+* 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_HWSS_DCE100_H__
+#define __DC_HWSS_DCE100_H__
+
+#include "core_types.h"
+
+struct dc;
+
+bool dce100_hw_sequencer_construct(struct dc *dc);
+
+#endif /* __DC_HWSS_DCE100_H__ */
+
diff --git a/drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.c
new file mode 100644
index 000000000000..e67ba81f1c85
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.c
@@ -0,0 +1,1134 @@
+/*
+* 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 "link_encoder.h"
+#include "stream_encoder.h"
+
+#include "resource.h"
+#include "include/irq_service_interface.h"
+
+#include "../virtual/virtual_stream_encoder.h"
+#include "dce110/dce110_resource.h"
+#include "dce110/dce110_timing_generator.h"
+#include "dce110/dce110_link_encoder.h"
+#include "dce110/dce110_mem_input.h"
+#include "dce110/dce110_ipp.h"
+#include "dce110/dce110_transform.h"
+#include "dce110/dce110_stream_encoder.h"
+#include "dce110/dce110_opp.h"
+#include "dce110/dce110_clock_source.h"
+
+#include "dce/dce_10_0_d.h"
+
+#ifndef mmDP_DPHY_INTERNAL_CTRL
+	#define mmDP_DPHY_INTERNAL_CTRL 0x4aa7
+	#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7
+	#define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7
+	#define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7
+	#define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7
+	#define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7
+	#define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7
+	#define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7
+	#define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7
+	#define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7
+#endif
+
+enum dce100_clk_src_array_id {
+	DCE100_CLK_SRC_PLL0 = 0,
+	DCE100_CLK_SRC_PLL1,
+	DCE100_CLK_SRC_EXT,
+
+	DCE100_CLK_SRC_TOTAL
+};
+
+static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = {
+	{
+		.crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp =  (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp =  (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+	},
+	{
+		.crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL),
+		.dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+	}
+};
+
+static const struct dce110_mem_input_reg_offsets dce100_mi_reg_offsets[] = {
+	{
+		.dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE0_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE1_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE2_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG3_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE3_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG4_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE4_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	},
+	{
+		.dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+		.dmif = (mmDMIF_PG5_DPG_WATERMARK_MASK_CONTROL
+				- mmDPG_WATERMARK_MASK_CONTROL),
+		.pipe = (mmPIPE5_DMIF_BUFFER_CONTROL
+				- mmPIPE0_DMIF_BUFFER_CONTROL),
+	}
+};
+
+
+static const struct dce110_clk_src_reg_offsets dce100_clk_src_reg_offsets[] = {
+	{
+		.pll_cntl = mmBPHYC_PLL0_PLL_CNTL,
+		.pixclk_resync_cntl  = mmPIXCLK0_RESYNC_CNTL
+	},
+	{
+		.pll_cntl = mmBPHYC_PLL1_PLL_CNTL,
+		.pixclk_resync_cntl  = mmPIXCLK1_RESYNC_CNTL
+	}
+};
+
+static const struct dce110_transform_reg_offsets dce100_xfm_offsets[] = {
+{
+	.scl_offset = (mmSCL0_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmCRTC0_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB0_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL1_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmCRTC1_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB1_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL2_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmCRTC2_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB2_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{
+	.scl_offset = (mmSCL3_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmCRTC3_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB3_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL4_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmCRTC4_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB4_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+},
+{	.scl_offset = (mmSCL5_SCL_CONTROL - mmSCL_CONTROL),
+	.dcfe_offset = (mmCRTC5_DCFE_MEM_PWR_CTRL - mmDCFE_MEM_PWR_CTRL),
+	.dcp_offset = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+	.lb_offset = (mmLB5_LB_DATA_FORMAT - mmLB_DATA_FORMAT),
+}
+};
+
+static const struct dce110_ipp_reg_offsets dce100_ipp_reg_offsets[] = {
+{
+	.dcp_offset = (mmDCP0_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP1_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP2_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP3_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP4_CUR_CONTROL - mmCUR_CONTROL),
+},
+{
+	.dcp_offset = (mmDCP5_CUR_CONTROL - mmCUR_CONTROL),
+}
+};
+
+
+static const struct dce110_link_enc_bl_registers link_enc_bl_regs = {
+		.BL_PWM_CNTL = mmBL_PWM_CNTL,
+		.BL_PWM_GRP1_REG_LOCK = mmBL_PWM_GRP1_REG_LOCK,
+		.BL_PWM_PERIOD_CNTL = mmBL_PWM_PERIOD_CNTL,
+		.LVTMA_PWRSEQ_CNTL = mmLVTMA_PWRSEQ_CNTL,
+		.LVTMA_PWRSEQ_STATE = mmLVTMA_PWRSEQ_STATE
+};
+
+#define aux_regs(id)\
+[id] = {\
+	.AUX_CONTROL = mmDP_AUX ## id ## _AUX_CONTROL,\
+	.AUX_DPHY_RX_CONTROL0 = mmDP_AUX ## id ## _AUX_DPHY_RX_CONTROL0\
+}
+
+static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = {
+	aux_regs(0),
+	aux_regs(1),
+	aux_regs(2),
+	aux_regs(3),
+	aux_regs(4),
+	aux_regs(5)
+};
+
+#define link_regs(id)\
+[id] = {\
+	.DIG_BE_CNTL = mmDIG ## id ## _DIG_BE_CNTL,\
+	.DIG_BE_EN_CNTL = mmDIG ## id ## _DIG_BE_EN_CNTL,\
+	.DP_CONFIG = mmDP ## id ## _DP_CONFIG,\
+	.DP_DPHY_CNTL = mmDP ## id ## _DP_DPHY_CNTL,\
+	.DP_DPHY_INTERNAL_CTRL = mmDP ## id ## _DP_DPHY_INTERNAL_CTRL,\
+	.DP_DPHY_PRBS_CNTL = mmDP ## id ## _DP_DPHY_PRBS_CNTL,\
+	.DP_DPHY_SYM0 = mmDP ## id ## _DP_DPHY_SYM0,\
+	.DP_DPHY_SYM1 = mmDP ## id ## _DP_DPHY_SYM1,\
+	.DP_DPHY_SYM2 = mmDP ## id ## _DP_DPHY_SYM2,\
+	.DP_DPHY_TRAINING_PATTERN_SEL = mmDP ## id ## _DP_DPHY_TRAINING_PATTERN_SEL,\
+	.DP_LINK_CNTL = mmDP ## id ## _DP_LINK_CNTL,\
+	.DP_LINK_FRAMING_CNTL = mmDP ## id ## _DP_LINK_FRAMING_CNTL,\
+	.DP_MSE_SAT0 = mmDP ## id ## _DP_MSE_SAT0,\
+	.DP_MSE_SAT1 = mmDP ## id ## _DP_MSE_SAT1,\
+	.DP_MSE_SAT2 = mmDP ## id ## _DP_MSE_SAT2,\
+	.DP_MSE_SAT_UPDATE = mmDP ## id ## _DP_MSE_SAT_UPDATE,\
+	.DP_SEC_CNTL = mmDP ## id ## _DP_SEC_CNTL,\
+	.DP_VID_STREAM_CNTL = mmDP ## id ## _DP_VID_STREAM_CNTL\
+}
+
+static const struct dce110_link_enc_registers link_enc_regs[] = {
+	link_regs(0),
+	link_regs(1),
+	link_regs(2),
+	link_regs(3),
+	link_regs(4),
+	link_regs(5),
+	link_regs(6)
+};
+
+#define stream_enc_regs(id)\
+[id] = {\
+	.AFMT_AVI_INFO0 = mmDIG ## id ## _AFMT_AVI_INFO0,\
+	.AFMT_AVI_INFO1 = mmDIG ## id ## _AFMT_AVI_INFO1,\
+	.AFMT_AVI_INFO2 = mmDIG ## id ## _AFMT_AVI_INFO2,\
+	.AFMT_AVI_INFO3 = mmDIG ## id ## _AFMT_AVI_INFO3,\
+	.AFMT_GENERIC_0 = mmDIG ## id ## _AFMT_GENERIC_0,\
+	.AFMT_GENERIC_7 = mmDIG ## id ## _AFMT_GENERIC_7,\
+	.AFMT_GENERIC_HDR = mmDIG ## id ## _AFMT_GENERIC_HDR,\
+	.AFMT_INFOFRAME_CONTROL0 = mmDIG ## id ## _AFMT_INFOFRAME_CONTROL0,\
+	.AFMT_VBI_PACKET_CONTROL = mmDIG ## id ## _AFMT_VBI_PACKET_CONTROL,\
+	.DIG_FE_CNTL = mmDIG ## id ## _DIG_FE_CNTL,\
+	.DP_MSE_RATE_CNTL = mmDP ## id ## _DP_MSE_RATE_CNTL,\
+	.DP_MSE_RATE_UPDATE = mmDP ## id ## _DP_MSE_RATE_UPDATE,\
+	.DP_PIXEL_FORMAT = mmDP ## id ## _DP_PIXEL_FORMAT,\
+	.DP_SEC_CNTL = mmDP ## id ## _DP_SEC_CNTL,\
+	.DP_STEER_FIFO = mmDP ## id ## _DP_STEER_FIFO,\
+	.DP_VID_M = mmDP ## id ## _DP_VID_M,\
+	.DP_VID_N = mmDP ## id ## _DP_VID_N,\
+	.DP_VID_STREAM_CNTL = mmDP ## id ## _DP_VID_STREAM_CNTL,\
+	.DP_VID_TIMING = mmDP ## id ## _DP_VID_TIMING,\
+	.HDMI_CONTROL = mmDIG ## id ## _HDMI_CONTROL,\
+	.HDMI_GC = mmDIG ## id ## _HDMI_GC,\
+	.HDMI_GENERIC_PACKET_CONTROL0 = mmDIG ## id ## _HDMI_GENERIC_PACKET_CONTROL0,\
+	.HDMI_GENERIC_PACKET_CONTROL1 = mmDIG ## id ## _HDMI_GENERIC_PACKET_CONTROL1,\
+	.HDMI_INFOFRAME_CONTROL0 = mmDIG ## id ## _HDMI_INFOFRAME_CONTROL0,\
+	.HDMI_INFOFRAME_CONTROL1 = mmDIG ## id ## _HDMI_INFOFRAME_CONTROL1,\
+	.HDMI_VBI_PACKET_CONTROL = mmDIG ## id ## _HDMI_VBI_PACKET_CONTROL,\
+	.TMDS_CNTL = mmDIG ## id ## _TMDS_CNTL\
+}
+
+static const struct dce110_stream_enc_registers stream_enc_regs[] = {
+	stream_enc_regs(0),
+	stream_enc_regs(1),
+	stream_enc_regs(2),
+	stream_enc_regs(3),
+	stream_enc_regs(4),
+	stream_enc_regs(5),
+	stream_enc_regs(6)
+};
+
+#define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03
+
+static const struct dce110_opp_reg_offsets dce100_opp_reg_offsets[] = {
+{
+	.fmt_offset = (mmFMT0_FMT_CONTROL - mmFMT_CONTROL),
+	.dcfe_offset = (mmCRTC0_DCFE_MEM_PWR_CTRL - DCFE_MEM_PWR_CTRL_REG_BASE),
+	.dcp_offset = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT1_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmCRTC1_DCFE_MEM_PWR_CTRL - DCFE_MEM_PWR_CTRL_REG_BASE),
+	.dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT2_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmCRTC2_DCFE_MEM_PWR_CTRL - DCFE_MEM_PWR_CTRL_REG_BASE),
+	.dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{
+	.fmt_offset = (mmFMT3_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmCRTC3_DCFE_MEM_PWR_CTRL - DCFE_MEM_PWR_CTRL_REG_BASE),
+	.dcp_offset = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT4_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmCRTC4_DCFE_MEM_PWR_CTRL - DCFE_MEM_PWR_CTRL_REG_BASE),
+	.dcp_offset = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+},
+{	.fmt_offset = (mmFMT5_FMT_CONTROL - mmFMT0_FMT_CONTROL),
+	.dcfe_offset = (mmCRTC5_DCFE_MEM_PWR_CTRL - DCFE_MEM_PWR_CTRL_REG_BASE),
+	.dcp_offset = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
+}
+};
+
+
+static struct timing_generator *dce100_timing_generator_create(
+		struct adapter_service *as,
+		struct dc_context *ctx,
+		uint32_t instance,
+		const struct dce110_timing_generator_offsets *offsets)
+{
+	struct dce110_timing_generator *tg110 =
+		dm_alloc(ctx, sizeof(struct dce110_timing_generator));
+
+	if (!tg110)
+		return NULL;
+
+	if (dce110_timing_generator_construct(tg110, as, ctx, instance,
+			offsets))
+		return &tg110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ctx, tg110);
+	return NULL;
+}
+
+static struct stream_encoder *dce100_stream_encoder_create(
+	enum engine_id eng_id,
+	struct dc_context *ctx,
+	struct dc_bios *bp,
+	const struct dce110_stream_enc_registers *regs)
+{
+	struct dce110_stream_encoder *enc110 =
+		dm_alloc(ctx, sizeof(struct dce110_stream_encoder));
+
+	if (!enc110)
+		return NULL;
+
+	if (dce110_stream_encoder_construct(enc110, ctx, bp, eng_id, regs))
+		return &enc110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ctx, enc110);
+	return NULL;
+}
+
+static struct mem_input *dce100_mem_input_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offset)
+{
+	struct dce110_mem_input *mem_input110 =
+		dm_alloc(ctx, sizeof(struct dce110_mem_input));
+
+	if (!mem_input110)
+		return NULL;
+
+	if (dce110_mem_input_construct(mem_input110,
+			ctx, inst, offset))
+		return &mem_input110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ctx, mem_input110);
+	return NULL;
+}
+
+static void dce100_transform_destroy(struct transform **xfm)
+{
+	dm_free((*xfm)->ctx, TO_DCE110_TRANSFORM(*xfm));
+	*xfm = NULL;
+}
+
+static struct transform *dce100_transform_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_transform_reg_offsets *offsets)
+{
+	struct dce110_transform *transform =
+		dm_alloc(ctx, sizeof(struct dce110_transform));
+
+	if (!transform)
+		return NULL;
+
+	if (dce110_transform_construct(transform, ctx, inst, offsets))
+		return &transform->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ctx, transform);
+	return NULL;
+}
+
+static struct input_pixel_processor *dce100_ipp_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_ipp_reg_offsets *offsets)
+{
+	struct dce110_ipp *ipp =
+		dm_alloc(ctx, sizeof(struct dce110_ipp));
+
+	if (!ipp)
+		return NULL;
+
+	if (dce110_ipp_construct(ipp, ctx, inst, offsets))
+		return &ipp->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ctx, ipp);
+	return NULL;
+}
+
+struct link_encoder *dce100_link_encoder_create(
+	const struct encoder_init_data *enc_init_data)
+{
+	struct dce110_link_encoder *enc110 =
+		dm_alloc(
+			enc_init_data->ctx,
+			sizeof(struct dce110_link_encoder));
+
+	if (!enc110)
+		return NULL;
+
+	if (dce110_link_encoder_construct(
+			enc110,
+			enc_init_data,
+			&link_enc_regs[enc_init_data->transmitter],
+			&link_enc_aux_regs[enc_init_data->channel - 1],
+			&link_enc_bl_regs))
+		return &enc110->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(enc_init_data->ctx, enc110);
+	return NULL;
+}
+
+
+struct output_pixel_processor *dce100_opp_create(
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_opp_reg_offsets *offset)
+{
+	struct dce110_opp *opp =
+		dm_alloc(ctx, sizeof(struct dce110_opp));
+
+	if (!opp)
+		return NULL;
+
+	if (dce110_opp_construct(opp,
+			ctx, inst, offset))
+		return &opp->base;
+
+	BREAK_TO_DEBUGGER();
+	dm_free(ctx, opp);
+	return NULL;
+}
+
+
+void dce100_opp_destroy(struct output_pixel_processor **opp)
+{
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coeff128_dx);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coeff128_oem);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coeff128);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.axis_x_1025);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.axis_x_256);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.coordinates_x);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_regamma);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_resulted);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_oem);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp)->regamma.rgb_user);
+	dm_free((*opp)->ctx, FROM_DCE11_OPP(*opp));
+	*opp = NULL;
+}
+
+struct clock_source *dce100_clock_source_create(
+	struct dc_context *ctx,
+	struct dc_bios *bios,
+	enum clock_source_id id,
+	const struct dce110_clk_src_reg_offsets *offsets)
+{
+	struct dce110_clk_src *clk_src =
+		dm_alloc(ctx, sizeof(struct dce110_clk_src));
+
+	if (!clk_src)
+		return NULL;
+
+	if (dce110_clk_src_construct(clk_src, ctx, bios, id, offsets))
+		return &clk_src->base;
+
+	BREAK_TO_DEBUGGER();
+	return NULL;
+}
+
+void dce100_clock_source_destroy(struct clock_source **clk_src)
+{
+	dm_free((*clk_src)->ctx, TO_DCE110_CLK_SRC(*clk_src));
+	*clk_src = NULL;
+}
+
+void dce100_destruct_resource_pool(struct resource_pool *pool)
+{
+	unsigned int i;
+
+	for (i = 0; i < pool->controller_count; i++) {
+		if (pool->opps[i] != NULL)
+			dce100_opp_destroy(&pool->opps[i]);
+
+		if (pool->transforms[i] != NULL)
+			dce100_transform_destroy(&pool->transforms[i]);
+
+		if (pool->ipps[i] != NULL)
+			dce110_ipp_destroy(&pool->ipps[i]);
+
+		if (pool->mis[i] != NULL) {
+			dm_free(pool->mis[i]->ctx,
+					TO_DCE110_MEM_INPUT(pool->mis[i]));
+			pool->mis[i] = NULL;
+		}
+
+		if (pool->timing_generators[i] != NULL)	{
+			dm_free(pool->timing_generators[i]->ctx,
+					DCE110TG_FROM_TG(pool->timing_generators[i]));
+			pool->timing_generators[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		if (pool->stream_enc[i] != NULL)
+			dm_free(pool->stream_enc[i]->ctx,
+				DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
+	}
+
+	for (i = 0; i < pool->clk_src_count; i++) {
+		if (pool->clock_sources[i] != NULL)
+			dce100_clock_source_destroy(&pool->clock_sources[i]);
+	}
+
+	for (i = 0; i < pool->audio_count; i++)	{
+		if (pool->audios[i] != NULL)
+			dal_audio_destroy(&pool->audios[i]);
+	}
+
+	if (pool->display_clock != NULL)
+		dal_display_clock_destroy(&pool->display_clock);
+
+	if (pool->scaler_filter != NULL)
+		dal_scaler_filter_destroy(&pool->scaler_filter);
+
+	if (pool->irqs != NULL)
+		dal_irq_service_destroy(&pool->irqs);
+
+	if (pool->adapter_srv != NULL)
+		dal_adapter_service_destroy(&pool->adapter_srv);
+}
+
+static struct clock_source *find_first_free_pll(
+		struct resource_context *res_ctx)
+{
+	if (res_ctx->clock_source_ref_count[DCE100_CLK_SRC_PLL0] == 0)
+		return res_ctx->pool.clock_sources[DCE100_CLK_SRC_PLL0];
+
+	if (res_ctx->clock_source_ref_count[DCE100_CLK_SRC_PLL1] == 0)
+		return res_ctx->pool.clock_sources[DCE100_CLK_SRC_PLL1];
+
+	return 0;
+}
+
+static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
+{
+	switch (crtc_id) {
+	case CONTROLLER_ID_D0:
+		return DTO_SOURCE_ID0;
+	case CONTROLLER_ID_D1:
+		return DTO_SOURCE_ID1;
+	case CONTROLLER_ID_D2:
+		return DTO_SOURCE_ID2;
+	case CONTROLLER_ID_D3:
+		return DTO_SOURCE_ID3;
+	case CONTROLLER_ID_D4:
+		return DTO_SOURCE_ID4;
+	case CONTROLLER_ID_D5:
+		return DTO_SOURCE_ID5;
+	default:
+		return DTO_SOURCE_UNKNOWN;
+	}
+}
+
+static void build_audio_output(
+	const struct core_stream *stream,
+	struct audio_output *audio_output)
+{
+	audio_output->engine_id = stream->stream_enc->id;
+
+	audio_output->signal = stream->signal;
+
+	/* audio_crtc_info  */
+
+	audio_output->crtc_info.h_total =
+		stream->public.timing.h_total;
+
+	/*
+	 * Audio packets are sent during actual CRTC blank physical signal, we
+	 * need to specify actual active signal portion
+	 */
+	audio_output->crtc_info.h_active =
+			stream->public.timing.h_addressable
+			+ stream->public.timing.h_border_left
+			+ stream->public.timing.h_border_right;
+
+	audio_output->crtc_info.v_active =
+			stream->public.timing.v_addressable
+			+ stream->public.timing.v_border_top
+			+ stream->public.timing.v_border_bottom;
+
+	audio_output->crtc_info.pixel_repetition = 1;
+
+	audio_output->crtc_info.interlaced =
+			stream->public.timing.flags.INTERLACE;
+
+	audio_output->crtc_info.refresh_rate =
+		(stream->public.timing.pix_clk_khz*1000)/
+		(stream->public.timing.h_total*stream->public.timing.v_total);
+
+	audio_output->crtc_info.color_depth =
+		stream->public.timing.display_color_depth;
+
+	audio_output->crtc_info.requested_pixel_clock =
+			stream->pix_clk_params.requested_pix_clk;
+
+	/*
+	 * TODO - Investigate why calculated pixel clk has to be
+	 * requested pixel clk
+	 */
+	audio_output->crtc_info.calculated_pixel_clock =
+			stream->pix_clk_params.requested_pix_clk;
+
+	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
+			stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+		audio_output->pll_info.dp_dto_source_clock_in_khz =
+			dal_display_clock_get_dp_ref_clk_frequency(
+				stream->dis_clk);
+	}
+
+	audio_output->pll_info.feed_back_divider =
+			stream->pll_settings.feedback_divider;
+
+	audio_output->pll_info.dto_source =
+		translate_to_dto_source(
+			stream->controller_idx + 1);
+
+	/* TODO hard code to enable for now. Need get from stream */
+	audio_output->pll_info.ss_enabled = true;
+
+	audio_output->pll_info.ss_percentage =
+			stream->pll_settings.ss_percentage;
+}
+
+static void get_pixel_clock_parameters(
+	const struct core_stream *stream,
+	struct pixel_clk_params *pixel_clk_params)
+{
+	pixel_clk_params->requested_pix_clk = stream->public.timing.pix_clk_khz;
+	pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id;
+	pixel_clk_params->signal_type = stream->sink->public.sink_signal;
+	pixel_clk_params->controller_id = stream->controller_idx + 1;
+	/* TODO: un-hardcode*/
+	pixel_clk_params->requested_sym_clk = LINK_RATE_LOW *
+		LINK_RATE_REF_FREQ_IN_KHZ;
+	pixel_clk_params->flags.ENABLE_SS = 0;
+	pixel_clk_params->color_depth =
+		stream->public.timing.display_color_depth;
+	pixel_clk_params->flags.DISPLAY_BLANKED = 1;
+}
+
+static enum dc_status build_stream_hw_param(struct core_stream *stream)
+{
+	/*TODO: unhardcode*/
+	stream->max_tmds_clk_from_edid_in_mhz = 0;
+	stream->max_hdmi_deep_color = COLOR_DEPTH_121212;
+	stream->max_hdmi_pixel_clock = 600000;
+
+	get_pixel_clock_parameters(stream, &stream->pix_clk_params);
+	stream->clock_source->funcs->get_pix_clk_dividers(
+		stream->clock_source,
+		&stream->pix_clk_params,
+		&stream->pll_settings);
+
+	build_audio_output(stream, &stream->audio_output);
+
+	return DC_OK;
+}
+
+static enum dc_status validate_mapped_resource(
+		const struct dc *dc,
+		struct validate_context *context)
+{
+	enum dc_status status = DC_OK;
+	uint8_t i, j;
+
+	for (i = 0; i < context->target_count; i++) {
+		struct core_target *target = context->targets[i];
+
+		if (context->target_flags[i].unchanged)
+			continue;
+		for (j = 0; j < target->public.stream_count; j++) {
+			struct core_stream *stream =
+				DC_STREAM_TO_CORE(target->public.streams[j]);
+			struct core_link *link = stream->sink->link;
+
+			if (!stream->tg->funcs->validate_timing(
+					stream->tg, &stream->public.timing))
+				return DC_FAIL_CONTROLLER_VALIDATE;
+
+			if (stream->signal == SIGNAL_TYPE_VIRTUAL)
+				return status;
+
+			status = build_stream_hw_param(stream);
+
+			if (status != DC_OK)
+				return status;
+
+			if (!link->link_enc->funcs->validate_output_with_stream(
+					link->link_enc,
+					stream))
+				return DC_FAIL_ENC_VALIDATE;
+
+			/* TODO: validate audio ASIC caps, encoder */
+
+			status = dc_link_validate_mode_timing(stream->sink,
+					link,
+					&stream->public.timing);
+
+			if (status != DC_OK)
+				return status;
+
+			build_info_frame(stream);
+		}
+	}
+
+	return DC_OK;
+}
+
+enum dc_status dce100_validate_bandwidth(
+	const struct dc *dc,
+	struct validate_context *context)
+{
+	/* TODO implement when needed */
+
+	return DC_OK;
+}
+
+static void set_target_unchanged(
+		struct validate_context *context,
+		uint8_t target_idx)
+{
+	uint8_t i;
+	struct core_target *target = context->targets[target_idx];
+
+	context->target_flags[target_idx].unchanged = true;
+	for (i = 0; i < target->public.stream_count; i++) {
+		struct core_stream *core_stream =
+			DC_STREAM_TO_CORE(target->public.streams[i]);
+		uint8_t index = core_stream->controller_idx;
+
+		context->res_ctx.controller_ctx[index].flags.unchanged = true;
+	}
+}
+
+static enum dc_status map_clock_resources(
+		const struct dc *dc,
+		struct validate_context *context)
+{
+	uint8_t i, j;
+
+	/* mark resources used for targets that are already active */
+	for (i = 0; i < context->target_count; i++) {
+		struct core_target *target = context->targets[i];
+
+		if (!context->target_flags[i].unchanged)
+			continue;
+
+		for (j = 0; j < target->public.stream_count; j++) {
+			struct core_stream *stream =
+				DC_STREAM_TO_CORE(target->public.streams[j]);
+
+			reference_clock_source(
+				&context->res_ctx,
+				stream->clock_source);
+		}
+	}
+
+	/* acquire new resources */
+	for (i = 0; i < context->target_count; i++) {
+		struct core_target *target = context->targets[i];
+
+		if (context->target_flags[i].unchanged)
+			continue;
+
+		for (j = 0; j < target->public.stream_count; j++) {
+			struct core_stream *stream =
+				DC_STREAM_TO_CORE(target->public.streams[j]);
+
+			if (dc_is_dp_signal(stream->signal)
+				|| stream->signal == SIGNAL_TYPE_VIRTUAL)
+				stream->clock_source = context->res_ctx.
+					pool.clock_sources[DCE100_CLK_SRC_EXT];
+			else
+				stream->clock_source =
+					find_used_clk_src_for_sharing(
+							context, stream);
+			if (stream->clock_source == NULL)
+				stream->clock_source =
+					find_first_free_pll(&context->res_ctx);
+
+			if (stream->clock_source == NULL)
+				return DC_NO_CLOCK_SOURCE_RESOURCE;
+
+			reference_clock_source(
+					&context->res_ctx,
+					stream->clock_source);
+		}
+	}
+
+	return DC_OK;
+}
+
+enum dc_status dce100_validate_with_context(
+		const struct dc *dc,
+		const struct dc_validation_set set[],
+		uint8_t set_count,
+		struct validate_context *context)
+{
+	enum dc_status result = DC_ERROR_UNEXPECTED;
+	uint8_t i, j;
+	struct dc_context *dc_ctx = dc->ctx;
+
+	for (i = 0; i < set_count; i++) {
+		context->targets[i] = DC_TARGET_TO_CORE(set[i].target);
+
+		for (j = 0; j < dc->current_context.target_count; j++)
+			if (dc->current_context.targets[j] == context->targets[i])
+				set_target_unchanged(context, i);
+
+		if (!context->target_flags[i].unchanged)
+			if (!logical_attach_surfaces_to_target(
+					(struct dc_surface **)set[i].surfaces,
+					set[i].surface_count,
+					&context->targets[i]->public)) {
+				DC_ERROR("Failed to attach surface to target!\n");
+				return DC_FAIL_ATTACH_SURFACES;
+			}
+	}
+
+	context->target_count = set_count;
+
+	context->res_ctx.pool = dc->res_pool;
+
+	result = map_resources(dc, context);
+
+	if (result == DC_OK)
+		result = map_clock_resources(dc, context);
+
+	if (result == DC_OK)
+		result = validate_mapped_resource(dc, context);
+
+	if (result == DC_OK)
+		build_scaling_params_for_context(dc, context);
+
+	if (result == DC_OK)
+		result = dce100_validate_bandwidth(dc, context);
+
+	return result;
+}
+
+static struct resource_funcs dce100_res_pool_funcs = {
+	.destruct = dce100_destruct_resource_pool,
+	.link_enc_create = dce100_link_encoder_create,
+	.link_enc_destroy = dce110_link_encoder_destroy,
+	.validate_with_context = dce100_validate_with_context,
+	.validate_bandwidth = dce100_validate_bandwidth
+};
+
+bool dce100_construct_resource_pool(
+	struct adapter_service *adapter_serv,
+	uint8_t num_virtual_links,
+	struct dc *dc,
+	struct resource_pool *pool)
+{
+	unsigned int i;
+	struct audio_init_data audio_init_data = { 0 };
+	struct dc_context *ctx = dc->ctx;
+
+	pool->adapter_srv = adapter_serv;
+	pool->funcs = &dce100_res_pool_funcs;
+
+	pool->stream_engines.engine.ENGINE_ID_DIGA = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGB = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGC = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGD = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGE = 1;
+	pool->stream_engines.engine.ENGINE_ID_DIGF = 1;
+
+	pool->clock_sources[DCE100_CLK_SRC_PLL0] = dce100_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_ID_PLL0, &dce100_clk_src_reg_offsets[0]);
+	pool->clock_sources[DCE100_CLK_SRC_PLL1] = dce100_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_ID_PLL1, &dce100_clk_src_reg_offsets[1]);
+	pool->clock_sources[DCE100_CLK_SRC_EXT] =  dce100_clock_source_create(
+		ctx, dal_adapter_service_get_bios_parser(adapter_serv),
+		CLOCK_SOURCE_ID_EXTERNAL, &dce100_clk_src_reg_offsets[0]);
+	pool->clk_src_count = DCE100_CLK_SRC_TOTAL;
+
+	for (i = 0; i < pool->clk_src_count; i++) {
+		if (pool->clock_sources[i] == NULL) {
+			dm_error("DC: failed to create clock sources!\n");
+			BREAK_TO_DEBUGGER();
+			goto clk_src_create_fail;
+		}
+	}
+
+	pool->display_clock = dal_display_clock_dce110_create(ctx, adapter_serv);
+	if (pool->display_clock == NULL) {
+		dm_error("DC: failed to create display clock!\n");
+		BREAK_TO_DEBUGGER();
+		goto disp_clk_create_fail;
+	}
+
+	{
+		struct irq_service_init_data init_data;
+
+		init_data.ctx = dc->ctx;
+		pool->irqs = dal_irq_service_create(
+				dal_adapter_service_get_dce_version(
+					dc->res_pool.adapter_srv),
+				&init_data);
+		if (!pool->irqs)
+			goto irqs_create_fail;
+
+	}
+
+	pool->controller_count =
+		dal_adapter_service_get_func_controllers_num(adapter_serv);
+	pool->stream_enc_count = dal_adapter_service_get_stream_engines_num(
+			adapter_serv);
+	pool->scaler_filter = dal_scaler_filter_create(ctx);
+	if (pool->scaler_filter == NULL) {
+		BREAK_TO_DEBUGGER();
+		dm_error("DC: failed to create filter!\n");
+		goto filter_create_fail;
+	}
+
+	for (i = 0; i < pool->controller_count; i++) {
+		pool->timing_generators[i] = dce100_timing_generator_create(
+				adapter_serv, ctx, i, &dce100_tg_offsets[i]);
+		if (pool->timing_generators[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create tg!\n");
+			goto controller_create_fail;
+		}
+
+		pool->mis[i] = dce100_mem_input_create(ctx, i,
+				&dce100_mi_reg_offsets[i]);
+		if (pool->mis[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create memory input!\n");
+			goto controller_create_fail;
+		}
+
+		pool->ipps[i] = dce100_ipp_create(ctx, i,
+				&dce100_ipp_reg_offsets[i]);
+		if (pool->ipps[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create input pixel processor!\n");
+			goto controller_create_fail;
+		}
+
+		pool->transforms[i] = dce100_transform_create(
+					ctx, i, &dce100_xfm_offsets[i]);
+		if (pool->transforms[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create transform!\n");
+			goto controller_create_fail;
+		}
+		pool->transforms[i]->funcs->transform_set_scaler_filter(
+				pool->transforms[i],
+				pool->scaler_filter);
+
+		pool->opps[i] = dce100_opp_create(ctx, i, &dce100_opp_reg_offsets[i]);
+		if (pool->opps[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create output pixel processor!\n");
+			goto controller_create_fail;
+		}
+	}
+
+	audio_init_data.as = adapter_serv;
+	audio_init_data.ctx = ctx;
+	pool->audio_count = 0;
+	for (i = 0; i < pool->controller_count; i++) {
+		struct graphics_object_id obj_id;
+
+		obj_id = dal_adapter_service_enum_audio_object(adapter_serv, i);
+		if (false == dal_graphics_object_id_is_valid(obj_id)) {
+			/* no more valid audio objects */
+			break;
+		}
+
+		audio_init_data.audio_stream_id = obj_id;
+		pool->audios[i] = dal_audio_create(&audio_init_data);
+		if (pool->audios[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create DPPs!\n");
+			goto audio_create_fail;
+		}
+		pool->audio_count++;
+	}
+
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		/* TODO: rework fragile code*/
+		if (pool->stream_engines.u_all & 1 << i) {
+			pool->stream_enc[i] = dce100_stream_encoder_create(
+				i, dc->ctx,
+				dal_adapter_service_get_bios_parser(
+					adapter_serv),
+				&stream_enc_regs[i]);
+			if (pool->stream_enc[i] == NULL) {
+				BREAK_TO_DEBUGGER();
+				dm_error("DC: failed to create stream_encoder!\n");
+				goto stream_enc_create_fail;
+			}
+		}
+	}
+
+	for (i = 0; i < num_virtual_links; i++) {
+		pool->stream_enc[pool->stream_enc_count] =
+			virtual_stream_encoder_create(
+				dc->ctx, dal_adapter_service_get_bios_parser(
+								adapter_serv));
+		if (pool->stream_enc[pool->stream_enc_count] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create stream_encoder!\n");
+			goto stream_enc_create_fail;
+		}
+		pool->stream_enc_count++;
+	}
+
+	return true;
+
+stream_enc_create_fail:
+	for (i = 0; i < pool->stream_enc_count; i++) {
+		if (pool->stream_enc[i] != NULL)
+			dm_free(pool->stream_enc[i]->ctx,
+				DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
+	}
+
+audio_create_fail:
+	for (i = 0; i < pool->controller_count; i++) {
+		if (pool->audios[i] != NULL)
+			dal_audio_destroy(&pool->audios[i]);
+	}
+
+controller_create_fail:
+	for (i = 0; i < pool->controller_count; i++) {
+		if (pool->opps[i] != NULL)
+			dce100_opp_destroy(&pool->opps[i]);
+
+		if (pool->transforms[i] != NULL)
+			dce100_transform_destroy(&pool->transforms[i]);
+
+		if (pool->ipps[i] != NULL)
+			dce110_ipp_destroy(&pool->ipps[i]);
+
+		if (pool->mis[i] != NULL) {
+			dm_free(pool->mis[i]->ctx,
+					TO_DCE110_MEM_INPUT(pool->mis[i]));
+			pool->mis[i] = NULL;
+		}
+
+		if (pool->timing_generators[i] != NULL)	{
+			dm_free(pool->timing_generators[i]->ctx,
+				DCE110TG_FROM_TG(pool->timing_generators[i]));
+			pool->timing_generators[i] = NULL;
+		}
+	}
+
+filter_create_fail:
+	dal_irq_service_destroy(&pool->irqs);
+
+irqs_create_fail:
+	dal_display_clock_destroy(&pool->display_clock);
+
+disp_clk_create_fail:
+clk_src_create_fail:
+	for (i = 0; i < pool->clk_src_count; i++) {
+		if (pool->clock_sources[i] != NULL)
+			dce100_clock_source_destroy(&pool->clock_sources[i]);
+	}
+
+	return false;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.h b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.h
new file mode 100644
index 000000000000..2a23d864831f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce100/dce100_resource.h
@@ -0,0 +1,43 @@
+/*
+* Copyright 2015 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 DCE100_RESOURCE_H_
+#define DCE100_RESOURCE_H_
+
+struct adapter_service;
+struct dc;
+struct resource_pool;
+struct dc_validation_set;
+
+
+bool dce100_construct_resource_pool(
+	struct adapter_service *adapter_serv,
+	uint8_t num_virtual_links,
+	struct dc *dc,
+	struct resource_pool *pool);
+
+void dce100_destruct_resource_pool(struct resource_pool *pool);
+
+#endif /* DCE100_RESOURCE_H_ */
-- 
2.1.4



More information about the dri-devel mailing list