ALSA side use these apis to know display audio routing map in gfx side. And use the API to disable unused pin's audio output.
Signed-off-by: Wang Xingchao xingchao.wang@linux.intel.com --- sound/pci/hda/hda_i915.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_i915.h | 4 +++ sound/pci/hda/patch_hdmi.c | 20 +++++++++-- 3 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 76c13d5..7ac446f 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -22,9 +22,73 @@ #include <drm/i915_powerwell.h> #include "hda_i915.h"
+/* Haswell power well */ static void (*get_power)(void); static void (*put_power)(void);
+/* Haswell audio routing */ +static int (*get_using_pipe)(int); +static int (*disable_unused_pipe)(int, int *); +static int (*restore_eld)(void); + +#define i915_pipe_name(p) ((p) + 'A') + +static int busy_pins[3] = {0, 0, 0}; + +int hdmi_disable_unused_pipe(int pin_idx, int pipe_idx) +{ + busy_pins[pin_idx] = 1; + if (disable_unused_pipe) + disable_unused_pipe(pipe_idx, busy_pins); + + return 0; +} +EXPORT_SYMBOL(hdmi_disable_unused_pipe); + +void hdmi_restore_pineld(int pin_idx) +{ + busy_pins[pin_idx] = 0; + if (restore_eld) + restore_eld(); +} +EXPORT_SYMBOL(hdmi_restore_pineld); + +int hdmi_get_using_pipe(int pin_idx) +{ + int pipe = -1; + + if (get_using_pipe) + pipe = get_using_pipe(pin_idx); + + if (pipe != -1) + snd_printd("HDMI: pin %d get using pipe %c\n", pin_idx, i915_pipe_name(pipe)); + + return pipe; +} +EXPORT_SYMBOL(hdmi_get_using_pipe); + +static int init_audio_routing(void) +{ + get_using_pipe = symbol_request(i915_using_pipe); + if (!get_using_pipe) + return -ENODEV; + + disable_unused_pipe = symbol_request(i915_disable_pipe); + if (!disable_unused_pipe) { + get_using_pipe = NULL; + return -ENODEV; + } + + restore_eld = symbol_request(i915_restore_pineld); + if (!restore_eld) { + restore_eld = NULL; + get_using_pipe = NULL; + return -ENODEV; + } + + return 0; +} + void hda_display_power(bool enable) { if (!get_power || !put_power) @@ -57,6 +121,10 @@ int hda_i915_init(void)
snd_printd("HDA driver get symbol successfully from i915 module\n");
+ err = init_audio_routing(); + if (err < 0) + snd_printd("HDA driver get audior routing APIs failed!\n"); + return err; }
@@ -71,5 +139,20 @@ int hda_i915_exit(void) put_power = NULL; }
+ if (get_using_pipe) { + symbol_put(get_using_pipe); + get_using_pipe = NULL; + } + + if (disable_unused_pipe) { + symbol_put(disable_unused_pipe); + disable_unused_pipe = NULL; + } + + if (restore_eld) { + symbol_put(restore_eld); + restore_eld = NULL; + } + return 0; } diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h index 5a63da2..52d6f09 100644 --- a/sound/pci/hda/hda_i915.h +++ b/sound/pci/hda/hda_i915.h @@ -32,4 +32,8 @@ static inline int hda_i915_exit(void) } #endif
+extern int hdmi_get_using_pipe(int pin_idx); +extern int hdmi_disable_unused_pipe(int pin_idx, int pipe_idx); +extern void hdmi_restore_pineld(int pin_idx); + #endif diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d766f40..2a1e977 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -39,6 +39,7 @@ #include "hda_codec.h" #include "hda_local.h" #include "hda_jack.h" +#include "hda_i915.h"
static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); @@ -1131,6 +1132,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_spec_per_pin *per_pin; struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; + int pipe_idx;
/* Validate hinfo */ pin_idx = hinfo_to_pin_index(spec, hinfo); @@ -1139,12 +1141,21 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, per_pin = get_pin(spec, pin_idx); eld = &per_pin->sink_eld;
+ if (codec->vendor_id == 0x80862807) { + hsw_verify_cvt_D0(spec, codec); + + pipe_idx = hdmi_get_using_pipe(pin_idx); + if (pipe_idx < 0) + snd_printdd("HDMI: Pin %d has no valid pipe in use\n", pin_idx); + else { + hdmi_disable_unused_pipe(pin_idx, pipe_idx); + msleep(10); + } + } + if (!eld->monitor_present || !eld->eld_valid) return -EIO;
- if (codec->vendor_id == 0x80862807) - hsw_verify_cvt_D0(spec, codec); - /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { per_cvt = get_cvt(spec, cvt_idx); @@ -1514,6 +1525,9 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, snd_hda_spdif_ctls_unassign(codec, pin_idx); per_pin->chmap_set = false; memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); + + if (codec->vendor_id == 0x80862807) + hdmi_restore_pineld(pin_idx); }
return 0;