[PATCH v2 11/26] drm/amd/dal: Audio
Harry Wentland
harry.wentland at amd.com
Tue Feb 16 22:27:51 UTC 2016
Responsible for programming the audio encoder in the display path.
Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
---
drivers/gpu/drm/amd/dal/dc/audio/Makefile | 22 +
drivers/gpu/drm/amd/dal/dc/audio/audio.h | 195 ++
drivers/gpu/drm/amd/dal/dc/audio/audio_base.c | 470 +++++
.../gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c | 453 +++++
.../gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h | 42 +
.../amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c | 1930 ++++++++++++++++++++
.../amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h | 47 +
drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c | 771 ++++++++
drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h | 285 +++
9 files changed, 4215 insertions(+)
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/Makefile
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/audio.h
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c
create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/Makefile b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
new file mode 100644
index 000000000000..0999372cecf0
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the 'audio' sub-component of DAL.
+# It provides the control and status of HW adapter resources,
+# that are global for the ASIC and sharable between pipes.
+
+AUDIO = audio_base.o hw_ctx_audio.o
+
+AMD_DAL_AUDIO = $(addprefix $(AMDDALPATH)/dc/audio/,$(AUDIO))
+
+AMD_DAL_FILES += $(AMD_DAL_AUDIO)
+
+
+###############################################################################
+# DCE 11x
+###############################################################################
+ifdef CONFIG_DRM_AMD_DAL_DCE11_0
+AUDIO_DCE11 = audio_dce110.o hw_ctx_audio_dce110.o
+
+AMD_DAL_AUDIO_DCE11 = $(addprefix $(AMDDALPATH)/dc/audio/dce110/,$(AUDIO_DCE11))
+
+AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE11)
+endif
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/audio.h b/drivers/gpu/drm/amd/dal/dc/audio/audio.h
new file mode 100644
index 000000000000..ad2dc18ef37b
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/audio.h
@@ -0,0 +1,195 @@
+/*
+ * 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_H__
+#define __DAL_AUDIO_H__
+
+#include "include/audio_interface.h"
+#include "hw_ctx_audio.h"
+#include "include/link_service_types.h"
+
+/***** only for hook functions *****/
+/**
+ *which will be overwritten by derived audio object.
+ *audio hw context object is independent object
+ */
+
+struct audio;
+
+struct audio_funcs {
+ /*
+ *get_object_id
+ *get_object_type
+ *enumerate_input_signals
+ *enumerate_output_signals
+ *is_input_signal_supported
+ *is_output_signal_supported
+ *set_object_properties
+ *get_object_properties
+ */
+
+ void (*destroy)(struct audio **audio);
+ /*power_up
+ *power_down
+ *release_hw_base
+ */
+
+ /* setup audio */
+ enum audio_result (*setup)(
+ struct audio *audio,
+ struct audio_output *output,
+ struct audio_info *info);
+
+ enum audio_result (*enable_output)(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal);
+
+ enum audio_result (*disable_output)(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal);
+
+ /*enable_azalia_audio_jack_presence
+ * disable_azalia_audio_jack_presence
+ */
+
+ enum audio_result (*unmute)(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal);
+
+ enum audio_result (*mute)(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal);
+
+ /* SW initialization that cannot be done in constructor. This will
+ * be done is audio_power_up but is not in audio_interface. It is only
+ * called by power_up
+ */
+ enum audio_result (*initialize)(
+ struct audio *audio);
+
+ /* enable channel splitting mapping */
+ 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);
+
+ /* get current multi channel split. */
+ enum audio_result (*get_channel_splitting_mapping)(
+ struct audio *audio,
+ enum engine_id engine_id,
+ struct audio_channel_associate_info *audio_mapping);
+
+ /* set payload value for the unsolicited response */
+ void (*set_unsolicited_response_payload)(
+ struct audio *audio,
+ enum audio_payload payload);
+
+ /* Update audio wall clock source */
+ 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);
+
+ /* options and features supported by Audio */
+ struct audio_feature_support (*get_supported_features)(
+ struct audio *audio);
+
+ /*
+ *check_audio_bandwidth
+ *write_reg
+ *read_reg
+ *enable_gtc_embedding_with_group
+ *disable_gtc_embedding
+ *register_interrupt
+ *unregister_interrupt
+ *process_interrupt
+ *create_hw_ctx
+ *getHwCtx
+ *setHwCtx
+ *handle_interrupt
+ */
+};
+
+struct audio {
+ /* hook functions. they will be overwritten by specific ASIC */
+ const struct audio_funcs *funcs;
+ /* TODO: static struct audio_funcs funcs;*/
+
+ /*external structures - get service from external*/
+ struct graphics_object_id id;
+ struct adapter_service *adapter_service;
+ /* audio HW context */
+ struct hw_ctx_audio *hw_ctx;
+ struct dc_context *ctx;
+ /* audio supports input and output signals */
+ uint32_t input_signals;
+ uint32_t output_signals;
+};
+
+/* - functions defined by audio.h will be used by audio component only.
+ * but audio.c also implements some function defined by dal\include
+ */
+
+/* graphics_object_base implemention
+ * 1.input_signals and output_signals are moved
+ * into audio object.
+ *
+ * 2.Get the Graphics Object ID
+ *
+ * Outside audio:
+ * use dal_graphics_object_id_get_audio_id
+ * Within audio:
+ * use audio->go_base.id
+ *
+ * 3. Get the Graphics Object Type
+ *
+ * use object_id.type
+ * not function implemented.
+ * 4. Common Graphics Object Properties
+ * use object id ->go_properties.multi_path
+ * not function implemented.
+ */
+
+bool dal_audio_construct_base(
+ struct audio *audio,
+ const struct audio_init_data *init_data);
+
+void dal_audio_destruct_base(
+ struct audio *audio);
+
+void dal_audio_release_hw_base(
+ struct audio *audio);
+
+#endif /* __DAL_AUDIO__ */
+
+
+
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
new file mode 100644
index 000000000000..bfd6725d9b91
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
@@ -0,0 +1,470 @@
+/*
+ * 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.h"
+#include "hw_ctx_audio.h"
+
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+#include "dce110/audio_dce110.h"
+#include "dce110/hw_ctx_audio_dce110.h"
+#endif
+
+/***** static function : only used within audio.c *****/
+
+/* stub for hook functions */
+static void destroy(
+ struct audio **audio)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+static enum audio_result setup(
+ struct audio *audio,
+ struct audio_output *output,
+ struct audio_info *info)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+static enum audio_result enable_output(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+static enum audio_result disable_output(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+static enum audio_result unmute(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+static enum audio_result mute(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+static enum audio_result initialize(
+ struct audio *audio)
+{
+ /*DCE specific, must be implemented in derived. Implemeentaion of
+ *initialize will create audio hw context. create_hw_ctx
+ */
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return AUDIO_RESULT_OK;
+}
+
+/* set payload value for the unsolicited response */
+static void set_unsolicited_response_payload(
+ struct audio *audio,
+ enum audio_payload payload)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* update audio wall clock source */
+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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+static struct audio_feature_support get_supported_features(struct audio *audio)
+{
+ /*DCE specific, must be implemented in derived*/
+ struct audio_feature_support features;
+
+ dm_memset(&features, 0, sizeof(features));
+
+ features.ENGINE_DIGA = 1;
+ features.ENGINE_DIGB = 1;
+
+ return features;
+}
+
+static const struct audio_funcs audio_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,
+};
+
+/***** SCOPE : declare in audio.h. use within dal-audio. *****/
+
+bool dal_audio_construct_base(
+ struct audio *audio,
+ const struct audio_init_data *init_data)
+{
+ enum signal_type signals = SIGNAL_TYPE_HDMI_TYPE_A;
+
+ ASSERT(init_data->as != NULL);
+
+ /* base hook functions */
+ audio->funcs = &audio_funcs;
+
+ /*setup pointers to get service from dal service compoenents*/
+ audio->adapter_service = init_data->as;
+
+ audio->ctx = init_data->ctx;
+
+ /* save audio endpoint number to identify object creating */
+ audio->id = init_data->audio_stream_id;
+
+ /* Fill supported signals. !!! be aware that android definition is
+ * already shift to vector.
+ */
+ signals |= SIGNAL_TYPE_DISPLAY_PORT;
+ signals |= SIGNAL_TYPE_DISPLAY_PORT_MST;
+ signals |= SIGNAL_TYPE_EDP;
+ signals |= SIGNAL_TYPE_DISPLAY_PORT;
+ signals |= SIGNAL_TYPE_WIRELESS;
+
+ /* Audio supports same set for input and output signals */
+ audio->input_signals = signals;
+ audio->output_signals = signals;
+
+ return true;
+}
+
+/* except hw_ctx, no other hw need reset. so do nothing */
+void dal_audio_destruct_base(
+ struct audio *audio)
+{
+}
+
+/* Enumerate Graphics Object supported Input/Output Signal Types */
+uint32_t dal_audio_enumerate_input_signals(
+ struct audio *audio)
+{
+ return audio->input_signals;
+}
+
+uint32_t dal_audio_enumerate_output_signals(
+ struct audio *audio)
+{
+ return audio->output_signals;
+}
+
+/* Check if signal supported by GraphicsObject */
+bool dal_audio_is_input_signal_supported(
+ struct audio *audio,
+ enum signal_type signal)
+{
+ return (signal & audio->output_signals) != 0;
+}
+
+bool dal_audio_is_output_signal_supported(
+ struct audio *audio,
+ enum signal_type signal)
+{
+ return (signal & audio->input_signals) != 0;
+}
+
+/***** SCOPE : declare in dal\include *****/
+
+/* audio object creator triage. memory allocate and release will be
+ * done within dal_audio_create_dcexx
+ */
+struct audio *dal_audio_create(
+ const struct audio_init_data *init_data)
+{
+ struct adapter_service *as;
+
+ if (init_data->as == NULL)
+ return NULL;
+
+ as = init_data->as;
+ switch (dal_adapter_service_get_dce_version(as)) {
+#if defined(CONFIG_DRM_AMD_DAL_DCE10_0)
+ case DCE_VERSION_10_0:
+ return dal_audio_create_dce110(init_data);
+#endif
+#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
+ case DCE_VERSION_11_0:
+ return dal_audio_create_dce110(init_data);
+#endif
+ default:
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/* audio object creator triage.
+ * memory for "struct audio dal_audio_create_dce8x" allocate
+ * will happens within dal_audio_dce8x. memory allocate is done
+ * with dal_audio_create_dce8x. memory release is initiated by
+ * dal_audio_destroy. It will call hook function which will finially
+ * used destroy() of dal_audio_dce8x. therefore, no memroy allocate
+ *and release happen physcially at audio base object.
+ */
+void dal_audio_destroy(
+ struct audio **audio)
+{
+ if (!audio || !*audio) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ (*audio)->funcs->destroy(audio);
+
+ *audio = NULL;
+}
+
+const struct graphics_object_id dal_audio_get_graphics_object_id(
+ const struct audio *audio)
+{
+ return audio->id;
+}
+
+/* enable azalia audio endpoint. This function call hw_ctx directly
+ *not overwitten at audio level.
+ */
+enum audio_result dal_audio_enable_azalia_audio_jack_presence(
+ struct audio *audio,
+ enum engine_id engine_id)
+{
+ audio->hw_ctx->funcs->enable_azalia_audio(audio->hw_ctx, engine_id);
+ return AUDIO_RESULT_OK;
+}
+
+/* disable azalia audio endpoint. This function call hw_ctx directly
+ *not overwitten at audio level.
+ */
+enum audio_result dal_audio_disable_azalia_audio_jack_presence(
+ struct audio *audio,
+ enum engine_id engine_id)
+{
+ audio->hw_ctx->funcs->disable_azalia_audio(audio->hw_ctx, engine_id);
+ return AUDIO_RESULT_OK;
+}
+
+/* get audio bandwidth information. This function call hw_ctx directly
+ *not overwitten at audio level.
+ */
+void dal_audio_check_audio_bandwidth(
+ struct audio *audio,
+ const struct audio_crtc_info *info,
+ uint32_t channel_count,
+ enum signal_type signal,
+ union audio_sample_rates *sample_rates)
+{
+ dal_hw_ctx_audio_check_audio_bandwidth(
+ audio->hw_ctx, info, channel_count, signal, sample_rates);
+}
+
+/* DP Audio register write access. This function call hw_ctx directly
+ * not overwitten at audio level.
+ */
+
+/*assign GTC group and enable GTC value embedding*/
+void dal_audio_enable_gtc_embedding_with_group(
+ struct audio *audio,
+ uint32_t group_num,
+ uint32_t audio_latency)
+{
+ audio->hw_ctx->funcs->enable_gtc_embedding_with_group(
+ audio->hw_ctx, group_num, audio_latency);
+}
+
+/* disable GTC value embedding */
+void dal_audio_disable_gtc_embedding(
+ struct audio *audio)
+{
+ audio->hw_ctx->funcs->disable_gtc_embedding(audio->hw_ctx);
+}
+
+/* perform power up sequence (boot up, resume, recovery) */
+enum audio_result dal_audio_power_up(
+ struct audio *audio)
+{
+ return audio->funcs->initialize(audio);
+}
+
+/* perform power down (shut down, stand by) */
+enum audio_result dal_audio_power_down(
+ struct audio *audio)
+{
+ return AUDIO_RESULT_OK;
+}
+
+/* setup audio */
+enum audio_result dal_audio_setup(
+ struct audio *audio,
+ struct audio_output *output,
+ struct audio_info *info)
+{
+ return audio->funcs->setup(audio, output, info);
+}
+
+/* enable audio */
+enum audio_result dal_audio_enable_output(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ return audio->funcs->enable_output(audio, engine_id, signal);
+}
+
+/* disable audio */
+enum audio_result dal_audio_disable_output(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ return audio->funcs->disable_output(audio, engine_id, signal);
+}
+
+/* unmute audio */
+enum audio_result dal_audio_unmute(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ return audio->funcs->unmute(audio, engine_id, signal);
+}
+
+/* mute audio */
+enum audio_result dal_audio_mute(
+ struct audio *audio,
+ enum engine_id engine_id,
+ enum signal_type signal)
+{
+ return audio->funcs->mute(audio, engine_id, signal);
+}
+
+/* Enable multi channel split */
+void dal_audio_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->funcs->enable_channel_splitting_mapping(
+ audio, engine_id, signal, audio_mapping, enable);
+}
+
+/* get current multi channel split. */
+enum audio_result dal_audio_get_channel_splitting_mapping(
+ struct audio *audio,
+ enum engine_id engine_id,
+ struct audio_channel_associate_info *audio_mapping)
+{
+ return audio->funcs->get_channel_splitting_mapping(
+ audio, engine_id, audio_mapping);
+}
+
+/* set payload value for the unsolicited response */
+void dal_audio_set_unsolicited_response_payload(
+ struct audio *audio,
+ enum audio_payload payload)
+{
+ audio->funcs->set_unsolicited_response_payload(audio, payload);
+}
+
+/* update audio wall clock source */
+void dal_audio_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->funcs->setup_audio_wall_dto(audio, signal, crtc_info, pll_info);
+}
+
+struct audio_feature_support dal_audio_get_supported_features(
+ struct audio *audio)
+{
+ return audio->funcs->get_supported_features(audio);
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c
new file mode 100644
index 000000000000..1aa0c1e61b32
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c
@@ -0,0 +1,453 @@
+/*
+ * 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_dce110.h"
+
+/***** static functions *****/
+
+static void destruct(struct audio_dce110 *audio)
+{
+ /*release memory allocated for hw_ctx -- allocated is initiated
+ *by audio_dce110 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_dce110 *audio = NULL;
+
+ audio = container_of(*ptr, struct audio_dce110, base);
+
+ destruct(audio);
+
+ /* release memory allocated for audio_dce110*/
+ dm_free((*ptr)->ctx, audio);
+ *ptr = NULL;
+}
+
+
+/* The inital call of hook function comes from audio object level.
+ *The passing object handle "struct audio *audio" point to base object
+ *already.There is not need to get base object from audio_dce110.
+ */
+
+/**
+* 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_dce110_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_dce110 *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_dce110(
+ const struct audio_init_data *init_data)
+{
+ /*allocate memory for audio_dce110 */
+ struct audio_dce110 *audio = dm_alloc(init_data->ctx, sizeof(*audio));
+
+ if (audio == NULL) {
+ ASSERT_CRITICAL(audio);
+ return NULL;
+ }
+ /*pointer to base_audio_block of audio_dce110 ==> 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(init_data->ctx, audio);
+ return NULL;
+}
+
+/* Do not need expose construct_dce110 and destruct_dce110 becuase there is
+ *derived object after dce110
+ */
+
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h
new file mode 100644
index 000000000000..e5ff823368b3
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.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 __DAL_AUDIO_DCE_110_H__
+#define __DAL_AUDIO_DCE_110_H__
+
+#include "audio/audio.h"
+#include "audio/hw_ctx_audio.h"
+#include "audio/dce110/hw_ctx_audio_dce110.h"
+
+
+
+struct audio_dce110 {
+ struct audio base;
+ /* dce-specific members are following */
+ /* none */
+};
+
+struct audio *dal_audio_create_dce110(const struct audio_init_data *init_data);
+
+#endif /*__DAL_AUDIO_DCE_110_H__*/
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c
new file mode 100644
index 000000000000..f24b964bdd8d
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c
@@ -0,0 +1,1930 @@
+/*
+ * 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_dce110.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+#define FROM_BASE(ptr) \
+ container_of((ptr), struct hw_ctx_audio_dce110, 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
+};
+
+static void destruct(
+ struct hw_ctx_audio_dce110 *hw_ctx_dce110)
+{
+ dal_audio_destruct_hw_ctx_audio(&hw_ctx_dce110->base);
+}
+
+static void destroy(
+ struct hw_ctx_audio **ptr)
+{
+ struct hw_ctx_audio_dce110 *hw_ctx_dce110;
+
+ hw_ctx_dce110 = container_of(
+ *ptr, struct hw_ctx_audio_dce110, base);
+
+ destruct(hw_ctx_dce110);
+ /* release memory allocated for struct hw_ctx_audio_dce110 */
+ dm_free((*ptr)->ctx, hw_ctx_dce110);
+
+ *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.*/
+ dm_delay_in_microseconds(hw_ctx->ctx, 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_dce110 *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 dce110 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_dce110 is derived from audio directly, not via dce80 */
+struct hw_ctx_audio *dal_hw_ctx_audio_dce110_create(
+ struct dc_context *ctx,
+ uint32_t azalia_stream_id)
+{
+ /* allocate memory for struc hw_ctx_audio_dce110 */
+ struct hw_ctx_audio_dce110 *hw_ctx_dce110 =
+ dm_alloc(ctx, sizeof(struct hw_ctx_audio_dce110));
+
+ if (!hw_ctx_dce110) {
+ ASSERT_CRITICAL(hw_ctx_dce110);
+ return NULL;
+ }
+
+ /*return pointer to hw_ctx_audio back to caller -- audio object */
+ if (construct(
+ hw_ctx_dce110, azalia_stream_id, ctx))
+ return &hw_ctx_dce110->base;
+
+ dal_logger_write(
+ ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_AUDIO,
+ "Failed to create hw_ctx_audio for DCE11\n");
+
+
+ dm_free(ctx, hw_ctx_dce110);
+
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h
new file mode 100644
index 000000000000..1ad3826aeb9f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.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_DCE110_H__
+#define __DAL_HW_CTX_AUDIO_DCE110_H__
+
+#include "audio/hw_ctx_audio.h"
+
+struct hw_ctx_audio_dce110 {
+ 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_dce110_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/audio/hw_ctx_audio.c b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c
new file mode 100644
index 000000000000..58207f53bff1
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c
@@ -0,0 +1,771 @@
+/*
+ * 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_audio.h"
+
+/* 25.2MHz/1.001*/
+/* 25.2MHz/1.001*/
+/* 25.2MHz*/
+/* 27MHz */
+/* 27MHz*1.001*/
+/* 27MHz*1.001*/
+/* 54MHz*/
+/* 54MHz*1.001*/
+/* 74.25MHz/1.001*/
+/* 74.25MHz*/
+/* 148.5MHz/1.001*/
+/* 148.5MHz*/
+
+static const struct audio_clock_info audio_clock_info_table[12] = {
+ {2517, 4576, 28125, 7007, 31250, 6864, 28125},
+ {2518, 4576, 28125, 7007, 31250, 6864, 28125},
+ {2520, 4096, 25200, 6272, 28000, 6144, 25200},
+ {2700, 4096, 27000, 6272, 30000, 6144, 27000},
+ {2702, 4096, 27027, 6272, 30030, 6144, 27027},
+ {2703, 4096, 27027, 6272, 30030, 6144, 27027},
+ {5400, 4096, 54000, 6272, 60000, 6144, 54000},
+ {5405, 4096, 54054, 6272, 60060, 6144, 54054},
+ {7417, 11648, 210937, 17836, 234375, 11648, 140625},
+ {7425, 4096, 74250, 6272, 82500, 6144, 74250},
+ {14835, 11648, 421875, 8918, 234375, 5824, 140625},
+ {14850, 4096, 148500, 6272, 165000, 6144, 148500}
+};
+
+static const struct audio_clock_info audio_clock_info_table_36bpc[12] = {
+ {2517, 9152, 84375, 7007, 48875, 9152, 56250},
+ {2518, 9152, 84375, 7007, 48875, 9152, 56250},
+ {2520, 4096, 37800, 6272, 42000, 6144, 37800},
+ {2700, 4096, 40500, 6272, 45000, 6144, 40500},
+ {2702, 8192, 81081, 6272, 45045, 8192, 54054},
+ {2703, 8192, 81081, 6272, 45045, 8192, 54054},
+ {5400, 4096, 81000, 6272, 90000, 6144, 81000},
+ {5405, 4096, 81081, 6272, 90090, 6144, 81081},
+ {7417, 11648, 316406, 17836, 351562, 11648, 210937},
+ {7425, 4096, 111375, 6272, 123750, 6144, 111375},
+ {14835, 11648, 632812, 17836, 703125, 11648, 421875},
+ {14850, 4096, 222750, 6272, 247500, 6144, 222750}
+};
+
+static const struct audio_clock_info audio_clock_info_table_48bpc[12] = {
+ {2517, 4576, 56250, 7007, 62500, 6864, 56250},
+ {2518, 4576, 56250, 7007, 62500, 6864, 56250},
+ {2520, 4096, 50400, 6272, 56000, 6144, 50400},
+ {2700, 4096, 54000, 6272, 60000, 6144, 54000},
+ {2702, 4096, 54054, 6267, 60060, 8192, 54054},
+ {2703, 4096, 54054, 6272, 60060, 8192, 54054},
+ {5400, 4096, 108000, 6272, 120000, 6144, 108000},
+ {5405, 4096, 108108, 6272, 120120, 6144, 108108},
+ {7417, 11648, 421875, 17836, 468750, 11648, 281250},
+ {7425, 4096, 148500, 6272, 165000, 6144, 148500},
+ {14835, 11648, 843750, 8918, 468750, 11648, 281250},
+ {14850, 4096, 297000, 6272, 330000, 6144, 297000}
+};
+
+
+/***** static function *****/
+
+/*
+ * except of HW context create function, caller will access other functions of
+ * hw ctx via handle hw_ctx. Memory allocation for struct hw_ctx_audio_dce8x
+ * will happen in hw_ctx_audio_dce8x. Memory allocation is done with
+ * dal_audio_create_hw_ctx_audio_dce8x. Memory release is done by caller
+ * via hw_ctx->functions.destroy(). It will finally use destroy() of
+ * hw_ctx_audio_dce8x. Therefore, no memory allocate and release happen
+ * physically at hw ctx base object.
+ */
+static void destroy(
+ struct hw_ctx_audio **ptr)
+{
+ /* Attention!
+ * You must override this method in derived class */
+}
+
+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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+ /* setup DP audio */
+static void setup_dp_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+ /* setup VCE audio */
+static void setup_vce_audio(
+ const struct hw_ctx_audio *hw_ctx)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* enable Azalia audio */
+static void enable_azalia_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* disable Azalia audio */
+static void disable_azalia_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* enable DP audio */
+static void enable_dp_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* disable DP audio */
+static void disable_dp_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* unmute audio */
+static void unmute_azalia_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* mute audio */
+static void mute_azalia_audio(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* initialize HW state */
+static void hw_initialize(
+ const struct hw_ctx_audio *hw_ctx)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* Assign GTC group and enable GTC value embedding */
+static void enable_gtc_embedding_with_group(
+ const struct hw_ctx_audio *hw_ctx,
+ uint32_t groupNum,
+ uint32_t audioLatency)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* Disable GTC value embedding */
+static void disable_gtc_embedding(
+ const struct hw_ctx_audio *hw_ctx)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* Disable Azalia Clock Gating Feature */
+static void disable_az_clock_gating(
+ const struct hw_ctx_audio *hw_ctx)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return false;
+}
+
+/* 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)
+{
+ /*DCE specific, must be implemented in derived*/
+ BREAK_TO_DEBUGGER();
+ return false;
+}
+
+
+
+
+
+
+
+
+
+/*****SCOPE : within audio hw context dal-audio-hw-ctx *****/
+
+
+/* check whether specified sample rates can fit into a given timing */
+void dal_hw_ctx_audio_check_audio_bandwidth(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ enum signal_type signal,
+ union audio_sample_rates *sample_rates)
+{
+ switch (signal) {
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ dal_audio_hw_ctx_check_audio_bandwidth_hdmi(
+ hw_ctx, crtc_info, channel_count, sample_rates);
+ break;
+ case SIGNAL_TYPE_EDP:
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ dal_audio_hw_ctx_check_audio_bandwidth_dpsst(
+ hw_ctx, crtc_info, channel_count, sample_rates);
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ dal_audio_hw_ctx_check_audio_bandwidth_dpmst(
+ hw_ctx, crtc_info, channel_count, sample_rates);
+ break;
+ default:
+ break;
+ }
+}
+
+/*For HDMI, calculate if specified sample rates can fit into a given timing */
+void dal_audio_hw_ctx_check_audio_bandwidth_hdmi(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ union audio_sample_rates *sample_rates)
+{
+ uint32_t samples;
+ uint32_t h_blank;
+ bool limit_freq_to_48_khz = false;
+ bool limit_freq_to_88_2_khz = false;
+ bool limit_freq_to_96_khz = false;
+ bool limit_freq_to_174_4_khz = false;
+
+ /* For two channels supported return whatever sink support,unmodified*/
+ if (channel_count > 2) {
+
+ /* Based on HDMI spec 1.3 Table 7.5 */
+ if ((crtc_info->requested_pixel_clock <= 27000) &&
+ (crtc_info->v_active <= 576) &&
+ !(crtc_info->interlaced) &&
+ !(crtc_info->pixel_repetition == 2 ||
+ crtc_info->pixel_repetition == 4)) {
+ limit_freq_to_48_khz = true;
+
+ } else if ((crtc_info->requested_pixel_clock <= 27000) &&
+ (crtc_info->v_active <= 576) &&
+ (crtc_info->interlaced) &&
+ (crtc_info->pixel_repetition == 2)) {
+ limit_freq_to_88_2_khz = true;
+
+ } else if ((crtc_info->requested_pixel_clock <= 54000) &&
+ (crtc_info->v_active <= 576) &&
+ !(crtc_info->interlaced)) {
+ limit_freq_to_174_4_khz = true;
+ }
+ }
+
+ /* Also do some calculation for the available Audio Bandwidth for the
+ * 8 ch (i.e. for the Layout 1 => ch > 2)
+ */
+ h_blank = crtc_info->h_total - crtc_info->h_active;
+
+ if (crtc_info->pixel_repetition)
+ h_blank *= crtc_info->pixel_repetition;
+
+ /*based on HDMI spec 1.3 Table 7.5 */
+ h_blank -= 58;
+ /*for Control Period */
+ h_blank -= 16;
+
+ samples = h_blank * 10;
+ /* Number of Audio Packets (multiplied by 10) per Line (for 8 ch number
+ * of Audio samples per line multiplied by 10 - Layout 1)
+ */
+ samples /= 32;
+ samples *= crtc_info->v_active;
+ /*Number of samples multiplied by 10, per second */
+ samples *= crtc_info->refresh_rate;
+ /*Number of Audio samples per second */
+ samples /= 10;
+
+ /* @todo do it after deep color is implemented
+ * 8xx - deep color bandwidth scaling
+ * Extra bandwidth is avaliable in deep color b/c link runs faster than
+ * pixel rate. This has the effect of allowing more tmds characters to
+ * be transmitted during blank
+ */
+
+ switch (crtc_info->color_depth) {
+ case COLOR_DEPTH_888:
+ samples *= 4;
+ break;
+ case COLOR_DEPTH_101010:
+ samples *= 5;
+ break;
+ case COLOR_DEPTH_121212:
+ samples *= 6;
+ break;
+ default:
+ samples *= 4;
+ break;
+ }
+
+ samples /= 4;
+
+ /*check limitation*/
+ if (samples < 88200)
+ limit_freq_to_48_khz = true;
+ else if (samples < 96000)
+ limit_freq_to_88_2_khz = true;
+ else if (samples < 176400)
+ limit_freq_to_96_khz = true;
+ else if (samples < 192000)
+ limit_freq_to_174_4_khz = true;
+
+ if (sample_rates != NULL) {
+ /* limit frequencies */
+ if (limit_freq_to_174_4_khz)
+ sample_rates->rate.RATE_192 = 0;
+
+ if (limit_freq_to_96_khz) {
+ sample_rates->rate.RATE_192 = 0;
+ sample_rates->rate.RATE_176_4 = 0;
+ }
+ if (limit_freq_to_88_2_khz) {
+ sample_rates->rate.RATE_192 = 0;
+ sample_rates->rate.RATE_176_4 = 0;
+ sample_rates->rate.RATE_96 = 0;
+ }
+ if (limit_freq_to_48_khz) {
+ sample_rates->rate.RATE_192 = 0;
+ sample_rates->rate.RATE_176_4 = 0;
+ sample_rates->rate.RATE_96 = 0;
+ sample_rates->rate.RATE_88_2 = 0;
+ }
+ }
+}
+
+/*For DP SST, calculate if specified sample rates can fit into a given timing */
+void dal_audio_hw_ctx_check_audio_bandwidth_dpsst(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ union audio_sample_rates *sample_rates)
+{
+ /* do nothing */
+}
+
+/*For DP MST, calculate if specified sample rates can fit into a given timing */
+void dal_audio_hw_ctx_check_audio_bandwidth_dpmst(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ union audio_sample_rates *sample_rates)
+{
+ /* do nothing */
+}
+
+/* calculate max number of Audio packets per line */
+uint32_t dal_audio_hw_ctx_calc_max_audio_packets_per_line(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info)
+{
+ uint32_t max_packets_per_line;
+
+ max_packets_per_line =
+ crtc_info->h_total - crtc_info->h_active;
+
+ if (crtc_info->pixel_repetition)
+ max_packets_per_line *= crtc_info->pixel_repetition;
+
+ /* for other hdmi features */
+ max_packets_per_line -= 58;
+ /* for Control Period */
+ max_packets_per_line -= 16;
+ /* Number of Audio Packets per Line */
+ max_packets_per_line /= 32;
+
+ return max_packets_per_line;
+}
+
+/**
+* speakersToChannels
+*
+* @brief
+* translate speakers to channels
+*
+* FL - Front Left
+* FR - Front Right
+* RL - Rear Left
+* RR - Rear Right
+* RC - Rear Center
+* FC - Front Center
+* FLC - Front Left Center
+* FRC - Front Right Center
+* RLC - Rear Left Center
+* RRC - Rear Right Center
+* LFE - Low Freq Effect
+*
+* FC
+* FLC FRC
+* FL FR
+*
+* LFE
+* ()
+*
+*
+* RL RR
+* RLC RRC
+* RC
+*
+* ch 8 7 6 5 4 3 2 1
+* 0b00000011 - - - - - - FR FL
+* 0b00000111 - - - - - LFE FR FL
+* 0b00001011 - - - - FC - FR FL
+* 0b00001111 - - - - FC LFE FR FL
+* 0b00010011 - - - RC - - FR FL
+* 0b00010111 - - - RC - LFE FR FL
+* 0b00011011 - - - RC FC - FR FL
+* 0b00011111 - - - RC FC LFE FR FL
+* 0b00110011 - - RR RL - - FR FL
+* 0b00110111 - - RR RL - LFE FR FL
+* 0b00111011 - - RR RL FC - FR FL
+* 0b00111111 - - RR RL FC LFE FR FL
+* 0b01110011 - RC RR RL - - FR FL
+* 0b01110111 - RC RR RL - LFE FR FL
+* 0b01111011 - RC RR RL FC - FR FL
+* 0b01111111 - RC RR RL FC LFE FR FL
+* 0b11110011 RRC RLC RR RL - - FR FL
+* 0b11110111 RRC RLC RR RL - LFE FR FL
+* 0b11111011 RRC RLC RR RL FC - FR FL
+* 0b11111111 RRC RLC RR RL FC LFE FR FL
+* 0b11000011 FRC FLC - - - - FR FL
+* 0b11000111 FRC FLC - - - LFE FR FL
+* 0b11001011 FRC FLC - - FC - FR FL
+* 0b11001111 FRC FLC - - FC LFE FR FL
+* 0b11010011 FRC FLC - RC - - FR FL
+* 0b11010111 FRC FLC - RC - LFE FR FL
+* 0b11011011 FRC FLC - RC FC - FR FL
+* 0b11011111 FRC FLC - RC FC LFE FR FL
+* 0b11110011 FRC FLC RR RL - - FR FL
+* 0b11110111 FRC FLC RR RL - LFE FR FL
+* 0b11111011 FRC FLC RR RL FC - FR FL
+* 0b11111111 FRC FLC RR RL FC LFE FR FL
+*
+* @param
+* speakers - speaker information as it comes from CEA audio block
+*/
+/* translate speakers to channels */
+union audio_cea_channels dal_audio_hw_ctx_speakers_to_channels(
+ const struct hw_ctx_audio *hw_ctx,
+ struct audio_speaker_flags speaker_flags)
+{
+ union audio_cea_channels cea_channels = {0};
+
+ /* these are one to one */
+ cea_channels.channels.FL = speaker_flags.FL_FR;
+ cea_channels.channels.FR = speaker_flags.FL_FR;
+ cea_channels.channels.LFE = speaker_flags.LFE;
+ cea_channels.channels.FC = speaker_flags.FC;
+
+ /* if Rear Left and Right exist move RC speaker to channel 7
+ * otherwise to channel 5
+ */
+ if (speaker_flags.RL_RR) {
+ cea_channels.channels.RL_RC = speaker_flags.RL_RR;
+ cea_channels.channels.RR = speaker_flags.RL_RR;
+ cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
+ } else {
+ cea_channels.channels.RL_RC = speaker_flags.RC;
+ }
+
+ /* FRONT Left Right Center and REAR Left Right Center are exclusive */
+ if (speaker_flags.FLC_FRC) {
+ cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
+ cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
+ } else {
+ cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
+ cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
+ }
+
+ return cea_channels;
+}
+
+/* check whether specified audio format supported */
+bool dal_audio_hw_ctx_is_audio_format_supported(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_info *audio_info,
+ enum audio_format_code audio_format_code,
+ uint32_t *format_index)
+{
+ uint32_t index;
+ uint32_t max_channe_index = 0;
+ bool found = false;
+
+ if (audio_info == NULL)
+ return found;
+
+ /* pass through whole array */
+ for (index = 0; index < audio_info->mode_count; index++) {
+ if (audio_info->modes[index].format_code == audio_format_code) {
+ if (found) {
+ /* format has multiply entries, choose one with
+ * highst number of channels */
+ if (audio_info->modes[index].channel_count >
+ audio_info->modes[max_channe_index].channel_count) {
+ max_channe_index = index;
+ }
+ } else {
+ /* format found, save it's index */
+ found = true;
+ max_channe_index = index;
+ }
+ }
+ }
+
+ /* return index */
+ if (found && format_index != NULL)
+ *format_index = max_channe_index;
+
+ return found;
+}
+
+/* search pixel clock value for HDMI */
+bool dal_audio_hw_ctx_get_audio_clock_info(
+ const struct hw_ctx_audio *hw_ctx,
+ enum dc_color_depth color_depth,
+ uint32_t crtc_pixel_clock_in_khz,
+ uint32_t actual_pixel_clock_in_khz,
+ struct audio_clock_info *audio_clock_info)
+{
+ const struct audio_clock_info *clock_info;
+ uint32_t index;
+ uint32_t crtc_pixel_clock_in_10khz = crtc_pixel_clock_in_khz / 10;
+ uint32_t audio_array_size;
+
+ if (audio_clock_info == NULL)
+ return false; /* should not happen */
+
+ switch (color_depth) {
+ case COLOR_DEPTH_161616:
+ clock_info = audio_clock_info_table_48bpc;
+ audio_array_size = ARRAY_SIZE(
+ audio_clock_info_table_48bpc);
+ break;
+ case COLOR_DEPTH_121212:
+ clock_info = audio_clock_info_table_36bpc;
+ audio_array_size = ARRAY_SIZE(
+ audio_clock_info_table_36bpc);
+ break;
+ default:
+ clock_info = audio_clock_info_table;
+ audio_array_size = ARRAY_SIZE(
+ audio_clock_info_table);
+ break;
+ }
+
+ if (clock_info != NULL) {
+ /* search for exact pixel clock in table */
+ for (index = 0; index < audio_array_size; index++) {
+ if (clock_info[index].pixel_clock_in_10khz >
+ crtc_pixel_clock_in_10khz)
+ break; /* not match */
+ else if (clock_info[index].pixel_clock_in_10khz ==
+ crtc_pixel_clock_in_10khz) {
+ /* match found */
+ if (audio_clock_info != NULL) {
+ *audio_clock_info = clock_info[index];
+ return true;
+ }
+ }
+ }
+ }
+
+
+ /* not found */
+ if (actual_pixel_clock_in_khz == 0)
+ actual_pixel_clock_in_khz = crtc_pixel_clock_in_khz;
+
+ /* See HDMI spec the table entry under
+ * pixel clock of "Other". */
+ audio_clock_info->pixel_clock_in_10khz =
+ actual_pixel_clock_in_khz / 10;
+ audio_clock_info->cts_32khz = actual_pixel_clock_in_khz;
+ audio_clock_info->cts_44khz = actual_pixel_clock_in_khz;
+ audio_clock_info->cts_48khz = actual_pixel_clock_in_khz;
+
+ audio_clock_info->n_32khz = 4096;
+ audio_clock_info->n_44khz = 6272;
+ audio_clock_info->n_48khz = 6144;
+
+ return true;
+}
+
+static const struct hw_ctx_audio_funcs funcs = {
+ .destroy = destroy,
+ .setup_audio_wall_dto =
+ setup_audio_wall_dto,
+ .setup_hdmi_audio =
+ setup_hdmi_audio,
+ .setup_dp_audio = setup_dp_audio,
+ .setup_vce_audio = setup_vce_audio,
+ .enable_azalia_audio =
+ enable_azalia_audio,
+ .disable_azalia_audio =
+ disable_azalia_audio,
+ .enable_dp_audio =
+ enable_dp_audio,
+ .disable_dp_audio =
+ disable_dp_audio,
+ .setup_azalia =
+ setup_azalia,
+ .disable_az_clock_gating =
+ disable_az_clock_gating,
+ .unmute_azalia_audio =
+ unmute_azalia_audio,
+ .mute_azalia_audio =
+ mute_azalia_audio,
+ .setup_channel_splitting_mapping =
+ setup_channel_splitting_mapping,
+ .get_channel_splitting_mapping =
+ get_channel_splitting_mapping,
+ .set_unsolicited_response_payload =
+ set_unsolicited_response_payload,
+ .hw_initialize =
+ hw_initialize,
+ .enable_gtc_embedding_with_group =
+ enable_gtc_embedding_with_group,
+ .disable_gtc_embedding =
+ disable_gtc_embedding,
+ .get_azalia_clock_info_hdmi =
+ get_azalia_clock_info_hdmi,
+ .get_azalia_clock_info_dp =
+ get_azalia_clock_info_dp,
+};
+/* --- object creator, destroy, construct, destruct --- */
+
+bool dal_audio_construct_hw_ctx_audio(
+ struct hw_ctx_audio *ctx)
+{
+ ctx->funcs = &funcs;
+
+ /* internal variables */
+
+ return true;
+}
+
+void dal_audio_destruct_hw_ctx_audio(
+ struct hw_ctx_audio *ctx)
+{
+ /* nothing to do */
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h
new file mode 100644
index 000000000000..8ab2e5851f91
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h
@@ -0,0 +1,285 @@
+/*
+ * 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_H__
+#define __DAL_HW_CTX_AUDIO_H__
+
+#include "include/audio_interface.h"
+#include "include/link_service_types.h"
+
+struct hw_ctx_audio;
+
+
+struct azalia_reg_offsets {
+ uint32_t azf0endpointx_azalia_f0_codec_endpoint_index;
+ uint32_t azf0endpointx_azalia_f0_codec_endpoint_data;
+};
+
+/***** hook functions *****/
+
+struct hw_ctx_audio_funcs {
+
+ /* functions for hw_ctx creation */
+ void (*destroy)(
+ struct hw_ctx_audio **ptr);
+
+ /***** from dal2 hwcontextaudio.hpp *****/
+
+ 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);
+
+ /* MM register access read_register write_register */
+
+ /***** from dal2 hwcontextaudio_hal.hpp *****/
+
+ /* setup HDMI audio */
+ void (*setup_hdmi_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id,
+ const struct audio_crtc_info *crtc_info);
+
+ /* setup DP audio */
+ void (*setup_dp_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* setup VCE audio */
+ void (*setup_vce_audio)(
+ const struct hw_ctx_audio *hw_ctx);
+
+ /* enable Azalia audio */
+ void (*enable_azalia_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* disable Azalia audio */
+ void (*disable_azalia_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* enable DP audio */
+ void (*enable_dp_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* disable DP audio */
+ void (*disable_dp_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* setup Azalia HW block */
+ 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);
+
+ /* unmute audio */
+ void (*unmute_azalia_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* mute audio */
+ void (*mute_azalia_audio)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id);
+
+ /* enable channel splitting mapping */
+ 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);
+
+ /* get current channel spliting */
+ bool (*get_channel_splitting_mapping)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id,
+ struct audio_channel_associate_info *audio_mapping);
+
+ /* set the payload value for the unsolicited response */
+ void (*set_unsolicited_response_payload)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum audio_payload payload);
+
+ /* initialize HW state */
+ void (*hw_initialize)(
+ const struct hw_ctx_audio *hw_ctx);
+
+ /* check_audio_bandwidth */
+
+ /* Assign GTC group and enable GTC value embedding */
+ void (*enable_gtc_embedding_with_group)(
+ const struct hw_ctx_audio *hw_ctx,
+ uint32_t groupNum,
+ uint32_t audioLatency);
+
+ /* Disable GTC value embedding */
+ void (*disable_gtc_embedding)(
+ const struct hw_ctx_audio *hw_ctx);
+
+ /* Disable Azalia Clock Gating Feature */
+ void (*disable_az_clock_gating)(
+ const struct hw_ctx_audio *hw_ctx);
+
+ /* ~~~~ protected: ~~~~*/
+
+ /* calc_max_audio_packets_per_line */
+ /* speakers_to_channels */
+ /* is_audio_format_supported */
+ /* get_audio_clock_info */
+
+ /* search pixel clock value for Azalia HDMI Audio */
+ 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);
+
+ /* search pixel clock value for Azalia DP Audio */
+ 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);
+
+ void (*enable_afmt_clock)(
+ const struct hw_ctx_audio *hw_ctx,
+ enum engine_id engine_id,
+ bool enable);
+
+ /* @@@@ private: @@@@ */
+
+ /* check_audio_bandwidth_hdmi */
+ /* check_audio_bandwidth_dpsst */
+ /* check_audio_bandwidth_dpmst */
+
+};
+
+
+struct hw_ctx_audio {
+ const struct hw_ctx_audio_funcs *funcs;
+ struct dc_context *ctx;
+
+ /*audio_clock_infoTable[12];
+ *audio_clock_infoTable_36bpc[12];
+ *audio_clock_infoTable_48bpc[12];
+ *used by hw_ctx_audio.c file only. Will declare as static array
+ *azaliaclockinfoTable[12] -- not used
+ *BusNumberMask; BusNumberShift; DeviceNumberMask;
+ *not used by dce6 and after
+ */
+};
+
+
+
+/* --- object construct, destruct --- */
+
+/*
+ *called by derived audio object for specific ASIC. In case no derived object,
+ *these two functions do not need exposed.
+ */
+bool dal_audio_construct_hw_ctx_audio(
+ struct hw_ctx_audio *hw_ctx);
+
+void dal_audio_destruct_hw_ctx_audio(
+ struct hw_ctx_audio *hw_ctx);
+
+/*
+ *creator of audio HW context will be implemented by specific ASIC object only.
+ *Top base or interface object does not have implementation of creator.
+ */
+
+
+/* --- functions called by audio hw context itself --- */
+
+/* MM register access */
+/*read_register - dal_read_reg */
+/*write_register - dal_write_reg*/
+
+
+/*check whether specified sample rates can fit into a given timing */
+void dal_hw_ctx_audio_check_audio_bandwidth(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ enum signal_type signal,
+ union audio_sample_rates *sample_rates);
+
+/*For HDMI, calculate if specified sample rates can fit into a given timing */
+void dal_audio_hw_ctx_check_audio_bandwidth_hdmi(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ union audio_sample_rates *sample_rates);
+
+/*For DPSST, calculate if specified sample rates can fit into a given timing */
+void dal_audio_hw_ctx_check_audio_bandwidth_dpsst(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ union audio_sample_rates *sample_rates);
+
+/*For DPMST, calculate if specified sample rates can fit into a given timing */
+void dal_audio_hw_ctx_check_audio_bandwidth_dpmst(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info,
+ uint32_t channel_count,
+ union audio_sample_rates *sample_rates);
+
+/* calculate max number of Audio packets per line */
+uint32_t dal_audio_hw_ctx_calc_max_audio_packets_per_line(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_crtc_info *crtc_info);
+
+/* translate speakers to channels */
+union audio_cea_channels dal_audio_hw_ctx_speakers_to_channels(
+ const struct hw_ctx_audio *hw_ctx,
+ struct audio_speaker_flags speaker_flags);
+
+/* check whether specified audio format supported */
+bool dal_audio_hw_ctx_is_audio_format_supported(
+ const struct hw_ctx_audio *hw_ctx,
+ const struct audio_info *audio_info,
+ enum audio_format_code audio_format_code,
+ uint32_t *format_index);
+
+/* search pixel clock value for HDMI */
+bool dal_audio_hw_ctx_get_audio_clock_info(
+ const struct hw_ctx_audio *hw_ctx,
+ enum dc_color_depth color_depth,
+ uint32_t crtc_pixel_clock_in_khz,
+ uint32_t actual_pixel_clock_in_khz,
+ struct audio_clock_info *audio_clock_info);
+
+
+#endif /* __DAL_HW_CTX_AUDIO_H__ */
+
--
2.1.4
More information about the dri-devel
mailing list