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