diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0803-drm-amd-dal-Adding-Hawaii-and-Bonaire-support-to-DAL.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0803-drm-amd-dal-Adding-Hawaii-and-Bonaire-support-to-DAL.patch | 19970 |
1 files changed, 0 insertions, 19970 deletions
diff --git a/common/recipes-kernel/linux/files/0803-drm-amd-dal-Adding-Hawaii-and-Bonaire-support-to-DAL.patch b/common/recipes-kernel/linux/files/0803-drm-amd-dal-Adding-Hawaii-and-Bonaire-support-to-DAL.patch deleted file mode 100644 index 0a8091e8..00000000 --- a/common/recipes-kernel/linux/files/0803-drm-amd-dal-Adding-Hawaii-and-Bonaire-support-to-DAL.patch +++ /dev/null @@ -1,19970 +0,0 @@ -From f916c629a50d432a9b9b46d859ddbc93e2ca1973 Mon Sep 17 00:00:00 2001 -From: Harry Wentland <harry.wentland@amd.com> -Date: Wed, 17 Feb 2016 10:41:59 -0500 -Subject: [PATCH 0803/1110] drm/amd/dal: Adding Hawaii and Bonaire support to - DAL - -Signed-off-by: Harry Wentland <harry.wentland@amd.com> -Acked-by: Jordan Lazare <Jordan.Lazare@amd.com> ---- - drivers/gpu/drm/amd/dal/Kconfig | 17 +- - drivers/gpu/drm/amd/dal/dc/Makefile | 4 + - drivers/gpu/drm/amd/dal/dc/adapter/Makefile | 8 + - .../gpu/drm/amd/dal/dc/adapter/adapter_service.c | 13 + - .../adapter/dce80/hw_ctx_adapter_service_dce80.c | 322 ++++ - .../adapter/dce80/hw_ctx_adapter_service_dce80.h | 40 + - .../gpu/drm/amd/dal/dc/asic_capability/Makefile | 13 + - .../amd/dal/dc/asic_capability/asic_capability.c | 8 + - .../dc/asic_capability/hawaii_asic_capability.c | 151 ++ - .../dc/asic_capability/hawaii_asic_capability.h | 37 + - drivers/gpu/drm/amd/dal/dc/audio/Makefile | 12 + - drivers/gpu/drm/amd/dal/dc/audio/audio_base.c | 9 + - .../gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.c | 434 +++++ - .../gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.h | 41 + - .../amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.c | 1926 ++++++++++++++++++++ - .../amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.h | 75 + - drivers/gpu/drm/amd/dal/dc/bios/Makefile | 13 + - .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.c | 6 +- - .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.h | 4 + - .../gpu/drm/amd/dal/dc/bios/command_table_helper.c | 5 + - .../gpu/drm/amd/dal/dc/bios/command_table_helper.h | 3 + - .../dal/dc/bios/dce80/bios_parser_helper_dce80.c | 773 ++++++++ - .../dal/dc/bios/dce80/bios_parser_helper_dce80.h | 33 + - .../dal/dc/bios/dce80/command_table_helper_dce80.c | 355 ++++ - .../dal/dc/bios/dce80/command_table_helper_dce80.h | 33 + - drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c | 7 + - drivers/gpu/drm/amd/dal/dc/core/dc_resource.c | 3 + - drivers/gpu/drm/amd/dal/dc/dce80/Makefile | 17 + - .../gpu/drm/amd/dal/dc/dce80/dce80_compressor.c | 867 +++++++++ - .../gpu/drm/amd/dal/dc/dce80/dce80_compressor.h | 84 + - .../gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.c | 308 ++++ - .../gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.h | 36 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.c | 64 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.h | 49 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp_gamma.c | 85 + - .../gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.c | 329 ++++ - .../gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.h | 39 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.c | 217 +++ - drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.h | 41 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.c | 141 ++ - drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.h | 130 ++ - drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_csc.c | 905 +++++++++ - .../gpu/drm/amd/dal/dc/dce80/dce80_opp_formatter.c | 577 ++++++ - .../gpu/drm/amd/dal/dc/dce80/dce80_opp_regamma.c | 546 ++++++ - drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.c | 1267 +++++++++++++ - drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.h | 42 + - .../drm/amd/dal/dc/dce80/dce80_stream_encoder.c | 1104 +++++++++++ - .../drm/amd/dal/dc/dce80/dce80_stream_encoder.h | 85 + - .../drm/amd/dal/dc/dce80/dce80_timing_generator.c | 241 +++ - .../drm/amd/dal/dc/dce80/dce80_timing_generator.h | 49 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.c | 91 + - drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.h | 87 + - .../amd/dal/dc/dce80/dce80_transform_bit_depth.c | 841 +++++++++ - .../amd/dal/dc/dce80/dce80_transform_bit_depth.h | 51 + - .../drm/amd/dal/dc/dce80/dce80_transform_gamut.c | 297 +++ - .../gpu/drm/amd/dal/dc/dce80/dce80_transform_scl.c | 814 +++++++++ - drivers/gpu/drm/amd/dal/dc/gpio/Makefile | 12 + - .../gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.c | 893 +++++++++ - .../gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.h | 46 + - .../drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.c | 78 + - .../drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.h | 32 + - .../gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.c | 378 ++++ - .../gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.h | 44 + - .../drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.c | 424 +++++ - .../drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.h | 32 + - drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c | 9 + - drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c | 10 +- - drivers/gpu/drm/amd/dal/dc/gpu/Makefile | 12 + - .../amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.c | 52 + - .../amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.h | 31 + - .../drm/amd/dal/dc/gpu/dce80/display_clock_dce80.c | 925 ++++++++++ - .../drm/amd/dal/dc/gpu/dce80/display_clock_dce80.h | 58 + - drivers/gpu/drm/amd/dal/dc/i2caux/Makefile | 11 + - .../drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.c | 740 ++++++++ - .../drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.h | 54 + - .../amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.c | 901 +++++++++ - .../amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.h | 54 + - .../amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.c | 187 ++ - .../amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.h | 43 + - .../gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.c | 264 +++ - .../gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.h | 39 + - drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c | 8 + - drivers/gpu/drm/amd/dal/dc/irq/irq_service.c | 11 + - drivers/gpu/drm/amd/dal/include/dal_types.h | 3 + - .../drm/amd/dal/include/display_clock_interface.h | 6 + - 85 files changed, 19100 insertions(+), 6 deletions(-) - create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/Makefile - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp_gamma.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_csc.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_formatter.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_regamma.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_gamut.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_scl.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.h - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.c - create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.h - -diff --git a/drivers/gpu/drm/amd/dal/Kconfig b/drivers/gpu/drm/amd/dal/Kconfig -index 0dc6f86..b108756 100644 ---- a/drivers/gpu/drm/amd/dal/Kconfig -+++ b/drivers/gpu/drm/amd/dal/Kconfig -@@ -19,14 +19,14 @@ config DRM_AMD_DAL_VBIOS_PRESENT - x86 platforms and there is a VBIOS - present in the system - --config DRM_AMD_DAL_DCE11_0 -- bool "Carrizo family" -+config DRM_AMD_DAL_DCE8_0 -+ bool "CI family" - depends on DRM_AMD_DAL - help - Choose this option - if you want to have -- CZ family -- for display engine -+ CI family -+ for display engine. - - config DRM_AMD_DAL_DCE10_0 - bool "VI family" -@@ -37,6 +37,15 @@ config DRM_AMD_DAL_DCE10_0 - VI family for display - engine. - -+config DRM_AMD_DAL_DCE11_0 -+ bool "Carrizo family" -+ depends on DRM_AMD_DAL -+ help -+ Choose this option -+ if you want to have -+ CZ family -+ for display engine -+ - config DEBUG_KERNEL_DAL - bool "Enable kgdb break in DAL" - depends on DRM_AMD_DAL -diff --git a/drivers/gpu/drm/amd/dal/dc/Makefile b/drivers/gpu/drm/amd/dal/dc/Makefile -index aed26ee..5112ec9 100644 ---- a/drivers/gpu/drm/amd/dal/dc/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/Makefile -@@ -13,6 +13,10 @@ ifdef CONFIG_DRM_AMD_DAL_DCE10_0 - DC_LIBS += dce100 - endif - -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+DC_LIBS += dce80 -+endif -+ - AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/dc/,$(DC_LIBS))) - - include $(AMD_DC) -diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile -index 2c6ca7a..db1f0e8 100644 ---- a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile -@@ -8,6 +8,14 @@ AMD_DAL_ADAPTER = $(addprefix $(AMDDALPATH)/dc/adapter/,$(ADAPTER)) - - AMD_DAL_FILES += $(AMD_DAL_ADAPTER) - -+############################################################################### -+# DCE 8x -+############################################################################### -+ -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+AMD_DAL_FILES += $(AMDDALPATH)/dc/adapter/dce80/hw_ctx_adapter_service_dce80.o -+endif -+ - - ############################################################################### - # DCE 11x -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 dd2f931..f914a8c 100644 ---- a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c -+++ b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c -@@ -41,6 +41,10 @@ - - #include "atom.h" - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/hw_ctx_adapter_service_dce80.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) - #include "dce110/hw_ctx_adapter_service_dce110.h" - #endif -@@ -665,6 +669,10 @@ static struct hw_ctx_adapter_service *create_hw_ctx( - return dal_adapter_service_create_hw_ctx_diag(ctx); - - switch (dce_version) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ return dal_adapter_service_create_hw_ctx_dce80(ctx); -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: - return dal_adapter_service_create_hw_ctx_dce110(ctx); -@@ -903,6 +911,11 @@ enum dce_version dal_adapter_service_get_dce_version( - uint32_t version = as->asic_cap->data[ASIC_DATA_DCE_VERSION]; - - switch (version) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case 0x80: -+ /* CI Bonaire */ -+ return DCE_VERSION_8_0; -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case 0x100: - return DCE_VERSION_10_0; -diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.c b/drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.c -new file mode 100644 -index 0000000..9d6505c ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.c -@@ -0,0 +1,322 @@ -+/* -+ * 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/adapter_service_types.h" -+#include "include/grph_object_id.h" -+#include "../hw_ctx_adapter_service.h" -+ -+#include "hw_ctx_adapter_service_dce80.h" -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#ifndef mmCC_DC_HDMI_STRAPS -+#define mmCC_DC_HDMI_STRAPS 0x1918 -+#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 -+ -+enum { -+ MAX_NUMBER_OF_AUDIO_PINS = 7 -+}; -+ -+static const uint32_t audio_index_reg_offset[] = { -+ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, -+ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX, -+ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX, -+ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX, -+ mmAZF0ENDPOINT4_AZALIA_F0_CODEC_ENDPOINT_INDEX, -+ mmAZF0ENDPOINT5_AZALIA_F0_CODEC_ENDPOINT_INDEX, -+ /* TR, BN has 7 audio endpoints but 6 DIGs */ -+ mmAZF0ENDPOINT6_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, -+ mmAZF0ENDPOINT4_AZALIA_F0_CODEC_ENDPOINT_DATA, -+ mmAZF0ENDPOINT5_AZALIA_F0_CODEC_ENDPOINT_DATA, -+ mmAZF0ENDPOINT6_AZALIA_F0_CODEC_ENDPOINT_DATA -+}; -+ -+static const struct graphics_object_id invalid_go = { -+ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN -+}; -+ -+#define FROM_HW_CTX(ptr) \ -+ container_of((ptr), struct hw_ctx_adapter_service_dce80, base) -+ -+static void destruct( -+ struct hw_ctx_adapter_service_dce80 *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_dce80 *hw_ctx = -+ FROM_HW_CTX(ptr); -+ -+ destruct(hw_ctx); -+ -+ dm_free(ptr->ctx, hw_ctx); -+} -+ -+static uint32_t get_number_of_connected_audio_endpoints_multistream( -+ struct hw_ctx_adapter_service *hw_ctx) -+{ -+ struct dc_context *ctx = hw_ctx->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; -+} -+ -+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); -+ -+ /* unexpected value */ -+ ASSERT_CRITICAL(false); -+ return field; -+} -+ -+static bool power_up( -+ struct hw_ctx_adapter_service *hw_ctx) -+{ -+ 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); -+ } -+ -+ /* get the number of connected audio endpoints */ -+ FROM_HW_CTX(hw_ctx)->number_of_connected_audio_endpoints = -+ get_number_of_connected_audio_endpoints(hw_ctx); -+ -+ return true; -+} -+ -+static struct graphics_object_id enum_fake_path_resource( -+ const struct hw_ctx_adapter_service *hw_ctx, -+ uint32_t index) -+{ -+ if (index == 0) -+ return dal_graphics_object_id_init( -+ CONNECTOR_ID_VGA, -+ ENUM_ID_1, -+ OBJECT_TYPE_CONNECTOR); -+ else if (index == 1) -+ return dal_graphics_object_id_init( -+ ENCODER_ID_INTERNAL_KLDSCP_DAC1, -+ ENUM_ID_1, -+ OBJECT_TYPE_ENCODER); -+ else -+ return invalid_go; -+} -+ -+static struct graphics_object_id enum_stereo_sync_object( -+ const struct hw_ctx_adapter_service *hw_ctx, -+ uint32_t index) -+{ -+ return invalid_go; -+} -+ -+static struct graphics_object_id enum_sync_output_object( -+ const struct hw_ctx_adapter_service *hw_ctx, -+ uint32_t index) -+{ -+ return invalid_go; -+} -+ -+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) -+ return invalid_go; -+ else -+ return dal_graphics_object_id_init( -+ AUDIO_ID_INTERNAL_AZALIA, -+ (enum object_enum_id)(index + 1), -+ OBJECT_TYPE_AUDIO); -+} -+ -+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) -+{ -+ uint32_t number_of_connected_audio_endpoints = -+ FROM_HW_CTX(hw_ctx)->number_of_connected_audio_endpoints; -+ -+ uint32_t co_func_audio_endpoint = number_of_connected_audio_endpoints; -+ struct dc_context *ctx = hw_ctx->ctx; -+ -+ if (co_func_audio_endpoint > number_of_audio_capable_display_path) -+ co_func_audio_endpoint = number_of_audio_capable_display_path; -+ -+ if (co_func_audio_endpoint > number_of_controllers) -+ co_func_audio_endpoint = number_of_controllers; -+ -+ if (co_func_audio_endpoint < number_of_connected_audio_endpoints) { -+ const uint32_t addr = mmCC_RCU_DC_AUDIO_PORT_CONNECTIVITY; -+ -+ uint32_t value; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value(value, -+ 7 - co_func_audio_endpoint, -+ CC_RCU_DC_AUDIO_PORT_CONNECTIVITY, -+ PORT_CONNECTIVITY); -+ set_reg_field_value(value, -+ 1, -+ CC_RCU_DC_AUDIO_PORT_CONNECTIVITY, -+ PORT_CONNECTIVITY_OVERRIDE_ENABLE); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+} -+ -+static const struct hw_ctx_adapter_service_funcs funcs = { -+ destroy, -+ power_up, -+ enum_fake_path_resource, -+ enum_stereo_sync_object, -+ enum_sync_output_object, -+ enum_audio_object, -+ update_audio_connectivity -+}; -+ -+static bool construct( -+ struct hw_ctx_adapter_service_dce80 *hw_ctx, -+ struct dc_context *ctx) -+{ -+ if (!dal_adapter_service_construct_hw_ctx(&hw_ctx->base, ctx)) { -+ BREAK_TO_DEBUGGER(); -+ 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_dce80(struct dc_context *ctx) -+{ -+ struct hw_ctx_adapter_service_dce80 *hw_ctx = -+ dm_alloc(ctx, sizeof(struct hw_ctx_adapter_service_dce80)); -+ -+ if (!hw_ctx) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(hw_ctx, ctx)) -+ return &hw_ctx->base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(ctx, hw_ctx); -+ -+ return NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.h b/drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.h -new file mode 100644 -index 0000000..a735eaf ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce80/hw_ctx_adapter_service_dce80.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_HW_CTX_ADAPTER_SERVICE_DCE80_H__ -+#define __DAL_HW_CTX_ADAPTER_SERVICE_DCE80_H__ -+ -+struct hw_ctx_adapter_service_dce80 { -+ struct hw_ctx_adapter_service base; -+ uint32_t number_of_connected_audio_endpoints; -+}; -+ -+struct hw_ctx_adapter_service * -+ dal_adapter_service_create_hw_ctx_dce80( -+ struct dc_context *ctx); -+ -+#endif /* __DAL_HW_CTX_ADAPTER_SERVICE_DCE80_H__ */ -+ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile -index 8491b38..b243542 100644 ---- a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile -@@ -10,6 +10,19 @@ AMD_DAL_ASIC_CAPABILITY = \ - AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY) - - ############################################################################### -+# DCE 8x -+############################################################################### -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+ASIC_CAPABILITY_DCE80 = hawaii_asic_capability.o -+ -+AMD_DAL_ASIC_CAPABILITY_DCE80 = \ -+ $(addprefix $(AMDDALPATH)/dc/asic_capability/,$(ASIC_CAPABILITY_DCE80)) -+ -+AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY_DCE80) -+endif -+ -+ -+############################################################################### - # DCE 10x - ############################################################################### - ifdef CONFIG_DRM_AMD_DAL_DCE10_0 -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 7a905f5..69909dd 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 -@@ -32,6 +32,10 @@ - #include "include/dal_types.h" - #include "include/dal_asic_id.h" - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "hawaii_asic_capability.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - #include "tonga_asic_capability.h" - #endif -@@ -85,6 +89,10 @@ static bool construct( - - switch (init->chip_family) { - case FAMILY_CI: -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ dal_hawaii_asic_capability_create(cap, init); -+ asic_supported = true; -+#endif - break; - - case FAMILY_KV: -diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.c -new file mode 100644 -index 0000000..2745ac1 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.c -@@ -0,0 +1,151 @@ -+/* -+ * 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 -+ * -+ */ -+ -+/* -+ * Includes -+ */ -+ -+#include "dm_services.h" -+ -+#include "include/asic_capability_interface.h" -+#include "include/asic_capability_types.h" -+#include "include/dal_types.h" -+#include "include/dal_asic_id.h" -+#include "include/logger_interface.h" -+#include "hawaii_asic_capability.h" -+ -+#include "atom.h" -+ -+#include "dce/dce_8_0_d.h" -+#include "gmc/gmc_7_1_d.h" -+ -+ -+/* -+ * Sea Islands (CI) ASIC capability. -+ * -+ * dal_hawaii_asic_capability_create -+ * -+ * Create and initiate hawaii capability. -+ */ -+void dal_hawaii_asic_capability_create(struct asic_capability *cap, -+ struct hw_asic_id *init) -+{ -+ uint32_t mc_seq_misc0; -+ -+ /* ASIC data */ -+ cap->data[ASIC_DATA_CONTROLLERS_NUM] = 6; -+ cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 6; -+ cap->data[ASIC_DATA_DIGFE_NUM] = 6; -+ cap->data[ASIC_DATA_LINEBUFFER_NUM] = 6; -+ cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS] = 2; -+ cap->data[ASIC_DATA_MIN_DISPCLK_FOR_UNDERSCAN] = 300000; -+ -+ cap->data[ASIC_DATA_DCE_VERSION] = 0x80; /* DCE 8.0 */ -+ -+ /* Pixel RAM is 1712 entries of 144 bits each or -+ * in other words 246528 bits. */ -+ cap->data[ASIC_DATA_LINEBUFFER_SIZE] = 1712 * 144; -+ cap->data[ASIC_DATA_DRAM_BANDWIDTH_EFFICIENCY] = 70; -+ cap->data[ASIC_DATA_CLOCKSOURCES_NUM] = 3; -+ cap->data[ASIC_DATA_MC_LATENCY] = 5000; /* units of ns */ -+ -+ /* StutterModeEnhanced; Quad DMIF Buffer */ -+ cap->data[ASIC_DATA_STUTTERMODE] = 0x2002; -+ cap->data[ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR] = 4; -+ cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY] = 2; -+ -+ /* 3 HDMI support by default */ -+ cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 3; -+ -+ cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ] = 40; -+ -+ mc_seq_misc0 = dm_read_reg(cap->ctx, mmMC_SEQ_MISC0); -+ -+ switch (mc_seq_misc0 & MC_MISC0__MEMORY_TYPE_MASK) { -+ case MC_MISC0__MEMORY_TYPE__GDDR1: -+ case MC_MISC0__MEMORY_TYPE__DDR2: -+ case MC_MISC0__MEMORY_TYPE__DDR3: -+ case MC_MISC0__MEMORY_TYPE__GDDR3: -+ case MC_MISC0__MEMORY_TYPE__GDDR4: -+ cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER] = 2; -+ break; -+ case MC_MISC0__MEMORY_TYPE__GDDR5: -+ cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER] = 4; -+ break; -+ default: -+ dal_logger_write(cap->ctx->logger, -+ LOG_MAJOR_ERROR, -+ LOG_MINOR_MASK_ALL, -+ "%s:Unrecognized memory type!", __func__); -+ cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER] = 2; -+ break; -+ } -+ -+ /* ASIC stereo 3D capability */ -+ cap->stereo_3d_caps.INTERLEAVE = 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.DISPLAY_BASED_ON_WS = true; -+ -+ /* ASIC basic capability */ -+ cap->caps.DP_MST_SUPPORTED = true; -+ cap->caps.PANEL_SELF_REFRESH_SUPPORTED = true; -+ -+ cap->caps.MIRABILIS_SUPPORTED = true; -+ cap->caps.MIRABILIS_ENABLED_BY_DEFAULT = true; -+ -+ /* Remap device tag IDs when patching VBIOS. */ -+ cap->caps.DEVICE_TAG_REMAP_SUPPORTED = true; -+ -+ /* Report headless if no OPM attached (with MXM connectors present). */ -+ cap->caps.HEADLESS_NO_OPM_SUPPORTED = true; -+ -+ -+ cap->caps.HPD_CHECK_FOR_EDID = true; -+ cap->caps.NO_VCC_OFF_HPD_POLLING = true; -+ -+ /* true will hang the system! */ -+ cap->caps.DFSBYPASS_DYNAMIC_SUPPORT = false; -+ -+ /* Do w/a on CI A0 by default */ -+ if (init->hw_internal_rev == CI_BONAIRE_M_A0) -+ cap->bugs.LB_WA_IS_SUPPORTED = true; -+ -+ /* Apply MC Tuning for Hawaii */ -+ if (ASIC_REV_IS_HAWAII_P(init->hw_internal_rev)) -+ cap->caps.NEED_MC_TUNING = true; -+ -+ /* DCE6.0 and DCE8.0 has a HW issue when accessing registers -+ * from ROM block. When there is a W access following R or W access -+ * right after (no more than couple of cycles) the first W access -+ * sometimes is not executed (in rate of about once per 100K tries). -+ * It creates problems in different scenarios of FL setup. */ -+ cap->bugs.ROM_REGISTER_ACCESS = true; -+ -+ /* VCE is supported */ -+ cap->caps.VCE_SUPPORTED = true; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.h b/drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.h -new file mode 100644 -index 0000000..191d9b2 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/hawaii_asic_capability.h -@@ -0,0 +1,37 @@ -+/* -+ * 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_BONAIRE_CAPABILITY_H__ -+#define __DAL_BONAIRE_CAPABILITY_H__ -+ -+/* Forward declaration */ -+struct asic_capability; -+struct hw_asic_id; -+ -+/* Create and initialise Bonaire data */ -+void dal_hawaii_asic_capability_create(struct asic_capability *cap, -+ struct hw_asic_id *init); -+ -+#endif /* __DAL_BONAIRE_CAPABILITY_H__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/audio/Makefile b/drivers/gpu/drm/amd/dal/dc/audio/Makefile -index 0999372..2433d90 100644 ---- a/drivers/gpu/drm/amd/dal/dc/audio/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/audio/Makefile -@@ -11,6 +11,18 @@ AMD_DAL_FILES += $(AMD_DAL_AUDIO) - - - ############################################################################### -+# DCE 8x -+############################################################################### -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+AUDIO_DCE80 = audio_dce80.o hw_ctx_audio_dce80.o -+ -+AMD_DAL_AUDIO_DCE80 = $(addprefix $(AMDDALPATH)/dc/audio/dce80/,$(AUDIO_DCE80)) -+ -+AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE80) -+endif -+ -+ -+############################################################################### - # DCE 11x - ############################################################################### - ifdef CONFIG_DRM_AMD_DAL_DCE11_0 -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 bfd6725..269c75d 100644 ---- a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c -+++ b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c -@@ -30,6 +30,11 @@ - #include "audio.h" - #include "hw_ctx_audio.h" - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/audio_dce80.h" -+#include "dce80/hw_ctx_audio_dce80.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) - #include "dce110/audio_dce110.h" - #include "dce110/hw_ctx_audio_dce110.h" -@@ -264,6 +269,10 @@ struct audio *dal_audio_create( - - as = init_data->as; - switch (dal_adapter_service_get_dce_version(as)) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ return dal_audio_create_dce80(init_data); -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: - return dal_audio_create_dce110(init_data); -diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.c b/drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.c -new file mode 100644 -index 0000000..d6f437c ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.c -@@ -0,0 +1,434 @@ -+/* -+ * 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_dce80.h" -+ -+/***** static functions *****/ -+ -+static void destruct(struct audio_dce80 *audio) -+{ -+ /*release memory allocated for hw_ctx -- allocated is initiated -+ *by audio_dce80 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_dce80 *audio = NULL; -+ -+ audio = container_of(*ptr, struct audio_dce80, base); -+ -+ destruct(audio); -+ -+ /* release memory allocated for audio_dce80*/ -+ dm_free(audio->base.ctx, 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_dce80. -+ */ -+ -+/** -+* Setup -+* -+* @brief -+* setup Audio HW block, to be called by dal_audio_setup -+* -+* @param -+* engine_id - HDMI engine id -+* pTiming - CRTC timing -+* actualPixelClock - actual programmed pixel clock -+*/ -+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: -+ case SIGNAL_TYPE_WIRELESS: -+ /* setup HDMI audio engine */ -+ audio->hw_ctx->funcs->setup_hdmi_audio( -+ audio->hw_ctx, output->engine_id, &output->crtc_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 */ -+ break; -+ default: -+ return AUDIO_RESULT_ERROR; -+ } -+ -+ /* setup Azalia block */ -+ audio->hw_ctx->funcs->setup_azalia( -+ audio->hw_ctx, -+ output->engine_id, -+ output->signal, -+ &output->crtc_info, -+ &output->pll_info, -+ info); -+ -+ return AUDIO_RESULT_OK; -+} -+ -+/** -+* enable_output -+* -+* @brief -+* enable Audio HW block, to be called by dal_audio_enable_output -+* -+* @param -+* engine_id - HDMI engine id -+*/ -+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: { -+ /* 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 -+* -+* @param -+* engine_id - HDMI engine id -+*/ -+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); -+ 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); -+ } -+ break; -+ default: -+ return AUDIO_RESULT_ERROR; -+ } -+ -+ return AUDIO_RESULT_OK; -+} -+ -+/** -+* unmute -+* -+* @brief -+* unmute audio, to be called by dal_audio_unmute -+* -+* @param -+* engine_id - engine id -+*/ -+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_WIRELESS: -+ 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; -+ default: -+ return AUDIO_RESULT_ERROR; -+ } -+ return AUDIO_RESULT_OK; -+} -+ -+/** -+* mute -+* -+* @brief -+* mute audio, to be called by dal_audio_nmute -+* -+* @param -+* engine_id - engine id -+*/ -+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_WIRELESS: -+ 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; -+ 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. -+* -+* @param -+* NONE -+*/ -+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_audio_create_hw_ctx_audio_dce80( -+ 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); -+ -+ if (dal_adapter_service_is_feature_supported(FEATURE_LIGHT_SLEEP)) -+ audio->hw_ctx->funcs->disable_az_clock_gating(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; -+ } -+} -+ -+/** -+* SetUnsolicitedResponsePayload -+* -+* @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); -+} -+ -+/** -+* SetupAudioDTO -+* -+* @brief -+* Update audio source clock from hardware context. -+* -+* @param -+* determines if we have a HDMI link active -+* known pixel rate for HDMI -+* known DCPLL frequency -+*/ -+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); -+} -+ -+/** -+* GetSupportedFeatures -+* -+* @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 -+* -+* @param -+* NONE -+*/ -+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.ENGINE_DIGD = 1; -+ afs.ENGINE_DIGE = 1; -+ afs.ENGINE_DIGF = 1; -+ afs.ENGINE_DIGG = 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_dce80 *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_dce80( -+ const struct audio_init_data *init_data) -+{ -+ /*allocate memory for audio_dce80 */ -+ struct audio_dce80 *audio = dm_alloc(init_data->ctx, sizeof(struct audio_dce80)); -+ -+ if (audio == NULL) -+ return NULL; -+ -+ /*pointer to base_audio_block of audio_dce80 ==> audio base object */ -+ if (construct(audio, init_data)) -+ return &audio->base; -+ -+ /*release memory allocated if fail */ -+ dm_free(init_data->ctx, audio); -+ return NULL; -+} -+ -+/* Do not need expose construct_dce80 and destruct_dce80 becuase there is -+ *derived object after dce80 -+ */ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.h b/drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.h -new file mode 100644 -index 0000000..4fef455 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce80/audio_dce80.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 __DAL_AUDIO_80__ -+#define __DAL_AUDIO_80__ -+ -+#include "audio/audio.h" -+#include "audio/hw_ctx_audio.h" -+#include "audio/dce80/hw_ctx_audio_dce80.h" -+ -+ -+struct audio_dce80 { -+ struct audio base; -+ /* dce-specific members are following */ -+ /* none */ -+}; -+ -+struct audio *dal_audio_create_dce80(const struct audio_init_data *init_data); -+ -+#endif /* __DAL_AUDIO_80__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.c b/drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.c -new file mode 100644 -index 0000000..521ad07 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.c -@@ -0,0 +1,1926 @@ -+/* -+ * 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 "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+#include "hw_ctx_audio_dce80.h" -+ -+#define FROM_BASE(ptr) \ -+ container_of((ptr), struct hw_ctx_audio_dce80, 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 -+ -+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, -+ mmDIG6_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL -+}; -+/* --- static functions --- */ -+ -+/* static void dal_audio_destruct_hw_ctx_audio_dce80( -+ struct hw_ctx_audio_dce80 *ctx);*/ -+ -+ -+static void destroy( -+ struct hw_ctx_audio **ptr) -+{ -+ struct hw_ctx_audio_dce80 *hw_ctx_dce80; -+ -+ hw_ctx_dce80 = container_of( -+ *ptr, struct hw_ctx_audio_dce80, base); -+ -+ dal_audio_destruct_hw_ctx_audio_dce80(hw_ctx_dce80); -+ /* release memory allocated for struct hw_ctx_audio_dce80 */ -+ dm_free((*ptr)->ctx, hw_ctx_dce80); -+ -+ *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) -+{ -+ if (hbr_channel_count > 7) -+ return; -+ -+ { -+ union AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL value; -+ -+ value.u32All = dal_read_reg( -+ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL); -+ value.bits.HBR_CHANNEL_COUNT = hbr_channel_count; -+ dal_write_reg( -+ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL, value.u32All); -+ } -+}*/ -+ -+/* set compressed audio channel cound */ -+/*static void set_compressed_audio_channel_count( -+ const struct hw_ctx_audio *hw_ctx, -+ uint32_t compressed_audio_ch_count) -+{ -+ if (compressed_audio_ch_count > 7) -+ return; -+ -+ { -+ union AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL value; -+ -+ value.u32All = dal_read_reg( -+ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL); -+ value.bits.COMPRESSED_CHANNEL_COUNT = -+ compressed_audio_ch_count; -+ dal_write_reg( -+ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL, -+ value.u32All); -+ } -+}*/ -+ -+/* 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.u32All = dal_read_reg(mmAZALIA_CYCLIC_BUFFER_SYNC); -+ value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 1; -+ dal_write_reg(mmAZALIA_CYCLIC_BUFFER_SYNC, value.u32All); -+}*/ -+ -+ -+ -+/* disable HW/SW Sync */ -+/*static void disable_hw_sw_sync( -+ const struct hw_ctx_audio *hw_ctx) -+{ -+ union AZALIA_CYCLIC_BUFFER_SYNC value; -+ -+ value.u32All = dal_read_reg( -+ mmAZALIA_CYCLIC_BUFFER_SYNC); -+ value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 0; -+ dal_write_reg( -+ mmAZALIA_CYCLIC_BUFFER_SYNC, value.u32All); -+}*/ -+ -+ -+/* 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.u32All = 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.u32All); -+}*/ -+ -+ -+/* 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) -+{ -+ /*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);*/ -+} -+ -+/* 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); -+ -+ 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); -+ -+ /* 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); -+} -+ -+ /* Disable Azalia Clock Gating Feature */ -+static void disable_az_clock_gating( -+ const struct hw_ctx_audio *hw_ctx) -+{ -+ uint32_t value; -+ -+ value = dm_read_reg(hw_ctx->ctx, -+ mmAZALIA_CONTROLLER_CLOCK_GATING); -+ set_reg_field_value(value, 0, AZALIA_CONTROLLER_CLOCK_GATING, ENABLE_CLOCK_GATING); -+ dm_write_reg(hw_ctx->ctx, -+ mmAZALIA_CONTROLLER_CLOCK_GATING, 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 = -+ disable_az_clock_gating, -+ .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, -+}; -+ -+bool dal_audio_construct_hw_ctx_audio_dce80( -+ struct hw_ctx_audio_dce80 *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 dce80 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; -+ case 5: { -+ hw_ctx->az_mm_reg_offsets. -+ azf0endpointx_azalia_f0_codec_endpoint_index = -+ mmAZF0ENDPOINT4_AZALIA_F0_CODEC_ENDPOINT_INDEX; -+ hw_ctx->az_mm_reg_offsets. -+ azf0endpointx_azalia_f0_codec_endpoint_data = -+ mmAZF0ENDPOINT4_AZALIA_F0_CODEC_ENDPOINT_DATA; -+ } -+ break; -+ case 6: { -+ hw_ctx->az_mm_reg_offsets. -+ azf0endpointx_azalia_f0_codec_endpoint_index = -+ mmAZF0ENDPOINT5_AZALIA_F0_CODEC_ENDPOINT_INDEX; -+ hw_ctx->az_mm_reg_offsets. -+ azf0endpointx_azalia_f0_codec_endpoint_data = -+ mmAZF0ENDPOINT5_AZALIA_F0_CODEC_ENDPOINT_DATA; -+ } -+ break; -+ case 7: { -+ hw_ctx->az_mm_reg_offsets. -+ azf0endpointx_azalia_f0_codec_endpoint_index = -+ mmAZF0ENDPOINT6_AZALIA_F0_CODEC_ENDPOINT_INDEX; -+ hw_ctx->az_mm_reg_offsets. -+ azf0endpointx_azalia_f0_codec_endpoint_data = -+ mmAZF0ENDPOINT6_AZALIA_F0_CODEC_ENDPOINT_DATA; -+ } -+ break; -+ default: -+ /*DALASSERT_MSG(false,("Invalid Azalia stream ID!"));*/ -+ BREAK_TO_DEBUGGER(); -+ break; -+ } -+ -+ return true; -+} -+ -+ -+/* audio_dce80 is derived from audio directly, not via dce80 */ -+ -+void dal_audio_destruct_hw_ctx_audio_dce80( -+ struct hw_ctx_audio_dce80 *hw_ctx_dce80) -+{ -+ dal_audio_destruct_hw_ctx_audio(&hw_ctx_dce80->base); -+} -+ -+struct hw_ctx_audio *dal_audio_create_hw_ctx_audio_dce80( -+ struct dc_context *ctx, -+ uint32_t azalia_stream_id) -+{ -+ /* allocate memory for struc hw_ctx_audio_dce80 */ -+ struct hw_ctx_audio_dce80 *hw_ctx_dce80 = -+ dm_alloc(ctx, sizeof(struct hw_ctx_audio_dce80)); -+ -+ if (!hw_ctx_dce80) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ /*return pointer to hw_ctx_audio back to caller -- audio object */ -+ if (dal_audio_construct_hw_ctx_audio_dce80( -+ hw_ctx_dce80, azalia_stream_id, ctx)) -+ return &hw_ctx_dce80->base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(ctx, hw_ctx_dce80); -+ -+ return NULL; -+} -+ -+ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.h b/drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.h -new file mode 100644 -index 0000000..1d0e00d ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce80/hw_ctx_audio_dce80.h -@@ -0,0 +1,75 @@ -+/* -+ * 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_DCE80_H__ -+#define __DAL_HW_CTX_AUDIO_DCE80_H__ -+ -+#include "audio/hw_ctx_audio.h" -+ -+struct hw_ctx_audio_dce80 { -+ 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 */ -+}; -+ -+ -+/* --- helpers --- all static functions*/ -+/*set_high_bit_rate_capable -+set_hbr_channel_count -+set_compressed_audio_channel_count -+set_video_latency -+set_audio_latency -+enable_hw_sw_sync -+disable_hw_sw_sync -+update_sw_write_ptr -+update_av_association -+write_indirect_azalia_reg -+read_indirect_azalia_reg -+*/ -+ -+/* in case dce83 may derived from dce80, expose dce80 constructor -+*and destroy for derived */ -+bool dal_audio_construct_hw_ctx_audio_dce80( -+ struct hw_ctx_audio_dce80 *hw_ctx, -+ uint8_t azalia_stream_id, -+ struct dc_context *ctx); -+ -+void dal_audio_destruct_hw_ctx_audio_dce80( -+ struct hw_ctx_audio_dce80 *hw_ctx); -+ -+struct hw_ctx_audio *dal_audio_create_hw_ctx_audio_dce80( -+ struct dc_context *ctx, -+ uint32_t azalia_stream_id); -+ -+#endif /* __DAL_HW_CTX_AUDIO_DCE80_H__ */ -+ -+ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/bios/Makefile b/drivers/gpu/drm/amd/dal/dc/bios/Makefile -index ddfe457..e5c8876 100644 ---- a/drivers/gpu/drm/amd/dal/dc/bios/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/bios/Makefile -@@ -12,6 +12,19 @@ ifndef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT - AMD_DAL_FILES := $(filter-out $(AMDDALPATH)/dc/bios/bios_parser_helper.o,$(AMD_DAL_FILES)) - endif - -+############################################################################### -+# DCE 8x -+############################################################################### -+# All DCE8.x are derived from DCE8.0, so 8.0 MUST be defined if ANY of -+# DCE8.x is compiled. -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+ -+ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT -+AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce80/bios_parser_helper_dce80.o -+endif -+ -+AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce80/command_table_helper_dce80.o -+endif - - ############################################################################### - # DCE 11x -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 0aa227a..4e2bc90 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 -@@ -38,7 +38,11 @@ bool dal_bios_parser_init_bios_helper( - enum dce_version version) - { - switch (version) { -- -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ bp->bios_helper = dal_bios_parser_helper_dce80_get_table(); -+ return true; -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: - bp->bios_helper = dal_bios_parser_helper_dce110_get_table(); -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 1ad7455..c58b9bb 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 -@@ -26,6 +26,10 @@ - #ifndef __DAL_BIOS_PARSER_HELPER_H__ - #define __DAL_BIOS_PARSER_HELPER_H__ - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/bios_parser_helper_dce80.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) || defined(CONFIG_DRM_AMD_DAL_DCE10_0) - #include "dce110/bios_parser_helper_dce110.h" - #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 566604e..85a5924 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 -@@ -37,6 +37,11 @@ bool dal_bios_parser_init_cmd_tbl_helper( - enum dce_version dce) - { - switch (dce) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ *h = dal_cmd_tbl_helper_dce80_get_table(); -+ return true; -+#endif - - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: -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 4646cab..a462917 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 -@@ -26,6 +26,9 @@ - #ifndef __DAL_COMMAND_TABLE_HELPER_H__ - #define __DAL_COMMAND_TABLE_HELPER_H__ - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/command_table_helper_dce80.h" -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) || defined(CONFIG_DRM_AMD_DAL_DCE10_0) - #include "dce110/command_table_helper_dce110.h" - #endif -diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.c b/drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.c -new file mode 100644 -index 0000000..541a8c4 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.c -@@ -0,0 +1,773 @@ -+/* -+ * 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 "dce/dce_8_0_d.h" -+#include "bif/bif_4_1_d.h" -+ -+#include "include/grph_object_id.h" -+#include "include/grph_object_defs.h" -+#include "include/grph_object_ctrl_defs.h" -+#include "include/bios_parser_types.h" -+#include "include/adapter_service_types.h" -+ -+#include "../bios_parser_helper.h" -+ -+ -+static const uint8_t bios_scratch0_dacb_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) -+{ -+ enum signal_type sink = SIGNAL_TYPE_NONE; -+ /* VBIOS does not provide bitfield definitions */ -+ uint32_t reg; -+ /* DCE 8.0 does not support DAC2 */ -+ if (encoder.id == ENCODER_ID_INTERNAL_DAC2 -+ || encoder.id == ENCODER_ID_INTERNAL_KLDSCP_DAC2) { -+ BREAK_TO_DEBUGGER(); -+ /* TODO: DALASSERT_MSG(false, ("%s: DCE 8.0 Does not support -+ * DAC2!", __FUNCTION__)); */ -+ return SIGNAL_TYPE_NONE; -+ } -+ -+ reg = 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) { -+ reg <<= bios_scratch0_dacb_shift; -+ } -+ -+ switch (signal) { -+ case SIGNAL_TYPE_RGB: -+ if (reg & ATOM_S0_CRT2_MASK) -+ sink = SIGNAL_TYPE_RGB; -+ break; -+ case SIGNAL_TYPE_LVDS: -+ if (reg & ATOM_S0_LCD1) -+ sink = SIGNAL_TYPE_LVDS; -+ break; -+ case SIGNAL_TYPE_EDP: -+ if (reg & ATOM_S0_LCD1) -+ sink = SIGNAL_TYPE_EDP; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ break; -+ } -+ -+ return sink; -+} -+ -+static bool is_lid_open(struct dc_context *ctx) -+{ -+ bool result = false; -+ -+ /* VBIOS does not provide bitfield definitions */ -+ uint32_t reg; -+ -+ reg = dm_read_reg(ctx, -+ mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF); -+ -+ /* lid is open if the bit is not set */ -+ result = !(reg & ATOM_S6_LID_STATE); -+ -+ return result; -+} -+ -+static bool is_lid_status_changed( -+ struct dc_context *ctx) -+{ -+ bool result = false; -+ -+ /* VBIOS does not provide bitfield definitions */ -+ uint32_t reg; -+ -+ reg = dm_read_reg(ctx, -+ mmBIOS_SCRATCH_6); -+ -+ /* lid is open if the bit is not set */ -+ if (reg & ATOM_S6_LID_CHANGE) { -+ reg &= ~ATOM_S6_LID_CHANGE; -+ dm_write_reg(ctx, -+ mmBIOS_SCRATCH_6, reg); -+ -+ result = true; -+ } -+ -+ return result; -+} -+ -+static bool is_display_config_changed( -+ struct dc_context *ctx) -+{ -+ bool result = false; -+ -+ /* VBIOS does not provide bitfield definitions */ -+ uint32_t reg; -+ -+ reg = dm_read_reg(ctx, -+ mmBIOS_SCRATCH_6); -+ -+ /* lid is open if the bit is not set */ -+ if (reg & ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK) { -+ reg &= ~ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK; -+ dm_write_reg(ctx, -+ mmBIOS_SCRATCH_6, reg); -+ -+ result = true; -+ } -+ -+ return result; -+} -+ -+/** -+ * 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 -+ * NONE -+ */ -+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); -+} -+ -+/** -+ * is_accelerated_mode -+ * -+ * @brief -+ * set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when -+ * VGA/non-Accelerated mode is set -+ * -+ * @param -+ * NONE -+ */ -+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; -+} -+ -+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); -+} -+ -+/** -+ * 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: -+ /* TODO: DALASSERT_MSG(false, ("%s: DCE 8.0 Does -+ * not support DAC2!", __FUNCTION__)); -+ */ -+ default: -+ break; -+ } -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ break; -+ } -+} -+ -+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; -+} -+ -+/** -+ * 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: -+ switch (device_tag->dev_id.enum_id) { -+ case 1: -+ update |= ATOM_S0_CRT1_COLOR; -+ break; -+ case 2: -+ update |= ATOM_S0_CRT2_COLOR; -+ break; -+ default: -+ break; -+ } -+ 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_lcd_scale( -+ struct dc_context *ctx, -+ enum lcd_scale lcd_scale_request) -+{ -+ uint32_t reg; -+ -+ reg = dm_read_reg(ctx, mmBIOS_SCRATCH_6); -+ -+ reg &= ~ATOM_S6_REQ_LCD_EXPANSION_FULL; -+ reg &= ~ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO; -+ -+ switch (lcd_scale_request) { -+ case LCD_SCALE_FULLPANEL: -+ /* set Lcd Scale to Full Panel Mode */ -+ reg |= ATOM_S6_REQ_LCD_EXPANSION_FULL; -+ break; -+ case LCD_SCALE_ASPECTRATIO: -+ /* set Lcd Scale to Aspect-Ratio Mode */ -+ reg |= ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO; -+ break; -+ case LCD_SCALE_NONE: -+ default: -+ break; -+ } -+ -+ dm_write_reg(ctx, mmBIOS_SCRATCH_6, reg); -+} -+ -+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; -+} -+ -+static uint32_t fmt_control( -+ struct dc_context *ctx, -+ enum controller_id id, -+ uint32_t *value) -+{ -+ uint32_t result = 0; -+ uint32_t reg; -+ -+ switch (id) { -+ case CONTROLLER_ID_D0: -+ reg = mmFMT0_FMT_CONTROL; -+ break; -+ case CONTROLLER_ID_D1: -+ reg = mmFMT1_FMT_CONTROL; -+ break; -+ case CONTROLLER_ID_D2: -+ reg = mmFMT2_FMT_CONTROL; -+ break; -+ case CONTROLLER_ID_D3: -+ reg = mmFMT3_FMT_CONTROL; -+ break; -+ case CONTROLLER_ID_D4: -+ reg = mmFMT4_FMT_CONTROL; -+ break; -+ case CONTROLLER_ID_D5: -+ reg = mmFMT5_FMT_CONTROL; -+ break; -+ default: -+ return result; -+ } -+ -+ if (value != NULL) -+ dm_write_reg(ctx, reg, *value); -+ else -+ result = dm_read_reg(ctx, reg); -+ -+ return result; -+} -+ -+static uint32_t fmt_bit_depth_control( -+ struct dc_context *ctx, -+ enum controller_id id, -+ uint32_t *value) -+{ -+ uint32_t addr; -+ -+ switch (id) { -+ case CONTROLLER_ID_D0: -+ addr = mmFMT0_FMT_BIT_DEPTH_CONTROL; -+ break; -+ case CONTROLLER_ID_D1: -+ addr = mmFMT1_FMT_BIT_DEPTH_CONTROL; -+ break; -+ case CONTROLLER_ID_D2: -+ addr = mmFMT2_FMT_BIT_DEPTH_CONTROL; -+ break; -+ case CONTROLLER_ID_D3: -+ addr = mmFMT3_FMT_BIT_DEPTH_CONTROL; -+ break; -+ case CONTROLLER_ID_D4: -+ addr = mmFMT4_FMT_BIT_DEPTH_CONTROL; -+ break; -+ case CONTROLLER_ID_D5: -+ addr = mmFMT5_FMT_BIT_DEPTH_CONTROL; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ return 0; -+ } -+ -+ if (value != NULL) { -+ dm_write_reg(ctx, addr, *value); -+ return 0; -+ } else { -+ return dm_read_reg(ctx, addr); -+ } -+} -+ -+/** -+ * Read various BIOS Scratch registers and put the resulting information into a -+ * PowerPlay internal structure (which is not dependent on register bit layout). -+ */ -+static void get_bios_event_info( -+ struct dc_context *ctx, -+ struct bios_event_info *info) -+{ -+ uint32_t s2, s6; -+ uint32_t clear_mask; -+ -+ dm_memset(info, 0, sizeof(struct bios_event_info)); -+ -+ /* Handle backlight event ONLY. PPLib still handling other events */ -+ s6 = dm_read_reg(ctx, mmBIOS_SCRATCH_6); -+ -+ clear_mask = s6 & (ATOM_S6_VRI_BRIGHTNESS_CHANGE); -+ -+ dm_write_reg(ctx, -+ mmBIOS_SCRATCH_6, s6 & ~clear_mask); -+ -+ s2 = dm_read_reg(ctx, mmBIOS_SCRATCH_2); -+ -+ info->backlight_level = (s2 & ATOM_S2_CURRENT_BL_LEVEL_MASK) -+ >> ATOM_S2_CURRENT_BL_LEVEL_SHIFT; -+ info->backlight_changed = (0 != (s6 & ATOM_S6_VRI_BRIGHTNESS_CHANGE)); -+} -+ -+static void take_backlight_control( -+ struct dc_context *ctx, -+ bool control) -+{ -+ const uint32_t addr = mmBIOS_SCRATCH_2; -+ -+ uint32_t s2; -+ -+ s2 = dm_read_reg(ctx, addr); -+ -+ if (control) -+ s2 |= ATOM_S2_VRI_BRIGHT_ENABLE; -+ else -+ s2 &= ~ATOM_S2_VRI_BRIGHT_ENABLE; -+ -+ dm_write_reg(ctx, addr, s2); -+} -+ -+static uint32_t get_requested_backlight_level( -+ struct dc_context *ctx) -+{ -+ uint32_t s2; -+ -+ s2 = dm_read_reg(ctx, mmBIOS_SCRATCH_2); -+ -+ return (s2 & ATOM_S2_CURRENT_BL_LEVEL_MASK) -+ >> ATOM_S2_CURRENT_BL_LEVEL_SHIFT; -+} -+ -+static void update_requested_backlight_level( -+ struct dc_context *ctx, -+ uint32_t backlight_8bit) -+{ -+ const uint32_t addr = mmBIOS_SCRATCH_2; -+ -+ uint32_t s2; -+ -+ s2 = dm_read_reg(ctx, addr); -+ -+ s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; -+ backlight_8bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK -+ >> ATOM_S2_CURRENT_BL_LEVEL_SHIFT); -+ s2 |= (backlight_8bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT); -+ -+ dm_write_reg(ctx, addr, s2); -+} -+ -+static bool is_active_display( -+ struct dc_context *ctx, -+ enum signal_type signal, -+ const struct connector_device_tag_info *dev_tag) -+{ -+ uint32_t active = 0; -+ -+ uint32_t reg; -+ -+ switch (signal) { -+ 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: -+ active = ATOM_S3_DFP1_ACTIVE; -+ break; -+ case 2: -+ active = ATOM_S3_DFP2_ACTIVE; -+ break; -+ case 3: -+ active = ATOM_S3_DFP3_ACTIVE; -+ break; -+ case 4: -+ active = ATOM_S3_DFP4_ACTIVE; -+ break; -+ case 5: -+ active = ATOM_S3_DFP5_ACTIVE; -+ break; -+ -+ case 6: -+ active = ATOM_S3_DFP6_ACTIVE; -+ break; -+ default: -+ break; -+ } -+ } -+ break; -+ case SIGNAL_TYPE_LVDS: -+ case SIGNAL_TYPE_EDP: -+ active = ATOM_S3_LCD1_ACTIVE; -+ break; -+ case SIGNAL_TYPE_RGB: -+ if (dev_tag->dev_id.device_type == DEVICE_TYPE_CRT) -+ active = ATOM_S3_CRT1_ACTIVE; -+ break; -+ default: -+ break; -+ } -+ -+ reg = dm_read_reg(ctx, mmBIOS_SCRATCH_3); -+ reg &= ATOM_S3_DEVICE_ACTIVE_MASK; -+ -+ return 0 != (active & reg); -+} -+ -+static enum controller_id get_embedded_display_controller_id( -+ struct dc_context *ctx) -+{ -+ uint32_t reg; -+ -+ reg = dm_read_reg(ctx, mmBIOS_SCRATCH_3); -+ -+ if (ATOM_S3_LCD1_ACTIVE & reg) -+ return (reg & ATOM_S3_LCD1_CRTC_ACTIVE) ? -+ CONTROLLER_ID_D1 : CONTROLLER_ID_D0; -+ -+ return CONTROLLER_ID_UNDEFINED; -+} -+ -+static uint32_t get_embedded_display_refresh_rate( -+ struct dc_context *ctx) -+{ -+ uint32_t result = 0; -+ -+ uint32_t reg_3; -+ -+ reg_3 = dm_read_reg(ctx, mmBIOS_SCRATCH_3); -+ -+ if (ATOM_S3_LCD1_ACTIVE & reg_3) { -+ uint32_t reg_4; -+ -+ reg_4 = dm_read_reg(ctx, -+ mmBIOS_SCRATCH_4); -+ -+ result = (reg_4 & ATOM_S4_LCD1_REFRESH_MASK) -+ >> ATOM_S4_LCD1_REFRESH_SHIFT; -+ } -+ -+ return result; -+} -+ -+static const struct bios_parser_helper bios_parser_helper_funcs = { -+ .detect_sink = detect_sink, -+ .fmt_bit_depth_control = fmt_bit_depth_control, -+ .fmt_control = fmt_control, -+ .get_bios_event_info = get_bios_event_info, -+ .get_embedded_display_controller_id = -+ get_embedded_display_controller_id, -+ .get_embedded_display_refresh_rate = -+ get_embedded_display_refresh_rate, -+ .get_requested_backlight_level = get_requested_backlight_level, -+ .get_scratch_lcd_scale = get_scratch_lcd_scale, -+ .is_accelerated_mode = is_accelerated_mode, -+ .is_active_display = is_active_display, -+ .is_display_config_changed = is_display_config_changed, -+ .is_lid_open = is_lid_open, -+ .is_lid_status_changed = is_lid_status_changed, -+ .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 = take_backlight_control, -+ .update_requested_backlight_level = update_requested_backlight_level, -+}; -+ -+const struct bios_parser_helper *dal_bios_parser_helper_dce80_get_table() -+{ -+ return &bios_parser_helper_funcs; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.h b/drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.h -new file mode 100644 -index 0000000..db671be ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce80/bios_parser_helper_dce80.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_BIOS_PARSER_HELPER_DCE80_H__ -+#define __DAL_BIOS_PARSER_HELPER_DCE80_H__ -+ -+struct bios_parser_helper; -+ -+const struct bios_parser_helper *dal_bios_parser_helper_dce80_get_table(void); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.c b/drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.c -new file mode 100644 -index 0000000..d725c4c ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.c -@@ -0,0 +1,355 @@ -+/* -+ * 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/grph_object_id.h" -+#include "include/grph_object_defs.h" -+#include "include/bios_parser_types.h" -+#include "include/adapter_service_types.h" -+ -+#include "../command_table_helper.h" -+ -+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_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 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 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_ID_PLL0: -+ *atom_pll_id = ATOM_PPLL0; -+ break; -+ case CLOCK_SOURCE_ID_PLL1: -+ *atom_pll_id = ATOM_PPLL1; -+ break; -+ case CLOCK_SOURCE_ID_PLL2: -+ *atom_pll_id = ATOM_PPLL2; -+ break; -+ case CLOCK_SOURCE_ID_EXTERNAL: -+ *atom_pll_id = ATOM_PPLL_INVALID; -+ break; -+ case CLOCK_SOURCE_ID_DFS: -+ *atom_pll_id = ATOM_EXT_PLL1; -+ break; -+ case CLOCK_SOURCE_ID_VCE: -+ /* for VCE encoding, -+ * we need to pass in ATOM_PPLL_INVALID -+ */ -+ *atom_pll_id = ATOM_PPLL_INVALID; -+ break; -+ case CLOCK_SOURCE_ID_DP_DTO: -+ /* When programming DP DTO PLL ID should be invalid */ -+ *atom_pll_id = ATOM_PPLL_INVALID; -+ break; -+ case CLOCK_SOURCE_ID_UNDEFINED: -+ BREAK_TO_DEBUGGER(); /* check when this will happen! */ -+ *atom_pll_id = ATOM_PPLL_INVALID; -+ result = false; -+ break; -+ default: -+ result = false; -+ break; -+ } -+ -+ return result; -+} -+ -+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 signal_type_to_atom_dig_mode(enum signal_type s) -+{ -+ uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP; -+ -+ switch (s) { -+ case SIGNAL_TYPE_DISPLAY_PORT: -+ case SIGNAL_TYPE_EDP: -+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP; -+ break; -+ case SIGNAL_TYPE_LVDS: -+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_LVDS; -+ break; -+ case SIGNAL_TYPE_DVI_SINGLE_LINK: -+ case SIGNAL_TYPE_DVI_DUAL_LINK: -+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI; -+ break; -+ case SIGNAL_TYPE_HDMI_TYPE_A: -+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_HDMI; -+ break; -+ case SIGNAL_TYPE_DISPLAY_PORT_MST: -+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP_MST; -+ break; -+ default: -+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI; -+ break; -+ } -+ -+ return atom_dig_mode; -+} -+ -+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_CONFIG_V5_HPD1_SEL; -+ break; -+ case HPD_SOURCEID2: -+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL; -+ break; -+ case HPD_SOURCEID3: -+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL; -+ break; -+ case HPD_SOURCEID4: -+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL; -+ break; -+ case HPD_SOURCEID5: -+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL; -+ break; -+ case HPD_SOURCEID6: -+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL; -+ break; -+ case HPD_SOURCEID_UNKNOWN: -+ default: -+ atom_hpd_sel = 0; -+ break; -+ } -+ return atom_hpd_sel >> 4; -+} -+ -+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_V5__DIGA_SEL; -+ break; -+ case ENGINE_ID_DIGB: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGB_SEL; -+ break; -+ case ENGINE_ID_DIGC: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGC_SEL; -+ break; -+ case ENGINE_ID_DIGD: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGD_SEL; -+ break; -+ case ENGINE_ID_DIGE: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGE_SEL; -+ break; -+ case ENGINE_ID_DIGF: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGF_SEL; -+ break; -+ case ENGINE_ID_DIGG: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGG_SEL; -+ break; -+ default: -+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL; -+ break; -+ } -+ -+ return atom_dig_encoder_sel; -+} -+ -+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 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: -+ BREAK_TO_DEBUGGER(); /* Unhandle action in driver! */ -+ break; -+ } -+ -+ return atom_pipe_action; -+} -+ -+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 = -+ dal_cmd_table_helper_assign_control_parameter, -+ .clock_source_id_to_ref_clk_src = -+ dal_cmd_table_helper_clock_source_id_to_ref_clk_src, -+ .transmitter_bp_to_atom = dal_cmd_table_helper_transmitter_bp_to_atom, -+ .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, -+}; -+ -+const struct command_table_helper *dal_cmd_tbl_helper_dce80_get_table() -+{ -+ return &command_table_helper_funcs; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.h b/drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.h -new file mode 100644 -index 0000000..e675c35 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/bios/dce80/command_table_helper_dce80.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_COMMAND_TABLE_HELPER_DCE80_H__ -+#define __DAL_COMMAND_TABLE_HELPER_DCE80_H__ -+ -+struct command_table_helper; -+ -+const struct command_table_helper *dal_cmd_tbl_helper_dce80_get_table(void); -+ -+#endif -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 db4f131..133b174 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 -@@ -25,6 +25,9 @@ - #include "dm_services.h" - #include "core_types.h" - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/dce80_hw_sequencer.h" -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - #include "dce100/dce100_hw_sequencer.h" - #endif -@@ -40,6 +43,10 @@ bool dc_construct_hw_sequencer( - - switch (dce_ver) - { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ return dce80_hw_sequencer_construct(dc); -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: - return dce100_hw_sequencer_construct(dc); -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 70bf935..80fb823 100644 ---- a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c -+++ b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c -@@ -31,6 +31,9 @@ - #include "opp.h" - #include "transform.h" - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/dce80_resource.h" -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - #include "dce100/dce100_resource.h" - #endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/Makefile b/drivers/gpu/drm/amd/dal/dc/dce80/Makefile -new file mode 100644 -index 0000000..efe001f ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/Makefile -@@ -0,0 +1,17 @@ -+# -+# Makefile for the 'controller' sub-component of DAL. -+# It provides the control and status of HW CRTC block. -+ -+DCE80 = dce80_ipp.o dce80_ipp_gamma.o dce80_link_encoder.o dce80_opp.o \ -+ dce80_opp_formatter.o dce80_opp_regamma.o dce80_stream_encoder.o \ -+ dce80_timing_generator.o dce80_transform.o dce80_transform_gamut.o \ -+ dce80_transform_scl.o dce80_opp_csc.o\ -+ dce80_compressor.o dce80_mem_input.o dce80_hw_sequencer.o \ -+ dce80_transform_bit_depth.o dce80_resource.o -+ -+AMD_DAL_DCE80 = $(addprefix $(AMDDALPATH)/dc/dce80/,$(DCE80)) -+ -+AMD_DAL_FILES += $(AMD_DAL_DCE80) -+ -+ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.c -new file mode 100644 -index 0000000..a3b767e ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.c -@@ -0,0 +1,867 @@ -+/* -+ * 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_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+#include "gmc/gmc_7_1_sh_mask.h" -+#include "gmc/gmc_7_1_d.h" -+ -+#include "include/logger_interface.h" -+#include "include/adapter_service_interface.h" -+ -+#include "dce80_compressor.h" -+ -+#define DCP_REG(reg)\ -+ (reg + cp80->offsets.dcp_offset) -+#define DMIF_REG(reg)\ -+ (reg + cp80->offsets.dmif_offset) -+ -+static const struct dce80_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), -+}, -+{ -+ .dcp_offset = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+ .dmif_offset = (mmDMIF_PG3_DPG_PIPE_DPM_CONTROL -+ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+ .dmif_offset = (mmDMIF_PG4_DPG_PIPE_DPM_CONTROL -+ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+ .dmif_offset = (mmDMIF_PG5_DPG_PIPE_DPM_CONTROL -+ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -+} -+}; -+ -+static const uint32_t dce8_one_lpt_channel_max_resolution = 2048 * 1200; -+ -+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 dce80_compressor *cp80) -+{ -+ /*LPT_ALIGNMENT (in bytes) = ROW_SIZE * #BANKS * # DRAM CHANNELS. */ -+ return cp80->base.raw_size * cp80->base.banks_num * -+ cp80->base.dram_channels_num; -+} -+ -+static uint32_t lpt_memory_control_config(struct dce80_compressor *cp80, -+ uint32_t lpt_control) -+{ -+ /*LPT MC Config */ -+ if (cp80->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 (cp80->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( -+ cp80->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 (cp80->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( -+ cp80->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 (cp80->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( -+ cp80->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 (cp80->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( -+ cp80->base.ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_CONTROLLER, -+ "%s: Invalid LPT ROW_SIZE!!!", -+ __func__); -+ break; -+ } -+ } else { -+ dal_logger_write( -+ cp80->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 dce80_compressor *cp80, -+ uint32_t source_view_width, -+ uint32_t source_view_height) -+{ -+ if (cp80->base.embedded_panel_h_size != 0 && -+ cp80->base.embedded_panel_v_size != 0 && -+ ((source_view_width * source_view_height) > -+ (cp80->base.embedded_panel_h_size * -+ cp80->base.embedded_panel_v_size))) -+ return true; -+ -+ return false; -+} -+ -+static uint32_t align_to_chunks_number_per_line( -+ struct dce80_compressor *cp80, -+ uint32_t pixels) -+{ -+ return 256 * ((pixels + 255) / 256); -+} -+ -+static void wait_for_fbc_state_changed( -+ struct dce80_compressor *cp80, -+ bool enabled) -+{ -+ uint8_t counter = 0; -+ uint32_t addr = mmFBC_STATUS; -+ uint32_t value; -+ -+ while (counter < 10) { -+ value = dm_read_reg(cp80->base.ctx, addr); -+ if (get_reg_field_value( -+ value, -+ FBC_STATUS, -+ FBC_ENABLE_STATUS) == enabled) -+ break; -+ dm_delay_in_microseconds(cp80->base.ctx, 10); -+ counter++; -+ } -+ -+ if (counter == 10) { -+ dal_logger_write( -+ cp80->base.ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_CONTROLLER, -+ "%s: wait counter exceeded, changes to HW not applied", -+ __func__); -+ } -+} -+ -+void dce80_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); -+ 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 dce80_compressor_enable_fbc( -+ struct compressor *compressor, -+ uint32_t paths_num, -+ struct compr_addr_and_pitch_params *params) -+{ -+ struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); -+ -+ if (compressor->options.bits.FBC_SUPPORT && -+ (compressor->options.bits.DUMMY_BACKEND == 0) && -+ (!dce80_compressor_is_fbc_enabled_in_hw(compressor, NULL)) && -+ (!is_source_bigger_than_epanel_size( -+ cp80, -+ 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 <= -+ dce8_one_lpt_channel_max_resolution)) { -+ dce80_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; -+ cp80->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(cp80, true); -+ } -+} -+ -+void dce80_compressor_disable_fbc(struct compressor *compressor) -+{ -+ struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); -+ -+ if (compressor->options.bits.FBC_SUPPORT && -+ dce80_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) -+ dce80_compressor_disable_lpt(compressor); -+ -+ wait_for_fbc_state_changed(cp80, false); -+ } -+} -+ -+bool dce80_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_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 dce80_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 dce80_compressor_program_compressed_surface_address_and_pitch( -+ struct compressor *compressor, -+ struct compr_addr_and_pitch_params *params) -+{ -+ struct dce80_compressor *cp80 = TO_DCE80_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(cp80); -+ -+ 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( -+ cp80, -+ 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 DCE8 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 dce80_compressor_disable_lpt(struct compressor *compressor) -+{ -+ struct dce80_compressor *cp80 = TO_DCE80_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 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 dce80_compressor_enable_lpt(struct compressor *compressor) -+{ -+ struct dce80_compressor *cp80 = TO_DCE80_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); -+ -+ /* 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 dce80_compressor_program_lpt_control( -+ struct compressor *compressor, -+ struct compr_addr_and_pitch_params *params) -+{ -+ struct dce80_compressor *cp80 = TO_DCE80_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(cp80, 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(cp80); -+ source_view_width = -+ align_to_chunks_number_per_line( -+ cp80, -+ 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 dce80_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 DCE8: -+ * - 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, DCE8.1 also needs to set new DCE8.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 dce80_compressor_construct(struct dce80_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 *dce80_compressor_create(struct dc_context *ctx, -+ struct adapter_service *as) -+{ -+ struct dce80_compressor *cp80 = -+ dm_alloc(ctx, sizeof(struct dce80_compressor)); -+ -+ if (!cp80) -+ return NULL; -+ -+ if (dce80_compressor_construct(cp80, ctx, as)) -+ return &cp80->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, cp80); -+ return NULL; -+} -+ -+void dce80_compressor_destroy(struct compressor **compressor) -+{ -+ dm_free((*compressor)->ctx, TO_DCE80_COMPRESSOR(*compressor)); -+ *compressor = NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_compressor.h -new file mode 100644 -index 0000000..8254118 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_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_DCE80_H__ -+#define __DC_COMPRESSOR_DCE80_H__ -+ -+#include "../inc/compressor.h" -+ -+#define TO_DCE80_COMPRESSOR(compressor)\ -+ container_of(compressor, struct dce80_compressor, base) -+ -+struct dce80_compressor_reg_offsets { -+ uint32_t dcp_offset; -+ uint32_t dmif_offset; -+}; -+ -+struct dce80_compressor { -+ struct compressor base; -+ struct dce80_compressor_reg_offsets offsets; -+}; -+ -+struct compressor *dce80_compressor_create(struct dc_context *ctx, -+ struct adapter_service *as); -+ -+bool dce80_compressor_construct(struct dce80_compressor *cp80, -+ struct dc_context *ctx, struct adapter_service *as); -+ -+void dce80_compressor_destroy(struct compressor **cp); -+ -+/* FBC RELATED */ -+void dce80_compressor_power_up_fbc(struct compressor *cp); -+ -+void dce80_compressor_enable_fbc(struct compressor *cp, uint32_t paths_num, -+ struct compr_addr_and_pitch_params *params); -+ -+void dce80_compressor_disable_fbc(struct compressor *cp); -+ -+void dce80_compressor_set_fbc_invalidation_triggers(struct compressor *cp, -+ uint32_t fbc_trigger); -+ -+void dce80_compressor_program_compressed_surface_address_and_pitch( -+ struct compressor *cp, -+ struct compr_addr_and_pitch_params *params); -+ -+bool dce80_compressor_get_required_compressed_surface_size( -+ struct compressor *cp, -+ struct fbc_input_info *input_info, -+ struct fbc_requested_compressed_size *size); -+ -+bool dce80_compressor_is_fbc_enabled_in_hw(struct compressor *cp, -+ uint32_t *fbc_mapped_crtc_id); -+ -+/* LPT RELATED */ -+void dce80_compressor_enable_lpt(struct compressor *cp); -+ -+void dce80_compressor_disable_lpt(struct compressor *cp); -+ -+void dce80_compressor_program_lpt_control(struct compressor *cp, -+ struct compr_addr_and_pitch_params *params); -+ -+bool dce80_compressor_is_lpt_enabled_in_hw(struct compressor *cp); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.c -new file mode 100644 -index 0000000..9f3201f ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.c -@@ -0,0 +1,308 @@ -+/* -+ * 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 "dce80_hw_sequencer.h" -+ -+#include "dce110/dce110_hw_sequencer.h" -+ -+#include "gpu/dce80/dc_clock_gating_dce80.h" -+ -+/* include DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+struct dce80_hw_seq_reg_offsets { -+ uint32_t blnd; -+ uint32_t crtc; -+}; -+ -+enum pipe_lock_control { -+ PIPE_LOCK_CONTROL_GRAPHICS = 1 << 0, -+ PIPE_LOCK_CONTROL_BLENDER = 1 << 1, -+ PIPE_LOCK_CONTROL_SCL = 1 << 2, -+ PIPE_LOCK_CONTROL_SURFACE = 1 << 3, -+ PIPE_LOCK_CONTROL_MODE = 1 << 4 -+}; -+ -+enum blender_mode { -+ BLENDER_MODE_CURRENT_PIPE = 0,/* Data from current pipe only */ -+ BLENDER_MODE_OTHER_PIPE, /* Data from other pipe only */ -+ BLENDER_MODE_BLENDING,/* Alpha blending - blend 'current' and 'other' */ -+ BLENDER_MODE_STEREO -+}; -+ -+static const struct dce80_hw_seq_reg_offsets reg_offsets[] = { -+{ -+ .blnd = (mmBLND0_BLND_CONTROL - mmBLND_CONTROL), -+ .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -+}, -+{ -+ .blnd = (mmBLND1_BLND_CONTROL - mmBLND_CONTROL), -+ .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -+}, -+{ -+ .blnd = (mmBLND2_BLND_CONTROL - mmBLND_CONTROL), -+ .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -+}, -+{ -+ .blnd = (mmBLND3_BLND_CONTROL - mmBLND_CONTROL), -+ .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -+}, -+{ -+ .blnd = (mmBLND4_BLND_CONTROL - mmBLND_CONTROL), -+ .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -+}, -+{ -+ .blnd = (mmBLND5_BLND_CONTROL - mmBLND_CONTROL), -+ .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -+} -+}; -+ -+#define HW_REG_BLND(reg, id)\ -+ (reg + reg_offsets[id].blnd) -+ -+#define HW_REG_CRTC(reg, id)\ -+ (reg + reg_offsets[id].crtc) -+ -+ -+ -+/******************************************************************************* -+ * Private definitions -+ ******************************************************************************/ -+ -+/***************************PIPE_CONTROL***********************************/ -+static void dce80_enable_fe_clock( -+ struct dc_context *ctx, uint8_t controller_id, bool enable) -+{ -+ uint32_t value = 0; -+ uint32_t addr; -+ -+ addr = HW_REG_CRTC(mmCRTC_DCFE_CLOCK_CONTROL, controller_id); -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ enable, -+ CRTC_DCFE_CLOCK_CONTROL, -+ CRTC_DCFE_CLOCK_ENABLE); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+static bool dce80_pipe_control_lock( -+ struct dc_context *ctx, -+ uint8_t controller_idx, -+ uint32_t control_mask, -+ bool lock) -+{ -+ uint32_t addr = HW_REG_BLND(mmBLND_V_UPDATE_LOCK, controller_idx); -+ uint32_t value = dm_read_reg(ctx, addr); -+ bool need_to_wait = false; -+ -+ if (control_mask & PIPE_LOCK_CONTROL_GRAPHICS) -+ set_reg_field_value( -+ value, -+ lock, -+ BLND_V_UPDATE_LOCK, -+ BLND_DCP_GRPH_V_UPDATE_LOCK); -+ -+ if (control_mask & PIPE_LOCK_CONTROL_SCL) -+ set_reg_field_value( -+ value, -+ lock, -+ BLND_V_UPDATE_LOCK, -+ BLND_SCL_V_UPDATE_LOCK); -+ -+ if (control_mask & PIPE_LOCK_CONTROL_SURFACE) -+ set_reg_field_value( -+ value, -+ lock, -+ BLND_V_UPDATE_LOCK, -+ BLND_DCP_GRPH_SURF_V_UPDATE_LOCK); -+ -+ dm_write_reg(ctx, addr, value); -+ -+ if (!lock && need_to_wait) { -+ uint8_t counter = 0; -+ const uint8_t counter_limit = 100; -+ const uint16_t delay_us = 1000; -+ -+ uint8_t pipe_pending; -+ -+ addr = HW_REG_BLND(mmBLND_REG_UPDATE_STATUS, -+ controller_idx); -+ -+ while (counter < counter_limit) { -+ value = dm_read_reg(ctx, addr); -+ -+ pipe_pending = 0; -+ -+ if (control_mask & PIPE_LOCK_CONTROL_SCL) { -+ pipe_pending |= -+ get_reg_field_value( -+ value, -+ BLND_REG_UPDATE_STATUS, -+ SCL_BLNDc_UPDATE_PENDING); -+ pipe_pending |= -+ get_reg_field_value( -+ value, -+ BLND_REG_UPDATE_STATUS, -+ SCL_BLNDo_UPDATE_PENDING); -+ } -+ if (control_mask & PIPE_LOCK_CONTROL_GRAPHICS) { -+ pipe_pending |= -+ get_reg_field_value( -+ value, -+ BLND_REG_UPDATE_STATUS, -+ DCP_BLNDc_GRPH_UPDATE_PENDING); -+ pipe_pending |= -+ get_reg_field_value( -+ value, -+ BLND_REG_UPDATE_STATUS, -+ DCP_BLNDo_GRPH_UPDATE_PENDING); -+ } -+ if (control_mask & PIPE_LOCK_CONTROL_SURFACE) { -+ pipe_pending |= get_reg_field_value( -+ value, -+ BLND_REG_UPDATE_STATUS, -+ DCP_BLNDc_GRPH_SURF_UPDATE_PENDING); -+ pipe_pending |= get_reg_field_value( -+ value, -+ BLND_REG_UPDATE_STATUS, -+ DCP_BLNDo_GRPH_SURF_UPDATE_PENDING); -+ } -+ -+ if (pipe_pending == 0) -+ break; -+ -+ counter++; -+ dm_delay_in_microseconds(ctx, delay_us); -+ } -+ -+ if (counter == counter_limit) { -+ dal_logger_write( -+ ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_CONTROLLER, -+ "%s: wait for update exceeded (wait %d us)\n", -+ __func__, -+ counter * delay_us); -+ dal_logger_write( -+ ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_CONTROLLER, -+ "%s: control %d, remain value %x\n", -+ __func__, -+ control_mask, -+ value); -+ } else { -+ /* OK. */ -+ } -+ } -+ -+ return true; -+} -+ -+static void dce80_set_blender_mode( -+ struct dc_context *ctx, -+ uint8_t controller_id, -+ uint32_t mode) -+{ -+ uint32_t value; -+ uint32_t addr = HW_REG_BLND(mmBLND_CONTROL, controller_id); -+ uint32_t blnd_mode; -+ uint32_t feedthrough = 0; -+ -+ switch (mode) { -+ case BLENDER_MODE_OTHER_PIPE: -+ feedthrough = 0; -+ blnd_mode = 1; -+ break; -+ case BLENDER_MODE_BLENDING: -+ feedthrough = 0; -+ blnd_mode = 2; -+ break; -+ case BLENDER_MODE_CURRENT_PIPE: -+ default: -+ feedthrough = 1; -+ blnd_mode = 0; -+ break; -+ } -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ blnd_mode, -+ BLND_CONTROL, -+ BLND_MODE); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+static bool dce80_enable_display_power_gating( -+ struct dc_context *ctx, -+ uint8_t controller_id, -+ struct dc_bios *dcb, -+ enum pipe_gating_control power_gating) -+{ -+ enum bp_result bp_result = BP_RESULT_OK; -+ enum bp_pipe_control_action cntl; -+ -+ if (power_gating == PIPE_GATING_CONTROL_INIT) -+ cntl = ASIC_PIPE_INIT; -+ else if (power_gating == PIPE_GATING_CONTROL_ENABLE) -+ cntl = ASIC_PIPE_ENABLE; -+ else -+ cntl = ASIC_PIPE_DISABLE; -+ -+ if (!(power_gating == PIPE_GATING_CONTROL_INIT && controller_id != 0)) -+ bp_result = dcb->funcs->enable_disp_power_gating( -+ dcb, controller_id + 1, cntl); -+ -+ if (bp_result == BP_RESULT_OK) -+ return true; -+ else -+ return false; -+} -+ -+bool dce80_hw_sequencer_construct(struct dc *dc) -+{ -+ dce110_hw_sequencer_construct(dc); -+ -+ dc->hwss.clock_gating_power_up = dal_dc_clock_gating_dce80_power_up; -+ dc->hwss.enable_fe_clock = dce80_enable_fe_clock; -+ dc->hwss.enable_display_power_gating = dce80_enable_display_power_gating; -+ dc->hwss.pipe_control_lock = dce80_pipe_control_lock; -+ dc->hwss.set_blender_mode = dce80_set_blender_mode; -+ -+ return true; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_hw_sequencer.h -new file mode 100644 -index 0000000..9d6dd05 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_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_DCE80_H__ -+#define __DC_HWSS_DCE80_H__ -+ -+#include "core_types.h" -+ -+struct dc; -+ -+bool dce80_hw_sequencer_construct(struct dc *dc); -+ -+#endif /* __DC_HWSS_DCE80_H__ */ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.c -new file mode 100644 -index 0000000..6dde1eb ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.c -@@ -0,0 +1,64 @@ -+/* -+ * Copyright 2012-15 Advanced Micro Devices, Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -+ * OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * Authors: AMD -+ * -+ */ -+ -+#include "dm_services.h" -+#include "include/logger_interface.h" -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_ipp.h" -+ -+#include "dce110/dce110_ipp.h" -+ -+static struct ipp_funcs funcs = { -+ .ipp_cursor_set_attributes = dce110_ipp_cursor_set_attributes, -+ .ipp_cursor_set_position = dce110_ipp_cursor_set_position, -+ .ipp_program_prescale = dce110_ipp_program_prescale, -+ .ipp_set_degamma = dce110_ipp_set_degamma, -+}; -+ -+bool dce80_ipp_construct( -+ struct dce110_ipp *ipp, -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce110_ipp_reg_offsets *offset) -+{ -+ ipp->base.ctx = ctx; -+ -+ ipp->base.inst = inst; -+ -+ ipp->offsets = *offset; -+ -+ ipp->base.funcs = &funcs; -+ -+ return true; -+} -+ -+void dce80_ipp_destroy(struct input_pixel_processor **ipp) -+{ -+ dm_free((*ipp)->ctx, TO_DCE80_IPP(*ipp)); -+ *ipp = NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.h -new file mode 100644 -index 0000000..bd81693 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp.h -@@ -0,0 +1,49 @@ -+/* -+ * 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_IPP_DCE80_H__ -+#define __DC_IPP_DCE80_H__ -+ -+#include "inc/ipp.h" -+ -+#define TO_DCE80_IPP(input_pixel_processor)\ -+ container_of(input_pixel_processor, struct dce110_ipp, base) -+ -+struct dce110_ipp; -+struct dce110_ipp_reg_offsets; -+struct gamma_parameters; -+struct dev_c_lut; -+ -+ -+bool dce80_ipp_construct( -+ struct dce110_ipp *ipp, -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce110_ipp_reg_offsets *offset); -+ -+void dce80_ipp_destroy(struct input_pixel_processor **ipp); -+ -+ -+#endif /*__DC_IPP_DCE80_H__*/ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp_gamma.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp_gamma.c -new file mode 100644 -index 0000000..fdffb8c ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_ipp_gamma.c -@@ -0,0 +1,85 @@ -+/* -+ * 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 "include/fixed31_32.h" -+#include "basics/conversion.h" -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_ipp.h" -+#include "dce110/dce110_ipp.h" -+#include "gamma_types.h" -+ -+#define DCP_REG(reg)\ -+ (reg + ipp80->offsets.dcp_offset) -+ -+enum { -+ MAX_INPUT_LUT_ENTRY = 256 -+}; -+ -+ -+/*PROTOTYPE DECLARATIONS*/ -+ -+ -+static void set_legacy_input_gamma_mode( -+ struct dce110_ipp *ipp80, -+ bool is_legacy); -+ -+ -+ -+void dce80_ipp_set_legacy_input_gamma_mode( -+ struct input_pixel_processor *ipp, -+ bool is_legacy) -+{ -+ struct dce110_ipp *ipp80 = TO_DCE80_IPP(ipp); -+ -+ set_legacy_input_gamma_mode(ipp80, is_legacy); -+} -+ -+ -+static void set_legacy_input_gamma_mode( -+ struct dce110_ipp *ipp80, -+ bool is_legacy) -+{ -+ const uint32_t addr = DCP_REG(mmINPUT_GAMMA_CONTROL); -+ uint32_t value = dm_read_reg(ipp80->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ !is_legacy, -+ INPUT_GAMMA_CONTROL, -+ GRPH_INPUT_GAMMA_MODE); -+ -+ dm_write_reg(ipp80->base.ctx, addr, value); -+} -+ -+ -+ -+ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.c -new file mode 100644 -index 0000000..5288436 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.c -@@ -0,0 +1,329 @@ -+/* -+ * 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 "dce80_link_encoder.h" -+#include "stream_encoder.h" -+#include "../dce110/dce110_link_encoder.h" -+#include "i2caux_interface.h" -+ -+/* TODO: change to dce80 header file */ -+#include "dce/dce_11_0_d.h" -+#include "dce/dce_11_0_sh_mask.h" -+#include "dce/dce_11_0_enum.h" -+ -+#define LINK_REG(reg)\ -+ (enc110->link_regs->reg) -+ -+#define DCE8_UNIPHY_MAX_PIXEL_CLK_IN_KHZ 297000 -+ -+#define DEFAULT_AUX_MAX_DATA_SIZE 16 -+#define AUX_MAX_DEFER_WRITE_RETRY 20 -+/* -+ * @brief -+ * Trigger Source Select -+ * ASIC-dependent, actual values for register programming -+ */ -+#define DCE80_DIG_FE_SOURCE_SELECT_INVALID 0x0 -+#define DCE80_DIG_FE_SOURCE_SELECT_DIGA 0x01 -+#define DCE80_DIG_FE_SOURCE_SELECT_DIGB 0x02 -+#define DCE80_DIG_FE_SOURCE_SELECT_DIGC 0x04 -+#define DCE80_DIG_FE_SOURCE_SELECT_DIGD 0x08 -+#define DCE80_DIG_FE_SOURCE_SELECT_DIGE 0x10 -+#define DCE80_DIG_FE_SOURCE_SELECT_DIGF 0x20 -+ -+/* 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 -+ -+enum { -+ DP_MST_UPDATE_MAX_RETRY = 50 -+}; -+ -+static enum bp_result link_transmitter_control( -+ struct dce110_link_encoder *enc110, -+ struct bp_transmitter_control *cntl) -+{ -+ enum bp_result result; -+ struct dc_bios *bp = dal_adapter_service_get_bios_parser( -+ enc110->base.adapter_service); -+ -+ result = bp->funcs->transmitter_control(bp, cntl); -+ -+ return result; -+} -+ -+static void dce80_link_encoder_enable_tmds_output( -+ struct link_encoder *enc, -+ enum clock_source_id clock_source, -+ enum dc_color_depth color_depth, -+ bool hdmi, -+ bool dual_link, -+ uint32_t pixel_clock) -+{ -+ struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ struct bp_transmitter_control cntl = { 0 }; -+ enum bp_result result; -+ -+ /* Enable the PHY */ -+ -+ cntl.action = TRANSMITTER_CONTROL_ENABLE; -+ cntl.engine_id = enc->preferred_engine; -+ cntl.transmitter = enc110->base.transmitter; -+ cntl.pll_id = clock_source; -+ if (hdmi) { -+ cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; -+ cntl.lanes_number = 4; -+ } else if (dual_link) { -+ cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; -+ cntl.lanes_number = 8; -+ } else { -+ cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; -+ cntl.lanes_number = 4; -+ } -+ cntl.hpd_sel = enc110->base.hpd_source; -+ -+ cntl.pixel_clock = pixel_clock; -+ cntl.color_depth = color_depth; -+ -+ result = link_transmitter_control(enc110, &cntl); -+ -+ if (result != BP_RESULT_OK) { -+ dal_logger_write(ctx->logger, -+ LOG_MAJOR_ERROR, -+ LOG_MINOR_COMPONENT_ENCODER, -+ "%s: Failed to execute VBIOS command table!\n", -+ __func__); -+ BREAK_TO_DEBUGGER(); -+ } -+} -+ -+static void configure_encoder( -+ struct dce110_link_encoder *enc110, -+ const struct dc_link_settings *link_settings) -+{ -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr; -+ uint32_t value; -+ -+ /* set number of lanes */ -+ addr = LINK_REG(DP_CONFIG); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, link_settings->lane_count - LANE_COUNT_ONE, -+ DP_CONFIG, DP_UDI_LANES); -+ dm_write_reg(ctx, addr, value); -+ -+} -+ -+/* enables DP PHY output */ -+static void dce80_link_encoder_enable_dp_output( -+ struct link_encoder *enc, -+ const struct dc_link_settings *link_settings, -+ enum clock_source_id clock_source) -+{ -+ struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ struct bp_transmitter_control cntl = { 0 }; -+ enum bp_result result; -+ -+ /* Enable the PHY */ -+ -+ /* number_of_lanes is used for pixel clock adjust, -+ * but it's not passed to asic_control. -+ * We need to set number of lanes manually. -+ */ -+ configure_encoder(enc110, link_settings); -+ -+ cntl.action = TRANSMITTER_CONTROL_ENABLE; -+ cntl.engine_id = enc->preferred_engine; -+ cntl.transmitter = enc110->base.transmitter; -+ cntl.pll_id = clock_source; -+ cntl.signal = SIGNAL_TYPE_DISPLAY_PORT; -+ cntl.lanes_number = link_settings->lane_count; -+ cntl.hpd_sel = enc110->base.hpd_source; -+ cntl.pixel_clock = link_settings->link_rate -+ * LINK_RATE_REF_FREQ_IN_KHZ; -+ /* TODO: check if undefined works */ -+ cntl.color_depth = COLOR_DEPTH_UNDEFINED; -+ -+ result = link_transmitter_control(enc110, &cntl); -+ -+ if (result != BP_RESULT_OK) { -+ dal_logger_write(ctx->logger, -+ LOG_MAJOR_ERROR, -+ LOG_MINOR_COMPONENT_ENCODER, -+ "%s: Failed to execute VBIOS command table!\n", -+ __func__); -+ BREAK_TO_DEBUGGER(); -+ } -+} -+ -+static struct link_encoder_funcs dce80_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 = dce80_link_encoder_enable_tmds_output, -+ .enable_dp_output = dce80_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 = dce110_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 -+}; -+ -+ -+bool dce80_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) -+{ -+ struct graphics_object_encoder_cap_info enc_cap_info = {0}; -+ -+ enc110->base.funcs = &dce80_lnk_enc_funcs; -+ enc110->base.ctx = init_data->ctx; -+ enc110->base.id = init_data->encoder; -+ -+ enc110->base.hpd_source = init_data->hpd_source; -+ enc110->base.connector = init_data->connector; -+ enc110->base.input_signals = SIGNAL_TYPE_ALL; -+ -+ enc110->base.adapter_service = init_data->adapter_service; -+ -+ enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; -+ -+ enc110->base.features.flags.raw = 0; -+ -+ enc110->base.transmitter = init_data->transmitter; -+ -+ enc110->base.features.flags.bits.IS_AUDIO_CAPABLE = true; -+ -+ enc110->base.features.max_pixel_clock = DCE8_UNIPHY_MAX_PIXEL_CLK_IN_KHZ; -+ -+ /* set the flag to indicate whether driver poll the I2C data pin -+ * while doing the DP sink detect -+ */ -+ -+ if (dal_adapter_service_is_feature_supported( -+ FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) -+ enc110->base.features.flags.bits. -+ DP_SINK_DETECT_POLL_DATA_PIN = true; -+ -+ enc110->base.output_signals = -+ SIGNAL_TYPE_DVI_SINGLE_LINK | -+ SIGNAL_TYPE_DVI_DUAL_LINK | -+ SIGNAL_TYPE_LVDS | -+ SIGNAL_TYPE_DISPLAY_PORT | -+ SIGNAL_TYPE_DISPLAY_PORT_MST | -+ SIGNAL_TYPE_EDP | -+ SIGNAL_TYPE_HDMI_TYPE_A; -+ -+ /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. -+ * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. -+ * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer -+ * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. -+ * Prefer DIG assignment is decided by board design. -+ * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design -+ * and VBIOS will filter out 7 UNIPHY for DCE 8.0. -+ * By this, adding DIGG should not hurt DCE 8.0. -+ * This will let DCE 8.1 share DCE 8.0 as much as possible -+ */ -+ -+ enc110->link_regs = link_regs; -+ enc110->aux_regs = aux_regs; -+ enc110->bl_regs = bl_regs; -+ -+ switch (enc110->base.transmitter) { -+ case TRANSMITTER_UNIPHY_A: -+ enc110->base.preferred_engine = ENGINE_ID_DIGA; -+ break; -+ case TRANSMITTER_UNIPHY_B: -+ enc110->base.preferred_engine = ENGINE_ID_DIGB; -+ -+ break; -+ case TRANSMITTER_UNIPHY_C: -+ enc110->base.preferred_engine = ENGINE_ID_DIGC; -+ break; -+ case TRANSMITTER_UNIPHY_D: -+ enc110->base.preferred_engine = ENGINE_ID_DIGD; -+ break; -+ case TRANSMITTER_UNIPHY_E: -+ enc110->base.preferred_engine = ENGINE_ID_DIGE; -+ break; -+ case TRANSMITTER_UNIPHY_F: -+ enc110->base.preferred_engine = ENGINE_ID_DIGF; -+ break; -+ default: -+ ASSERT_CRITICAL(false); -+ enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; -+ break; -+ } -+ -+ dal_logger_write(init_data->ctx->logger, -+ LOG_MAJOR_I2C_AUX, -+ LOG_MINOR_I2C_AUX_CFG, -+ "Using channel: %s [%d]\n", -+ DECODE_CHANNEL_ID(init_data->channel), -+ init_data->channel); -+ -+ /* Override features with DCE-specific values */ -+ if (dal_adapter_service_get_encoder_cap_info( -+ enc110->base.adapter_service, -+ enc110->base.id, &enc_cap_info)) -+ enc110->base.features.flags.bits.IS_HBR2_CAPABLE = -+ enc_cap_info.dp_hbr2_cap; -+ -+ /* test pattern 3 support */ -+ enc110->base.features.flags.bits.IS_TPS3_CAPABLE = true; -+ enc110->base.features.max_deep_color = COLOR_DEPTH_121212; -+ -+ enc110->base.features.flags.bits.IS_Y_ONLY_CAPABLE = -+ dal_adapter_service_is_feature_supported( -+ FEATURE_SUPPORT_DP_Y_ONLY); -+ -+ enc110->base.features.flags.bits.IS_YCBCR_CAPABLE = -+ dal_adapter_service_is_feature_supported( -+ FEATURE_SUPPORT_DP_YUV); -+ -+ return true; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.h -new file mode 100644 -index 0000000..b894643 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_link_encoder.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 __DC_LINK_ENCODER__DCE80_H__ -+#define __DC_LINK_ENCODER__DCE80_H__ -+ -+#include "inc/link_encoder.h" -+#include "../dce110/dce110_link_encoder.h" -+ -+bool dce80_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); -+ -+#endif /* __DC_LINK_ENCODER__DCE80_H__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.c -new file mode 100644 -index 0000000..a8e9961 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.c -@@ -0,0 +1,217 @@ -+/* -+ * 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_DCE80_H__ -+ -+#define __DC_MEM_INPUT_DCE80_H__ -+ -+#include "dm_services.h" -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+/* TODO: this needs to be looked at, used by Stella's workaround*/ -+#include "gmc/gmc_7_1_d.h" -+#include "gmc/gmc_7_1_sh_mask.h" -+ -+#include "include/logger_interface.h" -+#include "adapter_service_interface.h" -+#include "inc/bandwidth_calcs.h" -+ -+#include "../dce110/dce110_mem_input.h" -+#include "dce80_mem_input.h" -+ -+ -+#define MAX_WATERMARK 0xFFFF -+#define SAFE_NBP_MARK 0x7FFF -+ -+#define DCP_REG(reg) (reg + mem_input80->offsets.dcp) -+#define DMIF_REG(reg) (reg + mem_input80->offsets.dmif) -+#define PIPE_REG(reg) (reg + mem_input80->offsets.pipe) -+ -+static uint32_t get_dmif_switch_time_us( -+ uint32_t h_total, -+ uint32_t v_total, -+ uint32_t pix_clk_khz) -+{ -+ uint32_t frame_time; -+ uint32_t pixels_per_second; -+ uint32_t pixels_per_frame; -+ uint32_t refresh_rate; -+ const uint32_t us_in_sec = 1000000; -+ const uint32_t min_single_frame_time_us = 30000; -+ /*return double of frame time*/ -+ const uint32_t single_frame_time_multiplier = 2; -+ -+ if (!h_total || v_total || !pix_clk_khz) -+ return single_frame_time_multiplier * min_single_frame_time_us; -+ -+ /*TODO: should we use pixel format normalized pixel clock here?*/ -+ pixels_per_second = pix_clk_khz * 1000; -+ pixels_per_frame = h_total * v_total; -+ -+ if (!pixels_per_second || !pixels_per_frame) { -+ /* avoid division by zero */ -+ ASSERT(pixels_per_frame); -+ ASSERT(pixels_per_second); -+ return single_frame_time_multiplier * min_single_frame_time_us; -+ } -+ -+ refresh_rate = pixels_per_second / pixels_per_frame; -+ -+ if (!refresh_rate) { -+ /* avoid division by zero*/ -+ ASSERT(refresh_rate); -+ return single_frame_time_multiplier * min_single_frame_time_us; -+ } -+ -+ frame_time = us_in_sec / refresh_rate; -+ -+ if (frame_time < min_single_frame_time_us) -+ frame_time = min_single_frame_time_us; -+ -+ frame_time *= single_frame_time_multiplier; -+ -+ return frame_time; -+} -+ -+static void allocate_mem_input( -+ struct mem_input *mi, -+ uint32_t h_total, -+ uint32_t v_total, -+ uint32_t pix_clk_khz, -+ uint32_t total_targets_num) -+{ -+ const uint32_t retry_delay = 10; -+ uint32_t retry_count = get_dmif_switch_time_us( -+ h_total, -+ v_total, -+ pix_clk_khz) / retry_delay; -+ -+ struct dce110_mem_input *bm80 = TO_DCE110_MEM_INPUT(mi); -+ uint32_t addr = bm80->offsets.pipe + mmPIPE0_DMIF_BUFFER_CONTROL; -+ uint32_t value; -+ uint32_t field; -+ -+ if (bm80->supported_stutter_mode -+ & STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION) -+ goto register_underflow_int; -+ -+ /*Allocate DMIF buffer*/ -+ value = dm_read_reg(mi->ctx, addr); -+ field = get_reg_field_value( -+ value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED); -+ if (field == 2) -+ goto register_underflow_int; -+ -+ set_reg_field_value( -+ value, -+ 2, -+ PIPE0_DMIF_BUFFER_CONTROL, -+ DMIF_BUFFERS_ALLOCATED); -+ -+ dm_write_reg(mi->ctx, addr, value); -+ -+ do { -+ value = dm_read_reg(mi->ctx, addr); -+ field = get_reg_field_value( -+ value, -+ PIPE0_DMIF_BUFFER_CONTROL, -+ DMIF_BUFFERS_ALLOCATION_COMPLETED); -+ -+ if (field) -+ break; -+ -+ dm_delay_in_microseconds(mi->ctx, retry_delay); -+ retry_count--; -+ -+ } while (retry_count > 0); -+ -+ if (field == 0) -+ dal_logger_write(mi->ctx->logger, -+ LOG_MAJOR_ERROR, -+ LOG_MINOR_COMPONENT_GPU, -+ "%s: DMIF allocation failed", -+ __func__); -+ -+ /* -+ * Stella Wong proposed the following change -+ * -+ * Value of mcHubRdReqDmifLimit.ENABLE: -+ * 00 - disable DMIF rdreq limit -+ * 01 - enable DMIF rdreq limit, disabled by DMIF stall = 1 || urg != 0 -+ * 02 - enable DMIF rdreq limit, disable by DMIF stall = 1 -+ * 03 - force enable DMIF rdreq limit, ignore DMIF stall / urgent -+ */ -+ addr = mmMC_HUB_RDREQ_DMIF_LIMIT; -+ value = dm_read_reg(mi->ctx, addr); -+ if (total_targets_num > 1) -+ set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE); -+ else -+ set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE); -+ dm_write_reg(mi->ctx, addr, value); -+ -+register_underflow_int: -+ /*todo*/; -+ /*register_interrupt(bm80, irq_source, ctrl_id);*/ -+} -+ -+static struct mem_input_funcs dce80_mem_input_funcs = { -+ .mem_input_program_display_marks = -+ dce110_mem_input_program_display_marks, -+ .allocate_mem_input = allocate_mem_input, -+ .free_mem_input = -+ dce110_free_mem_input, -+ .mem_input_program_surface_flip_and_addr = -+ dce110_mem_input_program_surface_flip_and_addr, -+ .mem_input_program_surface_config = -+ dce110_mem_input_program_surface_config, -+}; -+ -+/*****************************************/ -+/* Constructor, Destructor */ -+/*****************************************/ -+ -+bool dce80_mem_input_construct( -+ struct dce110_mem_input *mem_input80, -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce110_mem_input_reg_offsets *offsets) -+{ -+ -+ mem_input80->base.funcs = &dce80_mem_input_funcs; -+ mem_input80->base.ctx = ctx; -+ -+ mem_input80->base.inst = inst; -+ -+ mem_input80->offsets = *offsets; -+ -+ mem_input80->supported_stutter_mode = 0; -+ dal_adapter_service_get_feature_value(FEATURE_STUTTER_MODE, -+ &(mem_input80->supported_stutter_mode), -+ sizeof(mem_input80->supported_stutter_mode)); -+ -+ return true; -+} -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.h -new file mode 100644 -index 0000000..1d299da ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_mem_input.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_MEM_INPUT_DCE80_H__ -+#define __DC_MEM_INPUT_DCE80_H__ -+ -+#include "inc/mem_input.h" -+ -+bool dce80_mem_input_construct( -+ struct dce110_mem_input *mem_input80, -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce110_mem_input_reg_offsets *offsets); -+ -+ -+enum dc_status dce_base_validate_mapped_resource( -+ const struct dc *dc, -+ struct validate_context *context); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.c -new file mode 100644 -index 0000000..82c98a1 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.c -@@ -0,0 +1,141 @@ -+/* -+ * 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 DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_opp.h" -+ -+#define FROM_OPP(opp)\ -+ container_of(opp, struct dce80_opp, base) -+ -+enum { -+ MAX_LUT_ENTRY = 256, -+ MAX_NUMBER_OF_ENTRIES = 256 -+}; -+ -+static const struct dce80_opp_reg_offsets reg_offsets[] = { -+{ -+ .fmt_offset = (mmFMT0_FMT_CONTROL - mmFMT0_FMT_CONTROL), -+ .crtc_offset = (mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ .fmt_offset = (mmFMT1_FMT_CONTROL - mmFMT0_FMT_CONTROL), -+ .crtc_offset = (mmCRTC1_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ .fmt_offset = (mmFMT2_FMT_CONTROL - mmFMT0_FMT_CONTROL), -+ .crtc_offset = (mmCRTC2_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .fmt_offset = (mmFMT3_FMT_CONTROL - mmFMT0_FMT_CONTROL), -+ .crtc_offset = (mmCRTC3_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .fmt_offset = (mmFMT4_FMT_CONTROL - mmFMT0_FMT_CONTROL), -+ .crtc_offset = (mmCRTC4_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .fmt_offset = (mmFMT5_FMT_CONTROL - mmFMT0_FMT_CONTROL), -+ .crtc_offset = (mmCRTC5_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+} -+}; -+ -+ -+ -+static struct opp_funcs funcs = { -+ .opp_power_on_regamma_lut = dce80_opp_power_on_regamma_lut, -+ .opp_program_bit_depth_reduction = -+ dce80_opp_program_bit_depth_reduction, -+ .opp_program_clamping_and_pixel_encoding = -+ dce80_opp_program_clamping_and_pixel_encoding, -+ .opp_set_csc_adjustment = dce80_opp_set_csc_adjustment, -+ .opp_set_csc_default = dce80_opp_set_csc_default, -+ .opp_set_dyn_expansion = dce80_opp_set_dyn_expansion, -+ .opp_program_regamma_pwl = dce80_opp_program_regamma_pwl, -+ .opp_set_regamma_mode = dce80_opp_set_regamma_mode, -+ .opp_destroy = dce80_opp_destroy, -+}; -+ -+/*****************************************/ -+/* Constructor, Destructor */ -+/*****************************************/ -+ -+bool dce80_opp_construct(struct dce80_opp *opp80, -+ struct dc_context *ctx, -+ uint32_t inst) -+{ -+ if (inst >= ARRAY_SIZE(reg_offsets)) -+ return false; -+ -+ opp80->base.funcs = &funcs; -+ -+ opp80->base.ctx = ctx; -+ -+ opp80->base.inst = inst; -+ -+ opp80->offsets = reg_offsets[inst]; -+ -+ return true; -+} -+ -+void dce80_opp_destroy(struct output_pixel_processor **opp) -+{ -+ dm_free((*opp)->ctx, FROM_OPP(*opp)); -+ *opp = NULL; -+} -+ -+struct output_pixel_processor *dce80_opp_create( -+ struct dc_context *ctx, -+ uint32_t inst) -+{ -+ struct dce80_opp *opp = -+ dm_alloc(ctx, sizeof(struct dce80_opp)); -+ -+ if (!opp) -+ return NULL; -+ -+ if (dce80_opp_construct(opp, -+ ctx, inst)) -+ return &opp->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, opp); -+ return NULL; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.h -new file mode 100644 -index 0000000..d414f50 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp.h -@@ -0,0 +1,130 @@ -+/* 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_OPP_DCE80_H__ -+#define __DC_OPP_DCE80_H__ -+ -+#include "dc_types.h" -+#include "inc/opp.h" -+#include "gamma_types.h" -+ -+struct gamma_parameters; -+ -+struct dce80_regamma { -+ struct gamma_curve arr_curve_points[16]; -+ struct curve_points arr_points[3]; -+ uint32_t hw_points_num; -+ struct hw_x_point *coordinates_x; -+ struct pwl_result_data *rgb_resulted; -+ -+ /* re-gamma curve */ -+ struct pwl_float_data_ex *rgb_regamma; -+ /* coeff used to map user evenly distributed points -+ * to our hardware points (predefined) for gamma 256 */ -+ struct pixel_gamma_point *coeff128; -+ struct pixel_gamma_point *coeff128_oem; -+ /* coeff used to map user evenly distributed points -+ * to our hardware points (predefined) for gamma 1025 */ -+ struct pixel_gamma_point *coeff128_dx; -+ /* evenly distributed points, gamma 256 software points 0-255 */ -+ struct gamma_pixel *axis_x_256; -+ /* evenly distributed points, gamma 1025 software points 0-1025 */ -+ struct gamma_pixel *axis_x_1025; -+ /* OEM supplied gamma for regamma LUT */ -+ struct pwl_float_data *rgb_oem; -+ /* user supplied gamma */ -+ struct pwl_float_data *rgb_user; -+ uint32_t extra_points; -+ bool use_half_points; -+ struct fixed31_32 x_max1; -+ struct fixed31_32 x_max2; -+ struct fixed31_32 x_min; -+ struct fixed31_32 divider1; -+ struct fixed31_32 divider2; -+ struct fixed31_32 divider3; -+}; -+ -+/* OPP RELATED */ -+#define TO_DCE80_OPP(opp)\ -+ container_of(opp, struct dce80_opp, base) -+ -+struct dce80_opp_reg_offsets { -+ uint32_t fmt_offset; -+ uint32_t dcp_offset; -+ uint32_t crtc_offset; -+}; -+ -+struct dce80_opp { -+ struct output_pixel_processor base; -+ struct dce80_opp_reg_offsets offsets; -+ struct dce80_regamma regamma; -+}; -+ -+bool dce80_opp_construct(struct dce80_opp *opp80, -+ struct dc_context *ctx, -+ uint32_t inst); -+ -+void dce80_opp_destroy(struct output_pixel_processor **opp); -+ -+struct output_pixel_processor *dce80_opp_create( -+ struct dc_context *ctx, -+ uint32_t inst); -+ -+/* REGAMMA RELATED */ -+void dce80_opp_power_on_regamma_lut( -+ struct output_pixel_processor *opp, -+ bool power_on); -+ -+bool dce80_opp_program_regamma_pwl( -+ struct output_pixel_processor *opp, -+ const struct regamma_params *pamras); -+ -+void dce80_opp_set_regamma_mode(struct output_pixel_processor *opp, -+ enum opp_regamma mode); -+ -+void dce80_opp_set_csc_adjustment( -+ struct output_pixel_processor *opp, -+ const struct grph_csc_adjustment *adjust); -+ -+void dce80_opp_set_csc_default( -+ struct output_pixel_processor *opp, -+ const struct default_adjustment *default_adjust); -+ -+/* FORMATTER RELATED */ -+void dce80_opp_program_bit_depth_reduction( -+ struct output_pixel_processor *opp, -+ const struct bit_depth_reduction_params *params); -+ -+void dce80_opp_program_clamping_and_pixel_encoding( -+ struct output_pixel_processor *opp, -+ const struct clamping_and_pixel_encoding_params *params); -+ -+ -+void dce80_opp_set_dyn_expansion( -+ struct output_pixel_processor *opp, -+ enum color_space color_sp, -+ enum dc_color_depth color_dpth, -+ enum signal_type signal); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_csc.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_csc.c -new file mode 100644 -index 0000000..90662ae ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_csc.c -@@ -0,0 +1,905 @@ -+/* -+ * 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 "dce80_opp.h" -+#include "basics/conversion.h" -+ -+/* include DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#define DCP_REG(reg)\ -+ (reg + opp80->offsets.dcp_offset) -+ -+enum { -+ OUTPUT_CSC_MATRIX_SIZE = 12 -+}; -+ -+struct out_csc_color_matrix { -+ enum color_space color_space; -+ uint16_t regval[OUTPUT_CSC_MATRIX_SIZE]; -+}; -+ -+static const struct out_csc_color_matrix global_color_matrix[] = { -+{ COLOR_SPACE_SRGB_FULL_RANGE, -+ { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, -+{ COLOR_SPACE_SRGB_LIMITED_RANGE, -+ { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} }, -+{ COLOR_SPACE_YCBCR601, -+ { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47, -+ 0xF6B9, 0xE00, 0x1000} }, -+{ COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA, -+ 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }, -+/* YOnly same as YCbCr709 but Y in Full range -To do. */ -+{ COLOR_SPACE_YCBCR601_YONLY, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991, -+ 0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} }, -+{ COLOR_SPACE_YCBCR709_YONLY, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3, -+ 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} } -+}; -+ -+enum csc_color_mode { -+ /* 00 - BITS2:0 Bypass */ -+ CSC_COLOR_MODE_GRAPHICS_BYPASS, -+ /* 01 - hard coded coefficient TV RGB */ -+ CSC_COLOR_MODE_GRAPHICS_PREDEFINED, -+ /* 04 - programmable OUTPUT CSC coefficient */ -+ CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC, -+}; -+ -+static void program_color_matrix( -+ struct dce80_opp *opp80, -+ const struct out_csc_color_matrix *tbl_entry, -+ enum grph_color_adjust_option options) -+{ -+ struct dc_context *ctx = opp80->base.ctx; -+ { -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C11_C12); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[0], -+ OUTPUT_CSC_C11_C12, -+ OUTPUT_CSC_C11); -+ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[1], -+ OUTPUT_CSC_C11_C12, -+ OUTPUT_CSC_C12); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C13_C14); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[2], -+ OUTPUT_CSC_C13_C14, -+ OUTPUT_CSC_C13); -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[3], -+ OUTPUT_CSC_C13_C14, -+ OUTPUT_CSC_C14); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C21_C22); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[4], -+ OUTPUT_CSC_C21_C22, -+ OUTPUT_CSC_C21); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[5], -+ OUTPUT_CSC_C21_C22, -+ OUTPUT_CSC_C22); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C23_C24); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[6], -+ OUTPUT_CSC_C23_C24, -+ OUTPUT_CSC_C23); -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[7], -+ OUTPUT_CSC_C23_C24, -+ OUTPUT_CSC_C24); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C31_C32); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[8], -+ OUTPUT_CSC_C31_C32, -+ OUTPUT_CSC_C31); -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[9], -+ OUTPUT_CSC_C31_C32, -+ OUTPUT_CSC_C32); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C33_C34); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[10], -+ OUTPUT_CSC_C33_C34, -+ OUTPUT_CSC_C33); -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ value, -+ tbl_entry->regval[11], -+ OUTPUT_CSC_C33_C34, -+ OUTPUT_CSC_C34); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+} -+ -+/* -+ * initialize_color_float_adj_reference_values -+ * This initialize display color adjust input from API to HW range for later -+ * calculation use. This is shared by all the display color adjustment. -+ * @param : -+ * @return None -+ */ -+static void initialize_color_float_adj_reference_values( -+ const struct grph_csc_adjustment *adjust, -+ struct fixed31_32 *grph_cont, -+ struct fixed31_32 *grph_sat, -+ struct fixed31_32 *grph_bright, -+ struct fixed31_32 *sin_grph_hue, -+ struct fixed31_32 *cos_grph_hue) -+{ -+ /* Hue adjustment could be negative. -45 ~ +45 */ -+ struct fixed31_32 hue = -+ dal_fixed31_32_mul( -+ dal_fixed31_32_from_fraction(adjust->grph_hue, 180), -+ dal_fixed31_32_pi); -+ -+ *sin_grph_hue = dal_fixed31_32_sin(hue); -+ *cos_grph_hue = dal_fixed31_32_cos(hue); -+ -+ if (adjust->adjust_divider) { -+ *grph_cont = -+ dal_fixed31_32_from_fraction( -+ adjust->grph_cont, -+ adjust->adjust_divider); -+ *grph_sat = -+ dal_fixed31_32_from_fraction( -+ adjust->grph_sat, -+ adjust->adjust_divider); -+ *grph_bright = -+ dal_fixed31_32_from_fraction( -+ adjust->grph_bright, -+ adjust->adjust_divider); -+ } else { -+ *grph_cont = dal_fixed31_32_from_int(adjust->grph_cont); -+ *grph_sat = dal_fixed31_32_from_int(adjust->grph_sat); -+ *grph_bright = dal_fixed31_32_from_int(adjust->grph_bright); -+ } -+} -+ -+static inline struct fixed31_32 fixed31_32_clamp( -+ struct fixed31_32 value, -+ int32_t min_numerator, -+ int32_t max_numerator, -+ int32_t denominator) -+{ -+ return dal_fixed31_32_clamp( -+ value, -+ dal_fixed31_32_from_fraction( -+ min_numerator, -+ denominator), -+ dal_fixed31_32_from_fraction( -+ max_numerator, -+ denominator)); -+} -+ -+static void setup_reg_format( -+ struct fixed31_32 *coefficients, -+ uint16_t *reg_values) -+{ -+ enum { -+ LENGTH = 12, -+ DENOMINATOR = 10000 -+ }; -+ -+ static const int32_t min_numerator[] = { -+ -3 * DENOMINATOR, -+ -DENOMINATOR -+ }; -+ -+ static const int32_t max_numerator[] = { -+ DENOMINATOR, -+ DENOMINATOR -+ }; -+ -+ static const uint8_t integer_bits[] = { 2, 0 }; -+ -+ uint32_t i = 0; -+ -+ do { -+ const uint32_t index = (i % 4) == 3; -+ -+ reg_values[i] = fixed_point_to_int_frac( -+ fixed31_32_clamp(coefficients[(i + 8) % LENGTH], -+ min_numerator[index], -+ max_numerator[index], -+ DENOMINATOR), -+ integer_bits[index], 13); -+ -+ ++i; -+ } while (i != LENGTH); -+} -+ -+/** -+ ***************************************************************************** -+ * Function: setup_adjustments -+ * @note prepare to setup the values -+ * -+ * @see -+ * -+ ***************************************************************************** -+ */ -+static void setup_adjustments(const struct grph_csc_adjustment *adjust, -+ struct dc_csc_adjustments *adjustments) -+{ -+ if (adjust->adjust_divider != 0) { -+ adjustments->brightness = -+ dal_fixed31_32_from_fraction(adjust->grph_bright, -+ adjust->adjust_divider); -+ adjustments->contrast = -+ dal_fixed31_32_from_fraction(adjust->grph_cont, -+ adjust->adjust_divider); -+ adjustments->saturation = -+ dal_fixed31_32_from_fraction(adjust->grph_sat, -+ adjust->adjust_divider); -+ } else { -+ adjustments->brightness = -+ dal_fixed31_32_from_fraction(adjust->grph_bright, 1); -+ adjustments->contrast = -+ dal_fixed31_32_from_fraction(adjust->grph_cont, 1); -+ adjustments->saturation = -+ dal_fixed31_32_from_fraction(adjust->grph_sat, 1); -+ } -+ -+ /* convert degrees into radians */ -+ adjustments->hue = -+ dal_fixed31_32_mul( -+ dal_fixed31_32_from_fraction(adjust->grph_hue, 180), -+ dal_fixed31_32_pi); -+} -+ -+static void prepare_tv_rgb_ideal( -+ struct fixed31_32 *matrix) -+{ -+ static const int32_t matrix_[] = { -+ 85546875, 0, 0, 6250000, -+ 0, 85546875, 0, 6250000, -+ 0, 0, 85546875, 6250000 -+ }; -+ -+ uint32_t i = 0; -+ -+ do { -+ matrix[i] = dal_fixed31_32_from_fraction( -+ matrix_[i], -+ 100000000); -+ ++i; -+ } while (i != ARRAY_SIZE(matrix_)); -+} -+ -+/** -+ ***************************************************************************** -+ * Function: dal_transform_wide_gamut_set_rgb_adjustment_legacy -+ * -+ * @param [in] const struct grph_csc_adjustment *adjust -+ * -+ * @return -+ * void -+ * -+ * @note calculate and program color adjustments for sRGB color space -+ * -+ * @see -+ * -+ ***************************************************************************** -+ */ -+static void set_rgb_adjustment_legacy( -+ struct dce80_opp *opp80, -+ const struct grph_csc_adjustment *adjust) -+{ -+ const struct fixed31_32 k1 = -+ dal_fixed31_32_from_fraction(701000, 1000000); -+ const struct fixed31_32 k2 = -+ dal_fixed31_32_from_fraction(236568, 1000000); -+ const struct fixed31_32 k3 = -+ dal_fixed31_32_from_fraction(-587000, 1000000); -+ const struct fixed31_32 k4 = -+ dal_fixed31_32_from_fraction(464432, 1000000); -+ const struct fixed31_32 k5 = -+ dal_fixed31_32_from_fraction(-114000, 1000000); -+ const struct fixed31_32 k6 = -+ dal_fixed31_32_from_fraction(-701000, 1000000); -+ const struct fixed31_32 k7 = -+ dal_fixed31_32_from_fraction(-299000, 1000000); -+ const struct fixed31_32 k8 = -+ dal_fixed31_32_from_fraction(-292569, 1000000); -+ const struct fixed31_32 k9 = -+ dal_fixed31_32_from_fraction(413000, 1000000); -+ const struct fixed31_32 k10 = -+ dal_fixed31_32_from_fraction(-92482, 1000000); -+ const struct fixed31_32 k11 = -+ dal_fixed31_32_from_fraction(-114000, 1000000); -+ const struct fixed31_32 k12 = -+ dal_fixed31_32_from_fraction(385051, 1000000); -+ const struct fixed31_32 k13 = -+ dal_fixed31_32_from_fraction(-299000, 1000000); -+ const struct fixed31_32 k14 = -+ dal_fixed31_32_from_fraction(886000, 1000000); -+ const struct fixed31_32 k15 = -+ dal_fixed31_32_from_fraction(-587000, 1000000); -+ const struct fixed31_32 k16 = -+ dal_fixed31_32_from_fraction(-741914, 1000000); -+ const struct fixed31_32 k17 = -+ dal_fixed31_32_from_fraction(886000, 1000000); -+ const struct fixed31_32 k18 = -+ dal_fixed31_32_from_fraction(-144086, 1000000); -+ -+ const struct fixed31_32 luma_r = -+ dal_fixed31_32_from_fraction(299, 1000); -+ const struct fixed31_32 luma_g = -+ dal_fixed31_32_from_fraction(587, 1000); -+ const struct fixed31_32 luma_b = -+ dal_fixed31_32_from_fraction(114, 1000); -+ -+ struct out_csc_color_matrix tbl_entry; -+ struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE]; -+ -+ struct fixed31_32 grph_cont; -+ struct fixed31_32 grph_sat; -+ struct fixed31_32 grph_bright; -+ struct fixed31_32 sin_grph_hue; -+ struct fixed31_32 cos_grph_hue; -+ -+ initialize_color_float_adj_reference_values( -+ adjust, &grph_cont, &grph_sat, -+ &grph_bright, &sin_grph_hue, &cos_grph_hue); -+ -+ /* COEF_1_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 + -+ * Sin(GrphHue) * K2)) */ -+ /* (Cos(GrphHue) * K1 + Sin(GrphHue) * K2) */ -+ matrix[0] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k1), -+ dal_fixed31_32_mul(sin_grph_hue, k2)); -+ /* GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2 */ -+ matrix[0] = dal_fixed31_32_mul(grph_sat, matrix[0]); -+ /* (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2)) */ -+ matrix[0] = dal_fixed31_32_add(luma_r, matrix[0]); -+ /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * -+ * K2)) */ -+ matrix[0] = dal_fixed31_32_mul(grph_cont, matrix[0]); -+ -+ /* COEF_1_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 + -+ * Sin(GrphHue) * K4)) */ -+ /* (Cos(GrphHue) * K3 + Sin(GrphHue) * K4) */ -+ matrix[1] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k3), -+ dal_fixed31_32_mul(sin_grph_hue, k4)); -+ /* GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4) */ -+ matrix[1] = dal_fixed31_32_mul(grph_sat, matrix[1]); -+ /* (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4)) */ -+ matrix[1] = dal_fixed31_32_add(luma_g, matrix[1]); -+ /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * -+ * K4)) */ -+ matrix[1] = dal_fixed31_32_mul(grph_cont, matrix[1]); -+ -+ /* COEF_1_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 + -+ * Sin(GrphHue) * K6)) */ -+ /* (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */ -+ matrix[2] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k5), -+ dal_fixed31_32_mul(sin_grph_hue, k6)); -+ /* GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */ -+ matrix[2] = dal_fixed31_32_mul(grph_sat, matrix[2]); -+ /* LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */ -+ matrix[2] = dal_fixed31_32_add(luma_b, matrix[2]); -+ /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * -+ * K6)) */ -+ matrix[2] = dal_fixed31_32_mul(grph_cont, matrix[2]); -+ -+ /* COEF_1_4 = GrphBright */ -+ matrix[3] = grph_bright; -+ -+ /* COEF_2_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 + -+ * Sin(GrphHue) * K8)) */ -+ /* (Cos(GrphHue) * K7 + Sin(GrphHue) * K8) */ -+ matrix[4] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k7), -+ dal_fixed31_32_mul(sin_grph_hue, k8)); -+ /* GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8) */ -+ matrix[4] = dal_fixed31_32_mul(grph_sat, matrix[4]); -+ /* (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8)) */ -+ matrix[4] = dal_fixed31_32_add(luma_r, matrix[4]); -+ /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * -+ * K8)) */ -+ matrix[4] = dal_fixed31_32_mul(grph_cont, matrix[4]); -+ -+ /* COEF_2_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 + -+ * Sin(GrphHue) * K10)) */ -+ /* (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */ -+ matrix[5] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k9), -+ dal_fixed31_32_mul(sin_grph_hue, k10)); -+ /* GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */ -+ matrix[5] = dal_fixed31_32_mul(grph_sat, matrix[5]); -+ /* (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */ -+ matrix[5] = dal_fixed31_32_add(luma_g, matrix[5]); -+ /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * -+ * K10)) */ -+ matrix[5] = dal_fixed31_32_mul(grph_cont, matrix[5]); -+ -+ /* COEF_2_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 + -+ * Sin(GrphHue) * K12)) */ -+ /* (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */ -+ matrix[6] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k11), -+ dal_fixed31_32_mul(sin_grph_hue, k12)); -+ /* GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */ -+ matrix[6] = dal_fixed31_32_mul(grph_sat, matrix[6]); -+ /* (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */ -+ matrix[6] = dal_fixed31_32_add(luma_b, matrix[6]); -+ /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * -+ * K12)) */ -+ matrix[6] = dal_fixed31_32_mul(grph_cont, matrix[6]); -+ -+ /* COEF_2_4 = GrphBright */ -+ matrix[7] = grph_bright; -+ -+ /* COEF_3_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K13 + -+ * Sin(GrphHue) * K14)) */ -+ /* (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */ -+ matrix[8] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k13), -+ dal_fixed31_32_mul(sin_grph_hue, k14)); -+ /* GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */ -+ matrix[8] = dal_fixed31_32_mul(grph_sat, matrix[8]); -+ /* (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */ -+ matrix[8] = dal_fixed31_32_add(luma_r, matrix[8]); -+ /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * -+ * K14)) */ -+ matrix[8] = dal_fixed31_32_mul(grph_cont, matrix[8]); -+ -+ /* COEF_3_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 + -+ * Sin(GrphHue) * K16)) */ -+ /* GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16) */ -+ matrix[9] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k15), -+ dal_fixed31_32_mul(sin_grph_hue, k16)); -+ /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */ -+ matrix[9] = dal_fixed31_32_mul(grph_sat, matrix[9]); -+ /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */ -+ matrix[9] = dal_fixed31_32_add(luma_g, matrix[9]); -+ /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * -+ * K16)) */ -+ matrix[9] = dal_fixed31_32_mul(grph_cont, matrix[9]); -+ -+ /* COEF_3_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 + -+ * Sin(GrphHue) * K18)) */ -+ /* (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */ -+ matrix[10] = -+ dal_fixed31_32_add( -+ dal_fixed31_32_mul(cos_grph_hue, k17), -+ dal_fixed31_32_mul(sin_grph_hue, k18)); -+ /* GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */ -+ matrix[10] = dal_fixed31_32_mul(grph_sat, matrix[10]); -+ /* (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */ -+ matrix[10] = dal_fixed31_32_add(luma_b, matrix[10]); -+ /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * -+ * K18)) */ -+ matrix[10] = dal_fixed31_32_mul(grph_cont, matrix[10]); -+ -+ /* COEF_3_4 = GrphBright */ -+ matrix[11] = grph_bright; -+ -+ tbl_entry.color_space = adjust->c_space; -+ -+ convert_float_matrix(tbl_entry.regval, matrix, OUTPUT_CSC_MATRIX_SIZE); -+ -+ program_color_matrix( -+ opp80, &tbl_entry, adjust->color_adjust_option); -+} -+ -+/** -+ ***************************************************************************** -+ * Function: dal_transform_wide_gamut_set_rgb_limited_range_adjustment -+ * -+ * @param [in] const struct grph_csc_adjustment *adjust -+ * -+ * @return -+ * void -+ * -+ * @note calculate and program color adjustments for sRGB limited color space -+ * -+ * @see -+ * -+ ***************************************************************************** -+ */ -+static void set_rgb_limited_range_adjustment( -+ struct dce80_opp *opp80, -+ const struct grph_csc_adjustment *adjust) -+{ -+ struct out_csc_color_matrix reg_matrix; -+ struct fixed31_32 change_matrix[OUTPUT_CSC_MATRIX_SIZE]; -+ struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE]; -+ struct dc_csc_adjustments adjustments; -+ struct fixed31_32 ideals[OUTPUT_CSC_MATRIX_SIZE]; -+ -+ prepare_tv_rgb_ideal(ideals); -+ -+ setup_adjustments(adjust, &adjustments); -+ -+ calculate_adjustments(ideals, &adjustments, matrix); -+ -+ dm_memmove(change_matrix, matrix, sizeof(matrix)); -+ -+ /* from 1 -> 3 */ -+ matrix[8] = change_matrix[0]; -+ matrix[9] = change_matrix[1]; -+ matrix[10] = change_matrix[2]; -+ matrix[11] = change_matrix[3]; -+ -+ /* from 2 -> 1 */ -+ matrix[0] = change_matrix[4]; -+ matrix[1] = change_matrix[5]; -+ matrix[2] = change_matrix[6]; -+ matrix[3] = change_matrix[7]; -+ -+ /* from 3 -> 2 */ -+ matrix[4] = change_matrix[8]; -+ matrix[5] = change_matrix[9]; -+ matrix[6] = change_matrix[10]; -+ matrix[7] = change_matrix[11]; -+ -+ dm_memset(®_matrix, 0, sizeof(struct out_csc_color_matrix)); -+ -+ setup_reg_format(matrix, reg_matrix.regval); -+ -+ program_color_matrix(opp80, ®_matrix, GRPH_COLOR_MATRIX_SW); -+} -+ -+static void prepare_yuv_ideal( -+ bool b601, -+ struct fixed31_32 *matrix) -+{ -+ static const int32_t matrix_1[] = { -+ 25578516, 50216016, 9752344, 6250000, -+ -14764391, -28985609, 43750000, 50000000, -+ 43750000, -36635164, -7114836, 50000000 -+ }; -+ -+ static const int32_t matrix_2[] = { -+ 18187266, 61183125, 6176484, 6250000, -+ -10025059, -33724941, 43750000, 50000000, -+ 43750000, -39738379, -4011621, 50000000 -+ }; -+ -+ const int32_t *matrix_x = b601 ? matrix_1 : matrix_2; -+ -+ uint32_t i = 0; -+ -+ do { -+ matrix[i] = dal_fixed31_32_from_fraction( -+ matrix_x[i], -+ 100000000); -+ ++i; -+ } while (i != ARRAY_SIZE(matrix_1)); -+} -+ -+/** -+ ***************************************************************************** -+ * Function: dal_transform_wide_gamut_set_yuv_adjustment -+ * -+ * @param [in] const struct grph_csc_adjustment *adjust -+ * -+ * @return -+ * void -+ * -+ * @note calculate and program color adjustments for YUV color spaces -+ * -+ * @see -+ * -+ ***************************************************************************** -+ */ -+static void set_yuv_adjustment( -+ struct dce80_opp *opp80, -+ const struct grph_csc_adjustment *adjust) -+{ -+ bool b601 = (adjust->c_space == COLOR_SPACE_YPBPR601) || -+ (adjust->c_space == COLOR_SPACE_YCBCR601) || -+ (adjust->c_space == COLOR_SPACE_YCBCR601_YONLY); -+ struct out_csc_color_matrix reg_matrix; -+ struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE]; -+ struct dc_csc_adjustments adjustments; -+ struct fixed31_32 ideals[OUTPUT_CSC_MATRIX_SIZE]; -+ -+ prepare_yuv_ideal(b601, ideals); -+ -+ setup_adjustments(adjust, &adjustments); -+ -+ if ((adjust->c_space == COLOR_SPACE_YCBCR601_YONLY) || -+ (adjust->c_space == COLOR_SPACE_YCBCR709_YONLY)) -+ calculate_adjustments_y_only( -+ ideals, &adjustments, matrix); -+ else -+ calculate_adjustments( -+ ideals, &adjustments, matrix); -+ -+ dm_memset(®_matrix, 0, sizeof(struct out_csc_color_matrix)); -+ -+ setup_reg_format(matrix, reg_matrix.regval); -+ -+ program_color_matrix(opp80, ®_matrix, GRPH_COLOR_MATRIX_SW); -+} -+ -+static bool configure_graphics_mode( -+ struct dce80_opp *opp80, -+ enum csc_color_mode config, -+ enum graphics_csc_adjust_type csc_adjust_type, -+ enum color_space color_space) -+{ -+ struct dc_context *ctx = opp80->base.ctx; -+ uint32_t addr = DCP_REG(mmOUTPUT_CSC_CONTROL); -+ uint32_t value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ -+ if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) { -+ if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) { -+ set_reg_field_value( -+ value, -+ 4, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ } else { -+ -+ switch (color_space) { -+ case COLOR_SPACE_SRGB_FULL_RANGE: -+ /* by pass */ -+ set_reg_field_value( -+ value, -+ 0, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ case COLOR_SPACE_SRGB_LIMITED_RANGE: -+ /* TV RGB */ -+ set_reg_field_value( -+ value, -+ 1, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ case COLOR_SPACE_YCBCR601: -+ case COLOR_SPACE_YPBPR601: -+ case COLOR_SPACE_YCBCR601_YONLY: -+ /* YCbCr601 */ -+ set_reg_field_value( -+ value, -+ 2, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ case COLOR_SPACE_YCBCR709: -+ case COLOR_SPACE_YPBPR709: -+ case COLOR_SPACE_YCBCR709_YONLY: -+ /* YCbCr709 */ -+ set_reg_field_value( -+ value, -+ 3, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ default: -+ return false; -+ } -+ } -+ } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) { -+ switch (color_space) { -+ case COLOR_SPACE_SRGB_FULL_RANGE: -+ /* by pass */ -+ set_reg_field_value( -+ value, -+ 0, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ case COLOR_SPACE_SRGB_LIMITED_RANGE: -+ /* TV RGB */ -+ set_reg_field_value( -+ value, -+ 1, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ case COLOR_SPACE_YCBCR601: -+ case COLOR_SPACE_YPBPR601: -+ case COLOR_SPACE_YCBCR601_YONLY: -+ /* YCbCr601 */ -+ set_reg_field_value( -+ value, -+ 2, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ case COLOR_SPACE_YCBCR709: -+ case COLOR_SPACE_YPBPR709: -+ case COLOR_SPACE_YCBCR709_YONLY: -+ /* YCbCr709 */ -+ set_reg_field_value( -+ value, -+ 3, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ break; -+ default: -+ return false; -+ } -+ -+ } else -+ /* by pass */ -+ set_reg_field_value( -+ value, -+ 0, -+ OUTPUT_CSC_CONTROL, -+ OUTPUT_CSC_GRPH_MODE); -+ -+ addr = DCP_REG(mmOUTPUT_CSC_CONTROL); -+ dm_write_reg(ctx, addr, value); -+ -+ return true; -+} -+ -+void dce80_opp_set_csc_adjustment( -+ struct output_pixel_processor *opp, -+ const struct grph_csc_adjustment *adjust) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ enum csc_color_mode config = -+ CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; -+ -+ /* Apply color adjustments: brightness, saturation, hue, contrast and -+ * CSC. No need for different color space routine, color space defines -+ * the ideal values only, but keep original design to allow quick switch -+ * to the old legacy routines */ -+ switch (adjust->c_space) { -+ case COLOR_SPACE_SRGB_FULL_RANGE: -+ set_rgb_adjustment_legacy(opp80, adjust); -+ break; -+ case COLOR_SPACE_SRGB_LIMITED_RANGE: -+ set_rgb_limited_range_adjustment( -+ opp80, adjust); -+ break; -+ case COLOR_SPACE_YCBCR601: -+ case COLOR_SPACE_YCBCR709: -+ case COLOR_SPACE_YCBCR601_YONLY: -+ case COLOR_SPACE_YCBCR709_YONLY: -+ case COLOR_SPACE_YPBPR601: -+ case COLOR_SPACE_YPBPR709: -+ set_yuv_adjustment(opp80, adjust); -+ break; -+ default: -+ set_rgb_adjustment_legacy(opp80, adjust); -+ break; -+ } -+ -+ /* We did everything ,now program DxOUTPUT_CSC_CONTROL */ -+ configure_graphics_mode(opp80, config, adjust->csc_adjust_type, -+ adjust->c_space); -+} -+ -+void dce80_opp_set_csc_default( -+ struct output_pixel_processor *opp, -+ const struct default_adjustment *default_adjust) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ enum csc_color_mode config = -+ CSC_COLOR_MODE_GRAPHICS_PREDEFINED; -+ -+ if (default_adjust->force_hw_default == false) { -+ const struct out_csc_color_matrix *elm; -+ /* currently parameter not in use */ -+ enum grph_color_adjust_option option = -+ GRPH_COLOR_MATRIX_HW_DEFAULT; -+ uint32_t i; -+ /* -+ * HW default false we program locally defined matrix -+ * HW default true we use predefined hw matrix and we -+ * do not need to program matrix -+ * OEM wants the HW default via runtime parameter. -+ */ -+ option = GRPH_COLOR_MATRIX_SW; -+ -+ for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) { -+ elm = &global_color_matrix[i]; -+ if (elm->color_space != default_adjust->color_space) -+ continue; -+ /* program the matrix with default values from this -+ * file */ -+ program_color_matrix(opp80, elm, option); -+ config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; -+ break; -+ } -+ } -+ -+ /* configure the what we programmed : -+ * 1. Default values from this file -+ * 2. Use hardware default from ROM_A and we do not need to program -+ * matrix */ -+ -+ configure_graphics_mode(opp80, config, -+ default_adjust->csc_adjust_type, -+ default_adjust->color_space); -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_formatter.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_formatter.c -new file mode 100644 -index 0000000..9d0a214 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_formatter.c -@@ -0,0 +1,577 @@ -+/* -+ * 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_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_opp.h" -+ -+#define FMT_REG(reg)\ -+ (reg + opp80->offsets.fmt_offset) -+ -+/** -+ * set_truncation -+ * 1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp -+ * 2) enable truncation -+ * 3) HW remove 12bit FMT support for DCE8 power saving reason. -+ */ -+static void set_truncation( -+ struct dce80_opp *opp80, -+ const struct bit_depth_reduction_params *params) -+{ -+ uint32_t value = 0; -+ uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL); -+ -+ /*Disable truncation*/ -+ value = dm_read_reg(opp80->base.ctx, addr); -+ set_reg_field_value(value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN); -+ set_reg_field_value(value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH); -+ set_reg_field_value(value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE); -+ -+ dm_write_reg(opp80->base.ctx, addr, value); -+ -+ /* no 10bpc trunc on DCE8*/ -+ if (params->flags.TRUNCATE_ENABLED == 0 || -+ params->flags.TRUNCATE_DEPTH == 2) -+ return; -+ -+ /*Set truncation depth and Enable truncation*/ -+ set_reg_field_value(value, 1, -+ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN); -+ set_reg_field_value(value, params->flags.TRUNCATE_MODE, -+ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE); -+ set_reg_field_value(value, params->flags.TRUNCATE_DEPTH, -+ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH); -+ -+ dm_write_reg(opp80->base.ctx, addr, value); -+ -+} -+ -+/** -+ * set_spatial_dither -+ * 1) set spatial dithering mode: pattern of seed -+ * 2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp -+ * 3) set random seed -+ * 4) set random mode -+ * lfsr is reset every frame or not reset -+ * RGB dithering method -+ * 0: RGB data are all dithered with x^28+x^3+1 -+ * 1: R data is dithered with x^28+x^3+1 -+ * G data is dithered with x^28+X^9+1 -+ * B data is dithered with x^28+x^13+1 -+ * enable high pass filter or not -+ * 5) enable spatical dithering -+ */ -+static void set_spatial_dither( -+ struct dce80_opp *opp80, -+ const struct bit_depth_reduction_params *params) -+{ -+ uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL); -+ uint32_t depth_cntl_value = 0; -+ uint32_t dither_r_value = 0; -+ uint32_t dither_g_value = 0; -+ uint32_t dither_b_value = 0; -+ -+ /*Disable spatial (random) dithering*/ -+ depth_cntl_value = dm_read_reg(opp80->base.ctx, addr); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_MODE); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE); -+ set_reg_field_value(depth_cntl_value, 0, -+ FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE); -+ -+ dm_write_reg(opp80->base.ctx, addr, depth_cntl_value); -+ -+ /* no 10bpc on DCE8*/ -+ if (params->flags.SPATIAL_DITHER_ENABLED == 0 || -+ params->flags.SPATIAL_DITHER_DEPTH == 2) -+ return; -+ -+ /*Set seed for random values for -+ * spatial dithering for R,G,B channels*/ -+ addr = FMT_REG(mmFMT_DITHER_RAND_R_SEED); -+ set_reg_field_value(dither_r_value, params->r_seed_value, -+ FMT_DITHER_RAND_R_SEED, -+ FMT_RAND_R_SEED); -+ dm_write_reg(opp80->base.ctx, addr, dither_r_value); -+ -+ addr = FMT_REG(mmFMT_DITHER_RAND_G_SEED); -+ set_reg_field_value(dither_g_value, -+ params->g_seed_value, -+ FMT_DITHER_RAND_G_SEED, -+ FMT_RAND_G_SEED); -+ dm_write_reg(opp80->base.ctx, addr, dither_g_value); -+ -+ addr = FMT_REG(mmFMT_DITHER_RAND_B_SEED); -+ set_reg_field_value(dither_b_value, params->b_seed_value, -+ FMT_DITHER_RAND_B_SEED, -+ FMT_RAND_B_SEED); -+ dm_write_reg(opp80->base.ctx, addr, dither_b_value); -+ -+ /* FMT_OFFSET_R_Cr 31:16 0x0 Setting the zero -+ * offset for the R/Cr channel, lower 4LSB -+ * is forced to zeros. Typically set to 0 -+ * RGB and 0x80000 YCbCr. -+ */ -+ /* FMT_OFFSET_G_Y 31:16 0x0 Setting the zero -+ * offset for the G/Y channel, lower 4LSB is -+ * forced to zeros. Typically set to 0 RGB -+ * and 0x80000 YCbCr. -+ */ -+ /* FMT_OFFSET_B_Cb 31:16 0x0 Setting the zero -+ * offset for the B/Cb channel, lower 4LSB is -+ * forced to zeros. Typically set to 0 RGB and -+ * 0x80000 YCbCr. -+ */ -+ -+ /*Set spatial dithering bit depth*/ -+ set_reg_field_value(depth_cntl_value, -+ params->flags.SPATIAL_DITHER_DEPTH, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_SPATIAL_DITHER_DEPTH); -+ -+ /* Set spatial dithering mode -+ * (default is Seed patterrn AAAA...) -+ */ -+ set_reg_field_value(depth_cntl_value, -+ params->flags.SPATIAL_DITHER_MODE, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_SPATIAL_DITHER_MODE); -+ -+ /*Reset only at startup*/ -+ set_reg_field_value(depth_cntl_value, -+ params->flags.FRAME_RANDOM, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_RGB_RANDOM_ENABLE); -+ -+ /*Set RGB data dithered with x^28+x^3+1*/ -+ set_reg_field_value(depth_cntl_value, -+ params->flags.RGB_RANDOM, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_RGB_RANDOM_ENABLE); -+ -+ /*Disable High pass filter*/ -+ set_reg_field_value(depth_cntl_value, -+ params->flags.HIGHPASS_RANDOM, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_HIGHPASS_RANDOM_ENABLE); -+ -+ /*Enable spatial dithering*/ -+ set_reg_field_value(depth_cntl_value, -+ 1, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_SPATIAL_DITHER_EN); -+ -+ addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL); -+ dm_write_reg(opp80->base.ctx, addr, depth_cntl_value); -+ -+} -+ -+/** -+ * SetTemporalDither (Frame Modulation) -+ * 1) set temporal dither depth -+ * 2) select pattern: from hard-coded pattern or programmable pattern -+ * 3) select optimized strips for BGR or RGB LCD sub-pixel -+ * 4) set s matrix -+ * 5) set t matrix -+ * 6) set grey level for 0.25, 0.5, 0.75 -+ * 7) enable temporal dithering -+ */ -+static void set_temporal_dither( -+ struct dce80_opp *opp80, -+ const struct bit_depth_reduction_params *params) -+{ -+ uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL); -+ uint32_t value; -+ -+ /*Disable temporal (frame modulation) dithering first*/ -+ value = dm_read_reg(opp80->base.ctx, addr); -+ -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_EN); -+ -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_RESET); -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_OFFSET); -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_DEPTH); -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_LEVEL); -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_25FRC_SEL); -+ -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_50FRC_SEL); -+ -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_75FRC_SEL); -+ -+ dm_write_reg(opp80->base.ctx, addr, value); -+ -+ /* no 10bpc dither on DCE8*/ -+ if (params->flags.FRAME_MODULATION_ENABLED == 0 || -+ params->flags.FRAME_MODULATION_DEPTH == 2) -+ return; -+ -+ /* Set temporal dithering depth*/ -+ set_reg_field_value(value, -+ params->flags.FRAME_MODULATION_DEPTH, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_DEPTH); -+ -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_RESET); -+ -+ set_reg_field_value(value, -+ 0, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_OFFSET); -+ -+ /*Select legacy pattern based on FRC and Temporal level*/ -+ addr = FMT_REG(mmFMT_TEMPORAL_DITHER_PATTERN_CONTROL); -+ dm_write_reg(opp80->base.ctx, addr, 0); -+ /*Set s matrix*/ -+ addr = FMT_REG( -+ mmFMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX); -+ dm_write_reg(opp80->base.ctx, addr, 0); -+ /*Set t matrix*/ -+ addr = FMT_REG( -+ mmFMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX); -+ dm_write_reg(opp80->base.ctx, addr, 0); -+ -+ /*Select patterns for 0.25, 0.5 and 0.75 grey level*/ -+ set_reg_field_value(value, -+ params->flags.TEMPORAL_LEVEL, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_LEVEL); -+ -+ set_reg_field_value(value, -+ params->flags.FRC25, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_25FRC_SEL); -+ -+ set_reg_field_value(value, -+ params->flags.FRC50, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_50FRC_SEL); -+ -+ set_reg_field_value(value, -+ params->flags.FRC75, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_75FRC_SEL); -+ -+ /*Enable bit reduction by temporal (frame modulation) dithering*/ -+ set_reg_field_value(value, -+ 1, -+ FMT_BIT_DEPTH_CONTROL, -+ FMT_TEMPORAL_DITHER_EN); -+ -+ addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL); -+ dm_write_reg(opp80->base.ctx, addr, value); -+ -+} -+ -+/** -+ * Set Clamping -+ * 1) Set clamping format based on bpc - 0 for 6bpc (No clamping) -+ * 1 for 8 bpc -+ * 2 for 10 bpc -+ * 3 for 12 bpc -+ * 7 for programable -+ * 2) Enable clamp if Limited range requested -+ */ -+static void set_clamping( -+ struct dce80_opp *opp80, -+ const struct clamping_and_pixel_encoding_params *params) -+{ -+ uint32_t clamp_cntl_value = 0; -+ uint32_t red_clamp_value = 0; -+ uint32_t green_clamp_value = 0; -+ uint32_t blue_clamp_value = 0; -+ uint32_t addr = FMT_REG(mmFMT_CLAMP_CNTL); -+ -+ clamp_cntl_value = dm_read_reg(opp80->base.ctx, addr); -+ -+ set_reg_field_value(clamp_cntl_value, -+ 0, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_DATA_EN); -+ -+ set_reg_field_value(clamp_cntl_value, -+ 0, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_COLOR_FORMAT); -+ -+ switch (params->clamping_level) { -+ case CLAMPING_FULL_RANGE: -+ break; -+ -+ case CLAMPING_LIMITED_RANGE_8BPC: -+ set_reg_field_value(clamp_cntl_value, -+ 1, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_DATA_EN); -+ -+ set_reg_field_value(clamp_cntl_value, -+ 1, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_COLOR_FORMAT); -+ -+ break; -+ -+ case CLAMPING_LIMITED_RANGE_10BPC: -+ set_reg_field_value(clamp_cntl_value, -+ 1, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_DATA_EN); -+ -+ set_reg_field_value(clamp_cntl_value, -+ 2, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_COLOR_FORMAT); -+ -+ break; -+ case CLAMPING_LIMITED_RANGE_12BPC: -+ set_reg_field_value(clamp_cntl_value, -+ 1, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_DATA_EN); -+ -+ set_reg_field_value(clamp_cntl_value, -+ 3, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_COLOR_FORMAT); -+ -+ break; -+ case CLAMPING_LIMITED_RANGE_PROGRAMMABLE: -+ set_reg_field_value(clamp_cntl_value, -+ 1, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_DATA_EN); -+ -+ set_reg_field_value(clamp_cntl_value, -+ 7, -+ FMT_CLAMP_CNTL, -+ FMT_CLAMP_COLOR_FORMAT); -+ -+ /*set the defaults*/ -+ set_reg_field_value(red_clamp_value, -+ 0x10, -+ FMT_CLAMP_COMPONENT_R, -+ FMT_CLAMP_LOWER_R); -+ -+ set_reg_field_value(red_clamp_value, -+ 0xFEF, -+ FMT_CLAMP_COMPONENT_R, -+ FMT_CLAMP_UPPER_R); -+ -+ addr = FMT_REG(mmFMT_CLAMP_COMPONENT_R); -+ dm_write_reg(opp80->base.ctx, addr, red_clamp_value); -+ -+ set_reg_field_value(green_clamp_value, -+ 0x10, -+ FMT_CLAMP_COMPONENT_G, -+ FMT_CLAMP_LOWER_G); -+ -+ set_reg_field_value(green_clamp_value, -+ 0xFEF, -+ FMT_CLAMP_COMPONENT_G, -+ FMT_CLAMP_UPPER_G); -+ -+ addr = FMT_REG(mmFMT_CLAMP_COMPONENT_G); -+ dm_write_reg(opp80->base.ctx, addr, green_clamp_value); -+ -+ set_reg_field_value(blue_clamp_value, -+ 0x10, -+ FMT_CLAMP_COMPONENT_B, -+ FMT_CLAMP_LOWER_B); -+ -+ set_reg_field_value(blue_clamp_value, -+ 0xFEF, -+ FMT_CLAMP_COMPONENT_B, -+ FMT_CLAMP_UPPER_B); -+ -+ addr = FMT_REG(mmFMT_CLAMP_COMPONENT_B); -+ dm_write_reg(opp80->base.ctx, addr, blue_clamp_value); -+ -+ break; -+ -+ default: -+ break; -+ } -+ -+ addr = FMT_REG(mmFMT_CLAMP_CNTL); -+ /*Set clamp control*/ -+ dm_write_reg(opp80->base.ctx, addr, clamp_cntl_value); -+ -+} -+ -+/** -+ * set_pixel_encoding -+ * -+ * Set Pixel Encoding -+ * 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly -+ * 1: YCbCr 4:2:2 -+ */ -+static void set_pixel_encoding( -+ struct dce80_opp *opp80, -+ const struct clamping_and_pixel_encoding_params *params) -+{ -+ uint32_t fmt_cntl_value; -+ uint32_t addr = FMT_REG(mmFMT_CONTROL); -+ -+ /*RGB 4:4:4 or YCbCr 4:4:4 - 0; YCbCr 4:2:2 -1.*/ -+ fmt_cntl_value = dm_read_reg(opp80->base.ctx, addr); -+ -+ set_reg_field_value(fmt_cntl_value, -+ 0, -+ FMT_CONTROL, -+ FMT_PIXEL_ENCODING); -+ -+ if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) { -+ set_reg_field_value(fmt_cntl_value, -+ 1, -+ FMT_CONTROL, -+ FMT_PIXEL_ENCODING); -+ -+ /*00 - Pixels drop mode ,01 - Pixels average mode*/ -+ set_reg_field_value(fmt_cntl_value, -+ 0, -+ FMT_CONTROL, -+ FMT_SUBSAMPLING_MODE); -+ -+ /*00 - Cb before Cr ,01 - Cr before Cb*/ -+ set_reg_field_value(fmt_cntl_value, -+ 0, -+ FMT_CONTROL, -+ FMT_SUBSAMPLING_ORDER); -+ } -+ dm_write_reg(opp80->base.ctx, addr, fmt_cntl_value); -+ -+} -+ -+void dce80_opp_program_bit_depth_reduction( -+ struct output_pixel_processor *opp, -+ const struct bit_depth_reduction_params *params) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ -+ set_truncation(opp80, params); -+ set_spatial_dither(opp80, params); -+ set_temporal_dither(opp80, params); -+} -+ -+void dce80_opp_program_clamping_and_pixel_encoding( -+ struct output_pixel_processor *opp, -+ const struct clamping_and_pixel_encoding_params *params) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ -+ set_clamping(opp80, params); -+ set_pixel_encoding(opp80, params); -+} -+ -+void dce80_opp_set_dyn_expansion( -+ struct output_pixel_processor *opp, -+ enum color_space color_sp, -+ enum dc_color_depth color_dpth, -+ enum signal_type signal) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ uint32_t value; -+ bool enable_dyn_exp = false; -+ uint32_t addr = FMT_REG(mmFMT_DYNAMIC_EXP_CNTL); -+ -+ value = dm_read_reg(opp->ctx, addr); -+ -+ set_reg_field_value(value, 0, -+ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN); -+ set_reg_field_value(value, 0, -+ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE); -+ -+ /* From HW programming guide: -+ FMT_DYNAMIC_EXP_EN = 0 for limited RGB or YCbCr output -+ FMT_DYNAMIC_EXP_EN = 1 for RGB full range only*/ -+ if (color_sp == COLOR_SPACE_SRGB_FULL_RANGE) -+ enable_dyn_exp = true; -+ -+ /*00 - 10-bit -> 12-bit dynamic expansion*/ -+ /*01 - 8-bit -> 12-bit dynamic expansion*/ -+ if (signal == SIGNAL_TYPE_HDMI_TYPE_A) { -+ switch (color_dpth) { -+ case COLOR_DEPTH_888: -+ set_reg_field_value(value, enable_dyn_exp ? 1:0, -+ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN); -+ set_reg_field_value(value, 1, -+ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE); -+ break; -+ case COLOR_DEPTH_101010: -+ set_reg_field_value(value, enable_dyn_exp ? 1:0, -+ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN); -+ set_reg_field_value(value, 0, -+ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE); -+ break; -+ case COLOR_DEPTH_121212: -+ break; -+ default: -+ break; -+ } -+ } -+ -+ dm_write_reg(opp->ctx, addr, value); -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_regamma.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_regamma.c -new file mode 100644 -index 0000000..ef95e98 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_opp_regamma.c -@@ -0,0 +1,546 @@ -+/* -+ * 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 DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_opp.h" -+#include "gamma_types.h" -+ -+#define DCP_REG(reg)\ -+ (reg + opp80->offsets.dcp_offset) -+ -+#define DCFE_REG(reg)\ -+ (reg + opp80->offsets.crtc_offset) -+ -+enum { -+ MAX_PWL_ENTRY = 128, -+ MAX_REGIONS_NUMBER = 16 -+ -+}; -+ -+struct curve_config { -+ uint32_t offset; -+ int8_t segments[MAX_REGIONS_NUMBER]; -+ int8_t begin; -+}; -+ -+/* -+ ***************************************************************************** -+ * Function: regamma_config_regions_and_segments -+ * -+ * build regamma curve by using predefined hw points -+ * uses interface parameters ,like EDID coeff. -+ * -+ * @param : parameters interface parameters -+ * @return void -+ * -+ * @note -+ * -+ * @see -+ * -+ ***************************************************************************** -+ */ -+static void regamma_config_regions_and_segments( -+ struct dce80_opp *opp80, const struct regamma_params *params) -+{ -+ const struct gamma_curve *curve; -+ uint32_t value = 0; -+ -+ { -+ set_reg_field_value( -+ value, -+ params->arr_points[0].custom_float_x, -+ REGAMMA_CNTLA_START_CNTL, -+ REGAMMA_CNTLA_EXP_REGION_START); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ REGAMMA_CNTLA_START_CNTL, -+ REGAMMA_CNTLA_EXP_REGION_START_SEGMENT); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_START_CNTL), -+ value); -+ } -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ params->arr_points[0].custom_float_slope, -+ REGAMMA_CNTLA_SLOPE_CNTL, -+ REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_SLOPE_CNTL), value); -+ } -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ params->arr_points[1].custom_float_x, -+ REGAMMA_CNTLA_END_CNTL1, -+ REGAMMA_CNTLA_EXP_REGION_END); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_END_CNTL1), value); -+ } -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ params->arr_points[2].custom_float_slope, -+ REGAMMA_CNTLA_END_CNTL2, -+ REGAMMA_CNTLA_EXP_REGION_END_BASE); -+ -+ set_reg_field_value( -+ value, -+ params->arr_points[1].custom_float_y, -+ REGAMMA_CNTLA_END_CNTL2, -+ REGAMMA_CNTLA_EXP_REGION_END_SLOPE); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_END_CNTL2), value); -+ } -+ -+ curve = params->arr_curve_points; -+ -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_0_1, -+ REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_0_1, -+ REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_0_1, -+ REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_0_1, -+ REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS); -+ -+ dm_write_reg( -+ opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_0_1), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_2_3, -+ REGAMMA_CNTLA_EXP_REGION2_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_2_3, -+ REGAMMA_CNTLA_EXP_REGION2_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_2_3, -+ REGAMMA_CNTLA_EXP_REGION3_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_2_3, -+ REGAMMA_CNTLA_EXP_REGION3_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_2_3), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_4_5, -+ REGAMMA_CNTLA_EXP_REGION4_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_4_5, -+ REGAMMA_CNTLA_EXP_REGION4_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_4_5, -+ REGAMMA_CNTLA_EXP_REGION5_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_4_5, -+ REGAMMA_CNTLA_EXP_REGION5_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_4_5), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_6_7, -+ REGAMMA_CNTLA_EXP_REGION6_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_6_7, -+ REGAMMA_CNTLA_EXP_REGION6_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_6_7, -+ REGAMMA_CNTLA_EXP_REGION7_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_6_7, -+ REGAMMA_CNTLA_EXP_REGION7_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_6_7), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_8_9, -+ REGAMMA_CNTLA_EXP_REGION8_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_8_9, -+ REGAMMA_CNTLA_EXP_REGION8_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_8_9, -+ REGAMMA_CNTLA_EXP_REGION9_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_8_9, -+ REGAMMA_CNTLA_EXP_REGION9_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_8_9), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_10_11, -+ REGAMMA_CNTLA_EXP_REGION10_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_10_11, -+ REGAMMA_CNTLA_EXP_REGION10_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_10_11, -+ REGAMMA_CNTLA_EXP_REGION11_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_10_11, -+ REGAMMA_CNTLA_EXP_REGION11_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_10_11), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_12_13, -+ REGAMMA_CNTLA_EXP_REGION12_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_12_13, -+ REGAMMA_CNTLA_EXP_REGION12_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_12_13, -+ REGAMMA_CNTLA_EXP_REGION13_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_12_13, -+ REGAMMA_CNTLA_EXP_REGION13_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_12_13), -+ value); -+ } -+ -+ curve += 2; -+ { -+ value = 0; -+ set_reg_field_value( -+ value, -+ curve[0].offset, -+ REGAMMA_CNTLA_REGION_14_15, -+ REGAMMA_CNTLA_EXP_REGION14_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[0].segments_num, -+ REGAMMA_CNTLA_REGION_14_15, -+ REGAMMA_CNTLA_EXP_REGION14_NUM_SEGMENTS); -+ -+ set_reg_field_value( -+ value, -+ curve[1].offset, -+ REGAMMA_CNTLA_REGION_14_15, -+ REGAMMA_CNTLA_EXP_REGION15_LUT_OFFSET); -+ -+ set_reg_field_value( -+ value, -+ curve[1].segments_num, -+ REGAMMA_CNTLA_REGION_14_15, -+ REGAMMA_CNTLA_EXP_REGION15_NUM_SEGMENTS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CNTLA_REGION_14_15), -+ value); -+ } -+} -+ -+static void program_pwl( -+ struct dce80_opp *opp80, -+ const struct regamma_params *params) -+{ -+ uint32_t value; -+ -+ { -+ uint8_t max_tries = 10; -+ uint8_t counter = 0; -+ -+ /* Power on LUT memory */ -+ value = dm_read_reg(opp80->base.ctx, -+ DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ REGAMMA_LUT_LIGHT_SLEEP_DIS); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), value); -+ -+ while (counter < max_tries) { -+ value = -+ dm_read_reg( -+ opp80->base.ctx, -+ DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); -+ -+ if (get_reg_field_value( -+ value, -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ REGAMMA_LUT_MEM_PWR_STATE) == 0) -+ break; -+ -+ ++counter; -+ } -+ -+ if (counter == max_tries) { -+ dal_logger_write(opp80->base.ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_CONTROLLER, -+ "%s: regamma lut was not powered on " -+ "in a timely manner," -+ " programming still proceeds\n", -+ __func__); -+ } -+ } -+ -+ value = 0; -+ -+ set_reg_field_value( -+ value, -+ 7, -+ REGAMMA_LUT_WRITE_EN_MASK, -+ REGAMMA_LUT_WRITE_EN_MASK); -+ -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_LUT_WRITE_EN_MASK), value); -+ dm_write_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_LUT_INDEX), 0); -+ -+ /* Program REGAMMA_LUT_DATA */ -+ { -+ const uint32_t addr = DCP_REG(mmREGAMMA_LUT_DATA); -+ -+ uint32_t i = 0; -+ -+ const struct pwl_result_data *rgb = -+ params->rgb_resulted; -+ -+ while (i != params->hw_points_num) { -+ dm_write_reg(opp80->base.ctx, addr, rgb->red_reg); -+ dm_write_reg(opp80->base.ctx, addr, rgb->green_reg); -+ dm_write_reg(opp80->base.ctx, addr, rgb->blue_reg); -+ -+ dm_write_reg(opp80->base.ctx, addr, -+ rgb->delta_red_reg); -+ dm_write_reg(opp80->base.ctx, addr, -+ rgb->delta_green_reg); -+ dm_write_reg(opp80->base.ctx, addr, -+ rgb->delta_blue_reg); -+ -+ ++rgb; -+ ++i; -+ } -+ } -+ -+ /* we are done with DCP LUT memory; re-enable low power mode */ -+ value = dm_read_reg(opp80->base.ctx, -+ DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ REGAMMA_LUT_LIGHT_SLEEP_DIS); -+ -+ dm_write_reg(opp80->base.ctx, DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ value); -+} -+ -+ -+void dce80_opp_power_on_regamma_lut( -+ struct output_pixel_processor *opp, -+ bool power_on) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ -+ uint32_t value = -+ dm_read_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL)); -+ -+ set_reg_field_value( -+ value, -+ power_on, -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ REGAMMA_LUT_LIGHT_SLEEP_DIS); -+ -+ set_reg_field_value( -+ value, -+ power_on, -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ DCP_LUT_LIGHT_SLEEP_DIS); -+ -+ dm_write_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), value); -+} -+ -+bool dce80_opp_program_regamma_pwl( -+ struct output_pixel_processor *opp, -+ const struct regamma_params *params) -+{ -+ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ -+ regamma_config_regions_and_segments(opp80, params); -+ -+ program_pwl(opp80, params); -+ -+ return true; -+} -+ -+void dce80_opp_set_regamma_mode(struct output_pixel_processor *opp, -+ enum opp_regamma mode) -+{ -+ struct dce80_opp *opp80 = TO_DCE80_OPP(opp); -+ uint32_t value = dm_read_reg(opp80->base.ctx, -+ DCP_REG(mmREGAMMA_CONTROL)); -+ -+ set_reg_field_value( -+ value, -+ mode, -+ REGAMMA_CONTROL, -+ GRPH_REGAMMA_MODE); -+ -+ dm_write_reg(opp80->base.ctx, DCP_REG(mmREGAMMA_CONTROL), value); -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.c -new file mode 100644 -index 0000000..1eeb469 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.c -@@ -0,0 +1,1267 @@ -+/* -+ * 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_timing_generator.h" -+#include "dce110/dce110_mem_input.h" -+#include "dce110/dce110_resource.h" -+#include "dce80/dce80_timing_generator.h" -+#include "dce80/dce80_link_encoder.h" -+#include "dce110/dce110_link_encoder.h" -+#include "dce80/dce80_mem_input.h" -+#include "dce80/dce80_ipp.h" -+#include "dce80/dce80_transform.h" -+#include "dce110/dce110_stream_encoder.h" -+#include "dce80/dce80_stream_encoder.h" -+#include "dce80/dce80_opp.h" -+#include "dce110/dce110_ipp.h" -+#include "dce110/dce110_clock_source.h" -+ -+#include "dce/dce_8_0_d.h" -+ -+/* TODO remove this include */ -+ -+#ifndef mmDP_DPHY_INTERNAL_CTRL -+#define mmDP_DPHY_INTERNAL_CTRL 0x1CDE -+#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x1CDE -+#define mmDP1_DP_DPHY_INTERNAL_CTRL 0x1FDE -+#define mmDP2_DP_DPHY_INTERNAL_CTRL 0x42DE -+#define mmDP3_DP_DPHY_INTERNAL_CTRL 0x45DE -+#define mmDP4_DP_DPHY_INTERNAL_CTRL 0x48DE -+#define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4BDE -+#define mmDP6_DP_DPHY_INTERNAL_CTRL 0x4EDE -+#endif -+ -+enum dce80_clk_src_array_id { -+ DCE80_CLK_SRC_PLL0 = 0, -+ DCE80_CLK_SRC_PLL1, -+ DCE80_CLK_SRC_PLL2, -+ DCE80_CLK_SRC_EXT, -+ -+ DCE80_CLK_SRC_TOTAL -+}; -+ -+#define DCE11_DIG_FE_CNTL 0x4a00 -+#define DCE11_DIG_BE_CNTL 0x4a47 -+#define DCE11_DP_SEC 0x4ac3 -+ -+static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = { -+ { -+ .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), -+ .dcp = (mmGRPH_CONTROL - mmGRPH_CONTROL), -+ .dmif = (mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL -+ - mmDPG_WATERMARK_MASK_CONTROL), -+ }, -+ { -+ .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), -+ .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), -+ .dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL -+ - mmDPG_WATERMARK_MASK_CONTROL), -+ }, -+ { -+ .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), -+ .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), -+ .dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL -+ - mmDPG_WATERMARK_MASK_CONTROL), -+ }, -+ { -+ .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), -+ .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), -+ .dmif = (mmDMIF_PG3_DPG_WATERMARK_MASK_CONTROL -+ - mmDPG_WATERMARK_MASK_CONTROL), -+ }, -+ { -+ .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), -+ .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), -+ .dmif = (mmDMIF_PG4_DPG_WATERMARK_MASK_CONTROL -+ - mmDPG_WATERMARK_MASK_CONTROL), -+ }, -+ { -+ .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), -+ .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), -+ .dmif = (mmDMIF_PG5_DPG_WATERMARK_MASK_CONTROL -+ - mmDPG_WATERMARK_MASK_CONTROL), -+ } -+}; -+ -+static const struct dce110_mem_input_reg_offsets dce80_mi_reg_offsets[] = { -+ { -+ .dcp = (mmGRPH_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 dce80_transform_reg_offsets dce80_xfm_offsets[] = { -+{ -+ .scl_offset = (mmSCL_CONTROL - mmSCL_CONTROL), -+ .crtc_offset = (mmDCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmGRPH_CONTROL - mmGRPH_CONTROL), -+ .lb_offset = (mmLB_DATA_FORMAT - mmLB_DATA_FORMAT), -+}, -+{ .scl_offset = (mmSCL1_SCL_CONTROL - mmSCL_CONTROL), -+ .crtc_offset = (mmCRTC1_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), -+ .lb_offset = (mmLB1_LB_DATA_FORMAT - mmLB_DATA_FORMAT), -+}, -+{ .scl_offset = (mmSCL2_SCL_CONTROL - mmSCL_CONTROL), -+ .crtc_offset = (mmCRTC2_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), -+ .lb_offset = (mmLB2_LB_DATA_FORMAT - mmLB_DATA_FORMAT), -+}, -+{ -+ .scl_offset = (mmSCL3_SCL_CONTROL - mmSCL_CONTROL), -+ .crtc_offset = (mmCRTC3_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), -+ .lb_offset = (mmLB3_LB_DATA_FORMAT - mmLB_DATA_FORMAT), -+}, -+{ -+ .scl_offset = (mmSCL4_SCL_CONTROL - mmSCL_CONTROL), -+ .crtc_offset = (mmCRTC4_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), -+ .lb_offset = (mmLB4_LB_DATA_FORMAT - mmLB_DATA_FORMAT), -+}, -+{ -+ .scl_offset = (mmSCL5_SCL_CONTROL - mmSCL_CONTROL), -+ .crtc_offset = (mmCRTC5_DCFE_MEM_LIGHT_SLEEP_CNTL - -+ mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp_offset = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), -+ .lb_offset = (mmLB5_LB_DATA_FORMAT - mmLB_DATA_FORMAT), -+} -+}; -+ -+static const struct dce110_ipp_reg_offsets ipp_reg_offsets[] = { -+{ -+ .dcp_offset = (mmDCP0_CUR_CONTROL - mmDCP0_CUR_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP1_CUR_CONTROL - mmDCP0_CUR_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP2_CUR_CONTROL - mmDCP0_CUR_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP3_CUR_CONTROL - mmDCP0_CUR_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP4_CUR_CONTROL - mmDCP0_CUR_CONTROL), -+}, -+{ -+ .dcp_offset = (mmDCP5_CUR_CONTROL - mmDCP0_CUR_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_clk_src_reg_offsets dce80_clk_src_reg_offsets[] = { -+ { -+ .pll_cntl = mmDCCG_PLL0_PLL_CNTL, -+ .pixclk_resync_cntl = mmPIXCLK0_RESYNC_CNTL -+ }, -+ { -+ .pll_cntl = mmDCCG_PLL1_PLL_CNTL, -+ .pixclk_resync_cntl = mmPIXCLK1_RESYNC_CNTL -+ }, -+ { -+ .pll_cntl = mmDCCG_PLL2_PLL_CNTL, -+ .pixclk_resync_cntl = mmPIXCLK2_RESYNC_CNTL -+ } -+}; -+ -+static struct timing_generator *dce80_timing_generator_create( -+ struct adapter_service *as, -+ struct dc_context *ctx, -+ uint32_t instance, -+ const struct dce110_timing_generator_offsets *offsets) -+{ -+ struct dce110_timing_generator *tg110 = -+ dm_alloc(ctx, sizeof(struct dce110_timing_generator)); -+ -+ if (!tg110) -+ return NULL; -+ -+ if (dce80_timing_generator_construct(tg110, as, ctx, instance, offsets)) -+ return &tg110->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, tg110); -+ return NULL; -+} -+ -+static struct stream_encoder *dce80_stream_encoder_create( -+ enum engine_id eng_id, -+ struct dc_context *ctx, -+ struct dc_bios *dcb, -+ const struct dce110_stream_enc_registers *regs) -+{ -+ struct dce110_stream_encoder *enc110 = -+ dm_alloc(ctx, sizeof(struct dce110_stream_encoder)); -+ -+ if (!enc110) -+ return NULL; -+ -+ if (dce80_stream_encoder_construct(enc110, ctx, dcb, eng_id, regs)) -+ return &enc110->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, enc110); -+ return NULL; -+} -+ -+ -+static struct mem_input *dce80_mem_input_create( -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce110_mem_input_reg_offsets *offsets) -+{ -+ struct dce110_mem_input *mem_input80 = -+ dm_alloc(ctx, sizeof(struct dce110_mem_input)); -+ -+ if (!mem_input80) -+ return NULL; -+ -+ if (dce80_mem_input_construct(mem_input80, -+ ctx, inst, offsets)) -+ return &mem_input80->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, mem_input80); -+ return NULL; -+} -+ -+static void dce80_transform_destroy(struct transform **xfm) -+{ -+ dm_free((*xfm)->ctx, TO_DCE80_TRANSFORM(*xfm)); -+ *xfm = NULL; -+} -+ -+static struct transform *dce80_transform_create( -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce80_transform_reg_offsets *offsets) -+{ -+ struct dce80_transform *transform = -+ dm_alloc(ctx, sizeof(struct dce80_transform)); -+ -+ if (!transform) -+ return NULL; -+ -+ if (dce80_transform_construct(transform, ctx, inst, offsets)) -+ return &transform->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, transform); -+ return NULL; -+} -+ -+static struct input_pixel_processor *dce80_ipp_create( -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce110_ipp_reg_offsets *offset) -+{ -+ struct dce110_ipp *ipp = -+ dm_alloc(ctx, sizeof(struct dce110_ipp)); -+ -+ if (!ipp) -+ return NULL; -+ -+ if (dce80_ipp_construct(ipp, ctx, inst, offset)) -+ return &ipp->base; -+ -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(ctx, ipp); -+ return NULL; -+} -+ -+struct link_encoder *dce80_link_encoder_create( -+ const struct encoder_init_data *enc_init_data) -+{ -+ struct dce110_link_encoder *enc110 = -+ dm_alloc( -+ enc_init_data->ctx, -+ sizeof(struct dce110_link_encoder)); -+ -+ if (!enc110) -+ return NULL; -+ -+ if (dce80_link_encoder_construct( -+ enc110, -+ enc_init_data, -+ &link_enc_regs[enc_init_data->transmitter], -+ &link_enc_aux_regs[enc_init_data->channel - 1], -+ &link_enc_bl_regs)) -+ return &enc110->base; -+ -+ BREAK_TO_DEBUGGER(); -+ dm_free(enc_init_data->ctx, enc110); -+ return NULL; -+} -+ -+struct clock_source *dce80_clock_source_create( -+ struct dc_context *ctx, -+ struct dc_bios *bios, -+ enum clock_source_id id, -+ const struct dce110_clk_src_reg_offsets *offsets) -+{ -+ struct dce110_clk_src *clk_src = -+ dm_alloc(ctx, sizeof(struct dce110_clk_src)); -+ -+ if (!clk_src) -+ return NULL; -+ -+ if (dce110_clk_src_construct(clk_src, ctx, bios, id, offsets)) -+ return &clk_src->base; -+ -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+} -+ -+void dce80_clock_source_destroy(struct clock_source **clk_src) -+{ -+ dm_free((*clk_src)->ctx, TO_DCE110_CLK_SRC(*clk_src)); -+ *clk_src = NULL; -+} -+ -+void dce80_destruct_resource_pool(struct resource_pool *pool) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < pool->pipe_count; i++) { -+ if (pool->opps[i] != NULL) -+ dce80_opp_destroy(&pool->opps[i]); -+ -+ if (pool->transforms[i] != NULL) -+ dce80_transform_destroy(&pool->transforms[i]); -+ -+ if (pool->ipps[i] != NULL) -+ dce80_ipp_destroy(&pool->ipps[i]); -+ -+ if (pool->mis[i] != NULL) { -+ dm_free(pool->mis[i]->ctx, -+ TO_DCE110_MEM_INPUT(pool->mis[i])); -+ pool->mis[i] = NULL; -+ } -+ -+ if (pool->timing_generators[i] != NULL) { -+ dm_free(pool->timing_generators[i]->ctx, DCE110TG_FROM_TG(pool->timing_generators[i])); -+ pool->timing_generators[i] = NULL; -+ } -+ } -+ -+ for (i = 0; i < pool->stream_enc_count; i++) { -+ if (pool->stream_enc[i] != NULL) -+ dm_free(pool->stream_enc[i]->ctx, -+ DCE110STRENC_FROM_STRENC(pool->stream_enc[i])); -+ } -+ -+ for (i = 0; i < pool->clk_src_count; i++) { -+ if (pool->clock_sources[i] != NULL) { -+ dce80_clock_source_destroy(&pool->clock_sources[i]); -+ } -+ } -+ -+ for (i = 0; i < pool->audio_count; i++) { -+ if (pool->audios[i] != NULL) { -+ dal_audio_destroy(&pool->audios[i]); -+ } -+ } -+ -+ if (pool->display_clock != NULL) { -+ dal_display_clock_destroy(&pool->display_clock); -+ } -+ -+ if (pool->scaler_filter != NULL) { -+ dal_scaler_filter_destroy(&pool->scaler_filter); -+ } -+ if (pool->irqs != NULL) { -+ dal_irq_service_destroy(&pool->irqs); -+ } -+ -+ if (pool->adapter_srv != NULL) { -+ dal_adapter_service_destroy(&pool->adapter_srv); -+ } -+} -+ -+static struct clock_source *find_first_free_pll( -+ struct resource_context *res_ctx) -+{ -+ if (res_ctx->clock_source_ref_count[DCE80_CLK_SRC_PLL0] == 0) { -+ return res_ctx->pool.clock_sources[DCE80_CLK_SRC_PLL0]; -+ } -+ if (res_ctx->clock_source_ref_count[DCE80_CLK_SRC_PLL1] == 0) { -+ return res_ctx->pool.clock_sources[DCE80_CLK_SRC_PLL1]; -+ } -+ if (res_ctx->clock_source_ref_count[DCE80_CLK_SRC_PLL2] == 0) { -+ return res_ctx->pool.clock_sources[DCE80_CLK_SRC_PLL2]; -+ } -+ -+ 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 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; -+ -+ build_info_frame(pipe_ctx); -+ -+ /* do not need to validate non root pipes */ -+ break; -+ } -+ } -+ } -+ -+ return DC_OK; -+} -+ -+enum dc_status dce80_validate_bandwidth( -+ const struct 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->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->ratios.vert.value); -+ disp->graphics_h_taps = pipe_ctx->taps.h_taps; -+ disp->graphics_v_taps = pipe_ctx->taps.v_taps; -+ -+ /* TODO: remove when bw formula accepts taps per -+ * display -+ */ -+ if (max_vtaps < pipe_ctx->taps.v_taps) -+ max_vtaps = pipe_ctx->taps.v_taps; -+ if (max_htaps < pipe_ctx->taps.h_taps) -+ max_htaps = pipe_ctx->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 (dm_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 (dm_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 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.clock_sources[DCE80_CLK_SRC_EXT]; -+ else -+ pipe_ctx->clock_source = -+ find_used_clk_src_for_sharing( -+ &context->res_ctx, pipe_ctx); -+ if (pipe_ctx->clock_source == NULL) -+ pipe_ctx->clock_source = -+ find_first_free_pll(&context->res_ctx); -+ -+ if (pipe_ctx->clock_source == NULL) -+ return DC_NO_CLOCK_SOURCE_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 dce80_validate_with_context( -+ const struct dc *dc, -+ const struct dc_validation_set set[], -+ uint8_t set_count, -+ struct validate_context *context) -+{ -+ enum dc_status result = DC_ERROR_UNEXPECTED; -+ uint8_t i, j; -+ struct dc_context *dc_ctx = dc->ctx; -+ -+ for (i = 0; i < set_count; i++) { -+ bool unchanged = false; -+ -+ context->targets[i] = DC_TARGET_TO_CORE(set[i].target); -+ 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); -+ context->target_status[i] = -+ dc->current_context.target_status[j]; -+ } -+ if (!unchanged) -+ if (!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 = map_resources(dc, context); -+ -+ if (result == DC_OK) -+ result = map_clock_resources(dc, context); -+ -+ if (result == DC_OK) -+ result = validate_mapped_resource(dc, context); -+ -+ if (result == DC_OK) -+ build_scaling_params_for_context(dc, context); -+ -+ if (result == DC_OK) -+ result = dce80_validate_bandwidth(dc, context); -+ -+ return result; -+} -+ -+static struct resource_funcs dce80_res_pool_funcs = { -+ .destruct = dce80_destruct_resource_pool, -+ .link_enc_create = dce80_link_encoder_create, -+ .link_enc_destroy = dce110_link_encoder_destroy, -+ .validate_with_context = dce80_validate_with_context, -+ .validate_bandwidth = dce80_validate_bandwidth -+}; -+ -+bool dce80_construct_resource_pool( -+ struct adapter_service *adapter_serv, -+ uint8_t num_virtual_links, -+ struct dc *dc, -+ struct resource_pool *pool) -+{ -+ unsigned int i; -+ struct audio_init_data audio_init_data = { 0 }; -+ struct dc_context *ctx = dc->ctx; -+ pool->adapter_srv = adapter_serv; -+ pool->funcs = &dce80_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[DCE80_CLK_SRC_PLL0] = dce80_clock_source_create( -+ ctx, dal_adapter_service_get_bios_parser(adapter_serv), -+ CLOCK_SOURCE_ID_PLL0, &dce80_clk_src_reg_offsets[0]); -+ pool->clock_sources[DCE80_CLK_SRC_PLL1] = dce80_clock_source_create( -+ ctx, dal_adapter_service_get_bios_parser(adapter_serv), -+ CLOCK_SOURCE_ID_PLL1, &dce80_clk_src_reg_offsets[1]); -+ pool->clock_sources[DCE80_CLK_SRC_PLL2] = dce80_clock_source_create( -+ ctx, dal_adapter_service_get_bios_parser(adapter_serv), -+ CLOCK_SOURCE_ID_PLL2, &dce80_clk_src_reg_offsets[2]); -+ pool->clock_sources[DCE80_CLK_SRC_EXT] = dce80_clock_source_create( -+ ctx, dal_adapter_service_get_bios_parser(adapter_serv), -+ CLOCK_SOURCE_ID_EXTERNAL, &dce80_clk_src_reg_offsets[0]); -+ pool->clk_src_count = DCE80_CLK_SRC_TOTAL; -+ -+ for (i = 0; i < pool->clk_src_count; i++) { -+ if (pool->clock_sources[i] == NULL) { -+ dm_error("DC: failed to create clock sources!\n"); -+ BREAK_TO_DEBUGGER(); -+ goto clk_src_create_fail; -+ } -+ } -+ -+ pool->display_clock = dal_display_clock_dce80_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 = -+ dal_adapter_service_get_stream_engines_num(adapter_serv); -+ pool->scaler_filter = dal_scaler_filter_create(ctx); -+ if (pool->scaler_filter == NULL) { -+ BREAK_TO_DEBUGGER(); -+ dm_error("DC: failed to create filter!\n"); -+ goto filter_create_fail; -+ } -+ -+ for (i = 0; i < pool->pipe_count; i++) { -+ pool->timing_generators[i] = dce80_timing_generator_create( -+ adapter_serv, ctx, i, &dce80_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] = dce80_mem_input_create(ctx, i, -+ &dce80_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] = dce80_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] = dce80_transform_create( -+ ctx, i, &dce80_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] = dce80_opp_create(ctx, 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++) { -+ if (pool->stream_engines.u_all & 1 << i) { -+ pool->stream_enc[i] = dce80_stream_encoder_create( -+ i, dc->ctx, -+ dal_adapter_service_get_bios_parser( -+ adapter_serv), -+ &stream_enc_regs[i]); -+ -+ if (pool->stream_enc[i] == NULL) { -+ BREAK_TO_DEBUGGER(); -+ dm_error("DC: failed to create stream_encoder!\n"); -+ goto stream_enc_create_fail; -+ } -+ } -+ } -+ -+ for (i = 0; i < num_virtual_links; i++) { -+ pool->stream_enc[pool->stream_enc_count] = -+ virtual_stream_encoder_create( -+ dc->ctx, dal_adapter_service_get_bios_parser( -+ adapter_serv)); -+ if (pool->stream_enc[pool->stream_enc_count] == NULL) { -+ BREAK_TO_DEBUGGER(); -+ dm_error("DC: failed to create stream_encoder!\n"); -+ goto stream_enc_create_fail; -+ } -+ pool->stream_enc_count++; -+ } -+ -+ return true; -+ -+stream_enc_create_fail: -+ for (i = 0; i < pool->stream_enc_count; i++) { -+ if (pool->stream_enc[i] != NULL) -+ dm_free(pool->stream_enc[i]->ctx, -+ DCE110STRENC_FROM_STRENC(pool->stream_enc[i])); -+ } -+ -+audio_create_fail: -+ for (i = 0; i < pool->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) -+ dce80_opp_destroy(&pool->opps[i]); -+ -+ if (pool->transforms[i] != NULL) -+ dce80_transform_destroy(&pool->transforms[i]); -+ -+ if (pool->ipps[i] != NULL) -+ dce80_ipp_destroy(&pool->ipps[i]); -+ -+ if (pool->mis[i] != NULL) { -+ dm_free(pool->mis[i]->ctx, -+ TO_DCE110_MEM_INPUT(pool->mis[i])); -+ pool->mis[i] = NULL; -+ } -+ if (pool->timing_generators[i] != NULL) { -+ dm_free(pool->timing_generators[i]->ctx, -+ DCE110TG_FROM_TG(pool->timing_generators[i])); -+ pool->timing_generators[i] = NULL; -+ } -+ } -+ -+filter_create_fail: -+ dal_irq_service_destroy(&pool->irqs); -+ -+irqs_create_fail: -+ dal_display_clock_destroy(&pool->display_clock); -+ -+disp_clk_create_fail: -+clk_src_create_fail: -+ for (i = 0; i < pool->clk_src_count; i++) { -+ if (pool->clock_sources[i] != NULL) -+ dce80_clock_source_destroy(&pool->clock_sources[i]); -+ } -+ -+ return false; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_resource.h -new file mode 100644 -index 0000000..3d0f8fe ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_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_DCE80_H__ -+#define __DC_RESOURCE_DCE80_H__ -+ -+#include "core_types.h" -+ -+struct adapter_service; -+struct dc; -+struct resource_pool; -+ -+bool dce80_construct_resource_pool( -+ struct adapter_service *adapter_serv, -+ uint8_t num_virtual_links, -+ struct dc *dc, -+ struct resource_pool *pool); -+ -+#endif /* __DC_RESOURCE_DCE80_H__ */ -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.c -new file mode 100644 -index 0000000..d45a1e4 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.c -@@ -0,0 +1,1104 @@ -+/* -+ * 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 "bios_parser_types.h" -+#include "dc_bios_types.h" -+#include "../dce110/dce110_stream_encoder.h" -+#include "dce80_stream_encoder.h" -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#define LINK_REG(reg)\ -+ (enc110->regs->reg) -+ -+#define VBI_LINE_0 0 -+#define DP_BLANK_MAX_RETRY 20 -+ -+enum dp_pixel_encoding { -+ DP_PIXEL_ENCODING_RGB444 = 0, -+ DP_PIXEL_ENCODING_YCBCR422, -+ DP_PIXEL_ENCODING_YCBCR444, -+ DP_PIXEL_ENCODING_RGB_WIDE_GAMUT, -+ DP_PIXEL_ENCODING_Y_ONLY -+}; -+ -+enum dp_component_depth { -+ DP_COMPONENT_DEPTH_6BPC = 0, -+ DP_COMPONENT_DEPTH_8BPC, -+ DP_COMPONENT_DEPTH_10BPC, -+ DP_COMPONENT_DEPTH_12BPC -+}; -+ -+enum { -+ DP_MST_UPDATE_MAX_RETRY = 50 -+}; -+ -+static struct stream_encoder_funcs dce80_str_enc_funcs = { -+ .dp_set_stream_attribute = -+ dce80_stream_encoder_dp_set_stream_attribute, -+ .hdmi_set_stream_attribute = -+ dce80_stream_encoder_hdmi_set_stream_attribute, -+ .dvi_set_stream_attribute = -+ dce80_stream_encoder_dvi_set_stream_attribute, -+ .set_mst_bandwidth = -+ dce80_stream_encoder_set_mst_bandwidth, -+ .update_hdmi_info_packets = -+ dce80_stream_encoder_update_hdmi_info_packets, -+ .stop_hdmi_info_packets = -+ dce80_stream_encoder_stop_hdmi_info_packets, -+ .update_dp_info_packets = -+ dce80_stream_encoder_update_dp_info_packets, -+ .stop_dp_info_packets = -+ dce80_stream_encoder_stop_dp_info_packets, -+ .dp_blank = -+ dce80_stream_encoder_dp_blank, -+ .dp_unblank = -+ dce80_stream_encoder_dp_unblank, -+}; -+ -+static void dce80_update_generic_info_packet( -+ struct dce110_stream_encoder *enc110, -+ uint32_t packet_index, -+ const struct encoder_info_packet *info_packet) -+{ -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr; -+ uint32_t regval; -+ /* choose which generic packet to use */ -+ { -+ addr = LINK_REG(AFMT_VBI_PACKET_CONTROL); -+ -+ regval = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ regval, -+ packet_index, -+ AFMT_VBI_PACKET_CONTROL, -+ AFMT_GENERIC_INDEX); -+ -+ dm_write_reg(ctx, addr, regval); -+ } -+ -+ /* write generic packet header -+ * (4th byte is for GENERIC0 only) -+ */ -+ { -+ addr = LINK_REG(AFMT_GENERIC_HDR); -+ -+ regval = 0; -+ -+ set_reg_field_value( -+ regval, -+ info_packet->hb0, -+ AFMT_GENERIC_HDR, -+ AFMT_GENERIC_HB0); -+ -+ set_reg_field_value( -+ regval, -+ info_packet->hb1, -+ AFMT_GENERIC_HDR, -+ AFMT_GENERIC_HB1); -+ -+ set_reg_field_value( -+ regval, -+ info_packet->hb2, -+ AFMT_GENERIC_HDR, -+ AFMT_GENERIC_HB2); -+ -+ set_reg_field_value( -+ regval, -+ info_packet->hb3, -+ AFMT_GENERIC_HDR, -+ AFMT_GENERIC_HB3); -+ -+ dm_write_reg(ctx, addr, regval); -+ } -+ -+ /* write generic packet contents -+ * (we never use last 4 bytes) -+ * there are 8 (0-7) mmDIG0_AFMT_GENERIC0_x registers -+ */ -+ { -+ const uint32_t *content = -+ (const uint32_t *) &info_packet->sb[0]; -+ -+ uint32_t counter = 0; -+ -+ addr = LINK_REG(AFMT_GENERIC_0); -+ -+ do { -+ dm_write_reg(ctx, addr++, *content++); -+ -+ ++counter; -+ } while (counter < 7); -+ } -+ -+ addr = LINK_REG(AFMT_GENERIC_7); -+ -+ dm_write_reg( -+ ctx, -+ addr, -+ 0); -+ -+ /* force double-buffered packet update */ -+ { -+ addr = LINK_REG(AFMT_VBI_PACKET_CONTROL); -+ -+ regval = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ regval, -+ (packet_index == 0), -+ AFMT_VBI_PACKET_CONTROL, -+ AFMT_GENERIC0_UPDATE); -+ -+ set_reg_field_value( -+ regval, -+ (packet_index == 2), -+ AFMT_VBI_PACKET_CONTROL, -+ AFMT_GENERIC2_UPDATE); -+ -+ dm_write_reg(ctx, addr, regval); -+ } -+} -+ -+static void dce80_update_hdmi_info_packet( -+ struct dce110_stream_encoder *enc110, -+ uint32_t packet_index, -+ const struct encoder_info_packet *info_packet) -+{ -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t cont, send, line; -+ uint32_t addr = 0; -+ uint32_t regval; -+ -+ if (info_packet->valid) { -+ dce80_update_generic_info_packet( -+ enc110, -+ packet_index, -+ info_packet); -+ -+ /* enable transmission of packet(s) - -+ * packet transmission begins on the next frame -+ */ -+ cont = 1; -+ /* send packet(s) every frame */ -+ send = 1; -+ /* select line number to send packets on */ -+ line = 2; -+ } else { -+ cont = 0; -+ send = 0; -+ line = 0; -+ } -+ -+ /* choose which generic packet control to use */ -+ -+ switch (packet_index) { -+ case 0: -+ case 1: -+ addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL0); -+ break; -+ case 2: -+ case 3: -+ addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL1); -+ break; -+ default: -+ /* invalid HW packet index */ -+ dal_logger_write( -+ ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_ENCODER, -+ "Invalid HW packet index: %s()\n", -+ __func__); -+ break; -+ } -+ -+ regval = dm_read_reg(ctx, addr); -+ -+ switch (packet_index) { -+ case 0: -+ case 2: -+ set_reg_field_value( -+ regval, -+ cont, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC0_CONT); -+ set_reg_field_value( -+ regval, -+ send, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC0_SEND); -+ set_reg_field_value( -+ regval, -+ line, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC0_LINE); -+ break; -+ case 1: -+ case 3: -+ set_reg_field_value( -+ regval, -+ cont, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC1_CONT); -+ set_reg_field_value( -+ regval, -+ send, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC1_SEND); -+ set_reg_field_value( -+ regval, -+ line, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC1_LINE); -+ break; -+ default: -+ /* invalid HW packet index */ -+ dal_logger_write( -+ ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_ENCODER, -+ "Invalid HW packet index: %s()\n", -+ __func__); -+ break; -+ } -+ -+ dm_write_reg(ctx, addr, regval); -+} -+ -+bool dce80_stream_encoder_construct( -+ struct dce110_stream_encoder *enc110, -+ struct dc_context *ctx, -+ struct dc_bios *dcb, -+ enum engine_id eng_id, -+ const struct dce110_stream_enc_registers *regs) -+{ -+ if (!enc110) -+ return false; -+ if (!dcb) -+ return false; -+ -+ enc110->base.funcs = &dce80_str_enc_funcs; -+ enc110->base.ctx = ctx; -+ enc110->base.id = eng_id; -+ enc110->base.bp = dcb; -+ enc110->regs = regs; -+ -+ return true; -+} -+ -+/* setup stream encoder in dp mode */ -+void dce80_stream_encoder_dp_set_stream_attribute( -+ struct stream_encoder *enc, -+ struct dc_crtc_timing *crtc_timing) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = LINK_REG(DP_PIXEL_FORMAT); -+ uint32_t value = dm_read_reg(ctx, addr); -+ -+ /* set pixel encoding */ -+ switch (crtc_timing->pixel_encoding) { -+ case PIXEL_ENCODING_YCBCR422: -+ set_reg_field_value( -+ value, -+ DP_PIXEL_ENCODING_YCBCR422, -+ DP_PIXEL_FORMAT, -+ DP_PIXEL_ENCODING); -+ break; -+ case PIXEL_ENCODING_YCBCR444: -+ set_reg_field_value( -+ value, -+ DP_PIXEL_ENCODING_YCBCR444, -+ DP_PIXEL_FORMAT, -+ DP_PIXEL_ENCODING); -+ -+ if (crtc_timing->flags.Y_ONLY) -+ if (crtc_timing->display_color_depth != COLOR_DEPTH_666) -+ /* HW testing only, no use case yet. -+ * Color depth of Y-only could be -+ * 8, 10, 12, 16 bits -+ */ -+ set_reg_field_value( -+ value, -+ DP_PIXEL_ENCODING_Y_ONLY, -+ DP_PIXEL_FORMAT, -+ DP_PIXEL_ENCODING); -+ /* Note: DP_MSA_MISC1 bit 7 is the indicator -+ * of Y-only mode. -+ * This bit is set in HW if register -+ * DP_PIXEL_ENCODING is programmed to 0x4 -+ */ -+ break; -+ default: -+ set_reg_field_value( -+ value, -+ DP_PIXEL_ENCODING_RGB444, -+ DP_PIXEL_FORMAT, -+ DP_PIXEL_ENCODING); -+ break; -+ } -+ -+ /* set color depth */ -+ -+ switch (crtc_timing->display_color_depth) { -+ case COLOR_DEPTH_888: -+ set_reg_field_value( -+ value, -+ DP_COMPONENT_DEPTH_8BPC, -+ DP_PIXEL_FORMAT, -+ DP_COMPONENT_DEPTH); -+ break; -+ case COLOR_DEPTH_101010: -+ set_reg_field_value( -+ value, -+ DP_COMPONENT_DEPTH_10BPC, -+ DP_PIXEL_FORMAT, -+ DP_COMPONENT_DEPTH); -+ break; -+ case COLOR_DEPTH_121212: -+ set_reg_field_value( -+ value, -+ DP_COMPONENT_DEPTH_12BPC, -+ DP_PIXEL_FORMAT, -+ DP_COMPONENT_DEPTH); -+ break; -+ default: -+ set_reg_field_value( -+ value, -+ DP_COMPONENT_DEPTH_6BPC, -+ DP_PIXEL_FORMAT, -+ DP_COMPONENT_DEPTH); -+ break; -+ } -+ -+ /* set dynamic range and YCbCr range */ -+ set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_DYN_RANGE); -+ set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_YCBCR_RANGE); -+ -+ dm_write_reg(ctx, addr, value); -+ -+} -+ -+/* setup stream encoder in hdmi mode */ -+void dce80_stream_encoder_hdmi_set_stream_attribute( -+ struct stream_encoder *enc, -+ struct dc_crtc_timing *crtc_timing, -+ bool enable_audio) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = LINK_REG(TMDS_CNTL); -+ uint32_t value = dm_read_reg(ctx, addr); -+ uint32_t output_pixel_clock = crtc_timing->pix_clk_khz; -+ struct bp_encoder_control cntl = {0}; -+ -+ cntl.action = ENCODER_CONTROL_SETUP; -+ cntl.engine_id = enc110->base.id; -+ cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; -+ cntl.enable_dp_audio = enable_audio; -+ cntl.pixel_clock = crtc_timing->pix_clk_khz; -+ cntl.lanes_number = LANE_COUNT_FOUR; -+ cntl.color_depth = crtc_timing->display_color_depth; -+ -+ if (enc110->base.bp->funcs->encoder_control( -+ enc110->base.bp, &cntl) != BP_RESULT_OK) -+ return; -+ -+ switch (crtc_timing->pixel_encoding) { -+ case PIXEL_ENCODING_YCBCR422: -+ set_reg_field_value(value, 1, TMDS_CNTL, TMDS_PIXEL_ENCODING); -+ break; -+ default: -+ set_reg_field_value(value, 0, TMDS_CNTL, TMDS_PIXEL_ENCODING); -+ break; -+ } -+ -+ set_reg_field_value(value, 0, TMDS_CNTL, TMDS_COLOR_FORMAT); -+ dm_write_reg(ctx, addr, value); -+ -+ /* setup HDMI engine */ -+ addr = LINK_REG(HDMI_CONTROL); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_PACKET_GEN_VERSION); -+ set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_KEEPOUT_MODE); -+ set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE); -+ -+ switch (crtc_timing->display_color_depth) { -+ case COLOR_DEPTH_888: -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_DEPTH); -+ break; -+ case COLOR_DEPTH_101010: -+ set_reg_field_value( -+ value, -+ 1, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_DEPTH); -+ set_reg_field_value( -+ value, -+ 1, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_ENABLE); -+ output_pixel_clock = (crtc_timing->pix_clk_khz * 30) / 24; -+ break; -+ case COLOR_DEPTH_121212: -+ set_reg_field_value( -+ value, -+ 2, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_DEPTH); -+ set_reg_field_value( -+ value, -+ 1, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_ENABLE); -+ output_pixel_clock = (crtc_timing->pix_clk_khz * 36) / 24; -+ break; -+ case COLOR_DEPTH_161616: -+ set_reg_field_value( -+ value, -+ 3, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_DEPTH); -+ set_reg_field_value( -+ value, -+ 1, -+ HDMI_CONTROL, -+ HDMI_DEEP_COLOR_ENABLE); -+ output_pixel_clock = (crtc_timing->pix_clk_khz * 48) / 24; -+ break; -+ default: -+ break; -+ } -+ -+ dm_write_reg(ctx, addr, value); -+ -+ addr = LINK_REG(HDMI_VBI_PACKET_CONTROL); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT); -+ set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND); -+ set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND); -+ -+ dm_write_reg(ctx, addr, value); -+ -+ /* following belongs to audio */ -+ addr = LINK_REG(HDMI_INFOFRAME_CONTROL0); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ value, -+ 1, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AUDIO_INFO_SEND); -+ dm_write_reg(ctx, addr, value); -+ -+ addr = LINK_REG(AFMT_INFOFRAME_CONTROL0); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ value, -+ 1, -+ AFMT_INFOFRAME_CONTROL0, -+ AFMT_AUDIO_INFO_UPDATE); -+ dm_write_reg(ctx, addr, value); -+ -+ addr = LINK_REG(HDMI_INFOFRAME_CONTROL1); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ value, -+ VBI_LINE_0 + 2, -+ HDMI_INFOFRAME_CONTROL1, -+ HDMI_AUDIO_INFO_LINE); -+ dm_write_reg(ctx, addr, value); -+ -+ addr = LINK_REG(HDMI_GC); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, 0, HDMI_GC, HDMI_GC_AVMUTE); -+ dm_write_reg(ctx, addr, value); -+} -+ -+/* setup stream encoder in dvi mode */ -+void dce80_stream_encoder_dvi_set_stream_attribute( -+ struct stream_encoder *enc, -+ struct dc_crtc_timing *crtc_timing, -+ bool is_dual_link) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = LINK_REG(TMDS_CNTL); -+ uint32_t value = dm_read_reg(ctx, addr); -+ struct bp_encoder_control cntl = {0}; -+ -+ cntl.action = ENCODER_CONTROL_SETUP; -+ cntl.engine_id = enc110->base.id; -+ cntl.signal = is_dual_link ? -+ SIGNAL_TYPE_DVI_DUAL_LINK : -+ SIGNAL_TYPE_DVI_SINGLE_LINK; -+ cntl.enable_dp_audio = false; -+ cntl.pixel_clock = crtc_timing->pix_clk_khz; -+ cntl.lanes_number = (is_dual_link) ? -+ LANE_COUNT_EIGHT : LANE_COUNT_FOUR; -+ cntl.color_depth = crtc_timing->display_color_depth; -+ -+ if (enc110->base.bp->funcs->encoder_control( -+ enc110->base.bp, &cntl) != BP_RESULT_OK) -+ return; -+ -+ switch (crtc_timing->pixel_encoding) { -+ case PIXEL_ENCODING_YCBCR422: -+ set_reg_field_value(value, 1, TMDS_CNTL, TMDS_PIXEL_ENCODING); -+ break; -+ default: -+ set_reg_field_value(value, 0, TMDS_CNTL, TMDS_PIXEL_ENCODING); -+ break; -+ } -+ -+ switch (crtc_timing->pixel_encoding) { -+ case COLOR_DEPTH_101010: -+ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) -+ set_reg_field_value( -+ value, -+ 2, -+ TMDS_CNTL, -+ TMDS_COLOR_FORMAT); -+ else -+ set_reg_field_value( -+ value, -+ 0, -+ TMDS_CNTL, -+ TMDS_COLOR_FORMAT); -+ break; -+ default: -+ set_reg_field_value(value, 0, TMDS_CNTL, TMDS_COLOR_FORMAT); -+ break; -+ } -+ dm_write_reg(ctx, addr, value); -+} -+ -+void dce80_stream_encoder_set_mst_bandwidth( -+ struct stream_encoder *enc, -+ struct fixed31_32 avg_time_slots_per_mtp) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr; -+ uint32_t field; -+ uint32_t value; -+ uint32_t retries = 0; -+ uint32_t x = dal_fixed31_32_floor( -+ avg_time_slots_per_mtp); -+ uint32_t y = dal_fixed31_32_ceil( -+ dal_fixed31_32_shl( -+ dal_fixed31_32_sub_int( -+ avg_time_slots_per_mtp, -+ x), -+ 26)); -+ -+ { -+ addr = LINK_REG(DP_MSE_RATE_CNTL); -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ x, -+ DP_MSE_RATE_CNTL, -+ DP_MSE_RATE_X); -+ -+ set_reg_field_value( -+ value, -+ y, -+ DP_MSE_RATE_CNTL, -+ DP_MSE_RATE_Y); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ /* wait for update to be completed on the link */ -+ /* i.e. DP_MSE_RATE_UPDATE_PENDING field (read only) */ -+ /* is reset to 0 (not pending) */ -+ { -+ addr = LINK_REG(DP_MSE_RATE_UPDATE); -+ -+ do { -+ value = dm_read_reg(ctx, addr); -+ -+ field = get_reg_field_value( -+ value, -+ DP_MSE_RATE_UPDATE, -+ DP_MSE_RATE_UPDATE_PENDING); -+ -+ if (!(field & -+ DP_MSE_RATE_UPDATE__DP_MSE_RATE_UPDATE_PENDING_MASK)) -+ break; -+ -+ dm_delay_in_microseconds(ctx, 10); -+ -+ ++retries; -+ } while (retries < DP_MST_UPDATE_MAX_RETRY); -+ } -+} -+ -+void dce80_stream_encoder_update_hdmi_info_packets( -+ struct stream_encoder *enc, -+ const struct encoder_info_frame *info_frame) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr; -+ uint32_t regval; -+ uint32_t control0val; -+ uint32_t control1val; -+ -+ if (info_frame->avi.valid) { -+ const uint32_t *content = -+ (const uint32_t *) &info_frame->avi.sb[0]; -+ -+ addr = LINK_REG(AFMT_AVI_INFO0); -+ regval = content[0]; -+ -+ dm_write_reg( -+ ctx, -+ addr, -+ regval); -+ -+ addr = LINK_REG(AFMT_AVI_INFO1); -+ regval = content[1]; -+ -+ dm_write_reg( -+ ctx, -+ addr, -+ regval); -+ -+ addr = LINK_REG(AFMT_AVI_INFO2); -+ regval = content[2]; -+ -+ dm_write_reg( -+ ctx, -+ addr, -+ regval); -+ -+ addr = LINK_REG(AFMT_AVI_INFO3); -+ regval = content[3]; -+ -+ /* move version to AVI_INFO3 */ -+ set_reg_field_value( -+ regval, -+ info_frame->avi.hb1, -+ AFMT_AVI_INFO3, -+ AFMT_AVI_INFO_VERSION); -+ -+ dm_write_reg( -+ ctx, -+ addr, -+ regval); -+ -+ addr = LINK_REG(HDMI_INFOFRAME_CONTROL0); -+ control0val = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ control0val, -+ 1, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AVI_INFO_SEND); -+ -+ set_reg_field_value( -+ control0val, -+ 1, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AVI_INFO_CONT); -+ -+ dm_write_reg(ctx, addr, control0val); -+ -+ addr = LINK_REG(HDMI_INFOFRAME_CONTROL1); -+ -+ control1val = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ control1val, -+ VBI_LINE_0 + 2, -+ HDMI_INFOFRAME_CONTROL1, -+ HDMI_AVI_INFO_LINE); -+ -+ dm_write_reg(ctx, addr, control1val); -+ } else { -+ addr = LINK_REG(HDMI_INFOFRAME_CONTROL0); -+ -+ regval = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ regval, -+ 0, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AVI_INFO_SEND); -+ -+ set_reg_field_value( -+ regval, -+ 0, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AVI_INFO_CONT); -+ -+ dm_write_reg(ctx, addr, regval); -+ } -+ -+ dce80_update_hdmi_info_packet(enc110, 0, &info_frame->vendor); -+ dce80_update_hdmi_info_packet(enc110, 1, &info_frame->gamut); -+ dce80_update_hdmi_info_packet(enc110, 2, &info_frame->spd); -+} -+ -+void dce80_stream_encoder_stop_hdmi_info_packets( -+ struct stream_encoder *enc) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = 0; -+ uint32_t value = 0; -+ -+ /* stop generic packets 0 & 1 on HDMI */ -+ addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL0); -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC1_CONT); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC1_LINE); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC1_SEND); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC0_CONT); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC0_LINE); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL0, -+ HDMI_GENERIC0_SEND); -+ -+ dm_write_reg(ctx, addr, value); -+ -+ /* stop generic packets 2 & 3 on HDMI */ -+ addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL1); -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL1, -+ HDMI_GENERIC2_CONT); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL1, -+ HDMI_GENERIC2_LINE); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL1, -+ HDMI_GENERIC2_SEND); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL1, -+ HDMI_GENERIC3_CONT); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL1, -+ HDMI_GENERIC3_LINE); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_GENERIC_PACKET_CONTROL1, -+ HDMI_GENERIC3_SEND); -+ -+ dm_write_reg(ctx, addr, value); -+ -+ /* stop AVI packet on HDMI */ -+ addr = LINK_REG(HDMI_INFOFRAME_CONTROL0); -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AVI_INFO_SEND); -+ set_reg_field_value( -+ value, -+ 0, -+ HDMI_INFOFRAME_CONTROL0, -+ HDMI_AVI_INFO_CONT); -+ -+ dm_write_reg(ctx, addr, value); -+} -+void dce80_stream_encoder_update_dp_info_packets( -+ struct stream_encoder *enc, -+ const struct encoder_info_frame *info_frame) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = LINK_REG(DP_SEC_CNTL); -+ uint32_t value; -+ -+ if (info_frame->vsc.valid) -+ dce80_update_generic_info_packet( -+ enc110, -+ 0, -+ &info_frame->vsc); -+ -+ /* enable/disable transmission of packet(s). -+ * If enabled, packet transmission begins on the next frame -+ */ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ info_frame->vsc.valid, -+ DP_SEC_CNTL, -+ DP_SEC_GSP0_ENABLE); -+ -+ /* This bit is the master enable bit. -+ * When enabling secondary stream engine, -+ * this master bit must also be set. -+ * This register shared with audio info frame. -+ * Therefore we need to enable master bit -+ * if at least on of the fields is not 0 -+ */ -+ if (value) -+ set_reg_field_value( -+ value, -+ 1, -+ DP_SEC_CNTL, -+ DP_SEC_STREAM_ENABLE); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+void dce80_stream_encoder_stop_dp_info_packets( -+ struct stream_encoder *enc) -+{ -+ /* stop generic packets on DP */ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = LINK_REG(DP_SEC_CNTL); -+ uint32_t value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP0_ENABLE); -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP1_ENABLE); -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP2_ENABLE); -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP3_ENABLE); -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_AVI_ENABLE); -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_MPG_ENABLE); -+ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_STREAM_ENABLE); -+ -+ /* this register shared with audio info frame. -+ * therefore we need to keep master enabled -+ * if at least one of the fields is not 0 -+ */ -+ -+ if (value) -+ set_reg_field_value( -+ value, -+ 1, -+ DP_SEC_CNTL, -+ DP_SEC_STREAM_ENABLE); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+void dce80_stream_encoder_dp_blank( -+ struct stream_encoder *enc) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr = LINK_REG(DP_VID_STREAM_CNTL); -+ uint32_t value = dm_read_reg(ctx, addr); -+ uint32_t retries = 0; -+ uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; -+ -+ /* Note: For CZ, we are changing driver default to disable -+ * stream deferred to next VBLANK. If results are positive, we -+ * will make the same change to all DCE versions. There are a -+ * handful of panels that cannot handle disable stream at -+ * HBLANK and will result in a white line flash across the -+ * screen on stream disable. -+ */ -+ -+ /* Specify the video stream disable point -+ * (2 = start of the next vertical blank) -+ */ -+ set_reg_field_value( -+ value, -+ 2, -+ DP_VID_STREAM_CNTL, -+ DP_VID_STREAM_DIS_DEFER); -+ /* Larger delay to wait until VBLANK - use max retry of -+ * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + -+ * a little more because we may not trust delay accuracy. -+ */ -+ max_retries = DP_BLANK_MAX_RETRY * 150; -+ -+ /* disable DP stream */ -+ set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE); -+ dm_write_reg(ctx, addr, value); -+ -+ /* the encoder stops sending the video stream -+ * at the start of the vertical blanking. -+ * Poll for DP_VID_STREAM_STATUS == 0 -+ */ -+ -+ do { -+ value = dm_read_reg(ctx, addr); -+ -+ if (!get_reg_field_value( -+ value, -+ DP_VID_STREAM_CNTL, -+ DP_VID_STREAM_STATUS)) -+ break; -+ -+ dm_delay_in_microseconds(ctx, 10); -+ -+ ++retries; -+ } while (retries < max_retries); -+ -+ ASSERT(retries <= max_retries); -+ -+ /* Tell the DP encoder to ignore timing from CRTC, must be done after -+ * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is -+ * complete, stream status will be stuck in video stream enabled state, -+ * i.e. DP_VID_STREAM_STATUS stuck at 1. -+ */ -+ addr = LINK_REG(DP_STEER_FIFO); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, true, DP_STEER_FIFO, DP_STEER_FIFO_RESET); -+ dm_write_reg(ctx, addr, value); -+} -+ -+/* output video stream to link encoder */ -+void dce80_stream_encoder_dp_unblank( -+ struct stream_encoder *enc, -+ const struct encoder_unblank_param *param) -+{ -+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -+ struct dc_context *ctx = enc110->base.ctx; -+ uint32_t addr; -+ uint32_t value; -+ -+ if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) { -+ uint32_t n_vid = 0x8000; -+ uint32_t m_vid; -+ -+ /* M / N = Fstream / Flink -+ * m_vid / n_vid = pixel rate / link rate -+ */ -+ -+ uint64_t m_vid_l = n_vid; -+ -+ m_vid_l *= param->crtc_timing.pixel_clock; -+ m_vid_l = div_u64(m_vid_l, -+ param->link_settings.link_rate -+ * LINK_RATE_REF_FREQ_IN_KHZ); -+ -+ m_vid = (uint32_t) m_vid_l; -+ -+ /* enable auto measurement */ -+ addr = LINK_REG(DP_VID_TIMING); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, 0, DP_VID_TIMING, DP_VID_M_N_GEN_EN); -+ dm_write_reg(ctx, addr, value); -+ -+ /* auto measurement need 1 full 0x8000 symbol cycle to kick in, -+ * therefore program initial value for Mvid and Nvid -+ */ -+ addr = LINK_REG(DP_VID_N); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, n_vid, DP_VID_N, DP_VID_N); -+ dm_write_reg(ctx, addr, value); -+ -+ addr = LINK_REG(DP_VID_M); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, m_vid, DP_VID_M, DP_VID_M); -+ dm_write_reg(ctx, addr, value); -+ -+ addr = LINK_REG(DP_VID_TIMING); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, 1, DP_VID_TIMING, DP_VID_M_N_GEN_EN); -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ /* set DIG_START to 0x1 to resync FIFO */ -+ addr = LINK_REG(DIG_FE_CNTL); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, 1, DIG_FE_CNTL, DIG_START); -+ dm_write_reg(ctx, addr, value); -+ -+ /* switch DP encoder to CRTC data */ -+ addr = LINK_REG(DP_STEER_FIFO); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value(value, false, DP_STEER_FIFO, DP_STEER_FIFO_RESET); -+ dm_write_reg(ctx, addr, value); -+ -+ /* wait 100us for DIG/DP logic to prime -+ * (i.e. a few video lines) -+ */ -+ dm_delay_in_microseconds(ctx, 100); -+ -+ /* the hardware would start sending video at the start of the next DP -+ * frame (i.e. rising edge of the vblank). -+ * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this -+ * register has no effect on enable transition! HW always guarantees -+ * VID_STREAM enable at start of next frame, and this is not -+ * programmable -+ */ -+ addr = LINK_REG(DP_VID_STREAM_CNTL); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ value, -+ true, -+ DP_VID_STREAM_CNTL, -+ DP_VID_STREAM_ENABLE); -+ dm_write_reg(ctx, addr, value); -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.h -new file mode 100644 -index 0000000..f4645a8 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_stream_encoder.h -@@ -0,0 +1,85 @@ -+/* -+ * 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 "inc/stream_encoder.h" -+ -+#ifndef __DC_STREAM_ENCODER_DCE80_H__ -+#define __DC_STREAM_ENCODER_DCE80_H__ -+ -+bool dce80_stream_encoder_construct( -+ struct dce110_stream_encoder *enc110, -+ struct dc_context *ctx, -+ struct dc_bios *bp, -+ enum engine_id eng_id, -+ const struct dce110_stream_enc_registers *regs); -+ -+/***** HW programming ***********/ -+/* setup stream encoder in dp mode */ -+void dce80_stream_encoder_dp_set_stream_attribute( -+ struct stream_encoder *enc, -+ struct dc_crtc_timing *crtc_timing); -+ -+/* setup stream encoder in hdmi mode */ -+void dce80_stream_encoder_hdmi_set_stream_attribute( -+ struct stream_encoder *enc, -+ struct dc_crtc_timing *crtc_timing, -+ bool enable_audio); -+ -+/* setup stream encoder in dvi mode */ -+void dce80_stream_encoder_dvi_set_stream_attribute( -+ struct stream_encoder *enc, -+ struct dc_crtc_timing *crtc_timing, -+ bool is_dual_link); -+ -+/* set throttling for DP MST */ -+void dce80_stream_encoder_set_mst_bandwidth( -+ struct stream_encoder *enc, -+ struct fixed31_32 avg_time_slots_per_mtp); -+ -+void dce80_stream_encoder_update_hdmi_info_packets( -+ struct stream_encoder *enc, -+ const struct encoder_info_frame *info_frame); -+ -+void dce80_stream_encoder_stop_hdmi_info_packets( -+ struct stream_encoder *enc); -+ -+void dce80_stream_encoder_update_dp_info_packets( -+ struct stream_encoder *enc, -+ const struct encoder_info_frame *info_frame); -+ -+void dce80_stream_encoder_stop_dp_info_packets( -+ struct stream_encoder *enc); -+ -+/* output blank/idle stream to link encoder */ -+void dce80_stream_encoder_dp_blank( -+ struct stream_encoder *enc); -+ -+/* output video stream to link encoder */ -+void dce80_stream_encoder_dp_unblank( -+ struct stream_encoder *enc, -+ const struct encoder_unblank_param *param); -+ -+ -+#endif /* __DC_STREAM_ENCODER_DCE80_H__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.c -new file mode 100644 -index 0000000..80391c2 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.c -@@ -0,0 +1,241 @@ -+/* -+ * 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 DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dc_types.h" -+ -+#include "include/grph_object_id.h" -+#include "include/adapter_service_interface.h" -+#include "include/logger_interface.h" -+#include "../dce110/dce110_timing_generator.h" -+#include "dce80_timing_generator.h" -+ -+#include "../inc/timing_generator.h" -+ -+enum black_color_format { -+ BLACK_COLOR_FORMAT_RGB_FULLRANGE = 0, /* used as index in array */ -+ BLACK_COLOR_FORMAT_RGB_LIMITED, -+ BLACK_COLOR_FORMAT_YUV_TV, -+ BLACK_COLOR_FORMAT_YUV_CV, -+ BLACK_COLOR_FORMAT_YUV_SUPER_AA, -+ -+ BLACK_COLOR_FORMAT_COUNT -+}; -+ -+static const struct dce110_timing_generator_offsets reg_offsets[] = { -+{ -+ .crtc = (mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .crtc = (mmCRTC1_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .crtc = (mmCRTC2_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .crtc = (mmCRTC3_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .crtc = (mmCRTC4_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+}, -+{ -+ .crtc = (mmCRTC5_DCFE_MEM_LIGHT_SLEEP_CNTL - mmCRTC0_DCFE_MEM_LIGHT_SLEEP_CNTL), -+ .dcp = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), -+} -+}; -+ -+#define NUMBER_OF_FRAME_TO_WAIT_ON_TRIGGERED_RESET 10 -+ -+#define MAX_H_TOTAL (CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1) -+#define MAX_V_TOTAL (CRTC_V_TOTAL__CRTC_V_TOTAL_MASKhw + 1) -+ -+#define CRTC_REG(reg) (reg + tg110->offsets.crtc) -+#define DCP_REG(reg) (reg + tg110->offsets.dcp) -+#define DMIF_REG(reg) (reg + tg110->offsets.dmif) -+ -+void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_khz) -+{ -+ uint64_t pix_dur; -+ uint32_t addr = mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL1 -+ + DCE110TG_FROM_TG(tg)->offsets.dmif; -+ uint32_t value = dm_read_reg(tg->ctx, addr); -+ -+ if (pix_clk_khz == 0) -+ return; -+ -+ pix_dur = 1000000000 / pix_clk_khz; -+ -+ set_reg_field_value( -+ value, -+ pix_dur, -+ DPG_PIPE_ARBITRATION_CONTROL1, -+ PIXEL_DURATION); -+ -+ dm_write_reg(tg->ctx, addr, value); -+} -+ -+static void program_timing(struct timing_generator *tg, -+ const struct dc_crtc_timing *timing, -+ bool use_vbios) -+{ -+ if (!use_vbios) -+ program_pix_dur(tg, timing->pix_clk_khz); -+ -+ dce110_tg_program_timing(tg, timing, use_vbios); -+} -+ -+static struct timing_generator_funcs dce80_tg_funcs = { -+ .validate_timing = dce110_tg_validate_timing, -+ .program_timing = program_timing, -+ .enable_crtc = dce110_timing_generator_enable_crtc, -+ .disable_crtc = dce110_timing_generator_disable_crtc, -+ .is_counter_moving = dce110_timing_generator_is_counter_moving, -+ .get_position = dce110_timing_generator_get_crtc_positions, -+ .get_frame_count = dce110_timing_generator_get_vblank_counter, -+ .set_early_control = dce110_timing_generator_set_early_control, -+ .wait_for_state = dce110_tg_wait_for_state, -+ .set_blank = dce110_tg_set_blank, -+ .set_colors = dce110_tg_set_colors, -+ .set_overscan_blank_color = -+ dce110_timing_generator_set_overscan_color_black, -+ .set_blank_color = dce110_timing_generator_program_blank_color, -+ .disable_vga = dce110_timing_generator_disable_vga, -+ .did_triggered_reset_occur = -+ dce110_timing_generator_did_triggered_reset_occur, -+ .setup_global_swap_lock = -+ dce110_timing_generator_setup_global_swap_lock, -+ .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger, -+ .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger, -+ .tear_down_global_swap_lock = -+ dce110_timing_generator_tear_down_global_swap_lock, -+ -+ /* DCE8.0 overrides */ -+ .enable_advanced_request = -+ dce80_timing_generator_enable_advanced_request -+}; -+ -+bool dce80_timing_generator_construct( -+ struct dce110_timing_generator *tg110, -+ struct adapter_service *as, -+ struct dc_context *ctx, -+ uint32_t instance, -+ const struct dce110_timing_generator_offsets *offsets) -+{ -+ if (!tg110) -+ return false; -+ -+ if (!as) -+ return false; -+ -+ tg110->controller_id = CONTROLLER_ID_D0 + instance; -+ tg110->offsets = *offsets; -+ tg110->derived_offsets = reg_offsets[instance]; -+ -+ tg110->base.funcs = &dce80_tg_funcs; -+ -+ tg110->base.ctx = ctx; -+ tg110->base.bp = dal_adapter_service_get_bios_parser(as); -+ -+ tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; -+ tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; -+ -+ tg110->min_h_blank = 56; -+ tg110->min_h_front_porch = 4; -+ tg110->min_h_back_porch = 4; -+ -+ return true; -+} -+ -+void dce80_timing_generator_enable_advanced_request( -+ struct timing_generator *tg, -+ bool enable, -+ const struct dc_crtc_timing *timing) -+{ -+ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); -+ uint32_t addr = CRTC_REG(mmCRTC_START_LINE_CONTROL); -+ uint32_t value = dm_read_reg(tg->ctx, addr); -+ -+ if (enable && !DCE110TG_FROM_TG(tg)->disable_advanced_request) { -+ set_reg_field_value( -+ value, -+ 0, -+ CRTC_START_LINE_CONTROL, -+ CRTC_LEGACY_REQUESTOR_EN); -+ } else { -+ set_reg_field_value( -+ value, -+ 1, -+ CRTC_START_LINE_CONTROL, -+ CRTC_LEGACY_REQUESTOR_EN); -+ } -+ -+ if ((timing->v_sync_width + timing->v_front_porch) <= 3) { -+ set_reg_field_value( -+ value, -+ 3, -+ CRTC_START_LINE_CONTROL, -+ CRTC_ADVANCED_START_LINE_POSITION); -+ set_reg_field_value( -+ value, -+ 0, -+ CRTC_START_LINE_CONTROL, -+ CRTC_PREFETCH_EN); -+ } else { -+ set_reg_field_value( -+ value, -+ 4, -+ CRTC_START_LINE_CONTROL, -+ CRTC_ADVANCED_START_LINE_POSITION); -+ set_reg_field_value( -+ value, -+ 1, -+ CRTC_START_LINE_CONTROL, -+ CRTC_PREFETCH_EN); -+ } -+ -+ set_reg_field_value( -+ value, -+ 1, -+ CRTC_START_LINE_CONTROL, -+ CRTC_PROGRESSIVE_START_LINE_EARLY); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ CRTC_START_LINE_CONTROL, -+ CRTC_INTERLACE_START_LINE_EARLY); -+ -+ dm_write_reg(tg->ctx, addr, value); -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.h -new file mode 100644 -index 0000000..0b88686 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_timing_generator.h -@@ -0,0 +1,49 @@ -+/* -+ * 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_TIMING_GENERATOR_DCE80_H__ -+#define __DC_TIMING_GENERATOR_DCE80_H__ -+ -+ -+#include "../inc/timing_generator.h" -+#include "../include/grph_object_id.h" -+ -+/* DCE8.0 implementation inherits from DCE11.0 */ -+bool dce80_timing_generator_construct( -+ struct dce110_timing_generator *tg, -+ struct adapter_service *as, -+ struct dc_context *ctx, -+ uint32_t instance, -+ const struct dce110_timing_generator_offsets *offsets); -+ -+/******** HW programming ************/ -+void dce80_timing_generator_enable_advanced_request( -+ struct timing_generator *tg, -+ bool enable, -+ const struct dc_crtc_timing *timing); -+ -+ -+ -+#endif /* __DC_TIMING_GENERATOR_DCE80_H__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.c -new file mode 100644 -index 0000000..5654738 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.c -@@ -0,0 +1,91 @@ -+/* -+ * 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 DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dc_types.h" -+#include "core_types.h" -+ -+#include "include/grph_object_id.h" -+#include "include/fixed31_32.h" -+#include "include/logger_interface.h" -+ -+#include "dce80_transform.h" -+ -+#include "dce80_transform_bit_depth.h" -+ -+static struct transform_funcs dce80_transform_funcs = { -+ .transform_power_up = -+ dce80_transform_power_up, -+ .transform_set_scaler = -+ dce80_transform_set_scaler, -+ .transform_set_scaler_bypass = -+ dce80_transform_set_scaler_bypass, -+ .transform_update_viewport = -+ dce80_transform_update_viewport, -+ .transform_set_scaler_filter = -+ dce80_transform_set_scaler_filter, -+ .transform_set_gamut_remap = -+ dce80_transform_set_gamut_remap, -+ .transform_set_pixel_storage_depth = -+ dce80_transform_set_pixel_storage_depth, -+ .transform_get_current_pixel_storage_depth = -+ dce80_transform_get_current_pixel_storage_depth -+}; -+ -+/*****************************************/ -+/* Constructor, Destructor */ -+/*****************************************/ -+ -+bool dce80_transform_construct( -+ struct dce80_transform *xfm80, -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce80_transform_reg_offsets *reg_offsets) -+{ -+ xfm80->base.ctx = ctx; -+ -+ xfm80->base.inst = inst; -+ xfm80->base.funcs = &dce80_transform_funcs; -+ -+ xfm80->offsets = *reg_offsets; -+ -+ xfm80->lb_pixel_depth_supported = -+ LB_PIXEL_DEPTH_18BPP | -+ LB_PIXEL_DEPTH_24BPP | -+ LB_PIXEL_DEPTH_30BPP; -+ -+ return true; -+} -+ -+bool dce80_transform_power_up(struct transform *xfm) -+{ -+ return dce80_transform_power_up_line_buffer(xfm); -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.h -new file mode 100644 -index 0000000..adcc54b ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform.h -@@ -0,0 +1,87 @@ -+/* 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_TRANSFORM_DCE80_H__ -+#define __DAL_TRANSFORM_DCE80_H__ -+ -+#include "inc/transform.h" -+#include "include/grph_csc_types.h" -+ -+#define TO_DCE80_TRANSFORM(transform)\ -+ container_of(transform, struct dce80_transform, base) -+ -+struct dce80_transform_reg_offsets { -+ uint32_t scl_offset; -+ uint32_t crtc_offset; -+ uint32_t dcp_offset; -+ uint32_t lb_offset; -+}; -+ -+struct dce80_transform { -+ struct transform base; -+ struct dce80_transform_reg_offsets offsets; -+ -+ uint32_t lb_pixel_depth_supported; -+}; -+ -+bool dce80_transform_construct(struct dce80_transform *xfm80, -+ struct dc_context *ctx, -+ uint32_t inst, -+ const struct dce80_transform_reg_offsets *offsets); -+ -+bool dce80_transform_power_up(struct transform *xfm); -+ -+/* SCALER RELATED */ -+bool dce80_transform_set_scaler( -+ struct transform *xfm, -+ const struct scaler_data *data); -+ -+void dce80_transform_set_scaler_bypass(struct transform *xfm); -+ -+bool dce80_transform_update_viewport( -+ struct transform *xfm, -+ const struct rect *view_port, -+ bool is_fbc_attached); -+ -+void dce80_transform_set_scaler_filter( -+ struct transform *xfm, -+ struct scaler_filter *filter); -+ -+/* GAMUT RELATED */ -+void dce80_transform_set_gamut_remap( -+ struct transform *xfm, -+ const struct grph_csc_adjustment *adjust); -+ -+/* BIT DEPTH RELATED */ -+bool dce80_transform_set_pixel_storage_depth( -+ struct transform *xfm, -+ enum lb_pixel_depth depth, -+ const struct bit_depth_reduction_params *bit_depth_params); -+ -+bool dce80_transform_get_current_pixel_storage_depth( -+ struct transform *xfm, -+ enum lb_pixel_depth *depth); -+ -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.c -new file mode 100644 -index 0000000..1dc0dbc ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.c -@@ -0,0 +1,841 @@ -+/* -+ * 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 DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_transform.h" -+ -+#include "include/logger_interface.h" -+#include "include/fixed32_32.h" -+ -+#define DCP_REG(reg)\ -+ (reg + xfm80->offsets.dcp_offset) -+ -+#define LB_REG(reg)\ -+ (reg + xfm80->offsets.lb_offset) -+ -+#define LB_TOTAL_NUMBER_OF_ENTRIES 1712 -+#define LB_BITS_PER_ENTRY 144 -+ -+enum dcp_out_trunc_round_mode { -+ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, -+ DCP_OUT_TRUNC_ROUND_MODE_ROUND -+}; -+ -+enum dcp_out_trunc_round_depth { -+ DCP_OUT_TRUNC_ROUND_DEPTH_14BIT, -+ DCP_OUT_TRUNC_ROUND_DEPTH_13BIT, -+ DCP_OUT_TRUNC_ROUND_DEPTH_12BIT, -+ DCP_OUT_TRUNC_ROUND_DEPTH_11BIT, -+ DCP_OUT_TRUNC_ROUND_DEPTH_10BIT, -+ DCP_OUT_TRUNC_ROUND_DEPTH_9BIT, -+ DCP_OUT_TRUNC_ROUND_DEPTH_8BIT -+}; -+ -+/* defines the various methods of bit reduction available for use */ -+enum dcp_bit_depth_reduction_mode { -+ DCP_BIT_DEPTH_REDUCTION_MODE_DITHER, -+ DCP_BIT_DEPTH_REDUCTION_MODE_ROUND, -+ DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE, -+ DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED, -+ DCP_BIT_DEPTH_REDUCTION_MODE_INVALID -+}; -+ -+enum dcp_spatial_dither_mode { -+ DCP_SPATIAL_DITHER_MODE_AAAA, -+ DCP_SPATIAL_DITHER_MODE_A_AA_A, -+ DCP_SPATIAL_DITHER_MODE_AABBAABB, -+ DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC, -+ DCP_SPATIAL_DITHER_MODE_INVALID -+}; -+ -+enum dcp_spatial_dither_depth { -+ DCP_SPATIAL_DITHER_DEPTH_30BPP, -+ DCP_SPATIAL_DITHER_DEPTH_24BPP -+}; -+ -+static bool set_clamp( -+ struct dce80_transform *xfm80, -+ enum dc_color_depth depth); -+ -+static bool set_round( -+ struct dce80_transform *xfm80, -+ enum dcp_out_trunc_round_mode mode, -+ enum dcp_out_trunc_round_depth depth); -+ -+static bool set_dither( -+ struct dce80_transform *xfm80, -+ bool dither_enable, -+ enum dcp_spatial_dither_mode dither_mode, -+ enum dcp_spatial_dither_depth dither_depth, -+ bool frame_random_enable, -+ bool rgb_random_enable, -+ bool highpass_random_enable); -+ -+/** -+ ******************************************************************************* -+ * dce80_transform_bit_depth_reduction_program -+ * -+ * @brief -+ * Programs the DCP bit depth reduction registers (Clamp, Round/Truncate, -+ * Dither) for dce80 -+ * -+ * @param depth : bit depth to set the clamp to (should match denorm) -+ * -+ * @return -+ * true if succeeds. -+ ******************************************************************************* -+ */ -+static bool program_bit_depth_reduction( -+ struct dce80_transform *xfm80, -+ enum dc_color_depth depth) -+{ -+ enum dcp_bit_depth_reduction_mode depth_reduction_mode; -+ enum dcp_spatial_dither_mode spatial_dither_mode; -+ bool frame_random_enable; -+ bool rgb_random_enable; -+ bool highpass_random_enable; -+ -+ if (depth > COLOR_DEPTH_121212) { -+ ASSERT_CRITICAL(false); /* Invalid clamp bit depth */ -+ return false; -+ } -+ -+ depth_reduction_mode = DCP_BIT_DEPTH_REDUCTION_MODE_DITHER; -+ -+ spatial_dither_mode = DCP_SPATIAL_DITHER_MODE_A_AA_A; -+ -+ frame_random_enable = true; -+ rgb_random_enable = true; -+ highpass_random_enable = true; -+ -+ if (!set_clamp(xfm80, depth)) { -+ /* Failure in set_clamp() */ -+ ASSERT_CRITICAL(false); -+ return false; -+ } -+ switch (depth_reduction_mode) { -+ case DCP_BIT_DEPTH_REDUCTION_MODE_DITHER: -+ /* Spatial Dither: Set round/truncate to bypass (12bit), -+ * enable Dither (30bpp) */ -+ set_round(xfm80, -+ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, -+ DCP_OUT_TRUNC_ROUND_DEPTH_12BIT); -+ -+ set_dither(xfm80, true, spatial_dither_mode, -+ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, -+ rgb_random_enable, highpass_random_enable); -+ break; -+ case DCP_BIT_DEPTH_REDUCTION_MODE_ROUND: -+ /* Round: Enable round (10bit), disable Dither */ -+ set_round(xfm80, -+ DCP_OUT_TRUNC_ROUND_MODE_ROUND, -+ DCP_OUT_TRUNC_ROUND_DEPTH_10BIT); -+ -+ set_dither(xfm80, false, spatial_dither_mode, -+ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, -+ rgb_random_enable, highpass_random_enable); -+ break; -+ case DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE: /* Truncate */ -+ /* Truncate: Enable truncate (10bit), disable Dither */ -+ set_round(xfm80, -+ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, -+ DCP_OUT_TRUNC_ROUND_DEPTH_10BIT); -+ -+ set_dither(xfm80, false, spatial_dither_mode, -+ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, -+ rgb_random_enable, highpass_random_enable); -+ break; -+ -+ case DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED: /* Disabled */ -+ /* Truncate: Set round/truncate to bypass (12bit), -+ * disable Dither */ -+ set_round(xfm80, -+ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, -+ DCP_OUT_TRUNC_ROUND_DEPTH_12BIT); -+ -+ set_dither(xfm80, false, spatial_dither_mode, -+ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, -+ rgb_random_enable, highpass_random_enable); -+ break; -+ default: -+ /* Invalid DCP Depth reduction mode */ -+ ASSERT_CRITICAL(false); -+ break; -+ } -+ -+ return true; -+} -+ -+/** -+ ******************************************************************************* -+ * set_clamp -+ * -+ * @param depth : bit depth to set the clamp to (should match denorm) -+ * -+ * @brief -+ * Programs clamp according to panel bit depth. -+ * -+ * @return -+ * true if succeeds -+ * -+ ******************************************************************************* -+ */ -+static bool set_clamp( -+ struct dce80_transform *xfm80, -+ enum dc_color_depth depth) -+{ -+ uint32_t clamp_max = 0; -+ -+ /* At the clamp block the data will be MSB aligned, so we set the max -+ * clamp accordingly. -+ * For example, the max value for 6 bits MSB aligned (14 bit bus) would -+ * be "11 1111 0000 0000" in binary, so 0x3F00. -+ */ -+ switch (depth) { -+ case COLOR_DEPTH_666: -+ /* 6bit MSB aligned on 14 bit bus '11 1111 0000 0000' */ -+ clamp_max = 0x3F00; -+ break; -+ case COLOR_DEPTH_888: -+ /* 8bit MSB aligned on 14 bit bus '11 1111 800 0000' */ -+ clamp_max = 0x3FC0; -+ break; -+ case COLOR_DEPTH_101010: -+ /* 10bit MSB aligned on 14 bit bus '11 1111 1111 800' */ -+ clamp_max = 0x3FFC; -+ break; -+ case COLOR_DEPTH_121212: -+ /* 12bit MSB aligned on 14 bit bus '11 1111 1111 1111' */ -+ clamp_max = 0x3FFF; -+ break; -+ default: -+ ASSERT_CRITICAL(false); /* Invalid clamp bit depth */ -+ return false; -+ } -+ -+ { -+ uint32_t value = 0; -+ /* always set min to 0 */ -+ set_reg_field_value( -+ value, -+ 0, -+ OUT_CLAMP_CONTROL_B_CB, -+ OUT_CLAMP_MIN_B_CB); -+ -+ set_reg_field_value( -+ value, -+ clamp_max, -+ OUT_CLAMP_CONTROL_B_CB, -+ OUT_CLAMP_MAX_B_CB); -+ -+ dm_write_reg(xfm80->base.ctx, -+ DCP_REG(mmOUT_CLAMP_CONTROL_B_CB), -+ value); -+ } -+ -+ { -+ uint32_t value = 0; -+ /* always set min to 0 */ -+ set_reg_field_value( -+ value, -+ 0, -+ OUT_CLAMP_CONTROL_G_Y, -+ OUT_CLAMP_MIN_G_Y); -+ -+ set_reg_field_value( -+ value, -+ clamp_max, -+ OUT_CLAMP_CONTROL_G_Y, -+ OUT_CLAMP_MAX_G_Y); -+ -+ dm_write_reg(xfm80->base.ctx, -+ DCP_REG(mmOUT_CLAMP_CONTROL_G_Y), -+ value); -+ } -+ -+ { -+ uint32_t value = 0; -+ /* always set min to 0 */ -+ set_reg_field_value( -+ value, -+ 0, -+ OUT_CLAMP_CONTROL_R_CR, -+ OUT_CLAMP_MIN_R_CR); -+ -+ set_reg_field_value( -+ value, -+ clamp_max, -+ OUT_CLAMP_CONTROL_R_CR, -+ OUT_CLAMP_MAX_R_CR); -+ -+ dm_write_reg(xfm80->base.ctx, -+ DCP_REG(mmOUT_CLAMP_CONTROL_R_CR), -+ value); -+ } -+ -+ return true; -+} -+ -+/** -+ ******************************************************************************* -+ * set_round -+ * -+ * @brief -+ * Programs Round/Truncate -+ * -+ * @param [in] mode :round or truncate -+ * @param [in] depth :bit depth to round/truncate to -+ OUT_ROUND_TRUNC_MODE 3:0 0xA Output data round or truncate mode -+ POSSIBLE VALUES: -+ 00 - truncate to u0.12 -+ 01 - truncate to u0.11 -+ 02 - truncate to u0.10 -+ 03 - truncate to u0.9 -+ 04 - truncate to u0.8 -+ 05 - reserved -+ 06 - truncate to u0.14 -+ 07 - truncate to u0.13 set_reg_field_value( -+ value, -+ clamp_max, -+ OUT_CLAMP_CONTROL_R_CR, -+ OUT_CLAMP_MAX_R_CR); -+ 08 - round to u0.12 -+ 09 - round to u0.11 -+ 10 - round to u0.10 -+ 11 - round to u0.9 -+ 12 - round to u0.8 -+ 13 - reserved -+ 14 - round to u0.14 -+ 15 - round to u0.13 -+ -+ * @return -+ * true if succeeds. -+ ******************************************************************************* -+ */ -+static bool set_round( -+ struct dce80_transform *xfm80, -+ enum dcp_out_trunc_round_mode mode, -+ enum dcp_out_trunc_round_depth depth) -+{ -+ uint32_t depth_bits = 0; -+ uint32_t mode_bit = 0; -+ /* zero out all bits */ -+ uint32_t value = 0; -+ -+ /* set up bit depth */ -+ switch (depth) { -+ case DCP_OUT_TRUNC_ROUND_DEPTH_14BIT: -+ depth_bits = 6; -+ break; -+ case DCP_OUT_TRUNC_ROUND_DEPTH_13BIT: -+ depth_bits = 7; -+ break; -+ case DCP_OUT_TRUNC_ROUND_DEPTH_12BIT: -+ depth_bits = 0; -+ break; -+ case DCP_OUT_TRUNC_ROUND_DEPTH_11BIT: -+ depth_bits = 1; -+ break; -+ case DCP_OUT_TRUNC_ROUND_DEPTH_10BIT: -+ depth_bits = 2; -+ break; -+ case DCP_OUT_TRUNC_ROUND_DEPTH_9BIT: -+ depth_bits = 3; -+ break; -+ case DCP_OUT_TRUNC_ROUND_DEPTH_8BIT: -+ depth_bits = 4; -+ break; -+ default: -+ /* Invalid dcp_out_trunc_round_depth */ -+ ASSERT_CRITICAL(false); -+ return false; -+ } -+ -+ set_reg_field_value( -+ value, -+ depth_bits, -+ OUT_ROUND_CONTROL, -+ OUT_ROUND_TRUNC_MODE); -+ -+ /* set up round or truncate */ -+ switch (mode) { -+ case DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE: -+ mode_bit = 0; -+ break; -+ case DCP_OUT_TRUNC_ROUND_MODE_ROUND: -+ mode_bit = 1; -+ break; -+ default: -+ /* Invalid dcp_out_trunc_round_mode */ -+ ASSERT_CRITICAL(false); -+ return false; -+ } -+ -+ depth_bits |= mode_bit << 3; -+ -+ set_reg_field_value( -+ value, -+ depth_bits, -+ OUT_ROUND_CONTROL, -+ OUT_ROUND_TRUNC_MODE); -+ -+ /* write the register */ -+ dm_write_reg(xfm80->base.ctx, -+ DCP_REG(mmOUT_ROUND_CONTROL), -+ value); -+ -+ return true; -+} -+ -+/** -+ ******************************************************************************* -+ * set_dither -+ * -+ * @brief -+ * Programs Dither -+ * -+ * @param [in] dither_enable : enable dither -+ * @param [in] dither_mode : dither mode to set -+ * @param [in] dither_depth : bit depth to dither to -+ * @param [in] frame_random_enable : enable frame random -+ * @param [in] rgb_random_enable : enable rgb random -+ * @param [in] highpass_random_enable : enable highpass random -+ * -+ * @return -+ * true if succeeds. -+ ******************************************************************************* -+ */ -+ -+static bool set_dither( -+ struct dce80_transform *xfm80, -+ bool dither_enable, -+ enum dcp_spatial_dither_mode dither_mode, -+ enum dcp_spatial_dither_depth dither_depth, -+ bool frame_random_enable, -+ bool rgb_random_enable, -+ bool highpass_random_enable) -+{ -+ uint32_t dither_depth_bits = 0; -+ uint32_t dither_mode_bits = 0; -+ /* zero out all bits */ -+ uint32_t value = 0; -+ -+ /* set up the fields */ -+ if (dither_enable) -+ set_reg_field_value( -+ value, -+ 1, -+ DCP_SPATIAL_DITHER_CNTL, -+ DCP_SPATIAL_DITHER_EN); -+ -+ switch (dither_mode) { -+ case DCP_SPATIAL_DITHER_MODE_AAAA: -+ dither_mode_bits = 0; -+ break; -+ case DCP_SPATIAL_DITHER_MODE_A_AA_A: -+ dither_mode_bits = 1; -+ break; -+ case DCP_SPATIAL_DITHER_MODE_AABBAABB: -+ dither_mode_bits = 2; -+ break; -+ case DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC: -+ dither_mode_bits = 3; -+ break; -+ default: -+ /* Invalid dcp_spatial_dither_mode */ -+ ASSERT_CRITICAL(false); -+ return false; -+ -+ } -+ set_reg_field_value( -+ value, -+ dither_mode_bits, -+ DCP_SPATIAL_DITHER_CNTL, -+ DCP_SPATIAL_DITHER_MODE); -+ -+ switch (dither_depth) { -+ case DCP_SPATIAL_DITHER_DEPTH_30BPP: -+ dither_depth_bits = 0; -+ break; -+ case DCP_SPATIAL_DITHER_DEPTH_24BPP: -+ dither_depth_bits = 1; -+ break; -+ default: -+ /* Invalid dcp_spatial_dither_depth */ -+ ASSERT_CRITICAL(false); -+ return false; -+ } -+ -+ set_reg_field_value( -+ value, -+ dither_depth_bits, -+ DCP_SPATIAL_DITHER_CNTL, -+ DCP_SPATIAL_DITHER_DEPTH); -+ -+ if (frame_random_enable) -+ set_reg_field_value( -+ value, -+ 1, -+ DCP_SPATIAL_DITHER_CNTL, -+ DCP_FRAME_RANDOM_ENABLE); -+ -+ if (rgb_random_enable) -+ set_reg_field_value( -+ value, -+ 1, -+ DCP_SPATIAL_DITHER_CNTL, -+ DCP_RGB_RANDOM_ENABLE); -+ -+ if (highpass_random_enable) -+ set_reg_field_value( -+ value, -+ 1, -+ DCP_SPATIAL_DITHER_CNTL, -+ DCP_HIGHPASS_RANDOM_ENABLE); -+ -+ /* write the register */ -+ dm_write_reg(xfm80->base.ctx, -+ DCP_REG(mmDCP_SPATIAL_DITHER_CNTL), -+ value); -+ -+ return true; -+} -+ -+bool dce80_transform_get_max_num_of_supported_lines( -+ struct dce80_transform *xfm80, -+ enum lb_pixel_depth depth, -+ uint32_t pixel_width, -+ uint32_t *lines) -+{ -+ uint32_t pixels_per_entries = 0; -+ uint32_t max_pixels_supports = 0; -+ -+ if (pixel_width == 0) -+ return false; -+ -+ /* Find number of pixels that can fit into a single LB entry and -+ * take floor of the value since we cannot store a single pixel -+ * across multiple entries. */ -+ switch (depth) { -+ case LB_PIXEL_DEPTH_18BPP: -+ pixels_per_entries = LB_BITS_PER_ENTRY / 18; -+ break; -+ -+ case LB_PIXEL_DEPTH_24BPP: -+ pixels_per_entries = LB_BITS_PER_ENTRY / 24; -+ break; -+ -+ case LB_PIXEL_DEPTH_30BPP: -+ pixels_per_entries = LB_BITS_PER_ENTRY / 30; -+ break; -+ -+ case LB_PIXEL_DEPTH_36BPP: -+ pixels_per_entries = LB_BITS_PER_ENTRY / 36; -+ break; -+ -+ default: -+ dal_logger_write(xfm80->base.ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_GPU, -+ "%s: Invalid LB pixel depth", -+ __func__); -+ break; -+ } -+ -+ if (pixels_per_entries == 0) -+ return false; -+ -+ max_pixels_supports = pixels_per_entries * LB_TOTAL_NUMBER_OF_ENTRIES; -+ -+ *lines = max_pixels_supports / pixel_width; -+ return true; -+} -+ -+void dce80_transform_enable_alpha( -+ struct dce80_transform *xfm80, -+ bool enable) -+{ -+ struct dc_context *ctx = xfm80->base.ctx; -+ uint32_t value; -+ uint32_t addr = LB_REG(mmLB_DATA_FORMAT); -+ -+ value = dm_read_reg(ctx, addr); -+ -+ if (enable == 1) -+ set_reg_field_value( -+ value, -+ 1, -+ LB_DATA_FORMAT, -+ ALPHA_EN); -+ else -+ set_reg_field_value( -+ value, -+ 0, -+ LB_DATA_FORMAT, -+ ALPHA_EN); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+static enum lb_pixel_depth translate_display_bpp_to_lb_depth( -+ uint32_t display_bpp) -+{ -+ switch (display_bpp) { -+ case 18: -+ return LB_PIXEL_DEPTH_18BPP; -+ case 24: -+ return LB_PIXEL_DEPTH_24BPP; -+ case 36: -+ case 42: -+ case 48: -+ return LB_PIXEL_DEPTH_36BPP; -+ case 30: -+ default: -+ return LB_PIXEL_DEPTH_30BPP; -+ } -+} -+ -+bool dce80_transform_get_next_lower_pixel_storage_depth( -+ struct dce80_transform *xfm80, -+ uint32_t display_bpp, -+ enum lb_pixel_depth depth, -+ enum lb_pixel_depth *lower_depth) -+{ -+ enum lb_pixel_depth depth_req_by_display = -+ translate_display_bpp_to_lb_depth(display_bpp); -+ uint32_t current_required_depth = depth_req_by_display; -+ uint32_t current_depth = depth; -+ -+ /* if required display depth < current we could go down, for example -+ * from LB_PIXEL_DEPTH_30BPP to LB_PIXEL_DEPTH_24BPP -+ */ -+ if (current_required_depth < current_depth) { -+ current_depth = current_depth >> 1; -+ if (xfm80->lb_pixel_depth_supported & current_depth) { -+ *lower_depth = current_depth; -+ return true; -+ } -+ } -+ return false; -+} -+ -+bool dce80_transform_is_prefetch_enabled( -+ struct dce80_transform *xfm80) -+{ -+ uint32_t value = dm_read_reg( -+ xfm80->base.ctx, LB_REG(mmLB_DATA_FORMAT)); -+ -+ if (get_reg_field_value(value, LB_DATA_FORMAT, PREFETCH) == 1) -+ return true; -+ -+ return false; -+} -+ -+bool dce80_transform_get_current_pixel_storage_depth( -+ struct transform *xfm, -+ enum lb_pixel_depth *depth) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ uint32_t value = 0; -+ -+ if (depth == NULL) -+ return false; -+ -+ value = dm_read_reg( -+ xfm->ctx, -+ LB_REG(mmLB_DATA_FORMAT)); -+ -+ switch (get_reg_field_value(value, LB_DATA_FORMAT, PIXEL_DEPTH)) { -+ case 0: -+ *depth = LB_PIXEL_DEPTH_30BPP; -+ break; -+ case 1: -+ *depth = LB_PIXEL_DEPTH_24BPP; -+ break; -+ case 2: -+ *depth = LB_PIXEL_DEPTH_18BPP; -+ break; -+ case 3: -+ *depth = LB_PIXEL_DEPTH_36BPP; -+ break; -+ default: -+ dal_logger_write(xfm->ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_GPU, -+ "%s: Invalid LB pixel depth", -+ __func__); -+ *depth = LB_PIXEL_DEPTH_30BPP; -+ break; -+ } -+ return true; -+ -+} -+ -+static void set_denormalization( -+ struct dce80_transform *xfm80, -+ enum dc_color_depth depth) -+{ -+ uint32_t value = dm_read_reg(xfm80->base.ctx, -+ DCP_REG(mmDENORM_CONTROL)); -+ -+ switch (depth) { -+ case COLOR_DEPTH_666: -+ /* 63/64 for 6 bit output color depth */ -+ set_reg_field_value( -+ value, -+ 1, -+ DENORM_CONTROL, -+ DENORM_MODE); -+ break; -+ case COLOR_DEPTH_888: -+ /* Unity for 8 bit output color depth -+ * because prescale is disabled by default */ -+ set_reg_field_value( -+ value, -+ 0, -+ DENORM_CONTROL, -+ DENORM_MODE); -+ break; -+ case COLOR_DEPTH_101010: -+ /* 1023/1024 for 10 bit output color depth */ -+ set_reg_field_value( -+ value, -+ 3, -+ DENORM_CONTROL, -+ DENORM_MODE); -+ break; -+ case COLOR_DEPTH_121212: -+ /* 4095/4096 for 12 bit output color depth */ -+ set_reg_field_value( -+ value, -+ 5, -+ DENORM_CONTROL, -+ DENORM_MODE); -+ break; -+ case COLOR_DEPTH_141414: -+ case COLOR_DEPTH_161616: -+ default: -+ /* not valid used case! */ -+ break; -+ } -+ -+ dm_write_reg(xfm80->base.ctx, -+ DCP_REG(mmDENORM_CONTROL), -+ value); -+ -+} -+ -+bool dce80_transform_set_pixel_storage_depth( -+ struct transform *xfm, -+ enum lb_pixel_depth depth, -+ const struct bit_depth_reduction_params *bit_depth_params) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ bool ret = true; -+ uint32_t value; -+ enum dc_color_depth color_depth; -+ -+ value = dm_read_reg( -+ xfm->ctx, -+ LB_REG(mmLB_DATA_FORMAT)); -+ switch (depth) { -+ case LB_PIXEL_DEPTH_18BPP: -+ color_depth = COLOR_DEPTH_666; -+ set_reg_field_value(value, 2, LB_DATA_FORMAT, PIXEL_DEPTH); -+ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); -+ break; -+ case LB_PIXEL_DEPTH_24BPP: -+ color_depth = COLOR_DEPTH_888; -+ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_DEPTH); -+ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); -+ break; -+ case LB_PIXEL_DEPTH_30BPP: -+ color_depth = COLOR_DEPTH_101010; -+ set_reg_field_value(value, 0, LB_DATA_FORMAT, PIXEL_DEPTH); -+ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); -+ break; -+ case LB_PIXEL_DEPTH_36BPP: -+ color_depth = COLOR_DEPTH_121212; -+ set_reg_field_value(value, 3, LB_DATA_FORMAT, PIXEL_DEPTH); -+ set_reg_field_value(value, 0, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); -+ break; -+ default: -+ ret = false; -+ break; -+ } -+ -+ if (ret == true) { -+ set_denormalization(xfm80, color_depth); -+ ret = program_bit_depth_reduction(xfm80, color_depth); -+ -+ set_reg_field_value(value, 0, LB_DATA_FORMAT, ALPHA_EN); -+ dm_write_reg( -+ xfm->ctx, LB_REG(mmLB_DATA_FORMAT), value); -+ if (!(xfm80->lb_pixel_depth_supported & depth)) { -+ /*we should use unsupported capabilities -+ * unless it is required by w/a*/ -+ dal_logger_write(xfm->ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_GPU, -+ "%s: Capability not supported", -+ __func__); -+ } -+ } -+ -+ return ret; -+} -+ -+/* LB_MEMORY_CONFIG -+ * 00 - Use all three pieces of memory -+ * 01 - Use only one piece of memory of total 720x144 bits -+ * 10 - Use two pieces of memory of total 960x144 bits -+ * 11 - reserved -+ * -+ * LB_MEMORY_SIZE -+ * Total entries of LB memory. -+ * This number should be larger than 960. The default value is 1712(0x6B0) */ -+bool dce80_transform_power_up_line_buffer(struct transform *xfm) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ uint32_t value; -+ -+ value = dm_read_reg(xfm80->base.ctx, LB_REG(mmLB_MEMORY_CTRL)); -+ -+ /*Use all three pieces of memory always*/ -+ set_reg_field_value(value, 0, LB_MEMORY_CTRL, LB_MEMORY_CONFIG); -+ /*hard coded number DCE8 1712(0x6B0) Partitions: 720/960/1712*/ -+ set_reg_field_value(value, LB_TOTAL_NUMBER_OF_ENTRIES, LB_MEMORY_CTRL, -+ LB_MEMORY_SIZE); -+ -+ dm_write_reg(xfm80->base.ctx, LB_REG(mmLB_MEMORY_CTRL), value); -+ -+ return true; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.h b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.h -new file mode 100644 -index 0000000..af831f8 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_bit_depth.h -@@ -0,0 +1,51 @@ -+/* 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_TRANSFORM_BIT_DEPTH_DCE80_H__ -+#define __DC_TRANSFORM_BIT_DEPTH_DCE80_H__ -+ -+#include "dce80_transform.h" -+ -+bool dce80_transform_power_up_line_buffer(struct transform *xfm); -+ -+bool dce80_transform_get_max_num_of_supported_lines( -+ struct dce80_transform *xfm80, -+ enum lb_pixel_depth depth, -+ uint32_t pixel_width, -+ uint32_t *lines); -+ -+void dce80_transform_enable_alpha( -+ struct dce80_transform *xfm80, -+ bool enable); -+ -+bool dce80_transform_get_next_lower_pixel_storage_depth( -+ struct dce80_transform *xfm80, -+ uint32_t display_bpp, -+ enum lb_pixel_depth depth, -+ enum lb_pixel_depth *lower_depth); -+ -+bool dce80_transform_is_prefetch_enabled( -+ struct dce80_transform *xfm80); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_gamut.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_gamut.c -new file mode 100644 -index 0000000..df5db67 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_gamut.c -@@ -0,0 +1,297 @@ -+/* 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 "dce80_transform.h" -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+#include "include/fixed31_32.h" -+#include "basics/conversion.h" -+#include "include/grph_object_id.h" -+ -+enum { -+ GAMUT_MATRIX_SIZE = 12 -+}; -+ -+#define DCP_REG(reg)\ -+ (reg + xfm80->offsets.dcp_offset) -+ -+#define DISP_BRIGHTNESS_DEFAULT_HW 0 -+#define DISP_BRIGHTNESS_MIN_HW -25 -+#define DISP_BRIGHTNESS_MAX_HW 25 -+#define DISP_BRIGHTNESS_STEP_HW 1 -+#define DISP_BRIGHTNESS_HW_DIVIDER 100 -+ -+#define DISP_HUE_DEFAULT_HW 0 -+#define DISP_HUE_MIN_HW -30 -+#define DISP_HUE_MAX_HW 30 -+#define DISP_HUE_STEP_HW 1 -+#define DISP_HUE_HW_DIVIDER 1 -+ -+#define DISP_CONTRAST_DEFAULT_HW 100 -+#define DISP_CONTRAST_MIN_HW 50 -+#define DISP_CONTRAST_MAX_HW 150 -+#define DISP_CONTRAST_STEP_HW 1 -+#define DISP_CONTRAST_HW_DIVIDER 100 -+ -+#define DISP_SATURATION_DEFAULT_HW 100 -+#define DISP_SATURATION_MIN_HW 0 -+#define DISP_SATURATION_MAX_HW 200 -+#define DISP_SATURATION_STEP_HW 1 -+#define DISP_SATURATION_HW_DIVIDER 100 -+ -+#define DISP_KELVIN_DEGRES_DEFAULT 6500 -+#define DISP_KELVIN_DEGRES_MIN 4000 -+#define DISP_KELVIN_DEGRES_MAX 10000 -+#define DISP_KELVIN_DEGRES_STEP 100 -+#define DISP_KELVIN_HW_DIVIDER 10000 -+ -+static void program_gamut_remap( -+ struct dce80_transform *xfm80, -+ const uint16_t *reg_val) -+{ -+ struct dc_context *ctx = xfm80->base.ctx; -+ uint32_t value = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_CONTROL); -+ -+ /* the register controls ovl also */ -+ value = dm_read_reg(ctx, addr); -+ -+ if (reg_val) { -+ { -+ uint32_t reg_data = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C11_C12); -+ -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[0], -+ GAMUT_REMAP_C11_C12, -+ GAMUT_REMAP_C11); -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[1], -+ GAMUT_REMAP_C11_C12, -+ GAMUT_REMAP_C12); -+ -+ dm_write_reg(ctx, addr, reg_data); -+ } -+ { -+ uint32_t reg_data = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C13_C14); -+ -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[2], -+ GAMUT_REMAP_C13_C14, -+ GAMUT_REMAP_C13); -+ -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[3], -+ GAMUT_REMAP_C13_C14, -+ GAMUT_REMAP_C14); -+ -+ dm_write_reg(ctx, addr, reg_data); -+ } -+ { -+ uint32_t reg_data = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C21_C22); -+ -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[4], -+ GAMUT_REMAP_C21_C22, -+ GAMUT_REMAP_C21); -+ -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[5], -+ GAMUT_REMAP_C21_C22, -+ GAMUT_REMAP_C22); -+ -+ dm_write_reg(ctx, addr, reg_data); -+ } -+ { -+ uint32_t reg_data = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C23_C24); -+ -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[6], -+ GAMUT_REMAP_C23_C24, -+ GAMUT_REMAP_C23); -+ -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[7], -+ GAMUT_REMAP_C23_C24, -+ GAMUT_REMAP_C24); -+ -+ dm_write_reg(ctx, addr, reg_data); -+ } -+ { -+ uint32_t reg_data = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C31_C32); -+ -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[8], -+ GAMUT_REMAP_C31_C32, -+ GAMUT_REMAP_C31); -+ -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[9], -+ GAMUT_REMAP_C31_C32, -+ GAMUT_REMAP_C32); -+ -+ dm_write_reg(ctx, addr, reg_data); -+ } -+ { -+ uint32_t reg_data = 0; -+ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C33_C34); -+ -+ /* fixed S2.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[10], -+ GAMUT_REMAP_C33_C34, -+ GAMUT_REMAP_C33); -+ -+ /* fixed S0.13 format */ -+ set_reg_field_value( -+ reg_data, -+ reg_val[11], -+ GAMUT_REMAP_C33_C34, -+ GAMUT_REMAP_C34); -+ -+ dm_write_reg(ctx, addr, reg_data); -+ } -+ -+ set_reg_field_value( -+ value, -+ 1, -+ GAMUT_REMAP_CONTROL, -+ GRPH_GAMUT_REMAP_MODE); -+ -+ } else -+ set_reg_field_value( -+ value, -+ 0, -+ GAMUT_REMAP_CONTROL, -+ GRPH_GAMUT_REMAP_MODE); -+ -+ addr = DCP_REG(mmGAMUT_REMAP_CONTROL); -+ dm_write_reg(ctx, addr, value); -+ -+} -+ -+/** -+ ***************************************************************************** -+ * Function: dal_transform_wide_gamut_set_gamut_remap -+ * -+ * @param [in] const struct grph_csc_adjustment *adjust -+ * -+ * @return -+ * void -+ * -+ * @note calculate and apply color temperature adjustment to in Rgb color space -+ * -+ * @see -+ * -+ ***************************************************************************** -+ */ -+void dce80_transform_set_gamut_remap( -+ struct transform *xfm, -+ const struct grph_csc_adjustment *adjust) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ -+ if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW || -+ adjust->temperature_divider == 0) -+ program_gamut_remap(xfm80, NULL); -+ else { -+ struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE]; -+ uint16_t arr_reg_val[GAMUT_MATRIX_SIZE]; -+ -+ arr_matrix[0] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[0], -+ adjust->temperature_divider); -+ arr_matrix[1] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[1], -+ adjust->temperature_divider); -+ arr_matrix[2] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[2], -+ adjust->temperature_divider); -+ arr_matrix[3] = dal_fixed31_32_zero; -+ -+ arr_matrix[4] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[3], -+ adjust->temperature_divider); -+ arr_matrix[5] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[4], -+ adjust->temperature_divider); -+ arr_matrix[6] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[5], -+ adjust->temperature_divider); -+ arr_matrix[7] = dal_fixed31_32_zero; -+ -+ arr_matrix[8] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[6], -+ adjust->temperature_divider); -+ arr_matrix[9] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[7], -+ adjust->temperature_divider); -+ arr_matrix[10] = -+ dal_fixed31_32_from_fraction( -+ adjust->temperature_matrix[8], -+ adjust->temperature_divider); -+ arr_matrix[11] = dal_fixed31_32_zero; -+ -+ convert_float_matrix( -+ arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE); -+ -+ program_gamut_remap(xfm80, arr_reg_val); -+ } -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_scl.c b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_scl.c -new file mode 100644 -index 0000000..62a3a04 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/dce80/dce80_transform_scl.c -@@ -0,0 +1,814 @@ -+/* -+ * 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 DCE8 register header files */ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "dce80_transform.h" -+ -+#define UP_SCALER_RATIO_MAX 16000 -+#define DOWN_SCALER_RATIO_MAX 250 -+#define SCALER_RATIO_DIVIDER 1000 -+ -+#define SCL_REG(reg)\ -+ (reg + xfm80->offsets.scl_offset) -+ -+#define DCFE_REG(reg)\ -+ (reg + xfm80->offsets.crtc_offset) -+ -+static void disable_enhanced_sharpness(struct dce80_transform *xfm80) -+{ -+ uint32_t value; -+ -+ value = dm_read_reg(xfm80->base.ctx, -+ SCL_REG(mmSCL_F_SHARP_CONTROL)); -+ -+ set_reg_field_value(value, 0, -+ SCL_F_SHARP_CONTROL, SCL_HF_SHARP_EN); -+ -+ set_reg_field_value(value, 0, -+ SCL_F_SHARP_CONTROL, SCL_VF_SHARP_EN); -+ -+ set_reg_field_value(value, 0, -+ SCL_F_SHARP_CONTROL, SCL_HF_SHARP_SCALE_FACTOR); -+ -+ set_reg_field_value(value, 0, -+ SCL_F_SHARP_CONTROL, SCL_VF_SHARP_SCALE_FACTOR); -+ -+ dm_write_reg(xfm80->base.ctx, -+ SCL_REG(mmSCL_F_SHARP_CONTROL), value); -+} -+ -+/** -+* Function: -+* void setup_scaling_configuration -+* -+* Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps -+* Input: data -+* -+* Output: -+ void -+*/ -+static bool setup_scaling_configuration( -+ struct dce80_transform *xfm80, -+ const struct scaler_data *data) -+{ -+ struct dc_context *ctx = xfm80->base.ctx; -+ uint32_t addr; -+ uint32_t value; -+ -+ if (data->taps.h_taps + data->taps.v_taps <= 2) { -+ dce80_transform_set_scaler_bypass(&xfm80->base); -+ return false; -+ } -+ -+ { -+ addr = SCL_REG(mmSCL_MODE); -+ value = dm_read_reg(ctx, addr); -+ -+ if (data->dal_pixel_format <= PIXEL_FORMAT_GRPH_END) -+ set_reg_field_value(value, 1, SCL_MODE, SCL_MODE); -+ else -+ set_reg_field_value(value, 2, SCL_MODE, SCL_MODE); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ addr = SCL_REG(mmSCL_TAP_CONTROL); -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value(value, data->taps.h_taps - 1, -+ SCL_TAP_CONTROL, SCL_H_NUM_OF_TAPS); -+ -+ set_reg_field_value(value, data->taps.v_taps - 1, -+ SCL_TAP_CONTROL, SCL_V_NUM_OF_TAPS); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ { -+ addr = SCL_REG(mmSCL_CONTROL); -+ value = dm_read_reg(ctx, addr); -+ /* 1 - Replaced out of bound pixels with edge */ -+ set_reg_field_value(value, 1, SCL_CONTROL, SCL_BOUNDARY_MODE); -+ -+ /* 1 - Replaced out of bound pixels with the edge pixel. */ -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ return true; -+} -+ -+/** -+* Function: -+* void program_overscan -+* -+* Purpose: Programs overscan border -+* Input: overscan -+* -+* Output: -+ void -+*/ -+static void program_overscan( -+ struct dce80_transform *xfm80, -+ const struct overscan_info *overscan) -+{ -+ uint32_t overscan_left_right = 0; -+ uint32_t overscan_top_bottom = 0; -+ -+ set_reg_field_value(overscan_left_right, overscan->left, -+ EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT); -+ -+ set_reg_field_value(overscan_left_right, overscan->right, -+ EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT); -+ -+ set_reg_field_value(overscan_top_bottom, overscan->top, -+ EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP); -+ -+ set_reg_field_value(overscan_top_bottom, overscan->bottom, -+ EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM); -+ -+ dm_write_reg(xfm80->base.ctx, -+ SCL_REG(mmEXT_OVERSCAN_LEFT_RIGHT), -+ overscan_left_right); -+ -+ dm_write_reg(xfm80->base.ctx, -+ SCL_REG(mmEXT_OVERSCAN_TOP_BOTTOM), -+ overscan_top_bottom); -+} -+ -+static void program_two_taps_filter( -+ struct dce80_transform *xfm80, -+ bool enable, -+ bool vertical) -+{ -+ uint32_t addr; -+ uint32_t value; -+ /* 1: Hard coded 2 tap filter -+ * 0: Programmable 2 tap filter from coefficient RAM -+ */ -+ if (vertical) { -+ addr = SCL_REG(mmSCL_VERT_FILTER_CONTROL); -+ value = dm_read_reg(xfm80->base.ctx, addr); -+ set_reg_field_value( -+ value, -+ enable ? 1 : 0, -+ SCL_VERT_FILTER_CONTROL, -+ SCL_V_2TAP_HARDCODE_COEF_EN); -+ -+ } else { -+ addr = SCL_REG(mmSCL_HORZ_FILTER_CONTROL); -+ value = dm_read_reg(xfm80->base.ctx, addr); -+ set_reg_field_value( -+ value, -+ enable ? 1 : 0, -+ SCL_HORZ_FILTER_CONTROL, -+ SCL_H_2TAP_HARDCODE_COEF_EN); -+ } -+ -+ dm_write_reg(xfm80->base.ctx, addr, value); -+} -+ -+static void set_coeff_update_complete(struct dce80_transform *xfm80) -+{ -+ uint32_t value; -+ uint32_t addr = SCL_REG(mmSCL_UPDATE); -+ -+ value = dm_read_reg(xfm80->base.ctx, addr); -+ set_reg_field_value(value, 1, -+ SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+} -+ -+static void program_filter( -+ struct dce80_transform *xfm80, -+ enum ram_filter_type filter_type, -+ struct scaler_filter_params *scl_filter_params, -+ uint32_t *coeffs, -+ uint32_t coeffs_num) -+{ -+ uint32_t phase = 0; -+ uint32_t array_idx = 0; -+ uint32_t pair = 0; -+ -+ uint32_t taps_pairs = (scl_filter_params->taps + 1) / 2; -+ uint32_t phases_to_program = scl_filter_params->phases / 2 + 1; -+ -+ uint32_t i; -+ uint32_t addr; -+ uint32_t select_addr; -+ uint32_t select; -+ uint32_t data; -+ /* We need to disable power gating on coeff memory to do programming */ -+ -+ uint32_t pwr_ctrl_orig; -+ uint32_t pwr_ctrl_off; -+ -+ addr = DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL); -+ pwr_ctrl_orig = dm_read_reg(xfm80->base.ctx, addr); -+ pwr_ctrl_off = pwr_ctrl_orig; -+ set_reg_field_value( -+ pwr_ctrl_off, -+ 1, -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ SCL_LIGHT_SLEEP_DIS); -+ dm_write_reg(xfm80->base.ctx, addr, pwr_ctrl_off); -+ -+ /* Wait to disable gating: */ -+ for (i = 0; -+ i < 10 && -+ get_reg_field_value( -+ dm_read_reg(xfm80->base.ctx, addr), -+ DCFE_MEM_LIGHT_SLEEP_CNTL, -+ SCL_MEM_PWR_STATE); -+ i++) -+ dm_delay_in_microseconds(xfm80->base.ctx, 1); -+ -+ ASSERT(i < 10); -+ -+ select_addr = SCL_REG(mmSCL_COEF_RAM_SELECT); -+ select = dm_read_reg(xfm80->base.ctx, select_addr); -+ -+ set_reg_field_value( -+ select, -+ filter_type, -+ SCL_COEF_RAM_SELECT, -+ SCL_C_RAM_FILTER_TYPE); -+ set_reg_field_value( -+ select, -+ 0, -+ SCL_COEF_RAM_SELECT, -+ SCL_C_RAM_TAP_PAIR_IDX); -+ set_reg_field_value( -+ select, -+ 0, -+ SCL_COEF_RAM_SELECT, -+ SCL_C_RAM_PHASE); -+ -+ data = 0; -+ -+ for (phase = 0; phase < phases_to_program; phase++) { -+ /* we always program N/2 + 1 phases, total phases N, but N/2-1 -+ * are just mirror phase 0 is unique and phase N/2 is unique -+ * if N is even -+ */ -+ -+ set_reg_field_value( -+ select, -+ phase, -+ SCL_COEF_RAM_SELECT, -+ SCL_C_RAM_PHASE); -+ -+ for (pair = 0; pair < taps_pairs; pair++) { -+ set_reg_field_value( -+ select, -+ pair, -+ SCL_COEF_RAM_SELECT, -+ SCL_C_RAM_TAP_PAIR_IDX); -+ dm_write_reg(xfm80->base.ctx, select_addr, select); -+ -+ /* even tap write enable */ -+ set_reg_field_value( -+ data, -+ 1, -+ SCL_COEF_RAM_TAP_DATA, -+ SCL_C_RAM_EVEN_TAP_COEF_EN); -+ /* even tap data */ -+ set_reg_field_value( -+ data, -+ coeffs[array_idx], -+ SCL_COEF_RAM_TAP_DATA, -+ SCL_C_RAM_EVEN_TAP_COEF); -+ -+ /* if we have odd number of taps and the last pair is -+ * here then we do not need to program -+ */ -+ if (scl_filter_params->taps % 2 && -+ pair == taps_pairs - 1) { -+ /* odd tap write disable */ -+ set_reg_field_value( -+ data, -+ 0, -+ SCL_COEF_RAM_TAP_DATA, -+ SCL_C_RAM_ODD_TAP_COEF_EN); -+ set_reg_field_value( -+ data, -+ 0, -+ SCL_COEF_RAM_TAP_DATA, -+ SCL_C_RAM_ODD_TAP_COEF); -+ array_idx += 1; -+ } else { -+ /* odd tap write enable */ -+ set_reg_field_value( -+ data, -+ 1, -+ SCL_COEF_RAM_TAP_DATA, -+ SCL_C_RAM_ODD_TAP_COEF_EN); -+ /* dbg_val: 0x1000 / sclFilterParams->taps; */ -+ set_reg_field_value( -+ data, -+ coeffs[array_idx + 1], -+ SCL_COEF_RAM_TAP_DATA, -+ SCL_C_RAM_ODD_TAP_COEF); -+ -+ array_idx += 2; -+ } -+ -+ dm_write_reg( -+ xfm80->base.ctx, -+ SCL_REG(mmSCL_COEF_RAM_TAP_DATA), -+ data); -+ } -+ } -+ -+ ASSERT(coeffs_num == array_idx); -+ -+ /* reset the power gating register */ -+ dm_write_reg( -+ xfm80->base.ctx, -+ DCFE_REG(mmDCFE_MEM_LIGHT_SLEEP_CNTL), -+ pwr_ctrl_orig); -+ -+ set_coeff_update_complete(xfm80); -+} -+ -+/* -+ * -+ * Populates an array with filter coefficients in 1.1.12 fixed point form -+*/ -+static bool get_filter_coefficients( -+ struct dce80_transform *xfm80, -+ uint32_t taps, -+ uint32_t **data_tab, -+ uint32_t *data_size) -+{ -+ uint32_t num = 0; -+ uint32_t i; -+ const struct fixed31_32 *filter = -+ dal_scaler_filter_get( -+ xfm80->base.filter, -+ data_tab, -+ &num); -+ uint32_t *data_row; -+ -+ if (!filter) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ data_row = *data_tab; -+ -+ for (i = 0; i < num; ++i) { -+ /* req. format sign fixed 1.1.12, the values are always between -+ * [-1; 1] -+ * -+ * Each phase is mirrored as follows : -+ * 0 : Phase 0 -+ * 1 : Phase 1 or Phase 64 - 1 / 128 - 1 -+ * N : Phase N or Phase 64 - N / 128 - N -+ * -+ * Convert from Fixed31_32 to 1.1.12 by using floor on value -+ * shifted by number of required fractional bits(12) -+ */ -+ struct fixed31_32 value = filter[i]; -+ -+ data_row[i] = -+ dal_fixed31_32_floor(dal_fixed31_32_shl(value, 12)) & -+ 0x3FFC; -+ } -+ *data_size = num; -+ -+ return true; -+} -+ -+static bool program_multi_taps_filter( -+ struct dce80_transform *xfm80, -+ const struct scaler_data *data, -+ bool horizontal) -+{ -+ struct scaler_filter_params filter_params; -+ enum ram_filter_type filter_type; -+ uint32_t src_size; -+ uint32_t dst_size; -+ -+ uint32_t *filter_data = NULL; -+ uint32_t filter_data_size = 0; -+ -+ /* 16 phases total for DCE8 */ -+ filter_params.phases = 16; -+ -+ if (horizontal) { -+ filter_params.taps = data->taps.h_taps; -+ filter_params.sharpness = data->h_sharpness; -+ filter_params.flags.bits.HORIZONTAL = 1; -+ -+ src_size = data->viewport.width; -+ dst_size = -+ dal_fixed31_32_floor( -+ dal_fixed31_32_div( -+ dal_fixed31_32_from_int( -+ data->viewport.width), -+ data->ratios->horz)); -+ -+ filter_type = FILTER_TYPE_RGB_Y_HORIZONTAL; -+ } else { -+ filter_params.taps = data->taps.v_taps; -+ filter_params.sharpness = data->v_sharpness; -+ filter_params.flags.bits.HORIZONTAL = 0; -+ -+ src_size = data->viewport.height; -+ dst_size = -+ dal_fixed31_32_floor( -+ dal_fixed31_32_div( -+ dal_fixed31_32_from_int( -+ data->viewport.height), -+ data->ratios->vert)); -+ -+ filter_type = FILTER_TYPE_RGB_Y_VERTICAL; -+ } -+ -+ /* 1. Generate the coefficients */ -+ if (!dal_scaler_filter_generate( -+ xfm80->base.filter, -+ &filter_params, -+ src_size, -+ dst_size)) -+ return false; -+ -+ /* 2. Convert coefficients to fixed point format 1.12 (note coeff. -+ * could be negative(!) and range is [ from -1 to 1 ]) */ -+ if (!get_filter_coefficients( -+ xfm80, -+ filter_params.taps, -+ &filter_data, -+ &filter_data_size)) -+ return false; -+ -+ /* 3. Program the filter */ -+ program_filter( -+ xfm80, -+ filter_type, -+ &filter_params, -+ filter_data, -+ filter_data_size); -+ -+ /* 4. Program the alpha if necessary */ -+ if (data->flags.bits.SHOULD_PROGRAM_ALPHA) { -+ if (horizontal) -+ filter_type = FILTER_TYPE_ALPHA_HORIZONTAL; -+ else -+ filter_type = FILTER_TYPE_ALPHA_VERTICAL; -+ -+ program_filter( -+ xfm80, -+ filter_type, -+ &filter_params, -+ filter_data, -+ filter_data_size); -+ } -+ -+ return true; -+} -+ -+static void program_viewport( -+ struct dce80_transform *xfm80, -+ const struct rect *view_port) -+{ -+ struct dc_context *ctx = xfm80->base.ctx; -+ uint32_t value = 0; -+ uint32_t addr = 0; -+ -+ addr = SCL_REG(mmVIEWPORT_START); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ value, -+ view_port->x, -+ VIEWPORT_START, -+ VIEWPORT_X_START); -+ set_reg_field_value( -+ value, -+ view_port->y, -+ VIEWPORT_START, -+ VIEWPORT_Y_START); -+ dm_write_reg(ctx, addr, value); -+ -+ addr = SCL_REG(mmVIEWPORT_SIZE); -+ value = dm_read_reg(ctx, addr); -+ set_reg_field_value( -+ value, -+ view_port->height, -+ VIEWPORT_SIZE, -+ VIEWPORT_HEIGHT); -+ set_reg_field_value( -+ value, -+ view_port->width, -+ VIEWPORT_SIZE, -+ VIEWPORT_WIDTH); -+ dm_write_reg(ctx, addr, value); -+ -+ /* TODO: add stereo support */ -+} -+ -+static void calculate_inits( -+ struct dce80_transform *xfm80, -+ const struct scaler_data *data, -+ struct scl_ratios_inits *inits) -+{ -+ struct fixed31_32 h_init; -+ struct fixed31_32 v_init; -+ struct fixed31_32 v_init_bot; -+ -+ inits->bottom_enable = 0; -+ inits->h_int_scale_ratio = -+ dal_fixed31_32_u2d19(data->ratios->horz) << 5; -+ inits->v_int_scale_ratio = -+ dal_fixed31_32_u2d19(data->ratios->vert) << 5; -+ -+ h_init = -+ dal_fixed31_32_div_int( -+ dal_fixed31_32_add( -+ data->ratios->horz, -+ dal_fixed31_32_from_int(data->taps.h_taps + 1)), -+ 2); -+ inits->h_init.integer = dal_fixed31_32_floor(h_init); -+ inits->h_init.fraction = dal_fixed31_32_u0d19(h_init) << 5; -+ -+ v_init = -+ dal_fixed31_32_div_int( -+ dal_fixed31_32_add( -+ data->ratios->vert, -+ dal_fixed31_32_from_int(data->taps.v_taps + 1)), -+ 2); -+ inits->v_init.integer = dal_fixed31_32_floor(v_init); -+ inits->v_init.fraction = dal_fixed31_32_u0d19(v_init) << 5; -+ -+ if (data->flags.bits.INTERLACED) { -+ v_init_bot = -+ dal_fixed31_32_add( -+ dal_fixed31_32_div_int( -+ dal_fixed31_32_add( -+ data->ratios->vert, -+ dal_fixed31_32_from_int( -+ data->taps.v_taps + 1)), -+ 2), -+ data->ratios->vert); -+ inits->v_init_bottom.integer = dal_fixed31_32_floor(v_init_bot); -+ inits->v_init_bottom.fraction = -+ dal_fixed31_32_u0d19(v_init_bot) << 5; -+ -+ inits->bottom_enable = 1; -+ } -+} -+ -+static void program_scl_ratios_inits( -+ struct dce80_transform *xfm80, -+ struct scl_ratios_inits *inits) -+{ -+ uint32_t addr = SCL_REG(mmSCL_HORZ_FILTER_SCALE_RATIO); -+ uint32_t value = 0; -+ -+ set_reg_field_value( -+ value, -+ inits->h_int_scale_ratio, -+ SCL_HORZ_FILTER_SCALE_RATIO, -+ SCL_H_SCALE_RATIO); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+ -+ addr = SCL_REG(mmSCL_VERT_FILTER_SCALE_RATIO); -+ value = 0; -+ set_reg_field_value( -+ value, -+ inits->v_int_scale_ratio, -+ SCL_VERT_FILTER_SCALE_RATIO, -+ SCL_V_SCALE_RATIO); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+ -+ addr = SCL_REG(mmSCL_HORZ_FILTER_INIT); -+ value = 0; -+ set_reg_field_value( -+ value, -+ inits->h_init.integer, -+ SCL_HORZ_FILTER_INIT, -+ SCL_H_INIT_INT); -+ set_reg_field_value( -+ value, -+ inits->h_init.fraction, -+ SCL_HORZ_FILTER_INIT, -+ SCL_H_INIT_FRAC); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+ -+ addr = SCL_REG(mmSCL_VERT_FILTER_INIT); -+ value = 0; -+ set_reg_field_value( -+ value, -+ inits->v_init.integer, -+ SCL_VERT_FILTER_INIT, -+ SCL_V_INIT_INT); -+ set_reg_field_value( -+ value, -+ inits->v_init.fraction, -+ SCL_VERT_FILTER_INIT, -+ SCL_V_INIT_FRAC); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+ -+ if (inits->bottom_enable) { -+ addr = SCL_REG(mmSCL_VERT_FILTER_INIT_BOT); -+ value = 0; -+ set_reg_field_value( -+ value, -+ inits->v_init_bottom.integer, -+ SCL_VERT_FILTER_INIT_BOT, -+ SCL_V_INIT_INT_BOT); -+ set_reg_field_value( -+ value, -+ inits->v_init_bottom.fraction, -+ SCL_VERT_FILTER_INIT_BOT, -+ SCL_V_INIT_FRAC_BOT); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+ } -+ -+ addr = SCL_REG(mmSCL_AUTOMATIC_MODE_CONTROL); -+ value = 0; -+ set_reg_field_value( -+ value, -+ 0, -+ SCL_AUTOMATIC_MODE_CONTROL, -+ SCL_V_CALC_AUTO_RATIO_EN); -+ set_reg_field_value( -+ value, -+ 0, -+ SCL_AUTOMATIC_MODE_CONTROL, -+ SCL_H_CALC_AUTO_RATIO_EN); -+ dm_write_reg(xfm80->base.ctx, addr, value); -+} -+ -+static void get_viewport( -+ struct dce80_transform *xfm80, -+ struct rect *current_view_port) -+{ -+ uint32_t value_start; -+ uint32_t value_size; -+ -+ if (current_view_port == NULL) -+ return; -+ -+ value_start = dm_read_reg(xfm80->base.ctx, SCL_REG(mmVIEWPORT_START)); -+ value_size = dm_read_reg(xfm80->base.ctx, SCL_REG(mmVIEWPORT_SIZE)); -+ -+ current_view_port->x = get_reg_field_value( -+ value_start, -+ VIEWPORT_START, -+ VIEWPORT_X_START); -+ current_view_port->y = get_reg_field_value( -+ value_start, -+ VIEWPORT_START, -+ VIEWPORT_Y_START); -+ current_view_port->height = get_reg_field_value( -+ value_size, -+ VIEWPORT_SIZE, -+ VIEWPORT_HEIGHT); -+ current_view_port->width = get_reg_field_value( -+ value_size, -+ VIEWPORT_SIZE, -+ VIEWPORT_WIDTH); -+} -+ -+ -+bool dce80_transform_set_scaler( -+ struct transform *xfm, -+ const struct scaler_data *data) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ bool is_scaling_required; -+ struct dc_context *ctx = xfm->ctx; -+ -+ { -+ uint32_t addr = SCL_REG(mmSCL_BYPASS_CONTROL); -+ uint32_t value = dm_read_reg(xfm->ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ SCL_BYPASS_CONTROL, -+ SCL_BYPASS_MODE); -+ dm_write_reg(xfm->ctx, addr, value); -+ } -+ -+ disable_enhanced_sharpness(xfm80); -+ -+ /* 3. Program overscan */ -+ program_overscan(xfm80, &data->overscan); -+ -+ /* 4. Program taps and configuration */ -+ is_scaling_required = setup_scaling_configuration(xfm80, data); -+ if (is_scaling_required) { -+ /* 5. Calculate and program ratio, filter initialization */ -+ struct scl_ratios_inits inits = { 0 }; -+ -+ calculate_inits(xfm80, data, &inits); -+ -+ program_scl_ratios_inits(xfm80, &inits); -+ -+ /* 6. Program vertical filters */ -+ if (data->taps.v_taps > 2) { -+ program_two_taps_filter(xfm80, false, true); -+ -+ if (!program_multi_taps_filter(xfm80, data, false)) { -+ dal_logger_write(ctx->logger, -+ LOG_MAJOR_DCP, -+ LOG_MINOR_DCP_SCALER, -+ "Failed vertical taps programming\n"); -+ return false; -+ } -+ } else -+ program_two_taps_filter(xfm80, true, true); -+ -+ /* 7. Program horizontal filters */ -+ if (data->taps.h_taps > 2) { -+ program_two_taps_filter(xfm80, false, false); -+ -+ if (!program_multi_taps_filter(xfm80, data, true)) { -+ dal_logger_write(ctx->logger, -+ LOG_MAJOR_DCP, -+ LOG_MINOR_DCP_SCALER, -+ "Failed horizontal taps programming\n"); -+ return false; -+ } -+ } else -+ program_two_taps_filter(xfm80, true, false); -+ } -+ -+ return true; -+} -+ -+void dce80_transform_set_scaler_bypass(struct transform *xfm) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ uint32_t sclv_mode; -+ -+ disable_enhanced_sharpness(xfm80); -+ -+ sclv_mode = dm_read_reg(xfm->ctx, SCL_REG(mmSCL_MODE)); -+ set_reg_field_value(sclv_mode, 0, SCL_MODE, SCL_MODE); -+ dm_write_reg(xfm->ctx, SCL_REG(mmSCL_MODE), sclv_mode); -+} -+ -+bool dce80_transform_update_viewport( -+ struct transform *xfm, -+ const struct rect *view_port, -+ bool is_fbc_attached) -+{ -+ struct dce80_transform *xfm80 = TO_DCE80_TRANSFORM(xfm); -+ bool program_req = false; -+ struct rect current_view_port; -+ -+ if (view_port == NULL) -+ return program_req; -+ -+ get_viewport(xfm80, ¤t_view_port); -+ -+ if (current_view_port.x != view_port->x || -+ current_view_port.y != view_port->y || -+ current_view_port.height != view_port->height || -+ current_view_port.width != view_port->width) -+ program_req = true; -+ -+ if (program_req) { -+ /*underlay viewport is programmed with scaler -+ *program_viewport function pointer is not exposed*/ -+ program_viewport(xfm80, view_port); -+ } -+ -+ return program_req; -+} -+ -+void dce80_transform_set_scaler_filter( -+ struct transform *xfm, -+ struct scaler_filter *filter) -+{ -+ xfm->filter = filter; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/Makefile b/drivers/gpu/drm/amd/dal/dc/gpio/Makefile -index 2507bb5..a0d165c 100644 ---- a/drivers/gpu/drm/amd/dal/dc/gpio/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/Makefile -@@ -9,6 +9,18 @@ AMD_DAL_GPIO = $(addprefix $(AMDDALPATH)/dc/gpio/,$(GPIO)) - - AMD_DAL_FILES += $(AMD_DAL_GPIO) - -+############################################################################### -+# DCE 8x -+############################################################################### -+# all DCE8.x are derived from DCE8.0 -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+GPIO_DCE80 = hw_translate_dce80.o hw_factory_dce80.o \ -+ hw_ddc_dce80.o hw_hpd_dce80.o -+ -+AMD_DAL_GPIO_DCE80 = $(addprefix $(AMDDALPATH)/dc/gpio/dce80/,$(GPIO_DCE80)) -+ -+AMD_DAL_FILES += $(AMD_DAL_GPIO_DCE80) -+endif - - ############################################################################### - # DCE 11x -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.c -new file mode 100644 -index 0000000..850caeb ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.c -@@ -0,0 +1,893 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/gpio_types.h" -+#include "../hw_gpio_pin.h" -+#include "../hw_gpio.h" -+#include "../hw_ddc.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "hw_ddc_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+/* -+ * This unit -+ */ -+ -+#define FROM_HW_DDC(ptr) \ -+ container_of((ptr), struct hw_ddc_dce80, base) -+ -+#define FROM_HW_GPIO(ptr) \ -+ FROM_HW_DDC(container_of((ptr), struct hw_ddc, base)) -+ -+#define FROM_HW_GPIO_PIN(ptr) \ -+ FROM_HW_GPIO(container_of((ptr), struct hw_gpio, base)) -+ -+static void destruct( -+ struct hw_ddc_dce80 *pin) -+{ -+ dal_hw_ddc_destruct(&pin->base); -+} -+ -+static void destroy( -+ struct hw_gpio_pin **ptr) -+{ -+ struct hw_ddc_dce80 *pin = FROM_HW_GPIO_PIN(*ptr); -+ -+ destruct(pin); -+ -+ dm_free((*ptr)->ctx, pin); -+ -+ *ptr = NULL; -+} -+ -+static void setup_i2c_polling( -+ struct dc_context *ctx, -+ const uint32_t addr, -+ bool enable_detect, -+ bool detect_mode) -+{ -+ uint32_t value; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ enable_detect, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_ENABLE); -+ -+ set_reg_field_value( -+ value, -+ enable_detect, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_EDID_DETECT_ENABLE); -+ -+ if (enable_detect) -+ set_reg_field_value( -+ value, -+ detect_mode, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_EDID_DETECT_MODE); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+static enum gpio_result set_config( -+ struct hw_gpio_pin *ptr, -+ const struct gpio_config_data *config_data) -+{ -+ struct hw_ddc_dce80 *pin = FROM_HW_GPIO_PIN(ptr); -+ struct hw_gpio *hw_gpio = NULL; -+ uint32_t addr; -+ uint32_t regval; -+ uint32_t ddc_data_pd_en = 0; -+ uint32_t ddc_clk_pd_en = 0; -+ uint32_t aux_pad_mode = 0; -+ -+ hw_gpio = &pin->base.base; -+ -+ if (hw_gpio == NULL) { -+ ASSERT_CRITICAL(false); -+ return GPIO_RESULT_NULL_HANDLE; -+ } -+ -+ /* switch dual mode GPIO to I2C/AUX mode */ -+ -+ addr = hw_gpio->pin_reg.DC_GPIO_DATA_MASK.addr; -+ -+ regval = dm_read_reg(ptr->ctx, addr); -+ -+ ddc_data_pd_en = get_reg_field_value( -+ regval, -+ DC_GPIO_DDC1_MASK, -+ DC_GPIO_DDC1DATA_PD_EN); -+ -+ ddc_clk_pd_en = get_reg_field_value( -+ regval, -+ DC_GPIO_DDC1_MASK, -+ DC_GPIO_DDC1CLK_PD_EN); -+ -+ aux_pad_mode = get_reg_field_value( -+ regval, -+ DC_GPIO_DDC1_MASK, -+ AUX_PAD1_MODE); -+ -+ switch (config_data->config.ddc.type) { -+ case GPIO_DDC_CONFIG_TYPE_MODE_I2C: -+ /* On plug-in, there is a transient level on the pad -+ * which must be discharged through the internal pull-down. -+ * Enable internal pull-down, 2.5msec discharge time -+ * is required for detection of AUX mode */ -+ if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) { -+ if (!ddc_data_pd_en || !ddc_clk_pd_en) { -+ set_reg_field_value( -+ regval, -+ 1, -+ DC_GPIO_DDC1_MASK, -+ DC_GPIO_DDC1DATA_PD_EN); -+ -+ set_reg_field_value( -+ regval, -+ 1, -+ DC_GPIO_DDC1_MASK, -+ DC_GPIO_DDC1CLK_PD_EN); -+ -+ dm_write_reg(ptr->ctx, addr, regval); -+ -+ if (config_data->type == -+ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) -+ /* should not affect normal I2C R/W */ -+ /* [anaumov] in DAL2, there was -+ * dc_service_delay_in_microseconds(2500); */ -+ dm_sleep_in_milliseconds(ptr->ctx, 3); -+ } -+ } else { -+ uint32_t reg2 = regval; -+ uint32_t sda_pd_dis = 0; -+ uint32_t scl_pd_dis = 0; -+ -+ sda_pd_dis = get_reg_field_value( -+ reg2, -+ DC_GPIO_I2CPAD_MASK, -+ DC_GPIO_SDA_PD_DIS); -+ -+ scl_pd_dis = get_reg_field_value( -+ reg2, -+ DC_GPIO_I2CPAD_MASK, -+ DC_GPIO_SCL_PD_DIS); -+ -+ if (sda_pd_dis) { -+ sda_pd_dis = 0; -+ -+ dm_write_reg(ptr->ctx, addr, reg2); -+ -+ if (config_data->type == -+ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) -+ /* should not affect normal I2C R/W */ -+ /* [anaumov] in DAL2, there was -+ * dc_service_delay_in_microseconds(2500); */ -+ dm_sleep_in_milliseconds(ptr->ctx, 3); -+ } -+ -+ if (!scl_pd_dis) { -+ scl_pd_dis = 1; -+ -+ dm_write_reg(ptr->ctx, addr, reg2); -+ -+ if (config_data->type == -+ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) -+ /* should not affect normal I2C R/W */ -+ /* [anaumov] in DAL2, there was -+ * dc_service_delay_in_microseconds(2500); */ -+ dm_sleep_in_milliseconds(ptr->ctx, 3); -+ } -+ } -+ -+ if (aux_pad_mode) { -+ /* let pins to get de-asserted -+ * before setting pad to I2C mode */ -+ if (config_data->config.ddc.data_en_bit_present || -+ config_data->config.ddc.clock_en_bit_present) -+ /* [anaumov] in DAL2, there was -+ * dc_service_delay_in_microseconds(2000); */ -+ dm_sleep_in_milliseconds(ptr->ctx, 2); -+ -+ /* set the I2C pad mode */ -+ /* read the register again, -+ * some bits may have been changed */ -+ regval = dm_read_reg(ptr->ctx, addr); -+ -+ set_reg_field_value( -+ regval, -+ 0, -+ DC_GPIO_DDC1_MASK, -+ AUX_PAD1_MODE); -+ -+ dm_write_reg(ptr->ctx, addr, regval); -+ } -+ -+ return GPIO_RESULT_OK; -+ case GPIO_DDC_CONFIG_TYPE_MODE_AUX: -+ /* set the AUX pad mode */ -+ if (!aux_pad_mode) { -+ set_reg_field_value( -+ regval, -+ 1, -+ DC_GPIO_DDC1_MASK, -+ AUX_PAD1_MODE); -+ -+ dm_write_reg(ptr->ctx, addr, regval); -+ } -+ -+ return GPIO_RESULT_OK; -+ case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT: -+ if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) && -+ (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) { -+ setup_i2c_polling( -+ ptr->ctx, pin->addr.dc_i2c_ddc_setup, 1, 0); -+ return GPIO_RESULT_OK; -+ } -+ break; -+ case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT: -+ if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) && -+ (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) { -+ setup_i2c_polling( -+ ptr->ctx, pin->addr.dc_i2c_ddc_setup, 1, 1); -+ return GPIO_RESULT_OK; -+ } -+ break; -+ case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING: -+ if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) && -+ (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) { -+ setup_i2c_polling( -+ ptr->ctx, pin->addr.dc_i2c_ddc_setup, 0, 0); -+ return GPIO_RESULT_OK; -+ } -+ break; -+ } -+ -+ BREAK_TO_DEBUGGER(); -+ -+ return GPIO_RESULT_NON_SPECIFIC_ERROR; -+} -+ -+struct hw_ddc_dce80_init { -+ struct hw_gpio_pin_reg hw_gpio_data_reg; -+ struct hw_ddc_mask hw_ddc_mask; -+ struct hw_ddc_dce80_addr hw_ddc_dce80_addr; -+}; -+ -+static const struct hw_ddc_dce80_init -+ hw_ddc_dce80_init_data[GPIO_DDC_LINE_COUNT] = { -+ /* GPIO_DDC_LINE_DDC1 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC1_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC1_A, -+ DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC1_EN, -+ DC_GPIO_DDC1_EN__DC_GPIO_DDC1DATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC1_Y, -+ DC_GPIO_DDC1_Y__DC_GPIO_DDC1DATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_MASK_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_PD_EN_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_RECV_MASK, -+ DC_GPIO_DDC1_MASK__AUX_PAD1_MODE_MASK, -+ DC_GPIO_DDC1_MASK__AUX1_POL_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC1_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC2 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC2_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC2_A, -+ DC_GPIO_DDC2_A__DC_GPIO_DDC2DATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC2_EN, -+ DC_GPIO_DDC2_EN__DC_GPIO_DDC2DATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC2_Y, -+ DC_GPIO_DDC2_Y__DC_GPIO_DDC2DATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_MASK_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_PD_EN_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_RECV_MASK, -+ DC_GPIO_DDC2_MASK__AUX_PAD2_MODE_MASK, -+ DC_GPIO_DDC2_MASK__AUX2_POL_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC2_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC3 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC3_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC3_A, -+ DC_GPIO_DDC3_A__DC_GPIO_DDC3DATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC3_EN, -+ DC_GPIO_DDC3_EN__DC_GPIO_DDC3DATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC3_Y, -+ DC_GPIO_DDC3_Y__DC_GPIO_DDC3DATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_MASK_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_PD_EN_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_RECV_MASK, -+ DC_GPIO_DDC3_MASK__AUX_PAD3_MODE_MASK, -+ DC_GPIO_DDC3_MASK__AUX3_POL_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC3_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC4 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC4_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC4_A, -+ DC_GPIO_DDC4_A__DC_GPIO_DDC4DATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC4_EN, -+ DC_GPIO_DDC4_EN__DC_GPIO_DDC4DATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC4_Y, -+ DC_GPIO_DDC4_Y__DC_GPIO_DDC4DATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_MASK_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_PD_EN_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_RECV_MASK, -+ DC_GPIO_DDC4_MASK__AUX_PAD4_MODE_MASK, -+ DC_GPIO_DDC4_MASK__AUX4_POL_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC4_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC5 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC5_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC5_A, -+ DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC5_EN, -+ DC_GPIO_DDC5_EN__DC_GPIO_DDC5DATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC5_Y, -+ DC_GPIO_DDC5_Y__DC_GPIO_DDC5DATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_MASK_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_PD_EN_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_RECV_MASK, -+ DC_GPIO_DDC5_MASK__AUX_PAD5_MODE_MASK, -+ DC_GPIO_DDC5_MASK__AUX5_POL_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC5_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC6 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC6_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC6_A, -+ DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC6_EN, -+ DC_GPIO_DDC6_EN__DC_GPIO_DDC6DATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC6_Y, -+ DC_GPIO_DDC6_Y__DC_GPIO_DDC6DATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_MASK_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_PD_EN_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_RECV_MASK, -+ DC_GPIO_DDC6_MASK__AUX_PAD6_MODE_MASK, -+ DC_GPIO_DDC6_MASK__AUX6_POL_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC6_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC_VGA */ -+ { -+ { -+ { -+ mmDC_GPIO_DDCVGA_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDCVGA_A, -+ DC_GPIO_DDCVGA_A__DC_GPIO_DDCVGADATA_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDCVGA_EN, -+ DC_GPIO_DDCVGA_EN__DC_GPIO_DDCVGADATA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDCVGA_Y, -+ DC_GPIO_DDCVGA_Y__DC_GPIO_DDCVGADATA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_MASK_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_PD_EN_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_RECV_MASK, -+ DC_GPIO_DDCVGA_MASK__AUX_PADVGA_MODE_MASK, -+ DC_GPIO_DDCVGA_MASK__AUXVGA_POL_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDCVGA_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_I2CPAD */ -+ { -+ { -+ { -+ mmDC_GPIO_I2CPAD_MASK, -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_I2CPAD_A, -+ DC_GPIO_I2CPAD_A__DC_GPIO_SDA_A_MASK -+ }, -+ { -+ mmDC_GPIO_I2CPAD_EN, -+ DC_GPIO_I2CPAD_EN__DC_GPIO_SDA_EN_MASK -+ }, -+ { -+ mmDC_GPIO_I2CPAD_Y, -+ DC_GPIO_I2CPAD_Y__DC_GPIO_SDA_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_MASK_MASK, -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_PD_DIS_MASK, -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_RECV_MASK, -+ 0, -+ 0, -+ 0 -+ }, -+ { -+ 0 -+ } -+ } -+}; -+ -+static const struct hw_ddc_dce80_init -+ hw_ddc_dce80_init_clock[GPIO_DDC_LINE_COUNT] = { -+ /* GPIO_DDC_LINE_DDC1 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC1_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC1_A, -+ DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC1_EN, -+ DC_GPIO_DDC1_EN__DC_GPIO_DDC1CLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC1_Y, -+ DC_GPIO_DDC1_Y__DC_GPIO_DDC1CLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_MASK_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_PD_EN_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_RECV_MASK, -+ DC_GPIO_DDC1_MASK__AUX_PAD1_MODE_MASK, -+ DC_GPIO_DDC1_MASK__AUX1_POL_MASK, -+ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC1_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC2 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC2_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC2_A, -+ DC_GPIO_DDC2_A__DC_GPIO_DDC2CLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC2_EN, -+ DC_GPIO_DDC2_EN__DC_GPIO_DDC2CLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC2_Y, -+ DC_GPIO_DDC2_Y__DC_GPIO_DDC2CLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_MASK_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_PD_EN_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_RECV_MASK, -+ DC_GPIO_DDC2_MASK__AUX_PAD2_MODE_MASK, -+ DC_GPIO_DDC2_MASK__AUX2_POL_MASK, -+ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC2_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC3 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC3_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC3_A, -+ DC_GPIO_DDC3_A__DC_GPIO_DDC3CLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC3_EN, -+ DC_GPIO_DDC3_EN__DC_GPIO_DDC3CLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC3_Y, -+ DC_GPIO_DDC3_Y__DC_GPIO_DDC3CLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_MASK_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_PD_EN_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_RECV_MASK, -+ DC_GPIO_DDC3_MASK__AUX_PAD3_MODE_MASK, -+ DC_GPIO_DDC3_MASK__AUX3_POL_MASK, -+ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC3_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC4 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC4_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC4_A, -+ DC_GPIO_DDC4_A__DC_GPIO_DDC4CLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC4_EN, -+ DC_GPIO_DDC4_EN__DC_GPIO_DDC4CLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC4_Y, -+ DC_GPIO_DDC4_Y__DC_GPIO_DDC4CLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_MASK_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_PD_EN_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_RECV_MASK, -+ DC_GPIO_DDC4_MASK__AUX_PAD4_MODE_MASK, -+ DC_GPIO_DDC4_MASK__AUX4_POL_MASK, -+ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC4_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC5 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC5_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC5_A, -+ DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC5_EN, -+ DC_GPIO_DDC5_EN__DC_GPIO_DDC5CLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC5_Y, -+ DC_GPIO_DDC5_Y__DC_GPIO_DDC5CLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_MASK_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_PD_EN_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_RECV_MASK, -+ DC_GPIO_DDC5_MASK__AUX_PAD5_MODE_MASK, -+ DC_GPIO_DDC5_MASK__AUX5_POL_MASK, -+ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC5_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC6 */ -+ { -+ { -+ { -+ mmDC_GPIO_DDC6_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDC6_A, -+ DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDC6_EN, -+ DC_GPIO_DDC6_EN__DC_GPIO_DDC6CLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDC6_Y, -+ DC_GPIO_DDC6_Y__DC_GPIO_DDC6CLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_MASK_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_PD_EN_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_RECV_MASK, -+ DC_GPIO_DDC6_MASK__AUX_PAD6_MODE_MASK, -+ DC_GPIO_DDC6_MASK__AUX6_POL_MASK, -+ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDC6_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_DDC_VGA */ -+ { -+ { -+ { -+ mmDC_GPIO_DDCVGA_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_DDCVGA_A, -+ DC_GPIO_DDCVGA_A__DC_GPIO_DDCVGACLK_A_MASK -+ }, -+ { -+ mmDC_GPIO_DDCVGA_EN, -+ DC_GPIO_DDCVGA_EN__DC_GPIO_DDCVGACLK_EN_MASK -+ }, -+ { -+ mmDC_GPIO_DDCVGA_Y, -+ DC_GPIO_DDCVGA_Y__DC_GPIO_DDCVGACLK_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_MASK_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_PD_EN_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_RECV_MASK, -+ DC_GPIO_DDCVGA_MASK__AUX_PADVGA_MODE_MASK, -+ DC_GPIO_DDCVGA_MASK__AUXVGA_POL_MASK, -+ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_STR_MASK -+ }, -+ { -+ mmDC_I2C_DDCVGA_SETUP -+ } -+ }, -+ /* GPIO_DDC_LINE_I2CPAD */ -+ { -+ { -+ { -+ mmDC_GPIO_I2CPAD_MASK, -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_I2CPAD_A, -+ DC_GPIO_I2CPAD_A__DC_GPIO_SCL_A_MASK -+ }, -+ { -+ mmDC_GPIO_I2CPAD_EN, -+ DC_GPIO_I2CPAD_EN__DC_GPIO_SCL_EN_MASK -+ }, -+ { -+ mmDC_GPIO_I2CPAD_Y, -+ DC_GPIO_I2CPAD_Y__DC_GPIO_SCL_Y_MASK -+ } -+ }, -+ { -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_MASK_MASK, -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_PD_DIS_MASK, -+ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_RECV_MASK, -+ 0, -+ 0, -+ 0 -+ }, -+ { -+ 0 -+ } -+ } -+}; -+ -+static const struct hw_gpio_pin_funcs funcs = { -+ .destroy = destroy, -+ .open = dal_hw_ddc_open, -+ .get_value = dal_hw_gpio_get_value, -+ .set_value = dal_hw_gpio_set_value, -+ .set_config = set_config, -+ .change_mode = dal_hw_gpio_change_mode, -+ .close = dal_hw_gpio_close, -+}; -+ -+static bool construct( -+ struct hw_ddc_dce80 *pin, -+ enum gpio_id id, -+ uint32_t en, -+ struct dc_context *ctx) -+{ -+ const struct hw_ddc_dce80_init *init; -+ -+ if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ if (!dal_hw_ddc_construct(&pin->base, id, en, ctx)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ pin->base.base.base.funcs = &funcs; -+ -+ switch (id) { -+ case GPIO_ID_DDC_DATA: -+ init = hw_ddc_dce80_init_data + en; -+ -+ pin->base.base.pin_reg = init->hw_gpio_data_reg; -+ pin->base.mask = init->hw_ddc_mask; -+ pin->addr = init->hw_ddc_dce80_addr; -+ -+ return true; -+ case GPIO_ID_DDC_CLOCK: -+ init = hw_ddc_dce80_init_clock + en; -+ -+ pin->base.base.pin_reg = init->hw_gpio_data_reg; -+ pin->base.mask = init->hw_ddc_mask; -+ pin->addr = init->hw_ddc_dce80_addr; -+ -+ return true; -+ default: -+ BREAK_TO_DEBUGGER(); -+ } -+ -+ dal_hw_ddc_destruct(&pin->base); -+ -+ return false; -+} -+ -+struct hw_gpio_pin *dal_hw_ddc_dce80_create( -+ struct dc_context *ctx, -+ enum gpio_id id, -+ uint32_t en) -+{ -+ struct hw_ddc_dce80 *pin = dm_alloc(ctx, sizeof(struct hw_ddc_dce80)); -+ -+ if (!pin) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(pin, id, en, ctx)) -+ return &pin->base.base.base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(ctx, pin); -+ -+ return NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.h -new file mode 100644 -index 0000000..f5bbb83 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_ddc_dce80.h -@@ -0,0 +1,46 @@ -+/* -+ * 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_DDC_DCE80_H__ -+#define __DAL_HW_DDC_DCE80_H__ -+ -+struct hw_ddc_dce80_addr { -+ uint32_t dc_i2c_ddc_setup; -+}; -+ -+struct hw_ddc_dce80 { -+ struct hw_ddc base; -+ struct hw_ddc_dce80_addr addr; -+}; -+ -+struct hw_gpio_pin *dal_hw_ddc_dce80_create( -+ struct dc_context *ctx, -+ enum gpio_id id, -+ uint32_t en); -+ -+#define DDC_DCE80_FROM_BASE(ddc_base) \ -+ container_of(HW_DDC_FROM_BASE(ddc_base), struct hw_ddc_dce80, base) -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.c -new file mode 100644 -index 0000000..d1ea56d ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.c -@@ -0,0 +1,78 @@ -+/* -+ * 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 -+ * -+ */ -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+ -+#include "dm_services.h" -+#include "include/gpio_types.h" -+#include "../hw_factory.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "hw_factory_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "../hw_gpio_pin.h" -+#include "../hw_gpio.h" -+#include "../hw_gpio_pad.h" -+#include "../hw_ddc.h" -+#include "hw_ddc_dce80.h" -+#include "../hw_hpd.h" -+#include "hw_hpd_dce80.h" -+ -+/* -+ * This unit -+ */ -+static const struct hw_factory_funcs funcs = { -+ .create_ddc_data = dal_hw_ddc_dce80_create, -+ .create_ddc_clock = dal_hw_ddc_dce80_create, -+ .create_generic = NULL, -+ .create_hpd = dal_hw_hpd_dce80_create, -+ .create_gpio_pad = NULL, -+ .create_sync = NULL, -+ .create_gsl = NULL, -+}; -+ -+void dal_hw_factory_dce80_init( -+ struct hw_factory *factory) -+{ -+ factory->number_of_pins[GPIO_ID_DDC_DATA] = 8; -+ factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 8; -+ factory->number_of_pins[GPIO_ID_GENERIC] = 7; -+ factory->number_of_pins[GPIO_ID_HPD] = 6; -+ factory->number_of_pins[GPIO_ID_GPIO_PAD] = 31; -+ factory->number_of_pins[GPIO_ID_VIP_PAD] = 0; -+ factory->number_of_pins[GPIO_ID_SYNC] = 2; -+ factory->number_of_pins[GPIO_ID_GSL] = 4; -+ -+ factory->funcs = &funcs; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.h -new file mode 100644 -index 0000000..e78a8b3 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_factory_dce80.h -@@ -0,0 +1,32 @@ -+/* -+ * 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_FACTORY_DCE80_H__ -+#define __DAL_HW_FACTORY_DCE80_H__ -+ -+void dal_hw_factory_dce80_init( -+ struct hw_factory *factory); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.c -new file mode 100644 -index 0000000..67b249b ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.c -@@ -0,0 +1,378 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/gpio_types.h" -+#include "../hw_gpio_pin.h" -+#include "../hw_gpio.h" -+#include "../hw_hpd.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "hw_hpd_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+ -+/* -+ * This unit -+ */ -+ -+#define FROM_HW_HPD(ptr) \ -+ container_of((ptr), struct hw_hpd_dce80, base) -+ -+#define FROM_HW_GPIO(ptr) \ -+ FROM_HW_HPD(container_of((ptr), struct hw_hpd, base)) -+ -+#define FROM_HW_GPIO_PIN(ptr) \ -+ FROM_HW_GPIO(container_of((ptr), struct hw_gpio, base)) -+ -+static void destruct( -+ struct hw_hpd_dce80 *pin) -+{ -+ dal_hw_hpd_destruct(&pin->base); -+} -+ -+static void destroy( -+ struct hw_gpio_pin **ptr) -+{ -+ struct hw_hpd_dce80 *pin = FROM_HW_GPIO_PIN(*ptr); -+ -+ destruct(pin); -+ -+ dm_free((*ptr)->ctx, pin); -+ -+ *ptr = NULL; -+} -+ -+static enum gpio_result get_value( -+ const struct hw_gpio_pin *ptr, -+ uint32_t *value) -+{ -+ struct hw_hpd_dce80 *pin = FROM_HW_GPIO_PIN(ptr); -+ -+ /* in Interrupt mode we ask for SENSE bit */ -+ -+ if (ptr->mode == GPIO_MODE_INTERRUPT) { -+ uint32_t regval; -+ uint32_t hpd_delayed = 0; -+ uint32_t hpd_sense = 0; -+ -+ regval = dm_read_reg( -+ ptr->ctx, -+ pin->addr.DC_HPD_INT_STATUS); -+ -+ hpd_delayed = get_reg_field_value( -+ regval, -+ DC_HPD1_INT_STATUS, -+ DC_HPD1_SENSE_DELAYED); -+ -+ hpd_sense = get_reg_field_value( -+ regval, -+ DC_HPD1_INT_STATUS, -+ DC_HPD1_SENSE); -+ -+ *value = hpd_delayed; -+ return GPIO_RESULT_OK; -+ } -+ -+ /* in any other modes, operate as normal GPIO */ -+ -+ return dal_hw_gpio_get_value(ptr, value); -+} -+ -+static enum gpio_result set_config( -+ struct hw_gpio_pin *ptr, -+ const struct gpio_config_data *config_data) -+{ -+ struct hw_hpd_dce80 *pin = FROM_HW_GPIO_PIN(ptr); -+ -+ if (!config_data) -+ return GPIO_RESULT_INVALID_DATA; -+ -+ { -+ uint32_t value; -+ -+ value = dm_read_reg( -+ ptr->ctx, -+ pin->addr.DC_HPD_TOGGLE_FILT_CNTL); -+ -+ set_reg_field_value( -+ value, -+ config_data->config.hpd.delay_on_connect / 10, -+ DC_HPD1_TOGGLE_FILT_CNTL, -+ DC_HPD1_CONNECT_INT_DELAY); -+ -+ set_reg_field_value( -+ value, -+ config_data->config.hpd.delay_on_disconnect / 10, -+ DC_HPD1_TOGGLE_FILT_CNTL, -+ DC_HPD1_DISCONNECT_INT_DELAY); -+ -+ dm_write_reg( -+ ptr->ctx, -+ pin->addr.DC_HPD_TOGGLE_FILT_CNTL, -+ value); -+ -+ } -+ -+ return GPIO_RESULT_OK; -+} -+ -+struct hw_gpio_generic_dce80_init { -+ struct hw_gpio_pin_reg hw_gpio_data_reg; -+ struct hw_hpd_dce80_addr addr; -+}; -+ -+static const struct hw_gpio_generic_dce80_init -+ hw_gpio_generic_dce80_init[GPIO_HPD_COUNT] = { -+ /* GPIO_HPD_1 */ -+ { -+ { -+ { -+ mmDC_GPIO_HPD_MASK, -+ DC_GPIO_HPD_MASK__DC_GPIO_HPD1_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_A, -+ DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_EN, -+ DC_GPIO_HPD_EN__DC_GPIO_HPD1_EN_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_Y, -+ DC_GPIO_HPD_Y__DC_GPIO_HPD1_Y_MASK -+ } -+ }, -+ { -+ mmDC_HPD1_INT_STATUS, -+ mmDC_HPD1_TOGGLE_FILT_CNTL -+ } -+ }, -+ /* GPIO_HPD_2 */ -+ { -+ { -+ { -+ mmDC_GPIO_HPD_MASK, -+ DC_GPIO_HPD_MASK__DC_GPIO_HPD2_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_A, -+ DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_EN, -+ DC_GPIO_HPD_EN__DC_GPIO_HPD2_EN_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_Y, -+ DC_GPIO_HPD_Y__DC_GPIO_HPD2_Y_MASK -+ } -+ }, -+ { -+ mmDC_HPD2_INT_STATUS, -+ mmDC_HPD2_TOGGLE_FILT_CNTL -+ } -+ }, -+ /* GPIO_HPD_3 */ -+ { -+ { -+ { -+ mmDC_GPIO_HPD_MASK, -+ DC_GPIO_HPD_MASK__DC_GPIO_HPD3_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_A, -+ DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_EN, -+ DC_GPIO_HPD_EN__DC_GPIO_HPD3_EN_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_Y, -+ DC_GPIO_HPD_Y__DC_GPIO_HPD3_Y_MASK -+ } -+ }, -+ { -+ mmDC_HPD3_INT_STATUS, -+ mmDC_HPD3_TOGGLE_FILT_CNTL -+ } -+ }, -+ /* GPIO_HPD_4 */ -+ { -+ { -+ { -+ mmDC_GPIO_HPD_MASK, -+ DC_GPIO_HPD_MASK__DC_GPIO_HPD4_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_A, -+ DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_EN, -+ DC_GPIO_HPD_EN__DC_GPIO_HPD4_EN_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_Y, -+ DC_GPIO_HPD_Y__DC_GPIO_HPD4_Y_MASK -+ } -+ }, -+ { -+ mmDC_HPD4_INT_STATUS, -+ mmDC_HPD4_TOGGLE_FILT_CNTL -+ } -+ }, -+ /* GPIO_HPD_5 */ -+ { -+ { -+ { -+ mmDC_GPIO_HPD_MASK, -+ DC_GPIO_HPD_MASK__DC_GPIO_HPD5_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_A, -+ DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_EN, -+ DC_GPIO_HPD_EN__DC_GPIO_HPD5_EN_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_Y, -+ DC_GPIO_HPD_Y__DC_GPIO_HPD5_Y_MASK -+ } -+ }, -+ { -+ mmDC_HPD5_INT_STATUS, -+ mmDC_HPD5_TOGGLE_FILT_CNTL -+ } -+ }, -+ /* GPIO_HPD_1 */ -+ { -+ { -+ { -+ mmDC_GPIO_HPD_MASK, -+ DC_GPIO_HPD_MASK__DC_GPIO_HPD6_MASK_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_A, -+ DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_EN, -+ DC_GPIO_HPD_EN__DC_GPIO_HPD6_EN_MASK -+ }, -+ { -+ mmDC_GPIO_HPD_Y, -+ DC_GPIO_HPD_Y__DC_GPIO_HPD6_Y_MASK -+ } -+ }, -+ { -+ mmDC_HPD6_INT_STATUS, -+ mmDC_HPD6_TOGGLE_FILT_CNTL -+ } -+ } -+}; -+ -+static const struct hw_gpio_pin_funcs funcs = { -+ .destroy = destroy, -+ .open = dal_hw_gpio_open, -+ .get_value = get_value, -+ .set_value = dal_hw_gpio_set_value, -+ .set_config = set_config, -+ .change_mode = dal_hw_gpio_change_mode, -+ .close = dal_hw_gpio_close, -+}; -+ -+static bool construct( -+ struct hw_hpd_dce80 *pin, -+ enum gpio_id id, -+ uint32_t en, -+ struct dc_context *ctx) -+{ -+ const struct hw_gpio_generic_dce80_init *init; -+ -+ if (id != GPIO_ID_HPD) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ if ((en < GPIO_HPD_MIN) || (en > GPIO_HPD_MAX)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ if (!dal_hw_hpd_construct(&pin->base, id, en, ctx)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ pin->base.base.base.funcs = &funcs; -+ -+ init = hw_gpio_generic_dce80_init + en; -+ -+ pin->base.base.pin_reg = init->hw_gpio_data_reg; -+ -+ pin->addr = init->addr; -+ -+ return true; -+} -+ -+struct hw_gpio_pin *dal_hw_hpd_dce80_create( -+ struct dc_context *ctx, -+ enum gpio_id id, -+ uint32_t en) -+{ -+ struct hw_hpd_dce80 *pin = dm_alloc(ctx, sizeof(struct hw_hpd_dce80)); -+ -+ if (!pin) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(pin, id, en, ctx)) -+ return &pin->base.base.base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(ctx, pin); -+ -+ return NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.h -new file mode 100644 -index 0000000..d74dbec ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_hpd_dce80.h -@@ -0,0 +1,44 @@ -+/* -+ * 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_HPD_DCE80_H__ -+#define __DAL_HW_HPD_DCE80_H__ -+ -+struct hw_hpd_dce80_addr { -+ uint32_t DC_HPD_INT_STATUS; -+ uint32_t DC_HPD_TOGGLE_FILT_CNTL; -+}; -+ -+struct hw_hpd_dce80 { -+ struct hw_hpd base; -+ struct hw_hpd_dce80_addr addr; -+}; -+ -+struct hw_gpio_pin *dal_hw_hpd_dce80_create( -+ struct dc_context *ctx, -+ enum gpio_id id, -+ uint32_t en); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.c -new file mode 100644 -index 0000000..9788106 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.c -@@ -0,0 +1,424 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/gpio_types.h" -+#include "../hw_translate.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "hw_translate_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+/* -+ * This unit -+ */ -+ -+#include "../hw_gpio_pin.h" -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+#include "smu/smu_7_0_1_d.h" -+ -+/* -+ * @brief -+ * Returns index of first bit (starting with LSB) which is set -+ */ -+static uint32_t index_from_vector( -+ uint32_t vector) -+{ -+ uint32_t result = 0; -+ uint32_t mask = 1; -+ -+ do { -+ if (vector == mask) -+ return result; -+ -+ ++result; -+ mask <<= 1; -+ } while (mask); -+ -+ BREAK_TO_DEBUGGER(); -+ -+ return GPIO_ENUM_UNKNOWN; -+} -+ -+static bool offset_to_id( -+ uint32_t offset, -+ uint32_t mask, -+ enum gpio_id *id, -+ uint32_t *en) -+{ -+ switch (offset) { -+ /* GENERIC */ -+ case mmDC_GPIO_GENERIC_A: -+ *id = GPIO_ID_GENERIC; -+ switch (mask) { -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: -+ *en = GPIO_GENERIC_A; -+ return true; -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: -+ *en = GPIO_GENERIC_B; -+ return true; -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: -+ *en = GPIO_GENERIC_C; -+ return true; -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: -+ *en = GPIO_GENERIC_D; -+ return true; -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: -+ *en = GPIO_GENERIC_E; -+ return true; -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: -+ *en = GPIO_GENERIC_F; -+ return true; -+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: -+ *en = GPIO_GENERIC_G; -+ return true; -+ default: -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ break; -+ /* HPD */ -+ case mmDC_GPIO_HPD_A: -+ *id = GPIO_ID_HPD; -+ switch (mask) { -+ case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: -+ *en = GPIO_HPD_1; -+ return true; -+ case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: -+ *en = GPIO_HPD_2; -+ return true; -+ case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: -+ *en = GPIO_HPD_3; -+ return true; -+ case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: -+ *en = GPIO_HPD_4; -+ return true; -+ case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: -+ *en = GPIO_HPD_5; -+ return true; -+ case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: -+ *en = GPIO_HPD_6; -+ return true; -+ default: -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ break; -+ /* SYNCA */ -+ case mmDC_GPIO_SYNCA_A: -+ *id = GPIO_ID_SYNC; -+ switch (mask) { -+ case DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK: -+ *en = GPIO_SYNC_HSYNC_A; -+ return true; -+ case DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK: -+ *en = GPIO_SYNC_VSYNC_A; -+ return true; -+ default: -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ break; -+ /* mmDC_GPIO_GENLK_MASK */ -+ case mmDC_GPIO_GENLK_A: -+ *id = GPIO_ID_GSL; -+ switch (mask) { -+ case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: -+ *en = GPIO_GSL_GENLOCK_CLOCK; -+ return true; -+ case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: -+ *en = GPIO_GSL_GENLOCK_VSYNC; -+ return true; -+ case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: -+ *en = GPIO_GSL_SWAPLOCK_A; -+ return true; -+ case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: -+ *en = GPIO_GSL_SWAPLOCK_B; -+ return true; -+ default: -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ break; -+ /* GPIOPAD */ -+ case mmGPIOPAD_A: -+ *id = GPIO_ID_GPIO_PAD; -+ *en = index_from_vector(mask); -+ return (*en <= GPIO_GPIO_PAD_MAX); -+ /* DDC */ -+ /* we don't care about the GPIO_ID for DDC -+ * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK -+ * directly in the create method */ -+ case mmDC_GPIO_DDC1_A: -+ *en = GPIO_DDC_LINE_DDC1; -+ return true; -+ case mmDC_GPIO_DDC2_A: -+ *en = GPIO_DDC_LINE_DDC2; -+ return true; -+ case mmDC_GPIO_DDC3_A: -+ *en = GPIO_DDC_LINE_DDC3; -+ return true; -+ case mmDC_GPIO_DDC4_A: -+ *en = GPIO_DDC_LINE_DDC4; -+ return true; -+ case mmDC_GPIO_DDC5_A: -+ *en = GPIO_DDC_LINE_DDC5; -+ return true; -+ case mmDC_GPIO_DDC6_A: -+ *en = GPIO_DDC_LINE_DDC6; -+ return true; -+ case mmDC_GPIO_DDCVGA_A: -+ *en = GPIO_DDC_LINE_DDC_VGA; -+ return true; -+ /* GPIO_I2CPAD */ -+ case mmDC_GPIO_I2CPAD_A: -+ *en = GPIO_DDC_LINE_I2C_PAD; -+ return true; -+ /* Not implemented */ -+ case mmDC_GPIO_PWRSEQ_A: -+ case mmDC_GPIO_PAD_STRENGTH_1: -+ case mmDC_GPIO_PAD_STRENGTH_2: -+ case mmDC_GPIO_DEBUG: -+ return false; -+ /* UNEXPECTED */ -+ default: -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+} -+ -+static bool id_to_offset( -+ enum gpio_id id, -+ uint32_t en, -+ struct gpio_pin_info *info) -+{ -+ bool result = true; -+ -+ switch (id) { -+ case GPIO_ID_DDC_DATA: -+ info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK; -+ switch (en) { -+ case GPIO_DDC_LINE_DDC1: -+ info->offset = mmDC_GPIO_DDC1_A; -+ break; -+ case GPIO_DDC_LINE_DDC2: -+ info->offset = mmDC_GPIO_DDC2_A; -+ break; -+ case GPIO_DDC_LINE_DDC3: -+ info->offset = mmDC_GPIO_DDC3_A; -+ break; -+ case GPIO_DDC_LINE_DDC4: -+ info->offset = mmDC_GPIO_DDC4_A; -+ break; -+ case GPIO_DDC_LINE_DDC5: -+ info->offset = mmDC_GPIO_DDC5_A; -+ break; -+ case GPIO_DDC_LINE_DDC6: -+ info->offset = mmDC_GPIO_DDC6_A; -+ break; -+ case GPIO_DDC_LINE_DDC_VGA: -+ info->offset = mmDC_GPIO_DDCVGA_A; -+ break; -+ case GPIO_DDC_LINE_I2C_PAD: -+ info->offset = mmDC_GPIO_I2CPAD_A; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ break; -+ case GPIO_ID_DDC_CLOCK: -+ info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK; -+ switch (en) { -+ case GPIO_DDC_LINE_DDC1: -+ info->offset = mmDC_GPIO_DDC1_A; -+ break; -+ case GPIO_DDC_LINE_DDC2: -+ info->offset = mmDC_GPIO_DDC2_A; -+ break; -+ case GPIO_DDC_LINE_DDC3: -+ info->offset = mmDC_GPIO_DDC3_A; -+ break; -+ case GPIO_DDC_LINE_DDC4: -+ info->offset = mmDC_GPIO_DDC4_A; -+ break; -+ case GPIO_DDC_LINE_DDC5: -+ info->offset = mmDC_GPIO_DDC5_A; -+ break; -+ case GPIO_DDC_LINE_DDC6: -+ info->offset = mmDC_GPIO_DDC6_A; -+ break; -+ case GPIO_DDC_LINE_DDC_VGA: -+ info->offset = mmDC_GPIO_DDCVGA_A; -+ break; -+ case GPIO_DDC_LINE_I2C_PAD: -+ info->offset = mmDC_GPIO_I2CPAD_A; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ break; -+ case GPIO_ID_GENERIC: -+ info->offset = mmDC_GPIO_GENERIC_A; -+ switch (en) { -+ case GPIO_GENERIC_A: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; -+ break; -+ case GPIO_GENERIC_B: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; -+ break; -+ case GPIO_GENERIC_C: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; -+ break; -+ case GPIO_GENERIC_D: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; -+ break; -+ case GPIO_GENERIC_E: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; -+ break; -+ case GPIO_GENERIC_F: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; -+ break; -+ case GPIO_GENERIC_G: -+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ break; -+ case GPIO_ID_HPD: -+ info->offset = mmDC_GPIO_HPD_A; -+ switch (en) { -+ case GPIO_HPD_1: -+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; -+ break; -+ case GPIO_HPD_2: -+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; -+ break; -+ case GPIO_HPD_3: -+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; -+ break; -+ case GPIO_HPD_4: -+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; -+ break; -+ case GPIO_HPD_5: -+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; -+ break; -+ case GPIO_HPD_6: -+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ break; -+ case GPIO_ID_SYNC: -+ switch (en) { -+ case GPIO_SYNC_HSYNC_A: -+ info->offset = mmDC_GPIO_SYNCA_A; -+ info->mask = DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK; -+ break; -+ case GPIO_SYNC_VSYNC_A: -+ info->offset = mmDC_GPIO_SYNCA_A; -+ info->mask = DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK; -+ break; -+ case GPIO_SYNC_HSYNC_B: -+ case GPIO_SYNC_VSYNC_B: -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ break; -+ case GPIO_ID_GSL: -+ switch (en) { -+ case GPIO_GSL_GENLOCK_CLOCK: -+ info->offset = mmDC_GPIO_GENLK_A; -+ info->mask = DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK; -+ break; -+ case GPIO_GSL_GENLOCK_VSYNC: -+ info->offset = mmDC_GPIO_GENLK_A; -+ info->mask = -+ DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK; -+ break; -+ case GPIO_GSL_SWAPLOCK_A: -+ info->offset = mmDC_GPIO_GENLK_A; -+ info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK; -+ break; -+ case GPIO_GSL_SWAPLOCK_B: -+ info->offset = mmDC_GPIO_GENLK_A; -+ info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK; -+ break; -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ break; -+ case GPIO_ID_GPIO_PAD: -+ info->offset = mmGPIOPAD_A; -+ info->mask = (1 << en); -+ result = (info->mask <= GPIO_GPIO_PAD_MAX); -+ break; -+ case GPIO_ID_VIP_PAD: -+ default: -+ BREAK_TO_DEBUGGER(); -+ result = false; -+ } -+ -+ if (result) { -+ info->offset_y = info->offset + 2; -+ info->offset_en = info->offset + 1; -+ info->offset_mask = info->offset - 1; -+ -+ info->mask_y = info->mask; -+ info->mask_en = info->mask; -+ info->mask_mask = info->mask; -+ } -+ -+ return result; -+} -+ -+static const struct hw_translate_funcs funcs = { -+ .offset_to_id = offset_to_id, -+ .id_to_offset = id_to_offset, -+}; -+ -+void dal_hw_translate_dce80_init( -+ struct hw_translate *translate) -+{ -+ translate->funcs = &funcs; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.h -new file mode 100644 -index 0000000..374f2f3 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce80/hw_translate_dce80.h -@@ -0,0 +1,32 @@ -+/* -+ * 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_TRANSLATE_DCE80_H__ -+#define __DAL_HW_TRANSLATE_DCE80_H__ -+ -+void dal_hw_translate_dce80_init( -+ struct hw_translate *tr); -+ -+#endif -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 e0f6ecf..9c8ff54 100644 ---- a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c -@@ -40,6 +40,10 @@ - * Post-requisites: headers required by this unit - */ - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/hw_factory_dce80.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) - #include "dce110/hw_factory_dce110.h" - #endif -@@ -61,6 +65,11 @@ bool dal_hw_factory_init( - } - - switch (dce_version) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ dal_hw_factory_dce80_init(factory); -+ return true; -+#endif - - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: -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 215322e..d3c6bc8 100644 ---- a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c -+++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c -@@ -40,6 +40,10 @@ - * Post-requisites: headers required by this unit - */ - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/hw_translate_dce80.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) - #include "dce110/hw_translate_dce110.h" - #endif -@@ -61,7 +65,11 @@ bool dal_hw_translate_init( - } - - switch (dce_version) { -- -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ dal_hw_translate_dce80_init(translate); -+ return true; -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: -diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile -index b481a6d..cb23508 100644 ---- a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile -@@ -9,6 +9,18 @@ AMD_DAL_GPU = $(addprefix $(AMDDALPATH)/dc/gpu/,$(GPU)) - - AMD_DAL_FILES += $(AMD_DAL_GPU) - -+############################################################################### -+# DCE 80 family -+############################################################################### -+ -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+GPU_DCE80 = display_clock_dce80.o dc_clock_gating_dce80.o -+ -+AMD_DAL_GPU_DCE80 = $(addprefix $(AMDDALPATH)/dc/gpu/dce80/,$(GPU_DCE80)) -+ -+AMD_DAL_FILES += $(AMD_DAL_GPU_DCE80) -+endif -+ - - ############################################################################### - # DCE 110 family -diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.c -new file mode 100644 -index 0000000..5f57577 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.c -@@ -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 -+ * -+ */ -+ -+#include "dm_services.h" -+#include "dc_clock_gating_dce80.h" -+ -+static void enable_hw_base_light_sleep(void) -+{ -+ /* TODO: implement */ -+} -+ -+static void disable_sw_manual_control_light_sleep(void) -+{ -+ /* TODO: implement */ -+} -+ -+static void enable_sw_manual_control_light_sleep(void) -+{ -+ /* TODO: implement */ -+} -+ -+void dal_dc_clock_gating_dce80_power_up(struct dc_context *ctx, bool enable) -+{ -+ if (enable) { -+ enable_hw_base_light_sleep(); -+ disable_sw_manual_control_light_sleep(); -+ } else { -+ enable_sw_manual_control_light_sleep(); -+ } -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.h -new file mode 100644 -index 0000000..f4111c5 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/dc_clock_gating_dce80.h -@@ -0,0 +1,31 @@ -+/* -+ * 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_DCE80_H__ -+#define __DAL_DC_CLOCK_GATING_DCE80_H__ -+ -+void dal_dc_clock_gating_dce80_power_up(struct dc_context *ctx, bool enable); -+ -+#endif /* __DAL_DC_CLOCK_GATING_DCE80_H__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.c -new file mode 100644 -index 0000000..760705f ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.c -@@ -0,0 +1,925 @@ -+/* -+ * 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_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+#include "include/adapter_service_interface.h" -+#include "include/bios_parser_interface.h" -+#include "include/fixed32_32.h" -+#include "include/logger_interface.h" -+ -+#include "../divider_range.h" -+#include "display_clock_dce80.h" -+ -+#define DCE80_DFS_BYPASS_THRESHOLD_KHZ 100000 -+ -+/* Max clock values for each state indexed by "enum clocks_state": */ -+static struct state_dependent_clocks max_clks_by_state[] = { -+/* ClocksStateInvalid - should not be used */ -+{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, -+/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */ -+{ .display_clk_khz = 0, .pixel_clk_khz = 0 }, -+/* ClocksStateLow */ -+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000}, -+/* ClocksStateNominal */ -+{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 }, -+/* ClocksStatePerformance */ -+{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } }; -+ -+ -+/* Starting point for each divider range.*/ -+enum divider_range_start { -+ DIVIDER_RANGE_01_START = 200, /* 2.00*/ -+ DIVIDER_RANGE_02_START = 1600, /* 16.00*/ -+ DIVIDER_RANGE_03_START = 3200, /* 32.00*/ -+ DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ -+}; -+ -+/* 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 */ -+}; -+ -+/* 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*/ -+}; -+ -+static struct divider_range divider_ranges[DIVIDER_RANGE_MAX]; -+ -+#define FROM_DISPLAY_CLOCK(base) \ -+ container_of(base, struct display_clock_dce80, disp_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 uint32_t get_scaler_efficiency(struct min_clock_params *params) -+{ -+ uint32_t scaler_efficiency = 3; -+ -+ switch (params->scaler_efficiency) { -+ case V_SCALER_EFFICIENCY_LB18BPP: -+ case V_SCALER_EFFICIENCY_LB24BPP: -+ scaler_efficiency = 4; -+ break; -+ -+ case V_SCALER_EFFICIENCY_LB30BPP: -+ case V_SCALER_EFFICIENCY_LB36BPP: -+ scaler_efficiency = 3; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return scaler_efficiency; -+} -+ -+static uint32_t get_actual_required_display_clk( -+ struct display_clock_dce80 *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(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 get_validation_clock(struct display_clock *dc) -+{ -+ uint32_t clk = 0; -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(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*/ -+ BREAK_TO_DEBUGGER(); -+ /* 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 uint32_t calc_single_display_min_clks( -+ struct display_clock *base, -+ struct min_clock_params *params, -+ bool set_clk) -+{ -+ struct fixed32_32 h_scale = dal_fixed32_32_from_int(1); -+ struct fixed32_32 v_scale = dal_fixed32_32_from_int(1); -+ uint32_t pix_clk_khz = params->requested_pixel_clock; -+ uint32_t line_total = params->timing_info.h_total; -+ uint32_t max_clk_khz = get_validation_clock(base); -+ struct fixed32_32 deep_color_factor = get_deep_color_factor(params); -+ uint32_t scaler_efficiency = get_scaler_efficiency(params); -+ struct fixed32_32 v_filter_init; -+ uint32_t v_filter_init_trunc; -+ struct fixed32_32 v_filter_init_ceil; -+ struct fixed32_32 src_lines_per_dst_line; -+ uint32_t src_wdth_rnd_to_chunks; -+ struct fixed32_32 scaling_coeff; -+ struct fixed32_32 fx_disp_clk_khz; -+ struct fixed32_32 fx_alt_disp_clk_khz; -+ uint32_t disp_clk_khz; -+ uint32_t alt_disp_clk_khz; -+ struct display_clock_dce80 *dc = FROM_DISPLAY_CLOCK(base); -+ -+ -+ if (0 != params->dest_view.height && 0 != params->dest_view.width) { -+ -+ h_scale = dal_fixed32_32_from_fraction( -+ params->source_view.width, -+ params->dest_view.width); -+ v_scale = dal_fixed32_32_from_fraction( -+ params->source_view.height, -+ params->dest_view.height); -+ } -+ -+ v_filter_init = dal_fixed32_32_from_fraction( -+ params->scaling_info.v_taps, 2u); -+ v_filter_init = dal_fixed32_32_add(v_filter_init, -+ dal_fixed32_32_div_int(v_scale, 2)); -+ v_filter_init = dal_fixed32_32_add(v_filter_init, -+ dal_fixed32_32_from_fraction(15, 10)); -+ -+ -+ 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); -+ v_filter_init_ceil = dal_fixed32_32_div_int(v_filter_init_ceil, 3); -+ v_filter_init_ceil = dal_fixed32_32_from_int( -+ dal_fixed32_32_ceil(v_filter_init_ceil)); -+ -+ src_lines_per_dst_line = dal_fixed32_32_max( -+ dal_fixed32_32_from_int(dal_fixed32_32_ceil(v_scale)), -+ v_filter_init_ceil); -+ -+ src_wdth_rnd_to_chunks = -+ ((params->source_view.width - 1) / 128) * 128 + 256; -+ -+ scaling_coeff = dal_fixed32_32_max( -+ dal_fixed32_32_from_fraction(params->scaling_info.h_taps, 4), -+ dal_fixed32_32_mul( -+ dal_fixed32_32_from_fraction( -+ params->scaling_info.v_taps, -+ scaler_efficiency), -+ h_scale)); -+ -+ scaling_coeff = dal_fixed32_32_max(scaling_coeff, h_scale); -+ -+ fx_disp_clk_khz = dal_fixed32_32_mul( -+ scaling_coeff, dal_fixed32_32_from_fraction(11, 10)); -+ if (0 != line_total) { -+ struct fixed32_32 d_clk = dal_fixed32_32_mul_int( -+ src_lines_per_dst_line, src_wdth_rnd_to_chunks); -+ d_clk = dal_fixed32_32_div_int(d_clk, line_total); -+ d_clk = dal_fixed32_32_mul(d_clk, -+ dal_fixed32_32_from_fraction(11, 10)); -+ fx_disp_clk_khz = dal_fixed32_32_max(fx_disp_clk_khz, d_clk); -+ } -+ -+ fx_disp_clk_khz = dal_fixed32_32_max(fx_disp_clk_khz, -+ dal_fixed32_32_mul(deep_color_factor, -+ dal_fixed32_32_from_fraction(11, 10))); -+ -+ fx_disp_clk_khz = dal_fixed32_32_mul_int(fx_disp_clk_khz, pix_clk_khz); -+ fx_disp_clk_khz = dal_fixed32_32_mul(fx_disp_clk_khz, -+ dal_fixed32_32_from_fraction(1005, 1000)); -+ -+ fx_alt_disp_clk_khz = scaling_coeff; -+ -+ if (0 != line_total) { -+ struct fixed32_32 d_clk = dal_fixed32_32_mul_int( -+ src_lines_per_dst_line, src_wdth_rnd_to_chunks); -+ d_clk = dal_fixed32_32_div_int(d_clk, line_total); -+ d_clk = dal_fixed32_32_mul(d_clk, -+ dal_fixed32_32_from_fraction(105, 100)); -+ fx_alt_disp_clk_khz = dal_fixed32_32_max( -+ fx_alt_disp_clk_khz, d_clk); -+ } -+ fx_alt_disp_clk_khz = dal_fixed32_32_max( -+ fx_alt_disp_clk_khz, fx_alt_disp_clk_khz); -+ -+ fx_alt_disp_clk_khz = dal_fixed32_32_mul_int( -+ fx_alt_disp_clk_khz, pix_clk_khz); -+ -+ /* convert to integer*/ -+ disp_clk_khz = dal_fixed32_32_floor(fx_disp_clk_khz); -+ alt_disp_clk_khz = dal_fixed32_32_floor(fx_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( -+ dc, disp_clk_khz); -+ alt_disp_clk_khz = get_actual_required_display_clk( -+ dc, alt_disp_clk_khz); -+ } -+ -+ if ((disp_clk_khz > max_clk_khz) && (alt_disp_clk_khz <= max_clk_khz)) -+ disp_clk_khz = alt_disp_clk_khz; -+ -+ return disp_clk_khz; -+ -+} -+ -+static uint32_t calc_cursor_bw_for_min_clks(struct min_clock_params *params) -+{ -+ -+ struct fixed32_32 v_scale = dal_fixed32_32_from_int(1); -+ struct fixed32_32 v_filter_ceiling; -+ struct fixed32_32 src_lines_per_dst_line; -+ struct fixed32_32 cursor_bw; -+ -+ -+ /* DCE8 Mode Support and Mode Set Architecture Specification Rev 1.3 -+ 6.3.3 Cursor data Throughput requirement on DISPCLK -+ The MCIF to DCP cursor data return throughput is one pixel per DISPCLK -+ shared among the display heads. -+ If (Total Cursor Bandwidth in pixels for All heads> DISPCLK) -+ The mode is not supported -+ Cursor Bandwidth in Pixels = Cursor Width * -+ (SourceLinesPerDestinationLine / Line Time) -+ Assuming that Cursor Width = 128 -+ */ -+ /*In the hardware doc they mention an Interlace Factor -+ It is not used here because we have already used it when -+ calculating destination view*/ -+ if (0 != params->dest_view.height) -+ v_scale = dal_fixed32_32_from_fraction( -+ params->source_view.height, -+ params->dest_view.height); -+ -+ { -+ /*Do: Vertical Filter Init = 0.5 + VTAPS/2 + VSR/2 * Interlace Factor*/ -+ /*Interlace Factor is included in verticalScaleRatio*/ -+ struct fixed32_32 v_filter = dal_fixed32_32_add( -+ dal_fixed32_32_from_fraction(params->scaling_info.v_taps, 2), -+ dal_fixed32_32_div_int(v_scale, 2)); -+ /*Do : Ceiling (Vertical Filter Init, 2)/3 )*/ -+ v_filter_ceiling = dal_fixed32_32_div_int(v_filter, 2); -+ v_filter_ceiling = dal_fixed32_32_mul_int( -+ dal_fixed32_32_from_int(dal_fixed32_32_ceil(v_filter_ceiling)), -+ 2); -+ v_filter_ceiling = dal_fixed32_32_div_int(v_filter_ceiling, 3); -+ } -+ /*Do : MAX( CeilCeiling (VSR), Ceiling (Vertical Filter Init, 2)/3 )*/ -+ /*Do : SourceLinesPerDestinationLine = -+ * MAX( Ceiling (VSR), Ceiling (Vertical Filter Init, 2)/3 )*/ -+ src_lines_per_dst_line = dal_fixed32_32_max(v_scale, v_filter_ceiling); -+ -+ if ((params->requested_pixel_clock != 0) && -+ (params->timing_info.h_total != 0)) { -+ /* pixelClock is in units of KHz. Calc lineTime in us*/ -+ struct fixed32_32 inv_line_time = dal_fixed32_32_from_fraction( -+ params->requested_pixel_clock, -+ params->timing_info.h_total); -+ cursor_bw = dal_fixed32_32_mul( -+ dal_fixed32_32_mul_int(inv_line_time, 128), -+ src_lines_per_dst_line); -+ } -+ -+ /* convert to integer*/ -+ return dal_fixed32_32_floor(cursor_bw); -+} -+ -+static bool validate( -+ struct display_clock *dc, -+ struct min_clock_params *params) -+{ -+ uint32_t max_clk_khz = get_validation_clock(dc); -+ uint32_t req_clk_khz; -+ -+ if (params == NULL) -+ return false; -+ -+ req_clk_khz = calc_single_display_min_clks(dc, params, false); -+ -+ return (req_clk_khz <= max_clk_khz); -+} -+ -+static uint32_t calculate_min_clock( -+ struct display_clock *dc, -+ uint32_t path_num, -+ struct min_clock_params *params) -+{ -+ uint32_t i; -+ uint32_t validation_clk_khz = get_validation_clock(dc); -+ uint32_t min_clk_khz = validation_clk_khz; -+ uint32_t max_clk_khz = 0; -+ uint32_t total_cursor_bw = 0; -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ -+ if (disp_clk->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( -+ dc, params, true); -+ -+ /* update the max required clock found*/ -+ if (disp_clk_khz > max_clk_khz) -+ max_clk_khz = disp_clk_khz; -+ -+ disp_clk_khz = calc_cursor_bw_for_min_clks(params); -+ -+ total_cursor_bw += disp_clk_khz; -+ -+ params++; -+ -+ } -+ } -+ -+ max_clk_khz = (total_cursor_bw > max_clk_khz) ? total_cursor_bw : -+ max_clk_khz; -+ -+ min_clk_khz = max_clk_khz; -+ -+ /*"Cursor data Throughput requirement on DISPCLK is now a factor, -+ * need to change the code */ -+ ASSERT(total_cursor_bw < validation_clk_khz); -+ -+ if (min_clk_khz > validation_clk_khz) -+ min_clk_khz = validation_clk_khz; -+ else if (min_clk_khz < dc->min_display_clk_threshold_khz) -+ min_clk_khz = dc->min_display_clk_threshold_khz; -+ -+ return min_clk_khz; -+} -+ -+static void set_clock( -+ struct display_clock *dc, -+ uint32_t requested_clk_khz) -+{ -+ struct bp_pixel_clock_parameters pxl_clk_params; -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ struct dc_bios *bp = dal_adapter_service_get_bios_parser(dc->as); -+ -+ /* Prepare to program display clock*/ -+ dm_memset(&pxl_clk_params, 0, sizeof(pxl_clk_params)); -+ -+ pxl_clk_params.target_pixel_clock = requested_clk_khz; -+ pxl_clk_params.pll_id = dc->id; -+ -+ bp->funcs->program_display_engine_pll(bp, &pxl_clk_params); -+ -+ if (disp_clk->dfs_bypass_enabled) { -+ -+ /* Cache the fixed display clock*/ -+ disp_clk->dfs_bypass_disp_clk = -+ pxl_clk_params.dfs_bypass_display_clock; -+ } -+ -+ /* from power down, we need mark the clock state as ClocksStateNominal -+ * from HWReset, so when resume we will call pplib voltage regulator.*/ -+ if (requested_clk_khz == 0) -+ disp_clk->cur_min_clks_state = CLOCKS_STATE_NOMINAL; -+} -+ -+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_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ if (disp_clk->dfs_bypass_enabled && disp_clk->dfs_bypass_disp_clk) -+ return disp_clk->dfs_bypass_disp_clk; -+ -+ /* Read the mmDENTIST_DISPCLK_CNTL to get the currently programmed -+ DID DENTIST_DISPCLK_WDIVIDER.*/ -+ value = dm_read_reg(dc->ctx, addr); -+ field = get_reg_field_value( -+ value, DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER); -+ -+ /* Convert DENTIST_DISPCLK_WDIVIDER to actual divider*/ -+ target_div = dal_divider_range_get_divider( -+ divider_ranges, -+ DIVIDER_RANGE_MAX, -+ field); -+ -+ if (target_div != INVALID_DIVIDER) -+ /* Calculate the current DFS clock in KHz. -+ Should be okay up to 42.9 THz before overflowing.*/ -+ disp_clock = (DIVIDER_RANGE_SCALE_FACTOR -+ * disp_clk->dentist_vco_freq_khz) / target_div; -+ return disp_clock; -+} -+ -+static void set_clock_state( -+ struct display_clock *dc, -+ struct display_clock_state clk_state) -+{ -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ disp_clk->clock_state = clk_state; -+} -+static struct display_clock_state get_clock_state( -+ struct display_clock *dc) -+{ -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ return disp_clk->clock_state; -+} -+ -+static enum clocks_state get_min_clocks_state(struct display_clock *dc) -+{ -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ return disp_clk->cur_min_clks_state; -+} -+ -+static enum clocks_state get_required_clocks_state -+ (struct display_clock *dc, -+ struct state_dependent_clocks *req_clocks) -+{ -+ int32_t i; -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ enum clocks_state low_req_clk = disp_clk->max_clks_state; -+ -+ if (!req_clocks) { -+ /* NULL pointer*/ -+ BREAK_TO_DEBUGGER(); -+ 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 bool set_min_clocks_state( -+ struct display_clock *dc, -+ enum clocks_state clocks_state) -+{ -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ if (clocks_state > disp_clk->max_clks_state) { -+ /*Requested state exceeds max supported state.*/ -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } else if (clocks_state == disp_clk->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; -+ } -+ -+ disp_clk->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_dce80 *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 store_max_clocks_state( -+ struct display_clock *dc, -+ enum clocks_state max_clocks_state) -+{ -+ struct display_clock_dce80 *disp_clk = FROM_DISPLAY_CLOCK(dc); -+ -+ switch (max_clocks_state) { -+ case CLOCKS_STATE_LOW: -+ case CLOCKS_STATE_NOMINAL: -+ case CLOCKS_STATE_PERFORMANCE: -+ case CLOCKS_STATE_ULTRA_LOW: -+ disp_clk->max_clks_state = max_clocks_state; -+ break; -+ -+ case CLOCKS_STATE_INVALID: -+ default: -+ /*Invalid Clocks State!*/ -+ BREAK_TO_DEBUGGER(); -+ break; -+ } -+} -+ -+static void display_clock_ss_construct( -+ struct display_clock_dce80 *disp_clk, -+ struct adapter_service *as) -+{ -+ uint32_t ss_entry_num = dal_adapter_service_get_ss_info_num(as, -+ AS_SIGNAL_TYPE_GPU_PLL); -+ -+ /*Read SS Info from VBIOS SS Info table for DP Reference Clock spread.*/ -+ if (ss_entry_num > 0) {/* Should be only one entry */ -+ struct spread_spectrum_info ss_info; -+ bool res; -+ -+ dm_memset(&ss_info, 0, sizeof(struct spread_spectrum_info)); -+ -+ res = dal_adapter_service_get_ss_info(as, -+ AS_SIGNAL_TYPE_GPU_PLL, 0, &ss_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 (res && ss_info.spread_spectrum_percentage != 0) { -+ disp_clk->ss_on_gpu_pll = true; -+ disp_clk->gpu_pll_ss_divider = -+ ss_info.spread_percentage_divider; -+ if (ss_info.type.CENTER_MODE == 0) -+ /* Currently we need only SS -+ * percentage for down-spread*/ -+ disp_clk->gpu_pll_ss_percentage = -+ ss_info.spread_spectrum_percentage; -+ } -+ } -+} -+ -+static bool display_clock_integrated_info_construct( -+ struct display_clock_dce80 *disp_clk, -+ struct adapter_service *as) -+{ -+ struct integrated_info info; -+ struct firmware_info fw_info; -+ bool res; -+ uint32_t i; -+ -+ res = dal_adapter_service_get_integrated_info(as, &info); -+ -+ disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq; -+ if (disp_clk->dentist_vco_freq_khz == 0) { -+ dal_adapter_service_get_firmware_info(as, &fw_info); -+ disp_clk->dentist_vco_freq_khz = -+ fw_info.smu_gpu_pll_output_freq; -+ if (disp_clk->dentist_vco_freq_khz == 0) -+ disp_clk->dentist_vco_freq_khz = 3600000; -+ } -+ disp_clk->disp_clk.min_display_clk_threshold_khz = -+ disp_clk->dentist_vco_freq_khz / 64; -+ -+ if (!res) -+ return false; -+ -+ /* TODO: initialise disp_clk->dfs_bypass_disp_clk */ -+ -+ /*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; -+ } -+ /*invalid input from bios*/ -+ ASSERT(info.disp_clk_voltage[i].max_supported_clk >= 100000); -+ } -+ disp_clk->dfs_bypass_enabled = -+ dal_adapter_service_is_dfs_bypass_enabled(as) && -+ dal_adapter_service_is_feature_supported( -+ FEATURE_ENABLE_DFS_BYPASS); -+ -+ disp_clk->use_max_disp_clk = -+ dal_adapter_service_is_feature_supported( -+ FEATURE_USE_MAX_DISPLAY_CLK); -+ return true; -+} -+ -+static uint32_t get_dfs_bypass_threshold(struct display_clock *dc) -+{ -+ return DCE80_DFS_BYPASS_THRESHOLD_KHZ; -+} -+ -+static void destroy(struct display_clock **dc) -+{ -+ struct display_clock_dce80 *disp_clk; -+ -+ disp_clk = FROM_DISPLAY_CLOCK(*dc); -+ dm_free((*dc)->ctx, disp_clk); -+ *dc = NULL; -+} -+ -+static const struct display_clock_funcs funcs = { -+ .calculate_min_clock = calculate_min_clock, -+ .destroy = destroy, -+ .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 = -+ dal_display_clock_base_set_dp_ref_clock_source, -+ .set_min_clocks_state = set_min_clocks_state, -+ .store_max_clocks_state = store_max_clocks_state, -+ .validate = validate, -+}; -+ -+static bool display_clock_construct( -+ struct dc_context *ctx, -+ struct display_clock_dce80 *disp_clk, -+ struct adapter_service *as) -+{ -+ struct display_clock *dc_base = &disp_clk->disp_clk; -+ -+ if (NULL == as) -+ return false; -+ -+ if (!dal_display_clock_construct_base(dc_base, ctx, as)) -+ return false; -+ -+ dc_base->funcs = &funcs; -+ /* -+ * set_dp_ref_clock_source -+ * set_clock_state -+ * get_clock_state -+ * get_dfs_bypass_threshold -+ */ -+ -+ disp_clk->gpu_pll_ss_percentage = 0; -+ disp_clk->gpu_pll_ss_divider = 1000; -+ disp_clk->ss_on_gpu_pll = false; -+ disp_clk->dfs_bypass_enabled = false; -+ disp_clk->dfs_bypass_disp_clk = 0; -+ disp_clk->use_max_disp_clk = true;/* false will hang the system! */ -+ -+ disp_clk->disp_clk.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_Dce50::StoreMaxClocksState(). This call will come in -+ * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/ -+ disp_clk->max_clks_state = CLOCKS_STATE_NOMINAL; -+/* Initially set current min clocks state to invalid since we -+ * cannot make any assumption about PPLIB's initial state. This will be updated -+ * by HWSS via SetMinClocksState() on first mode set prior to programming -+ * state dependent clocks.*/ -+ disp_clk->cur_min_clks_state = CLOCKS_STATE_INVALID; -+ -+ display_clock_ss_construct(disp_clk, as); -+ -+ if (!display_clock_integrated_info_construct(disp_clk, as)) { -+ dal_logger_write(dc_base->ctx->logger, -+ LOG_MAJOR_WARNING, -+ LOG_MINOR_COMPONENT_GPU, -+ "Cannot obtain VBIOS integrated info"); -+ } -+ -+ dal_divider_range_construct( -+ ÷r_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( -+ ÷r_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( -+ ÷r_ranges[DIVIDER_RANGE_03], -+ DIVIDER_RANGE_03_START, -+ DIVIDER_RANGE_03_STEP_SIZE, -+ DIVIDER_RANGE_03_BASE_DIVIDER_ID, -+ DIVIDER_RANGE_MAX_DIVIDER_ID); -+ return true; -+} -+ -+struct display_clock *dal_display_clock_dce80_create( -+ struct dc_context *ctx, -+ struct adapter_service *as) -+{ -+ struct display_clock_dce80 *disp_clk; -+ -+ disp_clk = dm_alloc(ctx, sizeof(struct display_clock_dce80)); -+ -+ if (disp_clk == NULL) -+ return NULL; -+ -+ if (display_clock_construct(ctx, disp_clk, as)) -+ return &disp_clk->disp_clk; -+ -+ dm_free(ctx, disp_clk); -+ return NULL; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.h -new file mode 100644 -index 0000000..2d68704 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce80/display_clock_dce80.h -@@ -0,0 +1,58 @@ -+/* -+ * 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_DCE80_H__ -+#define __DAL_DISPLAY_CLOCK_DCE80_H__ -+ -+#include "gpu/display_clock.h" -+ -+struct display_clock_dce80 { -+ struct display_clock disp_clk; -+ /* DFS input - GPUPLL VCO frequency - from VBIOS Firmware info. */ -+ uint32_t dentist_vco_freq_khz; -+ /* 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; -+ /* Max display block clocks state*/ -+ enum clocks_state max_clks_state; -+ /* Current minimum display block clocks state*/ -+ enum clocks_state cur_min_clks_state; -+ /* DFS-bypass feature variable -+ Cache the status of DFS-bypass feature*/ -+ bool dfs_bypass_enabled; -+ /* 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; -+ bool use_max_disp_clk; -+ struct display_clock_state clock_state; -+}; -+ -+struct display_clock *dal_display_clock_dce80_create( -+ struct dc_context *ctx, -+ struct adapter_service *as); -+ -+#endif /* __DAL_DISPLAY_CLOCK_DCE80_H__ */ -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile b/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile -index 390d83d..fc76821 100644 ---- a/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile -@@ -9,6 +9,17 @@ AMD_DAL_I2CAUX = $(addprefix $(AMDDALPATH)/dc/i2caux/,$(I2CAUX)) - - AMD_DAL_FILES += $(AMD_DAL_I2CAUX) - -+############################################################################### -+# DCE 8x family -+############################################################################### -+ifdef CONFIG_DRM_AMD_DAL_DCE8_0 -+I2CAUX_DCE80 = i2caux_dce80.o i2c_hw_engine_dce80.o \ -+ i2c_sw_engine_dce80.o aux_engine_dce80.o -+ -+AMD_DAL_I2CAUX_DCE80 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce80/,$(I2CAUX_DCE80)) -+ -+AMD_DAL_FILES += $(AMD_DAL_I2CAUX_DCE80) -+endif - - ############################################################################### - # DCE 11x family -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.c -new file mode 100644 -index 0000000..a4fc2cd ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.c -@@ -0,0 +1,740 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/i2caux_interface.h" -+#include "../engine.h" -+#include "../aux_engine.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "aux_engine_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+ -+/* -+ * This unit -+ */ -+ -+/* -+ * @brief -+ * Cast 'struct aux_engine *' -+ * to 'struct aux_engine_dce80 *' -+ */ -+#define FROM_AUX_ENGINE(ptr) \ -+ container_of((ptr), struct aux_engine_dce80, base) -+ -+/* -+ * @brief -+ * Cast 'struct engine *' -+ * to 'struct aux_engine_dce80 *' -+ */ -+#define FROM_ENGINE(ptr) \ -+ FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base)) -+ -+static void release_engine( -+ struct engine *engine) -+{ -+ struct aux_engine_dce80 *aux_engine = FROM_ENGINE(engine); -+ -+ const uint32_t addr = aux_engine->addr.AUX_ARB_CONTROL; -+ -+ uint32_t value = dm_read_reg(engine->ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_ARB_CONTROL, -+ AUX_SW_DONE_USING_AUX_REG); -+ -+ dm_write_reg(engine->ctx, addr, value); -+} -+ -+static void destruct( -+ struct aux_engine_dce80 *engine); -+ -+static void destroy( -+ struct aux_engine **aux_engine) -+{ -+ struct aux_engine_dce80 *engine = FROM_AUX_ENGINE(*aux_engine); -+ -+ destruct(engine); -+ -+ dm_free((*aux_engine)->base.ctx, engine); -+ -+ *aux_engine = NULL; -+} -+ -+#define SW_CAN_ACCESS_AUX 1 -+ -+static bool acquire_engine( -+ struct aux_engine *engine) -+{ -+ struct aux_engine_dce80 *aux_engine = FROM_AUX_ENGINE(engine); -+ uint32_t value; -+ uint32_t field; -+ -+ /* enable AUX before request SW to access AUX */ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_CONTROL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ field = get_reg_field_value( -+ value, -+ AUX_CONTROL, -+ AUX_EN); -+ -+ if (field == 0) { -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_CONTROL, -+ AUX_EN); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ } -+ -+ /* request SW to access AUX */ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_ARB_CONTROL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_ARB_CONTROL, -+ AUX_SW_USE_AUX_REG_REQ); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ field = get_reg_field_value( -+ value, -+ AUX_ARB_CONTROL, -+ AUX_REG_RW_CNTL_STATUS); -+ -+ return field == SW_CAN_ACCESS_AUX; -+ } -+} -+ -+static void configure( -+ struct aux_engine *engine, -+ union aux_config cfg) -+{ -+ struct aux_engine_dce80 *aux_engine = FROM_AUX_ENGINE(engine); -+ -+ const uint32_t addr = aux_engine->addr.AUX_CONTROL; -+ -+ uint32_t value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ (0 != cfg.bits.ALLOW_AUX_WHEN_HPD_LOW), -+ AUX_CONTROL, -+ AUX_IGNORE_HPD_DISCON); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+} -+ -+static bool start_gtc_sync( -+ struct aux_engine *engine) -+{ -+ /* TODO */ -+ return false; -+} -+ -+static void stop_gtc_sync( -+ struct aux_engine *engine) -+{ -+ /* TODO */ -+} -+ -+#define COMPOSE_AUX_SW_DATA_16_20(command, address) \ -+ ((command) | ((0xF0000 & (address)) >> 16)) -+ -+#define COMPOSE_AUX_SW_DATA_8_15(address) \ -+ ((0xFF00 & (address)) >> 8) -+ -+#define COMPOSE_AUX_SW_DATA_0_7(address) \ -+ (0xFF & (address)) -+ -+static void submit_channel_request( -+ struct aux_engine *engine, -+ struct aux_request_transaction_data *request) -+{ -+ struct aux_engine_dce80 *aux_engine = FROM_AUX_ENGINE(engine); -+ uint32_t value; -+ uint32_t length; -+ -+ bool is_write = -+ ((request->type == AUX_TRANSACTION_TYPE_DP) && -+ (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) || -+ ((request->type == AUX_TRANSACTION_TYPE_I2C) && -+ ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || -+ (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); -+ -+ /* clear_aux_error */ -+ { -+ const uint32_t addr = mmAUXN_IMPCAL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUXN_IMPCAL, -+ AUXN_CALOUT_ERROR_AK); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUXN_IMPCAL, -+ AUXN_CALOUT_ERROR_AK); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ { -+ const uint32_t addr = mmAUXP_IMPCAL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUXP_IMPCAL, -+ AUXP_CALOUT_ERROR_AK); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUXP_IMPCAL, -+ AUXP_CALOUT_ERROR_AK); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ -+ /* force_default_calibrate */ -+ { -+ const uint32_t addr = mmAUXN_IMPCAL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUXN_IMPCAL, -+ AUXN_IMPCAL_ENABLE); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUXN_IMPCAL, -+ AUXN_IMPCAL_OVERRIDE_ENABLE); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ { -+ const uint32_t addr = mmAUXP_IMPCAL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUXP_IMPCAL, -+ AUXP_IMPCAL_OVERRIDE_ENABLE); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUXP_IMPCAL, -+ AUXP_IMPCAL_OVERRIDE_ENABLE); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ -+ /* set the delay and the number of bytes to write */ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_SW_CONTROL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ request->delay, -+ AUX_SW_CONTROL, -+ AUX_SW_START_DELAY); -+ -+ /* The length include -+ * the 4 bit header and the 20 bit address -+ * (that is 3 byte). -+ * If the requested length is non zero this means -+ * an addition byte specifying the length is required. */ -+ -+ length = request->length ? 4 : 3; -+ if (is_write) -+ length += request->length; -+ -+ set_reg_field_value( -+ value, -+ length, -+ AUX_SW_CONTROL, -+ AUX_SW_WR_BYTES); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ -+ /* program action and address and payload data (if 'is_write') */ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_SW_DATA; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUX_SW_DATA, -+ AUX_SW_INDEX); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUX_SW_DATA, -+ AUX_SW_DATA_RW); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_SW_DATA, -+ AUX_SW_AUTOINCREMENT_DISABLE); -+ -+ set_reg_field_value( -+ value, -+ COMPOSE_AUX_SW_DATA_16_20( -+ request->action, request->address), -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUX_SW_DATA, -+ AUX_SW_AUTOINCREMENT_DISABLE); -+ -+ set_reg_field_value( -+ value, -+ COMPOSE_AUX_SW_DATA_8_15(request->address), -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ COMPOSE_AUX_SW_DATA_0_7(request->address), -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ if (request->length) { -+ set_reg_field_value( -+ value, -+ request->length - 1, -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ -+ if (is_write) { -+ /* Load the HW buffer with the Data to be sent. -+ * This is relevant for write operation. -+ * For read, the data recived data will be -+ * processed in process_channel_reply(). */ -+ uint32_t i = 0; -+ -+ while (i < request->length) { -+ -+ set_reg_field_value( -+ value, -+ request->data[i], -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ dm_write_reg( -+ engine->base.ctx, addr, value); -+ -+ ++i; -+ } -+ } -+ } -+ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_INTERRUPT_CONTROL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_INTERRUPT_CONTROL, -+ AUX_SW_DONE_ACK); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_SW_CONTROL; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_SW_CONTROL, -+ AUX_SW_GO); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ } -+} -+ -+static void process_channel_reply( -+ struct aux_engine *engine, -+ struct aux_reply_transaction_data *reply) -+{ -+ struct aux_engine_dce80 *aux_engine = FROM_AUX_ENGINE(engine); -+ -+ /* Need to do a read to get the number of bytes to process -+ * Alternatively, this information can be passed - -+ * but that causes coupling which isn't good either. */ -+ -+ uint32_t bytes_replied; -+ uint32_t value; -+ -+ { -+ const uint32_t addr = aux_engine->addr.AUX_SW_STATUS; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ bytes_replied = get_reg_field_value( -+ value, -+ AUX_SW_STATUS, -+ AUX_SW_REPLY_BYTE_COUNT); -+ } -+ -+ if (bytes_replied) { -+ uint32_t reply_result; -+ -+ const uint32_t addr = aux_engine->addr.AUX_SW_DATA; -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ AUX_SW_DATA, -+ AUX_SW_INDEX); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_SW_DATA, -+ AUX_SW_AUTOINCREMENT_DISABLE); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ AUX_SW_DATA, -+ AUX_SW_DATA_RW); -+ -+ dm_write_reg(engine->base.ctx, addr, value); -+ -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ reply_result = get_reg_field_value( -+ value, -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ reply_result = reply_result >> 4; -+ -+ switch (reply_result) { -+ case 0: /* ACK */ { -+ uint32_t i = 0; -+ -+ /* first byte was already used -+ * to get the command status */ -+ --bytes_replied; -+ -+ while (i < bytes_replied) { -+ value = dm_read_reg( -+ engine->base.ctx, addr); -+ -+ reply->data[i] = get_reg_field_value( -+ value, -+ AUX_SW_DATA, -+ AUX_SW_DATA); -+ -+ ++i; -+ } -+ -+ reply->status = AUX_TRANSACTION_REPLY_AUX_ACK; -+ } -+ break; -+ case 1: /* NACK */ -+ reply->status = AUX_TRANSACTION_REPLY_AUX_NACK; -+ break; -+ case 2: /* DEFER */ -+ reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER; -+ break; -+ case 4: /* AUX ACK / I2C NACK */ -+ reply->status = AUX_TRANSACTION_REPLY_I2C_NACK; -+ break; -+ case 8: /* AUX ACK / I2C DEFER */ -+ reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER; -+ break; -+ default: -+ reply->status = AUX_TRANSACTION_REPLY_INVALID; -+ } -+ } else { -+ /* Need to handle an error case... -+ * hopefully, upper layer function won't call this function -+ * if the number of bytes in the reply was 0 -+ * because there was surely an error that was asserted -+ * that should have been handled -+ * for hot plug case, this could happens*/ -+ if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) -+ ASSERT_CRITICAL(false); -+ } -+} -+ -+static enum aux_channel_operation_result get_channel_status( -+ struct aux_engine *engine, -+ uint8_t *returned_bytes) -+{ -+ struct aux_engine_dce80 *aux_engine = FROM_AUX_ENGINE(engine); -+ -+ const uint32_t addr = aux_engine->addr.AUX_SW_STATUS; -+ -+ uint32_t value; -+ uint32_t aux_sw_done; -+ -+ if (returned_bytes == NULL) { -+ /*caller pass NULL pointer*/ -+ ASSERT_CRITICAL(false); -+ return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN; -+ } -+ *returned_bytes = 0; -+ -+ /* poll to make sure that SW_DONE is asserted */ -+ { -+ uint32_t time_elapsed = 0; -+ -+ do { -+ value = dm_read_reg(engine->base.ctx, addr); -+ -+ aux_sw_done = get_reg_field_value( -+ value, -+ AUX_SW_STATUS, -+ AUX_SW_DONE); -+ -+ if (aux_sw_done) -+ break; -+ -+ dm_delay_in_microseconds(engine->base.ctx, 10); -+ -+ time_elapsed += 10; -+ } while (time_elapsed < aux_engine->timeout_period); -+ -+ -+ } -+ -+ /* Note that the following bits are set in 'status.bits' -+ * during CTS 4.2.1.2: -+ * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP, -+ * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H. -+ * -+ * AUX_SW_RX_MIN_COUNT_VIOL is an internal, -+ * HW debugging bit and should be ignored. */ -+ if (aux_sw_done) { -+ if (get_reg_field_value( -+ value, -+ AUX_SW_STATUS, -+ AUX_SW_RX_TIMEOUT_STATE) || -+ get_reg_field_value( -+ value, -+ AUX_SW_STATUS, -+ AUX_SW_RX_TIMEOUT)) -+ return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; -+ else if (get_reg_field_value( -+ value, -+ AUX_SW_STATUS, -+ AUX_SW_RX_INVALID_STOP)) -+ return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY; -+ -+ *returned_bytes = get_reg_field_value( -+ value, -+ AUX_SW_STATUS, -+ AUX_SW_REPLY_BYTE_COUNT); -+ if (*returned_bytes == 0) -+ return -+ AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY; -+ else { -+ *returned_bytes -= 1; -+ return AUX_CHANNEL_OPERATION_SUCCEEDED; -+ } -+ } else { -+ /*time_elapsed >= aux_engine->timeout_period */ -+ if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) -+ ASSERT_CRITICAL(false); -+ return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; -+ } -+} -+ -+static const int32_t aux_channel_offset[] = { -+ mmDP_AUX0_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL, -+ mmDP_AUX1_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL, -+ mmDP_AUX2_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL, -+ mmDP_AUX3_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL, -+ mmDP_AUX4_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL, -+ mmDP_AUX5_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL -+}; -+ -+static const struct aux_engine_funcs aux_engine_funcs = { -+ .destroy = destroy, -+ .acquire_engine = acquire_engine, -+ .configure = configure, -+ .start_gtc_sync = start_gtc_sync, -+ .stop_gtc_sync = stop_gtc_sync, -+ .submit_channel_request = submit_channel_request, -+ .process_channel_reply = process_channel_reply, -+ .get_channel_status = get_channel_status, -+}; -+ -+static const struct engine_funcs engine_funcs = { -+ .release_engine = release_engine, -+ .submit_request = dal_aux_engine_submit_request, -+ .keep_power_up_count = dal_i2caux_keep_power_up_count, -+ .get_engine_type = dal_aux_engine_get_engine_type, -+ .acquire = dal_aux_engine_acquire, -+}; -+ -+static bool construct( -+ struct aux_engine_dce80 *engine, -+ const struct aux_engine_dce80_create_arg *arg) -+{ -+ int32_t offset; -+ -+ if (arg->engine_id >= sizeof(aux_channel_offset) / sizeof(int32_t)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ if (!dal_aux_engine_construct(&engine->base, arg->ctx)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ engine->base.base.funcs = &engine_funcs; -+ engine->base.funcs = &aux_engine_funcs; -+ offset = aux_channel_offset[arg->engine_id]; -+ engine->addr.AUX_CONTROL = mmAUX_CONTROL + offset; -+ engine->addr.AUX_ARB_CONTROL = mmAUX_ARB_CONTROL + offset; -+ engine->addr.AUX_SW_DATA = mmAUX_SW_DATA + offset; -+ engine->addr.AUX_SW_CONTROL = mmAUX_SW_CONTROL + offset; -+ engine->addr.AUX_INTERRUPT_CONTROL = mmAUX_INTERRUPT_CONTROL + offset; -+ engine->addr.AUX_SW_STATUS = mmAUX_SW_STATUS + offset; -+ engine->addr.AUX_GTC_SYNC_CONTROL = mmAUX_GTC_SYNC_CONTROL + offset; -+ engine->addr.AUX_GTC_SYNC_STATUS = mmAUX_GTC_SYNC_STATUS + offset; -+ engine->addr.AUX_GTC_SYNC_CONTROLLER_STATUS = -+ mmAUX_GTC_SYNC_CONTROLLER_STATUS + offset; -+ -+ engine->timeout_period = arg->timeout_period; -+ -+ return true; -+} -+ -+static void destruct( -+ struct aux_engine_dce80 *engine) -+{ -+ dal_aux_engine_destruct(&engine->base); -+} -+ -+struct aux_engine *dal_aux_engine_dce80_create( -+ const struct aux_engine_dce80_create_arg *arg) -+{ -+ struct aux_engine_dce80 *engine; -+ -+ if (!arg) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ engine = dm_alloc(arg->ctx, sizeof(struct aux_engine_dce80)); -+ -+ if (!engine) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(engine, arg)) -+ return &engine->base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(arg->ctx, engine); -+ -+ return NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.h -new file mode 100644 -index 0000000..8523c45 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/aux_engine_dce80.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_AUX_ENGINE_DCE80_H__ -+#define __DAL_AUX_ENGINE_DCE80_H__ -+ -+struct aux_engine_dce80 { -+ struct aux_engine base; -+ struct { -+ uint32_t AUX_CONTROL; -+ uint32_t AUX_ARB_CONTROL; -+ uint32_t AUX_SW_DATA; -+ uint32_t AUX_SW_CONTROL; -+ uint32_t AUX_INTERRUPT_CONTROL; -+ uint32_t AUX_SW_STATUS; -+ uint32_t AUX_GTC_SYNC_CONTROL; -+ uint32_t AUX_GTC_SYNC_STATUS; -+ uint32_t AUX_GTC_SYNC_CONTROLLER_STATUS; -+ } addr; -+ uint32_t timeout_period; -+}; -+ -+struct aux_engine_dce80_create_arg { -+ uint32_t engine_id; -+ uint32_t timeout_period; -+ struct dc_context *ctx; -+}; -+ -+struct aux_engine *dal_aux_engine_dce80_create( -+ const struct aux_engine_dce80_create_arg *arg); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.c -new file mode 100644 -index 0000000..3d61963 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.c -@@ -0,0 +1,901 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/i2caux_interface.h" -+#include "../engine.h" -+#include "../i2c_engine.h" -+#include "../i2c_hw_engine.h" -+#include "../i2c_generic_hw_engine.h" -+/* -+ * Header of this unit -+ */ -+ -+#include "i2c_hw_engine_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+/* -+ * This unit -+ */ -+ -+enum dc_i2c_status { -+ DC_I2C_STATUS__DC_I2C_STATUS_IDLE, -+ DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW, -+ DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW -+}; -+ -+enum dc_i2c_arbitration { -+ DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL, -+ DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH -+}; -+ -+enum { -+ /* No timeout in HW -+ * (timeout implemented in SW by querying status) */ -+ I2C_SETUP_TIME_LIMIT = 255, -+ I2C_HW_BUFFER_SIZE = 144 -+}; -+ -+/* -+ * @brief -+ * Cast 'struct i2c_hw_engine *' -+ * to 'struct i2c_hw_engine_dce80 *' -+ */ -+#define FROM_I2C_HW_ENGINE(ptr) \ -+ container_of((ptr), struct i2c_hw_engine_dce80, base) -+ -+/* -+ * @brief -+ * Cast pointer to 'struct i2c_engine *' -+ * to pointer to 'struct i2c_hw_engine_dce80 *' -+ */ -+#define FROM_I2C_ENGINE(ptr) \ -+ FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base)) -+ -+/* -+ * @brief -+ * Cast pointer to 'struct engine *' -+ * to 'pointer to struct i2c_hw_engine_dce80 *' -+ */ -+#define FROM_ENGINE(ptr) \ -+ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) -+ -+static void disable_i2c_hw_engine( -+ struct i2c_hw_engine_dce80 *engine) -+{ -+ const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; -+ uint32_t value = 0; -+ -+ struct dc_context *ctx = NULL; -+ -+ ctx = engine->base.base.base.ctx; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_ENABLE); -+ -+ dm_write_reg(ctx, addr, value); -+} -+ -+static void release_engine( -+ struct engine *engine) -+{ -+ struct i2c_hw_engine_dce80 *hw_engine = FROM_ENGINE(engine); -+ -+ struct i2c_engine *base = NULL; -+ bool safe_to_reset; -+ uint32_t value = 0; -+ -+ base = &hw_engine->base.base; -+ -+ /* Restore original HW engine speed */ -+ -+ base->funcs->set_speed(base, hw_engine->base.original_speed); -+ -+ /* Release I2C */ -+ { -+ value = dm_read_reg(engine->ctx, mmDC_I2C_ARBITRATION); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_ARBITRATION, -+ DC_I2C_SW_DONE_USING_I2C_REG); -+ -+ dm_write_reg(engine->ctx, mmDC_I2C_ARBITRATION, value); -+ } -+ -+ /* Reset HW engine */ -+ { -+ uint32_t i2c_sw_status = 0; -+ -+ value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); -+ -+ i2c_sw_status = get_reg_field_value( -+ value, -+ DC_I2C_SW_STATUS, -+ DC_I2C_SW_STATUS); -+ /* if used by SW, safe to reset */ -+ safe_to_reset = (i2c_sw_status == 1); -+ } -+ { -+ value = dm_read_reg(engine->ctx, mmDC_I2C_CONTROL); -+ -+ if (safe_to_reset) -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_CONTROL, -+ DC_I2C_SOFT_RESET); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_CONTROL, -+ DC_I2C_SW_STATUS_RESET); -+ -+ dm_write_reg(engine->ctx, mmDC_I2C_CONTROL, value); -+ } -+ -+ /* HW I2c engine - clock gating feature */ -+ if (!hw_engine->engine_keep_power_up_count) -+ disable_i2c_hw_engine(hw_engine); -+} -+ -+static void keep_power_up_count( -+ struct engine *engine, -+ bool keep_power_up) -+{ -+ struct i2c_hw_engine_dce80 *hw_engine = FROM_ENGINE(engine); -+ -+ if (keep_power_up) -+ ++hw_engine->engine_keep_power_up_count; -+ else { -+ --hw_engine->engine_keep_power_up_count; -+ -+ if (!hw_engine->engine_keep_power_up_count) -+ disable_i2c_hw_engine(hw_engine); -+ } -+} -+ -+static void destruct( -+ struct i2c_hw_engine_dce80 *engine) -+{ -+ dal_i2c_hw_engine_destruct(&engine->base); -+} -+ -+static void destroy( -+ struct i2c_engine **i2c_engine) -+{ -+ struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(*i2c_engine); -+ -+ destruct(engine); -+ -+ dm_free((*i2c_engine)->base.ctx, engine); -+ -+ *i2c_engine = NULL; -+} -+ -+static bool setup_engine( -+ struct i2c_engine *i2c_engine) -+{ -+ uint32_t value = 0; -+ struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine); -+ -+ /* Program pin select */ -+ { -+ const uint32_t addr = mmDC_I2C_CONTROL; -+ -+ value = dm_read_reg(i2c_engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_GO); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_SOFT_RESET); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_SEND_RESET); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_SW_STATUS_RESET); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_TRANSACTION_COUNT); -+ -+ set_reg_field_value( -+ value, -+ engine->engine_id, -+ DC_I2C_CONTROL, -+ DC_I2C_DDC_SELECT); -+ -+ -+ dm_write_reg(i2c_engine->base.ctx, addr, value); -+ } -+ -+ /* Program time limit */ -+ { -+ const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; -+ -+ value = dm_read_reg(i2c_engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ I2C_SETUP_TIME_LIMIT, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_TIME_LIMIT); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_ENABLE); -+ -+ dm_write_reg(i2c_engine->base.ctx, addr, value); -+ } -+ -+ /* Program HW priority -+ * set to High - interrupt software I2C at any time -+ * Enable restart of SW I2C that was interrupted by HW -+ * disable queuing of software while I2C is in use by HW */ -+ { -+ value = dm_read_reg(i2c_engine->base.ctx, -+ mmDC_I2C_ARBITRATION); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_ARBITRATION, -+ DC_I2C_NO_QUEUED_SW_GO); -+ -+ set_reg_field_value( -+ value, -+ DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL, -+ DC_I2C_ARBITRATION, -+ DC_I2C_SW_PRIORITY); -+ -+ dm_write_reg(i2c_engine->base.ctx, -+ mmDC_I2C_ARBITRATION, value); -+ } -+ -+ return true; -+} -+ -+static uint32_t get_speed( -+ const struct i2c_engine *i2c_engine) -+{ -+ const struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine); -+ -+ const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; -+ -+ uint32_t pre_scale = 0; -+ -+ uint32_t value = dm_read_reg(i2c_engine->base.ctx, addr); -+ -+ pre_scale = get_reg_field_value( -+ value, -+ DC_I2C_DDC1_SPEED, -+ DC_I2C_DDC1_PRESCALE); -+ -+ /* [anaumov] it seems following is unnecessary */ -+ /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/ -+ -+ return pre_scale ? -+ engine->reference_frequency / pre_scale : -+ engine->base.default_speed; -+} -+ -+static void set_speed( -+ struct i2c_engine *i2c_engine, -+ uint32_t speed) -+{ -+ struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine); -+ -+ if (speed) { -+ const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; -+ -+ uint32_t value = dm_read_reg(i2c_engine->base.ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ engine->reference_frequency / speed, -+ DC_I2C_DDC1_SPEED, -+ DC_I2C_DDC1_PRESCALE); -+ -+ set_reg_field_value( -+ value, -+ 2, -+ DC_I2C_DDC1_SPEED, -+ DC_I2C_DDC1_THRESHOLD); -+ -+ dm_write_reg(i2c_engine->base.ctx, addr, value); -+ } -+} -+ -+static inline void reset_hw_engine(struct engine *engine) -+{ -+ uint32_t value = dm_read_reg(engine->ctx, mmDC_I2C_CONTROL); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_CONTROL, -+ DC_I2C_SOFT_RESET); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_CONTROL, -+ DC_I2C_SW_STATUS_RESET); -+ -+ dm_write_reg(engine->ctx, mmDC_I2C_CONTROL, value); -+} -+ -+static bool is_hw_busy(struct engine *engine) -+{ -+ uint32_t i2c_sw_status = 0; -+ -+ uint32_t value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); -+ -+ i2c_sw_status = get_reg_field_value( -+ value, -+ DC_I2C_SW_STATUS, -+ DC_I2C_SW_STATUS); -+ -+ if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE) -+ return false; -+ -+ reset_hw_engine(engine); -+ -+ value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); -+ -+ i2c_sw_status = get_reg_field_value( -+ value, -+ DC_I2C_SW_STATUS, -+ DC_I2C_SW_STATUS); -+ -+ return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE; -+} -+ -+/* -+ * @brief -+ * DC_GPIO_DDC MM register offsets -+ */ -+static const uint32_t transaction_addr[] = { -+ mmDC_I2C_TRANSACTION0, -+ mmDC_I2C_TRANSACTION1, -+ mmDC_I2C_TRANSACTION2, -+ mmDC_I2C_TRANSACTION3 -+}; -+ -+static bool process_transaction( -+ struct i2c_hw_engine_dce80 *engine, -+ struct i2c_request_transaction_data *request) -+{ -+ uint8_t length = request->length; -+ uint8_t *buffer = request->data; -+ -+ bool last_transaction = false; -+ uint32_t value = 0; -+ -+ struct dc_context *ctx = NULL; -+ -+ ctx = engine->base.base.base.ctx; -+ -+ { -+ const uint32_t addr = -+ transaction_addr[engine->transaction_count]; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_TRANSACTION0, -+ DC_I2C_STOP_ON_NACK0); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_TRANSACTION0, -+ DC_I2C_START0); -+ -+ -+ if ((engine->transaction_count == 3) || -+ (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || -+ (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) { -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_TRANSACTION0, -+ DC_I2C_STOP0); -+ -+ last_transaction = true; -+ } else -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_TRANSACTION0, -+ DC_I2C_STOP0); -+ -+ set_reg_field_value( -+ value, -+ (0 != (request->action & -+ I2CAUX_TRANSACTION_ACTION_I2C_READ)), -+ DC_I2C_TRANSACTION0, -+ DC_I2C_RW0); -+ -+ set_reg_field_value( -+ value, -+ length, -+ DC_I2C_TRANSACTION0, -+ DC_I2C_COUNT0); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ /* Write the I2C address and I2C data -+ * into the hardware circular buffer, one byte per entry. -+ * As an example, the 7-bit I2C slave address for CRT monitor -+ * for reading DDC/EDID information is 0b1010001. -+ * For an I2C send operation, the LSB must be programmed to 0; -+ * for I2C receive operation, the LSB must be programmed to 1. */ -+ -+ { -+ value = 0; -+ -+ set_reg_field_value( -+ value, -+ false, -+ DC_I2C_DATA, -+ DC_I2C_DATA_RW); -+ -+ set_reg_field_value( -+ value, -+ request->address, -+ DC_I2C_DATA, -+ DC_I2C_DATA); -+ -+ if (engine->transaction_count == 0) { -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DATA, -+ DC_I2C_INDEX); -+ -+ /*enable index write*/ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_DATA, -+ DC_I2C_INDEX_WRITE); -+ } -+ -+ dm_write_reg(ctx, mmDC_I2C_DATA, value); -+ -+ if (!(request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) { -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DATA, -+ DC_I2C_INDEX_WRITE); -+ -+ while (length) { -+ -+ set_reg_field_value( -+ value, -+ *buffer++, -+ DC_I2C_DATA, -+ DC_I2C_DATA); -+ -+ dm_write_reg(ctx, mmDC_I2C_DATA, value); -+ --length; -+ } -+ } -+ } -+ -+ ++engine->transaction_count; -+ engine->buffer_used_bytes += length + 1; -+ -+ return last_transaction; -+} -+ -+static void execute_transaction( -+ struct i2c_hw_engine_dce80 *engine) -+{ -+ uint32_t value = 0; -+ struct dc_context *ctx = NULL; -+ -+ ctx = engine->base.base.base.ctx; -+ -+ { -+ const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_DATA_DRIVE_EN); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_CLK_DRIVE_EN); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_DATA_DRIVE_SEL); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_INTRA_TRANSACTION_DELAY); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_DDC1_SETUP, -+ DC_I2C_DDC1_INTRA_BYTE_DELAY); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ { -+ const uint32_t addr = mmDC_I2C_CONTROL; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_SOFT_RESET); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_SW_STATUS_RESET); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_SEND_RESET); -+ -+ set_reg_field_value( -+ value, -+ 0, -+ DC_I2C_CONTROL, -+ DC_I2C_GO); -+ -+ set_reg_field_value( -+ value, -+ engine->transaction_count - 1, -+ DC_I2C_CONTROL, -+ DC_I2C_TRANSACTION_COUNT); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ /* start I2C transfer */ -+ { -+ const uint32_t addr = mmDC_I2C_CONTROL; -+ -+ value = dm_read_reg(ctx, addr); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_CONTROL, -+ DC_I2C_GO); -+ -+ dm_write_reg(ctx, addr, value); -+ } -+ -+ /* all transactions were executed and HW buffer became empty -+ * (even though it actually happens when status becomes DONE) */ -+ engine->transaction_count = 0; -+ engine->buffer_used_bytes = 0; -+} -+ -+static void submit_channel_request( -+ struct i2c_engine *engine, -+ struct i2c_request_transaction_data *request) -+{ -+ request->status = I2C_CHANNEL_OPERATION_SUCCEEDED; -+ -+ if (!process_transaction(FROM_I2C_ENGINE(engine), request)) -+ return; -+ -+ if (is_hw_busy(&engine->base)) { -+ request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; -+ return; -+ } -+ -+ execute_transaction(FROM_I2C_ENGINE(engine)); -+} -+ -+static void process_channel_reply( -+ struct i2c_engine *engine, -+ struct i2c_reply_transaction_data *reply) -+{ -+ uint8_t length = reply->length; -+ uint8_t *buffer = reply->data; -+ -+ uint32_t value = 0; -+ -+ /*set index*/ -+ set_reg_field_value( -+ value, -+ length - 1, -+ DC_I2C_DATA, -+ DC_I2C_INDEX); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_DATA, -+ DC_I2C_DATA_RW); -+ -+ set_reg_field_value( -+ value, -+ 1, -+ DC_I2C_DATA, -+ DC_I2C_INDEX_WRITE); -+ -+ dm_write_reg(engine->base.ctx, mmDC_I2C_DATA, value); -+ -+ while (length) { -+ /* after reading the status, -+ * if the I2C operation executed successfully -+ * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller -+ * should read data bytes from I2C circular data buffer */ -+ -+ value = dm_read_reg(engine->base.ctx, mmDC_I2C_DATA); -+ -+ *buffer++ = get_reg_field_value( -+ value, -+ DC_I2C_DATA, -+ DC_I2C_DATA); -+ -+ --length; -+ } -+} -+ -+static enum i2c_channel_operation_result get_channel_status( -+ struct i2c_engine *engine, -+ uint8_t *returned_bytes) -+{ -+ uint32_t i2c_sw_status = 0; -+ uint32_t value = dm_read_reg(engine->base.ctx, mmDC_I2C_SW_STATUS); -+ -+ i2c_sw_status = get_reg_field_value( -+ value, -+ DC_I2C_SW_STATUS, -+ DC_I2C_SW_STATUS); -+ -+ if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW) -+ return I2C_CHANNEL_OPERATION_ENGINE_BUSY; -+ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_STOPPED_ON_NACK_MASK) -+ return I2C_CHANNEL_OPERATION_NO_RESPONSE; -+ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_TIMEOUT_MASK) -+ return I2C_CHANNEL_OPERATION_TIMEOUT; -+ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_ABORTED_MASK) -+ return I2C_CHANNEL_OPERATION_FAILED; -+ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_DONE_MASK) -+ return I2C_CHANNEL_OPERATION_SUCCEEDED; -+ -+ /* in DAL2, I2C_RESULT_OK was returned */ -+ return I2C_CHANNEL_OPERATION_NOT_STARTED; -+} -+ -+static uint8_t get_hw_buffer_available_size( -+ const struct i2c_hw_engine *engine) -+{ -+ return I2C_HW_BUFFER_SIZE - -+ FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes; -+} -+ -+static uint32_t get_transaction_timeout( -+ const struct i2c_hw_engine *engine, -+ uint32_t length) -+{ -+ uint32_t speed = engine->base.funcs->get_speed(&engine->base); -+ -+ uint32_t period_timeout; -+ uint32_t num_of_clock_stretches; -+ -+ if (!speed) -+ return 0; -+ -+ period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed; -+ -+ num_of_clock_stretches = 1 + (length << 3) + 1; -+ num_of_clock_stretches += -+ (FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes << 3) + -+ (FROM_I2C_HW_ENGINE(engine)->transaction_count << 1); -+ -+ return period_timeout * num_of_clock_stretches; -+} -+ -+/* -+ * @brief -+ * DC_I2C_DDC1_SETUP MM register offsets -+ * -+ * @note -+ * The indices of this offset array are DDC engine IDs -+ */ -+static const int32_t ddc_setup_offset[] = { -+ -+ mmDC_I2C_DDC1_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 1 */ -+ mmDC_I2C_DDC2_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 2 */ -+ mmDC_I2C_DDC3_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 3 */ -+ mmDC_I2C_DDC4_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 4 */ -+ mmDC_I2C_DDC5_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 5 */ -+ mmDC_I2C_DDC6_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 6 */ -+ mmDC_I2C_DDCVGA_SETUP - mmDC_I2C_DDC1_SETUP /* DDC Engine 7 */ -+}; -+ -+/* -+ * @brief -+ * DC_I2C_DDC1_SPEED MM register offsets -+ * -+ * @note -+ * The indices of this offset array are DDC engine IDs -+ */ -+static const int32_t ddc_speed_offset[] = { -+ mmDC_I2C_DDC1_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 1 */ -+ mmDC_I2C_DDC2_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 2 */ -+ mmDC_I2C_DDC3_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 3 */ -+ mmDC_I2C_DDC4_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 4 */ -+ mmDC_I2C_DDC5_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 5 */ -+ mmDC_I2C_DDC6_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 6 */ -+ mmDC_I2C_DDCVGA_SPEED - mmDC_I2C_DDC1_SPEED /* DDC Engine 7 */ -+}; -+ -+static const struct i2c_engine_funcs i2c_engine_funcs = { -+ .destroy = destroy, -+ .get_speed = get_speed, -+ .set_speed = set_speed, -+ .setup_engine = setup_engine, -+ .submit_channel_request = submit_channel_request, -+ .process_channel_reply = process_channel_reply, -+ .get_channel_status = get_channel_status, -+ .acquire_engine = dal_i2c_hw_engine_acquire_engine, -+}; -+ -+static const struct engine_funcs engine_funcs = { -+ .release_engine = release_engine, -+ .keep_power_up_count = keep_power_up_count, -+ .get_engine_type = dal_i2c_hw_engine_get_engine_type, -+ .acquire = dal_i2c_engine_acquire, -+ .submit_request = dal_i2c_hw_engine_submit_request, -+}; -+ -+static const struct i2c_hw_engine_funcs i2c_hw_engine_funcs = { -+ .get_hw_buffer_available_size = -+ get_hw_buffer_available_size, -+ .get_transaction_timeout = -+ get_transaction_timeout, -+ .wait_on_operation_result = -+ dal_i2c_hw_engine_wait_on_operation_result, -+}; -+ -+static bool construct( -+ struct i2c_hw_engine_dce80 *engine, -+ const struct i2c_hw_engine_dce80_create_arg *arg) -+{ -+ if (arg->engine_id >= sizeof(ddc_setup_offset) / sizeof(int32_t)) -+ return false; -+ if (arg->engine_id >= sizeof(ddc_speed_offset) / sizeof(int32_t)) -+ return false; -+ -+ if (!arg->reference_frequency) -+ return false; -+ -+ if (!dal_i2c_hw_engine_construct(&engine->base, arg->ctx)) -+ return false; -+ -+ engine->base.base.base.funcs = &engine_funcs; -+ engine->base.base.funcs = &i2c_engine_funcs; -+ engine->base.funcs = &i2c_hw_engine_funcs; -+ engine->base.default_speed = arg->default_speed; -+ engine->addr.DC_I2C_DDCX_SETUP = -+ mmDC_I2C_DDC1_SETUP + ddc_setup_offset[arg->engine_id]; -+ engine->addr.DC_I2C_DDCX_SPEED = -+ mmDC_I2C_DDC1_SPEED + ddc_speed_offset[arg->engine_id]; -+ -+ engine->engine_id = arg->engine_id; -+ engine->reference_frequency = arg->reference_frequency; -+ engine->buffer_used_bytes = 0; -+ engine->transaction_count = 0; -+ engine->engine_keep_power_up_count = 1; -+ -+ return true; -+} -+ -+struct i2c_engine *dal_i2c_hw_engine_dce80_create( -+ const struct i2c_hw_engine_dce80_create_arg *arg) -+{ -+ struct i2c_hw_engine_dce80 *engine; -+ -+ if (!arg) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ engine = dm_alloc(arg->ctx, sizeof(struct i2c_hw_engine_dce80)); -+ -+ if (!engine) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(engine, arg)) -+ return &engine->base.base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(arg->ctx, engine); -+ -+ return NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.h -new file mode 100644 -index 0000000..5c6116f ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_hw_engine_dce80.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_I2C_HW_ENGINE_DCE80_H__ -+#define __DAL_I2C_HW_ENGINE_DCE80_H__ -+ -+struct i2c_hw_engine_dce80 { -+ struct i2c_hw_engine base; -+ struct { -+ uint32_t DC_I2C_DDCX_SETUP; -+ uint32_t DC_I2C_DDCX_SPEED; -+ } addr; -+ uint32_t engine_id; -+ /* expressed in kilohertz */ -+ uint32_t reference_frequency; -+ /* number of bytes currently used in HW buffer */ -+ uint32_t buffer_used_bytes; -+ /* number of pending transactions (before GO) */ -+ uint32_t transaction_count; -+ uint32_t engine_keep_power_up_count; -+}; -+ -+struct i2c_hw_engine_dce80_create_arg { -+ uint32_t engine_id; -+ uint32_t reference_frequency; -+ uint32_t default_speed; -+ struct dc_context *ctx; -+}; -+ -+struct i2c_engine *dal_i2c_hw_engine_dce80_create( -+ const struct i2c_hw_engine_dce80_create_arg *arg); -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.c -new file mode 100644 -index 0000000..e5135c5 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.c -@@ -0,0 +1,187 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/i2caux_interface.h" -+#include "../engine.h" -+#include "../i2c_engine.h" -+#include "../i2c_sw_engine.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "i2c_sw_engine_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "dce/dce_8_0_d.h" -+#include "dce/dce_8_0_sh_mask.h" -+ -+/* -+ * This unit -+ */ -+ -+static const uint32_t ddc_hw_status_addr[] = { -+ mmDC_I2C_DDC1_HW_STATUS, -+ mmDC_I2C_DDC2_HW_STATUS, -+ mmDC_I2C_DDC3_HW_STATUS, -+ mmDC_I2C_DDC4_HW_STATUS, -+ mmDC_I2C_DDC5_HW_STATUS, -+ mmDC_I2C_DDC6_HW_STATUS, -+ mmDC_I2C_DDCVGA_HW_STATUS -+}; -+ -+ -+/* -+ * @brief -+ * Cast 'struct i2c_sw_engine *' -+ * to 'struct i2c_sw_engine_dce80 *' -+ */ -+#define FROM_I2C_SW_ENGINE(ptr) \ -+ container_of((ptr), struct i2c_sw_engine_dce80, base) -+ -+/* -+ * @brief -+ * Cast 'struct i2c_engine *' -+ * to 'struct i2c_sw_engine_dce80 *' -+ */ -+#define FROM_I2C_ENGINE(ptr) \ -+ FROM_I2C_SW_ENGINE(container_of((ptr), struct i2c_sw_engine, base)) -+ -+/* -+ * @brief -+ * Cast 'struct engine *' -+ * to 'struct i2c_sw_engine_dce80 *' -+ */ -+#define FROM_ENGINE(ptr) \ -+ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) -+ -+static void release_engine( -+ struct engine *engine) -+{ -+ -+} -+ -+static void destruct( -+ struct i2c_sw_engine_dce80 *engine) -+{ -+ dal_i2c_sw_engine_destruct(&engine->base); -+} -+ -+static void destroy( -+ struct i2c_engine **engine) -+{ -+ struct i2c_sw_engine_dce80 *sw_engine = FROM_I2C_ENGINE(*engine); -+ -+ destruct(sw_engine); -+ -+ dm_free((*engine)->base.ctx, sw_engine); -+ -+ *engine = NULL; -+} -+ -+ -+static bool acquire_engine( -+ struct i2c_engine *engine, -+ struct ddc *ddc_handle) -+{ -+ return dal_i2caux_i2c_sw_engine_acquire_engine(engine, ddc_handle); -+} -+ -+static const struct i2c_engine_funcs i2c_engine_funcs = { -+ .acquire_engine = acquire_engine, -+ .destroy = destroy, -+ .get_speed = dal_i2c_sw_engine_get_speed, -+ .set_speed = dal_i2c_sw_engine_set_speed, -+ .setup_engine = dal_i2c_engine_setup_i2c_engine, -+ .submit_channel_request = dal_i2c_sw_engine_submit_channel_request, -+ .process_channel_reply = dal_i2c_engine_process_channel_reply, -+ .get_channel_status = dal_i2c_sw_engine_get_channel_status, -+}; -+ -+static const struct engine_funcs engine_funcs = { -+ .release_engine = release_engine, -+ .get_engine_type = dal_i2c_sw_engine_get_engine_type, -+ .acquire = dal_i2c_engine_acquire, -+ .submit_request = dal_i2c_sw_engine_submit_request, -+ .keep_power_up_count = dal_i2caux_keep_power_up_count, -+}; -+ -+static bool construct( -+ struct i2c_sw_engine_dce80 *engine, -+ const struct i2c_sw_engine_dce80_create_arg *arg) -+{ -+ struct i2c_sw_engine_create_arg arg_base; -+ -+ arg_base.ctx = arg->ctx; -+ arg_base.default_speed = arg->default_speed; -+ -+ if (!dal_i2c_sw_engine_construct(&engine->base, &arg_base)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ engine->base.base.base.funcs = &engine_funcs; -+ engine->base.base.funcs = &i2c_engine_funcs; -+ engine->base.default_speed = arg->default_speed; -+ engine->engine_id = arg->engine_id; -+ -+ return true; -+} -+ -+struct i2c_engine *dal_i2c_sw_engine_dce80_create( -+ const struct i2c_sw_engine_dce80_create_arg *arg) -+{ -+ struct i2c_sw_engine_dce80 *engine; -+ -+ if (!arg) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ engine = dm_alloc(arg->ctx, sizeof(struct i2c_sw_engine_dce80)); -+ -+ if (!engine) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(engine, arg)) -+ return &engine->base.base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(arg->ctx, engine); -+ -+ return NULL; -+} -+ -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.h -new file mode 100644 -index 0000000..26355c0 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2c_sw_engine_dce80.h -@@ -0,0 +1,43 @@ -+/* -+ * 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_I2C_SW_ENGINE_DCE80_H__ -+#define __DAL_I2C_SW_ENGINE_DCE80_H__ -+ -+struct i2c_sw_engine_dce80 { -+ struct i2c_sw_engine base; -+ uint32_t engine_id; -+}; -+ -+struct i2c_sw_engine_dce80_create_arg { -+ uint32_t engine_id; -+ uint32_t default_speed; -+ struct dc_context *ctx; -+}; -+ -+struct i2c_engine *dal_i2c_sw_engine_dce80_create( -+ const struct i2c_sw_engine_dce80_create_arg *arg); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.c -new file mode 100644 -index 0000000..4abf488 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.c -@@ -0,0 +1,264 @@ -+/* -+ * 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" -+ -+/* -+ * Pre-requisites: headers required by header of this unit -+ */ -+#include "include/i2caux_interface.h" -+#include "../i2caux.h" -+ -+/* -+ * Header of this unit -+ */ -+ -+#include "i2caux_dce80.h" -+ -+/* -+ * Post-requisites: headers required by this unit -+ */ -+ -+#include "../engine.h" -+#include "../i2c_engine.h" -+#include "../i2c_sw_engine.h" -+#include "i2c_sw_engine_dce80.h" -+#include "../i2c_hw_engine.h" -+#include "i2c_hw_engine_dce80.h" -+#include "../i2c_generic_hw_engine.h" -+#include "../aux_engine.h" -+#include "aux_engine_dce80.h" -+ -+ -+/* -+ * This unit -+ */ -+ -+#define FROM_I2C_AUX(ptr) \ -+ container_of((ptr), struct i2caux_dce80, base) -+ -+static void destruct( -+ struct i2caux_dce80 *i2caux_dce80) -+{ -+ dal_i2caux_destruct(&i2caux_dce80->base); -+} -+ -+static void destroy( -+ struct i2caux **i2c_engine) -+{ -+ struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(*i2c_engine); -+ -+ destruct(i2caux_dce80); -+ -+ dm_free((*i2c_engine)->ctx, i2caux_dce80); -+ -+ *i2c_engine = NULL; -+} -+ -+static struct i2c_engine *acquire_i2c_hw_engine( -+ struct i2caux *i2caux, -+ struct ddc *ddc) -+{ -+ struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(i2caux); -+ -+ struct i2c_engine *engine = NULL; -+ bool non_generic; -+ -+ if (!ddc) -+ return NULL; -+ -+ if (dal_ddc_is_hw_supported(ddc)) { -+ enum gpio_ddc_line line = dal_ddc_get_line(ddc); -+ -+ if (line < GPIO_DDC_LINE_COUNT) { -+ non_generic = true; -+ engine = i2caux->i2c_hw_engines[line]; -+ } -+ } -+ -+ if (!engine) { -+ non_generic = false; -+ engine = i2caux->i2c_generic_hw_engine; -+ } -+ -+ if (!engine) -+ return NULL; -+ -+ if (non_generic) { -+ if (!i2caux_dce80->i2c_hw_buffer_in_use && -+ engine->base.funcs->acquire(&engine->base, ddc)) { -+ i2caux_dce80->i2c_hw_buffer_in_use = true; -+ return engine; -+ } -+ } else { -+ if (engine->base.funcs->acquire(&engine->base, ddc)) -+ return engine; -+ } -+ -+ return NULL; -+} -+ -+static void release_engine( -+ struct i2caux *i2caux, -+ struct engine *engine) -+{ -+ if (engine->funcs->get_engine_type(engine) == -+ I2CAUX_ENGINE_TYPE_I2C_DDC_HW) -+ FROM_I2C_AUX(i2caux)->i2c_hw_buffer_in_use = false; -+ -+ dal_i2caux_release_engine(i2caux, engine); -+} -+ -+static const enum gpio_ddc_line hw_ddc_lines[] = { -+ GPIO_DDC_LINE_DDC1, -+ GPIO_DDC_LINE_DDC2, -+ GPIO_DDC_LINE_DDC3, -+ GPIO_DDC_LINE_DDC4, -+ GPIO_DDC_LINE_DDC5, -+ GPIO_DDC_LINE_DDC6, -+ GPIO_DDC_LINE_DDC_VGA -+}; -+ -+static const enum gpio_ddc_line hw_aux_lines[] = { -+ GPIO_DDC_LINE_DDC1, -+ GPIO_DDC_LINE_DDC2, -+ GPIO_DDC_LINE_DDC3, -+ GPIO_DDC_LINE_DDC4, -+ GPIO_DDC_LINE_DDC5, -+ GPIO_DDC_LINE_DDC6 -+}; -+ -+static const struct i2caux_funcs i2caux_funcs = { -+ .destroy = destroy, -+ .acquire_i2c_hw_engine = acquire_i2c_hw_engine, -+ .release_engine = release_engine, -+ .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine, -+ .acquire_aux_engine = dal_i2caux_acquire_aux_engine, -+}; -+ -+static bool construct( -+ struct i2caux_dce80 *i2caux_dce80, -+ struct adapter_service *as, -+ struct dc_context *ctx) -+{ -+ /* Entire family have I2C engine reference clock frequency -+ * changed from XTALIN (27) to XTALIN/2 (13.5) */ -+ -+ struct i2caux *base = &i2caux_dce80->base; -+ -+ uint32_t reference_frequency = -+ dal_i2caux_get_reference_clock(as) >> 1; -+ -+ bool use_i2c_sw_engine = dal_adapter_service_is_feature_supported( -+ FEATURE_RESTORE_USAGE_I2C_SW_ENGINE); -+ -+ uint32_t i; -+ -+ if (!dal_i2caux_construct(base, as, ctx)) { -+ BREAK_TO_DEBUGGER(); -+ return false; -+ } -+ -+ i2caux_dce80->base.funcs = &i2caux_funcs; -+ i2caux_dce80->i2c_hw_buffer_in_use = false; -+ -+ /* Create I2C HW engines (HW + SW pairs) -+ * for all lines which has assisted HW DDC -+ * 'i' (loop counter) used as DDC/AUX engine_id */ -+ -+ i = 0; -+ -+ do { -+ enum gpio_ddc_line line_id = hw_ddc_lines[i]; -+ -+ struct i2c_hw_engine_dce80_create_arg hw_arg; -+ -+ if (use_i2c_sw_engine) { -+ struct i2c_sw_engine_dce80_create_arg sw_arg; -+ -+ sw_arg.engine_id = i; -+ sw_arg.default_speed = base->default_i2c_sw_speed; -+ sw_arg.ctx = ctx; -+ base->i2c_sw_engines[line_id] = -+ dal_i2c_sw_engine_dce80_create(&sw_arg); -+ } -+ -+ hw_arg.engine_id = i; -+ hw_arg.reference_frequency = reference_frequency; -+ hw_arg.default_speed = base->default_i2c_hw_speed; -+ hw_arg.ctx = ctx; -+ -+ base->i2c_hw_engines[line_id] = -+ dal_i2c_hw_engine_dce80_create(&hw_arg); -+ -+ ++i; -+ } while (i < ARRAY_SIZE(hw_ddc_lines)); -+ -+ /* Create AUX engines for all lines which has assisted HW AUX -+ * 'i' (loop counter) used as DDC/AUX engine_id */ -+ -+ i = 0; -+ -+ do { -+ enum gpio_ddc_line line_id = hw_aux_lines[i]; -+ -+ struct aux_engine_dce80_create_arg arg; -+ -+ arg.engine_id = i; -+ arg.timeout_period = base->aux_timeout_period; -+ arg.ctx = ctx; -+ -+ base->aux_engines[line_id] = -+ dal_aux_engine_dce80_create(&arg); -+ -+ ++i; -+ } while (i < ARRAY_SIZE(hw_aux_lines)); -+ -+ /* TODO Generic I2C SW and HW */ -+ -+ return true; -+} -+ -+struct i2caux *dal_i2caux_dce80_create( -+ struct adapter_service *as, -+ struct dc_context *ctx) -+{ -+ struct i2caux_dce80 *i2caux_dce80 = -+ dm_alloc(ctx, sizeof(struct i2caux_dce80)); -+ -+ if (!i2caux_dce80) { -+ BREAK_TO_DEBUGGER(); -+ return NULL; -+ } -+ -+ if (construct(i2caux_dce80, as, ctx)) -+ return &i2caux_dce80->base; -+ -+ BREAK_TO_DEBUGGER(); -+ -+ dm_free(ctx, i2caux_dce80); -+ -+ return NULL; -+} -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.h -new file mode 100644 -index 0000000..85417a8 ---- /dev/null -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce80/i2caux_dce80.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_I2C_AUX_DCE80_H__ -+#define __DAL_I2C_AUX_DCE80_H__ -+ -+struct i2caux_dce80 { -+ struct i2caux base; -+ /* indicate the I2C HW circular buffer is in use */ -+ bool i2c_hw_buffer_in_use; -+}; -+ -+struct i2caux *dal_i2caux_dce80_create( -+ struct adapter_service *as, -+ struct dc_context *ctx); -+ -+#endif -diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c -index 4c2f2cb..47e7922 100644 ---- a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c -+++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c -@@ -48,6 +48,10 @@ - * This unit - */ - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+#include "dce80/i2caux_dce80.h" -+#endif -+ - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) || defined(CONFIG_DRM_AMD_DAL_DCE10_0) - #include "dce110/i2caux_dce110.h" - #endif -@@ -79,6 +83,10 @@ struct i2caux *dal_i2caux_create( - } - - switch (dce_version) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ return dal_i2caux_dce80_create(as, ctx); -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: -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 1372331..3e2f232 100644 ---- a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c -+++ b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c -@@ -32,6 +32,13 @@ - #include "dce110/irq_service_dce110.h" - #endif - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ /* -+ * TODO: implement DCE8.x IRQ service -+ */ -+#include "dce110/irq_service_dce110.h" -+#endif -+ - #include "irq_service.h" - - bool dal_irq_service_construct( -@@ -50,6 +57,10 @@ struct irq_service *dal_irq_service_create( - struct irq_service_init_data *init_data) - { - switch (version) { -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ case DCE_VERSION_8_0: -+ return dal_irq_service_dce110_create(init_data); -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - case DCE_VERSION_10_0: - return dal_irq_service_dce110_create(init_data); -diff --git a/drivers/gpu/drm/amd/dal/include/dal_types.h b/drivers/gpu/drm/amd/dal/include/dal_types.h -index 3739776..8fdde70 100644 ---- a/drivers/gpu/drm/amd/dal/include/dal_types.h -+++ b/drivers/gpu/drm/amd/dal/include/dal_types.h -@@ -34,6 +34,9 @@ struct dc_bios; - - enum dce_version { - DCE_VERSION_UNKNOWN = (-1), -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+ DCE_VERSION_8_0, -+#endif - #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) - DCE_VERSION_10_0, - #endif -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 009b583..a621930 100644 ---- a/drivers/gpu/drm/amd/dal/include/display_clock_interface.h -+++ b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h -@@ -143,6 +143,12 @@ struct display_clock *dal_display_clock_dce80_create( - struct adapter_service *as); - #endif - -+#if defined(CONFIG_DRM_AMD_DAL_DCE8_0) -+struct display_clock *dal_display_clock_dce80_create( -+ struct dc_context *ctx, -+ struct adapter_service *as); -+#endif -+ - void dal_display_clock_destroy(struct display_clock **to_destroy); - bool dal_display_clock_validate( - struct display_clock *disp_clk, --- -2.7.4 - |