2019-05-27 06:55:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2010-03-08 02:44:23 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* patch_hdmi.c - routines for HDMI/DisplayPort codecs
|
|
|
|
*
|
|
|
|
* Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
|
2010-09-07 10:27:25 +00:00
|
|
|
* Copyright (c) 2006 ATI Technologies Inc.
|
|
|
|
* Copyright (c) 2008 NVIDIA Corp. All rights reserved.
|
|
|
|
* Copyright (c) 2008 Wei Ni <wni@nvidia.com>
|
2013-10-24 18:10:35 +00:00
|
|
|
* Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
|
2010-03-08 02:44:23 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Wu Fengguang <wfg@linux.intel.com>
|
|
|
|
*
|
|
|
|
* Maintained by:
|
|
|
|
* Wu Fengguang <wfg@linux.intel.com>
|
|
|
|
*/
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/delay.h>
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
#include <linux/pci.h>
|
2010-09-07 10:27:25 +00:00
|
|
|
#include <linux/slab.h>
|
2011-07-15 17:13:37 +00:00
|
|
|
#include <linux/module.h>
|
2018-06-27 06:25:32 +00:00
|
|
|
#include <linux/pm_runtime.h>
|
2010-09-07 10:27:25 +00:00
|
|
|
#include <sound/core.h>
|
2011-05-19 09:46:03 +00:00
|
|
|
#include <sound/jack.h>
|
2012-09-06 02:02:37 +00:00
|
|
|
#include <sound/asoundef.h>
|
2012-07-31 09:36:00 +00:00
|
|
|
#include <sound/tlv.h>
|
2015-08-19 08:48:58 +00:00
|
|
|
#include <sound/hdaudio.h>
|
|
|
|
#include <sound/hda_i915.h>
|
2016-03-04 14:29:46 +00:00
|
|
|
#include <sound/hda_chmap.h>
|
2018-08-22 20:24:57 +00:00
|
|
|
#include <sound/hda_codec.h>
|
2010-09-07 10:27:25 +00:00
|
|
|
#include "hda_local.h"
|
2011-10-27 20:12:46 +00:00
|
|
|
#include "hda_jack.h"
|
2019-12-02 07:49:47 +00:00
|
|
|
#include "hda_controller.h"
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2011-01-11 17:11:04 +00:00
|
|
|
static bool static_hdmi_pcm;
|
|
|
|
module_param(static_hdmi_pcm, bool, 0644);
|
|
|
|
MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
|
|
|
|
|
2020-04-15 16:25:23 +00:00
|
|
|
static bool enable_acomp = true;
|
|
|
|
module_param(enable_acomp, bool, 0444);
|
|
|
|
MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
|
|
|
|
|
2020-07-06 20:53:17 +00:00
|
|
|
static bool enable_silent_stream =
|
|
|
|
IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
|
|
|
|
module_param(enable_silent_stream, bool, 0644);
|
|
|
|
MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_spec_per_cvt {
|
|
|
|
hda_nid_t cvt_nid;
|
|
|
|
int assigned;
|
|
|
|
unsigned int channels_min;
|
|
|
|
unsigned int channels_max;
|
|
|
|
u32 rates;
|
|
|
|
u64 formats;
|
|
|
|
unsigned int maxbps;
|
|
|
|
};
|
2010-03-08 02:44:23 +00:00
|
|
|
|
ALSA: hda - Remove limit of widget connections
Currently we set the max number of connections to be 32, but there
seems codec that gives longer connection lists like AD1988, and we see
errors in proc output and else. (Though, in the case of AD1988, it's
a list of all codecs connected to a single vendor widget, so this must
be something fishy, but it's still valid from the h/w design POV.)
This patch tries to remove this restriction. For efficiency, we still
use the fixed size array in the parser, but takes a dynamic array when
the size is reported to be greater than that.
Now the fixed array size is found only in patch_hdmi.c, but it should
be fine, as the codec itself can't support so many pins.
Reported-by: Raymond Yau <superquad.vortex2@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-02-07 17:18:19 +00:00
|
|
|
/* max. connections to a widget */
|
|
|
|
#define HDA_MAX_CONNECTIONS 32
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_spec_per_pin {
|
|
|
|
hda_nid_t pin_nid;
|
2017-01-12 08:04:53 +00:00
|
|
|
int dev_id;
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
/* pin idx, different device entries on the same pin use the same idx */
|
|
|
|
int pin_nid_idx;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int num_mux_nids;
|
|
|
|
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
|
2014-03-20 05:01:06 +00:00
|
|
|
int mux_idx;
|
ALSA: hda - hdmi: Fix programmed active channel count
Currently the converter channel count is set to the number of actual
input channels. The audio infoframe channel count field is set
similarly.
However, sometimes the used channel map does not map all input channels
to outputs. Notably, 3 channel modes (e.g. 2.1) require a dummy input
channel so there are 4 input channels. According to the HDA
specification, converter channel count should be programmed according to
the number of _active_ channels.
On Intel HDMI codecs (but not on NVIDIA), setting the converter channel
to a higher value than there are actually mapped channels to HDMI slots
will cause no audio to be output at all.
Note that the effects of this issue are currently partially masked by
other bugs that prevent the driver from actually unmapping channels in
certain cases. For example, if a 4 channel stream is first created and
prepared, it gets a FL,FR,RL,RR mapping (ALSA->HDMI slot mapping 0->0,
1->1, 2->4, 3->5). If one thereafter assigns a FR,FL,FC mapping to it,
the driver will remap 2->3 but fail to unmap 2->4 and 3->5, so there are
still 4 active channels and the issue will not trigger in this case.
These bugs will be fixed separately.
Fix the channel counts in the converter channel count field and in the
audio infoframe channel count field to match the actual number of active
channels.
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-10-04 23:25:40 +00:00
|
|
|
hda_nid_t cvt_nid;
|
2011-11-16 08:29:47 +00:00
|
|
|
|
|
|
|
struct hda_codec *codec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_eld sink_eld;
|
2013-10-17 16:21:12 +00:00
|
|
|
struct mutex lock;
|
2011-11-16 08:29:47 +00:00
|
|
|
struct delayed_work work;
|
2016-01-12 03:13:26 +00:00
|
|
|
struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
|
2011-11-18 22:59:32 +00:00
|
|
|
int repoll_count;
|
2013-09-02 10:33:02 +00:00
|
|
|
bool setup; /* the stream has been set up by prepare callback */
|
2020-12-10 17:44:45 +00:00
|
|
|
bool silent_stream;
|
2013-09-02 10:33:02 +00:00
|
|
|
int channels; /* current number of channels */
|
2012-09-06 15:42:08 +00:00
|
|
|
bool non_pcm;
|
2012-07-31 09:36:00 +00:00
|
|
|
bool chmap_set; /* channel-map override by ALSA API? */
|
|
|
|
unsigned char chmap[8]; /* ALSA API channel-map */
|
2015-05-27 11:45:45 +00:00
|
|
|
#ifdef CONFIG_SND_PROC_FS
|
2013-10-17 16:21:12 +00:00
|
|
|
struct snd_info_entry *proc_entry;
|
|
|
|
#endif
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
};
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2013-10-24 18:10:34 +00:00
|
|
|
/* operations used by generic code that can be overridden by patches */
|
|
|
|
struct hdmi_ops {
|
|
|
|
int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id, unsigned char *buf, int *eld_size);
|
2013-10-24 18:10:34 +00:00
|
|
|
|
|
|
|
void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id,
|
2013-10-24 18:10:34 +00:00
|
|
|
int ca, int active_channels, int conn_type);
|
|
|
|
|
|
|
|
/* enable/disable HBR (HD passthrough) */
|
2019-11-19 08:47:09 +00:00
|
|
|
int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
|
|
|
|
int dev_id, bool hbr);
|
2013-10-24 18:10:34 +00:00
|
|
|
|
|
|
|
int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
hda_nid_t pin_nid, int dev_id, u32 stream_tag,
|
|
|
|
int format);
|
2013-10-24 18:10:34 +00:00
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
void (*pin_cvt_fixup)(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin,
|
|
|
|
hda_nid_t cvt_nid);
|
2013-10-24 18:10:34 +00:00
|
|
|
};
|
|
|
|
|
2016-01-12 03:13:26 +00:00
|
|
|
struct hdmi_pcm {
|
|
|
|
struct hda_pcm *pcm;
|
|
|
|
struct snd_jack *jack;
|
2016-02-23 08:33:37 +00:00
|
|
|
struct snd_kcontrol *eld_ctl;
|
2016-01-12 03:13:26 +00:00
|
|
|
};
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_spec {
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
struct hda_codec *codec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int num_cvts;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct snd_array cvts; /* struct hdmi_spec_per_cvt */
|
|
|
|
hda_nid_t cvt_nids[4]; /* only for haswell fix */
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* num_pins is the number of virtual pins
|
|
|
|
* for example, there are 3 pins, and each pin
|
|
|
|
* has 4 device entries, then the num_pins is 12
|
|
|
|
*/
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int num_pins;
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* num_nids is the number of real pins
|
|
|
|
* In the above example, num_nids is 3
|
|
|
|
*/
|
|
|
|
int num_nids;
|
|
|
|
/*
|
|
|
|
* dev_num is the number of device entries
|
|
|
|
* on each pin.
|
|
|
|
* In the above example, dev_num is 4
|
|
|
|
*/
|
|
|
|
int dev_num;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct snd_array pins; /* struct hdmi_spec_per_pin */
|
2016-01-12 03:13:26 +00:00
|
|
|
struct hdmi_pcm pcm_rec[16];
|
2015-12-16 05:42:42 +00:00
|
|
|
struct mutex pcm_lock;
|
2019-10-29 20:41:20 +00:00
|
|
|
struct mutex bind_lock; /* for audio component binding */
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
/* pcm_bitmap means which pcms have been assigned to pins*/
|
|
|
|
unsigned long pcm_bitmap;
|
2015-12-16 05:42:43 +00:00
|
|
|
int pcm_used; /* counter of pcm_rec[] */
|
2015-12-16 08:48:16 +00:00
|
|
|
/* bitmap shows whether the pcm is opened in user space
|
|
|
|
* bit 0 means the first playback PCM (PCM3);
|
|
|
|
* bit 1 means the second playback PCM, and so on.
|
|
|
|
*/
|
|
|
|
unsigned long pcm_in_use;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2013-02-19 15:11:25 +00:00
|
|
|
struct hdmi_eld temp_eld;
|
2013-10-24 18:10:34 +00:00
|
|
|
struct hdmi_ops ops;
|
2014-01-30 18:52:16 +00:00
|
|
|
|
|
|
|
bool dyn_pin_out;
|
2015-12-16 05:42:41 +00:00
|
|
|
bool dyn_pcm_assign;
|
2021-03-01 11:12:02 +00:00
|
|
|
bool dyn_pcm_no_legacy;
|
2019-11-11 19:09:37 +00:00
|
|
|
bool intel_hsw_fixup; /* apply Intel platform-specific fixups */
|
2010-03-08 02:44:23 +00:00
|
|
|
/*
|
2013-10-24 18:10:35 +00:00
|
|
|
* Non-generic VIA/NVIDIA specific
|
2010-03-08 02:44:23 +00:00
|
|
|
*/
|
|
|
|
struct hda_multi_out multiout;
|
2012-06-15 12:34:42 +00:00
|
|
|
struct hda_pcm_stream pcm_playback;
|
2015-08-19 08:48:58 +00:00
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
bool use_acomp_notifier; /* use eld_notify callback for hotplug */
|
|
|
|
bool acomp_registered; /* audio component registered in this driver */
|
2020-08-04 15:58:34 +00:00
|
|
|
bool force_connect; /* force connectivity */
|
2018-07-11 13:17:22 +00:00
|
|
|
struct drm_audio_component_audio_ops drm_audio_ops;
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */
|
2016-03-04 14:29:46 +00:00
|
|
|
|
|
|
|
struct hdac_chmap chmap;
|
2017-04-13 07:35:35 +00:00
|
|
|
hda_nid_t vendor_nid;
|
2019-03-13 16:09:23 +00:00
|
|
|
const int *port_map;
|
|
|
|
int port_num;
|
2020-07-06 20:53:17 +00:00
|
|
|
bool send_silent_stream; /* Flag to enable silent stream feature */
|
2010-03-08 02:44:23 +00:00
|
|
|
};
|
|
|
|
|
ALSA: hda: Make audio component support more generic
This is the final step for more generic support of DRM audio
component. The generic audio component code is now moved to its own
file, and the symbols are renamed from snd_hac_i915_* to
snd_hdac_acomp_*, respectively. The generic code is enabled via the
new kconfig, CONFIG_SND_HDA_COMPONENT, while CONFIG_SND_HDA_I915 is
kept as the super-class.
Along with the split, three new callbacks are added to audio_ops:
pin2port is for providing the conversion between the pin number and
the widget id, and master_bind/master_unbin are called at binding /
unbinding the master component, respectively. All these are optional,
but used in i915 implementation and also other later implementations.
A note about the new snd_hdac_acomp_init() function: there is a slight
difference between this and the old snd_hdac_i915_init(). The latter
(still) synchronizes with the master component binding, i.e. it
assures that the relevant DRM component gets bound when it returns, or
gives a negative error. Meanwhile the new function doesn't
synchronize but just leaves as is. It's the responsibility by the
caller's side to synchronize, or the caller may accept the
asynchronous binding on the fly.
v1->v2: Fix missing NULL check in master_bind/unbind
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 14:23:16 +00:00
|
|
|
#ifdef CONFIG_SND_HDA_COMPONENT
|
2016-03-18 14:10:08 +00:00
|
|
|
static inline bool codec_has_acomp(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
return spec->use_acomp_notifier;
|
|
|
|
}
|
2015-12-10 12:01:28 +00:00
|
|
|
#else
|
|
|
|
#define codec_has_acomp(codec) false
|
|
|
|
#endif
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
struct hdmi_audio_infoframe {
|
|
|
|
u8 type; /* 0x84 */
|
|
|
|
u8 ver; /* 0x01 */
|
|
|
|
u8 len; /* 0x0a */
|
|
|
|
|
2010-09-21 06:25:49 +00:00
|
|
|
u8 checksum;
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
|
|
|
|
u8 SS01_SF24;
|
|
|
|
u8 CXT04;
|
|
|
|
u8 CA;
|
|
|
|
u8 LFEPBL01_LSV36_DM_INH7;
|
2010-09-21 06:25:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct dp_audio_infoframe {
|
|
|
|
u8 type; /* 0x84 */
|
|
|
|
u8 len; /* 0x1b */
|
|
|
|
u8 ver; /* 0x11 << 2 */
|
|
|
|
|
|
|
|
u8 CC02_CT47; /* match with HDMI infoframe from this on */
|
|
|
|
u8 SS01_SF24;
|
|
|
|
u8 CXT04;
|
|
|
|
u8 CA;
|
|
|
|
u8 LFEPBL01_LSV36_DM_INH7;
|
2010-03-08 02:44:23 +00:00
|
|
|
};
|
|
|
|
|
2011-02-11 11:17:30 +00:00
|
|
|
union audio_infoframe {
|
|
|
|
struct hdmi_audio_infoframe hdmi;
|
|
|
|
struct dp_audio_infoframe dp;
|
|
|
|
u8 bytes[0];
|
|
|
|
};
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
/*
|
|
|
|
* HDMI routines
|
|
|
|
*/
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
#define get_pin(spec, idx) \
|
|
|
|
((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
|
|
|
|
#define get_cvt(spec, idx) \
|
|
|
|
((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx))
|
2016-01-12 03:13:26 +00:00
|
|
|
/* obtain hdmi_pcm object assigned to idx */
|
|
|
|
#define get_hdmi_pcm(spec, idx) (&(spec)->pcm_rec[idx])
|
|
|
|
/* obtain hda_pcm object assigned to idx */
|
|
|
|
#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
|
2013-03-13 13:40:31 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
static int pin_id_to_pin_index(struct hda_codec *codec,
|
|
|
|
hda_nid_t pin_nid, int dev_id)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
2014-02-25 11:21:03 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int pin_idx;
|
2017-01-12 08:04:53 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* (dev_id == -1) means it is NON-MST pin
|
|
|
|
* return the first virtual pin on this port
|
|
|
|
*/
|
|
|
|
if (dev_id == -1)
|
|
|
|
dev_id = 0;
|
|
|
|
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
per_pin = get_pin(spec, pin_idx);
|
|
|
|
if ((per_pin->pin_nid == pin_nid) &&
|
|
|
|
(per_pin->dev_id == dev_id))
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return pin_idx;
|
2017-01-12 08:04:53 +00:00
|
|
|
}
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2020-12-11 12:45:47 +00:00
|
|
|
codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-12-16 05:42:43 +00:00
|
|
|
static int hinfo_to_pcm_index(struct hda_codec *codec,
|
|
|
|
struct hda_pcm_stream *hinfo)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int pcm_idx;
|
|
|
|
|
|
|
|
for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++)
|
|
|
|
if (get_pcm_rec(spec, pcm_idx)->stream == hinfo)
|
|
|
|
return pcm_idx;
|
|
|
|
|
2020-07-03 15:38:18 +00:00
|
|
|
codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo);
|
2015-12-16 05:42:43 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
static int hinfo_to_pin_index(struct hda_codec *codec,
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hda_pcm_stream *hinfo)
|
|
|
|
{
|
2014-02-25 11:21:03 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2015-12-16 05:42:41 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int pin_idx;
|
|
|
|
|
2015-12-16 05:42:41 +00:00
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
per_pin = get_pin(spec, pin_idx);
|
2016-01-12 03:13:26 +00:00
|
|
|
if (per_pin->pcm &&
|
|
|
|
per_pin->pcm->pcm->stream == hinfo)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return pin_idx;
|
2015-12-16 05:42:41 +00:00
|
|
|
}
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2020-07-03 15:38:18 +00:00
|
|
|
codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo,
|
|
|
|
hinfo_to_pcm_index(codec, hinfo));
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-02-03 02:48:34 +00:00
|
|
|
static struct hdmi_spec_per_pin *pcm_idx_to_pin(struct hdmi_spec *spec,
|
|
|
|
int pcm_idx)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->num_pins; i++) {
|
|
|
|
per_pin = get_pin(spec, i);
|
|
|
|
if (per_pin->pcm_idx == pcm_idx)
|
|
|
|
return per_pin;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
{
|
2014-02-25 11:21:03 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int cvt_idx;
|
|
|
|
|
|
|
|
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
|
2013-03-13 13:40:31 +00:00
|
|
|
if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return cvt_idx;
|
|
|
|
|
2020-12-11 12:45:47 +00:00
|
|
|
codec_warn(codec, "HDMI: cvt NID 0x%x not registered\n", cvt_nid);
|
2010-03-08 02:44:23 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2011-09-30 21:35:41 +00:00
|
|
|
static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
2013-02-19 15:11:23 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-10-17 16:21:12 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2013-02-19 15:11:23 +00:00
|
|
|
struct hdmi_eld *eld;
|
2016-02-23 08:33:37 +00:00
|
|
|
int pcm_idx;
|
2011-09-30 21:35:41 +00:00
|
|
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
|
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
pcm_idx = kcontrol->private_value;
|
|
|
|
mutex_lock(&spec->pcm_lock);
|
|
|
|
per_pin = pcm_idx_to_pin(spec, pcm_idx);
|
|
|
|
if (!per_pin) {
|
|
|
|
/* no pin is bound to the pcm */
|
|
|
|
uinfo->count = 0;
|
2018-07-12 21:06:51 +00:00
|
|
|
goto unlock;
|
2016-02-23 08:33:37 +00:00
|
|
|
}
|
2013-10-17 16:21:12 +00:00
|
|
|
eld = &per_pin->sink_eld;
|
2013-02-19 15:11:23 +00:00
|
|
|
uinfo->count = eld->eld_valid ? eld->eld_size : 0;
|
2011-09-30 21:35:41 +00:00
|
|
|
|
2018-07-12 21:06:51 +00:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&spec->pcm_lock);
|
2011-09-30 21:35:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
2013-02-19 15:11:23 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-10-17 16:21:12 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2013-02-19 15:11:23 +00:00
|
|
|
struct hdmi_eld *eld;
|
2016-02-23 08:33:37 +00:00
|
|
|
int pcm_idx;
|
2018-07-12 21:06:51 +00:00
|
|
|
int err = 0;
|
2011-09-30 21:35:41 +00:00
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
pcm_idx = kcontrol->private_value;
|
|
|
|
mutex_lock(&spec->pcm_lock);
|
|
|
|
per_pin = pcm_idx_to_pin(spec, pcm_idx);
|
|
|
|
if (!per_pin) {
|
|
|
|
/* no pin is bound to the pcm */
|
|
|
|
memset(ucontrol->value.bytes.data, 0,
|
|
|
|
ARRAY_SIZE(ucontrol->value.bytes.data));
|
2018-07-12 21:06:51 +00:00
|
|
|
goto unlock;
|
2016-02-23 08:33:37 +00:00
|
|
|
}
|
2013-02-19 15:11:23 +00:00
|
|
|
|
2018-07-12 21:06:51 +00:00
|
|
|
eld = &per_pin->sink_eld;
|
2016-02-05 08:05:41 +00:00
|
|
|
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
|
|
|
|
eld->eld_size > ELD_MAX_SIZE) {
|
2013-02-19 15:11:23 +00:00
|
|
|
snd_BUG();
|
2018-07-12 21:06:51 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
2013-02-19 15:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(ucontrol->value.bytes.data, 0,
|
|
|
|
ARRAY_SIZE(ucontrol->value.bytes.data));
|
|
|
|
if (eld->eld_valid)
|
|
|
|
memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
|
|
|
|
eld->eld_size);
|
2011-09-30 21:35:41 +00:00
|
|
|
|
2018-07-12 21:06:51 +00:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&spec->pcm_lock);
|
|
|
|
return err;
|
2011-09-30 21:35:41 +00:00
|
|
|
}
|
|
|
|
|
2017-02-19 18:48:09 +00:00
|
|
|
static const struct snd_kcontrol_new eld_bytes_ctl = {
|
ALSA: control: Add verification for kctl accesses
The current implementation of ALSA control API fully relies on the
callbacks of each driver, and there is no verification of the values
passed via API. This patch is an attempt to improve the situation
slightly by adding the validation code for the values stored via info
and get callbacks.
The patch adds a new kconfig, CONFIG_SND_CTL_VALIDATION. It depends
on CONFIG_SND_DEBUG and off as default since the validation would
require a slight overhead including the additional call of info
callback at each get callback invocation.
When this config is enabled, the values stored by each info callback
invocation are verified, namely:
- Whether the info type is valid
- Whether the number of enum items is non-zero
- Whether the given info count is within the allowed boundary
Similarly, the values stored at each get callback are verified as
well:
- Whether the values are within the given range
- Whether the values are aligned with the given step
- Whether any further changes are seen in the data array over the
given info count
The last point helps identifying a possibly invalid data type access,
typically a case where the info callback declares the type being
SNDRV_CTL_ELEM_TYPE_ENUMERATED while the get/put callbacks store
the values in value.integer.value[] array.
When a validation fails, the ALSA core logs an error message including
the device and the control ID, and the API call also returns an
error. So, with the new validation turned on, the driver behavior
difference may be visible on user-space, too -- it's intentional,
though, so that we can catch an error more clearly.
The patch also introduces a new ctl access type,
SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK. A driver may pass this flag with
other access bits to indicate that the ctl element won't be verified.
It's useful when a driver code is specially written to access the data
greater than info->count size by some reason. For example, this flag
is actually set now in HD-audio HDMI codec driver which needs to clear
the data array in the case of the disconnected monitor.
Also, the PCM channel-map helper code is slightly modified to avoid
the false-positive hit by this validation code, too.
Link: https://lore.kernel.org/r/20200104083556.27789-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-01-04 08:35:56 +00:00
|
|
|
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE |
|
|
|
|
SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK,
|
2011-09-30 21:35:41 +00:00
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
|
|
|
.name = "ELD",
|
|
|
|
.info = hdmi_eld_ctl_info,
|
|
|
|
.get = hdmi_eld_ctl_get,
|
|
|
|
};
|
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
static int hdmi_create_eld_ctl(struct hda_codec *codec, int pcm_idx,
|
2011-09-30 21:35:41 +00:00
|
|
|
int device)
|
|
|
|
{
|
|
|
|
struct snd_kcontrol *kctl;
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
|
|
|
|
if (!kctl)
|
|
|
|
return -ENOMEM;
|
2016-02-23 08:33:37 +00:00
|
|
|
kctl->private_value = pcm_idx;
|
2011-09-30 21:35:41 +00:00
|
|
|
kctl->id.device = device;
|
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
/* no pin nid is associated with the kctl now
|
|
|
|
* tbd: associate pin nid to eld ctl later
|
|
|
|
*/
|
|
|
|
err = snd_hda_ctl_add(codec, 0, kctl);
|
2011-09-30 21:35:41 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
get_hdmi_pcm(spec, pcm_idx)->eld_ctl = kctl;
|
2011-09-30 21:35:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
#ifdef BE_PARANOID
|
|
|
|
static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
|
|
|
|
int *packet_index, int *byte_index)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
|
|
|
|
val = snd_hda_codec_read(codec, pin_nid, 0,
|
|
|
|
AC_VERB_GET_HDMI_DIP_INDEX, 0);
|
|
|
|
|
|
|
|
*packet_index = val >> 5;
|
|
|
|
*byte_index = val & 0x1f;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
|
|
|
|
int packet_index, int byte_index)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
|
|
|
|
val = (packet_index << 5) | (byte_index & 0x1f);
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
|
|
|
|
unsigned char val)
|
|
|
|
{
|
|
|
|
snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
|
|
|
|
}
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
2014-01-30 18:52:16 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int pin_out;
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
/* Unmute */
|
|
|
|
if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
|
|
|
|
snd_hda_codec_write(codec, pin_nid, 0,
|
|
|
|
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
|
2014-01-30 18:52:16 +00:00
|
|
|
|
|
|
|
if (spec->dyn_pin_out)
|
|
|
|
/* Disable pin out until stream is active */
|
|
|
|
pin_out = 0;
|
|
|
|
else
|
|
|
|
/* Enable pin out: some machines with GM965 gets broken output
|
|
|
|
* when the pin is disabled or changed while using with HDMI
|
|
|
|
*/
|
|
|
|
pin_out = PIN_OUT;
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
snd_hda_codec_write(codec, pin_nid, 0,
|
2014-01-30 18:52:16 +00:00
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
2013-10-17 16:21:12 +00:00
|
|
|
/*
|
|
|
|
* ELD proc files
|
|
|
|
*/
|
|
|
|
|
2015-05-27 11:45:45 +00:00
|
|
|
#ifdef CONFIG_SND_PROC_FS
|
2013-10-17 16:21:12 +00:00
|
|
|
static void print_eld_info(struct snd_info_entry *entry,
|
|
|
|
struct snd_info_buffer *buffer)
|
|
|
|
{
|
|
|
|
struct hdmi_spec_per_pin *per_pin = entry->private_data;
|
|
|
|
|
|
|
|
mutex_lock(&per_pin->lock);
|
|
|
|
snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer);
|
|
|
|
mutex_unlock(&per_pin->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_eld_info(struct snd_info_entry *entry,
|
|
|
|
struct snd_info_buffer *buffer)
|
|
|
|
{
|
|
|
|
struct hdmi_spec_per_pin *per_pin = entry->private_data;
|
|
|
|
|
|
|
|
mutex_lock(&per_pin->lock);
|
|
|
|
snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
|
|
|
|
mutex_unlock(&per_pin->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
|
|
|
|
{
|
|
|
|
char name[32];
|
|
|
|
struct hda_codec *codec = per_pin->codec;
|
|
|
|
struct snd_info_entry *entry;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
|
2015-02-27 15:09:22 +00:00
|
|
|
err = snd_card_proc_new(codec->card, name, &entry);
|
2013-10-17 16:21:12 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
snd_info_set_text_ops(entry, per_pin, print_eld_info);
|
|
|
|
entry->c.text.write = write_eld_info;
|
2018-05-23 19:20:59 +00:00
|
|
|
entry->mode |= 0200;
|
2013-10-17 16:21:12 +00:00
|
|
|
per_pin->proc_entry = entry;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
2015-06-28 09:15:28 +00:00
|
|
|
if (!per_pin->codec->bus->shutdown) {
|
2015-04-22 16:26:38 +00:00
|
|
|
snd_info_free_entry(per_pin->proc_entry);
|
2013-10-17 16:21:12 +00:00
|
|
|
per_pin->proc_entry = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2013-10-21 14:31:45 +00:00
|
|
|
static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
|
|
|
|
int index)
|
2013-10-17 16:21:12 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2013-10-21 14:31:45 +00:00
|
|
|
static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
|
2013-10-17 16:21:12 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Audio InfoFrame routines
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Enable Audio InfoFrame Transmission
|
|
|
|
*/
|
|
|
|
static void hdmi_start_infoframe_trans(struct hda_codec *codec,
|
|
|
|
hda_nid_t pin_nid)
|
|
|
|
{
|
|
|
|
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
|
|
|
|
snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
|
|
|
|
AC_DIPXMIT_BEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable Audio InfoFrame Transmission
|
|
|
|
*/
|
|
|
|
static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
|
|
|
|
hda_nid_t pin_nid)
|
|
|
|
{
|
|
|
|
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
|
|
|
|
snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
|
|
|
|
AC_DIPXMIT_DISABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
|
|
|
int i;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = snd_hdmi_get_eld_size(codec, pin_nid);
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
size = snd_hda_codec_read(codec, pin_nid, 0,
|
|
|
|
AC_VERB_GET_HDMI_DIP_SIZE, i);
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
|
|
|
|
{
|
|
|
|
#ifdef BE_PARANOID
|
|
|
|
int i, j;
|
|
|
|
int size;
|
|
|
|
int pi, bi;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
size = snd_hda_codec_read(codec, pin_nid, 0,
|
|
|
|
AC_VERB_GET_HDMI_DIP_SIZE, i);
|
|
|
|
if (size == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
hdmi_set_dip_index(codec, pin_nid, i, 0x0);
|
|
|
|
for (j = 1; j < 1000; j++) {
|
|
|
|
hdmi_write_dip_byte(codec, pin_nid, 0x0);
|
|
|
|
hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
|
|
|
|
if (pi != i)
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec, "dip index %d: %d != %d\n",
|
2010-03-08 02:44:23 +00:00
|
|
|
bi, pi, i);
|
|
|
|
if (bi == 0) /* byte index wrapped around */
|
|
|
|
break;
|
|
|
|
}
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec,
|
2010-03-08 02:44:23 +00:00
|
|
|
"HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
|
|
|
|
i, size, j);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-09-21 06:25:49 +00:00
|
|
|
static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
2010-09-21 06:25:49 +00:00
|
|
|
u8 *bytes = (u8 *)hdmi_ai;
|
2010-03-08 02:44:23 +00:00
|
|
|
u8 sum = 0;
|
|
|
|
int i;
|
|
|
|
|
2010-09-21 06:25:49 +00:00
|
|
|
hdmi_ai->checksum = 0;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2010-09-21 06:25:49 +00:00
|
|
|
for (i = 0; i < sizeof(*hdmi_ai); i++)
|
2010-03-08 02:44:23 +00:00
|
|
|
sum += bytes[i];
|
|
|
|
|
2010-09-21 06:25:49 +00:00
|
|
|
hdmi_ai->checksum = -sum;
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
|
|
|
|
hda_nid_t pin_nid,
|
2010-09-21 06:25:49 +00:00
|
|
|
u8 *dip, int size)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
hdmi_debug_dip_size(codec, pin_nid);
|
|
|
|
hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
|
|
|
|
|
|
|
|
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
|
2010-09-21 06:25:49 +00:00
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
hdmi_write_dip_byte(codec, pin_nid, dip[i]);
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
|
2010-09-21 06:25:49 +00:00
|
|
|
u8 *dip, int size)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
|
|
|
u8 val;
|
|
|
|
int i;
|
|
|
|
|
2020-12-11 13:16:13 +00:00
|
|
|
hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
|
2010-03-08 02:44:23 +00:00
|
|
|
if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
|
|
|
|
!= AC_DIPXMIT_BEST)
|
|
|
|
return false;
|
|
|
|
|
2010-09-21 06:25:49 +00:00
|
|
|
for (i = 0; i < size; i++) {
|
2010-03-08 02:44:23 +00:00
|
|
|
val = snd_hda_codec_read(codec, pin_nid, 0,
|
|
|
|
AC_VERB_GET_HDMI_DIP_DATA, 0);
|
2010-09-21 06:25:49 +00:00
|
|
|
if (val != dip[i])
|
2010-03-08 02:44:23 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
int dev_id, unsigned char *buf, int *eld_size)
|
|
|
|
{
|
|
|
|
snd_hda_set_dev_select(codec, nid, dev_id);
|
|
|
|
|
|
|
|
return snd_hdmi_get_eld(codec, nid, buf, eld_size);
|
|
|
|
}
|
|
|
|
|
2013-10-24 18:10:34 +00:00
|
|
|
static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
|
2019-11-19 08:47:09 +00:00
|
|
|
hda_nid_t pin_nid, int dev_id,
|
2013-10-24 18:10:34 +00:00
|
|
|
int ca, int active_channels,
|
|
|
|
int conn_type)
|
|
|
|
{
|
|
|
|
union audio_infoframe ai;
|
|
|
|
|
2014-03-11 21:12:52 +00:00
|
|
|
memset(&ai, 0, sizeof(ai));
|
2013-10-24 18:10:34 +00:00
|
|
|
if (conn_type == 0) { /* HDMI */
|
|
|
|
struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
|
|
|
|
|
|
|
|
hdmi_ai->type = 0x84;
|
|
|
|
hdmi_ai->ver = 0x01;
|
|
|
|
hdmi_ai->len = 0x0a;
|
|
|
|
hdmi_ai->CC02_CT47 = active_channels - 1;
|
|
|
|
hdmi_ai->CA = ca;
|
|
|
|
hdmi_checksum_audio_infoframe(hdmi_ai);
|
|
|
|
} else if (conn_type == 1) { /* DisplayPort */
|
|
|
|
struct dp_audio_infoframe *dp_ai = &ai.dp;
|
|
|
|
|
|
|
|
dp_ai->type = 0x84;
|
|
|
|
dp_ai->len = 0x1b;
|
|
|
|
dp_ai->ver = 0x11 << 2;
|
|
|
|
dp_ai->CC02_CT47 = active_channels - 1;
|
|
|
|
dp_ai->CA = ca;
|
|
|
|
} else {
|
2020-12-11 12:45:47 +00:00
|
|
|
codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid);
|
2013-10-24 18:10:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_set_dev_select(codec, pin_nid, dev_id);
|
|
|
|
|
2013-10-24 18:10:34 +00:00
|
|
|
/*
|
|
|
|
* sizeof(ai) is used instead of sizeof(*hdmi_ai) or
|
|
|
|
* sizeof(*dp_ai) to avoid partial match/update problems when
|
|
|
|
* the user switches between HDMI/DP monitors.
|
|
|
|
*/
|
|
|
|
if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
|
|
|
|
sizeof(ai))) {
|
2020-12-11 12:45:47 +00:00
|
|
|
codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n",
|
|
|
|
__func__, pin_nid, active_channels, ca);
|
2013-10-24 18:10:34 +00:00
|
|
|
hdmi_stop_infoframe_trans(codec, pin_nid);
|
|
|
|
hdmi_fill_audio_infoframe(codec, pin_nid,
|
|
|
|
ai.bytes, sizeof(ai));
|
|
|
|
hdmi_start_infoframe_trans(codec, pin_nid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-02 10:33:02 +00:00
|
|
|
static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin,
|
|
|
|
bool non_pcm)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
2013-10-24 18:10:34 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2016-03-04 14:29:49 +00:00
|
|
|
struct hdac_chmap *chmap = &spec->chmap;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
hda_nid_t pin_nid = per_pin->pin_nid;
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id = per_pin->dev_id;
|
2013-09-02 10:33:02 +00:00
|
|
|
int channels = per_pin->channels;
|
ALSA: hda - hdmi: Fix programmed active channel count
Currently the converter channel count is set to the number of actual
input channels. The audio infoframe channel count field is set
similarly.
However, sometimes the used channel map does not map all input channels
to outputs. Notably, 3 channel modes (e.g. 2.1) require a dummy input
channel so there are 4 input channels. According to the HDA
specification, converter channel count should be programmed according to
the number of _active_ channels.
On Intel HDMI codecs (but not on NVIDIA), setting the converter channel
to a higher value than there are actually mapped channels to HDMI slots
will cause no audio to be output at all.
Note that the effects of this issue are currently partially masked by
other bugs that prevent the driver from actually unmapping channels in
certain cases. For example, if a 4 channel stream is first created and
prepared, it gets a FL,FR,RL,RR mapping (ALSA->HDMI slot mapping 0->0,
1->1, 2->4, 3->5). If one thereafter assigns a FR,FL,FC mapping to it,
the driver will remap 2->3 but fail to unmap 2->4 and 3->5, so there are
still 4 active channels and the issue will not trigger in this case.
These bugs will be fixed separately.
Fix the channel counts in the converter channel count field and in the
audio infoframe channel count field to match the actual number of active
channels.
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-10-04 23:25:40 +00:00
|
|
|
int active_channels;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_eld *eld;
|
2016-03-04 14:29:50 +00:00
|
|
|
int ca;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2013-09-02 10:33:02 +00:00
|
|
|
if (!channels)
|
|
|
|
return;
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_set_dev_select(codec, pin_nid, dev_id);
|
|
|
|
|
2016-03-21 11:36:44 +00:00
|
|
|
/* some HW (e.g. HSW+) needs reprogramming the amp at each time */
|
|
|
|
if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
|
2013-09-04 20:37:12 +00:00
|
|
|
snd_hda_codec_write(codec, pin_nid, 0,
|
|
|
|
AC_VERB_SET_AMP_GAIN_MUTE,
|
|
|
|
AMP_OUT_UNMUTE);
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
eld = &per_pin->sink_eld;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2016-03-04 14:29:52 +00:00
|
|
|
ca = snd_hdac_channel_allocation(&codec->core,
|
2016-03-04 14:29:50 +00:00
|
|
|
eld->info.spk_alloc, channels,
|
|
|
|
per_pin->chmap_set, non_pcm, per_pin->chmap);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2016-03-04 14:29:52 +00:00
|
|
|
active_channels = snd_hdac_get_active_channels(ca);
|
ALSA: hda - hdmi: Fix programmed active channel count
Currently the converter channel count is set to the number of actual
input channels. The audio infoframe channel count field is set
similarly.
However, sometimes the used channel map does not map all input channels
to outputs. Notably, 3 channel modes (e.g. 2.1) require a dummy input
channel so there are 4 input channels. According to the HDA
specification, converter channel count should be programmed according to
the number of _active_ channels.
On Intel HDMI codecs (but not on NVIDIA), setting the converter channel
to a higher value than there are actually mapped channels to HDMI slots
will cause no audio to be output at all.
Note that the effects of this issue are currently partially masked by
other bugs that prevent the driver from actually unmapping channels in
certain cases. For example, if a 4 channel stream is first created and
prepared, it gets a FL,FR,RL,RR mapping (ALSA->HDMI slot mapping 0->0,
1->1, 2->4, 3->5). If one thereafter assigns a FR,FL,FC mapping to it,
the driver will remap 2->3 but fail to unmap 2->4 and 3->5, so there are
still 4 active channels and the issue will not trigger in this case.
These bugs will be fixed separately.
Fix the channel counts in the converter channel count field and in the
audio infoframe channel count field to match the actual number of active
channels.
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-10-04 23:25:40 +00:00
|
|
|
|
2016-03-04 14:29:49 +00:00
|
|
|
chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid,
|
|
|
|
active_channels);
|
ALSA: hda - hdmi: Fix programmed active channel count
Currently the converter channel count is set to the number of actual
input channels. The audio infoframe channel count field is set
similarly.
However, sometimes the used channel map does not map all input channels
to outputs. Notably, 3 channel modes (e.g. 2.1) require a dummy input
channel so there are 4 input channels. According to the HDA
specification, converter channel count should be programmed according to
the number of _active_ channels.
On Intel HDMI codecs (but not on NVIDIA), setting the converter channel
to a higher value than there are actually mapped channels to HDMI slots
will cause no audio to be output at all.
Note that the effects of this issue are currently partially masked by
other bugs that prevent the driver from actually unmapping channels in
certain cases. For example, if a 4 channel stream is first created and
prepared, it gets a FL,FR,RL,RR mapping (ALSA->HDMI slot mapping 0->0,
1->1, 2->4, 3->5). If one thereafter assigns a FR,FL,FC mapping to it,
the driver will remap 2->3 but fail to unmap 2->4 and 3->5, so there are
still 4 active channels and the issue will not trigger in this case.
These bugs will be fixed separately.
Fix the channel counts in the converter channel count field and in the
audio infoframe channel count field to match the actual number of active
channels.
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-10-04 23:25:40 +00:00
|
|
|
|
2013-10-07 16:24:52 +00:00
|
|
|
/*
|
|
|
|
* always configure channel mapping, it may have been changed by the
|
|
|
|
* user in the meantime
|
|
|
|
*/
|
2016-03-04 14:29:52 +00:00
|
|
|
snd_hdac_setup_channel_mapping(&spec->chmap,
|
2016-03-04 14:29:50 +00:00
|
|
|
pin_nid, non_pcm, ca, channels,
|
|
|
|
per_pin->chmap, per_pin->chmap_set);
|
2013-10-07 16:24:52 +00:00
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
|
|
|
|
ca, active_channels, eld->info.conn_type);
|
2012-09-06 02:02:37 +00:00
|
|
|
|
2012-09-06 15:42:08 +00:00
|
|
|
per_pin->non_pcm = non_pcm;
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unsolicited events
|
|
|
|
*/
|
|
|
|
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
|
2010-07-28 12:21:55 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
int dev_id)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2017-01-12 08:04:53 +00:00
|
|
|
int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
|
2014-09-11 13:22:46 +00:00
|
|
|
|
2013-12-04 02:19:41 +00:00
|
|
|
if (pin_idx < 0)
|
|
|
|
return;
|
2018-06-27 06:25:32 +00:00
|
|
|
mutex_lock(&spec->pcm_lock);
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
hdmi_present_sense(get_pin(spec, pin_idx), 1);
|
2018-06-27 06:25:32 +00:00
|
|
|
mutex_unlock(&spec->pcm_lock);
|
2013-12-04 02:19:41 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 13:22:46 +00:00
|
|
|
static void jack_callback(struct hda_codec *codec,
|
|
|
|
struct hda_jack_callback *jack)
|
|
|
|
{
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
/* stop polling when notification is enabled */
|
|
|
|
if (codec_has_acomp(codec))
|
|
|
|
return;
|
|
|
|
|
2019-11-19 08:47:08 +00:00
|
|
|
check_presence_and_report(codec, jack->nid, jack->dev_id);
|
2014-09-11 13:22:46 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 16:28:01 +00:00
|
|
|
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
|
|
|
|
struct hda_jack_tbl *jack)
|
2013-12-04 02:19:41 +00:00
|
|
|
{
|
2011-10-27 23:16:55 +00:00
|
|
|
jack->jack_dirty = 1;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec,
|
2020-12-11 12:45:47 +00:00
|
|
|
"HDMI hot plug event: Codec=%d NID=0x%x Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
|
2019-11-19 08:47:08 +00:00
|
|
|
codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA),
|
2012-04-10 09:00:35 +00:00
|
|
|
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2019-11-19 08:47:08 +00:00
|
|
|
check_presence_and_report(codec, jack->nid, jack->dev_id);
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
|
|
|
{
|
|
|
|
int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
|
|
|
|
int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
|
|
|
|
int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
|
|
|
|
int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
|
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_info(codec,
|
2012-06-21 09:41:05 +00:00
|
|
|
"HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
codec->addr,
|
2010-03-08 02:44:23 +00:00
|
|
|
tag,
|
|
|
|
subtag,
|
|
|
|
cp_state,
|
|
|
|
cp_ready);
|
|
|
|
|
|
|
|
/* TODO */
|
2020-01-13 21:14:05 +00:00
|
|
|
if (cp_state) {
|
2010-03-08 02:44:23 +00:00
|
|
|
;
|
2020-01-13 21:14:05 +00:00
|
|
|
}
|
|
|
|
if (cp_ready) {
|
2010-03-08 02:44:23 +00:00
|
|
|
;
|
2020-01-13 21:14:05 +00:00
|
|
|
}
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
|
|
|
|
{
|
|
|
|
int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
|
|
|
|
int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
|
2019-11-19 08:47:08 +00:00
|
|
|
struct hda_jack_tbl *jack;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
if (codec_has_acomp(codec))
|
|
|
|
return;
|
|
|
|
|
2019-11-19 08:47:08 +00:00
|
|
|
if (codec->dp_mst) {
|
|
|
|
int dev_entry =
|
|
|
|
(res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
|
|
|
|
|
|
|
|
jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry);
|
|
|
|
} else {
|
|
|
|
jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!jack) {
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
|
2010-03-08 02:44:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subtag == 0)
|
2020-02-06 16:28:01 +00:00
|
|
|
hdmi_intrinsic_event(codec, res, jack);
|
2010-03-08 02:44:23 +00:00
|
|
|
else
|
|
|
|
hdmi_non_intrinsic_event(codec, res);
|
|
|
|
}
|
|
|
|
|
2013-09-04 20:37:12 +00:00
|
|
|
static void haswell_verify_D0(struct hda_codec *codec,
|
2013-06-18 02:41:53 +00:00
|
|
|
hda_nid_t cvt_nid, hda_nid_t nid)
|
2013-04-10 10:26:07 +00:00
|
|
|
{
|
2013-09-04 20:37:12 +00:00
|
|
|
int pwr;
|
2013-04-10 10:26:07 +00:00
|
|
|
|
2013-06-18 02:41:53 +00:00
|
|
|
/* For Haswell, the converter 1/2 may keep in D3 state after bootup,
|
|
|
|
* thus pins could only choose converter 0 for use. Make sure the
|
|
|
|
* converters are in correct power state */
|
2013-06-18 14:28:36 +00:00
|
|
|
if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
|
2013-06-18 02:41:53 +00:00
|
|
|
snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
|
|
|
|
|
2013-06-18 14:28:36 +00:00
|
|
|
if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
|
2013-04-10 10:26:07 +00:00
|
|
|
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
|
|
|
|
AC_PWRST_D0);
|
|
|
|
msleep(40);
|
|
|
|
pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
|
|
|
|
pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
|
2020-12-11 12:45:47 +00:00
|
|
|
codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
|
2013-04-10 10:26:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
/*
|
|
|
|
* Callbacks
|
|
|
|
*/
|
|
|
|
|
2010-08-03 12:21:00 +00:00
|
|
|
/* HBR should be Non-PCM, 8 channels */
|
|
|
|
#define is_hbr_format(format) \
|
|
|
|
((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
|
|
|
|
|
2013-10-24 18:10:34 +00:00
|
|
|
static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id, bool hbr)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
2013-10-24 18:10:34 +00:00
|
|
|
int pinctl, new_pinctl;
|
2013-04-10 10:26:07 +00:00
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_set_dev_select(codec, pin_nid, dev_id);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
|
2010-08-03 10:28:58 +00:00
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
|
|
2013-11-10 18:56:10 +00:00
|
|
|
if (pinctl < 0)
|
|
|
|
return hbr ? -EINVAL : 0;
|
|
|
|
|
2010-08-03 10:28:58 +00:00
|
|
|
new_pinctl = pinctl & ~AC_PINCTL_EPT;
|
2013-10-24 18:10:34 +00:00
|
|
|
if (hbr)
|
2010-08-03 10:28:58 +00:00
|
|
|
new_pinctl |= AC_PINCTL_EPT_HBR;
|
|
|
|
else
|
|
|
|
new_pinctl |= AC_PINCTL_EPT_NATIVE;
|
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec,
|
|
|
|
"hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
pin_nid,
|
2010-08-03 10:28:58 +00:00
|
|
|
pinctl == new_pinctl ? "" : "new-",
|
|
|
|
new_pinctl);
|
|
|
|
|
|
|
|
if (pinctl != new_pinctl)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
snd_hda_codec_write(codec, pin_nid, 0,
|
2010-08-03 10:28:58 +00:00
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
|
new_pinctl);
|
2013-10-24 18:10:34 +00:00
|
|
|
} else if (hbr)
|
|
|
|
return -EINVAL;
|
2010-08-03 10:28:58 +00:00
|
|
|
|
2013-10-24 18:10:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
hda_nid_t pin_nid, int dev_id,
|
|
|
|
u32 stream_tag, int format)
|
2013-10-24 18:10:34 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2017-09-19 22:25:05 +00:00
|
|
|
unsigned int param;
|
2013-10-24 18:10:34 +00:00
|
|
|
int err;
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id,
|
|
|
|
is_hbr_format(format));
|
2013-10-24 18:10:34 +00:00
|
|
|
|
|
|
|
if (err) {
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
|
2013-10-24 18:10:34 +00:00
|
|
|
return err;
|
2010-08-03 10:28:58 +00:00
|
|
|
}
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2019-11-11 19:09:37 +00:00
|
|
|
if (spec->intel_hsw_fixup) {
|
2017-09-19 22:25:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* on recent platforms IEC Coding Type is required for HBR
|
|
|
|
* support, read current Digital Converter settings and set
|
|
|
|
* ICT bitfield if needed.
|
|
|
|
*/
|
|
|
|
param = snd_hda_codec_read(codec, cvt_nid, 0,
|
|
|
|
AC_VERB_GET_DIGI_CONVERT_1, 0);
|
|
|
|
|
|
|
|
param = (param >> 16) & ~(AC_DIG3_ICT);
|
|
|
|
|
|
|
|
/* on recent platforms ICT mode is required for HBR support */
|
|
|
|
if (is_hbr_format(format))
|
|
|
|
param |= 0x1;
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, cvt_nid, 0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_3, param);
|
|
|
|
}
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
|
2010-08-03 10:28:58 +00:00
|
|
|
return 0;
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
/* Try to find an available converter
|
|
|
|
* If pin_idx is less then zero, just try to find an available converter.
|
|
|
|
* Otherwise, try to find an available converter and get the cvt mux index
|
|
|
|
* of the pin.
|
|
|
|
*/
|
2013-06-18 13:42:14 +00:00
|
|
|
static int hdmi_choose_cvt(struct hda_codec *codec,
|
2016-03-21 11:56:46 +00:00
|
|
|
int pin_idx, int *cvt_id)
|
2010-08-13 06:45:23 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
|
|
|
struct hdmi_spec_per_cvt *per_cvt = NULL;
|
2013-06-18 13:42:14 +00:00
|
|
|
int cvt_idx, mux_idx = 0;
|
2010-08-13 06:45:23 +00:00
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
/* pin_idx < 0 means no pin will be bound to the converter */
|
|
|
|
if (pin_idx < 0)
|
|
|
|
per_pin = NULL;
|
|
|
|
else
|
|
|
|
per_pin = get_pin(spec, pin_idx);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
if (per_pin && per_pin->silent_stream) {
|
|
|
|
cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
|
|
|
|
if (cvt_id)
|
|
|
|
*cvt_id = cvt_idx;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* Dynamically assign converter to stream */
|
|
|
|
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
|
2013-03-13 13:40:31 +00:00
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
2010-08-13 06:45:23 +00:00
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* Must not already be assigned */
|
|
|
|
if (per_cvt->assigned)
|
|
|
|
continue;
|
2015-12-16 05:42:42 +00:00
|
|
|
if (per_pin == NULL)
|
|
|
|
break;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* Must be in pin's mux's list of converters */
|
|
|
|
for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
|
|
|
|
if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
|
|
|
|
break;
|
|
|
|
/* Not in mux list */
|
|
|
|
if (mux_idx == per_pin->num_mux_nids)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
}
|
2013-06-18 13:42:14 +00:00
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* No free converters */
|
|
|
|
if (cvt_idx == spec->num_cvts)
|
2015-12-16 05:42:42 +00:00
|
|
|
return -EBUSY;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
if (per_pin != NULL)
|
|
|
|
per_pin->mux_idx = mux_idx;
|
2014-03-20 05:01:06 +00:00
|
|
|
|
2013-06-18 13:42:14 +00:00
|
|
|
if (cvt_id)
|
|
|
|
*cvt_id = cvt_idx;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-20 05:01:06 +00:00
|
|
|
/* Assure the pin select the right convetor */
|
|
|
|
static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
hda_nid_t pin_nid = per_pin->pin_nid;
|
|
|
|
int mux_idx, curr;
|
|
|
|
|
|
|
|
mux_idx = per_pin->mux_idx;
|
|
|
|
curr = snd_hda_codec_read(codec, pin_nid, 0,
|
|
|
|
AC_VERB_GET_CONNECT_SEL, 0);
|
|
|
|
if (curr != mux_idx)
|
|
|
|
snd_hda_codec_write_cache(codec, pin_nid, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
|
|
|
mux_idx);
|
|
|
|
}
|
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
/* get the mux index for the converter of the pins
|
|
|
|
* converter's mux index is the same for all pins on Intel platform
|
|
|
|
*/
|
|
|
|
static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
|
|
|
|
hda_nid_t cvt_nid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->num_cvts; i++)
|
|
|
|
if (spec->cvt_nids[i] == cvt_nid)
|
|
|
|
return i;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2013-11-04 06:13:13 +00:00
|
|
|
/* Intel HDMI workaround to fix audio routing issue:
|
|
|
|
* For some Intel display codecs, pins share the same connection list.
|
|
|
|
* So a conveter can be selected by multiple pins and playback on any of these
|
|
|
|
* pins will generate sound on the external display, because audio flows from
|
|
|
|
* the same converter to the display pipeline. Also muting one pin may make
|
|
|
|
* other pins have no sound output.
|
|
|
|
* So this function assures that an assigned converter for a pin is not selected
|
|
|
|
* by any other pins.
|
|
|
|
*/
|
|
|
|
static void intel_not_share_assigned_cvt(struct hda_codec *codec,
|
2017-01-12 08:04:53 +00:00
|
|
|
hda_nid_t pin_nid,
|
|
|
|
int dev_id, int mux_idx)
|
2013-06-18 13:42:14 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2015-03-03 09:07:24 +00:00
|
|
|
hda_nid_t nid;
|
2013-09-22 00:34:45 +00:00
|
|
|
int cvt_idx, curr;
|
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
2017-01-12 08:04:53 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
|
|
|
int pin_idx;
|
|
|
|
|
|
|
|
/* configure the pins connections */
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
int dev_id_saved;
|
|
|
|
int dev_num;
|
2013-06-18 13:42:14 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
per_pin = get_pin(spec, pin_idx);
|
|
|
|
/*
|
|
|
|
* pin not connected to monitor
|
|
|
|
* no need to operate on it
|
|
|
|
*/
|
|
|
|
if (!per_pin->pcm)
|
|
|
|
continue;
|
2013-09-22 00:34:45 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
if ((per_pin->pin_nid == pin_nid) &&
|
|
|
|
(per_pin->dev_id == dev_id))
|
2013-09-22 00:34:45 +00:00
|
|
|
continue;
|
2013-06-18 13:42:14 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* if per_pin->dev_id >= dev_num,
|
|
|
|
* snd_hda_get_dev_select() will fail,
|
|
|
|
* and the following operation is unpredictable.
|
|
|
|
* So skip this situation.
|
|
|
|
*/
|
|
|
|
dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
|
|
|
|
if (per_pin->dev_id >= dev_num)
|
2013-06-18 13:42:14 +00:00
|
|
|
continue;
|
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
nid = per_pin->pin_nid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calling this function should not impact
|
|
|
|
* on the device entry selection
|
|
|
|
* So let's save the dev id for each pin,
|
|
|
|
* and restore it when return
|
|
|
|
*/
|
|
|
|
dev_id_saved = snd_hda_get_dev_select(codec, nid);
|
|
|
|
snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
|
2013-09-22 00:34:45 +00:00
|
|
|
curr = snd_hda_codec_read(codec, nid, 0,
|
2013-06-18 13:42:14 +00:00
|
|
|
AC_VERB_GET_CONNECT_SEL, 0);
|
2017-01-12 08:04:53 +00:00
|
|
|
if (curr != mux_idx) {
|
|
|
|
snd_hda_set_dev_select(codec, nid, dev_id_saved);
|
2013-09-22 00:34:45 +00:00
|
|
|
continue;
|
2017-01-12 08:04:53 +00:00
|
|
|
}
|
|
|
|
|
2013-06-18 13:42:14 +00:00
|
|
|
|
2013-09-22 00:34:45 +00:00
|
|
|
/* choose an unassigned converter. The conveters in the
|
|
|
|
* connection list are in the same order as in the codec.
|
|
|
|
*/
|
|
|
|
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
|
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
|
|
|
if (!per_cvt->assigned) {
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec,
|
2020-12-11 12:45:47 +00:00
|
|
|
"choose cvt %d for pin NID 0x%x\n",
|
|
|
|
cvt_idx, nid);
|
2013-09-22 00:34:45 +00:00
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
2013-06-18 13:42:14 +00:00
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
2013-09-22 00:34:45 +00:00
|
|
|
cvt_idx);
|
|
|
|
break;
|
|
|
|
}
|
2013-06-18 13:42:14 +00:00
|
|
|
}
|
2017-01-12 08:04:53 +00:00
|
|
|
snd_hda_set_dev_select(codec, nid, dev_id_saved);
|
2013-06-18 13:42:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
/* A wrapper of intel_not_share_asigned_cvt() */
|
|
|
|
static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
|
2017-01-12 08:04:53 +00:00
|
|
|
hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
|
2015-12-16 05:42:42 +00:00
|
|
|
{
|
|
|
|
int mux_idx;
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
/* On Intel platform, the mapping of converter nid to
|
|
|
|
* mux index of the pins are always the same.
|
|
|
|
* The pin nid may be 0, this means all pins will not
|
|
|
|
* share the converter.
|
|
|
|
*/
|
|
|
|
mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
|
|
|
|
if (mux_idx >= 0)
|
2017-01-12 08:04:53 +00:00
|
|
|
intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
|
2015-12-16 05:42:42 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
/* skeleton caller of pin_cvt_fixup ops */
|
|
|
|
static void pin_cvt_fixup(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin,
|
|
|
|
hda_nid_t cvt_nid)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (spec->ops.pin_cvt_fixup)
|
|
|
|
spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
|
|
|
|
}
|
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
/* called in hdmi_pcm_open when no pin is assigned to the PCM
|
|
|
|
* in dyn_pcm_assign mode.
|
|
|
|
*/
|
|
|
|
static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
2015-12-16 08:48:16 +00:00
|
|
|
int cvt_idx, pcm_idx;
|
2015-12-16 05:42:42 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt = NULL;
|
|
|
|
int err;
|
|
|
|
|
2015-12-16 08:48:16 +00:00
|
|
|
pcm_idx = hinfo_to_pcm_index(codec, hinfo);
|
|
|
|
if (pcm_idx < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
err = hdmi_choose_cvt(codec, -1, &cvt_idx);
|
2015-12-16 05:42:42 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
|
|
|
per_cvt->assigned = 1;
|
|
|
|
hinfo->nid = per_cvt->cvt_nid;
|
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
|
2015-12-16 05:42:42 +00:00
|
|
|
|
2015-12-16 08:48:16 +00:00
|
|
|
set_bit(pcm_idx, &spec->pcm_in_use);
|
2015-12-16 05:42:42 +00:00
|
|
|
/* todo: setup spdif ctls assign */
|
|
|
|
|
|
|
|
/* Initially set the converter's capabilities */
|
|
|
|
hinfo->channels_min = per_cvt->channels_min;
|
|
|
|
hinfo->channels_max = per_cvt->channels_max;
|
|
|
|
hinfo->rates = per_cvt->rates;
|
|
|
|
hinfo->formats = per_cvt->formats;
|
|
|
|
hinfo->maxbps = per_cvt->maxbps;
|
|
|
|
|
|
|
|
/* Store the updated parameters */
|
|
|
|
runtime->hw.channels_min = hinfo->channels_min;
|
|
|
|
runtime->hw.channels_max = hinfo->channels_max;
|
|
|
|
runtime->hw.formats = hinfo->formats;
|
|
|
|
runtime->hw.rates = hinfo->rates;
|
|
|
|
|
|
|
|
snd_pcm_hw_constraint_step(substream->runtime, 0,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-18 13:42:14 +00:00
|
|
|
/*
|
|
|
|
* HDA PCM callbacks
|
|
|
|
*/
|
|
|
|
static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
2016-03-21 11:56:46 +00:00
|
|
|
int pin_idx, cvt_idx, pcm_idx;
|
2013-06-18 13:42:14 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
|
|
|
struct hdmi_eld *eld;
|
|
|
|
struct hdmi_spec_per_cvt *per_cvt = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Validate hinfo */
|
2015-12-16 05:42:43 +00:00
|
|
|
pcm_idx = hinfo_to_pcm_index(codec, hinfo);
|
|
|
|
if (pcm_idx < 0)
|
2013-06-18 13:42:14 +00:00
|
|
|
return -EINVAL;
|
2015-12-16 05:42:43 +00:00
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
mutex_lock(&spec->pcm_lock);
|
2014-02-25 11:21:03 +00:00
|
|
|
pin_idx = hinfo_to_pin_index(codec, hinfo);
|
2015-12-16 05:42:42 +00:00
|
|
|
if (!spec->dyn_pcm_assign) {
|
|
|
|
if (snd_BUG_ON(pin_idx < 0)) {
|
2018-07-12 21:06:51 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
2015-12-16 05:42:42 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* no pin is assigned to the PCM
|
|
|
|
* PA need pcm open successfully when probe
|
|
|
|
*/
|
|
|
|
if (pin_idx < 0) {
|
|
|
|
err = hdmi_pcm_open_no_pin(hinfo, codec, substream);
|
2018-07-12 21:06:51 +00:00
|
|
|
goto unlock;
|
2015-12-16 05:42:42 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-18 13:42:14 +00:00
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx);
|
2018-07-12 21:06:51 +00:00
|
|
|
if (err < 0)
|
|
|
|
goto unlock;
|
2013-06-18 13:42:14 +00:00
|
|
|
|
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* Claim converter */
|
|
|
|
per_cvt->assigned = 1;
|
2015-12-16 05:42:42 +00:00
|
|
|
|
2015-12-16 08:48:16 +00:00
|
|
|
set_bit(pcm_idx, &spec->pcm_in_use);
|
2015-12-16 05:42:42 +00:00
|
|
|
per_pin = get_pin(spec, pin_idx);
|
ALSA: hda - hdmi: Fix programmed active channel count
Currently the converter channel count is set to the number of actual
input channels. The audio infoframe channel count field is set
similarly.
However, sometimes the used channel map does not map all input channels
to outputs. Notably, 3 channel modes (e.g. 2.1) require a dummy input
channel so there are 4 input channels. According to the HDA
specification, converter channel count should be programmed according to
the number of _active_ channels.
On Intel HDMI codecs (but not on NVIDIA), setting the converter channel
to a higher value than there are actually mapped channels to HDMI slots
will cause no audio to be output at all.
Note that the effects of this issue are currently partially masked by
other bugs that prevent the driver from actually unmapping channels in
certain cases. For example, if a 4 channel stream is first created and
prepared, it gets a FL,FR,RL,RR mapping (ALSA->HDMI slot mapping 0->0,
1->1, 2->4, 3->5). If one thereafter assigns a FR,FL,FC mapping to it,
the driver will remap 2->3 but fail to unmap 2->4 and 3->5, so there are
still 4 active channels and the issue will not trigger in this case.
These bugs will be fixed separately.
Fix the channel counts in the converter channel count field and in the
audio infoframe channel count field to match the actual number of active
channels.
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-10-04 23:25:40 +00:00
|
|
|
per_pin->cvt_nid = per_cvt->cvt_nid;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
hinfo->nid = per_cvt->cvt_nid;
|
|
|
|
|
2019-12-02 07:49:47 +00:00
|
|
|
/* flip stripe flag for the assigned stream if supported */
|
|
|
|
if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
|
|
|
|
azx_stream(get_azx_dev(substream))->stripe = 1;
|
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
|
2013-06-18 14:14:22 +00:00
|
|
|
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
2016-03-21 11:56:46 +00:00
|
|
|
per_pin->mux_idx);
|
2013-06-18 13:42:14 +00:00
|
|
|
|
|
|
|
/* configure unused pins to choose other converters */
|
2016-03-21 11:56:46 +00:00
|
|
|
pin_cvt_fixup(codec, per_pin, 0);
|
2013-06-18 13:42:14 +00:00
|
|
|
|
2015-12-16 05:42:43 +00:00
|
|
|
snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
|
2010-08-13 06:45:23 +00:00
|
|
|
|
2011-06-01 17:14:20 +00:00
|
|
|
/* Initially set the converter's capabilities */
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
hinfo->channels_min = per_cvt->channels_min;
|
|
|
|
hinfo->channels_max = per_cvt->channels_max;
|
|
|
|
hinfo->rates = per_cvt->rates;
|
|
|
|
hinfo->formats = per_cvt->formats;
|
|
|
|
hinfo->maxbps = per_cvt->maxbps;
|
2011-06-01 17:14:20 +00:00
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
eld = &per_pin->sink_eld;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* Restrict capabilities by ELD if this isn't disabled */
|
2011-06-01 17:14:16 +00:00
|
|
|
if (!static_hdmi_pcm && eld->eld_valid) {
|
2013-02-19 15:11:24 +00:00
|
|
|
snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
|
2010-08-13 06:45:23 +00:00
|
|
|
if (hinfo->channels_min > hinfo->channels_max ||
|
2013-02-01 13:01:27 +00:00
|
|
|
!hinfo->rates || !hinfo->formats) {
|
|
|
|
per_cvt->assigned = 0;
|
|
|
|
hinfo->nid = 0;
|
2015-12-16 05:42:43 +00:00
|
|
|
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
|
2018-07-12 21:06:51 +00:00
|
|
|
err = -ENODEV;
|
|
|
|
goto unlock;
|
2013-02-01 13:01:27 +00:00
|
|
|
}
|
2010-08-13 06:45:23 +00:00
|
|
|
}
|
2011-06-01 17:14:20 +00:00
|
|
|
|
|
|
|
/* Store the updated parameters */
|
2011-01-14 09:30:46 +00:00
|
|
|
runtime->hw.channels_min = hinfo->channels_min;
|
|
|
|
runtime->hw.channels_max = hinfo->channels_max;
|
|
|
|
runtime->hw.formats = hinfo->formats;
|
|
|
|
runtime->hw.rates = hinfo->rates;
|
2011-01-14 09:33:26 +00:00
|
|
|
|
|
|
|
snd_pcm_hw_constraint_step(substream->runtime, 0,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
|
2018-07-12 21:06:51 +00:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&spec->pcm_lock);
|
|
|
|
return err;
|
2010-08-13 06:45:23 +00:00
|
|
|
}
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
/*
|
|
|
|
* HDA/HDMI auto parsing
|
|
|
|
*/
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
hda_nid_t pin_nid = per_pin->pin_nid;
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id = per_pin->dev_id;
|
2019-11-27 16:12:40 +00:00
|
|
|
int conns;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_warn(codec,
|
2020-12-11 12:45:47 +00:00
|
|
|
"HDMI: pin NID 0x%x wcaps %#x does not support connection list\n",
|
2010-03-08 02:44:23 +00:00
|
|
|
pin_nid, get_wcaps(codec, pin_nid));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_set_dev_select(codec, pin_nid, dev_id);
|
|
|
|
|
2019-11-27 16:12:40 +00:00
|
|
|
if (spec->intel_hsw_fixup) {
|
|
|
|
conns = spec->num_cvts;
|
|
|
|
memcpy(per_pin->mux_nids, spec->cvt_nids,
|
|
|
|
sizeof(hda_nid_t) * conns);
|
|
|
|
} else {
|
|
|
|
conns = snd_hda_get_raw_connections(codec, pin_nid,
|
|
|
|
per_pin->mux_nids,
|
|
|
|
HDA_MAX_CONNECTIONS);
|
|
|
|
}
|
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/* all the device entries on the same pin have the same conn list */
|
2019-11-27 16:12:40 +00:00
|
|
|
per_pin->num_mux_nids = conns;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
|
2019-11-19 08:47:10 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2021-03-01 11:12:02 +00:00
|
|
|
/* on the new machines, try to assign the pcm slot dynamically,
|
|
|
|
* not use the preferred fixed map (legacy way) anymore.
|
|
|
|
*/
|
|
|
|
if (spec->dyn_pcm_no_legacy)
|
|
|
|
goto last_try;
|
|
|
|
|
2019-11-19 08:47:10 +00:00
|
|
|
/*
|
2019-11-29 14:37:55 +00:00
|
|
|
* generic_hdmi_build_pcms() may allocate extra PCMs on some
|
|
|
|
* platforms (with maximum of 'num_nids + dev_num - 1')
|
2019-11-19 08:47:10 +00:00
|
|
|
*
|
|
|
|
* The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n
|
|
|
|
* if m==0. This guarantees that dynamic pcm assignments are compatible
|
2019-11-29 14:37:55 +00:00
|
|
|
* with the legacy static per_pin-pcm assignment that existed in the
|
2019-11-19 08:47:10 +00:00
|
|
|
* days before DP-MST.
|
|
|
|
*
|
2019-12-03 15:41:05 +00:00
|
|
|
* Intel DP-MST prefers this legacy behavior for compatibility, too.
|
|
|
|
*
|
2019-11-19 08:47:10 +00:00
|
|
|
* per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)).
|
|
|
|
*/
|
2019-11-29 14:37:55 +00:00
|
|
|
|
2019-12-03 15:41:05 +00:00
|
|
|
if (per_pin->dev_id == 0 || spec->intel_hsw_fixup) {
|
2019-11-29 14:37:55 +00:00
|
|
|
if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
|
|
|
|
return per_pin->pin_nid_idx;
|
|
|
|
} else {
|
|
|
|
i = spec->num_nids + (per_pin->dev_id - 1);
|
|
|
|
if (i < spec->pcm_used && !(test_bit(i, &spec->pcm_bitmap)))
|
|
|
|
return i;
|
2019-11-19 08:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* have a second try; check the area over num_nids */
|
2017-01-12 08:04:53 +00:00
|
|
|
for (i = spec->num_nids; i < spec->pcm_used; i++) {
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
if (!test_bit(i, &spec->pcm_bitmap))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2021-03-01 11:12:02 +00:00
|
|
|
last_try:
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
/* the last try; check the empty slots in pins */
|
2017-01-12 08:04:53 +00:00
|
|
|
for (i = 0; i < spec->num_nids; i++) {
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
if (!test_bit(i, &spec->pcm_bitmap))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
/* pcm already be attached to the pin */
|
|
|
|
if (per_pin->pcm)
|
|
|
|
return;
|
|
|
|
idx = hdmi_find_pcm_slot(spec, per_pin);
|
2016-03-01 07:18:26 +00:00
|
|
|
if (idx == -EBUSY)
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
return;
|
|
|
|
per_pin->pcm_idx = idx;
|
2016-01-12 03:13:26 +00:00
|
|
|
per_pin->pcm = get_hdmi_pcm(spec, idx);
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
set_bit(idx, &spec->pcm_bitmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
/* pcm already be detached from the pin */
|
|
|
|
if (!per_pin->pcm)
|
|
|
|
return;
|
|
|
|
idx = per_pin->pcm_idx;
|
|
|
|
per_pin->pcm_idx = -1;
|
|
|
|
per_pin->pcm = NULL;
|
|
|
|
if (idx >= 0 && idx < spec->pcm_used)
|
|
|
|
clear_bit(idx, &spec->pcm_bitmap);
|
|
|
|
}
|
|
|
|
|
2015-12-16 08:48:16 +00:00
|
|
|
static int hdmi_get_pin_cvt_mux(struct hdmi_spec *spec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin, hda_nid_t cvt_nid)
|
|
|
|
{
|
|
|
|
int mux_idx;
|
|
|
|
|
|
|
|
for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
|
|
|
|
if (per_pin->mux_nids[mux_idx] == cvt_nid)
|
|
|
|
break;
|
|
|
|
return mux_idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid);
|
|
|
|
|
|
|
|
static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = per_pin->codec;
|
|
|
|
struct hda_pcm *pcm;
|
|
|
|
struct hda_pcm_stream *hinfo;
|
|
|
|
struct snd_pcm_substream *substream;
|
|
|
|
int mux_idx;
|
|
|
|
bool non_pcm;
|
|
|
|
|
|
|
|
if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used)
|
2016-01-12 03:13:26 +00:00
|
|
|
pcm = get_pcm_rec(spec, per_pin->pcm_idx);
|
2015-12-16 08:48:16 +00:00
|
|
|
else
|
|
|
|
return;
|
ALSA: hda - Skip jack and others for non-existing PCM streams
When CONFIG_SND_DYNAMIC_MINORS isn't set, there are only limited
number of devices available, and HD-audio, especially with HDMI/DP
codec, will fail to create more than two devices.
The driver warns about the lack of such devices and skips the PCM
device creations, but the HDMI driver still tries to create the
corresponding JACK, SPDIF and ELD controls even for the non-existing
PCM substreams. This results in confusion on user-space, and even may
break the operation.
Similarly, Intel HDMI/DP codec builds the ELD notification from i915
graphics driver, and this may be broken if a notification is sent for
the non-existing PCM stream.
This patch adds the check of the existence of the assigned PCM
substream in the both scenarios above, and skips the further operation
if the PCM substream is not assigned.
Fixes: 9152085defb6 ("ALSA: hda - add DP MST audio support")
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-04-25 14:19:13 +00:00
|
|
|
if (!pcm->pcm)
|
|
|
|
return;
|
2015-12-16 08:48:16 +00:00
|
|
|
if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* hdmi audio only uses playback and one substream */
|
|
|
|
hinfo = pcm->stream;
|
|
|
|
substream = pcm->pcm->streams[0].substream;
|
|
|
|
|
|
|
|
per_pin->cvt_nid = hinfo->nid;
|
|
|
|
|
|
|
|
mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
|
2017-01-12 08:04:53 +00:00
|
|
|
if (mux_idx < per_pin->num_mux_nids) {
|
|
|
|
snd_hda_set_dev_select(codec, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id);
|
2015-12-16 08:48:16 +00:00
|
|
|
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
|
|
|
mux_idx);
|
2017-01-12 08:04:53 +00:00
|
|
|
}
|
2015-12-16 08:48:16 +00:00
|
|
|
snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
|
|
|
|
|
|
|
|
non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
|
|
|
|
if (substream->runtime)
|
|
|
|
per_pin->channels = substream->runtime->channels;
|
|
|
|
per_pin->setup = true;
|
|
|
|
per_pin->mux_idx = mux_idx;
|
|
|
|
|
|
|
|
hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used)
|
|
|
|
snd_hda_spdif_ctls_unassign(per_pin->codec, per_pin->pcm_idx);
|
|
|
|
|
|
|
|
per_pin->chmap_set = false;
|
|
|
|
memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
|
|
|
|
|
|
|
|
per_pin->setup = false;
|
|
|
|
per_pin->channels = 0;
|
|
|
|
}
|
|
|
|
|
2020-02-06 16:28:04 +00:00
|
|
|
static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (per_pin->pcm_idx >= 0)
|
|
|
|
return spec->pcm_rec[per_pin->pcm_idx].jack;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-11-13 08:12:12 +00:00
|
|
|
/* update per_pin ELD from the given new ELD;
|
|
|
|
* setup info frame and notification accordingly
|
2020-02-06 16:28:04 +00:00
|
|
|
* also notify ELD kctl and report jack status changes
|
2015-11-13 08:12:12 +00:00
|
|
|
*/
|
2020-02-06 16:28:04 +00:00
|
|
|
static void update_eld(struct hda_codec *codec,
|
2015-11-13 08:12:12 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin,
|
2020-02-06 16:28:04 +00:00
|
|
|
struct hdmi_eld *eld,
|
|
|
|
int repoll)
|
2015-11-13 08:12:12 +00:00
|
|
|
{
|
|
|
|
struct hdmi_eld *pin_eld = &per_pin->sink_eld;
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2020-02-06 16:28:04 +00:00
|
|
|
struct snd_jack *pcm_jack;
|
2015-11-13 08:12:12 +00:00
|
|
|
bool old_eld_valid = pin_eld->eld_valid;
|
|
|
|
bool eld_changed;
|
2019-09-05 15:48:26 +00:00
|
|
|
int pcm_idx;
|
2015-11-13 08:12:12 +00:00
|
|
|
|
2020-02-06 16:28:04 +00:00
|
|
|
if (eld->eld_valid) {
|
|
|
|
if (eld->eld_size <= 0 ||
|
|
|
|
snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
|
|
|
|
eld->eld_size) < 0) {
|
|
|
|
eld->eld_valid = false;
|
|
|
|
if (repoll) {
|
|
|
|
schedule_delayed_work(&per_pin->work,
|
|
|
|
msecs_to_jiffies(300));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!eld->eld_valid || eld->eld_size <= 0) {
|
|
|
|
eld->eld_valid = false;
|
|
|
|
eld->eld_size = 0;
|
|
|
|
}
|
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
/* for monitor disconnection, save pcm_idx firstly */
|
|
|
|
pcm_idx = per_pin->pcm_idx;
|
2020-02-06 16:28:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* pcm_idx >=0 before update_eld() means it is in monitor
|
|
|
|
* disconnected event. Jack must be fetched before update_eld().
|
|
|
|
*/
|
|
|
|
pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
|
|
|
|
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
if (spec->dyn_pcm_assign) {
|
2015-12-16 08:48:16 +00:00
|
|
|
if (eld->eld_valid) {
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
hdmi_attach_hda_pcm(spec, per_pin);
|
2015-12-16 08:48:16 +00:00
|
|
|
hdmi_pcm_setup_pin(spec, per_pin);
|
|
|
|
} else {
|
|
|
|
hdmi_pcm_reset_pin(spec, per_pin);
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
hdmi_detach_hda_pcm(spec, per_pin);
|
2015-12-16 08:48:16 +00:00
|
|
|
}
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
}
|
2016-02-23 08:33:37 +00:00
|
|
|
/* if pcm_idx == -1, it means this is in monitor connection event
|
|
|
|
* we can get the correct pcm_idx now.
|
|
|
|
*/
|
|
|
|
if (pcm_idx == -1)
|
|
|
|
pcm_idx = per_pin->pcm_idx;
|
2020-02-06 16:28:04 +00:00
|
|
|
if (!pcm_jack)
|
|
|
|
pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
|
ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug
Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
When monitor is connected, find a proper PCM for the monitor.
When monitor is disconnected, unbind the PCM from the pin.
The binding policy (use Intel platform as example) is:
1. Try to use the legacy pin-pcm mapping for the device entry 0
of the pin.
2. If step 1 fails, try to bind pin to the backup PCMs. For example,
on Intel platform, if DP MST is enabled, 5 PCMs will be created.
PCM 3, PCM 7, PCM 8 are supposed to be used by device entry 0 of
pin 5, pin 6 and pin 7. PCM 9 and PCM 10 are the backup PCMs.
3. If step 2 fails, try to find any PCM to bind to the pin.
Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-12-16 08:48:15 +00:00
|
|
|
|
2015-11-13 08:12:12 +00:00
|
|
|
if (eld->eld_valid)
|
|
|
|
snd_hdmi_show_eld(codec, &eld->info);
|
|
|
|
|
|
|
|
eld_changed = (pin_eld->eld_valid != eld->eld_valid);
|
2019-07-17 12:30:23 +00:00
|
|
|
eld_changed |= (pin_eld->monitor_present != eld->monitor_present);
|
|
|
|
if (!eld_changed && eld->eld_valid && pin_eld->eld_valid)
|
2015-11-13 08:12:12 +00:00
|
|
|
if (pin_eld->eld_size != eld->eld_size ||
|
|
|
|
memcmp(pin_eld->eld_buffer, eld->eld_buffer,
|
|
|
|
eld->eld_size) != 0)
|
|
|
|
eld_changed = true;
|
|
|
|
|
2019-07-17 12:30:23 +00:00
|
|
|
if (eld_changed) {
|
|
|
|
pin_eld->monitor_present = eld->monitor_present;
|
|
|
|
pin_eld->eld_valid = eld->eld_valid;
|
|
|
|
pin_eld->eld_size = eld->eld_size;
|
|
|
|
if (eld->eld_valid)
|
|
|
|
memcpy(pin_eld->eld_buffer, eld->eld_buffer,
|
|
|
|
eld->eld_size);
|
|
|
|
pin_eld->info = eld->info;
|
|
|
|
}
|
2015-11-13 08:12:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-setup pin and infoframe. This is needed e.g. when
|
|
|
|
* - sink is first plugged-in
|
|
|
|
* - transcoder can change during stream playback on Haswell
|
|
|
|
* and this can make HW reset converter selection on a pin.
|
|
|
|
*/
|
|
|
|
if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
|
2016-03-21 11:56:46 +00:00
|
|
|
pin_cvt_fixup(codec, per_pin, 0);
|
2015-11-13 08:12:12 +00:00
|
|
|
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
|
|
|
|
}
|
|
|
|
|
2016-02-23 08:33:37 +00:00
|
|
|
if (eld_changed && pcm_idx >= 0)
|
2015-11-13 08:12:12 +00:00
|
|
|
snd_ctl_notify(codec->card,
|
|
|
|
SNDRV_CTL_EVENT_MASK_VALUE |
|
|
|
|
SNDRV_CTL_EVENT_MASK_INFO,
|
2016-02-23 08:33:37 +00:00
|
|
|
&get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
|
2015-11-13 08:12:12 +00:00
|
|
|
|
2020-02-06 16:28:04 +00:00
|
|
|
if (eld_changed && pcm_jack)
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
snd_jack_report(pcm_jack,
|
|
|
|
(eld->monitor_present && eld->eld_valid) ?
|
|
|
|
SND_JACK_AVOUT : 0);
|
2020-02-04 10:27:46 +00:00
|
|
|
}
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
|
2015-11-12 14:36:13 +00:00
|
|
|
/* update ELD and jack state via HD-audio verbs */
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
|
2015-11-12 14:36:13 +00:00
|
|
|
int repoll)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
2011-11-16 08:29:47 +00:00
|
|
|
struct hda_codec *codec = per_pin->codec;
|
2013-02-19 15:11:25 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_eld *eld = &spec->temp_eld;
|
2011-11-16 08:29:47 +00:00
|
|
|
hda_nid_t pin_nid = per_pin->pin_nid;
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id = per_pin->dev_id;
|
ALSA: HDA: Unify HDMI hotplug handling.
This change unifies the initial handling of a pin's state with the code to
update a pin's state after a hotplug (unsolicited response) event. The
initial probing, and all updates, are now routed through hdmi_present_sense.
The stored PD and ELDV status is now always derived from GetPinSense verb
execution, and not from the data in the unsolicited response. This means:
a) The WAR for NVIDIA codec's UR.PD values ("old_pin_detect") can be
removed, since this only affected the no-longer-used unsolicited
response payload.
b) In turn, this means that most NVIDIA codecs can simply use
patch_generic_hdmi instead of having a custom variant just to set
old_pin_detect.
c) When PD && ELDV becomes true, no extra verbs are executed, because the
GetPinSense that was previously executed by snd_hdmi_get_eld (really,
hdmi_eld_valid) has simply moved into hdmi_present_sense.
d) When PD && ELDV becomes false, there is a single extra GetPinSense verb
executed for codecs where old_pin_detect wasn't set, i.e. some NVIDIA,
and all ATI/AMD and Intel codecs. I doubt this will be a performance
issue.
The new unified code in hdmi_present_sense also ensures that eld->eld_valid
is not set unless eld->monitor_present is also set. This protects against
potential invalid combinations of PD and ELDV received from HW, and
transitively from a graphics driver.
Also, print the derived PD/ELDV bits from hdmi_present_sense so the kernel
log always displays the actual state stored, which will differ from the
values in the unsolicited response for NVIDIA HW where old_pin_detect was
previously set.
Finally, a couple of small tweaks originally by Takashi:
* Clear the ELD content to zero before reading it, so that if it's not
read (i.e. when !(PD && ELDV)) it's in a known state.
* Don't show ELD fields in /proc ELD files when the ELD isn't valid.
The only possibility I can see for regression here is a codec where the
GetPinSense verb returns incorrect data. However, we're already exposed
to that, since that data is used (a) from hdmi_add_pin to set up the
initial pin state, and (b) within snd_hda_input_jack_report to query
a pin's presence value. As such, I don't believe any HW has bugs here.
Includes-changes-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-05-24 23:11:17 +00:00
|
|
|
/*
|
|
|
|
* Always execute a GetPinSense verb here, even when called from
|
|
|
|
* hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
|
|
|
|
* response's PD bit is not the real PD value, but indicates that
|
|
|
|
* the real PD value changed. An older version of the HD-audio
|
|
|
|
* specification worked this way. Hence, we just ignore the data in
|
|
|
|
* the unsolicited response to avoid custom WARs.
|
|
|
|
*/
|
2013-12-18 09:46:04 +00:00
|
|
|
int present;
|
2020-02-06 16:28:03 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = snd_hda_power_up_pm(codec);
|
|
|
|
if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec)))
|
|
|
|
goto out;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
|
2013-12-18 09:46:04 +00:00
|
|
|
|
2013-10-17 16:21:12 +00:00
|
|
|
mutex_lock(&per_pin->lock);
|
2016-04-13 07:45:53 +00:00
|
|
|
eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
|
|
|
|
if (eld->monitor_present)
|
2013-02-19 15:11:25 +00:00
|
|
|
eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
|
|
|
|
else
|
|
|
|
eld->eld_valid = false;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec,
|
2020-12-11 12:45:47 +00:00
|
|
|
"HDMI status: Codec=%d NID=0x%x Presence_Detect=%d ELD_Valid=%d\n",
|
2016-04-13 07:45:53 +00:00
|
|
|
codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
|
ALSA: HDA: Unify HDMI hotplug handling.
This change unifies the initial handling of a pin's state with the code to
update a pin's state after a hotplug (unsolicited response) event. The
initial probing, and all updates, are now routed through hdmi_present_sense.
The stored PD and ELDV status is now always derived from GetPinSense verb
execution, and not from the data in the unsolicited response. This means:
a) The WAR for NVIDIA codec's UR.PD values ("old_pin_detect") can be
removed, since this only affected the no-longer-used unsolicited
response payload.
b) In turn, this means that most NVIDIA codecs can simply use
patch_generic_hdmi instead of having a custom variant just to set
old_pin_detect.
c) When PD && ELDV becomes true, no extra verbs are executed, because the
GetPinSense that was previously executed by snd_hdmi_get_eld (really,
hdmi_eld_valid) has simply moved into hdmi_present_sense.
d) When PD && ELDV becomes false, there is a single extra GetPinSense verb
executed for codecs where old_pin_detect wasn't set, i.e. some NVIDIA,
and all ATI/AMD and Intel codecs. I doubt this will be a performance
issue.
The new unified code in hdmi_present_sense also ensures that eld->eld_valid
is not set unless eld->monitor_present is also set. This protects against
potential invalid combinations of PD and ELDV received from HW, and
transitively from a graphics driver.
Also, print the derived PD/ELDV bits from hdmi_present_sense so the kernel
log always displays the actual state stored, which will differ from the
values in the unsolicited response for NVIDIA HW where old_pin_detect was
previously set.
Finally, a couple of small tweaks originally by Takashi:
* Clear the ELD content to zero before reading it, so that if it's not
read (i.e. when !(PD && ELDV)) it's in a known state.
* Don't show ELD fields in /proc ELD files when the ELD isn't valid.
The only possibility I can see for regression here is a codec where the
GetPinSense verb returns incorrect data. However, we're already exposed
to that, since that data is used (a) from hdmi_add_pin to set up the
initial pin state, and (b) within snd_hda_input_jack_report to query
a pin's presence value. As such, I don't believe any HW has bugs here.
Includes-changes-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-05-24 23:11:17 +00:00
|
|
|
|
2013-02-19 15:11:25 +00:00
|
|
|
if (eld->eld_valid) {
|
2019-11-19 08:47:09 +00:00
|
|
|
if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
|
|
|
|
eld->eld_buffer, &eld->eld_size) < 0)
|
2013-02-19 15:11:25 +00:00
|
|
|
eld->eld_valid = false;
|
2011-11-16 08:29:47 +00:00
|
|
|
}
|
2013-02-19 15:11:25 +00:00
|
|
|
|
2020-02-06 16:28:04 +00:00
|
|
|
update_eld(codec, per_pin, eld, repoll);
|
2020-02-04 10:27:46 +00:00
|
|
|
mutex_unlock(&per_pin->lock);
|
2020-02-06 16:28:03 +00:00
|
|
|
out:
|
|
|
|
snd_hda_power_down_pm(codec);
|
2016-02-19 07:42:06 +00:00
|
|
|
}
|
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
#define I915_SILENT_RATE 48000
|
|
|
|
#define I915_SILENT_CHANNELS 2
|
|
|
|
#define I915_SILENT_FORMAT SNDRV_PCM_FORMAT_S16_LE
|
|
|
|
#define I915_SILENT_FORMAT_BITS 16
|
|
|
|
#define I915_SILENT_FMT_MASK 0xf
|
|
|
|
|
2020-07-06 20:53:17 +00:00
|
|
|
static void silent_stream_enable(struct hda_codec *codec,
|
2020-12-10 17:44:45 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
2020-07-06 20:53:17 +00:00
|
|
|
{
|
2020-12-10 17:44:45 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
|
|
|
int cvt_idx, pin_idx, err;
|
|
|
|
unsigned int format;
|
2020-07-06 20:53:17 +00:00
|
|
|
|
|
|
|
mutex_lock(&per_pin->lock);
|
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
if (per_pin->setup) {
|
|
|
|
codec_dbg(codec, "hdmi: PCM already open, no silent stream\n");
|
|
|
|
goto unlock_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id);
|
|
|
|
err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx);
|
|
|
|
if (err) {
|
|
|
|
codec_err(codec, "hdmi: no free converter to enable silent mode\n");
|
|
|
|
goto unlock_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
|
|
|
per_cvt->assigned = 1;
|
|
|
|
per_pin->cvt_nid = per_cvt->cvt_nid;
|
|
|
|
per_pin->silent_stream = true;
|
|
|
|
|
|
|
|
codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n",
|
|
|
|
per_pin->pin_nid, per_cvt->cvt_nid);
|
2020-07-06 20:53:17 +00:00
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
|
|
|
|
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
|
|
|
per_pin->mux_idx);
|
2020-07-06 20:53:17 +00:00
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
/* configure unused pins to choose other converters */
|
|
|
|
pin_cvt_fixup(codec, per_pin, 0);
|
|
|
|
|
|
|
|
snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id, I915_SILENT_RATE);
|
|
|
|
|
|
|
|
/* trigger silent stream generation in hw */
|
|
|
|
format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS,
|
|
|
|
I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0);
|
|
|
|
snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
|
|
|
|
I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
|
|
|
|
usleep_range(100, 200);
|
|
|
|
snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
|
|
|
|
|
|
|
|
per_pin->channels = I915_SILENT_CHANNELS;
|
2020-07-06 20:53:17 +00:00
|
|
|
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
|
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
unlock_out:
|
2020-07-06 20:53:17 +00:00
|
|
|
mutex_unlock(&per_pin->lock);
|
|
|
|
}
|
|
|
|
|
2020-12-10 17:44:45 +00:00
|
|
|
static void silent_stream_disable(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
|
|
|
int cvt_idx;
|
|
|
|
|
|
|
|
mutex_lock(&per_pin->lock);
|
|
|
|
if (!per_pin->silent_stream)
|
|
|
|
goto unlock_out;
|
|
|
|
|
|
|
|
codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n",
|
|
|
|
per_pin->pin_nid, per_pin->cvt_nid);
|
|
|
|
|
|
|
|
cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
|
|
|
|
if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) {
|
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
|
|
|
per_cvt->assigned = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
per_pin->cvt_nid = 0;
|
|
|
|
per_pin->silent_stream = false;
|
|
|
|
|
|
|
|
unlock_out:
|
2021-01-01 08:38:52 +00:00
|
|
|
mutex_unlock(&per_pin->lock);
|
2020-12-10 17:44:45 +00:00
|
|
|
}
|
|
|
|
|
2015-11-12 14:36:13 +00:00
|
|
|
/* update ELD and jack state via audio component */
|
|
|
|
static void sync_eld_via_acomp(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_eld *eld = &spec->temp_eld;
|
2020-07-06 20:53:17 +00:00
|
|
|
bool monitor_prev, monitor_next;
|
2015-11-12 14:36:13 +00:00
|
|
|
|
2015-12-01 11:39:38 +00:00
|
|
|
mutex_lock(&per_pin->lock);
|
2016-03-21 15:07:30 +00:00
|
|
|
eld->monitor_present = false;
|
2020-07-06 20:53:17 +00:00
|
|
|
monitor_prev = per_pin->sink_eld.monitor_present;
|
2020-02-06 16:28:04 +00:00
|
|
|
eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
|
2017-01-12 08:04:53 +00:00
|
|
|
per_pin->dev_id, &eld->monitor_present,
|
|
|
|
eld->eld_buffer, ELD_MAX_SIZE);
|
2020-02-06 16:28:04 +00:00
|
|
|
eld->eld_valid = (eld->eld_size > 0);
|
|
|
|
update_eld(codec, per_pin, eld, 0);
|
2020-07-06 20:53:17 +00:00
|
|
|
monitor_next = per_pin->sink_eld.monitor_present;
|
2015-12-01 11:39:38 +00:00
|
|
|
mutex_unlock(&per_pin->lock);
|
2020-07-06 20:53:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Power-up will call hdmi_present_sense, so the PM calls
|
|
|
|
* have to be done without mutex held.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (spec->send_silent_stream) {
|
|
|
|
int pm_ret;
|
|
|
|
|
|
|
|
if (!monitor_prev && monitor_next) {
|
|
|
|
pm_ret = snd_hda_power_up_pm(codec);
|
|
|
|
if (pm_ret < 0)
|
|
|
|
codec_err(codec,
|
|
|
|
"Monitor plugged-in, Failed to power up codec ret=[%d]\n",
|
|
|
|
pm_ret);
|
|
|
|
silent_stream_enable(codec, per_pin);
|
|
|
|
} else if (monitor_prev && !monitor_next) {
|
2020-12-10 17:44:45 +00:00
|
|
|
silent_stream_disable(codec, per_pin);
|
2020-07-06 20:53:17 +00:00
|
|
|
pm_ret = snd_hda_power_down_pm(codec);
|
|
|
|
if (pm_ret < 0)
|
|
|
|
codec_err(codec,
|
|
|
|
"Monitor plugged-out, Failed to power down codec ret=[%d]\n",
|
|
|
|
pm_ret);
|
|
|
|
}
|
|
|
|
}
|
2015-11-12 14:36:13 +00:00
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
2015-11-12 14:36:13 +00:00
|
|
|
{
|
|
|
|
struct hda_codec *codec = per_pin->codec;
|
|
|
|
|
2020-02-06 16:28:03 +00:00
|
|
|
if (!codec_has_acomp(codec))
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
hdmi_present_sense_via_verbs(per_pin, repoll);
|
2020-02-06 16:28:03 +00:00
|
|
|
else
|
2015-11-12 14:36:13 +00:00
|
|
|
sync_eld_via_acomp(codec, per_pin);
|
|
|
|
}
|
|
|
|
|
2011-11-16 08:29:47 +00:00
|
|
|
static void hdmi_repoll_eld(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct hdmi_spec_per_pin *per_pin =
|
|
|
|
container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
|
2018-06-27 06:25:32 +00:00
|
|
|
struct hda_codec *codec = per_pin->codec;
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda/hdmi - Read the pin sense from register when repolling
The driver will check the monitor presence when resuming from suspend,
starting poll or interrupt triggers. In these 3 situations, the
jack_dirty will be set to 1 first, then the hda_jack.c reads the
pin_sense from register, after reading the register, the jack_dirty
will be set to 0. But hdmi_repoll_work() is enabled in these 3
situations, It will read the pin_sense a couple of times subsequently,
since the jack_dirty is 0 now, It does not read the register anymore,
instead it uses the shadow pin_sense which is read at the first time.
It is meaningless to check the shadow pin_sense a couple of times,
we need to read the register to check the real plugging state, so
we set the jack_dirty to 1 in the hdmi_repoll_work().
Signed-off-by: Hui Wang <hui.wang@canonical.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2019-05-06 14:09:31 +00:00
|
|
|
struct hda_jack_tbl *jack;
|
|
|
|
|
2019-11-19 08:47:08 +00:00
|
|
|
jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id);
|
ALSA: hda/hdmi - Read the pin sense from register when repolling
The driver will check the monitor presence when resuming from suspend,
starting poll or interrupt triggers. In these 3 situations, the
jack_dirty will be set to 1 first, then the hda_jack.c reads the
pin_sense from register, after reading the register, the jack_dirty
will be set to 0. But hdmi_repoll_work() is enabled in these 3
situations, It will read the pin_sense a couple of times subsequently,
since the jack_dirty is 0 now, It does not read the register anymore,
instead it uses the shadow pin_sense which is read at the first time.
It is meaningless to check the shadow pin_sense a couple of times,
we need to read the register to check the real plugging state, so
we set the jack_dirty to 1 in the hdmi_repoll_work().
Signed-off-by: Hui Wang <hui.wang@canonical.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2019-05-06 14:09:31 +00:00
|
|
|
if (jack)
|
|
|
|
jack->jack_dirty = 1;
|
2011-11-16 08:29:47 +00:00
|
|
|
|
2011-11-18 22:59:32 +00:00
|
|
|
if (per_pin->repoll_count++ > 6)
|
|
|
|
per_pin->repoll_count = 0;
|
|
|
|
|
2018-06-27 06:25:32 +00:00
|
|
|
mutex_lock(&spec->pcm_lock);
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
hdmi_present_sense(per_pin, per_pin->repoll_count);
|
2018-06-27 06:25:32 +00:00
|
|
|
mutex_unlock(&spec->pcm_lock);
|
2011-11-16 08:29:47 +00:00
|
|
|
}
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
unsigned int caps, config;
|
|
|
|
int pin_idx;
|
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2011-05-19 09:46:03 +00:00
|
|
|
int err;
|
2017-01-12 08:04:53 +00:00
|
|
|
int dev_num, i;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2012-11-21 13:27:37 +00:00
|
|
|
caps = snd_hda_query_pin_caps(codec, pin_nid);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
|
|
|
|
return 0;
|
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* For DP MST audio, Configuration Default is the same for
|
|
|
|
* all device entries on the same pin
|
|
|
|
*/
|
2012-11-21 13:27:37 +00:00
|
|
|
config = snd_hda_codec_get_pincfg(codec, pin_nid);
|
2020-08-04 15:58:34 +00:00
|
|
|
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE &&
|
|
|
|
!spec->force_connect)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* To simplify the implementation, malloc all
|
|
|
|
* the virtual pins in the initialization statically
|
|
|
|
*/
|
2019-11-11 19:09:37 +00:00
|
|
|
if (spec->intel_hsw_fixup) {
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
2021-03-24 17:23:37 +00:00
|
|
|
* On Intel platforms, device entries count returned
|
|
|
|
* by AC_PAR_DEVLIST_LEN is dynamic, and depends on
|
|
|
|
* the type of receiver that is connected. Allocate pin
|
|
|
|
* structures based on worst case.
|
2017-01-12 08:04:53 +00:00
|
|
|
*/
|
2021-03-24 17:23:37 +00:00
|
|
|
dev_num = spec->dev_num;
|
2017-01-12 08:04:53 +00:00
|
|
|
} else if (spec->dyn_pcm_assign && codec->dp_mst) {
|
|
|
|
dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
|
|
|
|
/*
|
|
|
|
* spec->dev_num is the maxinum number of device entries
|
|
|
|
* among all the pins
|
|
|
|
*/
|
|
|
|
spec->dev_num = (spec->dev_num > dev_num) ?
|
|
|
|
spec->dev_num : dev_num;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If the platform doesn't support DP MST,
|
|
|
|
* manually set dev_num to 1. This means
|
|
|
|
* the pin has only one device entry.
|
|
|
|
*/
|
|
|
|
dev_num = 1;
|
|
|
|
spec->dev_num = 1;
|
2016-01-12 03:13:26 +00:00
|
|
|
}
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
for (i = 0; i < dev_num; i++) {
|
|
|
|
pin_idx = spec->num_pins;
|
|
|
|
per_pin = snd_array_new(&spec->pins);
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
if (!per_pin)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (spec->dyn_pcm_assign) {
|
|
|
|
per_pin->pcm = NULL;
|
|
|
|
per_pin->pcm_idx = -1;
|
|
|
|
} else {
|
|
|
|
per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
|
|
|
|
per_pin->pcm_idx = pin_idx;
|
|
|
|
}
|
|
|
|
per_pin->pin_nid = pin_nid;
|
|
|
|
per_pin->pin_nid_idx = spec->num_nids;
|
|
|
|
per_pin->dev_id = i;
|
|
|
|
per_pin->non_pcm = false;
|
|
|
|
snd_hda_set_dev_select(codec, pin_nid, i);
|
|
|
|
err = hdmi_read_pin_conn(codec, pin_idx);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec->num_pins++;
|
|
|
|
}
|
|
|
|
spec->num_nids++;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
return 0;
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
|
2010-03-08 02:44:23 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
|
|
|
unsigned int chans;
|
|
|
|
int err;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
chans = get_wcaps(codec, cvt_nid);
|
|
|
|
chans = get_wcaps_channels(chans);
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
per_cvt = snd_array_new(&spec->cvts);
|
|
|
|
if (!per_cvt)
|
|
|
|
return -ENOMEM;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
|
|
|
per_cvt->cvt_nid = cvt_nid;
|
|
|
|
per_cvt->channels_min = 2;
|
2012-07-31 09:36:00 +00:00
|
|
|
if (chans <= 16) {
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
per_cvt->channels_max = chans;
|
2016-03-04 14:29:46 +00:00
|
|
|
if (chans > spec->chmap.channels_max)
|
|
|
|
spec->chmap.channels_max = chans;
|
2012-07-31 09:36:00 +00:00
|
|
|
}
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
|
|
|
err = snd_hda_query_supported_pcm(codec, cvt_nid,
|
|
|
|
&per_cvt->rates,
|
|
|
|
&per_cvt->formats,
|
|
|
|
&per_cvt->maxbps);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
|
|
|
|
spec->cvt_nids[spec->num_cvts] = cvt_nid;
|
|
|
|
spec->num_cvts++;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-04 15:58:34 +00:00
|
|
|
static const struct snd_pci_quirk force_connect_list[] = {
|
2020-08-11 09:53:34 +00:00
|
|
|
SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
|
2020-08-04 15:58:34 +00:00
|
|
|
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2010-03-08 02:44:23 +00:00
|
|
|
static int hdmi_parse_codec(struct hda_codec *codec)
|
|
|
|
{
|
2020-08-04 15:58:34 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
When HDMI PCM devices are opened in a specific order, with at least one
HDMI/DP receiver connected, ALSA PCM open fails to -EBUSY on the
connected monitor, on recent Intel platforms (ICL/JSL and newer). While
this is not a typical sequence, at least Pulseaudio does this every time
when it is started, to discover the available PCMs.
The rootcause is an invalid assumption in hdmi_add_pin(), where the
total number of converters is assumed to be known at the time the
function is called. On older Intel platforms this held true, but after
ICL/JSL, the order how pins and converters are in the subnode list as
returned by snd_hda_get_sub_nodes(), was changed. As a result,
information for some converters was not stored to per_pin->mux_nids.
And this means some pins cannot be connected to all converters, and
application instead gets -EBUSY instead at open.
The assumption that converters are always before pins in the subnode
list, is not really a valid one. Fix the problem in hdmi_parse_codec()
by introducing separate loops for discovering converters and pins.
BugLink: https://github.com/thesofproject/linux/issues/1978
BugLink: https://github.com/thesofproject/linux/issues/2216
BugLink: https://github.com/thesofproject/linux/issues/2217
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200703153818.2808592-1-kai.vehmanen@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-07-03 15:38:17 +00:00
|
|
|
hda_nid_t start_nid;
|
|
|
|
unsigned int caps;
|
2010-03-08 02:44:23 +00:00
|
|
|
int i, nodes;
|
2020-08-04 15:58:34 +00:00
|
|
|
const struct snd_pci_quirk *q;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
When HDMI PCM devices are opened in a specific order, with at least one
HDMI/DP receiver connected, ALSA PCM open fails to -EBUSY on the
connected monitor, on recent Intel platforms (ICL/JSL and newer). While
this is not a typical sequence, at least Pulseaudio does this every time
when it is started, to discover the available PCMs.
The rootcause is an invalid assumption in hdmi_add_pin(), where the
total number of converters is assumed to be known at the time the
function is called. On older Intel platforms this held true, but after
ICL/JSL, the order how pins and converters are in the subnode list as
returned by snd_hda_get_sub_nodes(), was changed. As a result,
information for some converters was not stored to per_pin->mux_nids.
And this means some pins cannot be connected to all converters, and
application instead gets -EBUSY instead at open.
The assumption that converters are always before pins in the subnode
list, is not really a valid one. Fix the problem in hdmi_parse_codec()
by introducing separate loops for discovering converters and pins.
BugLink: https://github.com/thesofproject/linux/issues/1978
BugLink: https://github.com/thesofproject/linux/issues/2216
BugLink: https://github.com/thesofproject/linux/issues/2217
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200703153818.2808592-1-kai.vehmanen@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-07-03 15:38:17 +00:00
|
|
|
nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
|
|
|
|
if (!start_nid || nodes < 0) {
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
|
2010-03-08 02:44:23 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-08-04 15:58:34 +00:00
|
|
|
q = snd_pci_quirk_lookup(codec->bus->pci, force_connect_list);
|
|
|
|
|
|
|
|
if (q && q->value)
|
|
|
|
spec->force_connect = true;
|
|
|
|
|
ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
When HDMI PCM devices are opened in a specific order, with at least one
HDMI/DP receiver connected, ALSA PCM open fails to -EBUSY on the
connected monitor, on recent Intel platforms (ICL/JSL and newer). While
this is not a typical sequence, at least Pulseaudio does this every time
when it is started, to discover the available PCMs.
The rootcause is an invalid assumption in hdmi_add_pin(), where the
total number of converters is assumed to be known at the time the
function is called. On older Intel platforms this held true, but after
ICL/JSL, the order how pins and converters are in the subnode list as
returned by snd_hda_get_sub_nodes(), was changed. As a result,
information for some converters was not stored to per_pin->mux_nids.
And this means some pins cannot be connected to all converters, and
application instead gets -EBUSY instead at open.
The assumption that converters are always before pins in the subnode
list, is not really a valid one. Fix the problem in hdmi_parse_codec()
by introducing separate loops for discovering converters and pins.
BugLink: https://github.com/thesofproject/linux/issues/1978
BugLink: https://github.com/thesofproject/linux/issues/2216
BugLink: https://github.com/thesofproject/linux/issues/2217
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200703153818.2808592-1-kai.vehmanen@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-07-03 15:38:17 +00:00
|
|
|
/*
|
|
|
|
* hdmi_add_pin() assumes total amount of converters to
|
|
|
|
* be known, so first discover all converters
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nodes; i++) {
|
|
|
|
hda_nid_t nid = start_nid + i;
|
2010-03-08 02:44:23 +00:00
|
|
|
|
2012-11-21 13:27:37 +00:00
|
|
|
caps = get_wcaps(codec, nid);
|
2010-03-08 02:44:23 +00:00
|
|
|
|
|
|
|
if (!(caps & AC_WCAP_DIGITAL))
|
|
|
|
continue;
|
|
|
|
|
ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
When HDMI PCM devices are opened in a specific order, with at least one
HDMI/DP receiver connected, ALSA PCM open fails to -EBUSY on the
connected monitor, on recent Intel platforms (ICL/JSL and newer). While
this is not a typical sequence, at least Pulseaudio does this every time
when it is started, to discover the available PCMs.
The rootcause is an invalid assumption in hdmi_add_pin(), where the
total number of converters is assumed to be known at the time the
function is called. On older Intel platforms this held true, but after
ICL/JSL, the order how pins and converters are in the subnode list as
returned by snd_hda_get_sub_nodes(), was changed. As a result,
information for some converters was not stored to per_pin->mux_nids.
And this means some pins cannot be connected to all converters, and
application instead gets -EBUSY instead at open.
The assumption that converters are always before pins in the subnode
list, is not really a valid one. Fix the problem in hdmi_parse_codec()
by introducing separate loops for discovering converters and pins.
BugLink: https://github.com/thesofproject/linux/issues/1978
BugLink: https://github.com/thesofproject/linux/issues/2216
BugLink: https://github.com/thesofproject/linux/issues/2217
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200703153818.2808592-1-kai.vehmanen@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-07-03 15:38:17 +00:00
|
|
|
if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
hdmi_add_cvt(codec, nid);
|
ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
When HDMI PCM devices are opened in a specific order, with at least one
HDMI/DP receiver connected, ALSA PCM open fails to -EBUSY on the
connected monitor, on recent Intel platforms (ICL/JSL and newer). While
this is not a typical sequence, at least Pulseaudio does this every time
when it is started, to discover the available PCMs.
The rootcause is an invalid assumption in hdmi_add_pin(), where the
total number of converters is assumed to be known at the time the
function is called. On older Intel platforms this held true, but after
ICL/JSL, the order how pins and converters are in the subnode list as
returned by snd_hda_get_sub_nodes(), was changed. As a result,
information for some converters was not stored to per_pin->mux_nids.
And this means some pins cannot be connected to all converters, and
application instead gets -EBUSY instead at open.
The assumption that converters are always before pins in the subnode
list, is not really a valid one. Fix the problem in hdmi_parse_codec()
by introducing separate loops for discovering converters and pins.
BugLink: https://github.com/thesofproject/linux/issues/1978
BugLink: https://github.com/thesofproject/linux/issues/2216
BugLink: https://github.com/thesofproject/linux/issues/2217
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200703153818.2808592-1-kai.vehmanen@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-07-03 15:38:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* discover audio pins */
|
|
|
|
for (i = 0; i < nodes; i++) {
|
|
|
|
hda_nid_t nid = start_nid + i;
|
|
|
|
|
|
|
|
caps = get_wcaps(codec, nid);
|
|
|
|
|
|
|
|
if (!(caps & AC_WCAP_DIGITAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (get_wcaps_type(caps) == AC_WID_PIN)
|
2010-05-14 08:36:15 +00:00
|
|
|
hdmi_add_pin(codec, nid);
|
2010-03-08 02:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
/*
|
|
|
|
*/
|
2012-09-06 15:42:08 +00:00
|
|
|
static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
|
|
|
|
{
|
|
|
|
struct hda_spdif_out *spdif;
|
|
|
|
bool non_pcm;
|
|
|
|
|
|
|
|
mutex_lock(&codec->spdif_mutex);
|
|
|
|
spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
|
2016-06-16 03:13:25 +00:00
|
|
|
/* Add sanity check to pass klockwork check.
|
|
|
|
* This should never happen.
|
|
|
|
*/
|
2020-04-26 13:17:22 +00:00
|
|
|
if (WARN_ON(spdif == NULL)) {
|
|
|
|
mutex_unlock(&codec->spdif_mutex);
|
2016-06-16 03:13:25 +00:00
|
|
|
return true;
|
2020-04-26 13:17:22 +00:00
|
|
|
}
|
2012-09-06 15:42:08 +00:00
|
|
|
non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
|
|
|
|
mutex_unlock(&codec->spdif_mutex);
|
|
|
|
return non_pcm;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
/*
|
|
|
|
* HDMI callbacks
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
hda_nid_t cvt_nid = hinfo->nid;
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2015-12-16 05:42:42 +00:00
|
|
|
int pin_idx;
|
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2015-09-02 06:11:40 +00:00
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
2012-09-06 15:42:08 +00:00
|
|
|
bool non_pcm;
|
2019-01-14 18:21:12 +00:00
|
|
|
int pinctl, stripe;
|
2018-07-12 21:06:51 +00:00
|
|
|
int err = 0;
|
2012-09-06 15:42:08 +00:00
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
mutex_lock(&spec->pcm_lock);
|
|
|
|
pin_idx = hinfo_to_pin_index(codec, hinfo);
|
|
|
|
if (spec->dyn_pcm_assign && pin_idx < 0) {
|
|
|
|
/* when dyn_pcm_assign and pcm is not bound to a pin
|
|
|
|
* skip pin setup and return 0 to make audio playback
|
|
|
|
* be ongoing
|
|
|
|
*/
|
2016-03-21 11:56:46 +00:00
|
|
|
pin_cvt_fixup(codec, NULL, cvt_nid);
|
2015-12-16 05:42:42 +00:00
|
|
|
snd_hda_codec_setup_stream(codec, cvt_nid,
|
|
|
|
stream_tag, 0, format);
|
2018-07-12 21:06:51 +00:00
|
|
|
goto unlock;
|
2015-12-16 05:42:42 +00:00
|
|
|
}
|
2012-09-06 15:42:08 +00:00
|
|
|
|
2015-12-16 05:42:42 +00:00
|
|
|
if (snd_BUG_ON(pin_idx < 0)) {
|
2018-07-12 21:06:51 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
2015-12-16 05:42:42 +00:00
|
|
|
}
|
|
|
|
per_pin = get_pin(spec, pin_idx);
|
2016-03-21 11:56:46 +00:00
|
|
|
|
|
|
|
/* Verify pin:cvt selections to avoid silent audio after S3.
|
|
|
|
* After S3, the audio driver restores pin:cvt selections
|
|
|
|
* but this can happen before gfx is ready and such selection
|
|
|
|
* is overlooked by HW. Thus multiple pins can share a same
|
|
|
|
* default convertor and mute control will affect each other,
|
|
|
|
* which can cause a resumed audio playback become silent
|
|
|
|
* after S3.
|
|
|
|
*/
|
|
|
|
pin_cvt_fixup(codec, per_pin, 0);
|
2014-03-20 05:01:06 +00:00
|
|
|
|
2015-09-02 06:11:40 +00:00
|
|
|
/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
|
|
|
|
/* Todo: add DP1.2 MST audio support later */
|
2016-03-18 18:45:13 +00:00
|
|
|
if (codec_has_acomp(codec))
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id, runtime->rate);
|
2015-09-02 06:11:40 +00:00
|
|
|
|
2012-09-06 15:42:08 +00:00
|
|
|
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
|
2013-10-17 16:21:12 +00:00
|
|
|
mutex_lock(&per_pin->lock);
|
2013-09-02 10:33:02 +00:00
|
|
|
per_pin->channels = substream->runtime->channels;
|
|
|
|
per_pin->setup = true;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2019-01-14 18:21:12 +00:00
|
|
|
if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) {
|
|
|
|
stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core,
|
|
|
|
substream);
|
|
|
|
snd_hda_codec_write(codec, cvt_nid, 0,
|
|
|
|
AC_VERB_SET_STRIPE_CONTROL,
|
|
|
|
stripe);
|
|
|
|
}
|
|
|
|
|
2013-09-02 10:33:02 +00:00
|
|
|
hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
|
2013-10-17 16:21:12 +00:00
|
|
|
mutex_unlock(&per_pin->lock);
|
2014-01-30 18:52:16 +00:00
|
|
|
if (spec->dyn_pin_out) {
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_set_dev_select(codec, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id);
|
|
|
|
pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
|
2014-01-30 18:52:16 +00:00
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_codec_write(codec, per_pin->pin_nid, 0,
|
2014-01-30 18:52:16 +00:00
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
|
pinctl | PIN_OUT);
|
|
|
|
}
|
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/* snd_hda_set_dev_select() has been called before */
|
2019-11-19 08:47:09 +00:00
|
|
|
err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id, stream_tag, format);
|
2018-07-12 21:06:51 +00:00
|
|
|
unlock:
|
2015-12-16 05:42:42 +00:00
|
|
|
mutex_unlock(&spec->pcm_lock);
|
|
|
|
return err;
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
|
|
|
|
2012-08-06 12:49:36 +00:00
|
|
|
static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
snd_hda_codec_cleanup_stream(codec, hinfo->nid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-26 16:08:14 +00:00
|
|
|
static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2015-12-16 05:42:43 +00:00
|
|
|
int cvt_idx, pin_idx, pcm_idx;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2014-01-30 18:52:16 +00:00
|
|
|
int pinctl;
|
2018-07-12 21:06:51 +00:00
|
|
|
int err = 0;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2020-10-13 15:26:28 +00:00
|
|
|
mutex_lock(&spec->pcm_lock);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
if (hinfo->nid) {
|
2015-12-16 05:42:43 +00:00
|
|
|
pcm_idx = hinfo_to_pcm_index(codec, hinfo);
|
2020-10-13 15:26:28 +00:00
|
|
|
if (snd_BUG_ON(pcm_idx < 0)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2014-02-25 11:21:03 +00:00
|
|
|
cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
|
2020-10-13 15:26:28 +00:00
|
|
|
if (snd_BUG_ON(cvt_idx < 0)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2013-03-13 13:40:31 +00:00
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
per_cvt->assigned = 0;
|
|
|
|
hinfo->nid = 0;
|
|
|
|
|
2019-12-14 17:52:17 +00:00
|
|
|
azx_stream(get_azx_dev(substream))->stripe = 0;
|
|
|
|
|
2016-01-29 05:53:27 +00:00
|
|
|
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
|
2015-12-16 08:48:16 +00:00
|
|
|
clear_bit(pcm_idx, &spec->pcm_in_use);
|
2014-02-25 11:21:03 +00:00
|
|
|
pin_idx = hinfo_to_pin_index(codec, hinfo);
|
2018-07-12 21:06:51 +00:00
|
|
|
if (spec->dyn_pcm_assign && pin_idx < 0)
|
|
|
|
goto unlock;
|
2015-12-16 05:42:42 +00:00
|
|
|
|
|
|
|
if (snd_BUG_ON(pin_idx < 0)) {
|
2018-07-12 21:06:51 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
2015-12-16 05:42:42 +00:00
|
|
|
}
|
2013-03-13 13:40:31 +00:00
|
|
|
per_pin = get_pin(spec, pin_idx);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2014-01-30 18:52:16 +00:00
|
|
|
if (spec->dyn_pin_out) {
|
2019-11-19 08:47:09 +00:00
|
|
|
snd_hda_set_dev_select(codec, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id);
|
2014-01-30 18:52:16 +00:00
|
|
|
pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
|
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
|
snd_hda_codec_write(codec, per_pin->pin_nid, 0,
|
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
|
pinctl & ~PIN_OUT);
|
|
|
|
}
|
|
|
|
|
2013-10-17 16:21:12 +00:00
|
|
|
mutex_lock(&per_pin->lock);
|
2012-07-31 09:36:00 +00:00
|
|
|
per_pin->chmap_set = false;
|
|
|
|
memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
|
2013-09-02 10:33:02 +00:00
|
|
|
|
|
|
|
per_pin->setup = false;
|
|
|
|
per_pin->channels = 0;
|
2013-10-17 16:21:12 +00:00
|
|
|
mutex_unlock(&per_pin->lock);
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
}
|
2012-07-31 09:36:00 +00:00
|
|
|
|
2020-10-13 15:26:28 +00:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&spec->pcm_lock);
|
|
|
|
|
2018-07-12 21:06:51 +00:00
|
|
|
return err;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct hda_pcm_ops generic_ops = {
|
|
|
|
.open = hdmi_pcm_open,
|
2012-07-26 16:08:14 +00:00
|
|
|
.close = hdmi_pcm_close,
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
.prepare = generic_hdmi_playback_pcm_prepare,
|
2012-08-06 12:49:36 +00:00
|
|
|
.cleanup = generic_hdmi_playback_pcm_cleanup,
|
2010-09-07 10:27:25 +00:00
|
|
|
};
|
|
|
|
|
2016-04-04 13:53:54 +00:00
|
|
|
static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
|
|
|
|
{
|
2020-05-05 03:03:53 +00:00
|
|
|
struct hda_codec *codec = hdac_to_hda_codec(hdac);
|
2016-04-04 13:53:54 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
|
|
|
|
|
|
|
|
if (!per_pin)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return per_pin->sink_eld.info.spk_alloc;
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:47 +00:00
|
|
|
static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
|
|
|
|
unsigned char *chmap)
|
|
|
|
{
|
2020-05-05 03:03:53 +00:00
|
|
|
struct hda_codec *codec = hdac_to_hda_codec(hdac);
|
2016-03-04 14:29:47 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
|
|
|
|
|
|
|
|
/* chmap is already set to 0 in caller */
|
|
|
|
if (!per_pin)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
|
|
|
|
unsigned char *chmap, int prepared)
|
|
|
|
{
|
2020-05-05 03:03:53 +00:00
|
|
|
struct hda_codec *codec = hdac_to_hda_codec(hdac);
|
2016-03-04 14:29:47 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
|
|
|
|
|
2016-04-18 01:16:28 +00:00
|
|
|
if (!per_pin)
|
|
|
|
return;
|
2016-03-04 14:29:47 +00:00
|
|
|
mutex_lock(&per_pin->lock);
|
|
|
|
per_pin->chmap_set = true;
|
|
|
|
memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
|
|
|
|
if (prepared)
|
|
|
|
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
|
|
|
|
mutex_unlock(&per_pin->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
|
|
|
|
{
|
2020-05-05 03:03:53 +00:00
|
|
|
struct hda_codec *codec = hdac_to_hda_codec(hdac);
|
2016-03-04 14:29:47 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
|
|
|
|
|
|
|
|
return per_pin ? true:false;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static int generic_hdmi_build_pcms(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2019-10-29 13:40:09 +00:00
|
|
|
int idx, pcm_num;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
/*
|
|
|
|
* for non-mst mode, pcm number is the same as before
|
2019-10-29 13:40:09 +00:00
|
|
|
* for DP MST mode without extra PCM, pcm number is same
|
|
|
|
* for DP MST mode with extra PCMs, pcm number is
|
|
|
|
* (nid number + dev_num - 1)
|
|
|
|
* dev_num is the device entry number in a pin
|
2017-01-12 08:04:53 +00:00
|
|
|
*/
|
2019-10-29 13:40:09 +00:00
|
|
|
|
|
|
|
if (codec->mst_no_extra_pcms)
|
|
|
|
pcm_num = spec->num_nids;
|
|
|
|
else
|
|
|
|
pcm_num = spec->num_nids + spec->dev_num - 1;
|
|
|
|
|
|
|
|
codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num);
|
|
|
|
|
|
|
|
for (idx = 0; idx < pcm_num; idx++) {
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
struct hda_pcm *info;
|
2010-09-07 10:27:25 +00:00
|
|
|
struct hda_pcm_stream *pstr;
|
2013-03-13 13:40:31 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
|
2013-03-13 13:40:31 +00:00
|
|
|
if (!info)
|
|
|
|
return -ENOMEM;
|
2016-01-12 03:13:26 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
spec->pcm_rec[idx].pcm = info;
|
2015-12-16 05:42:43 +00:00
|
|
|
spec->pcm_used++;
|
2010-09-07 10:27:25 +00:00
|
|
|
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
2012-07-31 09:36:00 +00:00
|
|
|
info->own_chmap = true;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
pstr->substreams = 1;
|
|
|
|
pstr->ops = generic_ops;
|
2017-01-12 08:04:53 +00:00
|
|
|
/* pcm number is less than 16 */
|
|
|
|
if (spec->pcm_used >= 16)
|
|
|
|
break;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
/* other pstr fields are set in open */
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-12 03:13:27 +00:00
|
|
|
static void free_hdmi_jack_priv(struct snd_jack *jack)
|
2015-11-12 14:36:13 +00:00
|
|
|
{
|
2016-01-12 03:13:27 +00:00
|
|
|
struct hdmi_pcm *pcm = jack->private_data;
|
2015-11-12 14:36:13 +00:00
|
|
|
|
2016-01-12 03:13:27 +00:00
|
|
|
pcm->jack = NULL;
|
2015-11-12 14:36:13 +00:00
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
|
2015-11-12 14:36:13 +00:00
|
|
|
{
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
char hdmi_str[32] = "HDMI/DP";
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pcm_idx);
|
2015-11-12 14:36:13 +00:00
|
|
|
struct snd_jack *jack;
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
|
2015-11-12 14:36:13 +00:00
|
|
|
int err;
|
|
|
|
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
if (pcmdev > 0)
|
|
|
|
sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
|
|
|
|
if (!spec->dyn_pcm_assign &&
|
|
|
|
!is_jack_detectable(codec, per_pin->pin_nid))
|
|
|
|
strncat(hdmi_str, " Phantom",
|
|
|
|
sizeof(hdmi_str) - strlen(hdmi_str) - 1);
|
|
|
|
|
|
|
|
err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
|
2015-11-12 14:36:13 +00:00
|
|
|
true, false);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2016-01-12 03:13:27 +00:00
|
|
|
|
|
|
|
spec->pcm_rec[pcm_idx].jack = jack;
|
|
|
|
jack->private_data = &spec->pcm_rec[pcm_idx];
|
|
|
|
jack->private_free = free_hdmi_jack_priv;
|
2015-11-12 14:36:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static int generic_hdmi_build_controls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2017-09-03 13:18:49 +00:00
|
|
|
int dev, err;
|
2016-01-12 03:13:27 +00:00
|
|
|
int pin_idx, pcm_idx;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-01-12 03:13:27 +00:00
|
|
|
for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
|
ALSA: hda - Skip jack and others for non-existing PCM streams
When CONFIG_SND_DYNAMIC_MINORS isn't set, there are only limited
number of devices available, and HD-audio, especially with HDMI/DP
codec, will fail to create more than two devices.
The driver warns about the lack of such devices and skips the PCM
device creations, but the HDMI driver still tries to create the
corresponding JACK, SPDIF and ELD controls even for the non-existing
PCM substreams. This results in confusion on user-space, and even may
break the operation.
Similarly, Intel HDMI/DP codec builds the ELD notification from i915
graphics driver, and this may be broken if a notification is sent for
the non-existing PCM stream.
This patch adds the check of the existence of the assigned PCM
substream in the both scenarios above, and skips the further operation
if the PCM substream is not assigned.
Fixes: 9152085defb6 ("ALSA: hda - add DP MST audio support")
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-04-25 14:19:13 +00:00
|
|
|
if (!get_pcm_rec(spec, pcm_idx)->pcm) {
|
|
|
|
/* no PCM: mark this for skipping permanently */
|
|
|
|
set_bit(pcm_idx, &spec->pcm_bitmap);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-01-12 03:13:27 +00:00
|
|
|
err = generic_hdmi_build_jack(codec, pcm_idx);
|
2011-08-23 14:56:03 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2016-01-29 05:53:27 +00:00
|
|
|
/* create the spdif for each pcm
|
|
|
|
* pin will be bound when monitor is connected
|
|
|
|
*/
|
|
|
|
if (spec->dyn_pcm_assign)
|
|
|
|
err = snd_hda_create_dig_out_ctls(codec,
|
|
|
|
0, spec->cvt_nids[0],
|
|
|
|
HDA_PCM_TYPE_HDMI);
|
|
|
|
else {
|
|
|
|
struct hdmi_spec_per_pin *per_pin =
|
|
|
|
get_pin(spec, pcm_idx);
|
|
|
|
err = snd_hda_create_dig_out_ctls(codec,
|
2012-10-12 15:24:51 +00:00
|
|
|
per_pin->pin_nid,
|
|
|
|
per_pin->mux_nids[0],
|
|
|
|
HDA_PCM_TYPE_HDMI);
|
2016-01-29 05:53:27 +00:00
|
|
|
}
|
2010-09-07 10:27:25 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2016-01-29 05:53:27 +00:00
|
|
|
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
|
2011-09-30 21:35:41 +00:00
|
|
|
|
2017-09-03 13:18:49 +00:00
|
|
|
dev = get_pcm_rec(spec, pcm_idx)->device;
|
|
|
|
if (dev != SNDRV_PCM_INVALID_DEVICE) {
|
|
|
|
/* add control for ELD Bytes */
|
|
|
|
err = hdmi_create_eld_ctl(codec, pcm_idx, dev);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2016-02-23 08:33:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
2020-04-28 12:38:36 +00:00
|
|
|
struct hdmi_eld *pin_eld = &per_pin->sink_eld;
|
2011-12-01 16:41:36 +00:00
|
|
|
|
2020-04-28 12:38:36 +00:00
|
|
|
pin_eld->eld_valid = false;
|
2011-12-20 14:53:07 +00:00
|
|
|
hdmi_present_sense(per_pin, 0);
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
|
|
|
|
2012-07-31 09:36:00 +00:00
|
|
|
/* add channel maps */
|
2016-02-03 02:48:34 +00:00
|
|
|
for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
|
2015-02-27 16:43:19 +00:00
|
|
|
struct hda_pcm *pcm;
|
2013-08-22 07:55:36 +00:00
|
|
|
|
2016-02-03 02:48:34 +00:00
|
|
|
pcm = get_pcm_rec(spec, pcm_idx);
|
2015-02-27 16:43:19 +00:00
|
|
|
if (!pcm || !pcm->pcm)
|
2013-08-22 07:55:36 +00:00
|
|
|
break;
|
2016-03-04 14:29:51 +00:00
|
|
|
err = snd_hdac_add_chmap_ctls(pcm->pcm, pcm_idx, &spec->chmap);
|
2012-07-31 09:36:00 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-20 14:32:22 +00:00
|
|
|
static int generic_hdmi_init_per_pins(struct hda_codec *codec)
|
2010-09-07 10:27:25 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
int pin_idx;
|
|
|
|
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2011-11-16 08:29:47 +00:00
|
|
|
per_pin->codec = codec;
|
2013-10-17 16:21:12 +00:00
|
|
|
mutex_init(&per_pin->lock);
|
2011-11-16 08:29:47 +00:00
|
|
|
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
|
2013-10-17 16:21:12 +00:00
|
|
|
eld_proc_new(per_pin, pin_idx);
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
2012-06-20 14:32:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int generic_hdmi_init(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int pin_idx;
|
|
|
|
|
2019-10-29 20:41:20 +00:00
|
|
|
mutex_lock(&spec->bind_lock);
|
2012-06-20 14:32:22 +00:00
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
2012-06-20 14:32:22 +00:00
|
|
|
hda_nid_t pin_nid = per_pin->pin_nid;
|
2017-01-12 08:04:53 +00:00
|
|
|
int dev_id = per_pin->dev_id;
|
2012-06-20 14:32:22 +00:00
|
|
|
|
2017-01-12 08:04:53 +00:00
|
|
|
snd_hda_set_dev_select(codec, pin_nid, dev_id);
|
2012-06-20 14:32:22 +00:00
|
|
|
hdmi_init_pin(codec, pin_nid);
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
if (codec_has_acomp(codec))
|
|
|
|
continue;
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id,
|
|
|
|
jack_callback);
|
2012-06-20 14:32:22 +00:00
|
|
|
}
|
2019-10-29 20:41:20 +00:00
|
|
|
mutex_unlock(&spec->bind_lock);
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
static void hdmi_array_init(struct hdmi_spec *spec, int nums)
|
|
|
|
{
|
|
|
|
snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
|
|
|
|
snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdmi_array_free(struct hdmi_spec *spec)
|
|
|
|
{
|
|
|
|
snd_array_free(&spec->pins);
|
|
|
|
snd_array_free(&spec->cvts);
|
|
|
|
}
|
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
static void generic_spec_free(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (spec) {
|
|
|
|
hdmi_array_free(spec);
|
|
|
|
kfree(spec);
|
|
|
|
codec->spec = NULL;
|
|
|
|
}
|
|
|
|
codec->dp_mst = false;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static void generic_hdmi_free(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2016-01-12 03:13:27 +00:00
|
|
|
int pin_idx, pcm_idx;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
if (spec->acomp_registered) {
|
|
|
|
snd_hdac_acomp_exit(&codec->bus->core);
|
|
|
|
} else if (codec_has_acomp(codec)) {
|
ALSA: hda: Make audio component support more generic
This is the final step for more generic support of DRM audio
component. The generic audio component code is now moved to its own
file, and the symbols are renamed from snd_hac_i915_* to
snd_hdac_acomp_*, respectively. The generic code is enabled via the
new kconfig, CONFIG_SND_HDA_COMPONENT, while CONFIG_SND_HDA_I915 is
kept as the super-class.
Along with the split, three new callbacks are added to audio_ops:
pin2port is for providing the conversion between the pin number and
the widget id, and master_bind/master_unbin are called at binding /
unbinding the master component, respectively. All these are optional,
but used in i915 implementation and also other later implementations.
A note about the new snd_hdac_acomp_init() function: there is a slight
difference between this and the old snd_hdac_i915_init(). The latter
(still) synchronizes with the master component binding, i.e. it
assures that the relevant DRM component gets bound when it returns, or
gives a negative error. Meanwhile the new function doesn't
synchronize but just leaves as is. It's the responsibility by the
caller's side to synchronize, or the caller may accept the
asynchronous binding on the fly.
v1->v2: Fix missing NULL check in master_bind/unbind
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 14:23:16 +00:00
|
|
|
snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
|
2019-07-16 06:56:51 +00:00
|
|
|
}
|
2019-11-22 13:26:24 +00:00
|
|
|
codec->relaxed_resume = 0;
|
2015-08-19 08:48:58 +00:00
|
|
|
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
2015-02-27 21:43:26 +00:00
|
|
|
cancel_delayed_work_sync(&per_pin->work);
|
2013-10-17 16:21:12 +00:00
|
|
|
eld_proc_free(per_pin);
|
2016-01-12 03:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
|
|
|
|
if (spec->pcm_rec[pcm_idx].jack == NULL)
|
|
|
|
continue;
|
|
|
|
if (spec->dyn_pcm_assign)
|
|
|
|
snd_device_free(codec->card,
|
|
|
|
spec->pcm_rec[pcm_idx].jack);
|
|
|
|
else
|
|
|
|
spec->pcm_rec[pcm_idx].jack = NULL;
|
ALSA: hda: HDMI: Support codecs with fewer cvts than pins
The general concept of this change is to create a PCM device for each
pin widget instead of each converter widget. Whenever a PCM is opened,
a converter is dynamically selected to drive that pin based on those
available for muxing into the pin.
The one thing this model doesn't support is a single PCM/converter
sending audio to multiple pin widgets at once.
Note that this means that a struct hda_pcm_stream's nid variable is
set to 0 except between a stream's open and cleanup calls. The dynamic
de-assignment of converters to PCMs occurs within cleanup, not close,
in order for it to co-incide with when controller stream IDs are
cleaned up from converters.
While the PCM for a pin is not open, the pin is disabled (its widget
control's PIN_OUT bit is cleared) so that if the currently routed
converter is used to drive a different PCM/pin, that audio does not
leak out over a disabled pin.
We use the recently added SPDIF virtualization feature in order to
create SPDIF controls for each pin widget instead of each converter
widget, so that state is specific to a PCM.
In order to support this, a number of more mechanical changes are made:
* s/nid/pin_nid/ or s/nid/cvt_nid/ in many places in order to make it
clear exactly what the code is dealing with.
* We now have per_pin and per_cvt arrays in hdmi_spec to store relevant
data. In particular, we store a converter's capabilities in the per_cvt
entry, rather than relying on a combination of codec_pcm_pars and
the struct hda_pcm_stream.
* ELD-related workarounds were removed from hdmi_channel_allocation
into hdmi_instrinsic in order to simplifiy infoframe calculations and
remove HW dependencies.
* Various functions only apply to a single pin, since there is now
only 1 pin per PCM. For example, hdmi_setup_infoframe,
hdmi_setup_stream.
* hdmi_add_pin and hdmi_add_cvt are more oriented at pure codec parsing
and data retrieval, rather than determining which pins/converters
are to be used for creating PCMs.
This is quite a large change; it may be appropriate to simply read the
result of the patch rather than the diffs. Some small parts of the change
might be separable into different patches, but I think the bulk of the
change will probably always be one large patch. Hopefully the change
isn't too opaque!
This has been tested on:
* NVIDIA GeForce 400 series discrete graphics card. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM
audio to a PC monitor that supports audio.
* NVIDIA GeForce 520 discrete graphics card. This model is the new
1 codec n converters m pins m>n model. Tested stereo PCM audio to a
PC monitor that supports audio.
* NVIDIA GeForce 400 series laptop graphics chip. This model has the
classical 1:1:1 codec:converter:pcm widget model. Tested stereo PCM,
multi-channel PCM, and AC3 pass-through to an AV receiver.
* Intel Ibex Peak laptop. This model is the new 1 codec n converters m
pins m>n model. Tested stereo PCM, multi-channel PCM, and AC3 pass-
through to an AV receiver.
Note that I'm not familiar at all with AC3 pass-through. Hence, I may
not have covered all possible mechanisms that are applicable here. I do
know that my receiver definitely received AC3, not decoded PCM. I tested
with mplayer's "-afm hwac3" and/or "-af lavcac3enc" options, and alsa a
WAV file that I believe has AC3 content rather than PCM.
I also tested:
* Play a stream
* Mute while playing
* Stop stream
* Play some other streams to re-assign the converter to a different
pin, PCM, set of SPDIF controls, ... hence hopefully triggering
cleanup for the original PCM.
* Unmute original stream while not playing
* Play a stream on the original pin/PCM.
This was to test SPDIF control virtualization.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:21 +00:00
|
|
|
}
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
generic_spec_free(codec);
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
|
|
|
|
2013-06-24 11:45:23 +00:00
|
|
|
#ifdef CONFIG_PM
|
2021-03-10 11:28:09 +00:00
|
|
|
static int generic_hdmi_suspend(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int pin_idx;
|
|
|
|
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
|
|
|
cancel_delayed_work_sync(&per_pin->work);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-24 11:45:23 +00:00
|
|
|
static int generic_hdmi_resume(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int pin_idx;
|
|
|
|
|
2014-06-18 19:48:09 +00:00
|
|
|
codec->patch_ops.init(codec);
|
ALSA: hda: Manage concurrent reg access more properly
In the commit 8e85def5723e ("ALSA: hda: enable regmap internal
locking"), we re-enabled the regmap lock due to the reported
regression that showed the possible concurrent accesses. It was a
temporary workaround, and there are still a few opened races even
after the revert. In this patch, we cover those still opened windows
with a proper mutex lock and disable the regmap internal lock again.
First off, the patch introduces a new snd_hdac_device.regmap_lock
mutex that is applied for each snd_hdac_regmap_*() call, including
read, write and update helpers. The mutex is applied carefully so
that it won't block the self-power-up procedure in the helper
function. Also, this assures the protection for the accesses without
regmap, too.
The snd_hdac_regmap_update_raw() is refactored to use the standard
regmap_update_bits_check() function instead of the open-code. The
non-regmap case is still open-coded but it's an easy part. The all
read and write operations are in the single mutex protection, so it's
now race-free.
In addition, a couple of new helper functions are added:
snd_hdac_regmap_update_raw_once() and snd_hdac_regmap_sync(). Both
are called from HD-audio legacy driver. The former is to initialize
the given verb bits but only once when it's not initialized yet. Due
to this condition, the function invokes regcache_cache_only(), and
it's now performed inside the regmap_lock (formerly it was racy) too.
The latter function is for simply invoking regcache_sync() inside the
regmap_lock, which is called from the codec resume call path.
Along with that, the HD-audio codec driver code is slightly modified /
simplified to adapt those new functions.
And finally, snd_hdac_regmap_read_raw(), *_write_raw(), etc are
rewritten with the helper macro. It's just for simplification because
the code logic is identical among all those functions.
Tested-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200109090104.26073-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-01-09 09:01:04 +00:00
|
|
|
snd_hda_regmap_sync(codec);
|
2013-06-24 11:45:23 +00:00
|
|
|
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
|
|
|
hdmi_present_sense(per_pin, 1);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-05-02 10:17:41 +00:00
|
|
|
static const struct hda_codec_ops generic_hdmi_patch_ops = {
|
2010-09-07 10:27:25 +00:00
|
|
|
.init = generic_hdmi_init,
|
|
|
|
.free = generic_hdmi_free,
|
|
|
|
.build_pcms = generic_hdmi_build_pcms,
|
|
|
|
.build_controls = generic_hdmi_build_controls,
|
|
|
|
.unsol_event = hdmi_unsol_event,
|
2013-06-24 11:45:23 +00:00
|
|
|
#ifdef CONFIG_PM
|
2021-03-10 11:28:09 +00:00
|
|
|
.suspend = generic_hdmi_suspend,
|
2013-06-24 11:45:23 +00:00
|
|
|
.resume = generic_hdmi_resume,
|
|
|
|
#endif
|
2010-09-07 10:27:25 +00:00
|
|
|
};
|
|
|
|
|
2013-10-24 18:10:34 +00:00
|
|
|
static const struct hdmi_ops generic_standard_hdmi_ops = {
|
2019-11-19 08:47:09 +00:00
|
|
|
.pin_get_eld = hdmi_pin_get_eld,
|
2013-10-24 18:10:34 +00:00
|
|
|
.pin_setup_infoframe = hdmi_pin_setup_infoframe,
|
|
|
|
.pin_hbr_setup = hdmi_pin_hbr_setup,
|
|
|
|
.setup_stream = hdmi_setup_stream,
|
2016-03-04 14:29:46 +00:00
|
|
|
};
|
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
/* allocate codec->spec and assign/initialize generic parser ops */
|
|
|
|
static int alloc_generic_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (!spec)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
spec->codec = codec;
|
2016-03-21 11:18:33 +00:00
|
|
|
spec->ops = generic_standard_hdmi_ops;
|
2017-01-12 08:04:53 +00:00
|
|
|
spec->dev_num = 1; /* initialize to 1 */
|
2016-03-21 11:18:33 +00:00
|
|
|
mutex_init(&spec->pcm_lock);
|
2019-10-29 20:41:20 +00:00
|
|
|
mutex_init(&spec->bind_lock);
|
2016-03-21 11:18:33 +00:00
|
|
|
snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
|
|
|
|
|
|
|
|
spec->chmap.ops.get_chmap = hdmi_get_chmap;
|
|
|
|
spec->chmap.ops.set_chmap = hdmi_set_chmap;
|
|
|
|
spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
|
2020-10-11 09:19:33 +00:00
|
|
|
spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc;
|
2016-03-21 11:18:33 +00:00
|
|
|
|
|
|
|
codec->spec = spec;
|
|
|
|
hdmi_array_init(spec, 4);
|
|
|
|
|
|
|
|
codec->patch_ops = generic_hdmi_patch_ops;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generic HDMI parser */
|
|
|
|
static int patch_generic_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = alloc_generic_hdmi(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = hdmi_parse_codec(codec);
|
|
|
|
if (err < 0) {
|
|
|
|
generic_spec_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
generic_hdmi_init_per_pins(codec);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
/*
|
|
|
|
* generic audio component binding
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* turn on / off the unsol event jack detection dynamically */
|
|
|
|
static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid,
|
2019-11-19 08:47:08 +00:00
|
|
|
int dev_id, bool use_acomp)
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
{
|
|
|
|
struct hda_jack_tbl *tbl;
|
|
|
|
|
2019-11-19 08:47:08 +00:00
|
|
|
tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
if (tbl) {
|
|
|
|
/* clear unsol even if component notifier is used, or re-enable
|
|
|
|
* if notifier is cleared
|
|
|
|
*/
|
|
|
|
unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag);
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_UNSOLICITED_ENABLE, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set up / clear component notifier dynamically */
|
|
|
|
static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
|
|
|
|
bool use_acomp)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops);
|
2019-10-29 20:41:20 +00:00
|
|
|
mutex_lock(&spec->bind_lock);
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
spec->use_acomp_notifier = use_acomp;
|
|
|
|
spec->codec->relaxed_resume = use_acomp;
|
ALSA: hda/hdmi: Fix keep_power assignment for non-component devices
It's been reported that, when neither nouveau nor Nvidia graphics
driver is used, the screen starts flickering. And, after comparing
between the working case (stable 4.4.x) and the broken case, it turned
out that the problem comes from the audio component binding. The
Nvidia and AMD audio binding code clears the bus->keep_power flag
whenever snd_hdac_acomp_init() succeeds. But this doesn't mean that
the component is actually bound, but it merely indicates that it's
ready for binding. So, when both nouveau and Nvidia are blacklisted
or not ready, the driver keeps running without the audio component but
also with bus->keep_power = false. This made the driver runtime PM
kicked in and powering down when unused, which results in flickering
in the graphics side, as it seems.
For fixing the bug, this patch moves the bus->keep_power flag change
into generic_acomp_notifier_set() that is the function called from the
master_bind callback of component ops; i.e. it's guaranteed that the
binding succeeded.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=208609
Fixes: 5a858e79c911 ("ALSA: hda - Disable audio component for legacy Nvidia HDMI codecs")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20200728082033.23933-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-07-28 08:20:33 +00:00
|
|
|
spec->codec->bus->keep_power = 0;
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
/* reprogram each jack detection logic depending on the notifier */
|
ALSA: hda/hdmi: Don't use standard hda_jack for generic HDMI jacks
The current HDMI codec driver code manages the jack detection in two
different ways: for Intel codecs with audio component, the driver
creates snd_jack objects by itself while the standard hda_jack stuff
is used for the rest. This was basically because the audio component
doesn't need the pin sense reading and the unsol event handling, hence
it just needs to report the corresponding jacks directly.
It was a bit messy but not too messy until the driver got DP-MST
support for Nvidia that re-uses the part of dyn_pcm_assign feature
while keeping the pin sense and the unsol event handling. Now, for
DP-MST, we use hda_jack for pin sensing and unsol events but use the
own snd_jack objects. Meanwhile for non-DP-MST, hda_jack is used for
pin sense and unsol events, and the jacks are bound on hda_jack.
Moreover, there is a polling mode support where the unsol event isn't
used. For those, we also have special handling.
For simplifying those messes, this patch unifies the snd_jack handling
over all generic HDMI codes. The driver creates snd_jack objects just
like Intel codecs did in the past but now for all devices. For the
system without audio component binding, we still need the pin sense
and the unsol event handling, and those are still done with the
hda_jack table as before. But hda_jack is no longer used for the
actual snd_jack handling.
Since the hda_jack is no longer used for jack reporting, we removed
snd_hda_jack_report_sync() calls, which also allowed to simplify the
return type of hda_present_sense() and co. pin_idx_to_pcm_jack() was
simplified as well because it behaves same for all cases now.
Note that the hda_jack is still used for the simple HDMI codecs; they
are really simple enough, so no big reason to change intrusively.
Reviewed-by: Nikhil Mahale <nmahale@nvidia.com>
Link: https://lore.kernel.org/r/20200206162804.4734-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-02-06 16:28:02 +00:00
|
|
|
for (i = 0; i < spec->num_pins; i++)
|
|
|
|
reprogram_jack_detect(spec->codec,
|
|
|
|
get_pin(spec, i)->pin_nid,
|
|
|
|
get_pin(spec, i)->dev_id,
|
|
|
|
use_acomp);
|
2019-10-29 20:41:20 +00:00
|
|
|
mutex_unlock(&spec->bind_lock);
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* enable / disable the notifier via master bind / unbind */
|
|
|
|
static int generic_acomp_master_bind(struct device *dev,
|
|
|
|
struct drm_audio_component *acomp)
|
|
|
|
{
|
|
|
|
generic_acomp_notifier_set(acomp, true);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void generic_acomp_master_unbind(struct device *dev,
|
|
|
|
struct drm_audio_component *acomp)
|
|
|
|
{
|
|
|
|
generic_acomp_notifier_set(acomp, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check whether both HD-audio and DRM PCI devices belong to the same bus */
|
|
|
|
static int match_bound_vga(struct device *dev, int subtype, void *data)
|
|
|
|
{
|
|
|
|
struct hdac_bus *bus = data;
|
|
|
|
struct pci_dev *pci, *master;
|
|
|
|
|
|
|
|
if (!dev_is_pci(dev) || !dev_is_pci(bus->dev))
|
|
|
|
return 0;
|
|
|
|
master = to_pci_dev(bus->dev);
|
|
|
|
pci = to_pci_dev(dev);
|
|
|
|
return master->bus == pci->bus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* audio component notifier for AMD/Nvidia HDMI codecs */
|
|
|
|
static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = audio_ptr;
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
hda_nid_t pin_nid = spec->port2pin(codec, port);
|
|
|
|
|
|
|
|
if (!pin_nid)
|
|
|
|
return;
|
|
|
|
if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN)
|
|
|
|
return;
|
|
|
|
/* skip notification during system suspend (but not in runtime PM);
|
|
|
|
* the state will be updated at resume
|
|
|
|
*/
|
|
|
|
if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
|
|
|
|
return;
|
|
|
|
/* ditto during suspend/resume process itself */
|
|
|
|
if (snd_hdac_is_in_pm(&codec->core))
|
|
|
|
return;
|
|
|
|
|
|
|
|
check_presence_and_report(codec, pin_nid, dev_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set up the private drm_audio_ops from the template */
|
|
|
|
static void setup_drm_audio_ops(struct hda_codec *codec,
|
|
|
|
const struct drm_audio_component_audio_ops *ops)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
spec->drm_audio_ops.audio_ptr = codec;
|
|
|
|
/* intel_audio_codec_enable() or intel_audio_codec_disable()
|
|
|
|
* will call pin_eld_notify with using audio_ptr pointer
|
|
|
|
* We need make sure audio_ptr is really setup
|
|
|
|
*/
|
|
|
|
wmb();
|
|
|
|
spec->drm_audio_ops.pin2port = ops->pin2port;
|
|
|
|
spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify;
|
|
|
|
spec->drm_audio_ops.master_bind = ops->master_bind;
|
|
|
|
spec->drm_audio_ops.master_unbind = ops->master_unbind;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize the generic HDMI audio component */
|
|
|
|
static void generic_acomp_init(struct hda_codec *codec,
|
|
|
|
const struct drm_audio_component_audio_ops *ops,
|
|
|
|
int (*port2pin)(struct hda_codec *, int))
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
2020-04-15 16:25:23 +00:00
|
|
|
if (!enable_acomp) {
|
|
|
|
codec_info(codec, "audio component disabled by module option\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
spec->port2pin = port2pin;
|
|
|
|
setup_drm_audio_ops(codec, ops);
|
|
|
|
if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
|
2019-08-27 14:37:50 +00:00
|
|
|
match_bound_vga, 0)) {
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
spec->acomp_registered = true;
|
2019-08-27 14:37:50 +00:00
|
|
|
}
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
/*
|
|
|
|
* Intel codec parsers and helpers
|
|
|
|
*/
|
|
|
|
|
2019-03-13 16:09:23 +00:00
|
|
|
#define INTEL_GET_VENDOR_VERB 0xf81
|
|
|
|
#define INTEL_SET_VENDOR_VERB 0x781
|
|
|
|
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
|
|
|
|
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
|
2013-02-08 22:09:52 +00:00
|
|
|
|
|
|
|
static void intel_haswell_enable_all_pins(struct hda_codec *codec,
|
2013-05-08 06:09:34 +00:00
|
|
|
bool update_tree)
|
2013-02-08 22:09:52 +00:00
|
|
|
{
|
|
|
|
unsigned int vendor_param;
|
2017-04-13 07:35:35 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-02-08 22:09:52 +00:00
|
|
|
|
2017-04-13 07:35:35 +00:00
|
|
|
vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
|
2013-02-08 22:09:52 +00:00
|
|
|
INTEL_GET_VENDOR_VERB, 0);
|
|
|
|
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
|
2017-04-13 07:35:35 +00:00
|
|
|
vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
|
2013-02-08 22:09:52 +00:00
|
|
|
INTEL_SET_VENDOR_VERB, vendor_param);
|
|
|
|
if (vendor_param == -1)
|
|
|
|
return;
|
|
|
|
|
2013-05-08 06:09:34 +00:00
|
|
|
if (update_tree)
|
|
|
|
snd_hda_codec_update_widgets(codec);
|
2013-02-08 22:09:52 +00:00
|
|
|
}
|
|
|
|
|
2013-02-08 22:10:04 +00:00
|
|
|
static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
unsigned int vendor_param;
|
2017-04-13 07:35:35 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-02-08 22:10:04 +00:00
|
|
|
|
2017-04-13 07:35:35 +00:00
|
|
|
vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
|
2013-02-08 22:10:04 +00:00
|
|
|
INTEL_GET_VENDOR_VERB, 0);
|
|
|
|
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* enable DP1.2 mode */
|
|
|
|
vendor_param |= INTEL_EN_DP12;
|
ALSA: hda - Use regmap for command verb caches, too
Like the previous patches, this patch converts also to the regmap, at
this time, the cached verb writes are the target. But this conversion
needs a bit more caution than before.
- In the old code, we just record any verbs as is, and restore them at
resume. For the regmap scheme, this doesn't work, since a few verbs
like AMP or DIGI_CONVERT are asymmetrical. Such verbs are converted
either to the dedicated function (snd_hda_regmap_xxx_amp()) or
changed to the unified verb.
- Some verbs have to be declared as vendor-specific ones before
accessing via regmap.
Also, the minor optimization with codec->cached_write flag is dropped
in a few places, as this would confuse the operation. Further
optimizations will be brought in the later patches, if any.
This conversion ends up with a drop of significant amount of codes,
mostly the helper codes that are no longer used.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-02-26 11:34:49 +00:00
|
|
|
snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
|
2017-04-13 07:35:35 +00:00
|
|
|
snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
|
2013-02-08 22:10:04 +00:00
|
|
|
INTEL_SET_VENDOR_VERB, vendor_param);
|
|
|
|
}
|
|
|
|
|
2013-05-08 06:09:34 +00:00
|
|
|
/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
|
|
|
|
* Otherwise you may get severe h/w communication errors.
|
|
|
|
*/
|
|
|
|
static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|
|
|
unsigned int power_state)
|
|
|
|
{
|
|
|
|
if (power_state == AC_PWRST_D0) {
|
|
|
|
intel_haswell_enable_all_pins(codec, false);
|
|
|
|
intel_haswell_fixup_enable_dp12(codec);
|
|
|
|
}
|
2013-02-08 22:10:04 +00:00
|
|
|
|
2013-05-08 06:09:34 +00:00
|
|
|
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
|
|
|
|
snd_hda_codec_set_power_to_all(codec, fg, power_state);
|
|
|
|
}
|
2012-12-18 21:59:15 +00:00
|
|
|
|
ALSA: hda: Make audio component support more generic
This is the final step for more generic support of DRM audio
component. The generic audio component code is now moved to its own
file, and the symbols are renamed from snd_hac_i915_* to
snd_hdac_acomp_*, respectively. The generic code is enabled via the
new kconfig, CONFIG_SND_HDA_COMPONENT, while CONFIG_SND_HDA_I915 is
kept as the super-class.
Along with the split, three new callbacks are added to audio_ops:
pin2port is for providing the conversion between the pin number and
the widget id, and master_bind/master_unbin are called at binding /
unbinding the master component, respectively. All these are optional,
but used in i915 implementation and also other later implementations.
A note about the new snd_hdac_acomp_init() function: there is a slight
difference between this and the old snd_hdac_i915_init(). The latter
(still) synchronizes with the master component binding, i.e. it
assures that the relevant DRM component gets bound when it returns, or
gives a negative error. Meanwhile the new function doesn't
synchronize but just leaves as is. It's the responsibility by the
caller's side to synchronize, or the caller may accept the
asynchronous binding on the fly.
v1->v2: Fix missing NULL check in master_bind/unbind
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 14:23:16 +00:00
|
|
|
/* There is a fixed mapping between audio pin node and display port.
|
|
|
|
* on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
|
|
|
|
* Pin Widget 5 - PORT B (port = 1 in i915 driver)
|
|
|
|
* Pin Widget 6 - PORT C (port = 2 in i915 driver)
|
|
|
|
* Pin Widget 7 - PORT D (port = 3 in i915 driver)
|
|
|
|
*
|
|
|
|
* on VLV, ILK:
|
|
|
|
* Pin Widget 4 - PORT B (port = 1 in i915 driver)
|
|
|
|
* Pin Widget 5 - PORT C (port = 2 in i915 driver)
|
|
|
|
* Pin Widget 6 - PORT D (port = 3 in i915 driver)
|
|
|
|
*/
|
|
|
|
static int intel_base_nid(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
switch (codec->core.vendor_id) {
|
|
|
|
case 0x80860054: /* ILK */
|
|
|
|
case 0x80862804: /* ILK */
|
|
|
|
case 0x80862882: /* VLV */
|
|
|
|
return 4;
|
|
|
|
default:
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pin2port(void *audio_ptr, int pin_nid)
|
|
|
|
{
|
2019-03-13 16:09:23 +00:00
|
|
|
struct hda_codec *codec = audio_ptr;
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int base_nid, i;
|
ALSA: hda: Make audio component support more generic
This is the final step for more generic support of DRM audio
component. The generic audio component code is now moved to its own
file, and the symbols are renamed from snd_hac_i915_* to
snd_hdac_acomp_*, respectively. The generic code is enabled via the
new kconfig, CONFIG_SND_HDA_COMPONENT, while CONFIG_SND_HDA_I915 is
kept as the super-class.
Along with the split, three new callbacks are added to audio_ops:
pin2port is for providing the conversion between the pin number and
the widget id, and master_bind/master_unbin are called at binding /
unbinding the master component, respectively. All these are optional,
but used in i915 implementation and also other later implementations.
A note about the new snd_hdac_acomp_init() function: there is a slight
difference between this and the old snd_hdac_i915_init(). The latter
(still) synchronizes with the master component binding, i.e. it
assures that the relevant DRM component gets bound when it returns, or
gives a negative error. Meanwhile the new function doesn't
synchronize but just leaves as is. It's the responsibility by the
caller's side to synchronize, or the caller may accept the
asynchronous binding on the fly.
v1->v2: Fix missing NULL check in master_bind/unbind
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 14:23:16 +00:00
|
|
|
|
2019-03-13 16:09:23 +00:00
|
|
|
if (!spec->port_num) {
|
|
|
|
base_nid = intel_base_nid(codec);
|
|
|
|
if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
|
|
|
|
return -1;
|
2019-11-15 12:44:48 +00:00
|
|
|
return pin_nid - base_nid + 1;
|
2019-03-13 16:09:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* looking for the pin number in the mapping table and return
|
|
|
|
* the index which indicate the port number
|
|
|
|
*/
|
|
|
|
for (i = 0; i < spec->port_num; i++) {
|
|
|
|
if (pin_nid == spec->port_map[i])
|
2019-11-15 12:44:47 +00:00
|
|
|
return i;
|
2019-03-13 16:09:23 +00:00
|
|
|
}
|
|
|
|
|
2020-12-11 12:45:47 +00:00
|
|
|
codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
|
2019-03-13 16:09:23 +00:00
|
|
|
return -1;
|
ALSA: hda: Make audio component support more generic
This is the final step for more generic support of DRM audio
component. The generic audio component code is now moved to its own
file, and the symbols are renamed from snd_hac_i915_* to
snd_hdac_acomp_*, respectively. The generic code is enabled via the
new kconfig, CONFIG_SND_HDA_COMPONENT, while CONFIG_SND_HDA_I915 is
kept as the super-class.
Along with the split, three new callbacks are added to audio_ops:
pin2port is for providing the conversion between the pin number and
the widget id, and master_bind/master_unbin are called at binding /
unbinding the master component, respectively. All these are optional,
but used in i915 implementation and also other later implementations.
A note about the new snd_hdac_acomp_init() function: there is a slight
difference between this and the old snd_hdac_i915_init(). The latter
(still) synchronizes with the master component binding, i.e. it
assures that the relevant DRM component gets bound when it returns, or
gives a negative error. Meanwhile the new function doesn't
synchronize but just leaves as is. It's the responsibility by the
caller's side to synchronize, or the caller may accept the
asynchronous binding on the fly.
v1->v2: Fix missing NULL check in master_bind/unbind
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 14:23:16 +00:00
|
|
|
}
|
|
|
|
|
2019-07-15 21:14:53 +00:00
|
|
|
static int intel_port2pin(struct hda_codec *codec, int port)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (!spec->port_num) {
|
|
|
|
/* we assume only from port-B to port-D */
|
|
|
|
if (port < 1 || port > 3)
|
|
|
|
return 0;
|
|
|
|
return port + intel_base_nid(codec) - 1;
|
|
|
|
}
|
|
|
|
|
2019-11-15 12:44:47 +00:00
|
|
|
if (port < 0 || port >= spec->port_num)
|
2019-07-15 21:14:53 +00:00
|
|
|
return 0;
|
2019-11-15 12:44:47 +00:00
|
|
|
return spec->port_map[port];
|
2019-07-15 21:14:53 +00:00
|
|
|
}
|
|
|
|
|
drm/i915/dp: DP audio API changes for MST
DP MST provides the capability to send multiple video and audio streams
through a single port. This requires the API's between i915 and audio
drivers to distinguish between multiple audio capable displays that can be
connected to a port. Currently only the port identity is shared in the
APIs. This patch adds support for MST with an additional parameter
'int pipe'. The existing parameter 'port' does not change it's meaning.
pipe =
MST : display pipe that the stream originates from
Non-MST : -1
Affected APIs:
struct i915_audio_component_ops
- int (*sync_audio_rate)(struct device *, int port, int rate);
+ int (*sync_audio_rate)(struct device *, int port, int pipe,
+ int rate);
- int (*get_eld)(struct device *, int port, bool *enabled,
- unsigned char *buf, int max_bytes);
+ int (*get_eld)(struct device *, int port, int pipe,
+ bool *enabled, unsigned char *buf, int max_bytes);
struct i915_audio_component_audio_ops
- void (*pin_eld_notify)(void *audio_ptr, int port);
+ void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
This patch makes dummy changes in the audio drivers (thanks Libin) for
build to succeed. The audio side drivers will send the right 'pipe' values
for MST in patches that will follow.
v2:
Renamed the new API parameter from 'dev_id' to 'pipe'. (Jim, Ville)
Included Asoc driver API compatibility changes from Jeeja.
Added WARN_ON() for invalid pipe in get_saved_encoder(). (Takashi)
Added comment for av_enc_map[] definition. (Takashi)
v3:
Fixed logic error introduced while renaming 'dev_id' as 'pipe' (Ville)
Renamed get_saved_encoder() to get_saved_enc() to reduce line length
v4:
Rebased.
Parameter check for pipe < -1 values in get_saved_enc() (Ville)
Switched to for_each_pipe() in get_saved_enc() (Ville)
Renamed 'pipe' to 'dev_id' in audio side code (Takashi)
v5:
Included a comment for the dev_id arg. (Libin)
Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1474488168-2343-1-git-send-email-dhinakaran.pandiyan@intel.com
2016-09-21 20:02:48 +00:00
|
|
|
static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
|
2015-08-19 08:48:58 +00:00
|
|
|
{
|
|
|
|
struct hda_codec *codec = audio_ptr;
|
2016-03-21 13:50:24 +00:00
|
|
|
int pin_nid;
|
2017-01-12 08:04:53 +00:00
|
|
|
int dev_id = pipe;
|
2015-08-19 08:48:58 +00:00
|
|
|
|
2019-07-15 21:14:53 +00:00
|
|
|
pin_nid = intel_port2pin(codec, port);
|
|
|
|
if (!pin_nid)
|
2016-03-10 11:02:49 +00:00
|
|
|
return;
|
ALSA: hda - Skip ELD notification during system suspend
The recent addition of ELD notifier for Intel HDMI/DP codec may lead
the bad codec connection found as kernel messages like below:
Suspending console(s) (use no_console_suspend to debug)
hdmi_present_sense: snd_hda_codec_hdmi hdaudioC0D2: HDMI status: Codec=2 Pin=6 Presence_Detect=1 ELD_Valid=1
snd_hda_intel 0000:00:1f.3: spurious response 0x0:0x2, last cmd=0x206f2e08
snd_hda_intel 0000:00:1f.3: spurious response 0x0:0x2, last cmd=0x206f2e08
....
snd_hda_codec_hdmi hdaudioC0D2: HDMI: ELD buf size is 0, force 128
snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to polling mode: last cmd=0x206f2f00
snd_hda_intel 0000:00:1f.3: No response from codec, disabling MSI: last cmd=0x206f2f00
snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to single_cmd mode: last cmd=0x206f2f00
azx_single_wait_for_response: 42 callbacks suppressed
This seems appearing when the sound driver went to suspend before i915
driver. Then i915 driver disables HDMI/DP audio bit and calls the
registered notifier, and the HDA codec tries to handle it as a
hot(un)plug. But since the driver is already in the suspended state,
it fails miserably.
As this is a sort of spurious wakeup, it can be ignored safely, as
long as it's delivered during the system suspend. OTOH, if a
notification comes during the runtime suspend, the situation is
different: we need to wake up. But during the system suspend, such a
notification can't be the reason for a wakeup.
This patch addresses it by a simple check of the current sound card
status. The skipped notification doesn't matter because the HDA
driver will check the plugged status forcibly at the resume in
return.
Then, why the card status, not a runtime PM status or else? The HDA
controller driver is supposed to set the card status to D3 at the
system suspend but not at the runtime suspend. So we can see it as a
flag that is set only for the system suspend. Admittedly, it's a bit
ugly, but it should work well for now.
Reported-and-tested-by: "Zhang, Xiong Y" <xiong.y.zhang@intel.com>
Fixes: 25adc137c546 ('ALSA: hda - Wake the codec up on pin/ELD notify events')
Cc: <stable@vger.kernel.org> # v4.3+
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-11-27 13:23:00 +00:00
|
|
|
/* skip notification during system suspend (but not in runtime PM);
|
|
|
|
* the state will be updated at resume
|
|
|
|
*/
|
|
|
|
if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
|
|
|
|
return;
|
2015-11-27 13:53:35 +00:00
|
|
|
/* ditto during suspend/resume process itself */
|
2018-06-27 07:03:51 +00:00
|
|
|
if (snd_hdac_is_in_pm(&codec->core))
|
2015-11-27 13:53:35 +00:00
|
|
|
return;
|
ALSA: hda - Skip ELD notification during system suspend
The recent addition of ELD notifier for Intel HDMI/DP codec may lead
the bad codec connection found as kernel messages like below:
Suspending console(s) (use no_console_suspend to debug)
hdmi_present_sense: snd_hda_codec_hdmi hdaudioC0D2: HDMI status: Codec=2 Pin=6 Presence_Detect=1 ELD_Valid=1
snd_hda_intel 0000:00:1f.3: spurious response 0x0:0x2, last cmd=0x206f2e08
snd_hda_intel 0000:00:1f.3: spurious response 0x0:0x2, last cmd=0x206f2e08
....
snd_hda_codec_hdmi hdaudioC0D2: HDMI: ELD buf size is 0, force 128
snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to polling mode: last cmd=0x206f2f00
snd_hda_intel 0000:00:1f.3: No response from codec, disabling MSI: last cmd=0x206f2f00
snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to single_cmd mode: last cmd=0x206f2f00
azx_single_wait_for_response: 42 callbacks suppressed
This seems appearing when the sound driver went to suspend before i915
driver. Then i915 driver disables HDMI/DP audio bit and calls the
registered notifier, and the HDA codec tries to handle it as a
hot(un)plug. But since the driver is already in the suspended state,
it fails miserably.
As this is a sort of spurious wakeup, it can be ignored safely, as
long as it's delivered during the system suspend. OTOH, if a
notification comes during the runtime suspend, the situation is
different: we need to wake up. But during the system suspend, such a
notification can't be the reason for a wakeup.
This patch addresses it by a simple check of the current sound card
status. The skipped notification doesn't matter because the HDA
driver will check the plugged status forcibly at the resume in
return.
Then, why the card status, not a runtime PM status or else? The HDA
controller driver is supposed to set the card status to D3 at the
system suspend but not at the runtime suspend. So we can see it as a
flag that is set only for the system suspend. Admittedly, it's a bit
ugly, but it should work well for now.
Reported-and-tested-by: "Zhang, Xiong Y" <xiong.y.zhang@intel.com>
Fixes: 25adc137c546 ('ALSA: hda - Wake the codec up on pin/ELD notify events')
Cc: <stable@vger.kernel.org> # v4.3+
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-11-27 13:23:00 +00:00
|
|
|
|
2016-04-21 14:39:17 +00:00
|
|
|
snd_hdac_i915_set_bclk(&codec->bus->core);
|
2017-01-12 08:04:53 +00:00
|
|
|
check_presence_and_report(codec, pin_nid, dev_id);
|
2015-08-19 08:48:58 +00:00
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
static const struct drm_audio_component_audio_ops intel_audio_ops = {
|
|
|
|
.pin2port = intel_pin2port,
|
|
|
|
.pin_eld_notify = intel_pin_eld_notify,
|
|
|
|
};
|
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
/* register i915 component pin_eld_notify callback */
|
|
|
|
static void register_i915_notifier(struct hda_codec *codec)
|
2010-09-07 10:27:25 +00:00
|
|
|
{
|
2016-03-21 11:18:33 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
spec->use_acomp_notifier = true;
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
spec->port2pin = intel_port2pin;
|
|
|
|
setup_drm_audio_ops(codec, &intel_audio_ops);
|
ALSA: hda: Make audio component support more generic
This is the final step for more generic support of DRM audio
component. The generic audio component code is now moved to its own
file, and the symbols are renamed from snd_hac_i915_* to
snd_hdac_acomp_*, respectively. The generic code is enabled via the
new kconfig, CONFIG_SND_HDA_COMPONENT, while CONFIG_SND_HDA_I915 is
kept as the super-class.
Along with the split, three new callbacks are added to audio_ops:
pin2port is for providing the conversion between the pin number and
the widget id, and master_bind/master_unbin are called at binding /
unbinding the master component, respectively. All these are optional,
but used in i915 implementation and also other later implementations.
A note about the new snd_hdac_acomp_init() function: there is a slight
difference between this and the old snd_hdac_i915_init(). The latter
(still) synchronizes with the master component binding, i.e. it
assures that the relevant DRM component gets bound when it returns, or
gives a negative error. Meanwhile the new function doesn't
synchronize but just leaves as is. It's the responsibility by the
caller's side to synchronize, or the caller may accept the
asynchronous binding on the fly.
v1->v2: Fix missing NULL check in master_bind/unbind
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 14:23:16 +00:00
|
|
|
snd_hdac_acomp_register_notifier(&codec->bus->core,
|
2018-07-11 13:48:18 +00:00
|
|
|
&spec->drm_audio_ops);
|
2019-07-16 06:56:51 +00:00
|
|
|
/* no need for forcible resume for jack check thanks to notifier */
|
|
|
|
codec->relaxed_resume = 1;
|
2016-03-21 11:18:33 +00:00
|
|
|
}
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-03-21 11:42:06 +00:00
|
|
|
/* setup_stream ops override for HSW+ */
|
|
|
|
static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
hda_nid_t pin_nid, int dev_id, u32 stream_tag,
|
|
|
|
int format)
|
2016-03-21 11:42:06 +00:00
|
|
|
{
|
|
|
|
haswell_verify_D0(codec, cvt_nid, pin_nid);
|
2019-11-19 08:47:09 +00:00
|
|
|
return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
|
|
|
|
stream_tag, format);
|
2016-03-21 11:42:06 +00:00
|
|
|
}
|
2016-03-04 14:29:49 +00:00
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
/* pin_cvt_fixup ops override for HSW+ and VLV+ */
|
|
|
|
static void i915_pin_cvt_fixup(struct hda_codec *codec,
|
|
|
|
struct hdmi_spec_per_pin *per_pin,
|
|
|
|
hda_nid_t cvt_nid)
|
|
|
|
{
|
|
|
|
if (per_pin) {
|
2020-08-26 17:03:06 +00:00
|
|
|
haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
|
2017-01-12 08:04:53 +00:00
|
|
|
snd_hda_set_dev_select(codec, per_pin->pin_nid,
|
|
|
|
per_pin->dev_id);
|
2016-03-21 11:56:46 +00:00
|
|
|
intel_verify_pin_cvt_connect(codec, per_pin);
|
|
|
|
intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
|
2017-01-12 08:04:53 +00:00
|
|
|
per_pin->dev_id, per_pin->mux_idx);
|
2016-03-21 11:56:46 +00:00
|
|
|
} else {
|
2017-01-12 08:04:53 +00:00
|
|
|
intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
|
2016-03-21 11:56:46 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-04 14:29:49 +00:00
|
|
|
|
2017-06-28 12:18:29 +00:00
|
|
|
/* precondition and allocation for Intel codecs */
|
|
|
|
static int alloc_intel_hdmi(struct hda_codec *codec)
|
2016-03-21 11:18:33 +00:00
|
|
|
{
|
2019-08-13 15:11:28 +00:00
|
|
|
int err;
|
|
|
|
|
2017-06-28 12:18:29 +00:00
|
|
|
/* requires i915 binding */
|
2016-03-21 11:18:33 +00:00
|
|
|
if (!codec->bus->core.audio_component) {
|
|
|
|
codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
|
2018-06-27 07:54:46 +00:00
|
|
|
/* set probe_id here to prevent generic fallback binding */
|
|
|
|
codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
|
2016-03-21 11:18:33 +00:00
|
|
|
return -ENODEV;
|
2016-03-18 14:10:08 +00:00
|
|
|
}
|
2015-12-10 12:03:29 +00:00
|
|
|
|
2019-08-13 15:11:28 +00:00
|
|
|
err = alloc_generic_hdmi(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
/* no need to handle unsol events */
|
|
|
|
codec->patch_ops.unsol_event = NULL;
|
|
|
|
return 0;
|
2017-06-28 12:18:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* parse and post-process for Intel codecs */
|
|
|
|
static int parse_intel_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
2020-01-20 16:01:17 +00:00
|
|
|
int err, retries = 3;
|
|
|
|
|
|
|
|
do {
|
|
|
|
err = hdmi_parse_codec(codec);
|
|
|
|
} while (err < 0 && retries--);
|
2017-06-28 12:18:29 +00:00
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
generic_spec_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
generic_hdmi_init_per_pins(codec);
|
|
|
|
register_i915_notifier(codec);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Intel Haswell and onwards; audio component with eld notifier */
|
2019-03-13 16:09:23 +00:00
|
|
|
static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
|
2021-03-24 17:23:37 +00:00
|
|
|
const int *port_map, int port_num, int dev_num)
|
2017-06-28 12:18:29 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = alloc_intel_hdmi(codec);
|
2016-03-21 11:18:33 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
2017-01-12 08:04:53 +00:00
|
|
|
codec->dp_mst = true;
|
|
|
|
spec->dyn_pcm_assign = true;
|
2017-04-13 07:35:35 +00:00
|
|
|
spec->vendor_nid = vendor_nid;
|
2019-03-13 16:09:23 +00:00
|
|
|
spec->port_map = port_map;
|
|
|
|
spec->port_num = port_num;
|
2019-11-11 19:09:37 +00:00
|
|
|
spec->intel_hsw_fixup = true;
|
2021-03-24 17:23:37 +00:00
|
|
|
spec->dev_num = dev_num;
|
2012-12-18 21:59:15 +00:00
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
intel_haswell_enable_all_pins(codec, true);
|
|
|
|
intel_haswell_fixup_enable_dp12(codec);
|
|
|
|
|
2018-12-09 09:10:19 +00:00
|
|
|
codec->display_power_control = 1;
|
2015-04-29 09:43:43 +00:00
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
codec->patch_ops.set_power_state = haswell_set_power_state;
|
|
|
|
codec->depop_delay = 0;
|
|
|
|
codec->auto_runtime_pm = 1;
|
|
|
|
|
2016-03-21 11:42:06 +00:00
|
|
|
spec->ops.setup_stream = i915_hsw_setup_stream;
|
2016-03-21 11:56:46 +00:00
|
|
|
spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
|
2016-03-21 11:42:06 +00:00
|
|
|
|
2020-07-06 20:53:17 +00:00
|
|
|
/*
|
|
|
|
* Enable silent stream feature, if it is enabled via
|
|
|
|
* module param or Kconfig option
|
|
|
|
*/
|
|
|
|
if (enable_silent_stream)
|
|
|
|
spec->send_silent_stream = true;
|
|
|
|
|
2017-06-28 12:18:29 +00:00
|
|
|
return parse_intel_hdmi(codec);
|
2016-03-21 11:18:33 +00:00
|
|
|
}
|
|
|
|
|
2017-04-13 07:35:35 +00:00
|
|
|
static int patch_i915_hsw_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
2021-03-24 17:23:37 +00:00
|
|
|
return intel_hsw_common_init(codec, 0x08, NULL, 0, 3);
|
2017-04-13 07:35:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int patch_i915_glk_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
2021-03-24 17:23:37 +00:00
|
|
|
return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3);
|
2019-03-13 16:09:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int patch_i915_icl_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* pin to port mapping table where the value indicate the pin number and
|
2019-11-15 12:44:47 +00:00
|
|
|
* the index indicate the port number.
|
2019-03-13 16:09:23 +00:00
|
|
|
*/
|
2019-11-15 12:44:47 +00:00
|
|
|
static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
|
2019-03-13 16:09:23 +00:00
|
|
|
|
2021-03-24 17:23:37 +00:00
|
|
|
return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3);
|
2017-04-13 07:35:35 +00:00
|
|
|
}
|
|
|
|
|
2019-11-05 16:10:53 +00:00
|
|
|
static int patch_i915_tgl_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* pin to port mapping table where the value indicate the pin number and
|
2019-11-15 12:44:47 +00:00
|
|
|
* the index indicate the port number.
|
2019-11-05 16:10:53 +00:00
|
|
|
*/
|
|
|
|
static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
2021-03-01 11:12:02 +00:00
|
|
|
int ret;
|
2019-11-05 16:10:53 +00:00
|
|
|
|
2021-03-24 17:23:37 +00:00
|
|
|
ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4);
|
2021-03-01 11:12:02 +00:00
|
|
|
if (!ret) {
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
spec->dyn_pcm_no_legacy = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2019-11-05 16:10:53 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 13:50:24 +00:00
|
|
|
/* Intel Baytrail and Braswell; with eld notifier */
|
2016-03-21 11:18:33 +00:00
|
|
|
static int patch_i915_byt_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
int err;
|
|
|
|
|
2017-06-28 12:18:29 +00:00
|
|
|
err = alloc_intel_hdmi(codec);
|
2016-03-21 11:18:33 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
2015-06-09 08:50:38 +00:00
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
/* For Valleyview/Cherryview, only the display codec is in the display
|
|
|
|
* power well and can use link_power ops to request/release the power.
|
|
|
|
*/
|
2018-12-08 16:31:49 +00:00
|
|
|
codec->display_power_control = 1;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-03-21 11:18:33 +00:00
|
|
|
codec->depop_delay = 0;
|
|
|
|
codec->auto_runtime_pm = 1;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-03-21 11:56:46 +00:00
|
|
|
spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
|
|
|
|
|
2017-06-28 12:18:29 +00:00
|
|
|
return parse_intel_hdmi(codec);
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 13:50:24 +00:00
|
|
|
/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
|
2016-03-21 12:56:19 +00:00
|
|
|
static int patch_i915_cpt_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2017-06-28 12:18:29 +00:00
|
|
|
err = alloc_intel_hdmi(codec);
|
2016-03-21 12:56:19 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2017-06-28 12:18:29 +00:00
|
|
|
return parse_intel_hdmi(codec);
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
|
|
|
|
2011-06-01 17:14:19 +00:00
|
|
|
/*
|
|
|
|
* Shared non-generic implementations
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int simple_playback_build_pcms(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hda_pcm *info;
|
2012-06-21 06:23:27 +00:00
|
|
|
unsigned int chans;
|
|
|
|
struct hda_pcm_stream *pstr;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
2011-06-01 17:14:19 +00:00
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
per_cvt = get_cvt(spec, 0);
|
|
|
|
chans = get_wcaps(codec, per_cvt->cvt_nid);
|
2012-06-21 06:23:27 +00:00
|
|
|
chans = get_wcaps_channels(chans);
|
2011-06-01 17:14:19 +00:00
|
|
|
|
2015-02-27 16:43:19 +00:00
|
|
|
info = snd_hda_codec_pcm_new(codec, "HDMI 0");
|
2013-03-13 13:40:31 +00:00
|
|
|
if (!info)
|
|
|
|
return -ENOMEM;
|
2016-01-12 03:13:26 +00:00
|
|
|
spec->pcm_rec[0].pcm = info;
|
2012-06-21 06:23:27 +00:00
|
|
|
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
|
|
|
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
|
|
|
|
*pstr = spec->pcm_playback;
|
2013-03-13 13:40:31 +00:00
|
|
|
pstr->nid = per_cvt->cvt_nid;
|
2012-06-21 06:23:27 +00:00
|
|
|
if (pstr->channels_max <= 2 && chans && chans <= 16)
|
|
|
|
pstr->channels_max = chans;
|
2011-06-01 17:14:19 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-15 09:53:32 +00:00
|
|
|
/* unsolicited event for jack sensing */
|
|
|
|
static void simple_hdmi_unsol_event(struct hda_codec *codec,
|
|
|
|
unsigned int res)
|
|
|
|
{
|
2012-06-21 08:43:15 +00:00
|
|
|
snd_hda_jack_set_dirty_all(codec);
|
2012-06-15 09:53:32 +00:00
|
|
|
snd_hda_jack_report_sync(codec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generic_hdmi_build_jack can be used for simple_hdmi, too,
|
|
|
|
* as long as spec->pins[] is set correctly
|
|
|
|
*/
|
|
|
|
#define simple_hdmi_build_jack generic_hdmi_build_jack
|
|
|
|
|
2011-06-01 17:14:19 +00:00
|
|
|
static int simple_playback_build_controls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
2011-06-01 17:14:19 +00:00
|
|
|
int err;
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
per_cvt = get_cvt(spec, 0);
|
2013-12-10 20:46:34 +00:00
|
|
|
err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
|
|
|
|
per_cvt->cvt_nid,
|
|
|
|
HDA_PCM_TYPE_HDMI);
|
2012-06-21 06:23:27 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
return simple_hdmi_build_jack(codec, 0);
|
2011-06-01 17:14:19 +00:00
|
|
|
}
|
|
|
|
|
2012-06-15 10:45:43 +00:00
|
|
|
static int simple_playback_init(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
|
|
|
|
hda_nid_t pin = per_pin->pin_nid;
|
2012-06-21 06:23:27 +00:00
|
|
|
|
|
|
|
snd_hda_codec_write(codec, pin, 0,
|
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
|
|
|
/* some codecs require to unmute the pin */
|
|
|
|
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
|
|
|
|
snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
|
|
|
AMP_OUT_UNMUTE);
|
2019-11-19 08:47:08 +00:00
|
|
|
snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
|
2012-06-15 10:45:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-01 17:14:19 +00:00
|
|
|
static void simple_playback_free(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
|
2013-03-13 13:40:31 +00:00
|
|
|
hdmi_array_free(spec);
|
2011-06-01 17:14:19 +00:00
|
|
|
kfree(spec);
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
/*
|
|
|
|
* Nvidia specific implementations
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define Nv_VERB_SET_Channel_Allocation 0xF79
|
|
|
|
#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
|
|
|
|
#define Nv_VERB_SET_Audio_Protection_On 0xF98
|
|
|
|
#define Nv_VERB_SET_Audio_Protection_Off 0xF99
|
|
|
|
|
|
|
|
#define nvhdmi_master_con_nid_7x 0x04
|
|
|
|
#define nvhdmi_master_pin_nid_7x 0x05
|
|
|
|
|
2011-05-02 10:17:41 +00:00
|
|
|
static const hda_nid_t nvhdmi_con_nids_7x[4] = {
|
2010-09-07 10:27:25 +00:00
|
|
|
/*front, rear, clfe, rear_surr */
|
|
|
|
0x6, 0x8, 0xa, 0xc,
|
|
|
|
};
|
|
|
|
|
2012-06-15 12:38:31 +00:00
|
|
|
static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
|
|
|
|
/* set audio protect on */
|
|
|
|
{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
|
|
|
|
/* enable digital output on pin widget */
|
|
|
|
{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
|
2010-09-07 10:27:25 +00:00
|
|
|
/* set audio protect on */
|
|
|
|
{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
|
|
|
|
/* enable digital output on pin widget */
|
|
|
|
{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
|
|
|
{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
|
|
|
{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
|
|
|
{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
|
|
|
{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
|
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef LIMITED_RATE_FMT_SUPPORT
|
|
|
|
/* support only the safe format and rate */
|
|
|
|
#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
|
|
|
|
#define SUPPORTED_MAXBPS 16
|
|
|
|
#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
|
|
|
#else
|
|
|
|
/* support all rates and formats */
|
|
|
|
#define SUPPORTED_RATES \
|
|
|
|
(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
|
|
|
|
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
|
|
|
|
SNDRV_PCM_RATE_192000)
|
|
|
|
#define SUPPORTED_MAXBPS 24
|
|
|
|
#define SUPPORTED_FORMATS \
|
|
|
|
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
|
|
|
#endif
|
|
|
|
|
2012-06-15 12:38:31 +00:00
|
|
|
static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
|
2010-09-07 10:27:25 +00:00
|
|
|
{
|
2012-06-15 12:38:31 +00:00
|
|
|
snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-07 12:20:07 +00:00
|
|
|
static const unsigned int channels_2_6_8[] = {
|
2011-01-10 16:19:31 +00:00
|
|
|
2, 6, 8
|
|
|
|
};
|
|
|
|
|
2017-06-07 12:20:07 +00:00
|
|
|
static const unsigned int channels_2_8[] = {
|
2011-01-10 16:19:31 +00:00
|
|
|
2, 8
|
|
|
|
};
|
|
|
|
|
2017-06-07 12:20:07 +00:00
|
|
|
static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
|
2011-01-10 16:19:31 +00:00
|
|
|
.count = ARRAY_SIZE(channels_2_6_8),
|
|
|
|
.list = channels_2_6_8,
|
|
|
|
.mask = 0,
|
|
|
|
};
|
|
|
|
|
2017-06-07 12:20:07 +00:00
|
|
|
static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
|
2011-01-10 16:19:31 +00:00
|
|
|
.count = ARRAY_SIZE(channels_2_8),
|
|
|
|
.list = channels_2_8,
|
|
|
|
.mask = 0,
|
|
|
|
};
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2017-06-07 12:20:07 +00:00
|
|
|
const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
|
2011-01-10 16:19:31 +00:00
|
|
|
|
2015-10-01 14:20:04 +00:00
|
|
|
switch (codec->preset->vendor_id) {
|
2011-01-10 16:19:31 +00:00
|
|
|
case 0x10de0002:
|
|
|
|
case 0x10de0003:
|
|
|
|
case 0x10de0005:
|
|
|
|
case 0x10de0006:
|
|
|
|
hw_constraints_channels = &hw_constraints_2_8_channels;
|
|
|
|
break;
|
|
|
|
case 0x10de0007:
|
|
|
|
hw_constraints_channels = &hw_constraints_2_6_8_channels;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hw_constraints_channels != NULL) {
|
|
|
|
snd_pcm_hw_constraint_list(substream->runtime, 0,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
|
|
|
hw_constraints_channels);
|
2011-01-14 08:42:27 +00:00
|
|
|
} else {
|
|
|
|
snd_pcm_hw_constraint_step(substream->runtime, 0,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
|
2011-01-10 16:19:31 +00:00
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
|
|
|
|
stream_tag, format, substream);
|
|
|
|
}
|
|
|
|
|
2012-06-15 12:34:42 +00:00
|
|
|
static const struct hda_pcm_stream simple_pcm_playback = {
|
|
|
|
.substreams = 1,
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 2,
|
|
|
|
.ops = {
|
|
|
|
.open = simple_playback_pcm_open,
|
|
|
|
.close = simple_playback_pcm_close,
|
|
|
|
.prepare = simple_playback_pcm_prepare
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_codec_ops simple_hdmi_patch_ops = {
|
|
|
|
.build_controls = simple_playback_build_controls,
|
|
|
|
.build_pcms = simple_playback_build_pcms,
|
|
|
|
.init = simple_playback_init,
|
|
|
|
.free = simple_playback_free,
|
2012-06-15 12:40:21 +00:00
|
|
|
.unsol_event = simple_hdmi_unsol_event,
|
2012-06-15 12:34:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int patch_simple_hdmi(struct hda_codec *codec,
|
|
|
|
hda_nid_t cvt_nid, hda_nid_t pin_nid)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
|
|
|
struct hdmi_spec_per_pin *per_pin;
|
2012-06-15 12:34:42 +00:00
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (!spec)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
spec->codec = codec;
|
2012-06-15 12:34:42 +00:00
|
|
|
codec->spec = spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
hdmi_array_init(spec, 1);
|
2012-06-15 12:34:42 +00:00
|
|
|
|
|
|
|
spec->multiout.num_dacs = 0; /* no analog */
|
|
|
|
spec->multiout.max_channels = 2;
|
|
|
|
spec->multiout.dig_out_nid = cvt_nid;
|
|
|
|
spec->num_cvts = 1;
|
|
|
|
spec->num_pins = 1;
|
2013-03-13 13:40:31 +00:00
|
|
|
per_pin = snd_array_new(&spec->pins);
|
|
|
|
per_cvt = snd_array_new(&spec->cvts);
|
|
|
|
if (!per_pin || !per_cvt) {
|
|
|
|
simple_playback_free(codec);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
per_cvt->cvt_nid = cvt_nid;
|
|
|
|
per_pin->pin_nid = pin_nid;
|
2012-06-15 12:34:42 +00:00
|
|
|
spec->pcm_playback = simple_pcm_playback;
|
|
|
|
|
|
|
|
codec->patch_ops = simple_hdmi_patch_ops;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-07 00:19:04 +00:00
|
|
|
static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
|
|
|
|
int channels)
|
|
|
|
{
|
|
|
|
unsigned int chanmask;
|
|
|
|
int chan = channels ? (channels - 1) : 1;
|
|
|
|
|
|
|
|
switch (channels) {
|
|
|
|
default:
|
|
|
|
case 0:
|
|
|
|
case 2:
|
|
|
|
chanmask = 0x00;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
chanmask = 0x08;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
chanmask = 0x0b;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
chanmask = 0x13;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the audio infoframe channel allocation and checksum fields. The
|
|
|
|
* channel count is computed implicitly by the hardware. */
|
|
|
|
snd_hda_codec_write(codec, 0x1, 0,
|
|
|
|
Nv_VERB_SET_Channel_Allocation, chanmask);
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, 0x1, 0,
|
|
|
|
Nv_VERB_SET_Info_Frame_Checksum,
|
|
|
|
(0x71 - chan - chanmask));
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
|
|
|
|
0, AC_VERB_SET_CHANNEL_STREAMID, 0);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
/* set the stream id */
|
|
|
|
snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
|
|
|
|
AC_VERB_SET_CHANNEL_STREAMID, 0);
|
|
|
|
/* set the stream format */
|
|
|
|
snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
|
|
|
|
AC_VERB_SET_STREAM_FORMAT, 0);
|
|
|
|
}
|
|
|
|
|
2011-04-07 00:19:04 +00:00
|
|
|
/* The audio hardware sends a channel count of 0x7 (8ch) when all the
|
|
|
|
* streams are disabled. */
|
|
|
|
nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
int chs;
|
2011-11-02 20:40:06 +00:00
|
|
|
unsigned int dataDCC2, channel_id;
|
2010-09-07 10:27:25 +00:00
|
|
|
int i;
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2012-05-10 08:21:29 +00:00
|
|
|
struct hda_spdif_out *spdif;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
|
|
|
mutex_lock(&codec->spdif_mutex);
|
2013-03-13 13:40:31 +00:00
|
|
|
per_cvt = get_cvt(spec, 0);
|
|
|
|
spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
|
2010-09-07 10:27:25 +00:00
|
|
|
|
|
|
|
chs = substream->runtime->channels;
|
|
|
|
|
|
|
|
dataDCC2 = 0x2;
|
|
|
|
|
|
|
|
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
|
2010-09-07 10:27:25 +00:00
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_master_con_nid_7x,
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_1,
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
|
2010-09-07 10:27:25 +00:00
|
|
|
|
|
|
|
/* set the stream id */
|
|
|
|
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
|
|
|
|
AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
|
|
|
|
|
|
|
|
/* set the stream format */
|
|
|
|
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
|
|
|
|
AC_VERB_SET_STREAM_FORMAT, format);
|
|
|
|
|
|
|
|
/* turn on again (if needed) */
|
|
|
|
/* enable and set the channel status audio/data flag */
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
|
2010-09-07 10:27:25 +00:00
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_master_con_nid_7x,
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_1,
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
spdif->ctls & 0xff);
|
2010-09-07 10:27:25 +00:00
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_master_con_nid_7x,
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
if (chs == 2)
|
|
|
|
channel_id = 0;
|
|
|
|
else
|
|
|
|
channel_id = i * 2;
|
|
|
|
|
|
|
|
/* turn off SPDIF once;
|
|
|
|
*otherwise the IEC958 bits won't be updated
|
|
|
|
*/
|
|
|
|
if (codec->spdif_status_reset &&
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
(spdif->ctls & AC_DIG1_ENABLE))
|
2010-09-07 10:27:25 +00:00
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_con_nids_7x[i],
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_1,
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
|
2010-09-07 10:27:25 +00:00
|
|
|
/* set the stream id */
|
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_con_nids_7x[i],
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_CHANNEL_STREAMID,
|
|
|
|
(stream_tag << 4) | channel_id);
|
|
|
|
/* set the stream format */
|
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_con_nids_7x[i],
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_STREAM_FORMAT,
|
|
|
|
format);
|
|
|
|
/* turn on again (if needed) */
|
|
|
|
/* enable and set the channel status audio/data flag */
|
|
|
|
if (codec->spdif_status_reset &&
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
(spdif->ctls & AC_DIG1_ENABLE)) {
|
2010-09-07 10:27:25 +00:00
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_con_nids_7x[i],
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_1,
|
ALSA: hda: Allow multple SPDIF controls per codec
Currently, the data that backs the kcontrols created by
snd_hda_create_spdif_out_ctls is stored directly in struct hda_codec. When
multiple sets of these controls are stored, they will all manipulate the
same data, causing confusion. Instead, store an array of this data, one
copy per converter, to isolate the controls.
This patch would cause a behavioural change in the case where
snd_hda_create_spdif_out_ctls was called multiple times for a single codec.
As best I can tell, this is never the case for any codec.
This will be relevant at least for some HDMI audio codecs, such as the
NVIDIA GeForce 520 and Intel Ibex Peak. A future change will modify the
driver's handling of those codecs to create multiple PCMs per codec. Note
that this issue isn't affected by whether one creates a PCM-per-converter
or PCM-per-pin; there are multiple of both within a single codec in both
of those codecs.
Note that those codecs don't currently create multiple PCMs for the codec
due to the default HW mux state of all pins being to point at the same
converter, hence there is only a single converter routed to any pin, and
hence only a single PCM.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2011-06-01 17:14:17 +00:00
|
|
|
spdif->ctls & 0xff);
|
2010-09-07 10:27:25 +00:00
|
|
|
snd_hda_codec_write(codec,
|
|
|
|
nvhdmi_con_nids_7x[i],
|
|
|
|
0,
|
|
|
|
AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-07 00:19:04 +00:00
|
|
|
nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
|
2010-09-07 10:27:25 +00:00
|
|
|
|
|
|
|
mutex_unlock(&codec->spdif_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-02 10:17:41 +00:00
|
|
|
static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
|
2010-09-07 10:27:25 +00:00
|
|
|
.substreams = 1,
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 8,
|
|
|
|
.nid = nvhdmi_master_con_nid_7x,
|
|
|
|
.rates = SUPPORTED_RATES,
|
|
|
|
.maxbps = SUPPORTED_MAXBPS,
|
|
|
|
.formats = SUPPORTED_FORMATS,
|
|
|
|
.ops = {
|
|
|
|
.open = simple_playback_pcm_open,
|
|
|
|
.close = nvhdmi_8ch_7x_pcm_close,
|
|
|
|
.prepare = nvhdmi_8ch_7x_pcm_prepare
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int patch_nvhdmi_2ch(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
2012-06-15 12:34:42 +00:00
|
|
|
int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
|
|
|
|
nvhdmi_master_pin_nid_7x);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2012-06-15 12:38:31 +00:00
|
|
|
codec->patch_ops.init = nvhdmi_7x_init_2ch;
|
2012-06-15 12:34:42 +00:00
|
|
|
/* override the PCM rates, etc, as the codec doesn't give full list */
|
|
|
|
spec = codec->spec;
|
|
|
|
spec->pcm_playback.rates = SUPPORTED_RATES;
|
|
|
|
spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
|
|
|
|
spec->pcm_playback.formats = SUPPORTED_FORMATS;
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-01 10:17:41 +00:00
|
|
|
static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
int err = simple_playback_build_pcms(codec);
|
2013-03-13 13:40:31 +00:00
|
|
|
if (!err) {
|
|
|
|
struct hda_pcm *info = get_pcm_rec(spec, 0);
|
|
|
|
info->own_chmap = true;
|
|
|
|
}
|
2012-08-01 10:17:41 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-03-13 13:40:31 +00:00
|
|
|
struct hda_pcm *info;
|
2012-08-01 10:17:41 +00:00
|
|
|
struct snd_pcm_chmap *chmap;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = simple_playback_build_controls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* add channel maps */
|
2013-03-13 13:40:31 +00:00
|
|
|
info = get_pcm_rec(spec, 0);
|
|
|
|
err = snd_pcm_add_chmap_ctls(info->pcm,
|
2012-08-01 10:17:41 +00:00
|
|
|
SNDRV_PCM_STREAM_PLAYBACK,
|
|
|
|
snd_pcm_alt_chmaps, 8, 0, &chmap);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2015-10-01 14:20:04 +00:00
|
|
|
switch (codec->preset->vendor_id) {
|
2012-08-01 10:17:41 +00:00
|
|
|
case 0x10de0002:
|
|
|
|
case 0x10de0003:
|
|
|
|
case 0x10de0005:
|
|
|
|
case 0x10de0006:
|
|
|
|
chmap->channel_mask = (1U << 2) | (1U << 8);
|
|
|
|
break;
|
|
|
|
case 0x10de0007:
|
|
|
|
chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
int err = patch_nvhdmi_2ch(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
|
|
|
spec->multiout.max_channels = 8;
|
2012-06-15 12:34:42 +00:00
|
|
|
spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
|
2012-06-15 12:38:31 +00:00
|
|
|
codec->patch_ops.init = nvhdmi_7x_init_8ch;
|
2012-08-01 10:17:41 +00:00
|
|
|
codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
|
|
|
|
codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
|
2011-04-07 00:19:04 +00:00
|
|
|
|
|
|
|
/* Initialize the audio infoframe channel mask and checksum to something
|
|
|
|
* valid */
|
|
|
|
nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-03 15:15:00 +00:00
|
|
|
/*
|
|
|
|
* NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
|
|
|
|
* - 0x10de0015
|
|
|
|
* - 0x10de0040
|
|
|
|
*/
|
2016-03-04 14:29:46 +00:00
|
|
|
static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
|
2016-03-04 14:29:48 +00:00
|
|
|
struct hdac_cea_channel_speaker_allocation *cap, int channels)
|
2013-11-03 15:15:00 +00:00
|
|
|
{
|
|
|
|
if (cap->ca_index == 0x00 && channels == 2)
|
|
|
|
return SNDRV_CTL_TLVT_CHMAP_FIXED;
|
|
|
|
|
2016-03-14 05:05:06 +00:00
|
|
|
/* If the speaker allocation matches the channel count, it is OK. */
|
|
|
|
if (cap->channels != channels)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* all channels are remappable freely */
|
|
|
|
return SNDRV_CTL_TLVT_CHMAP_VAR;
|
2013-11-03 15:15:00 +00:00
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:50 +00:00
|
|
|
static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
|
|
|
|
int ca, int chs, unsigned char *map)
|
2013-11-03 15:15:00 +00:00
|
|
|
{
|
|
|
|
if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
/* map from pin NID to port; port is 0-based */
|
|
|
|
/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
|
|
|
|
static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
|
|
|
|
{
|
|
|
|
return pin_nid - 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reverse-map from port to pin NID: see above */
|
|
|
|
static int nvhdmi_port2pin(struct hda_codec *codec, int port)
|
|
|
|
{
|
|
|
|
return port + 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
|
|
|
|
.pin2port = nvhdmi_pin2port,
|
|
|
|
.pin_eld_notify = generic_acomp_pin_eld_notify,
|
|
|
|
.master_bind = generic_acomp_master_bind,
|
|
|
|
.master_unbind = generic_acomp_master_unbind,
|
|
|
|
};
|
|
|
|
|
2013-11-03 15:15:00 +00:00
|
|
|
static int patch_nvhdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
int err;
|
|
|
|
|
2019-11-19 08:47:10 +00:00
|
|
|
err = alloc_generic_hdmi(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
codec->dp_mst = true;
|
|
|
|
|
|
|
|
spec = codec->spec;
|
|
|
|
spec->dyn_pcm_assign = true;
|
|
|
|
|
|
|
|
err = hdmi_parse_codec(codec);
|
|
|
|
if (err < 0) {
|
|
|
|
generic_spec_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
generic_hdmi_init_per_pins(codec);
|
|
|
|
|
|
|
|
spec->dyn_pin_out = true;
|
|
|
|
|
|
|
|
spec->chmap.ops.chmap_cea_alloc_validate_get_type =
|
|
|
|
nvhdmi_chmap_cea_alloc_validate_get_type;
|
|
|
|
spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
|
|
|
|
|
|
|
|
codec->link_down_at_suspend = 1;
|
|
|
|
|
|
|
|
generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int patch_nvhdmi_legacy(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
|
|
|
int err;
|
|
|
|
|
2013-11-03 15:15:00 +00:00
|
|
|
err = patch_generic_hdmi(codec);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
spec = codec->spec;
|
2014-01-30 18:52:16 +00:00
|
|
|
spec->dyn_pin_out = true;
|
2013-11-03 15:15:00 +00:00
|
|
|
|
2016-03-04 14:29:46 +00:00
|
|
|
spec->chmap.ops.chmap_cea_alloc_validate_get_type =
|
2013-11-03 15:15:00 +00:00
|
|
|
nvhdmi_chmap_cea_alloc_validate_get_type;
|
2016-03-04 14:29:46 +00:00
|
|
|
spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
|
2013-11-03 15:15:00 +00:00
|
|
|
|
2019-10-17 15:04:11 +00:00
|
|
|
codec->link_down_at_suspend = 1;
|
|
|
|
|
2013-11-03 15:15:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-05 12:56:20 +00:00
|
|
|
/*
|
|
|
|
* The HDA codec on NVIDIA Tegra contains two scratch registers that are
|
|
|
|
* accessed using vendor-defined verbs. These registers can be used for
|
|
|
|
* interoperability between the HDA and HDMI drivers.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Audio Function Group node */
|
|
|
|
#define NVIDIA_AFG_NID 0x01
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The SCRATCH0 register is used to notify the HDMI codec of changes in audio
|
|
|
|
* format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
|
|
|
|
* be raised in the HDMI codec. The remainder of the bits is arbitrary. This
|
|
|
|
* implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
|
|
|
|
* additional bit (at position 30) to signal the validity of the format.
|
|
|
|
*
|
|
|
|
* | 31 | 30 | 29 16 | 15 0 |
|
|
|
|
* +---------+-------+--------+--------+
|
|
|
|
* | TRIGGER | VALID | UNUSED | FORMAT |
|
|
|
|
* +-----------------------------------|
|
|
|
|
*
|
|
|
|
* Note that for the trigger bit to take effect it needs to change value
|
|
|
|
* (i.e. it needs to be toggled).
|
|
|
|
*/
|
|
|
|
#define NVIDIA_GET_SCRATCH0 0xfa6
|
|
|
|
#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7
|
|
|
|
#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8
|
|
|
|
#define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9
|
|
|
|
#define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa
|
|
|
|
#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
|
|
|
|
#define NVIDIA_SCRATCH_VALID (1 << 6)
|
|
|
|
|
|
|
|
#define NVIDIA_GET_SCRATCH1 0xfab
|
|
|
|
#define NVIDIA_SET_SCRATCH1_BYTE0 0xfac
|
|
|
|
#define NVIDIA_SET_SCRATCH1_BYTE1 0xfad
|
|
|
|
#define NVIDIA_SET_SCRATCH1_BYTE2 0xfae
|
|
|
|
#define NVIDIA_SET_SCRATCH1_BYTE3 0xfaf
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
|
|
|
|
* the format is invalidated so that the HDMI codec can be disabled.
|
|
|
|
*/
|
|
|
|
static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format)
|
|
|
|
{
|
|
|
|
unsigned int value;
|
|
|
|
|
|
|
|
/* bits [31:30] contain the trigger and valid bits */
|
|
|
|
value = snd_hda_codec_read(codec, NVIDIA_AFG_NID, 0,
|
|
|
|
NVIDIA_GET_SCRATCH0, 0);
|
|
|
|
value = (value >> 24) & 0xff;
|
|
|
|
|
|
|
|
/* bits [15:0] are used to store the HDA format */
|
|
|
|
snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0,
|
|
|
|
NVIDIA_SET_SCRATCH0_BYTE0,
|
|
|
|
(format >> 0) & 0xff);
|
|
|
|
snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0,
|
|
|
|
NVIDIA_SET_SCRATCH0_BYTE1,
|
|
|
|
(format >> 8) & 0xff);
|
|
|
|
|
|
|
|
/* bits [16:24] are unused */
|
|
|
|
snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0,
|
|
|
|
NVIDIA_SET_SCRATCH0_BYTE2, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Bit 30 signals that the data is valid and hence that HDMI audio can
|
|
|
|
* be enabled.
|
|
|
|
*/
|
|
|
|
if (format == 0)
|
|
|
|
value &= ~NVIDIA_SCRATCH_VALID;
|
|
|
|
else
|
|
|
|
value |= NVIDIA_SCRATCH_VALID;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Whenever the trigger bit is toggled, an interrupt is raised in the
|
|
|
|
* HDMI codec. The HDMI driver will use that as trigger to update its
|
|
|
|
* configuration.
|
|
|
|
*/
|
|
|
|
value ^= NVIDIA_SCRATCH_TRIGGER;
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0,
|
|
|
|
NVIDIA_SET_SCRATCH0_BYTE3, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag,
|
|
|
|
format, substream);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* notify the HDMI codec of the format change */
|
|
|
|
tegra_hdmi_set_format(codec, format);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
/* invalidate the format in the HDMI codec */
|
|
|
|
tegra_hdmi_set_format(codec, 0);
|
|
|
|
|
|
|
|
return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->num_pins; i++) {
|
|
|
|
struct hda_pcm *pcm = get_pcm_rec(spec, i);
|
|
|
|
|
|
|
|
if (pcm->pcm_type == type)
|
|
|
|
return pcm;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tegra_hdmi_build_pcms(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hda_pcm_stream *stream;
|
|
|
|
struct hda_pcm *pcm;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = generic_hdmi_build_pcms(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
|
|
|
|
if (!pcm)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Override ->prepare() and ->cleanup() operations to notify the HDMI
|
|
|
|
* codec about format changes.
|
|
|
|
*/
|
|
|
|
stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
|
|
|
|
stream->ops.prepare = tegra_hdmi_pcm_prepare;
|
|
|
|
stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int patch_tegra_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
2020-08-25 05:24:14 +00:00
|
|
|
struct hdmi_spec *spec;
|
2015-05-05 12:56:20 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = patch_generic_hdmi(codec);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
|
2020-08-25 05:24:14 +00:00
|
|
|
spec = codec->spec;
|
|
|
|
spec->chmap.ops.chmap_cea_alloc_validate_get_type =
|
|
|
|
nvhdmi_chmap_cea_alloc_validate_get_type;
|
|
|
|
spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
|
2015-05-05 12:56:20 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
/*
|
2013-10-24 18:10:35 +00:00
|
|
|
* ATI/AMD-specific implementations
|
2010-09-07 10:27:25 +00:00
|
|
|
*/
|
|
|
|
|
2013-10-24 18:10:35 +00:00
|
|
|
#define is_amdhdmi_rev3_or_later(codec) \
|
2015-03-03 09:07:24 +00:00
|
|
|
((codec)->core.vendor_id == 0x1002aa01 && \
|
|
|
|
((codec)->core.revision_id & 0xff00) >= 0x0300)
|
2013-10-24 18:10:35 +00:00
|
|
|
#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
|
|
|
|
|
|
|
|
/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
|
|
|
|
#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771
|
|
|
|
#define ATI_VERB_SET_DOWNMIX_INFO 0x772
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_01 0x777
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_23 0x778
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_45 0x779
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_67 0x77a
|
2013-10-24 18:10:37 +00:00
|
|
|
#define ATI_VERB_SET_HBR_CONTROL 0x77c
|
2013-10-24 18:10:35 +00:00
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_1 0x785
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_3 0x786
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_5 0x787
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_7 0x788
|
|
|
|
#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
|
|
|
|
#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71
|
|
|
|
#define ATI_VERB_GET_DOWNMIX_INFO 0xf72
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_01 0xf77
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_23 0xf78
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_45 0xf79
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a
|
2013-10-24 18:10:37 +00:00
|
|
|
#define ATI_VERB_GET_HBR_CONTROL 0xf7c
|
2013-10-24 18:10:35 +00:00
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_1 0xf85
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_3 0xf86
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_5 0xf87
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_7 0xf88
|
|
|
|
#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89
|
|
|
|
|
2013-10-24 18:10:38 +00:00
|
|
|
/* AMD specific HDA cvt verbs */
|
|
|
|
#define ATI_VERB_SET_RAMP_RATE 0x770
|
|
|
|
#define ATI_VERB_GET_RAMP_RATE 0xf70
|
|
|
|
|
2013-10-24 18:10:35 +00:00
|
|
|
#define ATI_OUT_ENABLE 0x1
|
|
|
|
|
|
|
|
#define ATI_MULTICHANNEL_MODE_PAIRED 0
|
|
|
|
#define ATI_MULTICHANNEL_MODE_SINGLE 1
|
|
|
|
|
2013-10-24 18:10:37 +00:00
|
|
|
#define ATI_HBR_CAPABLE 0x01
|
|
|
|
#define ATI_HBR_ENABLE 0x10
|
|
|
|
|
2013-10-24 18:10:36 +00:00
|
|
|
static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id, unsigned char *buf, int *eld_size)
|
2013-10-24 18:10:36 +00:00
|
|
|
{
|
2019-11-19 08:47:09 +00:00
|
|
|
WARN_ON(dev_id != 0);
|
2013-10-24 18:10:36 +00:00
|
|
|
/* call hda_eld.c ATI/AMD-specific function */
|
|
|
|
return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
|
|
|
|
is_amdhdmi_rev3_or_later(codec));
|
|
|
|
}
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
|
|
|
|
hda_nid_t pin_nid, int dev_id, int ca,
|
2013-10-24 18:10:35 +00:00
|
|
|
int active_channels, int conn_type)
|
|
|
|
{
|
2019-11-19 08:47:09 +00:00
|
|
|
WARN_ON(dev_id != 0);
|
2013-10-24 18:10:35 +00:00
|
|
|
snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int atihdmi_paired_swap_fc_lfe(int pos)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* ATI/AMD have automatic FC/LFE swap built-in
|
|
|
|
* when in pairwise mapping mode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (pos) {
|
|
|
|
/* see channel_allocations[].speakers[] */
|
|
|
|
case 2: return 3;
|
|
|
|
case 3: return 2;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:50 +00:00
|
|
|
static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
|
|
|
|
int ca, int chs, unsigned char *map)
|
2013-10-24 18:10:35 +00:00
|
|
|
{
|
2016-03-04 14:29:48 +00:00
|
|
|
struct hdac_cea_channel_speaker_allocation *cap;
|
2013-10-24 18:10:35 +00:00
|
|
|
int i, j;
|
|
|
|
|
|
|
|
/* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
|
|
|
|
|
2016-03-04 14:29:52 +00:00
|
|
|
cap = snd_hdac_get_ch_alloc_from_ca(ca);
|
2013-10-24 18:10:35 +00:00
|
|
|
for (i = 0; i < chs; ++i) {
|
2016-03-04 14:29:52 +00:00
|
|
|
int mask = snd_hdac_chmap_to_spk_mask(map[i]);
|
2013-10-24 18:10:35 +00:00
|
|
|
bool ok = false;
|
|
|
|
bool companion_ok = false;
|
|
|
|
|
|
|
|
if (!mask)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0 + i % 2; j < 8; j += 2) {
|
|
|
|
int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
|
|
|
|
if (cap->speakers[chan_idx] == mask) {
|
|
|
|
/* channel is in a supported position */
|
|
|
|
ok = true;
|
|
|
|
|
|
|
|
if (i % 2 == 0 && i + 1 < chs) {
|
|
|
|
/* even channel, check the odd companion */
|
|
|
|
int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
|
2016-03-04 14:29:52 +00:00
|
|
|
int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
|
2013-10-24 18:10:35 +00:00
|
|
|
int comp_mask_act = cap->speakers[comp_chan_idx];
|
|
|
|
|
|
|
|
if (comp_mask_req == comp_mask_act)
|
|
|
|
companion_ok = true;
|
|
|
|
else
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (companion_ok)
|
|
|
|
i++; /* companion channel already checked */
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:49 +00:00
|
|
|
static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
|
|
|
|
hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
|
2013-10-24 18:10:35 +00:00
|
|
|
{
|
2020-05-05 03:03:53 +00:00
|
|
|
struct hda_codec *codec = hdac_to_hda_codec(hdac);
|
2013-10-24 18:10:35 +00:00
|
|
|
int verb;
|
|
|
|
int ati_channel_setup = 0;
|
|
|
|
|
|
|
|
if (hdmi_slot > 7)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!has_amd_full_remap_support(codec)) {
|
|
|
|
hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
|
|
|
|
|
|
|
|
/* In case this is an odd slot but without stream channel, do not
|
|
|
|
* disable the slot since the corresponding even slot could have a
|
|
|
|
* channel. In case neither have a channel, the slot pair will be
|
|
|
|
* disabled when this function is called for the even slot. */
|
|
|
|
if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
hdmi_slot -= hdmi_slot % 2;
|
|
|
|
|
|
|
|
if (stream_channel != 0xf)
|
|
|
|
stream_channel -= stream_channel % 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
|
|
|
|
|
|
|
|
/* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
|
|
|
|
|
|
|
|
if (stream_channel != 0xf)
|
|
|
|
ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
|
|
|
|
|
|
|
|
return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:49 +00:00
|
|
|
static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
|
|
|
|
hda_nid_t pin_nid, int asp_slot)
|
2013-10-24 18:10:35 +00:00
|
|
|
{
|
2020-05-05 03:03:53 +00:00
|
|
|
struct hda_codec *codec = hdac_to_hda_codec(hdac);
|
2013-10-24 18:10:35 +00:00
|
|
|
bool was_odd = false;
|
|
|
|
int ati_asp_slot = asp_slot;
|
|
|
|
int verb;
|
|
|
|
int ati_channel_setup;
|
|
|
|
|
|
|
|
if (asp_slot > 7)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!has_amd_full_remap_support(codec)) {
|
|
|
|
ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
|
|
|
|
if (ati_asp_slot % 2 != 0) {
|
|
|
|
ati_asp_slot -= 1;
|
|
|
|
was_odd = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
|
|
|
|
|
|
|
|
ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
|
|
|
|
|
|
|
|
if (!(ati_channel_setup & ATI_OUT_ENABLE))
|
|
|
|
return 0xf;
|
|
|
|
|
|
|
|
return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
|
|
|
|
}
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2016-03-04 14:29:46 +00:00
|
|
|
static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
|
|
|
|
struct hdac_chmap *chmap,
|
2016-03-04 14:29:48 +00:00
|
|
|
struct hdac_cea_channel_speaker_allocation *cap,
|
2016-03-04 14:29:46 +00:00
|
|
|
int channels)
|
2013-10-24 18:10:35 +00:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
|
|
|
|
* we need to take that into account (a single channel may take 2
|
|
|
|
* channel slots if we need to carry a silent channel next to it).
|
|
|
|
* On Rev3+ AMD codecs this function is not used.
|
|
|
|
*/
|
|
|
|
int chanpairs = 0;
|
|
|
|
|
|
|
|
/* We only produce even-numbered channel count TLVs */
|
|
|
|
if ((channels % 2) != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (c = 0; c < 7; c += 2) {
|
|
|
|
if (cap->speakers[c] || cap->speakers[c+1])
|
|
|
|
chanpairs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chanpairs * 2 != channels)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return SNDRV_CTL_TLVT_CHMAP_PAIRED;
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:50 +00:00
|
|
|
static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
|
2016-03-04 14:29:48 +00:00
|
|
|
struct hdac_cea_channel_speaker_allocation *cap,
|
|
|
|
unsigned int *chmap, int channels)
|
2013-10-24 18:10:35 +00:00
|
|
|
{
|
|
|
|
/* produce paired maps for pre-rev3 ATI/AMD codecs */
|
|
|
|
int count = 0;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
for (c = 7; c >= 0; c--) {
|
|
|
|
int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
|
|
|
|
int spk = cap->speakers[chan];
|
|
|
|
if (!spk) {
|
|
|
|
/* add N/A channel if the companion channel is occupied */
|
|
|
|
if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
|
|
|
|
chmap[count++] = SNDRV_CHMAP_NA;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:52 +00:00
|
|
|
chmap[count++] = snd_hdac_spk_to_chmap(spk);
|
2013-10-24 18:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WARN_ON(count != channels);
|
|
|
|
}
|
|
|
|
|
2013-10-24 18:10:37 +00:00
|
|
|
static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
int dev_id, bool hbr)
|
2013-10-24 18:10:37 +00:00
|
|
|
{
|
|
|
|
int hbr_ctl, hbr_ctl_new;
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
WARN_ON(dev_id != 0);
|
|
|
|
|
2013-10-24 18:10:37 +00:00
|
|
|
hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
|
2013-11-10 18:56:10 +00:00
|
|
|
if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
|
2013-10-24 18:10:37 +00:00
|
|
|
if (hbr)
|
|
|
|
hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
|
|
|
|
else
|
|
|
|
hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
|
|
|
|
|
2014-02-25 11:21:03 +00:00
|
|
|
codec_dbg(codec,
|
|
|
|
"atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
|
2013-10-24 18:10:37 +00:00
|
|
|
pin_nid,
|
|
|
|
hbr_ctl == hbr_ctl_new ? "" : "new-",
|
|
|
|
hbr_ctl_new);
|
|
|
|
|
|
|
|
if (hbr_ctl != hbr_ctl_new)
|
|
|
|
snd_hda_codec_write(codec, pin_nid, 0,
|
|
|
|
ATI_VERB_SET_HBR_CONTROL,
|
|
|
|
hbr_ctl_new);
|
|
|
|
|
|
|
|
} else if (hbr)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-24 18:10:38 +00:00
|
|
|
static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
|
2019-11-19 08:47:09 +00:00
|
|
|
hda_nid_t pin_nid, int dev_id,
|
|
|
|
u32 stream_tag, int format)
|
2013-10-24 18:10:38 +00:00
|
|
|
{
|
|
|
|
if (is_amdhdmi_rev3_or_later(codec)) {
|
|
|
|
int ramp_rate = 180; /* default as per AMD spec */
|
|
|
|
/* disable ramp-up/down for non-pcm as per AMD spec */
|
|
|
|
if (format & AC_FMT_TYPE_NON_PCM)
|
|
|
|
ramp_rate = 0;
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
|
|
|
|
}
|
|
|
|
|
2019-11-19 08:47:09 +00:00
|
|
|
return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
|
|
|
|
stream_tag, format);
|
2013-10-24 18:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-24 18:10:35 +00:00
|
|
|
static int atihdmi_init(struct hda_codec *codec)
|
2010-09-07 10:27:25 +00:00
|
|
|
{
|
|
|
|
struct hdmi_spec *spec = codec->spec;
|
2013-10-24 18:10:35 +00:00
|
|
|
int pin_idx, err;
|
2010-09-07 10:27:25 +00:00
|
|
|
|
2013-10-24 18:10:35 +00:00
|
|
|
err = generic_hdmi_init(codec);
|
|
|
|
|
|
|
|
if (err)
|
2010-09-07 10:27:25 +00:00
|
|
|
return err;
|
2013-10-24 18:10:35 +00:00
|
|
|
|
|
|
|
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
|
|
|
|
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
|
|
|
|
|
|
|
/* make sure downmix information in infoframe is zero */
|
|
|
|
snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
|
|
|
|
|
|
|
|
/* enable channel-wise remap mode if supported */
|
|
|
|
if (has_amd_full_remap_support(codec))
|
|
|
|
snd_hda_codec_write(codec, per_pin->pin_nid, 0,
|
|
|
|
ATI_VERB_SET_MULTICHANNEL_MODE,
|
|
|
|
ATI_MULTICHANNEL_MODE_SINGLE);
|
2010-09-07 10:27:25 +00:00
|
|
|
}
|
2019-11-22 21:43:53 +00:00
|
|
|
codec->auto_runtime_pm = 1;
|
2013-10-24 18:10:35 +00:00
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
/* map from pin NID to port; port is 0-based */
|
|
|
|
/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
|
|
|
|
static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
|
|
|
|
{
|
|
|
|
return pin_nid / 2 - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reverse-map from port to pin NID: see above */
|
|
|
|
static int atihdmi_port2pin(struct hda_codec *codec, int port)
|
|
|
|
{
|
|
|
|
return port * 2 + 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
|
|
|
|
.pin2port = atihdmi_pin2port,
|
|
|
|
.pin_eld_notify = generic_acomp_pin_eld_notify,
|
|
|
|
.master_bind = generic_acomp_master_bind,
|
|
|
|
.master_unbind = generic_acomp_master_unbind,
|
|
|
|
};
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
static int patch_atihdmi(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct hdmi_spec *spec;
|
2013-10-24 18:10:35 +00:00
|
|
|
struct hdmi_spec_per_cvt *per_cvt;
|
|
|
|
int err, cvt_idx;
|
|
|
|
|
|
|
|
err = patch_generic_hdmi(codec);
|
|
|
|
|
|
|
|
if (err)
|
2012-06-15 12:34:42 +00:00
|
|
|
return err;
|
2013-10-24 18:10:35 +00:00
|
|
|
|
|
|
|
codec->patch_ops.init = atihdmi_init;
|
|
|
|
|
2012-06-15 12:34:42 +00:00
|
|
|
spec = codec->spec;
|
2013-10-24 18:10:35 +00:00
|
|
|
|
2013-10-24 18:10:36 +00:00
|
|
|
spec->ops.pin_get_eld = atihdmi_pin_get_eld;
|
2013-10-24 18:10:35 +00:00
|
|
|
spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
|
2013-10-24 18:10:37 +00:00
|
|
|
spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
|
2013-10-24 18:10:38 +00:00
|
|
|
spec->ops.setup_stream = atihdmi_setup_stream;
|
2013-10-24 18:10:35 +00:00
|
|
|
|
2016-05-11 12:56:12 +00:00
|
|
|
spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
|
|
|
|
spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
|
|
|
|
|
2013-10-24 18:10:35 +00:00
|
|
|
if (!has_amd_full_remap_support(codec)) {
|
|
|
|
/* override to ATI/AMD-specific versions with pairwise mapping */
|
2016-03-04 14:29:46 +00:00
|
|
|
spec->chmap.ops.chmap_cea_alloc_validate_get_type =
|
2013-10-24 18:10:35 +00:00
|
|
|
atihdmi_paired_chmap_cea_alloc_validate_get_type;
|
2016-03-04 14:29:46 +00:00
|
|
|
spec->chmap.ops.cea_alloc_to_tlv_chmap =
|
|
|
|
atihdmi_paired_cea_alloc_to_tlv_chmap;
|
|
|
|
spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
|
2013-10-24 18:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ATI/AMD converters do not advertise all of their capabilities */
|
|
|
|
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
|
|
|
|
per_cvt = get_cvt(spec, cvt_idx);
|
|
|
|
per_cvt->channels_max = max(per_cvt->channels_max, 8u);
|
|
|
|
per_cvt->rates |= SUPPORTED_RATES;
|
|
|
|
per_cvt->formats |= SUPPORTED_FORMATS;
|
|
|
|
per_cvt->maxbps = max(per_cvt->maxbps, 24u);
|
|
|
|
}
|
|
|
|
|
2016-03-04 14:29:46 +00:00
|
|
|
spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
|
2013-10-24 18:10:35 +00:00
|
|
|
|
2018-06-21 11:33:53 +00:00
|
|
|
/* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
|
|
|
|
* the link-down as is. Tell the core to allow it.
|
|
|
|
*/
|
|
|
|
codec->link_down_at_suspend = 1;
|
|
|
|
|
ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI
AMD/ATI and Nvidia HDMI codec drivers didn't have the audio component
binding like i915, but it worked only with the traditional HD-audio
unsolicited event for the HDMI hotplug detection and the ELD read-up
thereafter. This has been a problem in many ways: first of all, it
goes through the hardware event transition (from GPU register write,
HD-audio controller trigger, and finally to HD-audio unsolicited event
handling), which is often unreliable and may miss some opportunities.
Second, each unsol event handling and ELD read-up need the explicit
power up / down when the codec is in the runtime suspend. Last but
not least, which is the most important, the hotplug wakeup may be
missed when the HD-audio controller is in runtime suspend. Especially
the last point is a big problem due to the recent change relevant with
vga_switcheroo that forcibly enables the runtime PM for AMD HDMI
controllers.
These issues are solved by introducing the audio component; the
hotplug notification is done by a direct function callback, which is
more accurate and reliable, and it can be processed without the actual
hardware access, i.e. no runtime PM trigger is needed, and the
HD-audio gets the event even if it's in runtime suspend. The same for
ELD query, as it's read directly from the cached ELD bytes stored in
the DRM driver, hence the whole hardware access can be skipped.
So here it is: this patch implements the audio component binding with
AMD/ATI and Nouveau DRM drivers. The biggest difference from i915
implementation is that this binding is fully optional and it can be
enabled asynchronously on the fly. That is, the driver will switch
from the HD-audio unsolicited event to the notify callback once when
the DRM component gets bound. Similarly, when DRM driver gets
unloaded, the HDMI event handling returns to the legacy mode, too.
Also, another difference from i915 is that the new code registers the
component in the codec driver, while i915 HDMI codec assumes the
component binding was already done in the HD-audio controller driver.
Hence the new code does need to de-register the component binding at
the codec exit, too.
Some other details:
- The match component ops assumes that both VGA and HD-audio
controller PCI entries belong to the same PCI bus, and only accepts
such an entry.
- The pin2port audio_ops is implemented with assumption of the fixed
widget layout. For AMD, it's starting from 3, with step 2 (3, 5, 7,
...), while for Nvidia, it's starting from 4, with step 1 (4, 5, 6,
...)
As of this patch, the corresponding component isn't implemented in DRM
side, so this change alone won't give any benefit. By the following
changes in DRM sides, the mission will be completed.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-07-11 16:05:52 +00:00
|
|
|
generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
|
|
|
|
|
2010-09-07 10:27:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-08 11:18:42 +00:00
|
|
|
/* VIA HDMI Implementation */
|
|
|
|
#define VIAHDMI_CVT_NID 0x02 /* audio converter1 */
|
|
|
|
#define VIAHDMI_PIN_NID 0x03 /* HDMI output pin1 */
|
|
|
|
|
|
|
|
static int patch_via_hdmi(struct hda_codec *codec)
|
|
|
|
{
|
2012-06-15 12:40:21 +00:00
|
|
|
return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
|
2012-06-08 11:18:42 +00:00
|
|
|
}
|
2010-09-07 10:27:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* patch entries
|
|
|
|
*/
|
2015-10-01 14:20:04 +00:00
|
|
|
static const struct hda_device_id snd_hda_id_hdmi[] = {
|
|
|
|
HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI", patch_atihdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI", patch_atihdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI", patch_atihdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI", patch_generic_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI", patch_generic_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI", patch_generic_hdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI", patch_nvhdmi_2ch),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x),
|
2019-11-19 08:47:10 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy),
|
2011-03-03 11:46:13 +00:00
|
|
|
/* 17 is known to be absent */
|
2019-11-19 08:47:10 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy),
|
|
|
|
HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi),
|
2018-12-03 15:53:17 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi),
|
2017-02-09 01:20:54 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi),
|
2016-03-13 20:58:57 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi),
|
2016-01-28 22:07:38 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi),
|
2020-06-11 18:08:45 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
|
2017-07-14 00:27:39 +00:00
|
|
|
HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi),
|
2016-03-21 13:50:24 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi),
|
2019-03-13 16:09:23 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi),
|
2016-03-21 13:50:24 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_i915_cpt_hdmi),
|
2016-03-21 12:56:19 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_i915_cpt_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
|
2016-03-21 11:18:33 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
|
2017-12-07 12:36:20 +00:00
|
|
|
HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi),
|
2017-04-13 07:35:35 +00:00
|
|
|
HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
|
2019-03-13 16:09:23 +00:00
|
|
|
HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi),
|
2019-11-05 16:10:53 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
|
2020-09-21 14:17:38 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi),
|
2020-11-16 14:19:55 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi),
|
2021-01-13 15:56:29 +00:00
|
|
|
HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
|
2020-09-02 15:42:07 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
|
2020-01-31 20:40:03 +00:00
|
|
|
HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
|
2020-04-09 18:58:17 +00:00
|
|
|
HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
|
2016-03-21 11:18:33 +00:00
|
|
|
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
|
|
|
|
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi),
|
2015-02-17 14:25:37 +00:00
|
|
|
/* special ID for generic HDMI */
|
2015-10-01 14:20:04 +00:00
|
|
|
HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
|
2010-09-07 10:27:25 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
2015-10-01 14:20:04 +00:00
|
|
|
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
|
2010-09-07 10:27:25 +00:00
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DESCRIPTION("HDMI HD-audio codec");
|
|
|
|
MODULE_ALIAS("snd-hda-codec-intelhdmi");
|
|
|
|
MODULE_ALIAS("snd-hda-codec-nvhdmi");
|
|
|
|
MODULE_ALIAS("snd-hda-codec-atihdmi");
|
|
|
|
|
2015-02-17 14:25:37 +00:00
|
|
|
static struct hda_codec_driver hdmi_driver = {
|
2015-10-01 14:20:04 +00:00
|
|
|
.id = snd_hda_id_hdmi,
|
2010-09-07 10:27:25 +00:00
|
|
|
};
|
|
|
|
|
2015-02-17 14:25:37 +00:00
|
|
|
module_hda_codec_driver(hdmi_driver);
|