diff options
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.patch | 391 |
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 + |