aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0956-drm-amd-dal-add-core-support-for-Polaris-family-v2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0956-drm-amd-dal-add-core-support-for-Polaris-family-v2.patch')
-rw-r--r--common/recipes-kernel/linux/files/0956-drm-amd-dal-add-core-support-for-Polaris-family-v2.patch9820
1 files changed, 9820 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0956-drm-amd-dal-add-core-support-for-Polaris-family-v2.patch b/common/recipes-kernel/linux/files/0956-drm-amd-dal-add-core-support-for-Polaris-family-v2.patch
new file mode 100644
index 00000000..6143ca86
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0956-drm-amd-dal-add-core-support-for-Polaris-family-v2.patch
@@ -0,0 +1,9820 @@
+From bc3e400b9b554d0e8448d89c7a721f887b612dfc Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexander.deucher@amd.com>
+Date: Tue, 15 Mar 2016 10:53:48 -0400
+Subject: [PATCH 0956/1110] drm/amd/dal: add core support for Polaris family
+ (v2)
+
+This adds core dc support for polaris 10 and 11.
+
+v2: add missing files
+
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ drivers/gpu/drm/amd/dal/dc/Makefile | 4 +
+ drivers/gpu/drm/amd/dal/dc/adapter/Makefile | 4 +
+ .../gpu/drm/amd/dal/dc/adapter/adapter_service.c | 12 +
+ .../adapter/dce112/hw_ctx_adapter_service_dce112.c | 302 +++
+ .../adapter/dce112/hw_ctx_adapter_service_dce112.h | 39 +
+ .../gpu/drm/amd/dal/dc/asic_capability/Makefile | 9 +
+ .../amd/dal/dc/asic_capability/asic_capability.c | 15 +-
+ .../dc/asic_capability/polaris10_asic_capability.c | 146 ++
+ .../dc/asic_capability/polaris10_asic_capability.h | 36 +
+ drivers/gpu/drm/amd/dal/dc/audio/Makefile | 8 +
+ drivers/gpu/drm/amd/dal/dc/audio/audio_base.c | 9 +
+ .../gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c | 451 +++++
+ .../gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h | 40 +
+ .../amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c | 1923 ++++++++++++++++++++
+ .../amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h | 47 +
+ drivers/gpu/drm/amd/dal/dc/bios/Makefile | 9 +
+ .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.c | 6 +
+ .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.h | 4 +
+ drivers/gpu/drm/amd/dal/dc/bios/command_table.c | 78 +-
+ .../gpu/drm/amd/dal/dc/bios/command_table_helper.c | 6 +
+ .../gpu/drm/amd/dal/dc/bios/command_table_helper.h | 3 +
+ .../dal/dc/bios/dce112/bios_parser_helper_dce112.c | 480 +++++
+ .../dal/dc/bios/dce112/bios_parser_helper_dce112.h | 34 +
+ .../dc/bios/dce112/command_table_helper_dce112.c | 417 +++++
+ .../dc/bios/dce112/command_table_helper_dce112.h | 34 +
+ drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c | 206 +++
+ drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c | 7 +
+ drivers/gpu/drm/amd/dal/dc/core/dc_resource.c | 22 +-
+ .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 1 +
+ .../amd/dal/dc/dce110/dce110_timing_generator.c | 2 +-
+ drivers/gpu/drm/amd/dal/dc/dce112/Makefile | 10 +
+ .../drm/amd/dal/dc/dce112/dce112_clock_source.c | 266 +++
+ .../drm/amd/dal/dc/dce112/dce112_clock_source.h | 52 +
+ .../gpu/drm/amd/dal/dc/dce112/dce112_compressor.c | 883 +++++++++
+ .../gpu/drm/amd/dal/dc/dce112/dce112_compressor.h | 84 +
+ .../drm/amd/dal/dc/dce112/dce112_hw_sequencer.c | 178 ++
+ .../drm/amd/dal/dc/dce112/dce112_hw_sequencer.h | 36 +
+ .../drm/amd/dal/dc/dce112/dce112_link_encoder.c | 116 ++
+ .../drm/amd/dal/dc/dce112/dce112_link_encoder.h | 41 +
+ .../gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c | 455 +++++
+ .../gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h | 38 +
+ .../gpu/drm/amd/dal/dc/dce112/dce112_resource.c | 1404 ++++++++++++++
+ .../gpu/drm/amd/dal/dc/dce112/dce112_resource.h | 42 +
+ drivers/gpu/drm/amd/dal/dc/dm_services_types.h | 5 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c | 3 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c | 3 +
+ drivers/gpu/drm/amd/dal/dc/gpu/Makefile | 8 +
+ .../amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c | 89 +
+ .../amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h | 33 +
+ .../amd/dal/dc/gpu/dce112/display_clock_dce112.c | 964 ++++++++++
+ .../amd/dal/dc/gpu/dce112/display_clock_dce112.h | 54 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c | 5 +-
+ drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h | 4 +-
+ drivers/gpu/drm/amd/dal/dc/irq/irq_service.c | 4 +
+ drivers/gpu/drm/amd/dal/include/dal_asic_id.h | 14 +
+ drivers/gpu/drm/amd/dal/include/dal_types.h | 3 +
+ .../drm/amd/dal/include/display_clock_interface.h | 6 +
+ 57 files changed, 9146 insertions(+), 8 deletions(-)
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h
+
+diff --git a/drivers/gpu/drm/amd/dal/dc/Makefile b/drivers/gpu/drm/amd/dal/dc/Makefile
+index 5112ec9..a718674 100644
+--- a/drivers/gpu/drm/amd/dal/dc/Makefile
++++ b/drivers/gpu/drm/amd/dal/dc/Makefile
+@@ -5,6 +5,10 @@
+ DC_LIBS = adapter asic_capability audio basics bios calcs \
+ gpio gpu i2caux irq virtual
+
++ifdef CONFIG_DRM_AMD_DAL_DCE11_2
++DC_LIBS += dce112
++endif
++
+ ifdef CONFIG_DRM_AMD_DAL_DCE11_0
+ DC_LIBS += dce110
+ endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
+index db1f0e8..370323e 100644
+--- a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
+@@ -25,6 +25,10 @@ ifdef CONFIG_DRM_AMD_DAL_DCE11_0
+ AMD_DAL_FILES += $(AMDDALPATH)/dc/adapter/dce110/hw_ctx_adapter_service_dce110.o
+ endif
+
++ifdef CONFIG_DRM_AMD_DAL_DCE11_2
++AMD_DAL_FILES += $(AMDDALPATH)/dc/adapter/dce112/hw_ctx_adapter_service_dce112.o
++endif
++
+ ###############################################################################
+ # FPGA Diagnositcs
+ ###############################################################################
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
+index f7aea01..308d456 100644
+--- a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
+@@ -49,6 +49,10 @@
+ #include "dce110/hw_ctx_adapter_service_dce110.h"
+ #endif
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "dce112/hw_ctx_adapter_service_dce112.h"
++#endif
++
+ #include "diagnostics/hw_ctx_adapter_service_diag.h"
+
+ /*
+@@ -664,6 +668,10 @@ static struct hw_ctx_adapter_service *create_hw_ctx(
+ case DCE_VERSION_11_0:
+ return dal_adapter_service_create_hw_ctx_dce110(ctx);
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ return dal_adapter_service_create_hw_ctx_dce112(ctx);
++#endif
+ default:
+ ASSERT_CRITICAL(false);
+ return NULL;
+@@ -907,6 +915,10 @@ enum dce_version dal_adapter_service_get_dce_version(
+ case 0x110:
+ return DCE_VERSION_11_0;
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case 0x112:
++ return DCE_VERSION_11_2;
++#endif
+ default:
+ ASSERT_CRITICAL(false);
+ return DCE_VERSION_UNKNOWN;
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c
+new file mode 100644
+index 0000000..f438998
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.c
+@@ -0,0 +1,302 @@
++/*
++ * 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 "../hw_ctx_adapter_service.h"
++
++#include "hw_ctx_adapter_service_dce112.h"
++
++#include "include/logger_interface.h"
++#include "include/grph_object_id.h"
++
++#include "dce/dce_11_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++
++#ifndef mmCC_DC_HDMI_STRAPS
++#define mmCC_DC_HDMI_STRAPS 0x4819
++#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40
++#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6
++#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700
++#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8
++#endif
++
++static const struct graphics_object_id invalid_go = {
++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN, 0
++};
++
++/* Macro */
++#define AUDIO_STRAPS_HDMI_ENABLE 0x2
++
++#define FROM_HW_CTX(ptr) \
++ container_of((ptr), struct hw_ctx_adapter_service_dce112, base)
++
++static const uint32_t audio_index_reg_offset[] = {
++ /*CZ has 3 DIGs but 4 audio endpoints*/
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX
++};
++
++static const uint32_t audio_data_reg_offset[] = {
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA,
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA,
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA,
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA,
++};
++
++enum {
++ MAX_NUMBER_OF_AUDIO_PINS = 4
++};
++
++static void destruct(
++ struct hw_ctx_adapter_service_dce112 *hw_ctx)
++{
++ /* There is nothing to destruct at the moment */
++ dal_adapter_service_destruct_hw_ctx(&hw_ctx->base);
++}
++
++static void destroy(
++ struct hw_ctx_adapter_service *ptr)
++{
++ struct hw_ctx_adapter_service_dce112 *hw_ctx =
++ FROM_HW_CTX(ptr);
++
++ destruct(hw_ctx);
++
++ dm_free(hw_ctx);
++}
++
++/*
++ * enum_audio_object
++ *
++ * @brief enumerate audio object
++ *
++ * @param
++ * const struct hw_ctx_adapter_service *hw_ctx - [in] provides num of endpoints
++ * uint32_t index - [in] audio index
++ *
++ * @return
++ * grphic object id
++ */
++static struct graphics_object_id enum_audio_object(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index)
++{
++ uint32_t number_of_connected_audio_endpoints =
++ FROM_HW_CTX(hw_ctx)->number_of_connected_audio_endpoints;
++
++ if (index >= number_of_connected_audio_endpoints ||
++ number_of_connected_audio_endpoints == 0)
++ return invalid_go;
++ else
++ return dal_graphics_object_id_init(
++ AUDIO_ID_INTERNAL_AZALIA,
++ (enum object_enum_id)(index + 1),
++ OBJECT_TYPE_AUDIO);
++}
++
++static uint32_t get_number_of_connected_audio_endpoints_multistream(
++ struct dc_context *ctx)
++{
++ uint32_t num_connected_audio_endpoints = 0;
++ uint32_t i;
++ uint32_t default_config =
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT;
++
++ /* find the total number of streams available via the
++ * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
++ * registers (one for each pin) starting from pin 1
++ * up to the max number of audio pins.
++ * We stop on the first pin where
++ * PORT_CONNECTIVITY == 1 (as instructed by HW team).
++ */
++ for (i = 0; i < MAX_NUMBER_OF_AUDIO_PINS; i++) {
++ uint32_t value = 0;
++
++ set_reg_field_value(value,
++ default_config,
++ AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ AZALIA_ENDPOINT_REG_INDEX);
++
++ dm_write_reg(ctx, audio_index_reg_offset[i], value);
++
++ value = 0;
++ value = dm_read_reg(ctx, audio_data_reg_offset[i]);
++
++ /* 1 means not supported*/
++ if (get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
++ PORT_CONNECTIVITY) == 1)
++ break;
++
++ num_connected_audio_endpoints++;
++ }
++
++ return num_connected_audio_endpoints;
++
++}
++
++/*
++ * get_number_of_connected_audio_endpoints
++ */
++static uint32_t get_number_of_connected_audio_endpoints(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ uint32_t addr = mmCC_DC_HDMI_STRAPS;
++ uint32_t value = 0;
++ uint32_t field = 0;
++
++ if (hw_ctx->cached_audio_straps == AUDIO_STRAPS_NOT_ALLOWED)
++ /* audio straps indicate no audio supported */
++ return 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ field = get_reg_field_value(
++ value, CC_DC_HDMI_STRAPS, AUDIO_STREAM_NUMBER);
++ if (field == 1)
++ /* multi streams not supported */
++ return 1;
++ else if (field == 0)
++ /* multi streams supported */
++ return get_number_of_connected_audio_endpoints_multistream(
++ hw_ctx->ctx);
++
++ /* unexpected value */
++ ASSERT_CRITICAL(false);
++ return field;
++}
++
++/*
++ * power_up
++ *
++ * @brief
++ * Determine and cache audio support from register.
++ *
++ * @param
++ * struct hw_ctx_adapter_service *hw_ctx - [in] adapter service hw context
++ *
++ * @return
++ * true if succeed, false otherwise
++ */
++static bool power_up(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ struct hw_ctx_adapter_service_dce112 *hw_ctx_dce11 =
++ FROM_HW_CTX(hw_ctx);
++ /* Allow DP audio all the time
++ * without additional pinstrap check on Fusion */
++
++ {
++ uint32_t value = 0;
++ uint32_t field = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, mmCC_DC_HDMI_STRAPS);
++ field = get_reg_field_value(
++ value, CC_DC_HDMI_STRAPS, HDMI_DISABLE);
++
++ if (field == 0) {
++ hw_ctx->cached_audio_straps = AUDIO_STRAPS_DP_HDMI_AUDIO;
++ } else {
++ value = dm_read_reg(
++ hw_ctx->ctx, mmDC_PINSTRAPS);
++ field = get_reg_field_value(
++ value,
++ DC_PINSTRAPS,
++ DC_PINSTRAPS_AUDIO);
++
++ if (field & AUDIO_STRAPS_HDMI_ENABLE)
++ hw_ctx->cached_audio_straps =
++ AUDIO_STRAPS_DP_HDMI_AUDIO_ON_DONGLE;
++ else
++ hw_ctx->cached_audio_straps =
++ AUDIO_STRAPS_DP_AUDIO_ALLOWED;
++ }
++
++ }
++
++ /* get the number of connected audio endpoints */
++ hw_ctx_dce11->number_of_connected_audio_endpoints =
++ get_number_of_connected_audio_endpoints(hw_ctx);
++
++ return true;
++}
++
++static void update_audio_connectivity(
++ struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t number_of_audio_capable_display_path,
++ uint32_t number_of_controllers)
++{
++ /* this one should be empty on DCE112 */
++}
++
++static const struct hw_ctx_adapter_service_funcs funcs = {
++ .destroy = destroy,
++ .power_up = power_up,
++ .enum_fake_path_resource = NULL,
++ .enum_stereo_sync_object = NULL,
++ .enum_sync_output_object = NULL,
++ .enum_audio_object = enum_audio_object,
++ .update_audio_connectivity = update_audio_connectivity
++};
++
++static bool construct(
++ struct hw_ctx_adapter_service_dce112 *hw_ctx,
++ struct dc_context *ctx)
++{
++ if (!dal_adapter_service_construct_hw_ctx(&hw_ctx->base, ctx)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ hw_ctx->base.funcs = &funcs;
++ hw_ctx->number_of_connected_audio_endpoints = 0;
++
++ return true;
++}
++
++struct hw_ctx_adapter_service *
++ dal_adapter_service_create_hw_ctx_dce112(
++ struct dc_context *ctx)
++{
++ struct hw_ctx_adapter_service_dce112 *hw_ctx =
++ dm_alloc(sizeof(struct hw_ctx_adapter_service_dce112));
++
++ if (!hw_ctx) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(hw_ctx, ctx))
++ return &hw_ctx->base;
++
++ ASSERT_CRITICAL(false);
++
++ dm_free(hw_ctx);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h
+new file mode 100644
+index 0000000..bc60030
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce112/hw_ctx_adapter_service_dce112.h
+@@ -0,0 +1,39 @@
++/*
++ * 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_HW_CTX_ADAPTER_SERVICE_DCE112_H__
++#define __DAL_HW_CTX_ADAPTER_SERVICE_DCE112_H__
++
++struct hw_ctx_adapter_service_dce112 {
++ struct hw_ctx_adapter_service base;
++ uint32_t number_of_connected_audio_endpoints;
++};
++
++struct hw_ctx_adapter_service *
++ dal_adapter_service_create_hw_ctx_dce112(
++ struct dc_context *ctx);
++
++#endif /* __DAL_HW_CTX_ADAPTER_SERVICE_DCE112_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
+index b243542..e80de2a 100644
+--- a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
+@@ -46,3 +46,12 @@ AMD_DAL_ASIC_CAPABILITY_DCE11 = \
+
+ AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY_DCE11)
+ endif
++
++ifdef CONFIG_DRM_AMD_DAL_DCE11_2
++ASIC_CAPABILITY_DCE112 = polaris10_asic_capability.o
++
++AMD_DAL_ASIC_CAPABILITY_DCE112 = \
++ $(addprefix $(AMDDALPATH)/dc/asic_capability/,$(ASIC_CAPABILITY_DCE112))
++
++AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY_DCE112)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
+index 75e0e27..aeabfc6 100644
+--- a/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
+@@ -44,6 +44,10 @@
+ #include "carrizo_asic_capability.h"
+ #endif
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "polaris10_asic_capability.h"
++#endif
++
+ /*
+ * Initializes asic_capability instance.
+ */
+@@ -108,7 +112,8 @@ static bool construct(
+ asic_supported = true;
+ #endif
+ break;
+- case FAMILY_VI:
++
++ case FAMILY_VI:
+ #if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
+ if (ASIC_REV_IS_TONGA_P(init->hw_internal_rev) ||
+ ASIC_REV_IS_FIJI_P(init->hw_internal_rev)) {
+@@ -117,7 +122,15 @@ static bool construct(
+ break;
+ }
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ if (ASIC_REV_IS_POLARIS10_P(init->hw_internal_rev) ||
++ ASIC_REV_IS_POLARIS11_M(init->hw_internal_rev)) {
++ polaris10_asic_capability_create(cap, init);
++ asic_supported = true;
++ }
++#endif
+ break;
++
+ default:
+ /* unsupported "chip_family" */
+ break;
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c
+new file mode 100644
+index 0000000..9e4fdfa
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.c
+@@ -0,0 +1,146 @@
++/*
++ * 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/asic_capability_interface.h"
++#include "include/asic_capability_types.h"
++
++#include "polaris10_asic_capability.h"
++
++#include "atom.h"
++#include "dce/dce_11_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++#include "dal_asic_id.h"
++
++#define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074
++
++/*
++ * carrizo_asic_capability_create
++ *
++ * Create and initiate Carrizo capability.
++ */
++void polaris10_asic_capability_create(struct asic_capability *cap,
++ struct hw_asic_id *init)
++{
++ uint32_t e_fuse_setting;
++ /* ASIC data */
++ if (ASIC_REV_IS_POLARIS11_M(init->hw_internal_rev)) {
++ cap->data[ASIC_DATA_CONTROLLERS_NUM] = 5;
++ cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 5;
++ cap->data[ASIC_DATA_LINEBUFFER_NUM] = 5;
++ cap->data[ASIC_DATA_DIGFE_NUM] = 5;
++ cap->data[ASIC_DATA_CLOCKSOURCES_NUM] = 7;
++ cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS] = 5;
++ cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 5;
++ } else {
++ cap->data[ASIC_DATA_CONTROLLERS_NUM] = 6;
++ cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 6;
++ cap->data[ASIC_DATA_LINEBUFFER_NUM] = 6;
++ cap->data[ASIC_DATA_DIGFE_NUM] = 6;
++ cap->data[ASIC_DATA_CLOCKSOURCES_NUM] = 8;
++ cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS] = 6;
++ cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 6;
++ }
++
++ cap->data[ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR] = 4;
++ cap->data[ASIC_DATA_DCE_VERSION] = 0x112; /* DCE 11 */
++ cap->data[ASIC_DATA_LINEBUFFER_SIZE] = 5124 * 144;
++ cap->data[ASIC_DATA_DRAM_BANDWIDTH_EFFICIENCY] = 70;
++
++ cap->data[ASIC_DATA_MC_LATENCY] = 3000;
++ cap->data[ASIC_DATA_STUTTERMODE] = 0x200A;
++ cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY] = 2;
++
++ cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER] = 4;
++ cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ] = 100;
++ cap->data[ASIC_DATA_NUM_OF_VIDEO_PLANES] = 0;
++
++ cap->data[ASIC_DATA_MIN_DISPCLK_FOR_UNDERSCAN] = 300000;
++
++ /* ASIC basic capability */
++ cap->caps.IS_FUSION = true;
++ cap->caps.DP_MST_SUPPORTED = true;
++ cap->caps.PANEL_SELF_REFRESH_SUPPORTED = true;
++ cap->caps.MIRABILIS_SUPPORTED = true;
++ cap->caps.NO_VCC_OFF_HPD_POLLING = true;
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.HPD_CHECK_FOR_EDID = true;
++ cap->caps.DFSBYPASS_DYNAMIC_SUPPORT = true;
++ cap->caps.SUPPORT_8BPP = false;
++
++ /* ASIC stereo 3d capability */
++ cap->stereo_3d_caps.DISPLAY_BASED_ON_WS = true;
++ cap->stereo_3d_caps.HDMI_FRAME_PACK = true;
++ cap->stereo_3d_caps.INTERLACE_FRAME_PACK = true;
++ cap->stereo_3d_caps.DISPLAYPORT_FRAME_PACK = true;
++ cap->stereo_3d_caps.DISPLAYPORT_FRAME_ALT = true;
++ cap->stereo_3d_caps.INTERLEAVE = true;
++
++ e_fuse_setting = dm_read_index_reg(cap->ctx,CGS_IND_REG__SMC, ixVCE_HARVEST_FUSE_MACRO__ADDRESS);
++
++ /* Bits [28:27]*/
++ switch ((e_fuse_setting >> 27) & 0x3) {
++ case 0:
++ /*both VCE engine are working*/
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = false;
++ /*TODO:
++ cap->caps.wirelessLowVCEPerformance = false;
++ m_AsicCaps.vceInstance0Enabled = true;
++ m_AsicCaps.vceInstance1Enabled = true;*/
++ cap->caps.NEED_MC_TUNING = true;
++ break;
++
++ case 1:
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
++ /*TODO:
++ m_AsicCaps.wirelessLowVCEPerformance = false;
++ m_AsicCaps.vceInstance1Enabled = true;*/
++ cap->caps.NEED_MC_TUNING = true;
++ break;
++
++ case 2:
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
++ /*TODO:
++ m_AsicCaps.wirelessLowVCEPerformance = false;
++ m_AsicCaps.vceInstance0Enabled = true;*/
++ cap->caps.NEED_MC_TUNING = true;
++ break;
++
++ case 3:
++ /* VCE_DISABLE = 0x3 - both VCE
++ * instances are in harvesting,
++ * no VCE supported any more.
++ */
++ cap->caps.VCE_SUPPORTED = false;
++ break;
++
++ default:
++ break;
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.h
+new file mode 100644
+index 0000000..c8aebe1
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/polaris10_asic_capability.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 __DAL_POLARIS10_ASIC_CAPABILITY_H__
++#define __DAL_POLARIS10_ASIC_CAPABILITY_H__
++
++/* Forward declaration */
++struct asic_capability;
++
++/* Create and initialize Polaris10 data */
++void polaris10_asic_capability_create(struct asic_capability *cap,
++ struct hw_asic_id *init);
++
++#endif /* __DAL_POLARIS10_ASIC_CAPABILITY_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/Makefile b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
+index 2433d90..9a9a64c 100644
+--- a/drivers/gpu/drm/amd/dal/dc/audio/Makefile
++++ b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
+@@ -32,3 +32,11 @@ AMD_DAL_AUDIO_DCE11 = $(addprefix $(AMDDALPATH)/dc/audio/dce110/,$(AUDIO_DCE11))
+
+ AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE11)
+ endif
++
++ifdef CONFIG_DRM_AMD_DAL_DCE11_2
++AUDIO_DCE112 = audio_dce112.o hw_ctx_audio_dce112.o
++
++AMD_DAL_AUDIO_DCE112 = $(addprefix $(AMDDALPATH)/dc/audio/dce112/,$(AUDIO_DCE112))
++
++AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE112)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
+index c297d95..a8137e0 100644
+--- a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
++++ b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
+@@ -40,6 +40,11 @@
+ #include "dce110/hw_ctx_audio_dce110.h"
+ #endif
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "dce112/audio_dce112.h"
++#include "dce112/hw_ctx_audio_dce112.h"
++#endif
++
+ /***** static function : only used within audio.c *****/
+
+ /* stub for hook functions */
+@@ -281,6 +286,10 @@ struct audio *dal_audio_create(
+ case DCE_VERSION_11_0:
+ return dal_audio_create_dce110(init_data);
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ return dal_audio_create_dce112(init_data);
++#endif
+ default:
+ BREAK_TO_DEBUGGER();
+ return NULL;
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c
+new file mode 100644
+index 0000000..66c32b0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.c
+@@ -0,0 +1,451 @@
++/*
++ * 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 "audio_dce112.h"
++
++/***** static functions *****/
++
++static void destruct(struct audio_dce112 *audio)
++{
++ /*release memory allocated for hw_ctx -- allocated is initiated
++ *by audio_dce112 power_up
++ *audio->base->hw_ctx = NULL is done within hw-ctx->destroy
++ */
++ if (audio->base.hw_ctx)
++ audio->base.hw_ctx->funcs->destroy(&(audio->base.hw_ctx));
++
++ /* reset base_audio_block */
++ dal_audio_destruct_base(&audio->base);
++}
++
++static void destroy(struct audio **ptr)
++{
++ struct audio_dce112 *audio = NULL;
++
++ audio = container_of(*ptr, struct audio_dce112, base);
++
++ destruct(audio);
++
++ /* release memory allocated for audio_dce112*/
++ dm_free(audio);
++ *ptr = NULL;
++}
++
++/* The inital call of hook function comes from audio object level.
++ *The passing object handle "struct audio *audio" point to base object
++ *already.There is not need to get base object from audio_dce112.
++ */
++
++/**
++* setup
++*
++* @brief
++* setup Audio HW block, to be called by dal_audio_setup
++*
++*/
++static enum audio_result setup(
++ struct audio *audio,
++ struct audio_output *output,
++ struct audio_info *info)
++{
++ switch (output->signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ /*setup HDMI audio engine*/
++ audio->hw_ctx->funcs->enable_afmt_clock(
++ audio->hw_ctx,
++ output->engine_id,
++ true);
++ audio->hw_ctx->funcs->setup_hdmi_audio(
++ audio->hw_ctx, output->engine_id, &output->crtc_info);
++
++ audio->hw_ctx->funcs->setup_azalia(
++ audio->hw_ctx,
++ output->engine_id,
++ output->signal,
++ &output->crtc_info,
++ &output->pll_info,
++ info);
++ break;
++
++ case SIGNAL_TYPE_WIRELESS:
++ /* setup Azalia block for Wireless Display - This
++ is different than for wired
++ displays because there is no
++ DIG to program.*/
++ /*TODO:
++ audio->hw_ctx->funcs->setup_azalia_for_vce(
++ audio->hw_ctx,
++ audio->signal,
++ audio->crtc_info,
++ info);
++ */
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* setup DP audio engine will be done at enable output */
++
++ /* setup Azalia block*/
++ audio->hw_ctx->funcs->setup_azalia(
++ audio->hw_ctx,
++ output->engine_id,
++ output->signal,
++ &output->crtc_info,
++ &output->pll_info,
++ info);
++
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* enable_output
++*
++* @brief
++* enable Audio HW block, to be called by dal_audio_enable_output
++*/
++static enum audio_result enable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ /* enable audio output */
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP: {
++ /* enable AFMT clock before enable audio*/
++ audio->hw_ctx->funcs->enable_afmt_clock(
++ audio->hw_ctx, engine_id, true);
++ /* setup DP audio engine */
++ audio->hw_ctx->funcs->setup_dp_audio(
++ audio->hw_ctx, engine_id);
++ /* enabl DP audio packets will be done at unblank */
++ audio->hw_ctx->funcs->enable_dp_audio(
++ audio->hw_ctx, engine_id);
++ }
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ /* route audio to VCE block */
++ audio->hw_ctx->funcs->setup_vce_audio(audio->hw_ctx);
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* disable_output
++*
++* @brief
++* disable Audio HW block, to be called by dal_audio_disable_output
++*
++*/
++static enum audio_result disable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_WIRELESS:
++ /* disable HDMI audio */
++ audio->hw_ctx->
++ funcs->disable_azalia_audio(
++ audio->hw_ctx, engine_id);
++ audio->hw_ctx->
++ funcs->enable_afmt_clock(
++ audio->hw_ctx, engine_id,
++ false);
++
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP: {
++ /* disable DP audio */
++ audio->hw_ctx->funcs->disable_dp_audio(
++ audio->hw_ctx, engine_id);
++ audio->hw_ctx->funcs->disable_azalia_audio(
++ audio->hw_ctx, engine_id);
++ audio->hw_ctx->funcs->enable_afmt_clock(
++ audio->hw_ctx, engine_id, false);
++ }
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* unmute
++*
++* @brief
++* unmute audio, to be called by dal_audio_unmute
++*
++*/
++static enum audio_result unmute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* unmute Azalia audio */
++ audio->hw_ctx->funcs->unmute_azalia_audio(
++ audio->hw_ctx, engine_id);
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ /*Do nothing for wireless display*/
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* mute
++*
++* @brief
++* mute audio, to be called by dal_audio_nmute
++*
++*/
++static enum audio_result mute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* mute Azalia audio */
++ audio->hw_ctx->funcs->mute_azalia_audio(
++ audio->hw_ctx, engine_id);
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ /*Do nothing for wireless display*/
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* initialize
++*
++* @brief
++* Perform SW initialization - create audio hw context. Then do HW
++* initialization. this function is called at dal_audio_power_up.
++*
++*/
++static enum audio_result initialize(
++ struct audio *audio)
++{
++ uint8_t audio_endpoint_enum_id = 0;
++
++ audio_endpoint_enum_id = audio->id.enum_id;
++
++ /* HW CTX already create*/
++ if (audio->hw_ctx != NULL)
++ return AUDIO_RESULT_OK;
++
++ audio->hw_ctx = dal_hw_ctx_audio_dce112_create(
++ audio->ctx,
++ audio_endpoint_enum_id);
++
++ if (audio->hw_ctx == NULL)
++ return AUDIO_RESULT_ERROR;
++
++ /* override HW default settings */
++ audio->hw_ctx->funcs->hw_initialize(audio->hw_ctx);
++
++ return AUDIO_RESULT_OK;
++}
++
++/* enable multi channel split */
++static void enable_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ audio->hw_ctx->funcs->setup_channel_splitting_mapping(
++ audio->hw_ctx,
++ engine_id,
++ signal,
++ audio_mapping, enable);
++}
++
++/* get current multi channel split. */
++static enum audio_result get_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ if (audio->hw_ctx->funcs->get_channel_splitting_mapping(
++ audio->hw_ctx, engine_id, audio_mapping)) {
++ return AUDIO_RESULT_OK;
++ } else {
++ return AUDIO_RESULT_ERROR;
++ }
++}
++
++/**
++* set_unsolicited_response_payload
++*
++* @brief
++* Set payload value for the unsolicited response
++*/
++static void set_unsolicited_response_payload(
++ struct audio *audio,
++ enum audio_payload payload)
++{
++ audio->hw_ctx->funcs->set_unsolicited_response_payload(
++ audio->hw_ctx, payload);
++}
++
++/**
++* setup_audio_wall_dto
++*
++* @brief
++* Update audio source clock from hardware context.
++*
++*/
++static void setup_audio_wall_dto(
++ struct audio *audio,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ audio->hw_ctx->funcs->setup_audio_wall_dto(
++ audio->hw_ctx, signal, crtc_info, pll_info);
++}
++
++/**
++* get_supported_features
++*
++* @brief
++* options and features supported by Audio
++* returns supported engines, signals.
++* features are reported for HW audio/Azalia block rather then Audio object
++* itself the difference for DCE6.x is that MultiStream Audio is now supported
++*
++*/
++static struct audio_feature_support get_supported_features(struct audio *audio)
++{
++ struct audio_feature_support afs = {0};
++
++ afs.ENGINE_DIGA = 1;
++ afs.ENGINE_DIGB = 1;
++ afs.ENGINE_DIGC = 1;
++ afs.MULTISTREAM_AUDIO = 1;
++
++ return afs;
++}
++
++static const struct audio_funcs funcs = {
++ .destroy = destroy,
++ .setup = setup,
++ .enable_output = enable_output,
++ .disable_output = disable_output,
++ .unmute = unmute,
++ .mute = mute,
++ .initialize = initialize,
++ .enable_channel_splitting_mapping =
++ enable_channel_splitting_mapping,
++ .get_channel_splitting_mapping =
++ get_channel_splitting_mapping,
++ .set_unsolicited_response_payload =
++ set_unsolicited_response_payload,
++ .setup_audio_wall_dto = setup_audio_wall_dto,
++ .get_supported_features = get_supported_features,
++};
++
++static bool construct(
++ struct audio_dce112 *audio,
++ const struct audio_init_data *init_data)
++{
++ struct audio *base = &audio->base;
++
++ /* base audio construct*/
++ if (!dal_audio_construct_base(base, init_data))
++ return false;
++
++ /*vtable methods*/
++ base->funcs = &funcs;
++ return true;
++}
++
++/* --- audio scope functions --- */
++
++struct audio *dal_audio_create_dce112(
++ const struct audio_init_data *init_data)
++{
++ /*allocate memory for audio_dce112 */
++ struct audio_dce112 *audio = dm_alloc(sizeof(*audio));
++
++ if (audio == NULL) {
++ ASSERT_CRITICAL(audio);
++ return NULL;
++ }
++ /*pointer to base_audio_block of audio_dce112 ==> audio base object */
++ if (construct(audio, init_data))
++ return &audio->base;
++
++ dal_logger_write(
++ init_data->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Failed to create audio object for DCE11\n");
++
++ /*release memory allocated if fail */
++ dm_free(audio);
++ return NULL;
++}
++
++/* Do not need expose construct_dce112 and destruct_dce112 becuase there is
++ *derived object after dce112
++ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h
+new file mode 100644
+index 0000000..7c8d71c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/audio_dce112.h
+@@ -0,0 +1,40 @@
++/*
++ * 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_AUDIO_DCE_112_H__
++#define __DAL_AUDIO_DCE_112_H__
++
++#include "audio/audio.h"
++#include "audio/hw_ctx_audio.h"
++#include "audio/dce112/hw_ctx_audio_dce112.h"
++
++struct audio_dce112 {
++ struct audio base;
++ /* dce-specific members are following */
++ /* none */
++};
++
++struct audio *dal_audio_create_dce112(const struct audio_init_data *init_data);
++
++#endif /*__DAL_AUDIO_DCE_112_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c
+new file mode 100644
+index 0000000..95cb86f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.c
+@@ -0,0 +1,1923 @@
++/*
++ * 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 "../hw_ctx_audio.h"
++#include "hw_ctx_audio_dce112.h"
++
++#include "dce/dce_11_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++
++#define FROM_BASE(ptr) \
++ container_of((ptr), struct hw_ctx_audio_dce112, base)
++
++#define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000
++#define DP_AUDIO_DTO_MODULE_WITHOUT_SS 360
++#define DP_AUDIO_DTO_PHASE_WITHOUT_SS 24
++
++#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUDIO_FRONT_END 0
++#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1
++#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__REGISTER_PROGRAMMABLE 2
++
++#define FIRST_AUDIO_STREAM_ID 1
++
++#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_AUDIO, \
++ "Audio:%s()\n", __func__)
++
++static const uint32_t engine_offset[] = {
++ 0,
++ mmDIG1_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG2_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG3_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG4_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG5_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL
++};
++
++static void destruct(
++ struct hw_ctx_audio_dce112 *hw_ctx_dce112)
++{
++ dal_audio_destruct_hw_ctx_audio(&hw_ctx_dce112->base);
++}
++
++static void destroy(
++ struct hw_ctx_audio **ptr)
++{
++ struct hw_ctx_audio_dce112 *hw_ctx_dce112;
++
++ hw_ctx_dce112 = container_of(
++ *ptr, struct hw_ctx_audio_dce112, base);
++
++ destruct(hw_ctx_dce112);
++ /* release memory allocated for struct hw_ctx_audio_dce112 */
++ dm_free(hw_ctx_dce112);
++
++ *ptr = NULL;
++}
++
++/* --- helpers --- */
++static void write_indirect_azalia_reg(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t reg_index,
++ uint32_t reg_data)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++ /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index;
++
++ set_reg_field_value(value, reg_index,
++ AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ AZALIA_ENDPOINT_REG_INDEX);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data;
++
++ value = 0;
++ set_reg_field_value(value, reg_data,
++ AZALIA_F0_CODEC_ENDPOINT_DATA,
++ AZALIA_ENDPOINT_REG_DATA);
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ dal_logger_write(
++ hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_AUDIO,
++ "AUDIO:write_indirect_azalia_reg: index: %u data: %u\n",
++ reg_index, reg_data);
++}
++
++static uint32_t read_indirect_azalia_reg(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t reg_index)
++{
++ uint32_t ret_val = 0;
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index;
++
++ set_reg_field_value(value, reg_index,
++ AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ AZALIA_ENDPOINT_REG_INDEX);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ ret_val = value;
++ }
++
++ dal_logger_write(
++ hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_AUDIO,
++ "AUDIO:read_indirect_azalia_reg: index: %u data: %u\n",
++ reg_index, ret_val);
++
++ return ret_val;
++}
++
++/* expose/not expose HBR capability to Audio driver */
++static void set_high_bit_rate_capable(
++ const struct hw_ctx_audio *hw_ctx,
++ bool capable)
++{
++ uint32_t value = 0;
++
++ /* set high bit rate audio capable*/
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR);
++
++ set_reg_field_value(value, capable,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
++ HBR_CAPABLE);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
++ value);
++}
++
++/* set HBR channnel count *
++static void set_hbr_channel_count(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t hbr_channel_count)
++{
++ uint32_t value = 0;
++
++ if (hbr_channel_count > 7)
++ return;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL);
++
++ set_reg_field_value(value, hbr_channel_count,
++ AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
++ HBR_CHANNEL_COUNT);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL, value);
++
++}
++
++*set compressed audio channel count *
++static void set_compressed_audio_channel_count(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t compressed_audio_ch_count)
++{
++ uint32_t value = 0;
++ if (compressed_audio_ch_count > 7)
++ return;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL);
++
++ set_reg_field_value(value, compressed_audio_ch_count,
++ AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
++ COMPRESSED_CHANNEL_COUNT);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
++ value);
++
++}
++*/
++/* set video latency in in ms/2+1 */
++static void set_video_latency(
++ const struct hw_ctx_audio *hw_ctx,
++ int latency_in_ms)
++{
++ uint32_t value = 0;
++
++ if ((latency_in_ms < 0) || (latency_in_ms > 255))
++ return;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
++
++ set_reg_field_value(value, latency_in_ms,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ VIDEO_LIPSYNC);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ value);
++
++}
++
++/* set audio latency in in ms/2+1 */
++static void set_audio_latency(
++ const struct hw_ctx_audio *hw_ctx,
++ int latency_in_ms)
++{
++ uint32_t value = 0;
++
++ if (latency_in_ms < 0)
++ latency_in_ms = 0;
++
++ if (latency_in_ms > 255)
++ latency_in_ms = 255;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
++
++ set_reg_field_value(value, latency_in_ms,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ AUDIO_LIPSYNC);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ value);
++
++}
++
++/* enable HW/SW Sync */
++/*static void enable_hw_sw_sync(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ union AZALIA_CYCLIC_BUFFER_SYNC value;
++
++ value = dal_read_reg(mmAZALIA_CYCLIC_BUFFER_SYNC);
++ value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 1;
++ dal_write_reg(mmAZALIA_CYCLIC_BUFFER_SYNC, value);
++}*/
++
++/* disable HW/SW Sync */
++/*static void disable_hw_sw_sync(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ union AZALIA_CYCLIC_BUFFER_SYNC value;
++
++ value = dal_read_reg(
++ mmAZALIA_CYCLIC_BUFFER_SYNC);
++ value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 0;
++ dal_write_reg(
++ mmAZALIA_CYCLIC_BUFFER_SYNC, value);
++}*/
++
++/* update hardware with software's current position in cyclic buffer */
++/*static void update_sw_write_ptr(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t offset)
++{
++ union AZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER value;
++
++ value = dal_read_reg(
++ mmAZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER);
++ value.bits.APPLICATION_POSITION_IN_CYCLIC_BUFFER = offset;
++ dal_write_reg(
++ mmAZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER,
++ value);
++}*/
++
++/* update Audio/Video association */
++/*static void update_av_association(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ uint32_t displayId)
++{
++
++}*/
++
++/* --- hook functions --- */
++static bool get_azalia_clock_info_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct azalia_clock_info *azalia_clock_info);
++
++static bool get_azalia_clock_info_dp(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t requested_pixel_clock_in_khz,
++ const struct audio_pll_info *pll_info,
++ struct azalia_clock_info *azalia_clock_info);
++
++static void setup_audio_wall_dto(
++ const struct hw_ctx_audio *hw_ctx,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ struct azalia_clock_info clock_info = { 0 };
++
++ uint32_t value = dm_read_reg(hw_ctx->ctx, mmDCCG_AUDIO_DTO_SOURCE);
++
++ /* TODO: GraphicsObject\inc\GraphicsObjectDefs.hpp(131):
++ *inline bool isHdmiSignal(SignalType signal)
++ *if (Signals::isHdmiSignal(signal))
++ */
++ if (dc_is_hdmi_signal(signal)) {
++ /*DTO0 Programming goal:
++ -generate 24MHz, 128*Fs from 24MHz
++ -use DTO0 when an active HDMI port is connected
++ (optionally a DP is connected) */
++
++ /* calculate DTO settings */
++ get_azalia_clock_info_hdmi(
++ hw_ctx,
++ crtc_info->requested_pixel_clock,
++ crtc_info->calculated_pixel_clock,
++ &clock_info);
++
++ /* On TN/SI, Program DTO source select and DTO select before
++ programming DTO modulo and DTO phase. These bits must be
++ programmed first, otherwise there will be no HDMI audio at boot
++ up. This is a HW sequence change (different from old ASICs).
++ Caution when changing this programming sequence.
++
++ HDMI enabled, using DTO0
++ program master CRTC for DTO0 */
++ {
++ set_reg_field_value(value,
++ pll_info->dto_source - DTO_SOURCE_ID0,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO0_SOURCE_SEL);
++
++ set_reg_field_value(value,
++ 0,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO_SEL);
++
++ dm_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO_SOURCE, value);
++ }
++
++ /* module */
++ {
++ value = dm_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_MODULE);
++ set_reg_field_value(value,
++ clock_info.audio_dto_module,
++ DCCG_AUDIO_DTO0_MODULE,
++ DCCG_AUDIO_DTO0_MODULE);
++ dm_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_MODULE, value);
++ }
++
++ /* phase */
++ {
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_PHASE);
++ set_reg_field_value(value,
++ clock_info.audio_dto_phase,
++ DCCG_AUDIO_DTO0_PHASE,
++ DCCG_AUDIO_DTO0_PHASE);
++
++ dm_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_PHASE, value);
++ }
++
++ } else {
++ /*DTO1 Programming goal:
++ -generate 24MHz, 512*Fs, 128*Fs from 24MHz
++ -default is to used DTO1, and switch to DTO0 when an audio
++ master HDMI port is connected
++ -use as default for DP
++
++ calculate DTO settings */
++ get_azalia_clock_info_dp(
++ hw_ctx,
++ crtc_info->requested_pixel_clock,
++ pll_info,
++ &clock_info);
++
++ /* Program DTO select before programming DTO modulo and DTO
++ phase. default to use DTO1 */
++
++ {
++ set_reg_field_value(value, 1,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO_SEL);
++ /*dal_write_reg(mmDCCG_AUDIO_DTO_SOURCE, value)*/
++
++ /* Select 512fs for DP TODO: web register definition
++ does not match register header file
++ set_reg_field_value(value, 1,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO2_USE_512FBR_DTO);
++ */
++
++ dm_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO_SOURCE, value);
++ }
++
++ /* module */
++ {
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_MODULE);
++
++ set_reg_field_value(value,
++ clock_info.audio_dto_module,
++ DCCG_AUDIO_DTO1_MODULE,
++ DCCG_AUDIO_DTO1_MODULE);
++
++ dm_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_MODULE, value);
++ }
++
++ /* phase */
++ {
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_PHASE);
++
++ set_reg_field_value(value,
++ clock_info.audio_dto_phase,
++ DCCG_AUDIO_DTO1_PHASE,
++ DCCG_AUDIO_DTO1_PHASE);
++
++ dm_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_PHASE, value);
++ }
++
++ /* DAL2 code separate DCCG_AUDIO_DTO_SEL and
++ DCCG_AUDIO_DTO2_USE_512FBR_DTO programming into two different
++ location. merge together should not hurt */
++ /*value.bits.DCCG_AUDIO_DTO2_USE_512FBR_DTO = 1;
++ dal_write_reg(mmDCCG_AUDIO_DTO_SOURCE, value);*/
++ }
++}
++
++/* setup HDMI audio */
++static void setup_hdmi_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ const struct audio_crtc_info *crtc_info)
++{
++ struct audio_clock_info audio_clock_info = {0};
++ uint32_t max_packets_per_line;
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* For now still do calculation, although this field is ignored when
++ above HDMI_PACKET_GEN_VERSION set to 1 */
++ max_packets_per_line =
++ dal_audio_hw_ctx_calc_max_audio_packets_per_line(
++ hw_ctx,
++ crtc_info);
++
++ /* HDMI_AUDIO_PACKET_CONTROL */
++ {
++ addr =
++ mmHDMI_AUDIO_PACKET_CONTROL + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, max_packets_per_line,
++ HDMI_AUDIO_PACKET_CONTROL,
++ HDMI_AUDIO_PACKETS_PER_LINE);
++ /* still apply RS600's default setting which is 1. */
++ set_reg_field_value(value, 1,
++ HDMI_AUDIO_PACKET_CONTROL,
++ HDMI_AUDIO_DELAY_EN);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_AUDIO_PACKET_CONTROL */
++ {
++ addr = mmAFMT_AUDIO_PACKET_CONTROL + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 1,
++ AFMT_AUDIO_PACKET_CONTROL,
++ AFMT_60958_CS_UPDATE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_AUDIO_PACKET_CONTROL2 */
++ {
++ addr = mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_AUDIO_LAYOUT_OVRD);
++
++ /*Register field changed.*/
++ set_reg_field_value(value, 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_60958_OSF_OVRD);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_PACKET_CONTROL */
++ {
++ addr = mmHDMI_ACR_PACKET_CONTROL + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 1,
++ HDMI_ACR_PACKET_CONTROL,
++ HDMI_ACR_AUTO_SEND);
++
++ /* Set HDMI_ACR_SOURCE to 0, to use hardwre
++ * computed CTS values.*/
++ set_reg_field_value(value, 0,
++ HDMI_ACR_PACKET_CONTROL,
++ HDMI_ACR_SOURCE);
++
++ /* For now clear HDMI_ACR_AUDIO_PRIORITY =>ACR packet has
++ higher priority over Audio Sample */
++ set_reg_field_value(value, 0,
++ HDMI_ACR_PACKET_CONTROL,
++ HDMI_ACR_AUDIO_PRIORITY);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Program audio clock sample/regeneration parameters */
++ if (dal_audio_hw_ctx_get_audio_clock_info(
++ hw_ctx,
++ crtc_info->color_depth,
++ crtc_info->requested_pixel_clock,
++ crtc_info->calculated_pixel_clock,
++ &audio_clock_info)) {
++
++ /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
++ {
++ addr = mmHDMI_ACR_32_0 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, audio_clock_info.cts_32khz,
++ HDMI_ACR_32_0,
++ HDMI_ACR_CTS_32);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
++ {
++ addr = mmHDMI_ACR_32_1 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.n_32khz,
++ HDMI_ACR_32_1,
++ HDMI_ACR_N_32);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
++ {
++ addr = mmHDMI_ACR_44_0 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.cts_44khz,
++ HDMI_ACR_44_0,
++ HDMI_ACR_CTS_44);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
++ {
++ addr = mmHDMI_ACR_44_1 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.n_44khz,
++ HDMI_ACR_44_1,
++ HDMI_ACR_N_44);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
++ {
++ addr = mmHDMI_ACR_48_0 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.cts_48khz,
++ HDMI_ACR_48_0,
++ HDMI_ACR_CTS_48);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
++ {
++ addr = mmHDMI_ACR_48_1 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.n_48khz,
++ HDMI_ACR_48_1,
++ HDMI_ACR_N_48);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Video driver cannot know in advance which sample rate will
++ be used by HD Audio driver
++ HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
++ programmed below in interruppt callback */
++ } /* if */
++
++ /* AFMT_60958_0__AFMT_60958_CS_CHANNEL_NUMBER_L_MASK &
++ AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */
++ {
++ addr = mmAFMT_60958_0 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 1,
++ AFMT_60958_0,
++ AFMT_60958_CS_CHANNEL_NUMBER_L);
++
++ /*HW default */
++ set_reg_field_value(value, 0,
++ AFMT_60958_0,
++ AFMT_60958_CS_CLOCK_ACCURACY);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_60958_1 AFMT_60958_CS_CHALNNEL_NUMBER_R */
++ {
++ addr = mmAFMT_60958_1 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 2,
++ AFMT_60958_1,
++ AFMT_60958_CS_CHANNEL_NUMBER_R);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /*AFMT_60958_2 now keep this settings until
++ * Programming guide comes out*/
++ {
++ addr = mmAFMT_60958_2 + engine_offset[engine_id];
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 3,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_2);
++
++ set_reg_field_value(value, 4,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_3);
++
++ set_reg_field_value(value, 5,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_4);
++
++ set_reg_field_value(value, 6,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_5);
++
++ set_reg_field_value(value, 7,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_6);
++
++ set_reg_field_value(value, 8,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_7);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++}
++
++ /* setup DP audio */
++static void setup_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /* --- DP Audio packet configurations --- */
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* ATP Configuration */
++ {
++ addr = mmDP_SEC_AUD_N + engine_offset[engine_id];
++
++ set_reg_field_value(value,
++ DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT,
++ DP_SEC_AUD_N,
++ DP_SEC_AUD_N);
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Async/auto-calc timestamp mode */
++ {
++ addr = mmDP_SEC_TIMESTAMP +
++ engine_offset[engine_id];
++
++ value = 0;
++
++ set_reg_field_value(value,
++ DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC,
++ DP_SEC_TIMESTAMP,
++ DP_SEC_TIMESTAMP_MODE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* --- The following are the registers
++ * copied from the SetupHDMI --- */
++
++ /* AFMT_AUDIO_PACKET_CONTROL */
++ {
++ addr = mmAFMT_AUDIO_PACKET_CONTROL +
++ engine_offset[engine_id];
++
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value,
++ 1,
++ AFMT_AUDIO_PACKET_CONTROL,
++ AFMT_60958_CS_UPDATE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_AUDIO_PACKET_CONTROL2 */
++ {
++ addr =
++ mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
++
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value,
++ 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_AUDIO_LAYOUT_OVRD);
++
++ set_reg_field_value(value,
++ 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_60958_OSF_OVRD);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_INFOFRAME_CONTROL0 */
++ {
++ addr =
++ mmAFMT_INFOFRAME_CONTROL0 + engine_offset[engine_id];
++
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value,
++ 1,
++ AFMT_INFOFRAME_CONTROL0,
++ AFMT_AUDIO_INFO_UPDATE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */
++ {
++ addr = mmAFMT_60958_0 + engine_offset[engine_id];
++
++ value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value,
++ 0,
++ AFMT_60958_0,
++ AFMT_60958_CS_CLOCK_ACCURACY);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++}
++
++ /* setup VCE audio */
++static void setup_vce_audio(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ struct dc_context *ctx = hw_ctx->ctx;
++
++ NOT_IMPLEMENTED();
++
++ /*TODO:
++ const uint32_t addr = mmDOUT_DCE_VCE_CONTROL;
++ uint32_t value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ addr);
++
++ set_reg_field_value(value,
++ FROM_BASE(hw_ctx)->azalia_stream_id - 1,
++ DOUT_DCE_VCE_CONTROL,
++ DC_VCE_AUDIO_STREAM_SELECT);
++
++ dal_write_reg(hw_ctx->ctx,
++ addr, value);*/
++}
++
++static void enable_afmt_clock(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ bool enable_flag)
++{
++ uint32_t engine_offs = engine_offset[engine_id];
++ uint32_t value;
++ uint32_t count = 0;
++ uint32_t enable = enable_flag ? 1:0;
++
++ /* Enable Audio packets*/
++ value = dm_read_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs);
++
++ /*enable AFMT clock*/
++ set_reg_field_value(value, enable,
++ AFMT_CNTL, AFMT_AUDIO_CLOCK_EN);
++ dm_write_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs, value);
++
++ /*wait for AFMT clock to turn on,
++ * the expectation is that this
++ * should complete in 1-2 reads)
++ */
++ do {
++ /* Wait for 1us between subsequent register reads.*/
++ udelay(1);
++ value = dm_read_reg(hw_ctx->ctx,
++ mmAFMT_CNTL + engine_offs);
++ } while (get_reg_field_value(value,
++ AFMT_CNTL, AFMT_AUDIO_CLOCK_ON) !=
++ enable && count++ < 10);
++}
++
++/* enable Azalia audio */
++static void enable_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ uint32_t value;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
++
++ if (get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ AUDIO_ENABLED) != 1)
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ AUDIO_ENABLED);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ value);
++}
++
++/* disable Azalia audio */
++static void disable_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ uint32_t value;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
++
++ set_reg_field_value(value, 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ AUDIO_ENABLED);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ value);
++}
++
++/* enable DP audio */
++static void enable_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmDP_SEC_CNTL + engine_offset[engine_id];
++
++ uint32_t value;
++
++ /* Enable Audio packets */
++ value = dm_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_ASP_ENABLE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++
++ /* Program the ATP and AIP next */
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_ATP_ENABLE);
++
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_AIP_ENABLE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++
++ /* Program STREAM_ENABLE after all the other enables. */
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++}
++
++/* disable DP audio */
++static void disable_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmDP_SEC_CNTL + engine_offset[engine_id];
++
++ uint32_t value;
++
++ /* Disable Audio packets */
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_ASP_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_ATP_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_AIP_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_ACM_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ /* This register shared with encoder info frame. Therefore we need to
++ keep master enabled if at least on of the fields is not 0 */
++ if (value != 0)
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++}
++
++static void configure_azalia(
++ const struct hw_ctx_audio *hw_ctx,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_info *audio_info)
++{
++ uint32_t speakers = audio_info->flags.info.ALLSPEAKERS;
++ uint32_t value;
++ uint32_t field = 0;
++ enum audio_format_code audio_format_code;
++ uint32_t format_index;
++ uint32_t index;
++ bool is_ac3_supported = false;
++ bool is_audio_format_supported = false;
++ union audio_sample_rates sample_rate;
++ uint32_t strlen = 0;
++
++ /* Speaker Allocation */
++ /*
++ uint32_t value;
++ uint32_t field = 0;*/
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
++
++ set_reg_field_value(value,
++ speakers,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ SPEAKER_ALLOCATION);
++
++ /* LFE_PLAYBACK_LEVEL = LFEPBL
++ * LFEPBL = 0 : Unknown or refer to other information
++ * LFEPBL = 1 : 0dB playback
++ * LFEPBL = 2 : +10dB playback
++ * LFE_BL = 3 : Reserved
++ */
++ set_reg_field_value(value,
++ 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ LFE_PLAYBACK_LEVEL);
++
++ set_reg_field_value(value,
++ 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ HDMI_CONNECTION);
++
++ set_reg_field_value(value,
++ 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ DP_CONNECTION);
++
++ field = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++
++ field &= ~0x1;
++
++ set_reg_field_value(value,
++ field,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++
++ /* set audio for output signal */
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ set_reg_field_value(value,
++ 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ HDMI_CONNECTION);
++
++ break;
++ case SIGNAL_TYPE_WIRELESS: {
++ /*LSB used for "is wireless" flag */
++ field = 0;
++ field = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++ field |= 0x1;
++ set_reg_field_value(value,
++ field,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++
++ set_reg_field_value(value,
++ 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ HDMI_CONNECTION);
++
++ }
++ break;
++ case SIGNAL_TYPE_EDP:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ set_reg_field_value(value,
++ 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ DP_CONNECTION);
++
++ break;
++ default:
++ break;
++ }
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ value);
++
++ /* Wireless Display identification */
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION);
++
++ set_reg_field_value(value,
++ signal == SIGNAL_TYPE_WIRELESS ? 1 : 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION,
++ WIRELESS_DISPLAY_IDENTIFICATION);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION,
++ value);
++
++ /* Audio Descriptors */
++ /* pass through all formats */
++ for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT;
++ format_index++) {
++ audio_format_code =
++ (AUDIO_FORMAT_CODE_FIRST + format_index);
++
++ /* those are unsupported, skip programming */
++ if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO ||
++ audio_format_code == AUDIO_FORMAT_CODE_DST)
++ continue;
++
++ value = 0;
++
++ /* check if supported */
++ is_audio_format_supported =
++ dal_audio_hw_ctx_is_audio_format_supported(
++ hw_ctx,
++ audio_info,
++ audio_format_code, &index);
++
++ if (is_audio_format_supported) {
++ const struct audio_mode *audio_mode =
++ &audio_info->modes[index];
++ union audio_sample_rates sample_rates =
++ audio_mode->sample_rates;
++ uint8_t byte2 = audio_mode->max_bit_rate;
++
++ /* adjust specific properties */
++ switch (audio_format_code) {
++ case AUDIO_FORMAT_CODE_LINEARPCM: {
++ dal_hw_ctx_audio_check_audio_bandwidth(
++ hw_ctx,
++ crtc_info,
++ audio_mode->channel_count,
++ signal,
++ &sample_rates);
++
++ byte2 = audio_mode->sample_size;
++
++ set_reg_field_value(value,
++ sample_rates.all,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ SUPPORTED_FREQUENCIES_STEREO);
++
++ }
++ break;
++ case AUDIO_FORMAT_CODE_AC3:
++ is_ac3_supported = true;
++ break;
++ case AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS:
++ case AUDIO_FORMAT_CODE_DTS_HD:
++ case AUDIO_FORMAT_CODE_MAT_MLP:
++ case AUDIO_FORMAT_CODE_DST:
++ case AUDIO_FORMAT_CODE_WMAPRO:
++ byte2 = audio_mode->vendor_specific;
++ break;
++ default:
++ break;
++ }
++
++ /* fill audio format data */
++ set_reg_field_value(value,
++ audio_mode->channel_count - 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ MAX_CHANNELS);
++
++ set_reg_field_value(value,
++ sample_rates.all,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ SUPPORTED_FREQUENCIES);
++
++ set_reg_field_value(value,
++ byte2,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ DESCRIPTOR_BYTE_2);
++
++ } /* if */
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 +
++ format_index,
++ value);
++ } /* for */
++
++ if (is_ac3_supported)
++ dm_write_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS,
++ 0x05);
++
++ /* check for 192khz/8-Ch support for HBR requirements */
++ sample_rate.all = 0;
++ sample_rate.rate.RATE_192 = 1;
++ dal_hw_ctx_audio_check_audio_bandwidth(
++ hw_ctx,
++ crtc_info,
++ 8,
++ signal,
++ &sample_rate);
++
++ set_high_bit_rate_capable(hw_ctx, sample_rate.rate.RATE_192);
++
++ /* Audio and Video Lipsync */
++ set_video_latency(hw_ctx, audio_info->video_latency);
++ set_audio_latency(hw_ctx, audio_info->audio_latency);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->manufacture_id,
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
++ MANUFACTURER_ID);
++
++ set_reg_field_value(value, audio_info->product_id,
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
++ PRODUCT_ID);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
++ value);
++
++ value = 0;
++
++ /*get display name string length */
++ while (audio_info->display_name[strlen++] != '\0') {
++ if (strlen >=
++ MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS)
++ break;
++ }
++ set_reg_field_value(value, strlen,
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
++ SINK_DESCRIPTION_LEN);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
++ value);
++
++ /*
++ *write the port ID:
++ *PORT_ID0 = display index
++ *PORT_ID1 = 16bit BDF
++ *(format MSB->LSB: 8bit Bus, 5bit Device, 3bit Function)
++ */
++
++ value = 0;
++
++ set_reg_field_value(value, audio_info->port_id[0],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
++ PORT_ID0);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->port_id[1],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
++ PORT_ID1);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
++ value);
++
++ /*write the 18 char monitor string */
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[0],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION0);
++
++ set_reg_field_value(value, audio_info->display_name[1],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION1);
++
++ set_reg_field_value(value, audio_info->display_name[2],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION2);
++
++ set_reg_field_value(value, audio_info->display_name[3],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION3);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[4],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION4);
++
++ set_reg_field_value(value, audio_info->display_name[5],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION5);
++
++ set_reg_field_value(value, audio_info->display_name[6],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION6);
++
++ set_reg_field_value(value, audio_info->display_name[7],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION7);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[8],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION8);
++
++ set_reg_field_value(value, audio_info->display_name[9],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION9);
++
++ set_reg_field_value(value, audio_info->display_name[10],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION10);
++
++ set_reg_field_value(value, audio_info->display_name[11],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION11);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[12],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION12);
++
++ set_reg_field_value(value, audio_info->display_name[13],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION13);
++
++ set_reg_field_value(value, audio_info->display_name[14],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION14);
++
++ set_reg_field_value(value, audio_info->display_name[15],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION15);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[16],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
++ DESCRIPTION16);
++
++ set_reg_field_value(value, audio_info->display_name[17],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
++ DESCRIPTION17);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
++ value);
++
++}
++
++/* setup Azalia HW block */
++static void setup_azalia(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info,
++ const struct audio_info *audio_info)
++{
++ uint32_t speakers = 0;
++ uint32_t channels = 0;
++
++ if (audio_info == NULL)
++ /* This should not happen.it does so we don't get BSOD*/
++ return;
++
++ speakers = audio_info->flags.info.ALLSPEAKERS;
++ channels = dal_audio_hw_ctx_speakers_to_channels(
++ hw_ctx,
++ audio_info->flags.speaker_flags).all;
++
++ /* setup the audio stream source select (audio -> dig mapping) */
++ {
++ const uint32_t addr =
++ mmAFMT_AUDIO_SRC_CONTROL + engine_offset[engine_id];
++
++ uint32_t value = 0;
++ /*convert one-based index to zero-based */
++ set_reg_field_value(value,
++ FROM_BASE(hw_ctx)->azalia_stream_id - 1,
++ AFMT_AUDIO_SRC_CONTROL,
++ AFMT_AUDIO_SRC_SELECT);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Channel allocation */
++ {
++ const uint32_t addr =
++ mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
++ uint32_t value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value,
++ channels,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_AUDIO_CHANNEL_ENABLE);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ configure_azalia(hw_ctx, signal, crtc_info, audio_info);
++}
++
++/* unmute audio */
++static void unmute_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmAFMT_AUDIO_PACKET_CONTROL +
++ engine_offset[engine_id];
++
++ uint32_t value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 1,
++ AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++}
++
++/* mute audio */
++static void mute_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmAFMT_AUDIO_PACKET_CONTROL +
++ engine_offset[engine_id];
++
++ uint32_t value = 0;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++}
++
++/* enable channel splitting mapping */
++static void setup_channel_splitting_mapping(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ uint32_t value = 0;
++
++ if ((audio_mapping == NULL || audio_mapping->u32all == 0) && enable)
++ return;
++
++ value = audio_mapping->u32all;
++
++ if (enable == false)
++ /*0xFFFFFFFF;*/
++ value = MULTI_CHANNEL_SPLIT_NO_ASSO_INFO;
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO,
++ value);
++}
++
++/* get current channel spliting */
++static bool get_channel_splitting_mapping(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ uint32_t value = 0;
++
++ if (audio_mapping == NULL)
++ return false;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO);
++
++ /*0xFFFFFFFF*/
++ if (get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_ASSOCIATION_INFO,
++ ASSOCIATION_INFO) !=
++ MULTI_CHANNEL_SPLIT_NO_ASSO_INFO) {
++ uint32_t multi_channel01_enable = 0;
++ uint32_t multi_channel23_enable = 0;
++ uint32_t multi_channel45_enable = 0;
++ uint32_t multi_channel67_enable = 0;
++ /* get the one we set.*/
++ audio_mapping->u32all = value;
++
++ /* check each enable status*/
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE);
++
++ multi_channel01_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL01_ENABLE);
++
++ multi_channel23_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL23_ENABLE);
++
++ multi_channel45_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL45_ENABLE);
++
++ multi_channel67_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL67_ENABLE);
++
++ if (multi_channel01_enable == 0 &&
++ multi_channel23_enable == 0 &&
++ multi_channel45_enable == 0 &&
++ multi_channel67_enable == 0)
++ dal_logger_write(hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Audio driver did not enable multi-channel\n");
++
++ return true;
++ }
++
++ return false;
++}
++
++/* set the payload value for the unsolicited response */
++static void set_unsolicited_response_payload(
++ const struct hw_ctx_audio *hw_ctx,
++ enum audio_payload payload)
++{
++ /* set the payload value for the unsolicited response
++ Jack presence is not required to be enabled */
++ uint32_t value = 0;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE);
++
++ set_reg_field_value(value, payload,
++ AZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
++ UNSOLICITED_RESPONSE_PAYLOAD);
++
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
++ UNSOLICITED_RESPONSE_FORCE);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
++ value);
++}
++
++/* initialize HW state */
++static void hw_initialize(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ uint32_t stream_id = FROM_BASE(hw_ctx)->azalia_stream_id;
++ uint32_t addr;
++
++ /* we only need to program the following registers once, so we only do
++ it for the first audio stream.*/
++ if (stream_id != FIRST_AUDIO_STREAM_ID)
++ return;
++
++ /* Suport R5 - 32khz
++ * Suport R6 - 44.1khz
++ * Suport R7 - 48khz
++ */
++ addr = mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES;
++ {
++ uint32_t value;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0x70,
++ AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
++ AUDIO_RATE_CAPABILITIES);
++
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /*Keep alive bit to verify HW block in BU. */
++ addr = mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES;
++ {
++ uint32_t value;
++
++ value = dm_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
++ CLKSTOP);
++
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
++ EPSS);
++ dm_write_reg(hw_ctx->ctx, addr, value);
++ }
++}
++
++/* Assign GTC group and enable GTC value embedding */
++static void enable_gtc_embedding_with_group(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t group_num,
++ uint32_t audio_latency)
++{
++ /*need to replace the static number with variable */
++ if (group_num <= 6) {
++ uint32_t value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING);
++
++ set_reg_field_value(
++ value,
++ group_num,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_GROUP);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_ENABLE);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ value);
++
++ /*update audio latency to LIPSYNC*/
++ set_audio_latency(hw_ctx, audio_latency);
++ } else {
++ dal_logger_write(
++ hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "GTC group number %d is too big",
++ group_num);
++ }
++}
++
++ /* Disable GTC value embedding */
++static void disable_gtc_embedding(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ uint32_t value = 0;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING);
++
++ set_reg_field_value(value, 0,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_ENABLE);
++
++ set_reg_field_value(value, 0,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_GROUP);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ value);
++}
++
++/* search pixel clock value for Azalia HDMI Audio */
++static bool get_azalia_clock_info_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct azalia_clock_info *azalia_clock_info)
++{
++ if (azalia_clock_info == NULL)
++ return false;
++
++ /* audio_dto_phase= 24 * 10,000;
++ * 24MHz in [100Hz] units */
++ azalia_clock_info->audio_dto_phase =
++ 24 * 10000;
++
++ /* audio_dto_module = PCLKFrequency * 10,000;
++ * [khz] -> [100Hz] */
++ azalia_clock_info->audio_dto_module =
++ actual_pixel_clock_in_khz * 10;
++
++ return true;
++}
++
++/* search pixel clock value for Azalia DP Audio */
++static bool get_azalia_clock_info_dp(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t requested_pixel_clock_in_khz,
++ const struct audio_pll_info *pll_info,
++ struct azalia_clock_info *azalia_clock_info)
++{
++ if (pll_info == NULL || azalia_clock_info == NULL)
++ return false;
++
++ /* Reported dpDtoSourceClockInkhz value for
++ * DCE8 already adjusted for SS, do not need any
++ * adjustment here anymore
++ */
++
++ /*audio_dto_phase = 24 * 10,000;
++ * 24MHz in [100Hz] units */
++ azalia_clock_info->audio_dto_phase = 24 * 10000;
++
++ /*audio_dto_module = dpDtoSourceClockInkhz * 10,000;
++ * [khz] ->[100Hz] */
++ azalia_clock_info->audio_dto_module =
++ pll_info->dp_dto_source_clock_in_khz * 10;
++
++ return true;
++}
++
++static const struct hw_ctx_audio_funcs funcs = {
++ .destroy = destroy,
++ .setup_audio_wall_dto =
++ setup_audio_wall_dto,
++ .setup_hdmi_audio =
++ setup_hdmi_audio,
++ .setup_dp_audio = setup_dp_audio,
++ .setup_vce_audio = setup_vce_audio,
++ .enable_azalia_audio =
++ enable_azalia_audio,
++ .disable_azalia_audio =
++ disable_azalia_audio,
++ .enable_dp_audio =
++ enable_dp_audio,
++ .disable_dp_audio =
++ disable_dp_audio,
++ .setup_azalia =
++ setup_azalia,
++ .disable_az_clock_gating = NULL,
++ .unmute_azalia_audio =
++ unmute_azalia_audio,
++ .mute_azalia_audio =
++ mute_azalia_audio,
++ .setup_channel_splitting_mapping =
++ setup_channel_splitting_mapping,
++ .get_channel_splitting_mapping =
++ get_channel_splitting_mapping,
++ .set_unsolicited_response_payload =
++ set_unsolicited_response_payload,
++ .hw_initialize =
++ hw_initialize,
++ .enable_gtc_embedding_with_group =
++ enable_gtc_embedding_with_group,
++ .disable_gtc_embedding =
++ disable_gtc_embedding,
++ .get_azalia_clock_info_hdmi =
++ get_azalia_clock_info_hdmi,
++ .get_azalia_clock_info_dp =
++ get_azalia_clock_info_dp,
++ .enable_afmt_clock = enable_afmt_clock
++};
++
++static bool construct(
++ struct hw_ctx_audio_dce112 *hw_ctx,
++ uint8_t azalia_stream_id,
++ struct dc_context *ctx)
++{
++ struct hw_ctx_audio *base = &hw_ctx->base;
++
++ if (!dal_audio_construct_hw_ctx_audio(base))
++ return false;
++
++ base->funcs = &funcs;
++
++ /* save audio endpoint or dig front for current dce112 audio object */
++ hw_ctx->azalia_stream_id = azalia_stream_id;
++ hw_ctx->base.ctx = ctx;
++
++ /* azalia audio endpoints register offsets. azalia is associated with
++ DIG front. save AUDIO register offset */
++ switch (azalia_stream_id) {
++ case 1: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ case 2: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ case 3: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ case 4: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ default:
++ dal_logger_write(
++ hw_ctx->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Invalid Azalia stream ID!");
++ break;
++ }
++
++ return true;
++}
++
++/* audio_dce112 is derived from audio directly, not via dce80 */
++struct hw_ctx_audio *dal_hw_ctx_audio_dce112_create(
++ struct dc_context *ctx,
++ uint32_t azalia_stream_id)
++{
++ /* allocate memory for struc hw_ctx_audio_dce112 */
++ struct hw_ctx_audio_dce112 *hw_ctx_dce112 =
++ dm_alloc(sizeof(struct hw_ctx_audio_dce112));
++
++ if (!hw_ctx_dce112) {
++ ASSERT_CRITICAL(hw_ctx_dce112);
++ return NULL;
++ }
++
++ /*return pointer to hw_ctx_audio back to caller -- audio object */
++ if (construct(
++ hw_ctx_dce112, azalia_stream_id, ctx))
++ return &hw_ctx_dce112->base;
++
++ dal_logger_write(
++ ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Failed to create hw_ctx_audio for DCE11\n");
++
++ dm_free(hw_ctx_dce112);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h
+new file mode 100644
+index 0000000..af61aad
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce112/hw_ctx_audio_dce112.h
+@@ -0,0 +1,47 @@
++/*
++ * 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_HW_CTX_AUDIO_DCE112_H__
++#define __DAL_HW_CTX_AUDIO_DCE112_H__
++
++#include "audio/hw_ctx_audio.h"
++
++struct hw_ctx_audio_dce112 {
++ struct hw_ctx_audio base;
++
++ /* azalia stream id 1 based indexing, corresponding to audio GO enumId*/
++ uint32_t azalia_stream_id;
++
++ /* azalia stream endpoint register offsets */
++ struct azalia_reg_offsets az_mm_reg_offsets;
++
++ /* audio encoder block MM register offset -- associate with DIG FRONT */
++};
++
++struct hw_ctx_audio *dal_hw_ctx_audio_dce112_create(
++ struct dc_context *ctx,
++ uint32_t azalia_stream_id);
++
++#endif /* __DAL_HW_CTX_AUDIO_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/Makefile b/drivers/gpu/drm/amd/dal/dc/bios/Makefile
+index e5c8876..9c90230 100644
+--- a/drivers/gpu/drm/amd/dal/dc/bios/Makefile
++++ b/drivers/gpu/drm/amd/dal/dc/bios/Makefile
+@@ -37,3 +37,12 @@ endif
+
+ AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce110/command_table_helper_dce110.o
+ endif
++
++ifdef CONFIG_DRM_AMD_DAL_DCE11_2
++ccflags-y += -DLATEST_ATOM_BIOS_SUPPORT
++ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce112/bios_parser_helper_dce112.o
++endif
++
++AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce112/command_table_helper_dce112.o
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
+index 4e2bc90..4204798 100644
+--- a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
++++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
+@@ -55,6 +55,12 @@ bool dal_bios_parser_init_bios_helper(
+ return true;
+
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ bp->bios_helper = dal_bios_parser_helper_dce112_get_table();
++ return true;
++
++#endif
+ default:
+ BREAK_TO_DEBUGGER();
+ return false;
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
+index c58b9bb..b93b046 100644
+--- a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
++++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
+@@ -34,6 +34,10 @@
+ #include "dce110/bios_parser_helper_dce110.h"
+ #endif
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "dce112/bios_parser_helper_dce112.h"
++#endif
++
+ struct bios_parser;
+
+ struct vbios_helper_data {
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table.c b/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
+index ccd1c7e..22524b3 100644
+--- a/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
+@@ -104,6 +104,13 @@ static enum bp_result encoder_control_digx_v3(
+ static enum bp_result encoder_control_digx_v4(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
++
++#ifdef LATEST_ATOM_BIOS_SUPPORT
++static enum bp_result encoder_control_digx_v5(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++#endif
++
+ static void init_encoder_control_dig_v1(struct bios_parser *bp);
+
+ static void init_dig_encoder_control(struct bios_parser *bp)
+@@ -112,12 +119,19 @@ static void init_dig_encoder_control(struct bios_parser *bp)
+ BIOS_CMD_TABLE_PARA_REVISION(DIGxEncoderControl);
+
+ switch (version) {
++ case 2:
++ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3;
++ break;
+ case 4:
+ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v4;
+ break;
+- case 2:
+- bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3;
++
++#ifdef LATEST_ATOM_BIOS_SUPPORT
++ case 5:
++ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v5;
+ break;
++#endif
++
+ default:
+ init_encoder_control_dig_v1(bp);
+ break;
+@@ -302,6 +316,66 @@ static enum bp_result encoder_control_digx_v4(
+ return result;
+ }
+
++#ifdef LATEST_ATOM_BIOS_SUPPORT
++static enum bp_result encoder_control_digx_v5(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ ENCODER_STREAM_SETUP_PARAMETERS_V5 params = {0};
++
++ params.ucDigId = (uint8_t)(cntl->engine_id);
++ params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
++
++ params.ulPixelClock = cntl->pixel_clock / 10;
++ params.ucDigMode =
++ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
++ cntl->signal,
++ cntl->enable_dp_audio));
++ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
++
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_888:
++ params.ucBitPerColor = PANEL_8BIT_PER_COLOR;
++ break;
++ case COLOR_DEPTH_101010:
++ params.ucBitPerColor = PANEL_10BIT_PER_COLOR;
++ break;
++ case COLOR_DEPTH_121212:
++ params.ucBitPerColor = PANEL_12BIT_PER_COLOR;
++ break;
++ case COLOR_DEPTH_161616:
++ params.ucBitPerColor = PANEL_16BIT_PER_COLOR;
++ break;
++ default:
++ break;
++ }
++
++ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_101010:
++ params.ulPixelClock =
++ (params.ulPixelClock * 30) / 24;
++ break;
++ case COLOR_DEPTH_121212:
++ params.ulPixelClock =
++ (params.ulPixelClock * 36) / 24;
++ break;
++ case COLOR_DEPTH_161616:
++ params.ulPixelClock =
++ (params.ulPixelClock * 48) / 24;
++ break;
++ default:
++ break;
++ }
++
++ if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++#endif
++
+ /*******************************************************************************
+ ********************************************************************************
+ **
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
+index 85a5924..a27db8c 100644
+--- a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
+@@ -55,6 +55,12 @@ bool dal_bios_parser_init_cmd_tbl_helper(
+ return true;
+ #endif
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ *h = dal_cmd_tbl_helper_dce112_get_table();
++ return true;
++#endif
++
+ default:
+ /* Unsupported DCE */
+ BREAK_TO_DEBUGGER();
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
+index a462917..e6a0d19 100644
+--- a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
+@@ -32,6 +32,9 @@
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) || defined(CONFIG_DRM_AMD_DAL_DCE10_0)
+ #include "dce110/command_table_helper_dce110.h"
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "dce112/command_table_helper_dce112.h"
++#endif
+
+ struct command_table_helper {
+ bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id);
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c
+new file mode 100644
+index 0000000..1b0f816
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.c
+@@ -0,0 +1,480 @@
++/*
++ * 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, sub license,
++ * 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 "atom.h"
++
++#include "include/bios_parser_types.h"
++#include "include/adapter_service_types.h"
++#include "include/logger_interface.h"
++
++#include "../bios_parser_helper.h"
++
++#include "dce/dce_11_0_d.h"
++#include "bif/bif_5_1_d.h"
++
++/**
++ * set_scratch_acc_mode_change
++ *
++ * @brief
++ * set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when
++ * VGA/non-Accelerated mode is set
++ *
++ * @param
++ * struct dc_context *ctx - [in] DAL context
++ */
++static void set_scratch_acc_mode_change(
++ struct dc_context *ctx)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = 0;
++
++ value = dm_read_reg(ctx, addr);
++
++ value |= ATOM_S6_ACC_MODE;
++
++ dm_write_reg(ctx, addr, value);
++}
++
++/*
++ * set_scratch_active_and_requested
++ *
++ * @brief
++ * Set VBIOS scratch pad registers about active and requested displays
++ *
++ * @param
++ * struct dc_context *ctx - [in] DAL context for register accessing
++ * struct vbios_helper_data *d - [in] values to write
++ */
++static void set_scratch_active_and_requested(
++ struct dc_context *ctx,
++ struct vbios_helper_data *d)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* mmBIOS_SCRATCH_3 = mmBIOS_SCRATCH_0 + ATOM_ACTIVE_INFO_DEF */
++ addr = mmBIOS_SCRATCH_3;
++
++ value = dm_read_reg(ctx, addr);
++
++ value &= ~ATOM_S3_DEVICE_ACTIVE_MASK;
++ value |= (d->active & ATOM_S3_DEVICE_ACTIVE_MASK);
++
++ dm_write_reg(ctx, addr, value);
++
++ /* mmBIOS_SCRATCH_6 = mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF */
++ addr = mmBIOS_SCRATCH_6;
++
++ value = dm_read_reg(ctx, addr);
++
++ value &= ~ATOM_S6_ACC_REQ_MASK;
++ value |= (d->requested & ATOM_S6_ACC_REQ_MASK);
++
++ dm_write_reg(ctx, addr, value);
++
++ /* mmBIOS_SCRATCH_5 = mmBIOS_SCRATCH_0 + ATOM_DOS_REQ_INFO_DEF */
++ addr = mmBIOS_SCRATCH_5;
++
++ value = dm_read_reg(ctx, addr);
++
++ value &= ~ATOM_S5_DOS_REQ_DEVICEw0;
++ value |= (d->active & ATOM_S5_DOS_REQ_DEVICEw0);
++
++ dm_write_reg(ctx, addr, value);
++
++ d->active = 0;
++ d->requested = 0;
++}
++
++/**
++ * get LCD Scale Mode from VBIOS scratch register
++ */
++static enum lcd_scale get_scratch_lcd_scale(
++ struct dc_context *ctx)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = 0;
++
++ value = dm_read_reg(ctx, addr);
++
++ if (value & ATOM_S6_REQ_LCD_EXPANSION_FULL)
++ return LCD_SCALE_FULLPANEL;
++ else if (value & ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO)
++ return LCD_SCALE_ASPECTRATIO;
++ else
++ return LCD_SCALE_NONE;
++}
++
++/**
++ * prepare_scratch_active_and_requested
++ *
++ * @brief
++ * prepare and update VBIOS scratch pad registers about active and requested
++ * displays
++ *
++ * @param
++ * data - helper's shared data
++ * enum controller_ild - controller Id
++ * enum signal_type - signal type used on display
++ * const struct connector_device_tag_info* - pointer to display type and enum id
++ */
++static void prepare_scratch_active_and_requested(
++ struct dc_context *ctx,
++ struct vbios_helper_data *data,
++ enum controller_id id,
++ enum signal_type s,
++ const struct connector_device_tag_info *dev_tag)
++{
++ switch (s) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ if (dev_tag->dev_id.device_type == DEVICE_TYPE_DFP)
++ switch (dev_tag->dev_id.enum_id) {
++ case 1:
++ data->requested |= ATOM_S6_ACC_REQ_DFP1;
++ data->active |= ATOM_S3_DFP1_ACTIVE;
++ break;
++ case 2:
++ data->requested |= ATOM_S6_ACC_REQ_DFP2;
++ data->active |= ATOM_S3_DFP2_ACTIVE;
++ break;
++ case 3:
++ data->requested |= ATOM_S6_ACC_REQ_DFP3;
++ data->active |= ATOM_S3_DFP3_ACTIVE;
++ break;
++ case 4:
++ data->requested |= ATOM_S6_ACC_REQ_DFP4;
++ data->active |= ATOM_S3_DFP4_ACTIVE;
++ break;
++ case 5:
++ data->requested |= ATOM_S6_ACC_REQ_DFP5;
++ data->active |= ATOM_S3_DFP5_ACTIVE;
++ break;
++ case 6:
++ data->requested |= ATOM_S6_ACC_REQ_DFP6;
++ data->active |= ATOM_S3_DFP6_ACTIVE;
++ break;
++ default:
++ break;
++ }
++ break;
++ case SIGNAL_TYPE_LVDS:
++ case SIGNAL_TYPE_EDP:
++ data->requested |= ATOM_S6_ACC_REQ_LCD1;
++ data->active |= ATOM_S3_LCD1_ACTIVE;
++ break;
++ case SIGNAL_TYPE_RGB:
++ if (dev_tag->dev_id.device_type == DEVICE_TYPE_CRT)
++ switch (dev_tag->dev_id.enum_id) {
++ case 1:
++ data->requested |= ATOM_S6_ACC_REQ_CRT1;
++ data->active |= ATOM_S3_CRT1_ACTIVE;
++ break;
++ case 2:
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_COMPONENT_BIOS,
++ "%s: DAL does not support DAC2!\n",
++ __func__);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_COMPONENT_BIOS,
++ "%s: No such signal!\n",
++ __func__);
++ break;
++ }
++}
++
++/*
++ * is_accelerated_mode
++ *
++ * @brief
++ * set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when
++ * VGA/non-Accelerated mode is set
++ *
++ * @param
++ * struct dc_context *ctx
++ *
++ * @return
++ * true if in acceleration mode, false otherwise.
++ */
++static bool is_accelerated_mode(
++ struct dc_context *ctx)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = dm_read_reg(ctx, addr);
++
++ return (value & ATOM_S6_ACC_MODE) ? true : false;
++}
++
++#define BIOS_SCRATCH0_DAC_B_SHIFT 8
++
++/**
++ * detect_sink
++ *
++ * @brief
++ * read VBIOS scratch register to determine whether display for the specified
++ * signal is present and return the actual sink signal type
++ * For analog signals VBIOS load detection has to be called prior reading the
++ * register
++ *
++ * @param
++ * encoder - encoder id (to specify DAC)
++ * connector - connector id (to check CV on DIN)
++ * signal - signal (as display type) to check
++ *
++ * @return
++ * signal_type - actual (on the sink) signal type detected
++ */
++static enum signal_type detect_sink(
++ struct dc_context *ctx,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type signal)
++{
++ uint32_t bios_scratch0;
++ uint32_t encoder_id = encoder.id;
++ /* after DCE 10.x does not support DAC2, so assert and return SIGNAL_TYPE_NONE */
++ if (encoder_id == ENCODER_ID_INTERNAL_DAC2
++ || encoder_id == ENCODER_ID_INTERNAL_KLDSCP_DAC2) {
++ ASSERT(false);
++ return SIGNAL_TYPE_NONE;
++ }
++
++ bios_scratch0 = dm_read_reg(ctx,
++ mmBIOS_SCRATCH_0 + ATOM_DEVICE_CONNECT_INFO_DEF);
++
++ /* In further processing we use DACB masks. If we want detect load on
++ * DACA, we need to shift the register so DACA bits will be in place of
++ * DACB bits
++ */
++ if (encoder_id == ENCODER_ID_INTERNAL_DAC1
++ || encoder_id == ENCODER_ID_INTERNAL_KLDSCP_DAC1
++ || encoder_id == ENCODER_ID_EXTERNAL_NUTMEG
++ || encoder_id == ENCODER_ID_EXTERNAL_TRAVIS) {
++ bios_scratch0 <<= BIOS_SCRATCH0_DAC_B_SHIFT;
++ }
++
++ switch (signal) {
++ case SIGNAL_TYPE_RGB: {
++ if (bios_scratch0 & ATOM_S0_CRT2_MASK)
++ return SIGNAL_TYPE_RGB;
++ break;
++ }
++ case SIGNAL_TYPE_LVDS: {
++ if (bios_scratch0 & ATOM_S0_LCD1)
++ return SIGNAL_TYPE_LVDS;
++ break;
++ }
++ case SIGNAL_TYPE_EDP: {
++ if (bios_scratch0 & ATOM_S0_LCD1)
++ return SIGNAL_TYPE_EDP;
++ break;
++ }
++ default:
++ break;
++ }
++
++ return SIGNAL_TYPE_NONE;
++}
++
++/**
++ * set_scratch_connected
++ *
++ * @brief
++ * update BIOS_SCRATCH_0 register about connected displays
++ *
++ * @param
++ * bool - update scratch register or just prepare info to be updated
++ * bool - connection state
++ * const struct connector_device_tag_info * - pointer to device type and enum ID
++ */
++static void set_scratch_connected(
++ struct dc_context *ctx,
++ struct graphics_object_id id,
++ bool connected,
++ const struct connector_device_tag_info *device_tag)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++ uint32_t update = 0;
++
++ switch (device_tag->dev_id.device_type) {
++ case DEVICE_TYPE_LCD:
++ /* For LCD VBIOS will update LCD Panel connected bit always and
++ * Lid state bit based on SBIOS info do not do anything here
++ * for LCD
++ */
++ break;
++ case DEVICE_TYPE_CRT:
++ /* CRT is not supported in DCE11 */
++ break;
++ case DEVICE_TYPE_DFP:
++ switch (device_tag->dev_id.enum_id) {
++ case 1:
++ update |= ATOM_S0_DFP1;
++ break;
++ case 2:
++ update |= ATOM_S0_DFP2;
++ break;
++ case 3:
++ update |= ATOM_S0_DFP3;
++ break;
++ case 4:
++ update |= ATOM_S0_DFP4;
++ break;
++ case 5:
++ update |= ATOM_S0_DFP5;
++ break;
++ case 6:
++ update |= ATOM_S0_DFP6;
++ break;
++ default:
++ break;
++ }
++ break;
++ case DEVICE_TYPE_CV:
++ /* DCE 8.0 does not support CV, so don't do anything */
++ break;
++
++ case DEVICE_TYPE_TV:
++ /* For TV VBIOS will update S-Video or
++ * Composite scratch bits on DAL_LoadDetect
++ * when called by driver, do not do anything
++ * here for TV
++ */
++ break;
++
++ default:
++ break;
++
++ }
++
++ /* update scratch register */
++ addr = mmBIOS_SCRATCH_0 + ATOM_DEVICE_CONNECT_INFO_DEF;
++
++ value = dm_read_reg(ctx, addr);
++
++ if (connected)
++ value |= update;
++ else
++ value &= ~update;
++
++ dm_write_reg(ctx, addr, value);
++}
++
++static void set_scratch_critical_state(
++ struct dc_context *ctx,
++ bool state)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = dm_read_reg(ctx, addr);
++
++ if (state)
++ value |= ATOM_S6_CRITICAL_STATE;
++ else
++ value &= ~ATOM_S6_CRITICAL_STATE;
++
++ dm_write_reg(ctx, addr, value);
++}
++
++static void set_scratch_lcd_scale(
++ struct dc_context *ctx,
++ enum lcd_scale lcd_scale_request)
++{
++ DAL_LOGGER_NOT_IMPL(
++ LOG_MINOR_COMPONENT_BIOS,
++ "Bios Parser:%s\n",
++ __func__);
++}
++
++static bool is_lid_open(struct dc_context *ctx)
++{
++ uint32_t bios_scratch6;
++
++ bios_scratch6 =
++ dm_read_reg(
++ ctx,
++ mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF);
++
++ /* lid is open if the bit is not set */
++ if (!(bios_scratch6 & ATOM_S6_LID_STATE))
++ return true;
++
++ return false;
++}
++
++/* function table */
++static const struct bios_parser_helper bios_parser_helper_funcs = {
++ .detect_sink = detect_sink,
++ .fmt_bit_depth_control = NULL,
++ .fmt_control = NULL,
++ .get_bios_event_info = NULL,
++ .get_embedded_display_controller_id = NULL,
++ .get_embedded_display_refresh_rate = NULL,
++ .get_requested_backlight_level = NULL,
++ .get_scratch_lcd_scale = get_scratch_lcd_scale,
++ .is_accelerated_mode = is_accelerated_mode,
++ .is_active_display = NULL,
++ .is_display_config_changed = NULL,
++ .is_lid_open = is_lid_open,
++ .is_lid_status_changed = NULL,
++ .prepare_scratch_active_and_requested =
++ prepare_scratch_active_and_requested,
++ .set_scratch_acc_mode_change = set_scratch_acc_mode_change,
++ .set_scratch_active_and_requested = set_scratch_active_and_requested,
++ .set_scratch_connected = set_scratch_connected,
++ .set_scratch_critical_state = set_scratch_critical_state,
++ .set_scratch_lcd_scale = set_scratch_lcd_scale,
++ .take_backlight_control = NULL,
++ .update_requested_backlight_level = NULL,
++};
++
++/*
++ * dal_bios_parser_dce112_init_bios_helper
++ *
++ * @brief
++ * Initialize BIOS helper functions
++ *
++ * @param
++ * const struct command_table_helper **h - [out] struct of functions
++ *
++ */
++
++const struct bios_parser_helper *dal_bios_parser_helper_dce112_get_table()
++{
++ return &bios_parser_helper_funcs;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h
+new file mode 100644
+index 0000000..044327e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/bios_parser_helper_dce112.h
+@@ -0,0 +1,34 @@
++/*
++ * 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, sub license,
++ * 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_BIOS_PARSER_HELPER_DCE112_H__
++#define __DAL_BIOS_PARSER_HELPER_DCE112_H__
++
++struct bios_parser_helper;
++
++/* Initialize BIOS helper functions */
++const struct bios_parser_helper *dal_bios_parser_helper_dce112_get_table(void);
++
++#endif /* __DAL_BIOS_PARSER_HELPER_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c
+new file mode 100644
+index 0000000..32ec228
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.c
+@@ -0,0 +1,417 @@
++/*
++ * 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 "atom.h"
++
++#include "include/bios_parser_types.h"
++#include "include/adapter_service_types.h"
++
++#include "../command_table_helper.h"
++
++static uint8_t phy_id_to_atom(enum transmitter t)
++{
++ uint8_t atom_phy_id;
++
++ switch (t) {
++ case TRANSMITTER_UNIPHY_A:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYA;
++ break;
++ case TRANSMITTER_UNIPHY_B:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYB;
++ break;
++ case TRANSMITTER_UNIPHY_C:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYC;
++ break;
++ case TRANSMITTER_UNIPHY_D:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYD;
++ break;
++ case TRANSMITTER_UNIPHY_E:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYE;
++ break;
++ case TRANSMITTER_UNIPHY_F:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYF;
++ break;
++ case TRANSMITTER_UNIPHY_G:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYG;
++ break;
++ default:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYA;
++ break;
++ }
++ return atom_phy_id;
++}
++
++static uint8_t signal_type_to_atom_dig_mode(enum signal_type s)
++{
++ uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP;
++
++ switch (s) {
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_EDP:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP;
++ break;
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI;
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_HDMI;
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP_MST;
++ break;
++ default:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI;
++ break;
++ }
++
++ return atom_dig_mode;
++}
++
++static uint8_t clock_source_id_to_atom_phy_clk_src_id(
++ enum clock_source_id id)
++{
++ uint8_t atom_phy_clk_src_id = 0;
++
++ switch (id) {
++ case CLOCK_SOURCE_ID_PLL0:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P0PLL;
++ break;
++ case CLOCK_SOURCE_ID_PLL1:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL;
++ break;
++ case CLOCK_SOURCE_ID_PLL2:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P2PLL;
++ break;
++ case CLOCK_SOURCE_ID_EXTERNAL:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT;
++ break;
++ default:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL;
++ break;
++ }
++
++ return atom_phy_clk_src_id >> 2;
++}
++
++static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
++{
++ uint8_t atom_hpd_sel = 0;
++
++ switch (id) {
++ case HPD_SOURCEID1:
++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD1_SEL;
++ break;
++ case HPD_SOURCEID2:
++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD2_SEL;
++ break;
++ case HPD_SOURCEID3:
++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD3_SEL;
++ break;
++ case HPD_SOURCEID4:
++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD4_SEL;
++ break;
++ case HPD_SOURCEID5:
++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD5_SEL;
++ break;
++ case HPD_SOURCEID6:
++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD6_SEL;
++ break;
++ case HPD_SOURCEID_UNKNOWN:
++ default:
++ atom_hpd_sel = 0;
++ break;
++ }
++ return atom_hpd_sel;
++}
++
++static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
++{
++ uint8_t atom_dig_encoder_sel = 0;
++
++ switch (id) {
++ case ENGINE_ID_DIGA:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL;
++ break;
++ case ENGINE_ID_DIGB:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGB_SEL;
++ break;
++ case ENGINE_ID_DIGC:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGC_SEL;
++ break;
++ case ENGINE_ID_DIGD:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGD_SEL;
++ break;
++ case ENGINE_ID_DIGE:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGE_SEL;
++ break;
++ case ENGINE_ID_DIGF:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGF_SEL;
++ break;
++ case ENGINE_ID_DIGG:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGG_SEL;
++ break;
++ case ENGINE_ID_UNKNOWN:
++ /* No DIG_FRONT is associated to DIG_BACKEND */
++ atom_dig_encoder_sel = 0;
++ break;
++ default:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL;
++ break;
++ }
++
++ return atom_dig_encoder_sel;
++}
++
++static bool clock_source_id_to_atom(
++ enum clock_source_id id,
++ uint32_t *atom_pll_id)
++{
++ bool result = true;
++
++ if (atom_pll_id != NULL)
++ switch (id) {
++ case CLOCK_SOURCE_COMBO_PHY_PLL0:
++ *atom_pll_id = ATOM_COMBOPHY_PLL0;
++ break;
++ case CLOCK_SOURCE_COMBO_PHY_PLL1:
++ *atom_pll_id = ATOM_COMBOPHY_PLL1;
++ break;
++ case CLOCK_SOURCE_COMBO_PHY_PLL2:
++ *atom_pll_id = ATOM_COMBOPHY_PLL2;
++ break;
++ case CLOCK_SOURCE_COMBO_PHY_PLL3:
++ *atom_pll_id = ATOM_COMBOPHY_PLL3;
++ break;
++ case CLOCK_SOURCE_COMBO_PHY_PLL4:
++ *atom_pll_id = ATOM_COMBOPHY_PLL4;
++ break;
++ case CLOCK_SOURCE_COMBO_PHY_PLL5:
++ *atom_pll_id = ATOM_COMBOPHY_PLL5;
++ break;
++ case CLOCK_SOURCE_COMBO_DISPLAY_PLL0:
++ *atom_pll_id = ATOM_PPLL0;
++ break;
++ case CLOCK_SOURCE_ID_DFS:
++ *atom_pll_id = ATOM_GCK_DFS;
++ break;
++ case CLOCK_SOURCE_ID_VCE:
++ *atom_pll_id = ATOM_DP_DTO;
++ break;
++ case CLOCK_SOURCE_ID_DP_DTO:
++ *atom_pll_id = ATOM_DP_DTO;
++ break;
++ case CLOCK_SOURCE_ID_UNDEFINED:
++ /* Should not happen */
++ *atom_pll_id = ATOM_PPLL_INVALID;
++ result = false;
++ break;
++ default:
++ result = false;
++ break;
++ }
++
++ return result;
++}
++
++static bool engine_bp_to_atom(enum engine_id id, uint32_t *atom_engine_id)
++{
++ bool result = false;
++
++ if (atom_engine_id != NULL)
++ switch (id) {
++ case ENGINE_ID_DIGA:
++ *atom_engine_id = ASIC_INT_DIG1_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGB:
++ *atom_engine_id = ASIC_INT_DIG2_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGC:
++ *atom_engine_id = ASIC_INT_DIG3_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGD:
++ *atom_engine_id = ASIC_INT_DIG4_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGE:
++ *atom_engine_id = ASIC_INT_DIG5_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGF:
++ *atom_engine_id = ASIC_INT_DIG6_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGG:
++ *atom_engine_id = ASIC_INT_DIG7_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DACA:
++ *atom_engine_id = ASIC_INT_DAC1_ENCODER_ID;
++ result = true;
++ break;
++ default:
++ break;
++ }
++
++ return result;
++}
++
++static uint8_t encoder_action_to_atom(enum bp_encoder_control_action action)
++{
++ uint8_t atom_action = 0;
++
++ switch (action) {
++ case ENCODER_CONTROL_ENABLE:
++ atom_action = ATOM_ENABLE;
++ break;
++ case ENCODER_CONTROL_DISABLE:
++ atom_action = ATOM_DISABLE;
++ break;
++ case ENCODER_CONTROL_SETUP:
++ atom_action = ATOM_ENCODER_CMD_STREAM_SETUP;
++ break;
++ case ENCODER_CONTROL_INIT:
++ atom_action = ATOM_ENCODER_INIT;
++ break;
++ default:
++ BREAK_TO_DEBUGGER(); /* Unhandle action in driver.!! */
++ break;
++ }
++
++ return atom_action;
++}
++
++static uint8_t disp_power_gating_action_to_atom(
++ enum bp_pipe_control_action action)
++{
++ uint8_t atom_pipe_action = 0;
++
++ switch (action) {
++ case ASIC_PIPE_DISABLE:
++ atom_pipe_action = ATOM_DISABLE;
++ break;
++ case ASIC_PIPE_ENABLE:
++ atom_pipe_action = ATOM_ENABLE;
++ break;
++ case ASIC_PIPE_INIT:
++ atom_pipe_action = ATOM_INIT;
++ break;
++ default:
++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
++ break;
++ }
++
++ return atom_pipe_action;
++}
++
++bool dc_clock_type_to_atom(enum bp_dce_clock_type id, uint32_t *atom_clock_type)
++{
++ bool retCode = true;
++
++ if (atom_clock_type != NULL) {
++ switch (id) {
++ case DCECLOCK_TYPE_DISPLAY_CLOCK:
++ *atom_clock_type = DCE_CLOCK_TYPE_DISPCLK;
++ break;
++
++ case DCECLOCK_TYPE_DPREFCLK:
++ *atom_clock_type = DCE_CLOCK_TYPE_DPREFCLK;
++ break;
++
++ default:
++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
++ break;
++ }
++ }
++
++ return retCode;
++}
++
++uint8_t transmitter_color_depth_to_atom(enum transmitter_color_depth id)
++{
++ uint8_t atomColorDepth = 0;
++
++ switch (id) {
++ case TRANSMITTER_COLOR_DEPTH_24:
++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
++ break;
++ case TRANSMITTER_COLOR_DEPTH_30:
++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
++ break;
++ case TRANSMITTER_COLOR_DEPTH_36:
++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
++ break;
++ case TRANSMITTER_COLOR_DEPTH_48:
++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
++ break;
++ default:
++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
++ break;
++ }
++
++ return atomColorDepth;
++}
++
++/* function table */
++static const struct command_table_helper command_table_helper_funcs = {
++ .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom,
++ .encoder_action_to_atom = encoder_action_to_atom,
++ .engine_bp_to_atom = engine_bp_to_atom,
++ .clock_source_id_to_atom = clock_source_id_to_atom,
++ .clock_source_id_to_atom_phy_clk_src_id =
++ clock_source_id_to_atom_phy_clk_src_id,
++ .signal_type_to_atom_dig_mode = signal_type_to_atom_dig_mode,
++ .hpd_sel_to_atom = hpd_sel_to_atom,
++ .dig_encoder_sel_to_atom = dig_encoder_sel_to_atom,
++ .phy_id_to_atom = phy_id_to_atom,
++ .disp_power_gating_action_to_atom = disp_power_gating_action_to_atom,
++ .assign_control_parameter = NULL,
++ .clock_source_id_to_ref_clk_src = NULL,
++ .transmitter_bp_to_atom = NULL,
++ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom,
++ .encoder_mode_bp_to_atom = dal_cmd_table_helper_encoder_mode_bp_to_atom,
++ .dc_clock_type_to_atom = dc_clock_type_to_atom,
++ .transmitter_color_depth_to_atom = transmitter_color_depth_to_atom,
++};
++
++/*
++ * dal_cmd_tbl_helper_dce110_get_table
++ *
++ * @brief
++ * Initialize command table helper functions
++ *
++ * @param
++ * const struct command_table_helper **h - [out] struct of functions
++ *
++ */
++const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table()
++{
++ return &command_table_helper_funcs;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h
+new file mode 100644
+index 0000000..dc36609
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce112/command_table_helper_dce112.h
+@@ -0,0 +1,34 @@
++/*
++ * 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_COMMAND_TABLE_HELPER_DCE112_H__
++#define __DAL_COMMAND_TABLE_HELPER_DCE112_H__
++
++struct command_table_helper;
++
++/* Initialize command table helper functions */
++const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table(void);
++
++#endif /* __DAL_COMMAND_TABLE_HELPER_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c b/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
+index f39499a..8a19139 100644
+--- a/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
++++ b/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
+@@ -3726,6 +3726,212 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip,
+ dceip.scatter_gather_pte_request_rows_in_tiling_mode = 2;
+ dceip.mcifwr_all_surfaces_burst_time = bw_int_to_fixed(0); /* todo: this is a bug*/
+ break;
++ case BW_CALCS_VERSION_ELLESMERE:
++ vbios.number_of_dram_channels = 8;
++ vbios.dram_channel_width_in_bits = 32;
++ vbios.number_of_dram_banks = 8;
++ vbios.high_yclk = bw_int_to_fixed(6000);
++ vbios.mid_yclk = bw_int_to_fixed(3200);
++ vbios.low_yclk = bw_int_to_fixed(1000);
++ vbios.low_sclk = bw_int_to_fixed(300);
++ vbios.mid_sclk = bw_int_to_fixed(974);
++ vbios.high_sclk = bw_int_to_fixed(1154);
++ vbios.low_voltage_max_dispclk = bw_int_to_fixed(459);
++ vbios.mid_voltage_max_dispclk = bw_int_to_fixed(654);
++ vbios.high_voltage_max_dispclk = bw_int_to_fixed(1132);
++ vbios.data_return_bus_width = bw_int_to_fixed(32);
++ vbios.trc = bw_int_to_fixed(48);
++ vbios.dmifmc_urgent_latency = bw_int_to_fixed(3);
++ vbios.stutter_self_refresh_exit_latency = bw_int_to_fixed(5);
++ vbios.nbp_state_change_latency = bw_int_to_fixed(45);
++ vbios.mcifwrmc_urgent_latency = bw_int_to_fixed(10);
++ vbios.scatter_gather_enable = true;
++ vbios.down_spread_percentage = bw_frc_to_fixed(5, 10);
++ vbios.cursor_width = 32;
++ vbios.average_compression_rate = 4;
++ vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel =
++ 256;
++ vbios.blackout_duration = bw_int_to_fixed(0); /* us */
++ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0);
++
++ dceip.dmif_request_buffer_size = bw_int_to_fixed(768);
++ dceip.de_tiling_buffer = bw_int_to_fixed(0);
++ dceip.dcfclk_request_generation = 0;
++ dceip.lines_interleaved_into_lb = 2;
++ dceip.chunk_width = 256;
++ dceip.number_of_graphics_pipes = 6;
++ dceip.number_of_underlay_pipes = 0;
++ dceip.display_write_back_supported = false;
++ dceip.argb_compression_support = false;
++ dceip.underlay_vscaler_efficiency6_bit_per_component =
++ bw_frc_to_fixed(35556, 10000);
++ dceip.underlay_vscaler_efficiency8_bit_per_component =
++ bw_frc_to_fixed(34286, 10000);
++ dceip.underlay_vscaler_efficiency10_bit_per_component =
++ bw_frc_to_fixed(32, 10);
++ dceip.underlay_vscaler_efficiency12_bit_per_component =
++ bw_int_to_fixed(3);
++ dceip.graphics_vscaler_efficiency6_bit_per_component =
++ bw_frc_to_fixed(35, 10);
++ dceip.graphics_vscaler_efficiency8_bit_per_component =
++ bw_frc_to_fixed(34286, 10000);
++ dceip.graphics_vscaler_efficiency10_bit_per_component =
++ bw_frc_to_fixed(32, 10);
++ dceip.graphics_vscaler_efficiency12_bit_per_component =
++ bw_int_to_fixed(3);
++ dceip.alpha_vscaler_efficiency = bw_int_to_fixed(3);
++ dceip.max_dmif_buffer_allocated = 4;
++ dceip.graphics_dmif_size = 12288;
++ dceip.underlay_luma_dmif_size = 19456;
++ dceip.underlay_chroma_dmif_size = 23552;
++ dceip.pre_downscaler_enabled = true;
++ dceip.underlay_downscale_prefetch_enabled = true;
++ dceip.lb_write_pixels_per_dispclk = bw_int_to_fixed(1);
++ dceip.lb_size_per_component444 = bw_int_to_fixed(245952);
++ dceip.graphics_lb_nodownscaling_multi_line_prefetching = true;
++ dceip.stutter_and_dram_clock_state_change_gated_before_cursor =
++ bw_int_to_fixed(1);
++ dceip.underlay420_luma_lb_size_per_component = bw_int_to_fixed(
++ 82176);
++ dceip.underlay420_chroma_lb_size_per_component =
++ bw_int_to_fixed(164352);
++ dceip.underlay422_lb_size_per_component = bw_int_to_fixed(
++ 82176);
++ dceip.cursor_chunk_width = bw_int_to_fixed(64);
++ dceip.cursor_dcp_buffer_lines = bw_int_to_fixed(4);
++ dceip.cursor_memory_interface_buffer_pixels = bw_int_to_fixed(
++ 64);
++ dceip.underlay_maximum_width_efficient_for_tiling =
++ bw_int_to_fixed(1920);
++ dceip.underlay_maximum_height_efficient_for_tiling =
++ bw_int_to_fixed(1080);
++ dceip.peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display =
++ bw_frc_to_fixed(3, 10);
++ dceip.peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation =
++ bw_int_to_fixed(25);
++ dceip.minimum_outstanding_pte_request_limit = bw_int_to_fixed(
++ 2);
++ dceip.maximum_total_outstanding_pte_requests_allowed_by_saw =
++ bw_int_to_fixed(128);
++ dceip.limit_excessive_outstanding_dmif_requests = true;
++ dceip.linear_mode_line_request_alternation_slice =
++ bw_int_to_fixed(64);
++ dceip.scatter_gather_lines_of_pte_prefetching_in_linear_mode =
++ 32;
++ dceip.display_write_back420_luma_mcifwr_buffer_size = 12288;
++ dceip.display_write_back420_chroma_mcifwr_buffer_size = 8192;
++ dceip.request_efficiency = bw_frc_to_fixed(8, 10);
++ dceip.dispclk_per_request = bw_int_to_fixed(2);
++ dceip.dispclk_ramping_factor = bw_frc_to_fixed(11, 10);
++ dceip.display_pipe_throughput_factor = bw_frc_to_fixed(
++ 105,
++ 100);
++ dceip.scatter_gather_pte_request_rows_in_tiling_mode = 2;
++ dceip.mcifwr_all_surfaces_burst_time = bw_int_to_fixed(0);
++ break;
++ case BW_CALCS_VERSION_BAFFIN:
++ vbios.number_of_dram_channels = 4;
++ vbios.dram_channel_width_in_bits = 32;
++ vbios.number_of_dram_banks = 8;
++ vbios.high_yclk = bw_int_to_fixed(6000);
++ vbios.mid_yclk = bw_int_to_fixed(3200);
++ vbios.low_yclk = bw_int_to_fixed(1000);
++ vbios.low_sclk = bw_int_to_fixed(300);
++ vbios.mid_sclk = bw_int_to_fixed(974);
++ vbios.high_sclk = bw_int_to_fixed(1154);
++ vbios.low_voltage_max_dispclk = bw_int_to_fixed(459);
++ vbios.mid_voltage_max_dispclk = bw_int_to_fixed(654);
++ vbios.high_voltage_max_dispclk = bw_int_to_fixed(1132);
++ vbios.data_return_bus_width = bw_int_to_fixed(32);
++ vbios.trc = bw_int_to_fixed(48);
++ vbios.dmifmc_urgent_latency = bw_int_to_fixed(3);
++ vbios.stutter_self_refresh_exit_latency = bw_int_to_fixed(5);
++ vbios.nbp_state_change_latency = bw_int_to_fixed(45);
++ vbios.mcifwrmc_urgent_latency = bw_int_to_fixed(10);
++ vbios.scatter_gather_enable = true;
++ vbios.down_spread_percentage = bw_frc_to_fixed(5, 10);
++ vbios.cursor_width = 32;
++ vbios.average_compression_rate = 4;
++ vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel =
++ 256;
++ vbios.blackout_duration = bw_int_to_fixed(0); /* us */
++ vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0);
++
++ dceip.dmif_request_buffer_size = bw_int_to_fixed(768);
++ dceip.de_tiling_buffer = bw_int_to_fixed(0);
++ dceip.dcfclk_request_generation = 0;
++ dceip.lines_interleaved_into_lb = 2;
++ dceip.chunk_width = 256;
++ dceip.number_of_graphics_pipes = 5;
++ dceip.number_of_underlay_pipes = 0;
++ dceip.display_write_back_supported = false;
++ dceip.argb_compression_support = false;
++ dceip.underlay_vscaler_efficiency6_bit_per_component =
++ bw_frc_to_fixed(35556, 10000);
++ dceip.underlay_vscaler_efficiency8_bit_per_component =
++ bw_frc_to_fixed(34286, 10000);
++ dceip.underlay_vscaler_efficiency10_bit_per_component =
++ bw_frc_to_fixed(32, 10);
++ dceip.underlay_vscaler_efficiency12_bit_per_component =
++ bw_int_to_fixed(3);
++ dceip.graphics_vscaler_efficiency6_bit_per_component =
++ bw_frc_to_fixed(35, 10);
++ dceip.graphics_vscaler_efficiency8_bit_per_component =
++ bw_frc_to_fixed(34286, 10000);
++ dceip.graphics_vscaler_efficiency10_bit_per_component =
++ bw_frc_to_fixed(32, 10);
++ dceip.graphics_vscaler_efficiency12_bit_per_component =
++ bw_int_to_fixed(3);
++ dceip.alpha_vscaler_efficiency = bw_int_to_fixed(3);
++ dceip.max_dmif_buffer_allocated = 4;
++ dceip.graphics_dmif_size = 12288;
++ dceip.underlay_luma_dmif_size = 19456;
++ dceip.underlay_chroma_dmif_size = 23552;
++ dceip.pre_downscaler_enabled = true;
++ dceip.underlay_downscale_prefetch_enabled = true;
++ dceip.lb_write_pixels_per_dispclk = bw_int_to_fixed(1);
++ dceip.lb_size_per_component444 = bw_int_to_fixed(245952);
++ dceip.graphics_lb_nodownscaling_multi_line_prefetching = true;
++ dceip.stutter_and_dram_clock_state_change_gated_before_cursor =
++ bw_int_to_fixed(1);
++ dceip.underlay420_luma_lb_size_per_component = bw_int_to_fixed(
++ 82176);
++ dceip.underlay420_chroma_lb_size_per_component =
++ bw_int_to_fixed(164352);
++ dceip.underlay422_lb_size_per_component = bw_int_to_fixed(
++ 82176);
++ dceip.cursor_chunk_width = bw_int_to_fixed(64);
++ dceip.cursor_dcp_buffer_lines = bw_int_to_fixed(4);
++ dceip.cursor_memory_interface_buffer_pixels = bw_int_to_fixed(
++ 64);
++ dceip.underlay_maximum_width_efficient_for_tiling =
++ bw_int_to_fixed(1920);
++ dceip.underlay_maximum_height_efficient_for_tiling =
++ bw_int_to_fixed(1080);
++ dceip.peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display =
++ bw_frc_to_fixed(3, 10);
++ dceip.peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation =
++ bw_int_to_fixed(25);
++ dceip.minimum_outstanding_pte_request_limit = bw_int_to_fixed(
++ 2);
++ dceip.maximum_total_outstanding_pte_requests_allowed_by_saw =
++ bw_int_to_fixed(128);
++ dceip.limit_excessive_outstanding_dmif_requests = true;
++ dceip.linear_mode_line_request_alternation_slice =
++ bw_int_to_fixed(64);
++ dceip.scatter_gather_lines_of_pte_prefetching_in_linear_mode =
++ 32;
++ dceip.display_write_back420_luma_mcifwr_buffer_size = 12288;
++ dceip.display_write_back420_chroma_mcifwr_buffer_size = 8192;
++ dceip.request_efficiency = bw_frc_to_fixed(8, 10);
++ dceip.dispclk_per_request = bw_int_to_fixed(2);
++ dceip.dispclk_ramping_factor = bw_frc_to_fixed(11, 10);
++ dceip.display_pipe_throughput_factor = bw_frc_to_fixed(
++ 105,
++ 100);
++ dceip.scatter_gather_pte_request_rows_in_tiling_mode = 2;
++ dceip.mcifwr_all_surfaces_burst_time = bw_int_to_fixed(0);
++ break;
+ default:
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
+index 61bb67a..f9dd0d8 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
+@@ -34,6 +34,9 @@
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ #include "dce110/dce110_hw_sequencer.h"
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "dce112/dce112_hw_sequencer.h"
++#endif
+
+ bool dc_construct_hw_sequencer(
+ struct adapter_service *adapter_serv,
+@@ -55,6 +58,10 @@ bool dc_construct_hw_sequencer(
+ case DCE_VERSION_11_0:
+ return dce110_hw_sequencer_construct(dc);
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ return dce112_hw_sequencer_construct(dc);
++#endif
+ default:
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+index 5f3b702..087670d 100644
+--- a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+@@ -41,11 +41,13 @@
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ #include "dce110/dce110_resource.h"
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#include "dce112/dce112_resource.h"
++#endif
+
+ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
+- {
++{
+ enum dce_version dc_version = DCE_VERSION_UNKNOWN;
+-
+ switch (asic_id.chip_family) {
+
+ #if defined(CONFIG_DRM_AMD_DAL_DCE8_0)
+@@ -68,6 +70,12 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
+ break;
+ }
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
++ ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev)) {
++ dc_version = DCE_VERSION_11_2;
++ }
++#endif
+ break;
+ default:
+ dc_version = DCE_VERSION_UNKNOWN;
+@@ -83,6 +91,11 @@ bool dc_construct_resource_pool(struct adapter_service *adapter_serv,
+ {
+
+ switch (dc_version) {
++#if defined(CONFIG_DRM_AMD_DAL_DCE8_0)
++ case DCE_VERSION_8_0:
++ return dce80_construct_resource_pool(
++ adapter_serv, num_virtual_links, dc, &dc->res_pool);
++#endif
+ #if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
+ case DCE_VERSION_10_0:
+ return dce100_construct_resource_pool(
+@@ -93,6 +106,11 @@ bool dc_construct_resource_pool(struct adapter_service *adapter_serv,
+ return dce110_construct_resource_pool(
+ adapter_serv, num_virtual_links, dc, &dc->res_pool);
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ return dce112_construct_resource_pool(
++ adapter_serv, num_virtual_links, dc, &dc->res_pool);
++#endif
+ default:
+ break;
+ }
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+index 3d4f8b7..a21fcbd 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+@@ -416,6 +416,7 @@ static void dce110_crtc_switch_to_clk_src(
+ uint32_t pixel_rate_cntl_value;
+ uint32_t addr;
+
++ /* These addresses are the same across DCE8 - DCE11.2 */
+ addr = mmCRTC0_PIXEL_RATE_CNTL + crtc_inst *
+ (mmCRTC1_PIXEL_RATE_CNTL - mmCRTC0_PIXEL_RATE_CNTL);
+
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
+index de370ee..a9ef65d 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
+@@ -59,7 +59,7 @@ enum black_color_format {
+
+ /* Flowing register offsets are same in files of
+ * dce/dce_11_0_d.h
+- * dce/vi_ellesmere_p/vi_ellesmere_d.h
++ * dce/vi_polaris10_p/vi_polaris10_d.h
+ *
+ * So we can create dce110 timing generator to use it.
+ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/Makefile b/drivers/gpu/drm/amd/dal/dc/dce112/Makefile
+new file mode 100644
+index 0000000..c7d61d9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the 'controller' sub-component of DAL.
++# It provides the control and status of HW CRTC block.
++
++DCE112 = dce112_link_encoder.o dce112_compressor.o dce112_hw_sequencer.o \
++dce112_resource.o dce112_clock_source.o dce112_mem_input.o
++
++AMD_DAL_DCE112 = $(addprefix $(AMDDALPATH)/dc/dce112/,$(DCE112))
++
++AMD_DAL_FILES += $(AMD_DAL_DCE112)
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c
+new file mode 100644
+index 0000000..7ec9508
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.c
+@@ -0,0 +1,266 @@
++/*
++ * 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 "dce112_clock_source.h"
++
++/* include DCE11.2 register header files */
++#include "dce/dce_11_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++
++#include "dc_types.h"
++#include "core_types.h"
++
++#include "include/grph_object_id.h"
++#include "include/logger_interface.h"
++
++/**
++ * Calculate PLL Dividers for given Clock Value.
++ * First will call VBIOS Adjust Exec table to check if requested Pixel clock
++ * will be Adjusted based on usage.
++ * Then it will calculate PLL Dividers for this Adjusted clock using preferred
++ * method (Maximum VCO frequency).
++ *
++ * \return
++ * Calculation error in units of 0.01%
++ */
++static uint32_t dce112_get_pix_clk_dividers(
++ struct clock_source *cs,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct dce112_clk_src *clk_src = TO_DCE112_CLK_SRC(cs);
++ uint32_t actualPixelClockInKHz;
++
++ if (pix_clk_params == NULL || pll_settings == NULL
++ || pix_clk_params->requested_pix_clk == 0) {
++ dal_logger_write(cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid parameters!!\n", __func__);
++ return 0;
++ }
++
++ memset(pll_settings, 0, sizeof(*pll_settings));
++
++ if (clk_src->base.id == CLOCK_SOURCE_ID_DP_DTO) {
++ pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
++ pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
++ pll_settings->actual_pix_clk =
++ pix_clk_params->requested_pix_clk;
++ return 0;
++ }
++ /* PLL only after this point */
++
++ actualPixelClockInKHz = pix_clk_params->requested_pix_clk;
++
++ /* Calculate Dividers */
++ if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
++ switch (pix_clk_params->color_depth) {
++ case COLOR_DEPTH_101010:
++ actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2;
++ break;
++ case COLOR_DEPTH_121212:
++ actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2;
++ break;
++ case COLOR_DEPTH_161616:
++ actualPixelClockInKHz = actualPixelClockInKHz * 2;
++ break;
++ default:
++ break;
++ }
++ }
++
++ pll_settings->actual_pix_clk = actualPixelClockInKHz;
++ pll_settings->adjusted_pix_clk = actualPixelClockInKHz;
++ pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk;
++
++ return 0;
++}
++
++static void program_pixel_clk_resync(
++ struct dce112_clk_src *clk_src,
++ enum signal_type signal_type,
++ enum dc_color_depth colordepth)
++{
++ uint32_t value = 0;
++
++ value = dm_read_reg(clk_src->base.ctx,
++ clk_src->offsets.pixclk_resync_cntl);
++
++ set_reg_field_value(
++ value,
++ 0,
++ PHYPLLA_PIXCLK_RESYNC_CNTL,
++ PHYPLLA_DCCG_DEEP_COLOR_CNTL);
++
++ /*
++ 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
++ 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
++ 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
++ 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
++ */
++ if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
++ return;
++
++ switch (colordepth) {
++ case COLOR_DEPTH_888:
++ set_reg_field_value(
++ value,
++ 0,
++ PHYPLLA_PIXCLK_RESYNC_CNTL,
++ PHYPLLA_DCCG_DEEP_COLOR_CNTL);
++ break;
++ case COLOR_DEPTH_101010:
++ set_reg_field_value(
++ value,
++ 1,
++ PHYPLLA_PIXCLK_RESYNC_CNTL,
++ PHYPLLA_DCCG_DEEP_COLOR_CNTL);
++ break;
++ case COLOR_DEPTH_121212:
++ set_reg_field_value(
++ value,
++ 2,
++ PHYPLLA_PIXCLK_RESYNC_CNTL,
++ PHYPLLA_DCCG_DEEP_COLOR_CNTL);
++ break;
++ case COLOR_DEPTH_161616:
++ set_reg_field_value(
++ value,
++ 3,
++ PHYPLLA_PIXCLK_RESYNC_CNTL,
++ PHYPLLA_DCCG_DEEP_COLOR_CNTL);
++ break;
++ default:
++ break;
++ }
++
++ dm_write_reg(
++ clk_src->base.ctx,
++ clk_src->offsets.pixclk_resync_cntl,
++ value);
++}
++
++static bool dce112_program_pix_clk(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct dce112_clk_src *dce112_clk_src = TO_DCE112_CLK_SRC(clk_src);
++ struct bp_pixel_clock_parameters bp_pc_params = {0};
++
++ /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
++ bp_pc_params.controller_id = pix_clk_params->controller_id;
++ bp_pc_params.pll_id = clk_src->id;
++ bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk;
++ bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
++ bp_pc_params.signal_type = pix_clk_params->signal_type;
++
++ if (clk_src->id != CLOCK_SOURCE_ID_DP_DTO) {
++ bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
++ pll_settings->use_external_clk;
++ bp_pc_params.flags.SET_XTALIN_REF_SRC =
++ !pll_settings->use_external_clk;
++ bp_pc_params.flags.SUPPORT_YUV_420 = 0;
++ }
++
++ if (dce112_clk_src->bios->funcs->set_pixel_clock(
++ dce112_clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
++ return false;
++
++ /* TODO: support YCBCR420 */
++
++ /* Resync deep color DTO */
++ if (clk_src->id != CLOCK_SOURCE_ID_DP_DTO)
++ program_pixel_clk_resync(dce112_clk_src,
++ pix_clk_params->signal_type,
++ pix_clk_params->color_depth);
++
++ return true;
++}
++
++static bool dce112_clock_source_power_down(
++ struct clock_source *clk_src)
++{
++ struct dce112_clk_src *dce112_clk_src = TO_DCE112_CLK_SRC(clk_src);
++ enum bp_result bp_result;
++ struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
++
++ if (clk_src->id == CLOCK_SOURCE_ID_DP_DTO)
++ return true;
++
++ /* If Pixel Clock is 0 it means Power Down Pll*/
++ bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED;
++ bp_pixel_clock_params.pll_id = clk_src->id;
++ bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
++
++ /*Call ASICControl to process ATOMBIOS Exec table*/
++ bp_result = dce112_clk_src->bios->funcs->set_pixel_clock(
++ dce112_clk_src->bios,
++ &bp_pixel_clock_params);
++
++ return bp_result == BP_RESULT_OK;
++}
++
++/*****************************************/
++/* Constructor */
++/*****************************************/
++static struct clock_source_funcs dce112_clk_src_funcs = {
++ .cs_power_down = dce112_clock_source_power_down,
++ .program_pix_clk = dce112_program_pix_clk,
++ .get_pix_clk_dividers = dce112_get_pix_clk_dividers
++};
++
++bool dce112_clk_src_construct(
++ struct dce112_clk_src *clk_src,
++ struct dc_context *ctx,
++ struct dc_bios *bios,
++ enum clock_source_id id,
++ const struct dce112_clk_src_reg_offsets *reg_offsets)
++{
++ struct firmware_info fw_info = { { 0 } };
++
++ clk_src->base.ctx = ctx;
++ clk_src->bios = bios;
++ clk_src->base.id = id;
++ clk_src->base.funcs = &dce112_clk_src_funcs;
++ clk_src->offsets = *reg_offsets;
++
++ if (clk_src->bios->funcs->get_firmware_info(
++ clk_src->bios, &fw_info) != BP_RESULT_OK) {
++ ASSERT_CRITICAL(false);
++ goto unexpected_failure;
++ }
++
++ clk_src->ext_clk_khz = fw_info.external_clock_source_frequency_for_dp;
++
++ return true;
++
++unexpected_failure:
++ return false;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h
+new file mode 100644
+index 0000000..40ecc58
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_clock_source.h
+@@ -0,0 +1,52 @@
++/* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_CLOCK_SOURCE_DCE110_H__
++#define __DC_CLOCK_SOURCE_DCE110_H__
++
++#include "clock_source.h"
++
++#define TO_DCE112_CLK_SRC(clk_src)\
++ container_of(clk_src, struct dce112_clk_src, base)
++
++struct dce112_clk_src_reg_offsets {
++ uint32_t pixclk_resync_cntl;
++};
++
++struct dce112_clk_src {
++ struct clock_source base;
++ struct dce112_clk_src_reg_offsets offsets;
++ struct dc_bios *bios;
++
++ uint32_t ext_clk_khz;
++};
++
++bool dce112_clk_src_construct(
++ struct dce112_clk_src *clk_src,
++ struct dc_context *ctx,
++ struct dc_bios *bios,
++ enum clock_source_id,
++ const struct dce112_clk_src_reg_offsets *reg_offsets);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c
+new file mode 100644
+index 0000000..9526ffd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.c
+@@ -0,0 +1,883 @@
++/*
++ * 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_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++#include "gmc/gmc_8_1_sh_mask.h"
++#include "gmc/gmc_8_1_d.h"
++
++#include "include/logger_interface.h"
++#include "include/adapter_service_interface.h"
++
++#include "dce112_compressor.h"
++
++#define DCP_REG(reg)\
++ (reg + cp110->offsets.dcp_offset)
++#define DMIF_REG(reg)\
++ (reg + cp110->offsets.dmif_offset)
++
++static const struct dce112_compressor_reg_offsets reg_offsets[] = {
++{
++ .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif_offset =
++ (mmDMIF_PG0_DPG_PIPE_DPM_CONTROL
++ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
++},
++{
++ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif_offset =
++ (mmDMIF_PG1_DPG_PIPE_DPM_CONTROL
++ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
++},
++{
++ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif_offset =
++ (mmDMIF_PG2_DPG_PIPE_DPM_CONTROL
++ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
++}
++};
++
++static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600;
++
++enum fbc_idle_force {
++ /* Bit 0 - Display registers updated */
++ FBC_IDLE_FORCE_DISPLAY_REGISTER_UPDATE = 0x00000001,
++
++ /* Bit 2 - FBC_GRPH_COMP_EN register updated */
++ FBC_IDLE_FORCE_GRPH_COMP_EN = 0x00000002,
++ /* Bit 3 - FBC_SRC_SEL register updated */
++ FBC_IDLE_FORCE_SRC_SEL_CHANGE = 0x00000004,
++ /* Bit 4 - FBC_MIN_COMPRESSION register updated */
++ FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE = 0x00000008,
++ /* Bit 5 - FBC_ALPHA_COMP_EN register updated */
++ FBC_IDLE_FORCE_ALPHA_COMP_EN = 0x00000010,
++ /* Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated */
++ FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN = 0x00000020,
++ /* Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated */
++ FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF = 0x00000040,
++
++ /* Bit 24 - Memory write to region 0 defined by MC registers. */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION0 = 0x01000000,
++ /* Bit 25 - Memory write to region 1 defined by MC registers */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION1 = 0x02000000,
++ /* Bit 26 - Memory write to region 2 defined by MC registers */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION2 = 0x04000000,
++ /* Bit 27 - Memory write to region 3 defined by MC registers. */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION3 = 0x08000000,
++
++ /* Bit 28 - Memory write from any client other than MCIF */
++ FBC_IDLE_FORCE_MEMORY_WRITE_OTHER_THAN_MCIF = 0x10000000,
++ /* Bit 29 - CG statics screen signal is inactive */
++ FBC_IDLE_FORCE_CG_STATIC_SCREEN_IS_INACTIVE = 0x20000000,
++};
++
++static uint32_t lpt_size_alignment(struct dce112_compressor *cp110)
++{
++ /*LPT_ALIGNMENT (in bytes) = ROW_SIZE * #BANKS * # DRAM CHANNELS. */
++ return cp110->base.raw_size * cp110->base.banks_num *
++ cp110->base.dram_channels_num;
++}
++
++static uint32_t lpt_memory_control_config(struct dce112_compressor *cp110,
++ uint32_t lpt_control)
++{
++ /*LPT MC Config */
++ if (cp110->base.options.bits.LPT_MC_CONFIG == 1) {
++ /* POSSIBLE VALUES for LPT NUM_PIPES (DRAM CHANNELS):
++ * 00 - 1 CHANNEL
++ * 01 - 2 CHANNELS
++ * 02 - 4 OR 6 CHANNELS
++ * (Only for discrete GPU, N/A for CZ)
++ * 03 - 8 OR 12 CHANNELS
++ * (Only for discrete GPU, N/A for CZ) */
++ switch (cp110->base.dram_channels_num) {
++ case 2:
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_PIPES);
++ break;
++ case 1:
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_PIPES);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT NUM_PIPES!!!",
++ __func__);
++ break;
++ }
++
++ /* The mapping for LPT NUM_BANKS is in
++ * GRPH_CONTROL.GRPH_NUM_BANKS register field
++ * Specifies the number of memory banks for tiling
++ * purposes. Only applies to 2D and 3D tiling modes.
++ * POSSIBLE VALUES:
++ * 00 - DCP_GRPH_NUM_BANKS_2BANK: ADDR_SURF_2_BANK
++ * 01 - DCP_GRPH_NUM_BANKS_4BANK: ADDR_SURF_4_BANK
++ * 02 - DCP_GRPH_NUM_BANKS_8BANK: ADDR_SURF_8_BANK
++ * 03 - DCP_GRPH_NUM_BANKS_16BANK: ADDR_SURF_16_BANK */
++ switch (cp110->base.banks_num) {
++ case 16:
++ set_reg_field_value(
++ lpt_control,
++ 3,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ case 8:
++ set_reg_field_value(
++ lpt_control,
++ 2,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ case 4:
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ case 2:
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT NUM_BANKS!!!",
++ __func__);
++ break;
++ }
++
++ /* The mapping is in DMIF_ADDR_CALC.
++ * ADDR_CONFIG_PIPE_INTERLEAVE_SIZE register field for
++ * Carrizo specifies the memory interleave per pipe.
++ * It effectively specifies the location of pipe bits in
++ * the memory address.
++ * POSSIBLE VALUES:
++ * 00 - ADDR_CONFIG_PIPE_INTERLEAVE_256B: 256 byte
++ * interleave
++ * 01 - ADDR_CONFIG_PIPE_INTERLEAVE_512B: 512 byte
++ * interleave
++ */
++ switch (cp110->base.channel_interleave_size) {
++ case 256: /*256B */
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE);
++ break;
++ case 512: /*512B */
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT INTERLEAVE_SIZE!!!",
++ __func__);
++ break;
++ }
++
++ /* The mapping for LOW_POWER_TILING_ROW_SIZE is in
++ * DMIF_ADDR_CALC.ADDR_CONFIG_ROW_SIZE register field
++ * for Carrizo. Specifies the size of dram row in bytes.
++ * This should match up with NOOFCOLS field in
++ * MC_ARB_RAMCFG (ROW_SIZE = 4 * 2 ^^ columns).
++ * This register DMIF_ADDR_CALC is not used by the
++ * hardware as it is only used for addrlib assertions.
++ * POSSIBLE VALUES:
++ * 00 - ADDR_CONFIG_1KB_ROW: Treat 1KB as DRAM row
++ * boundary
++ * 01 - ADDR_CONFIG_2KB_ROW: Treat 2KB as DRAM row
++ * boundary
++ * 02 - ADDR_CONFIG_4KB_ROW: Treat 4KB as DRAM row
++ * boundary */
++ switch (cp110->base.raw_size) {
++ case 4096: /*4 KB */
++ set_reg_field_value(
++ lpt_control,
++ 2,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROW_SIZE);
++ break;
++ case 2048:
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROW_SIZE);
++ break;
++ case 1024:
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROW_SIZE);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT ROW_SIZE!!!",
++ __func__);
++ break;
++ }
++ } else {
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: LPT MC Configuration is not provided",
++ __func__);
++ }
++
++ return lpt_control;
++}
++
++static bool is_source_bigger_than_epanel_size(
++ struct dce112_compressor *cp110,
++ uint32_t source_view_width,
++ uint32_t source_view_height)
++{
++ if (cp110->base.embedded_panel_h_size != 0 &&
++ cp110->base.embedded_panel_v_size != 0 &&
++ ((source_view_width * source_view_height) >
++ (cp110->base.embedded_panel_h_size *
++ cp110->base.embedded_panel_v_size)))
++ return true;
++
++ return false;
++}
++
++static uint32_t align_to_chunks_number_per_line(
++ struct dce112_compressor *cp110,
++ uint32_t pixels)
++{
++ return 256 * ((pixels + 255) / 256);
++}
++
++static void wait_for_fbc_state_changed(
++ struct dce112_compressor *cp110,
++ bool enabled)
++{
++ uint8_t counter = 0;
++ uint32_t addr = mmFBC_STATUS;
++ uint32_t value;
++
++ while (counter < 10) {
++ value = dm_read_reg(cp110->base.ctx, addr);
++ if (get_reg_field_value(
++ value,
++ FBC_STATUS,
++ FBC_ENABLE_STATUS) == enabled)
++ break;
++ udelay(10);
++ counter++;
++ }
++
++ if (counter == 10) {
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: wait counter exceeded, changes to HW not applied",
++ __func__);
++ }
++}
++
++void dce112_compressor_power_up_fbc(struct compressor *compressor)
++{
++ uint32_t value;
++ uint32_t addr;
++
++ addr = mmFBC_CNTL;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
++ set_reg_field_value(value, 1, FBC_CNTL, FBC_EN);
++ set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE);
++ if (compressor->options.bits.CLK_GATING_DISABLED == 1) {
++ /* HW needs to do power measurement comparison. */
++ set_reg_field_value(
++ value,
++ 0,
++ FBC_CNTL,
++ FBC_COMP_CLK_GATE_EN);
++ }
++ dm_write_reg(compressor->ctx, addr, value);
++
++ addr = mmFBC_COMP_MODE;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN);
++ set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN);
++ set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ addr = mmFBC_COMP_CNTL;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN);
++ dm_write_reg(compressor->ctx, addr, value);
++ /*FBC_MIN_COMPRESSION 0 ==> 2:1 */
++ /* 1 ==> 4:1 */
++ /* 2 ==> 8:1 */
++ /* 0xF ==> 1:1 */
++ set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION);
++ dm_write_reg(compressor->ctx, addr, value);
++ compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1;
++
++ value = 0;
++ dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value);
++
++ value = 0xFFFFFF;
++ dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value);
++}
++
++void dce112_compressor_enable_fbc(
++ struct compressor *compressor,
++ uint32_t paths_num,
++ struct compr_addr_and_pitch_params *params)
++{
++ struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
++
++ if (compressor->options.bits.FBC_SUPPORT &&
++ (compressor->options.bits.DUMMY_BACKEND == 0) &&
++ (!dce112_compressor_is_fbc_enabled_in_hw(compressor, NULL)) &&
++ (!is_source_bigger_than_epanel_size(
++ cp110,
++ params->source_view_width,
++ params->source_view_height))) {
++
++ uint32_t addr;
++ uint32_t value;
++
++ /* Before enabling FBC first need to enable LPT if applicable
++ * LPT state should always be changed (enable/disable) while FBC
++ * is disabled */
++ if (compressor->options.bits.LPT_SUPPORT && (paths_num < 2) &&
++ (params->source_view_width *
++ params->source_view_height <=
++ dce11_one_lpt_channel_max_resolution)) {
++ dce112_compressor_enable_lpt(compressor);
++ }
++
++ addr = mmFBC_CNTL;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
++ set_reg_field_value(
++ value,
++ params->inst,
++ FBC_CNTL, FBC_SRC_SEL);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ /* Keep track of enum controller_id FBC is attached to */
++ compressor->is_enabled = true;
++ compressor->attached_inst = params->inst;
++ cp110->offsets = reg_offsets[params->inst - 1];
++
++ /*Toggle it as there is bug in HW */
++ set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
++ dm_write_reg(compressor->ctx, addr, value);
++ set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ wait_for_fbc_state_changed(cp110, true);
++ }
++}
++
++void dce112_compressor_disable_fbc(struct compressor *compressor)
++{
++ struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
++
++ if (compressor->options.bits.FBC_SUPPORT &&
++ dce112_compressor_is_fbc_enabled_in_hw(compressor, NULL)) {
++ uint32_t reg_data;
++ /* Turn off compression */
++ reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL);
++ set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
++ dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data);
++
++ /* Reset enum controller_id to undefined */
++ compressor->attached_inst = 0;
++ compressor->is_enabled = false;
++
++ /* Whenever disabling FBC make sure LPT is disabled if LPT
++ * supported */
++ if (compressor->options.bits.LPT_SUPPORT)
++ dce112_compressor_disable_lpt(compressor);
++
++ wait_for_fbc_state_changed(cp110, false);
++ }
++}
++
++bool dce112_compressor_is_fbc_enabled_in_hw(
++ struct compressor *compressor,
++ uint32_t *inst)
++{
++ /* Check the hardware register */
++ uint32_t value;
++
++ value = dm_read_reg(compressor->ctx, mmFBC_STATUS);
++ if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) {
++ if (inst != NULL)
++ *inst = compressor->attached_inst;
++ return true;
++ }
++
++ value = dm_read_reg(compressor->ctx, mmFBC_MISC);
++ if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) {
++ value = dm_read_reg(compressor->ctx, mmFBC_CNTL);
++
++ if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) {
++ if (inst != NULL)
++ *inst =
++ compressor->attached_inst;
++ return true;
++ }
++ }
++ return false;
++}
++
++bool dce112_compressor_is_lpt_enabled_in_hw(struct compressor *compressor)
++{
++ /* Check the hardware register */
++ uint32_t value = dm_read_reg(compressor->ctx,
++ mmLOW_POWER_TILING_CONTROL);
++
++ return get_reg_field_value(
++ value,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ENABLE);
++}
++
++void dce112_compressor_program_compressed_surface_address_and_pitch(
++ struct compressor *compressor,
++ struct compr_addr_and_pitch_params *params)
++{
++ struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
++ uint32_t value = 0;
++ uint32_t fbc_pitch = 0;
++ uint32_t compressed_surf_address_low_part =
++ compressor->compr_surface_address.addr.low_part;
++
++ /* Clear content first. */
++ dm_write_reg(
++ compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
++ 0);
++ dm_write_reg(compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0);
++
++ if (compressor->options.bits.LPT_SUPPORT) {
++ uint32_t lpt_alignment = lpt_size_alignment(cp110);
++
++ if (lpt_alignment != 0) {
++ compressed_surf_address_low_part =
++ ((compressed_surf_address_low_part
++ + (lpt_alignment - 1)) / lpt_alignment)
++ * lpt_alignment;
++ }
++ }
++
++ /* Write address, HIGH has to be first. */
++ dm_write_reg(compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
++ compressor->compr_surface_address.addr.high_part);
++ dm_write_reg(compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS),
++ compressed_surf_address_low_part);
++
++ fbc_pitch = align_to_chunks_number_per_line(
++ cp110,
++ params->source_view_width);
++
++ if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1)
++ fbc_pitch = fbc_pitch / 8;
++ else
++ dal_logger_write(
++ compressor->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Unexpected DCE11 compression ratio",
++ __func__);
++
++ /* Clear content first. */
++ dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0);
++
++ /* Write FBC Pitch. */
++ set_reg_field_value(
++ value,
++ fbc_pitch,
++ GRPH_COMPRESS_PITCH,
++ GRPH_COMPRESS_PITCH);
++ dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value);
++
++}
++
++void dce112_compressor_disable_lpt(struct compressor *compressor)
++{
++ struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
++ uint32_t value;
++ uint32_t addr;
++ uint32_t inx;
++
++ /* Disable all pipes LPT Stutter */
++ for (inx = 0; inx < 3; inx++) {
++ value =
++ dm_read_reg(
++ compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH));
++ set_reg_field_value(
++ value,
++ 0,
++ DPG_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dm_write_reg(
++ compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH),
++ value);
++ }
++ /* Disable Underlay pipe LPT Stutter */
++ addr = mmDPGV0_PIPE_STUTTER_CONTROL_NONLPTCH;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 0,
++ DPGV0_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ /* Disable LPT */
++ addr = mmLOW_POWER_TILING_CONTROL;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ENABLE);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ /* Clear selection of Channel(s) containing Compressed Surface */
++ addr = mmGMCON_LPT_TARGET;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 0xFFFFFFFF,
++ GMCON_LPT_TARGET,
++ STCTRL_LPT_TARGET);
++ dm_write_reg(compressor->ctx, mmGMCON_LPT_TARGET, value);
++}
++
++void dce112_compressor_enable_lpt(struct compressor *compressor)
++{
++ struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
++ uint32_t value;
++ uint32_t addr;
++ uint32_t value_control;
++ uint32_t channels;
++
++ /* Enable LPT Stutter from Display pipe */
++ value = dm_read_reg(compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH));
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dm_write_reg(compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH), value);
++
++ /* Enable Underlay pipe LPT Stutter */
++ addr = mmDPGV0_PIPE_STUTTER_CONTROL_NONLPTCH;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPGV0_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ /* Selection of Channel(s) containing Compressed Surface: 0xfffffff
++ * will disable LPT.
++ * STCTRL_LPT_TARGETn corresponds to channel n. */
++ addr = mmLOW_POWER_TILING_CONTROL;
++ value_control = dm_read_reg(compressor->ctx, addr);
++ channels = get_reg_field_value(value_control,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_MODE);
++
++ addr = mmGMCON_LPT_TARGET;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ channels + 1, /* not mentioned in programming guide,
++ but follow DCE8.1 */
++ GMCON_LPT_TARGET,
++ STCTRL_LPT_TARGET);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ /* Enable LPT */
++ addr = mmLOW_POWER_TILING_CONTROL;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ENABLE);
++ dm_write_reg(compressor->ctx, addr, value);
++}
++
++void dce112_compressor_program_lpt_control(
++ struct compressor *compressor,
++ struct compr_addr_and_pitch_params *params)
++{
++ struct dce112_compressor *cp110 = TO_DCE112_COMPRESSOR(compressor);
++ uint32_t rows_per_channel;
++ uint32_t lpt_alignment;
++ uint32_t source_view_width;
++ uint32_t source_view_height;
++ uint32_t lpt_control = 0;
++
++ if (!compressor->options.bits.LPT_SUPPORT)
++ return;
++
++ lpt_control = dm_read_reg(compressor->ctx,
++ mmLOW_POWER_TILING_CONTROL);
++
++ /* POSSIBLE VALUES for Low Power Tiling Mode:
++ * 00 - Use channel 0
++ * 01 - Use Channel 0 and 1
++ * 02 - Use Channel 0,1,2,3
++ * 03 - reserved */
++ switch (compressor->lpt_channels_num) {
++ /* case 2:
++ * Use Channel 0 & 1 / Not used for DCE 11 */
++ case 1:
++ /*Use Channel 0 for LPT for DCE 11 */
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_MODE);
++ break;
++ default:
++ dal_logger_write(
++ compressor->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid selected DRAM channels for LPT!!!",
++ __func__);
++ break;
++ }
++
++ lpt_control = lpt_memory_control_config(cp110, lpt_control);
++
++ /* Program LOW_POWER_TILING_ROWS_PER_CHAN field which depends on
++ * FBC compressed surface pitch.
++ * LOW_POWER_TILING_ROWS_PER_CHAN = Roundup ((Surface Height *
++ * Surface Pitch) / (Row Size * Number of Channels *
++ * Number of Banks)). */
++ rows_per_channel = 0;
++ lpt_alignment = lpt_size_alignment(cp110);
++ source_view_width =
++ align_to_chunks_number_per_line(
++ cp110,
++ params->source_view_width);
++ source_view_height = (params->source_view_height + 1) & (~0x1);
++
++ if (lpt_alignment != 0) {
++ rows_per_channel = source_view_width * source_view_height * 4;
++ rows_per_channel =
++ (rows_per_channel % lpt_alignment) ?
++ (rows_per_channel / lpt_alignment + 1) :
++ rows_per_channel / lpt_alignment;
++ }
++
++ set_reg_field_value(
++ lpt_control,
++ rows_per_channel,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROWS_PER_CHAN);
++
++ dm_write_reg(compressor->ctx,
++ mmLOW_POWER_TILING_CONTROL, lpt_control);
++}
++
++/*
++ * DCE 11 Frame Buffer Compression Implementation
++ */
++
++void dce112_compressor_set_fbc_invalidation_triggers(
++ struct compressor *compressor,
++ uint32_t fbc_trigger)
++{
++ /* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19)
++ * for DCE 11 regions cannot be used - does not work with S/G
++ */
++ uint32_t addr = mmFBC_CLIENT_REGION_MASK;
++ uint32_t value = dm_read_reg(compressor->ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ FBC_CLIENT_REGION_MASK,
++ FBC_MEMORY_REGION_MASK);
++ dm_write_reg(compressor->ctx, addr, value);
++
++ /* Setup events when to clear all CSM entries (effectively marking
++ * current compressed data invalid)
++ * For DCE 11 CSM metadata 11111 means - "Not Compressed"
++ * Used as the initial value of the metadata sent to the compressor
++ * after invalidation, to indicate that the compressor should attempt
++ * to compress all chunks on the current pass. Also used when the chunk
++ * is not successfully written to memory.
++ * When this CSM value is detected, FBC reads from the uncompressed
++ * buffer. Set events according to passed in value, these events are
++ * valid for DCE11:
++ * - bit 0 - display register updated
++ * - bit 28 - memory write from any client except from MCIF
++ * - bit 29 - CG static screen signal is inactive
++ * In addition, DCE11.1 also needs to set new DCE11.1 specific events
++ * that are used to trigger invalidation on certain register changes,
++ * for example enabling of Alpha Compression may trigger invalidation of
++ * FBC once bit is set. These events are as follows:
++ * - Bit 2 - FBC_GRPH_COMP_EN register updated
++ * - Bit 3 - FBC_SRC_SEL register updated
++ * - Bit 4 - FBC_MIN_COMPRESSION register updated
++ * - Bit 5 - FBC_ALPHA_COMP_EN register updated
++ * - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated
++ * - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated
++ */
++ addr = mmFBC_IDLE_FORCE_CLEAR_MASK;
++ value = dm_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ fbc_trigger |
++ FBC_IDLE_FORCE_GRPH_COMP_EN |
++ FBC_IDLE_FORCE_SRC_SEL_CHANGE |
++ FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE |
++ FBC_IDLE_FORCE_ALPHA_COMP_EN |
++ FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN |
++ FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF,
++ FBC_IDLE_FORCE_CLEAR_MASK,
++ FBC_IDLE_FORCE_CLEAR_MASK);
++ dm_write_reg(compressor->ctx, addr, value);
++}
++
++bool dce112_compressor_construct(struct dce112_compressor *compressor,
++ struct dc_context *ctx, struct adapter_service *as)
++{
++ struct embedded_panel_info panel_info;
++
++ compressor->base.options.bits.FBC_SUPPORT = true;
++ if (!(dal_adapter_service_is_feature_supported(
++ FEATURE_DISABLE_LPT_SUPPORT)))
++ compressor->base.options.bits.LPT_SUPPORT = true;
++ /* For DCE 11 always use one DRAM channel for LPT */
++ compressor->base.lpt_channels_num = 1;
++
++ if (dal_adapter_service_is_feature_supported(FEATURE_DUMMY_FBC_BACKEND))
++ compressor->base.options.bits.DUMMY_BACKEND = true;
++
++ /* Check if this system has more than 1 DRAM channel; if only 1 then LPT
++ * should not be supported */
++ if (compressor->base.memory_bus_width == 64)
++ compressor->base.options.bits.LPT_SUPPORT = false;
++
++ if (dal_adapter_service_is_feature_supported(
++ FEATURE_DISABLE_FBC_COMP_CLK_GATE))
++ compressor->base.options.bits.CLK_GATING_DISABLED = true;
++
++ compressor->base.ctx = ctx;
++ compressor->base.embedded_panel_h_size = 0;
++ compressor->base.embedded_panel_v_size = 0;
++ compressor->base.memory_bus_width =
++ dal_adapter_service_get_asic_vram_bit_width(as);
++ compressor->base.allocated_size = 0;
++ compressor->base.preferred_requested_size = 0;
++ compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID;
++ compressor->base.options.raw = 0;
++ compressor->base.banks_num = 0;
++ compressor->base.raw_size = 0;
++ compressor->base.channel_interleave_size = 0;
++ compressor->base.dram_channels_num = 0;
++ compressor->base.lpt_channels_num = 0;
++ compressor->base.attached_inst = 0;
++ compressor->base.is_enabled = false;
++
++ if (dal_adapter_service_get_embedded_panel_info(as,
++ &panel_info)) {
++ compressor->base.embedded_panel_h_size =
++ panel_info.lcd_timing.horizontal_addressable;
++ compressor->base.embedded_panel_v_size =
++ panel_info.lcd_timing.vertical_addressable;
++ }
++ return true;
++}
++
++struct compressor *dce112_compressor_create(struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ struct dce112_compressor *cp110 =
++ dm_alloc(sizeof(struct dce112_compressor));
++
++ if (!cp110)
++ return NULL;
++
++ if (dce112_compressor_construct(cp110, ctx, as))
++ return &cp110->base;
++
++ BREAK_TO_DEBUGGER();
++ dm_free(cp110);
++ return NULL;
++}
++
++void dce112_compressor_destroy(struct compressor **compressor)
++{
++ dm_free(TO_DCE112_COMPRESSOR(*compressor));
++ *compressor = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h
+new file mode 100644
+index 0000000..bcf4480
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_compressor.h
+@@ -0,0 +1,84 @@
++/* 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_COMPRESSOR_DCE112_H__
++#define __DC_COMPRESSOR_DCE112_H__
++
++#include "../inc/compressor.h"
++
++#define TO_DCE112_COMPRESSOR(compressor)\
++ container_of(compressor, struct dce112_compressor, base)
++
++struct dce112_compressor_reg_offsets {
++ uint32_t dcp_offset;
++ uint32_t dmif_offset;
++};
++
++struct dce112_compressor {
++ struct compressor base;
++ struct dce112_compressor_reg_offsets offsets;
++};
++
++struct compressor *dce112_compressor_create(struct dc_context *ctx,
++ struct adapter_service *as);
++
++bool dce112_compressor_construct(struct dce112_compressor *cp110,
++ struct dc_context *ctx, struct adapter_service *as);
++
++void dce112_compressor_destroy(struct compressor **cp);
++
++/* FBC RELATED */
++void dce112_compressor_power_up_fbc(struct compressor *cp);
++
++void dce112_compressor_enable_fbc(struct compressor *cp, uint32_t paths_num,
++ struct compr_addr_and_pitch_params *params);
++
++void dce112_compressor_disable_fbc(struct compressor *cp);
++
++void dce112_compressor_set_fbc_invalidation_triggers(struct compressor *cp,
++ uint32_t fbc_trigger);
++
++void dce112_compressor_program_compressed_surface_address_and_pitch(
++ struct compressor *cp,
++ struct compr_addr_and_pitch_params *params);
++
++bool dce112_compressor_get_required_compressed_surface_size(
++ struct compressor *cp,
++ struct fbc_input_info *input_info,
++ struct fbc_requested_compressed_size *size);
++
++bool dce112_compressor_is_fbc_enabled_in_hw(struct compressor *cp,
++ uint32_t *fbc_mapped_crtc_id);
++
++/* LPT RELATED */
++void dce112_compressor_enable_lpt(struct compressor *cp);
++
++void dce112_compressor_disable_lpt(struct compressor *cp);
++
++void dce112_compressor_program_lpt_control(struct compressor *cp,
++ struct compr_addr_and_pitch_params *params);
++
++bool dce112_compressor_is_lpt_enabled_in_hw(struct compressor *cp);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c
+new file mode 100644
+index 0000000..b94130f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.c
+@@ -0,0 +1,178 @@
++/*
++ * 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 "dce112_hw_sequencer.h"
++
++#include "dce110/dce110_hw_sequencer.h"
++#include "gpu/dce112/dc_clock_gating_dce112.h"
++
++/* include DCE11.2 register header files */
++#include "dce/dce_11_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++
++static void dce112_crtc_switch_to_clk_src(
++ struct clock_source *clk_src, uint8_t crtc_inst)
++{
++ uint32_t pixel_rate_cntl_value;
++ uint32_t addr;
++
++ addr = mmCRTC0_PIXEL_RATE_CNTL + crtc_inst *
++ (mmCRTC1_PIXEL_RATE_CNTL - mmCRTC0_PIXEL_RATE_CNTL);
++
++ pixel_rate_cntl_value = dm_read_reg(clk_src->ctx, addr);
++
++ if (clk_src->id == CLOCK_SOURCE_ID_DP_DTO)
++ set_reg_field_value(pixel_rate_cntl_value, 1,
++ CRTC0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE);
++ else {
++ set_reg_field_value(pixel_rate_cntl_value,
++ 0,
++ CRTC0_PIXEL_RATE_CNTL,
++ DP_DTO0_ENABLE);
++
++ set_reg_field_value(pixel_rate_cntl_value,
++ clk_src->id - 1,
++ CRTC0_PIXEL_RATE_CNTL,
++ CRTC0_PIXEL_RATE_SOURCE);
++ }
++ dm_write_reg(clk_src->ctx, addr, pixel_rate_cntl_value);
++}
++
++static void dce112_init_pte(struct dc_context *ctx)
++{
++ uint32_t addr;
++ uint32_t value = 0;
++ uint32_t chunk_int = 0;
++ uint32_t chunk_mul = 0;
++
++ addr = mmUNP_DVMM_PTE_CONTROL;
++ value = dm_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DVMM_PTE_CONTROL,
++ DVMM_USE_SINGLE_PTE);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DVMM_PTE_CONTROL,
++ DVMM_PTE_BUFFER_MODE0);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DVMM_PTE_CONTROL,
++ DVMM_PTE_BUFFER_MODE1);
++
++ dm_write_reg(ctx, addr, value);
++
++ addr = mmDVMM_PTE_REQ;
++ value = dm_read_reg(ctx, addr);
++
++ chunk_int = get_reg_field_value(
++ value,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_INT);
++
++ chunk_mul = get_reg_field_value(
++ value,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
++
++ if (chunk_int != 0x4 || chunk_mul != 0x4) {
++
++ set_reg_field_value(
++ value,
++ 255,
++ DVMM_PTE_REQ,
++ MAX_PTEREQ_TO_ISSUE);
++
++ set_reg_field_value(
++ value,
++ 4,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_INT);
++
++ set_reg_field_value(
++ value,
++ 4,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
++
++ dm_write_reg(ctx, addr, value);
++ }
++}
++
++static bool dce112_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 (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
++ return true;
++
++ 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 (power_gating != PIPE_GATING_CONTROL_ENABLE)
++ dce112_init_pte(ctx);
++
++ if (bp_result == BP_RESULT_OK)
++ return true;
++ else
++ return false;
++}
++
++bool dce112_hw_sequencer_construct(struct core_dc *dc)
++{
++ /* All registers used by dce11.2 match those in dce11 in offset and
++ * structure
++ */
++ dce110_hw_sequencer_construct(dc);
++ dc->hwss.crtc_switch_to_clk_src = dce112_crtc_switch_to_clk_src;
++ dc->hwss.enable_display_power_gating = dce112_enable_display_power_gating;
++ dc->hwss.clock_gating_power_up = dal_dc_clock_gating_dce112_power_up;
++
++ return true;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_hw_sequencer.h
+new file mode 100644
+index 0000000..d96c582
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_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_DCE112_H__
++#define __DC_HWSS_DCE112_H__
++
++#include "core_types.h"
++
++struct core_dc;
++
++bool dce112_hw_sequencer_construct(struct core_dc *dc);
++
++#endif /* __DC_HWSS_DCE112_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c
+new file mode 100644
+index 0000000..23e127c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.c
+@@ -0,0 +1,116 @@
++/*
++ * 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 "core_types.h"
++#include "link_encoder.h"
++#include "stream_encoder.h"
++#include "dce112_link_encoder.h"
++#include "../dce110/dce110_link_encoder.h"
++#include "i2caux_interface.h"
++#include "dce/dce_11_2_sh_mask.h"
++
++/* For current ASICs pixel clock - 600MHz */
++#define MAX_ENCODER_CLK 600000
++
++#define DCE11_UNIPHY_MAX_PIXEL_CLK_IN_KHZ 600000
++
++#define DEFAULT_AUX_MAX_DATA_SIZE 16
++#define AUX_MAX_DEFER_WRITE_RETRY 20
++
++/* all values are in milliseconds */
++/* For eDP, after power-up/power/down,
++ * 300/500 msec max. delay from LCDVCC to black video generation */
++#define PANEL_POWER_UP_TIMEOUT 300
++#define PANEL_POWER_DOWN_TIMEOUT 500
++#define HPD_CHECK_INTERVAL 10
++
++/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
++#define TMDS_MIN_PIXEL_CLOCK 25000
++/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
++#define TMDS_MAX_PIXEL_CLOCK 165000
++/* For current ASICs pixel clock - 600MHz */
++#define MAX_ENCODER_CLOCK 600000
++
++enum {
++ DP_MST_UPDATE_MAX_RETRY = 50
++};
++
++static void dce112_link_encoder_dp_set_phy_pattern(
++ struct link_encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param)
++{
++ switch (param->dp_phy_pattern) {
++ case DP_TEST_PATTERN_TRAINING_PATTERN4:
++ dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 3);
++ break;
++ default:
++ dce110_link_encoder_dp_set_phy_pattern(enc, param);
++ break;
++ }
++}
++
++static struct link_encoder_funcs dce112_lnk_enc_funcs = {
++ .validate_output_with_stream =
++ dce110_link_encoder_validate_output_with_stream,
++ .hw_init = dce110_link_encoder_hw_init,
++ .setup = dce110_link_encoder_setup,
++ .enable_tmds_output = dce110_link_encoder_enable_tmds_output,
++ .enable_dp_output = dce110_link_encoder_enable_dp_output,
++ .enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output,
++ .disable_output = dce110_link_encoder_disable_output,
++ .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
++ .dp_set_phy_pattern = dce112_link_encoder_dp_set_phy_pattern,
++ .update_mst_stream_allocation_table =
++ dce110_link_encoder_update_mst_stream_allocation_table,
++ .set_lcd_backlight_level = dce110_link_encoder_set_lcd_backlight_level,
++ .backlight_control = dce110_link_encoder_edp_backlight_control,
++ .power_control = dce110_link_encoder_edp_power_control,
++ .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe,
++ .destroy = dce110_link_encoder_destroy
++};
++
++bool dce112_link_encoder_construct(
++ struct dce110_link_encoder *enc110,
++ const struct encoder_init_data *init_data,
++ const struct dce110_link_enc_registers *link_regs,
++ const struct dce110_link_enc_aux_registers *aux_regs,
++ const struct dce110_link_enc_bl_registers *bl_regs)
++{
++ dce110_link_encoder_construct(
++ enc110,
++ init_data,
++ link_regs,
++ aux_regs,
++ bl_regs);
++
++ enc110->base.funcs = &dce112_lnk_enc_funcs;
++
++ enc110->base.features.flags.bits.IS_HBR3_CAPABLE = true;
++
++ enc110->base.features.flags.bits.IS_TPS4_CAPABLE = true;
++
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h
+new file mode 100644
+index 0000000..cfc9cc5
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_link_encoder.h
+@@ -0,0 +1,41 @@
++/*
++ * 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_LINK_ENCODER__DCE112_H__
++#define __DC_LINK_ENCODER__DCE112_H__
++
++#include "link_encoder.h"
++#include "../dce110/dce110_link_encoder.h"
++
++bool dce112_link_encoder_construct(
++ struct dce110_link_encoder *enc110,
++ const struct encoder_init_data *init_data,
++ const struct dce110_link_enc_registers *link_regs,
++ const struct dce110_link_enc_aux_registers *aux_regs,
++ const struct dce110_link_enc_bl_registers *bl_regs);
++
++/****************** HW programming ************************/
++
++#endif /* __DC_LINK_ENCODER__DCE112_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c
+new file mode 100644
+index 0000000..823849e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.c
+@@ -0,0 +1,455 @@
++/*
++ * 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 "dce112_mem_input.h"
++
++
++#include "dce/dce_11_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++
++
++#define DCP_REG(reg) (reg + mem_input110->offsets.dcp)
++#define DMIF_REG(reg) (reg + mem_input110->offsets.dmif)
++#define PIPE_REG(reg) (reg + mem_input110->offsets.pipe)
++
++static void program_urgency_watermark(
++ const struct dc_context *ctx,
++ const uint32_t offset,
++ struct bw_watermarks marks_low,
++ uint32_t total_dest_line_time_ns)
++{
++ /* register value */
++ uint32_t urgency_cntl = 0;
++ uint32_t wm_mask_cntl = 0;
++
++ uint32_t urgency_addr = offset + mmDPG_PIPE_URGENCY_CONTROL;
++ uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++
++ /*Write mask to enable reading/writing of watermark set A*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 0,
++ DPG_WATERMARK_MASK_CONTROL,
++ URGENCY_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ urgency_cntl = dm_read_reg(ctx, urgency_addr);
++
++ set_reg_field_value(
++ urgency_cntl,
++ marks_low.a_mark,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_LOW_WATERMARK);
++
++ set_reg_field_value(
++ urgency_cntl,
++ total_dest_line_time_ns,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_HIGH_WATERMARK);
++ dm_write_reg(ctx, urgency_addr, urgency_cntl);
++
++ /*Write mask to enable reading/writing of watermark set B*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 1,
++ DPG_WATERMARK_MASK_CONTROL,
++ URGENCY_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ urgency_cntl = dm_read_reg(ctx, urgency_addr);
++
++ set_reg_field_value(urgency_cntl,
++ marks_low.b_mark,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_LOW_WATERMARK);
++
++ set_reg_field_value(urgency_cntl,
++ total_dest_line_time_ns,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_HIGH_WATERMARK);
++ dm_write_reg(ctx, urgency_addr, urgency_cntl);
++
++ /*Write mask to enable reading/writing of watermark set C*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 2,
++ DPG_WATERMARK_MASK_CONTROL,
++ URGENCY_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ urgency_cntl = dm_read_reg(ctx, urgency_addr);
++
++ set_reg_field_value(urgency_cntl,
++ marks_low.c_mark,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_LOW_WATERMARK);
++
++ set_reg_field_value(urgency_cntl,
++ total_dest_line_time_ns,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_HIGH_WATERMARK);
++ dm_write_reg(ctx, urgency_addr, urgency_cntl);
++
++ /*Write mask to enable reading/writing of watermark set D*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 3,
++ DPG_WATERMARK_MASK_CONTROL,
++ URGENCY_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ urgency_cntl = dm_read_reg(ctx, urgency_addr);
++
++ set_reg_field_value(urgency_cntl,
++ marks_low.d_mark,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_LOW_WATERMARK);
++
++ set_reg_field_value(urgency_cntl,
++ total_dest_line_time_ns,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_HIGH_WATERMARK);
++ dm_write_reg(ctx, urgency_addr, urgency_cntl);
++}
++
++static void program_stutter_watermark(
++ const struct dc_context *ctx,
++ const uint32_t offset,
++ struct bw_watermarks marks)
++{
++ /* register value */
++ uint32_t stutter_cntl = 0;
++ uint32_t wm_mask_cntl = 0;
++
++ uint32_t stutter_addr = offset + mmDPG_PIPE_STUTTER_CONTROL;
++ uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++
++ /*Write mask to enable reading/writing of watermark set A*/
++
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 0,
++ DPG_WATERMARK_MASK_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ stutter_cntl = dm_read_reg(ctx, stutter_addr);
++
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_ENABLE);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_IGNORE_FBC);
++
++ /*Write watermark set A*/
++ set_reg_field_value(stutter_cntl,
++ marks.a_mark,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK);
++ dm_write_reg(ctx, stutter_addr, stutter_cntl);
++
++ /*Write mask to enable reading/writing of watermark set B*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 1,
++ DPG_WATERMARK_MASK_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ stutter_cntl = dm_read_reg(ctx, stutter_addr);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_ENABLE);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_IGNORE_FBC);
++
++ /*Write watermark set B*/
++ set_reg_field_value(stutter_cntl,
++ marks.b_mark,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK);
++ dm_write_reg(ctx, stutter_addr, stutter_cntl);
++
++ /*Write mask to enable reading/writing of watermark set C*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 2,
++ DPG_WATERMARK_MASK_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ stutter_cntl = dm_read_reg(ctx, stutter_addr);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_ENABLE);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_IGNORE_FBC);
++
++ /*Write watermark set C*/
++ set_reg_field_value(stutter_cntl,
++ marks.c_mark,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK);
++ dm_write_reg(ctx, stutter_addr, stutter_cntl);
++
++ /*Write mask to enable reading/writing of watermark set D*/
++ wm_mask_cntl = dm_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 3,
++ DPG_WATERMARK_MASK_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
++ dm_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ stutter_cntl = dm_read_reg(ctx, stutter_addr);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_ENABLE);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_IGNORE_FBC);
++
++ /*Write watermark set D*/
++ set_reg_field_value(stutter_cntl,
++ marks.d_mark,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK);
++ dm_write_reg(ctx, stutter_addr, stutter_cntl);
++}
++
++static void program_nbp_watermark(
++ const struct dc_context *ctx,
++ const uint32_t offset,
++ struct bw_watermarks marks)
++{
++ uint32_t value;
++ uint32_t addr;
++ /* Write mask to enable reading/writing of watermark set A */
++ addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 0,
++ DPG_WATERMARK_MASK_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK_MASK);
++ dm_write_reg(ctx, addr, value);
++
++ addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_ENABLE);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write watermark set A */
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ marks.a_mark,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write mask to enable reading/writing of watermark set B */
++ addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_WATERMARK_MASK_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK_MASK);
++ dm_write_reg(ctx, addr, value);
++
++ addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_ENABLE);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write watermark set B */
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ marks.b_mark,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write mask to enable reading/writing of watermark set C */
++ addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 2,
++ DPG_WATERMARK_MASK_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK_MASK);
++ dm_write_reg(ctx, addr, value);
++
++ addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_ENABLE);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write watermark set C */
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ marks.c_mark,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write mask to enable reading/writing of watermark set D */
++ addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 3,
++ DPG_WATERMARK_MASK_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK_MASK);
++ dm_write_reg(ctx, addr, value);
++
++ addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_ENABLE);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
++ dm_write_reg(ctx, addr, value);
++
++ /* Write watermark set D */
++ value = dm_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ marks.d_mark,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK);
++ dm_write_reg(ctx, addr, value);
++}
++
++static void dce112_mem_input_program_display_marks(
++ struct mem_input *mem_input,
++ struct bw_watermarks nbp,
++ struct bw_watermarks stutter,
++ struct bw_watermarks urgent,
++ uint32_t total_dest_line_time_ns)
++{
++ struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mem_input);
++
++ program_urgency_watermark(
++ mem_input->ctx,
++ bm_dce110->offsets.dmif,
++ urgent,
++ total_dest_line_time_ns);
++
++ program_nbp_watermark(
++ mem_input->ctx,
++ bm_dce110->offsets.dmif,
++ nbp);
++
++ program_stutter_watermark(
++ mem_input->ctx,
++ bm_dce110->offsets.dmif,
++ stutter);
++}
++
++/*****************************************/
++/* Constructor, Destructor */
++/*****************************************/
++
++bool dce112_mem_input_construct(
++ struct dce110_mem_input *mem_input110,
++ struct dc_context *ctx,
++ uint32_t inst,
++ const struct dce110_mem_input_reg_offsets *offsets)
++{
++ if (!dce110_mem_input_construct(mem_input110, ctx, inst, offsets))
++ return false;
++
++ mem_input110->base.funcs->mem_input_program_display_marks =
++ dce112_mem_input_program_display_marks;
++
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h
+new file mode 100644
+index 0000000..de2aaf0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_mem_input.h
+@@ -0,0 +1,38 @@
++/* 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_MEM_INPUT_DCE112_H__
++#define __DC_MEM_INPUT_DCE112_H__
++
++#include "mem_input.h"
++#include "dce110/dce110_mem_input.h"
++
++bool dce112_mem_input_construct(
++ struct dce110_mem_input *mem_input110,
++ struct dc_context *ctx,
++ uint32_t inst,
++ const struct dce110_mem_input_reg_offsets *offsets);
++
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c
+new file mode 100644
+index 0000000..420b8ca
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.c
+@@ -0,0 +1,1404 @@
++/*
++* 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 "dce112/dce112_mem_input.h"
++#include "dce112/dce112_link_encoder.h"
++#include "dce110/dce110_link_encoder.h"
++#include "dce110/dce110_transform.h"
++#include "dce110/dce110_stream_encoder.h"
++#include "dce110/dce110_opp.h"
++#include "dce110/dce110_ipp.h"
++#include "dce112/dce112_clock_source.h"
++
++#include "dce/dce_11_2_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 dce112_clk_src_array_id {
++ DCE112_CLK_SRC_PLL0,
++ DCE112_CLK_SRC_PLL1,
++ DCE112_CLK_SRC_PLL2,
++ DCE112_CLK_SRC_PLL3,
++ DCE112_CLK_SRC_PLL4,
++ DCE112_CLK_SRC_PLL5,
++
++ DCE112_CLK_SRC_TOTAL
++};
++
++static const struct dce110_transform_reg_offsets dce112_xfm_offsets[] = {
++{
++ .scl_offset = (mmSCL0_SCL_CONTROL - mmSCL_CONTROL),
++ .dcfe_offset = (mmDCFE0_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 = (mmDCFE1_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 = (mmDCFE2_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 = (mmDCFE3_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 = (mmDCFE4_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 = (mmDCFE5_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_timing_generator_offsets dce112_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 dce112_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_ipp_reg_offsets 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)
++};
++
++#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)
++};
++
++static const struct dce110_opp_reg_offsets dce112_opp_reg_offsets[] = {
++{
++ .fmt_offset = (mmFMT0_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE0_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{ .fmt_offset = (mmFMT1_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE1_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{ .fmt_offset = (mmFMT2_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE2_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{
++ .fmt_offset = (mmFMT3_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE3_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{ .fmt_offset = (mmFMT4_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE4_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{ .fmt_offset = (mmFMT5_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE5_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++}
++};
++
++static const struct dce112_clk_src_reg_offsets dce112_clk_src_reg_offsets[] = {
++ {
++ .pixclk_resync_cntl = mmPHYPLLA_PIXCLK_RESYNC_CNTL
++ },
++ {
++ .pixclk_resync_cntl = mmPHYPLLB_PIXCLK_RESYNC_CNTL
++ },
++ {
++ .pixclk_resync_cntl = mmPHYPLLC_PIXCLK_RESYNC_CNTL
++ },
++ {
++ .pixclk_resync_cntl = mmPHYPLLD_PIXCLK_RESYNC_CNTL
++ },
++ {
++ .pixclk_resync_cntl = mmPHYPLLE_PIXCLK_RESYNC_CNTL
++ },
++ {
++ .pixclk_resync_cntl = mmPHYPLLF_PIXCLK_RESYNC_CNTL
++ }
++};
++
++static struct timing_generator *dce112_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(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(tg110);
++ return NULL;
++}
++
++static struct stream_encoder *dce112_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(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(enc110);
++ return NULL;
++}
++
++static struct mem_input *dce112_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(sizeof(struct dce110_mem_input));
++
++ if (!mem_input110)
++ return NULL;
++
++ if (dce112_mem_input_construct(mem_input110,
++ ctx, inst, offset))
++ return &mem_input110->base;
++
++ BREAK_TO_DEBUGGER();
++ dm_free(mem_input110);
++ return NULL;
++}
++
++static void dce112_transform_destroy(struct transform **xfm)
++{
++ dm_free(TO_DCE110_TRANSFORM(*xfm));
++ *xfm = NULL;
++}
++
++static struct transform *dce112_transform_create(
++ struct dc_context *ctx,
++ uint32_t inst,
++ const struct dce110_transform_reg_offsets *offsets)
++{
++ struct dce110_transform *transform =
++ dm_alloc(sizeof(struct dce110_transform));
++
++ if (!transform)
++ return NULL;
++
++ if (dce110_transform_construct(transform, ctx, inst, offsets))
++ return &transform->base;
++
++ BREAK_TO_DEBUGGER();
++ dm_free(transform);
++ return NULL;
++}
++struct link_encoder *dce112_link_encoder_create(
++ const struct encoder_init_data *enc_init_data)
++{
++ struct dce110_link_encoder *enc110 =
++ dm_alloc(sizeof(struct dce110_link_encoder));
++
++ if (!enc110)
++ return NULL;
++
++ if (dce112_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(enc110);
++ return NULL;
++}
++
++struct input_pixel_processor *dce112_ipp_create(
++ struct dc_context *ctx,
++ uint32_t inst,
++ const struct dce110_ipp_reg_offsets *offset)
++{
++ struct dce110_ipp *ipp =
++ dm_alloc(sizeof(struct dce110_ipp));
++
++ if (!ipp)
++ return NULL;
++
++ if (dce110_ipp_construct(ipp, ctx, inst, offset))
++ return &ipp->base;
++
++ BREAK_TO_DEBUGGER();
++ dm_free(ipp);
++ return NULL;
++}
++
++void dce112_ipp_destroy(struct input_pixel_processor **ipp)
++{
++ dm_free(TO_DCE110_IPP(*ipp));
++ *ipp = NULL;
++}
++
++struct output_pixel_processor *dce112_opp_create(
++ struct dc_context *ctx,
++ uint32_t inst,
++ const struct dce110_opp_reg_offsets *offset)
++{
++ struct dce110_opp *opp =
++ dm_alloc(sizeof(struct dce110_opp));
++
++ if (!opp)
++ return NULL;
++
++ if (dce110_opp_construct(opp,
++ ctx, inst, offset))
++ return &opp->base;
++
++ BREAK_TO_DEBUGGER();
++ dm_free(opp);
++ return NULL;
++}
++
++void dce112_opp_destroy(struct output_pixel_processor **opp)
++{
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.coeff128_dx);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.coeff128_oem);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.coeff128);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.axis_x_1025);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.axis_x_256);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.coordinates_x);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_regamma);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_resulted);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_oem);
++ dm_free(FROM_DCE11_OPP(*opp)->regamma.rgb_user);
++ dm_free(FROM_DCE11_OPP(*opp));
++ *opp = NULL;
++}
++
++struct clock_source *dce112_clock_source_create(
++ struct dc_context *ctx,
++ struct dc_bios *bios,
++ enum clock_source_id id,
++ const struct dce112_clk_src_reg_offsets *offsets)
++{
++ struct dce112_clk_src *clk_src =
++ dm_alloc(sizeof(struct dce112_clk_src));
++
++ if (!clk_src)
++ return NULL;
++
++ if (dce112_clk_src_construct(clk_src, ctx, bios, id, offsets))
++ return &clk_src->base;
++
++ BREAK_TO_DEBUGGER();
++ return NULL;
++}
++
++void dce112_clock_source_destroy(struct clock_source **clk_src)
++{
++ dm_free(TO_DCE112_CLK_SRC(*clk_src));
++ *clk_src = NULL;
++}
++
++void dce112_destruct_resource_pool(struct resource_pool *pool)
++{
++ unsigned int i;
++
++ for (i = 0; i < pool->pipe_count; i++) {
++ if (pool->opps[i] != NULL)
++ dce112_opp_destroy(&pool->opps[i]);
++
++ if (pool->transforms[i] != NULL)
++ dce112_transform_destroy(&pool->transforms[i]);
++
++ if (pool->ipps[i] != NULL)
++ dce112_ipp_destroy(&pool->ipps[i]);
++
++ if (pool->mis[i] != NULL) {
++ dm_free(TO_DCE110_MEM_INPUT(pool->mis[i]));
++ pool->mis[i] = NULL;
++ }
++
++ if (pool->timing_generators[i] != NULL) {
++ dm_free(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(DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
++ }
++
++ for (i = 0; i < pool->clk_src_count; i++) {
++ if (pool->clock_sources[i] != NULL) {
++ dce112_clock_source_destroy(&pool->clock_sources[i]);
++ }
++ }
++
++ if (pool->dp_clock_source != NULL)
++ dce112_clock_source_destroy(&pool->dp_clock_source);
++
++ 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_matching_pll(struct resource_context *res_ctx,
++ const struct core_stream *const stream)
++{
++ switch (stream->sink->link->link_enc->transmitter) {
++ case TRANSMITTER_UNIPHY_A:
++ return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL0];
++ case TRANSMITTER_UNIPHY_B:
++ return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL1];
++ case TRANSMITTER_UNIPHY_C:
++ return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL2];
++ case TRANSMITTER_UNIPHY_D:
++ return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL3];
++ case TRANSMITTER_UNIPHY_E:
++ return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL4];
++ case TRANSMITTER_UNIPHY_F:
++ return res_ctx->pool.clock_sources[DCE112_CLK_SRC_PLL5];
++ default:
++ return NULL;
++ };
++
++ 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 pipe_ctx *pipe_ctx,
++ struct audio_output *audio_output)
++{
++ const struct core_stream *stream = pipe_ctx->stream;
++ audio_output->engine_id = pipe_ctx->stream_enc->id;
++
++ audio_output->signal = pipe_ctx->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 =
++ pipe_ctx->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 =
++ pipe_ctx->pix_clk_params.requested_pix_clk;
++
++ if (pipe_ctx->signal == SIGNAL_TYPE_DISPLAY_PORT ||
++ pipe_ctx->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
++ audio_output->pll_info.dp_dto_source_clock_in_khz =
++ dal_display_clock_get_dp_ref_clk_frequency(
++ pipe_ctx->dis_clk);
++ }
++
++ audio_output->pll_info.feed_back_divider =
++ pipe_ctx->pll_settings.feedback_divider;
++
++ audio_output->pll_info.dto_source =
++ translate_to_dto_source(
++ pipe_ctx->pipe_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 =
++ pipe_ctx->pll_settings.ss_percentage;
++}
++
++static void get_pixel_clock_parameters(
++ const struct pipe_ctx *pipe_ctx,
++ struct pixel_clk_params *pixel_clk_params)
++{
++ const struct core_stream *stream = pipe_ctx->stream;
++ 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 = pipe_ctx->pipe_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_pipe_hw_param(struct pipe_ctx *pipe_ctx)
++{
++ /*TODO: unhardcode*/
++ pipe_ctx->max_tmds_clk_from_edid_in_mhz = 0;
++ pipe_ctx->max_hdmi_deep_color = COLOR_DEPTH_121212;
++ pipe_ctx->max_hdmi_pixel_clock = 600000;
++
++ get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->pix_clk_params);
++ pipe_ctx->clock_source->funcs->get_pix_clk_dividers(
++ pipe_ctx->clock_source,
++ &pipe_ctx->pix_clk_params,
++ &pipe_ctx->pll_settings);
++
++ build_audio_output(pipe_ctx, &pipe_ctx->audio_output);
++
++ return DC_OK;
++}
++
++static enum dc_status validate_mapped_resource(
++ const struct core_dc *dc,
++ struct validate_context *context)
++{
++ enum dc_status status = DC_OK;
++ uint8_t i, j, k;
++
++ 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;
++
++ for (k = 0; k < MAX_PIPES; k++) {
++ struct pipe_ctx *pipe_ctx =
++ &context->res_ctx.pipe_ctx[k];
++
++ if (context->res_ctx.pipe_ctx[k].stream != stream)
++ continue;
++
++ if (!pipe_ctx->tg->funcs->validate_timing(
++ pipe_ctx->tg, &stream->public.timing))
++ return DC_FAIL_CONTROLLER_VALIDATE;
++
++ status = build_pipe_hw_param(pipe_ctx);
++
++ if (status != DC_OK)
++ return status;
++
++ if (!link->link_enc->funcs->validate_output_with_stream(
++ link->link_enc,
++ pipe_ctx))
++ 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;
++
++ resource_build_info_frame(pipe_ctx);
++
++ /* do not need to validate non root pipes */
++ break;
++ }
++ }
++ }
++
++ return DC_OK;
++}
++
++enum dc_status dce112_validate_bandwidth(
++ const struct core_dc *dc,
++ struct validate_context *context)
++{
++ uint8_t i;
++ enum dc_status result = DC_ERROR_UNEXPECTED;
++ uint8_t number_of_displays = 0;
++ uint8_t max_htaps = 1;
++ uint8_t max_vtaps = 1;
++ bool all_displays_in_sync = true;
++ struct dc_crtc_timing prev_timing;
++
++ memset(&context->bw_mode_data, 0, sizeof(context->bw_mode_data));
++
++ for (i = 0; i < MAX_PIPES; i++) {
++ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
++ struct bw_calcs_input_single_display *disp = &context->
++ bw_mode_data.displays_data[number_of_displays];
++
++ if (pipe_ctx->stream == NULL)
++ continue;
++
++ if (pipe_ctx->scl_data.ratios.vert.value == 0) {
++ disp->graphics_scale_ratio = bw_int_to_fixed(1);
++ disp->graphics_h_taps = 2;
++ disp->graphics_v_taps = 2;
++
++ /* TODO: remove when bw formula accepts taps per
++ * display
++ */
++ if (max_vtaps < 2)
++ max_vtaps = 2;
++ if (max_htaps < 2)
++ max_htaps = 2;
++
++ } else {
++ disp->graphics_scale_ratio =
++ fixed31_32_to_bw_fixed(
++ pipe_ctx->scl_data.ratios.vert.value);
++ disp->graphics_h_taps = pipe_ctx->scl_data.taps.h_taps;
++ disp->graphics_v_taps = pipe_ctx->scl_data.taps.v_taps;
++
++ /* TODO: remove when bw formula accepts taps per
++ * display
++ */
++ if (max_vtaps < pipe_ctx->scl_data.taps.v_taps)
++ max_vtaps = pipe_ctx->scl_data.taps.v_taps;
++ if (max_htaps < pipe_ctx->scl_data.taps.h_taps)
++ max_htaps = pipe_ctx->scl_data.taps.h_taps;
++ }
++
++ disp->graphics_src_width =
++ pipe_ctx->stream->public.timing.h_addressable;
++ disp->graphics_src_height =
++ pipe_ctx->stream->public.timing.v_addressable;
++ disp->h_total = pipe_ctx->stream->public.timing.h_total;
++ disp->pixel_rate = bw_frc_to_fixed(
++ pipe_ctx->stream->public.timing.pix_clk_khz, 1000);
++
++ /*TODO: get from surface*/
++ disp->graphics_bytes_per_pixel = 4;
++ disp->graphics_tiling_mode = bw_def_tiled;
++
++ /* DCE11 defaults*/
++ disp->graphics_lb_bpc = 10;
++ disp->graphics_interlace_mode = false;
++ disp->fbc_enable = false;
++ disp->lpt_enable = false;
++ disp->graphics_stereo_mode = bw_def_mono;
++ disp->underlay_mode = bw_def_none;
++
++ /*All displays will be synchronized if timings are all
++ * the same
++ */
++ if (number_of_displays != 0 && all_displays_in_sync)
++ if (memcmp(&prev_timing,
++ &pipe_ctx->stream->public.timing,
++ sizeof(struct dc_crtc_timing)) != 0)
++ all_displays_in_sync = false;
++ if (number_of_displays == 0)
++ prev_timing = pipe_ctx->stream->public.timing;
++
++ number_of_displays++;
++ }
++
++ /* TODO: remove when bw formula accepts taps per
++ * display
++ */
++ context->bw_mode_data.displays_data[0].graphics_v_taps = max_vtaps;
++ context->bw_mode_data.displays_data[0].graphics_h_taps = max_htaps;
++
++ context->bw_mode_data.number_of_displays = number_of_displays;
++ context->bw_mode_data.display_synchronization_enabled =
++ all_displays_in_sync;
++
++ dal_logger_write(
++ dc->ctx->logger,
++ LOG_MAJOR_BWM,
++ LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS,
++ "%s: start",
++ __func__);
++
++ if (!bw_calcs(
++ dc->ctx,
++ &dc->bw_dceip,
++ &dc->bw_vbios,
++ &context->bw_mode_data,
++ &context->bw_results))
++ result = DC_FAIL_BANDWIDTH_VALIDATE;
++ else
++ result = DC_OK;
++
++ if (result == DC_FAIL_BANDWIDTH_VALIDATE)
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_BWM,
++ LOG_MINOR_BWM_MODE_VALIDATION,
++ "%s: Bandwidth validation failed!",
++ __func__);
++
++ if (memcmp(&dc->current_context.bw_results,
++ &context->bw_results, sizeof(context->bw_results))) {
++ struct log_entry log_entry;
++ dal_logger_open(
++ dc->ctx->logger,
++ &log_entry,
++ LOG_MAJOR_BWM,
++ LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS);
++ dal_logger_append(&log_entry, "%s: finish, numDisplays: %d\n"
++ "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n"
++ "stutMark_b: %d stutMark_a: %d\n",
++ __func__, number_of_displays,
++ context->bw_results.nbp_state_change_wm_ns[0].b_mark,
++ context->bw_results.nbp_state_change_wm_ns[0].a_mark,
++ context->bw_results.urgent_wm_ns[0].b_mark,
++ context->bw_results.urgent_wm_ns[0].a_mark,
++ context->bw_results.stutter_exit_wm_ns[0].b_mark,
++ context->bw_results.stutter_exit_wm_ns[0].a_mark);
++ dal_logger_append(&log_entry,
++ "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n"
++ "stutMark_b: %d stutMark_a: %d\n",
++ context->bw_results.nbp_state_change_wm_ns[1].b_mark,
++ context->bw_results.nbp_state_change_wm_ns[1].a_mark,
++ context->bw_results.urgent_wm_ns[1].b_mark,
++ context->bw_results.urgent_wm_ns[1].a_mark,
++ context->bw_results.stutter_exit_wm_ns[1].b_mark,
++ context->bw_results.stutter_exit_wm_ns[1].a_mark);
++ dal_logger_append(&log_entry,
++ "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n"
++ "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n",
++ context->bw_results.nbp_state_change_wm_ns[2].b_mark,
++ context->bw_results.nbp_state_change_wm_ns[2].a_mark,
++ context->bw_results.urgent_wm_ns[2].b_mark,
++ context->bw_results.urgent_wm_ns[2].a_mark,
++ context->bw_results.stutter_exit_wm_ns[2].b_mark,
++ context->bw_results.stutter_exit_wm_ns[2].a_mark,
++ context->bw_results.stutter_mode_enable);
++ dal_logger_append(&log_entry,
++ "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n"
++ "sclk: %d sclk_sleep: %d yclk: %d blackout_duration: %d\n",
++ context->bw_results.cpuc_state_change_enable,
++ context->bw_results.cpup_state_change_enable,
++ context->bw_results.nbp_state_change_enable,
++ context->bw_results.all_displays_in_sync,
++ context->bw_results.dispclk_khz,
++ context->bw_results.required_sclk,
++ context->bw_results.required_sclk_deep_sleep,
++ context->bw_results.required_yclk,
++ context->bw_results.required_blackout_duration_us);
++ dal_logger_close(&log_entry);
++ }
++ return result;
++}
++
++static void set_target_unchanged(
++ struct validate_context *context,
++ uint8_t target_idx)
++{
++ uint8_t i, j;
++ 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 *stream =
++ DC_STREAM_TO_CORE(target->public.streams[i]);
++ for (j = 0; j < MAX_PIPES; j++) {
++ if (context->res_ctx.pipe_ctx[j].stream == stream)
++ context->res_ctx.pipe_ctx[j].flags.unchanged =
++ true;
++ }
++ }
++}
++
++static enum dc_status map_clock_resources(
++ const struct core_dc *dc,
++ struct validate_context *context)
++{
++ uint8_t i, j, k;
++
++ /* 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]);
++
++ for (k = 0; k < MAX_PIPES; k++) {
++ struct pipe_ctx *pipe_ctx =
++ &context->res_ctx.pipe_ctx[k];
++
++ if (context->res_ctx.pipe_ctx[k].stream != stream)
++ continue;
++
++ if (dc_is_dp_signal(pipe_ctx->signal)
++ || pipe_ctx->signal == SIGNAL_TYPE_VIRTUAL)
++ pipe_ctx->clock_source =
++ context->res_ctx.pool.dp_clock_source;
++ else
++ pipe_ctx->clock_source =
++ find_matching_pll(&context->res_ctx,
++ stream);
++
++ if (pipe_ctx->clock_source == NULL)
++ return DC_NO_CLOCK_SOURCE_RESOURCE;
++
++ resource_reference_clock_source(
++ &context->res_ctx,
++ pipe_ctx->clock_source);
++
++ /* only one cs per stream regardless of mpo */
++ break;
++ }
++ }
++ }
++
++ return DC_OK;
++}
++
++enum dc_status dce112_validate_with_context(
++ const struct core_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++) {
++ bool unchanged = false;
++
++ context->targets[i] = DC_TARGET_TO_CORE(set[i].target);
++ dc_target_retain(&context->targets[i]->public);
++ context->target_count++;
++
++ for (j = 0; j < dc->current_context.target_count; j++)
++ if (dc->current_context.targets[j]
++ == context->targets[i]) {
++ unchanged = true;
++ set_target_unchanged(context, i);
++ resource_attach_surfaces_to_context(
++ (struct dc_surface **)dc->current_context.
++ target_status[j].surfaces,
++ dc->current_context.target_status[j].surface_count,
++ &context->targets[i]->public,
++ context);
++ context->target_status[i] =
++ dc->current_context.target_status[j];
++ }
++ if (!unchanged || set[i].surface_count != 0)
++ if (!resource_attach_surfaces_to_context(
++ (struct dc_surface **)set[i].surfaces,
++ set[i].surface_count,
++ &context->targets[i]->public,
++ context)) {
++ DC_ERROR("Failed to attach surface to target!\n");
++ return DC_FAIL_ATTACH_SURFACES;
++ }
++ }
++
++ context->res_ctx.pool = dc->res_pool;
++
++ result = resource_map_pool_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)
++ resource_build_scaling_params_for_context(dc, context);
++
++ if (result == DC_OK)
++ result = dce112_validate_bandwidth(dc, context);
++
++ return result;
++}
++
++static struct resource_funcs dce112_res_pool_funcs = {
++ .destruct = dce112_destruct_resource_pool,
++ .link_enc_create = dce112_link_encoder_create,
++ .validate_with_context = dce112_validate_with_context,
++ .validate_bandwidth = dce112_validate_bandwidth
++};
++
++static void bw_calcs_data_update_from_pplib(struct core_dc *dc)
++{
++ struct dm_pp_clock_levels clks = {0};
++
++ /*do system clock*/
++ dm_pp_get_clock_levels_by_type(
++ dc->ctx,
++ DM_PP_CLOCK_TYPE_ENGINE_CLK,
++ &clks);
++ /* convert all the clock fro kHz to fix point mHz */
++ dc->bw_vbios.high_sclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[clks.num_levels-1], 1000);
++ dc->bw_vbios.mid_sclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[clks.num_levels>>1], 1000);
++ dc->bw_vbios.low_sclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[0], 1000);
++
++ /*do display clock*/
++ dm_pp_get_clock_levels_by_type(
++ dc->ctx,
++ DM_PP_CLOCK_TYPE_DISPLAY_CLK,
++ &clks);
++
++ dc->bw_vbios.high_voltage_max_dispclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[clks.num_levels-1], 1000);
++ dc->bw_vbios.mid_voltage_max_dispclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[clks.num_levels>>1], 1000);
++ dc->bw_vbios.low_voltage_max_dispclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[0], 1000);
++
++ /*do memory clock*/
++ dm_pp_get_clock_levels_by_type(
++ dc->ctx,
++ DM_PP_CLOCK_TYPE_MEMORY_CLK,
++ &clks);
++
++ dc->bw_vbios.low_yclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000);
++ dc->bw_vbios.mid_yclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER,
++ 1000);
++ dc->bw_vbios.high_yclk = bw_frc_to_fixed(
++ clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER,
++ 1000);
++}
++
++
++bool dce112_construct_resource_pool(
++ struct adapter_service *adapter_serv,
++ uint8_t num_virtual_links,
++ struct core_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 = &dce112_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[DCE112_CLK_SRC_PLL0] = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_COMBO_PHY_PLL0, &dce112_clk_src_reg_offsets[0]);
++ pool->clock_sources[DCE112_CLK_SRC_PLL1] = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_COMBO_PHY_PLL1, &dce112_clk_src_reg_offsets[1]);
++ pool->clock_sources[DCE112_CLK_SRC_PLL2] = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_COMBO_PHY_PLL2, &dce112_clk_src_reg_offsets[2]);
++ pool->clock_sources[DCE112_CLK_SRC_PLL3] = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_COMBO_PHY_PLL3, &dce112_clk_src_reg_offsets[3]);
++ pool->clock_sources[DCE112_CLK_SRC_PLL4] = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_COMBO_PHY_PLL4, &dce112_clk_src_reg_offsets[4]);
++ pool->clock_sources[DCE112_CLK_SRC_PLL5] = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_COMBO_PHY_PLL5, &dce112_clk_src_reg_offsets[5]);
++ pool->clk_src_count = DCE112_CLK_SRC_TOTAL;
++
++ pool->dp_clock_source = dce112_clock_source_create(
++ ctx, dal_adapter_service_get_bios_parser(adapter_serv),
++ CLOCK_SOURCE_ID_DP_DTO, &dce112_clk_src_reg_offsets[0]);
++
++ 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_dce112_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->pipe_count =
++ dal_adapter_service_get_func_controllers_num(adapter_serv);
++ pool->stream_enc_count = 6;
++ 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->pipe_count; i++) {
++ pool->timing_generators[i] = dce112_timing_generator_create(
++ adapter_serv,
++ ctx,
++ i,
++ &dce112_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] = dce112_mem_input_create(
++ ctx,
++ i,
++ &dce112_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] = dce112_ipp_create(
++ ctx,
++ i,
++ &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] = dce112_transform_create(
++ ctx,
++ i,
++ &dce112_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] = dce112_opp_create(
++ ctx,
++ i,
++ &dce112_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->pipe_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] = dce112_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++;
++ }
++
++ /* Create hardware sequencer */
++ if (!dc_construct_hw_sequencer(adapter_serv, dc))
++ goto stream_enc_create_fail;
++
++ bw_calcs_init(&dc->bw_dceip, &dc->bw_vbios, BW_CALCS_VERSION_BAFFIN);
++
++ bw_calcs_data_update_from_pplib(dc);
++
++ return true;
++
++stream_enc_create_fail:
++ for (i = 0; i < pool->stream_enc_count; i++) {
++ if (pool->stream_enc[i] != NULL)
++ dm_free(DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
++ }
++
++audio_create_fail:
++ for (i = 0; i < pool->pipe_count; i++) {
++ if (pool->audios[i] != NULL)
++ dal_audio_destroy(&pool->audios[i]);
++ }
++
++controller_create_fail:
++ for (i = 0; i < pool->pipe_count; i++) {
++ if (pool->opps[i] != NULL)
++ dce112_opp_destroy(&pool->opps[i]);
++
++ if (pool->transforms[i] != NULL)
++ dce112_transform_destroy(&pool->transforms[i]);
++
++ if (pool->ipps[i] != NULL)
++ dce112_ipp_destroy(&pool->ipps[i]);
++
++ if (pool->mis[i] != NULL) {
++ dm_free(TO_DCE110_MEM_INPUT(pool->mis[i]));
++ pool->mis[i] = NULL;
++ }
++
++ if (pool->timing_generators[i] != NULL) {
++ dm_free(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)
++ dce112_clock_source_destroy(&pool->clock_sources[i]);
++ }
++
++ return false;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h
+new file mode 100644
+index 0000000..eed1faf
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce112/dce112_resource.h
+@@ -0,0 +1,42 @@
++/*
++* 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_RESOURCE_DCE112_H__
++#define __DC_RESOURCE_DCE112_H__
++
++#include "core_types.h"
++
++struct adapter_service;
++struct core_dc;
++struct resource_pool;
++
++bool dce112_construct_resource_pool(
++ struct adapter_service *adapter_serv,
++ uint8_t num_virtual_links,
++ struct core_dc *dc,
++ struct resource_pool *pool);
++
++#endif /* __DC_RESOURCE_DCE112_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dm_services_types.h b/drivers/gpu/drm/amd/dal/dc/dm_services_types.h
+index 1e87624..982e968 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dm_services_types.h
++++ b/drivers/gpu/drm/amd/dal/dc/dm_services_types.h
+@@ -212,6 +212,11 @@ enum dm_pp_clock_type {
+ struct dm_pp_clock_levels {
+ uint32_t num_levels;
+ uint32_t clocks_in_khz[DM_PP_MAX_CLOCK_LEVELS];
++
++ /* TODO: add latency for polaris11
++ * do we need to know invalid (unsustainable boost) level for watermark
++ * programming? if not we can just report less elements in array
++ */
+ };
+
+ struct dm_pp_single_disp_config {
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
+index 63d6b54..5037a2d 100644
+--- a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
+@@ -78,6 +78,9 @@ bool dal_hw_factory_init(
+ #endif
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ case DCE_VERSION_11_0:
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++#endif
+ dal_hw_factory_dce110_init(factory);
+ return true;
+ #endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
+index d3c6bc8..da56db7 100644
+--- a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
+@@ -75,6 +75,9 @@ bool dal_hw_translate_init(
+ case DCE_VERSION_10_0:
+ #endif
+ case DCE_VERSION_11_0:
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++#endif
+ dal_hw_translate_dce110_init(translate);
+ return true;
+ #endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
+index cb23508..3095006 100644
+--- a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
+@@ -32,3 +32,11 @@ AMD_DAL_GPU_DCE110 = $(addprefix $(AMDDALPATH)/dc/gpu/dce110/,$(GPU_DCE110))
+
+ AMD_DAL_FILES += $(AMD_DAL_GPU_DCE110)
+ endif
++
++ifdef CONFIG_DRM_AMD_DAL_DCE11_2
++GPU_DCE112 = display_clock_dce112.o dc_clock_gating_dce112.o
++
++AMD_DAL_GPU_DCE112 = $(addprefix $(AMDDALPATH)/dc/gpu/dce112/,$(GPU_DCE112))
++
++AMD_DAL_FILES += $(AMD_DAL_GPU_DCE110) $(AMD_DAL_GPU_DCE112)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c
+new file mode 100644
+index 0000000..bf24457
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.c
+@@ -0,0 +1,89 @@
++/*
++ * 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_2_d.h"
++#include "dce/dce_11_2_sh_mask.h"
++#include "dc_clock_gating_dce112.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_dce112_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/dce112/dc_clock_gating_dce112.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.h
+new file mode 100644
+index 0000000..118da64
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/dc_clock_gating_dce112.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_DCE112_H__
++#define __DAL_DC_CLOCK_GATING_DCE112_H__
++
++void dal_dc_clock_gating_dce112_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/dce112/display_clock_dce112.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c
+new file mode 100644
+index 0000000..e559f95
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.c
+@@ -0,0 +1,964 @@
++/*
++ * 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_2_d.h"
++#include "dce/dce_11_2_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_dce112.h"
++
++#define FROM_DISPLAY_CLOCK(base) \
++ container_of(base, struct display_clock_dce112, 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 = 4000000 } };
++
++/* 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 dce112_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_dce112 *dc = DCLCK112_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_dce112 *dc = DCLCK112_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_dce112 *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_dce112 *dc112;
++
++ dc112 = DCLCK112_FROM_BASE(*base);
++
++ dm_free(dc112);
++
++ *base = NULL;
++}
++
++static uint32_t get_validation_clock(struct display_clock *dc)
++{
++ uint32_t clk = 0;
++ struct display_clock_dce112 *disp_clk = DCLCK112_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_dce112 *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_dce112 *disp_clk_110 = DCLCK112_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_dce112 *dc = DCLCK112_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_dce112 *disp_clk,
++ struct adapter_service *as)
++{
++ struct integrated_info info;
++ uint32_t i;
++ struct display_clock *base = &disp_clk->disp_clk_base;
++
++ memset(&info, 0, sizeof(struct integrated_info));
++
++ disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq;
++ if (disp_clk->dentist_vco_freq_khz == 0)
++ disp_clk->dentist_vco_freq_khz = 3600000;
++
++ disp_clk->crystal_freq_khz = 100000;
++
++ base->min_display_clk_threshold_khz =
++ disp_clk->dentist_vco_freq_khz / 64;
++
++ /*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_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
++
++ /* 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_dce112 *disp_clk = DCLCK112_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_set_dce_clock_parameters dce_clk_params;
++ struct display_clock_dce112 *dc = DCLCK112_FROM_BASE(base);
++ struct dc_bios *bp = dal_adapter_service_get_bios_parser(base->as);
++
++ /* Prepare to program display clock*/
++ memset(&dce_clk_params, 0, sizeof(dce_clk_params));
++
++ dce_clk_params.target_clock_frequency = requested_clk_khz;
++ dce_clk_params.pll_id = dc->disp_clk_base.id;
++ dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
++
++ bp->funcs->set_dce_clock(bp, &dce_clk_params);
++
++ /* 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;
++
++ /*Program DP ref Clock*/
++ /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
++ dce_clk_params.target_clock_frequency = 0;
++ dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
++ dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
++ (dce_clk_params.pll_id == CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
++
++ bp->funcs->set_dce_clock(bp, &dce_clk_params);
++}
++
++static void set_clock_state(
++ struct display_clock *dc,
++ struct display_clock_state clk_state)
++{
++ struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
++
++ disp_clk->clock_state = clk_state;
++}
++
++static struct display_clock_state get_clock_state(
++ struct display_clock *dc)
++{
++ struct display_clock_dce112 *disp_clk = DCLCK112_FROM_BASE(dc);
++
++ return disp_clk->clock_state;
++}
++
++static uint32_t get_dfs_bypass_threshold(struct display_clock *dc)
++{
++ return dce112_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_dce112_construct(
++ struct display_clock_dce112 *dc112,
++ struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ struct display_clock *dc_base = &dc112->disp_clk_base;
++
++ if (NULL == as)
++ return false;
++
++ if (!dal_display_clock_construct_base(dc_base, ctx, as))
++ return false;
++
++ dc_base->funcs = &funcs;
++
++ dc112->dfs_bypass_disp_clk = 0;
++
++ if (!display_clock_integrated_info_construct(dc112, as))
++ dal_logger_write(dc_base->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "Cannot obtain VBIOS integrated info\n");
++
++ dc112->gpu_pll_ss_percentage = 0;
++ dc112->gpu_pll_ss_divider = 1000;
++ dc112->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_dce112::StoreMaxClocksState(). This call will come in
++ * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/
++ dc112->max_clks_state = CLOCKS_STATE_NOMINAL;
++
++ dc112->disp_clk_base.min_display_clk_threshold_khz =
++ dc112->crystal_freq_khz;
++
++ if (dc112->disp_clk_base.min_display_clk_threshold_khz <
++ (dc112->dentist_vco_freq_khz / 62))
++ dc112->disp_clk_base.min_display_clk_threshold_khz =
++ (dc112->dentist_vco_freq_khz / 62);
++
++ 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;
++
++ 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) {
++ dc112->ss_on_gpu_pll = true;
++ dc112->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 */
++ dc112->gpu_pll_ss_percentage =
++ info.spread_spectrum_percentage;
++ }
++ }
++
++ }
++ }
++
++ dc112->use_max_disp_clk = true;
++
++ return true;
++}
++
++/*****************************************************************************
++ * public functions
++ *****************************************************************************/
++
++struct display_clock *dal_display_clock_dce112_create(
++ struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ struct display_clock_dce112 *dc112;
++
++ dc112 = dm_alloc(sizeof(struct display_clock_dce112));
++
++ if (dc112 == NULL)
++ return NULL;
++
++ if (dal_display_clock_dce112_construct(dc112, ctx, as))
++ return &dc112->disp_clk_base;
++
++ dm_free(dc112);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h
+new file mode 100644
+index 0000000..02fc67a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce112/display_clock_dce112.h
+@@ -0,0 +1,54 @@
++/*
++ * 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_DCE112_H__
++#define __DAL_DISPLAY_CLOCK_DCE112_H__
++
++#include "gpu/display_clock.h"
++
++struct display_clock_dce112 {
++ struct display_clock disp_clk_base;
++ /* Max display block clocks state*/
++ enum clocks_state max_clks_state;
++ bool use_max_disp_clk;
++ uint32_t crystal_freq_khz;
++ 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 DCLCK112_FROM_BASE(dc_base) \
++ container_of(dc_base, struct display_clock_dce112, disp_clk_base)
++
++#endif /* __DAL_DISPLAY_CLOCK_DCE112_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
+index 47e7922..2d394cf 100644
+--- a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
+@@ -88,10 +88,13 @@ struct i2caux *dal_i2caux_create(
+ return dal_i2caux_dce80_create(as, ctx);
+ #endif
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++#endif
+ #if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
+ case DCE_VERSION_10_0:
+ #endif
+- case DCE_VERSION_11_0:
+ return dal_i2caux_dce110_create(as, ctx);
+ #endif
+ default:
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h b/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
+index d6a599c..da00b2e 100644
+--- a/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
++++ b/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
+@@ -505,7 +505,9 @@ struct bw_calcs_output {
+
+ enum bw_calcs_version {
+ BW_CALCS_VERSION_INVALID,
+- BW_CALCS_VERSION_CARRIZO
++ BW_CALCS_VERSION_CARRIZO,
++ BW_CALCS_VERSION_ELLESMERE,
++ BW_CALCS_VERSION_BAFFIN
+ };
+
+ /**
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
+index cde34ce..bfffa8e 100644
+--- a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
++++ b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
+@@ -65,6 +65,10 @@ struct irq_service *dal_irq_service_create(
+ case DCE_VERSION_10_0:
+ return dal_irq_service_dce110_create(init_data);
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ case DCE_VERSION_11_2:
++ return dal_irq_service_dce110_create(init_data);
++#endif
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ case DCE_VERSION_11_0:
+ return dal_irq_service_dce110_create(init_data);
+diff --git a/drivers/gpu/drm/amd/dal/include/dal_asic_id.h b/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
+index d8c4cd1..4cb6a9f 100644
+--- a/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
++++ b/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
+@@ -83,11 +83,25 @@
+ #define VI_TONGA_P_A1 21
+ #define VI_FIJI_P_A0 60
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++/* DCE112 */
++#define VI_POLARIS10_P_A0 80
++#define VI_POLARIS11_M_A0 90
++#endif
++
++#define VI_UNKNOWN 0xFF
++
+ #define ASIC_REV_IS_TONGA_P(eChipRev) ((eChipRev >= VI_TONGA_P_A0) && \
+ (eChipRev < 40))
+ #define ASIC_REV_IS_FIJI_P(eChipRev) ((eChipRev >= VI_FIJI_P_A0) && \
+ (eChipRev < 80))
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++#define ASIC_REV_IS_POLARIS10_P(eChipRev) ((eChipRev >= VI_POLARIS10_P_A0) && \
++ (eChipRev < VI_POLARIS11_M_A0))
++#define ASIC_REV_IS_POLARIS11_M(eChipRev) (eChipRev >= VI_POLARIS11_M_A0)
++#endif
++
+ /* DCE11 */
+ #define CZ_CARRIZO_A0 0x01
+
+diff --git a/drivers/gpu/drm/amd/dal/include/dal_types.h b/drivers/gpu/drm/amd/dal/include/dal_types.h
+index bcf83e9..21ee669 100644
+--- a/drivers/gpu/drm/amd/dal/include/dal_types.h
++++ b/drivers/gpu/drm/amd/dal/include/dal_types.h
+@@ -43,6 +43,9 @@ enum dce_version {
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ DCE_VERSION_11_0,
+ #endif
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++ DCE_VERSION_11_2,
++#endif
+ DCE_VERSION_MAX,
+ };
+
+diff --git a/drivers/gpu/drm/amd/dal/include/display_clock_interface.h b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
+index a625e24..317ce3b 100644
+--- a/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
++++ b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
+@@ -131,6 +131,12 @@ struct display_clock_state {
+
+ struct display_clock;
+
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_2)
++struct display_clock *dal_display_clock_dce112_create(
++ struct dc_context *ctx,
++ struct adapter_service *as);
++#endif
++
+ #if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ struct display_clock *dal_display_clock_dce110_create(
+ struct dc_context *ctx,
+--
+2.7.4
+