aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2857-drm-amd-display-Add-drm_audio_component-support-to-a.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2857-drm-amd-display-Add-drm_audio_component-support-to-a.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2857-drm-amd-display-Add-drm_audio_component-support-to-a.patch391
1 files changed, 391 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2857-drm-amd-display-Add-drm_audio_component-support-to-a.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2857-drm-amd-display-Add-drm_audio_component-support-to-a.patch
new file mode 100644
index 00000000..9d9f83a6
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/2857-drm-amd-display-Add-drm_audio_component-support-to-a.patch
@@ -0,0 +1,391 @@
+From c79327ffed56ef394c0ed766f8f3aa73207744c9 Mon Sep 17 00:00:00 2001
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Date: Fri, 28 Jun 2019 13:41:56 -0400
+Subject: [PATCH 2857/2940] drm/amd/display: Add drm_audio_component support to
+ amdgpu_dm
+
+[Why]
+The drm_audio_component can be used to give pin ELD notifications
+directly to the sound driver. This fixes audio endpoints disappearing
+due to missing unsolicited notifications.
+
+[How]
+Send the notification via the audio component whenever we enable or
+disable audio state on a stream. This matches what i915 does with
+their drm_audio_component and what Takashi Iwai's proposed hack for
+radeon/amdpgu did.
+
+This is a bit delayed in when the notification actually occurs, however.
+We wait until after all the programming is complete rather than sending
+the notification mid sequence.
+
+Particular care is needed for the get ELD callback since it can happen
+outside the locking and fencing DRM does for atomic commits.
+
+Change-Id: I5943cd04329514193a28d25ceedcb25e4fd07ff4
+Cc: Leo Li <sunpeng.li@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Takashi Iwai <tiwai@suse.de>
+---
+ drivers/gpu/drm/amd/display/Kconfig | 1 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 223 ++++++++++++++++++
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 25 ++
+ 3 files changed, 249 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
+index 33e7efbb4ef4..48c7423e92da 100644
+--- a/drivers/gpu/drm/amd/display/Kconfig
++++ b/drivers/gpu/drm/amd/display/Kconfig
+@@ -4,6 +4,7 @@ menu "Display Engine Configuration"
+ config DRM_AMD_DC
+ bool "AMD DC - Enable new display engine"
+ default y
++ select SND_HDA_COMPONENT if SND_HDA_CORE
+ select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
+ help
+ Choose this option if you want to use the new display engine
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 3435a0bfe3c5..d335b17689e4 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -55,6 +55,7 @@
+ #include <linux/types.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/firmware.h>
++#include <linux/component.h>
+
+ #include <drm/drmP.h>
+ #include <drm/drm_atomic.h>
+@@ -62,6 +63,7 @@
+ #include <drm/drm_dp_mst_helper.h>
+ #include <drm/drm_fb_helper.h>
+ #include <drm/drm_edid.h>
++#include <drm/drm_audio_component.h>
+
+ #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+ #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
+@@ -506,6 +508,139 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
+
+ }
+
++static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
++ int pipe, bool *enabled,
++ unsigned char *buf, int max_bytes)
++{
++ struct drm_device *dev = dev_get_drvdata(kdev);
++ struct amdgpu_device *adev = dev->dev_private;
++ struct drm_connector *connector;
++ struct drm_connector_list_iter conn_iter;
++ struct amdgpu_dm_connector *aconnector;
++ int ret = 0;
++
++ *enabled = false;
++
++ mutex_lock(&adev->dm.audio_lock);
++
++ drm_connector_list_iter_begin(dev, &conn_iter);
++ drm_for_each_connector_iter(connector, &conn_iter) {
++ aconnector = to_amdgpu_dm_connector(connector);
++ if (aconnector->audio_inst != port)
++ continue;
++
++ *enabled = true;
++ ret = drm_eld_size(connector->eld);
++ memcpy(buf, connector->eld, min(max_bytes, ret));
++
++ break;
++ }
++ drm_connector_list_iter_end(&conn_iter);
++
++ mutex_unlock(&adev->dm.audio_lock);
++
++ DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
++
++ return ret;
++}
++
++static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
++ .get_eld = amdgpu_dm_audio_component_get_eld,
++};
++
++static int amdgpu_dm_audio_component_bind(struct device *kdev,
++ struct device *hda_kdev, void *data)
++{
++ struct drm_device *dev = dev_get_drvdata(kdev);
++ struct amdgpu_device *adev = dev->dev_private;
++ struct drm_audio_component *acomp = data;
++
++ acomp->ops = &amdgpu_dm_audio_component_ops;
++ acomp->dev = kdev;
++ adev->dm.audio_component = acomp;
++
++ return 0;
++}
++
++static void amdgpu_dm_audio_component_unbind(struct device *kdev,
++ struct device *hda_kdev, void *data)
++{
++ struct drm_device *dev = dev_get_drvdata(kdev);
++ struct amdgpu_device *adev = dev->dev_private;
++ struct drm_audio_component *acomp = data;
++
++ acomp->ops = NULL;
++ acomp->dev = NULL;
++ adev->dm.audio_component = NULL;
++}
++
++static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
++ .bind = amdgpu_dm_audio_component_bind,
++ .unbind = amdgpu_dm_audio_component_unbind,
++};
++
++static int amdgpu_dm_audio_init(struct amdgpu_device *adev)
++{
++ int i, ret;
++
++ if (!amdgpu_audio)
++ return 0;
++
++ adev->mode_info.audio.enabled = true;
++
++ adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
++
++ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
++ adev->mode_info.audio.pin[i].channels = -1;
++ adev->mode_info.audio.pin[i].rate = -1;
++ adev->mode_info.audio.pin[i].bits_per_sample = -1;
++ adev->mode_info.audio.pin[i].status_bits = 0;
++ adev->mode_info.audio.pin[i].category_code = 0;
++ adev->mode_info.audio.pin[i].connected = false;
++ adev->mode_info.audio.pin[i].id =
++ adev->dm.dc->res_pool->audios[i]->inst;
++ adev->mode_info.audio.pin[i].offset = 0;
++ }
++
++ ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
++ if (ret < 0)
++ return ret;
++
++ adev->dm.audio_registered = true;
++
++ return 0;
++}
++
++static void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
++{
++ if (!amdgpu_audio)
++ return;
++
++ if (!adev->mode_info.audio.enabled)
++ return;
++
++ if (adev->dm.audio_registered) {
++ component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
++ adev->dm.audio_registered = false;
++ }
++
++ /* TODO: Disable audio? */
++
++ adev->mode_info.audio.enabled = false;
++}
++
++void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
++{
++ struct drm_audio_component *acomp = adev->dm.audio_component;
++
++ if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
++ DRM_DEBUG_KMS("Notify ELD: %d\n", pin);
++
++ acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
++ pin, -1);
++ }
++}
++
+ static int amdgpu_dm_init(struct amdgpu_device *adev)
+ {
+ struct dc_init_data init_data;
+@@ -516,6 +651,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
+ memset(&init_data, 0, sizeof(init_data));
+
+ mutex_init(&adev->dm.dc_lock);
++ mutex_init(&adev->dm.audio_lock);
+
+ if(amdgpu_dm_irq_init(adev)) {
+ DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
+@@ -619,6 +755,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
+
+ static void amdgpu_dm_fini(struct amdgpu_device *adev)
+ {
++ amdgpu_dm_audio_fini(adev);
++
+ amdgpu_dm_destroy_drm_device(&adev->dm);
+
+ /* DC Destroy TODO: Replace destroy DAL */
+@@ -638,6 +776,8 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
+ mod_freesync_destroy(adev->dm.freesync_module);
+ adev->dm.freesync_module = NULL;
+ }
++
++ mutex_destroy(&adev->dm.audio_lock);
+ mutex_destroy(&adev->dm.dc_lock);
+ return;
+ }
+@@ -1882,6 +2022,10 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
+ if (r)
+ return r;
+
++ r = amdgpu_dm_audio_init(adev);
++ if (r)
++ return r;
++
+ return 0;
+ }
+
+@@ -4815,6 +4959,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
+ aconnector->base.stereo_allowed = false;
+ aconnector->base.dpms = DRM_MODE_DPMS_OFF;
+ aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
++ aconnector->audio_inst = -1;
+ mutex_init(&aconnector->hpd_lock);
+
+ /*
+@@ -5704,6 +5849,81 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ kfree(bundle);
+ }
+
++static void amdgpu_dm_commit_audio(struct drm_device *dev,
++ struct drm_atomic_state *state)
++{
++ struct amdgpu_device *adev = dev->dev_private;
++ struct amdgpu_dm_connector *aconnector;
++ struct drm_connector *connector;
++ struct drm_connector_state *old_con_state, *new_con_state;
++ struct drm_crtc_state *new_crtc_state;
++ struct dm_crtc_state *new_dm_crtc_state;
++ const struct dc_stream_status *status;
++ int i, inst;
++
++ /* Notify device removals. */
++ for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
++ if (old_con_state->crtc != new_con_state->crtc) {
++ /* CRTC changes require notification. */
++ goto notify;
++ }
++
++ if (!new_con_state->crtc)
++ continue;
++
++ new_crtc_state = drm_atomic_get_new_crtc_state(
++ state, new_con_state->crtc);
++
++ if (!new_crtc_state)
++ continue;
++
++ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
++ continue;
++
++ notify:
++ aconnector = to_amdgpu_dm_connector(connector);
++
++ mutex_lock(&adev->dm.audio_lock);
++ inst = aconnector->audio_inst;
++ aconnector->audio_inst = -1;
++ mutex_unlock(&adev->dm.audio_lock);
++
++ amdgpu_dm_audio_eld_notify(adev, inst);
++ }
++
++ /* Notify audio device additions. */
++ for_each_new_connector_in_state(state, connector, new_con_state, i) {
++ if (!new_con_state->crtc)
++ continue;
++
++ new_crtc_state = drm_atomic_get_new_crtc_state(
++ state, new_con_state->crtc);
++
++ if (!new_crtc_state)
++ continue;
++
++ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
++ continue;
++
++ new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
++ if (!new_dm_crtc_state->stream)
++ continue;
++
++ status = dc_stream_get_status(new_dm_crtc_state->stream);
++ if (!status)
++ continue;
++
++ aconnector = to_amdgpu_dm_connector(connector);
++
++ mutex_lock(&adev->dm.audio_lock);
++ inst = status->audio_inst;
++ aconnector->audio_inst = inst;
++ mutex_unlock(&adev->dm.audio_lock);
++
++ amdgpu_dm_audio_eld_notify(adev, inst);
++ }
++}
++
+ /*
+ * Enable interrupts on CRTCs that are newly active, undergone
+ * a modeset, or have active planes again.
+@@ -6066,6 +6286,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+ /* Enable interrupts for CRTCs going from 0 to n active planes. */
+ amdgpu_dm_enable_crtc_interrupts(dev, state, false);
+
++ /* Update audio instances for each connector. */
++ amdgpu_dm_commit_audio(dev, state);
++
+ /*
+ * send vblank event on all events not handled in flip and
+ * mark consumed event for drm_atomic_helper_commit_hw_done
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+index e4338f0ca029..407c0fe0c20b 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+@@ -179,6 +179,28 @@ struct amdgpu_display_manager {
+ struct common_irq_params
+ vblank_params[DC_IRQ_SOURCE_VBLANK6 - DC_IRQ_SOURCE_VBLANK1 + 1];
+
++ /**
++ * @audio_lock:
++ *
++ * Guards access to audio instance changes.
++ */
++ struct mutex audio_lock;
++
++ /**
++ * @audio_component:
++ *
++ * Used to notify ELD changes to sound driver.
++ */
++ struct drm_audio_component *audio_component;
++
++ /**
++ * @audio_registered:
++ *
++ * True if the audio component has been registered
++ * successfully, false otherwise.
++ */
++ bool audio_registered;
++
+ /**
+ * @vupdate_params:
+ *
+@@ -248,6 +270,9 @@ struct amdgpu_dm_connector {
+ int max_vfreq ;
+ int pixel_clock_mhz;
+
++ /* Audio instance - protected by audio_lock. */
++ int audio_inst;
++
+ struct mutex hpd_lock;
+
+ bool fake_enable;
+--
+2.17.1
+