aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>2019-07-11 15:31:46 -0400
committerAlex Deucher <alexander.deucher@amd.com>2019-07-11 15:37:24 -0400
commit6ce8f316673f61416738e6df7329ca508a607762 (patch)
treed1d51b4022a1494f22ca5362cdd868e94f1f84d0
parent5fdb7c4c7f2691efd760b0b0dc00da4a3699f1a6 (diff)
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. 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> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/display/Kconfig1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c222
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h25
3 files changed, 248 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index 7073cfcf04e8..f954bf61af28 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -5,6 +5,7 @@ menu "Display Engine Configuration"
5config DRM_AMD_DC 5config DRM_AMD_DC
6 bool "AMD DC - Enable new display engine" 6 bool "AMD DC - Enable new display engine"
7 default y 7 default y
8 select SND_HDA_COMPONENT if SND_HDA_CORE
8 select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) 9 select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
9 help 10 help
10 Choose this option if you want to use the new display engine 11 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 0242d693f4f6..4a29f72334d0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -56,6 +56,7 @@
56#include <linux/pm_runtime.h> 56#include <linux/pm_runtime.h>
57#include <linux/pci.h> 57#include <linux/pci.h>
58#include <linux/firmware.h> 58#include <linux/firmware.h>
59#include <linux/component.h>
59 60
60#include <drm/drm_atomic.h> 61#include <drm/drm_atomic.h>
61#include <drm/drm_atomic_uapi.h> 62#include <drm/drm_atomic_uapi.h>
@@ -65,6 +66,7 @@
65#include <drm/drm_fourcc.h> 66#include <drm/drm_fourcc.h>
66#include <drm/drm_edid.h> 67#include <drm/drm_edid.h>
67#include <drm/drm_vblank.h> 68#include <drm/drm_vblank.h>
69#include <drm/drm_audio_component.h>
68 70
69#if defined(CONFIG_DRM_AMD_DC_DCN1_0) 71#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
70#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" 72#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
@@ -508,6 +510,139 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
508 510
509} 511}
510 512
513static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
514 int pipe, bool *enabled,
515 unsigned char *buf, int max_bytes)
516{
517 struct drm_device *dev = dev_get_drvdata(kdev);
518 struct amdgpu_device *adev = dev->dev_private;
519 struct drm_connector *connector;
520 struct drm_connector_list_iter conn_iter;
521 struct amdgpu_dm_connector *aconnector;
522 int ret = 0;
523
524 *enabled = false;
525
526 mutex_lock(&adev->dm.audio_lock);
527
528 drm_connector_list_iter_begin(dev, &conn_iter);
529 drm_for_each_connector_iter(connector, &conn_iter) {
530 aconnector = to_amdgpu_dm_connector(connector);
531 if (aconnector->audio_inst != port)
532 continue;
533
534 *enabled = true;
535 ret = drm_eld_size(connector->eld);
536 memcpy(buf, connector->eld, min(max_bytes, ret));
537
538 break;
539 }
540 drm_connector_list_iter_end(&conn_iter);
541
542 mutex_unlock(&adev->dm.audio_lock);
543
544 DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
545
546 return ret;
547}
548
549static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
550 .get_eld = amdgpu_dm_audio_component_get_eld,
551};
552
553static int amdgpu_dm_audio_component_bind(struct device *kdev,
554 struct device *hda_kdev, void *data)
555{
556 struct drm_device *dev = dev_get_drvdata(kdev);
557 struct amdgpu_device *adev = dev->dev_private;
558 struct drm_audio_component *acomp = data;
559
560 acomp->ops = &amdgpu_dm_audio_component_ops;
561 acomp->dev = kdev;
562 adev->dm.audio_component = acomp;
563
564 return 0;
565}
566
567static void amdgpu_dm_audio_component_unbind(struct device *kdev,
568 struct device *hda_kdev, void *data)
569{
570 struct drm_device *dev = dev_get_drvdata(kdev);
571 struct amdgpu_device *adev = dev->dev_private;
572 struct drm_audio_component *acomp = data;
573
574 acomp->ops = NULL;
575 acomp->dev = NULL;
576 adev->dm.audio_component = NULL;
577}
578
579static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
580 .bind = amdgpu_dm_audio_component_bind,
581 .unbind = amdgpu_dm_audio_component_unbind,
582};
583
584static int amdgpu_dm_audio_init(struct amdgpu_device *adev)
585{
586 int i, ret;
587
588 if (!amdgpu_audio)
589 return 0;
590
591 adev->mode_info.audio.enabled = true;
592
593 adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
594
595 for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
596 adev->mode_info.audio.pin[i].channels = -1;
597 adev->mode_info.audio.pin[i].rate = -1;
598 adev->mode_info.audio.pin[i].bits_per_sample = -1;
599 adev->mode_info.audio.pin[i].status_bits = 0;
600 adev->mode_info.audio.pin[i].category_code = 0;
601 adev->mode_info.audio.pin[i].connected = false;
602 adev->mode_info.audio.pin[i].id =
603 adev->dm.dc->res_pool->audios[i]->inst;
604 adev->mode_info.audio.pin[i].offset = 0;
605 }
606
607 ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
608 if (ret < 0)
609 return ret;
610
611 adev->dm.audio_registered = true;
612
613 return 0;
614}
615
616static void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
617{
618 if (!amdgpu_audio)
619 return;
620
621 if (!adev->mode_info.audio.enabled)
622 return;
623
624 if (adev->dm.audio_registered) {
625 component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
626 adev->dm.audio_registered = false;
627 }
628
629 /* TODO: Disable audio? */
630
631 adev->mode_info.audio.enabled = false;
632}
633
634void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
635{
636 struct drm_audio_component *acomp = adev->dm.audio_component;
637
638 if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
639 DRM_DEBUG_KMS("Notify ELD: %d\n", pin);
640
641 acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
642 pin, -1);
643 }
644}
645
511static int amdgpu_dm_init(struct amdgpu_device *adev) 646static int amdgpu_dm_init(struct amdgpu_device *adev)
512{ 647{
513 struct dc_init_data init_data; 648 struct dc_init_data init_data;
@@ -518,6 +653,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
518 memset(&init_data, 0, sizeof(init_data)); 653 memset(&init_data, 0, sizeof(init_data));
519 654
520 mutex_init(&adev->dm.dc_lock); 655 mutex_init(&adev->dm.dc_lock);
656 mutex_init(&adev->dm.audio_lock);
521 657
522 if(amdgpu_dm_irq_init(adev)) { 658 if(amdgpu_dm_irq_init(adev)) {
523 DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n"); 659 DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
@@ -621,6 +757,8 @@ error:
621 757
622static void amdgpu_dm_fini(struct amdgpu_device *adev) 758static void amdgpu_dm_fini(struct amdgpu_device *adev)
623{ 759{
760 amdgpu_dm_audio_fini(adev);
761
624 amdgpu_dm_destroy_drm_device(&adev->dm); 762 amdgpu_dm_destroy_drm_device(&adev->dm);
625 763
626 /* DC Destroy TODO: Replace destroy DAL */ 764 /* DC Destroy TODO: Replace destroy DAL */
@@ -641,6 +779,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
641 adev->dm.freesync_module = NULL; 779 adev->dm.freesync_module = NULL;
642 } 780 }
643 781
782 mutex_destroy(&adev->dm.audio_lock);
644 mutex_destroy(&adev->dm.dc_lock); 783 mutex_destroy(&adev->dm.dc_lock);
645 784
646 return; 785 return;
@@ -1888,6 +2027,10 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
1888 if (r) 2027 if (r)
1889 return r; 2028 return r;
1890 2029
2030 r = amdgpu_dm_audio_init(adev);
2031 if (r)
2032 return r;
2033
1891 return 0; 2034 return 0;
1892} 2035}
1893 2036
@@ -4834,6 +4977,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
4834 aconnector->base.stereo_allowed = false; 4977 aconnector->base.stereo_allowed = false;
4835 aconnector->base.dpms = DRM_MODE_DPMS_OFF; 4978 aconnector->base.dpms = DRM_MODE_DPMS_OFF;
4836 aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ 4979 aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
4980 aconnector->audio_inst = -1;
4837 mutex_init(&aconnector->hpd_lock); 4981 mutex_init(&aconnector->hpd_lock);
4838 4982
4839 /* 4983 /*
@@ -5728,6 +5872,81 @@ cleanup:
5728 kfree(bundle); 5872 kfree(bundle);
5729} 5873}
5730 5874
5875static void amdgpu_dm_commit_audio(struct drm_device *dev,
5876 struct drm_atomic_state *state)
5877{
5878 struct amdgpu_device *adev = dev->dev_private;
5879 struct amdgpu_dm_connector *aconnector;
5880 struct drm_connector *connector;
5881 struct drm_connector_state *old_con_state, *new_con_state;
5882 struct drm_crtc_state *new_crtc_state;
5883 struct dm_crtc_state *new_dm_crtc_state;
5884 const struct dc_stream_status *status;
5885 int i, inst;
5886
5887 /* Notify device removals. */
5888 for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
5889 if (old_con_state->crtc != new_con_state->crtc) {
5890 /* CRTC changes require notification. */
5891 goto notify;
5892 }
5893
5894 if (!new_con_state->crtc)
5895 continue;
5896
5897 new_crtc_state = drm_atomic_get_new_crtc_state(
5898 state, new_con_state->crtc);
5899
5900 if (!new_crtc_state)
5901 continue;
5902
5903 if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
5904 continue;
5905
5906 notify:
5907 aconnector = to_amdgpu_dm_connector(connector);
5908
5909 mutex_lock(&adev->dm.audio_lock);
5910 inst = aconnector->audio_inst;
5911 aconnector->audio_inst = -1;
5912 mutex_unlock(&adev->dm.audio_lock);
5913
5914 amdgpu_dm_audio_eld_notify(adev, inst);
5915 }
5916
5917 /* Notify audio device additions. */
5918 for_each_new_connector_in_state(state, connector, new_con_state, i) {
5919 if (!new_con_state->crtc)
5920 continue;
5921
5922 new_crtc_state = drm_atomic_get_new_crtc_state(
5923 state, new_con_state->crtc);
5924
5925 if (!new_crtc_state)
5926 continue;
5927
5928 if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
5929 continue;
5930
5931 new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
5932 if (!new_dm_crtc_state->stream)
5933 continue;
5934
5935 status = dc_stream_get_status(new_dm_crtc_state->stream);
5936 if (!status)
5937 continue;
5938
5939 aconnector = to_amdgpu_dm_connector(connector);
5940
5941 mutex_lock(&adev->dm.audio_lock);
5942 inst = status->audio_inst;
5943 aconnector->audio_inst = inst;
5944 mutex_unlock(&adev->dm.audio_lock);
5945
5946 amdgpu_dm_audio_eld_notify(adev, inst);
5947 }
5948}
5949
5731/* 5950/*
5732 * Enable interrupts on CRTCs that are newly active, undergone 5951 * Enable interrupts on CRTCs that are newly active, undergone
5733 * a modeset, or have active planes again. 5952 * a modeset, or have active planes again.
@@ -6106,6 +6325,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
6106 /* Enable interrupts for CRTCs going from 0 to n active planes. */ 6325 /* Enable interrupts for CRTCs going from 0 to n active planes. */
6107 amdgpu_dm_enable_crtc_interrupts(dev, state, false); 6326 amdgpu_dm_enable_crtc_interrupts(dev, state, false);
6108 6327
6328 /* Update audio instances for each connector. */
6329 amdgpu_dm_commit_audio(dev, state);
6330
6109 /* 6331 /*
6110 * send vblank event on all events not handled in flip and 6332 * send vblank event on all events not handled in flip and
6111 * mark consumed event for drm_atomic_helper_commit_hw_done 6333 * 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 baca5dc22b92..b89cbbfcc0e9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -144,6 +144,28 @@ struct amdgpu_display_manager {
144 struct mutex dc_lock; 144 struct mutex dc_lock;
145 145
146 /** 146 /**
147 * @audio_lock:
148 *
149 * Guards access to audio instance changes.
150 */
151 struct mutex audio_lock;
152
153 /**
154 * @audio_component:
155 *
156 * Used to notify ELD changes to sound driver.
157 */
158 struct drm_audio_component *audio_component;
159
160 /**
161 * @audio_registered:
162 *
163 * True if the audio component has been registered
164 * successfully, false otherwise.
165 */
166 bool audio_registered;
167
168 /**
147 * @irq_handler_list_low_tab: 169 * @irq_handler_list_low_tab:
148 * 170 *
149 * Low priority IRQ handler table. 171 * Low priority IRQ handler table.
@@ -254,6 +276,9 @@ struct amdgpu_dm_connector {
254 int max_vfreq ; 276 int max_vfreq ;
255 int pixel_clock_mhz; 277 int pixel_clock_mhz;
256 278
279 /* Audio instance - protected by audio_lock. */
280 int audio_inst;
281
257 struct mutex hpd_lock; 282 struct mutex hpd_lock;
258 283
259 bool fake_enable; 284 bool fake_enable;