Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/sound/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ struct hda_codec {
unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */
unsigned int ctl_dev_id:1; /* old control element id build behaviour */
unsigned int eld_jack_detect:1; /* Machine jack-detection by ELD */
unsigned int constrain_pcms:1; /* narrow the PCMs with hw_constraints
* because runtime->hw is not honoured
*/

unsigned long power_on_acct;
unsigned long power_off_acct;
Expand Down
35 changes: 35 additions & 0 deletions sound/hda/codecs/hdmi/hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,32 @@ static void pin_cvt_fixup(struct hda_codec *codec,
spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
}

/*
* Repeat the narrowing of the PCM as hw_constraints for a codec which asked for
* it. The runtime->hw of such a codec is overwritten after this open returns,
* losing everything set there, while nothing touches the constraints. A DSP
* driver exposing the PCM as an ASoC dynamic PCM backend is the case that needs
* it, the frontend being what userspace negotiates against there.
*/
static void hdmi_pcm_add_constraints(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream,
struct hdmi_eld *eld)
{
snd_pcm_hw_constraint_mask64(substream->runtime,
SNDRV_PCM_HW_PARAM_FORMAT, hinfo->formats);
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_CHANNELS,
hinfo->channels_min, hinfo->channels_max);
/*
* The rates a converter supports are a mask, which no constraint can
* take, so they are left to the caps the PCM was created with. The ELD
* rates are a finer restriction than @hinfo can express anyway, being
* correlated with the channel count.
*/
if (eld)
snd_pcm_hw_constraint_eld(substream->runtime, eld->eld_buffer);
}

/* called in hdmi_pcm_open when no pin is assigned to the PCM */
static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
Expand Down Expand Up @@ -871,6 +897,9 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
runtime->hw.formats = hinfo->formats;
runtime->hw.rates = hinfo->rates;

if (codec->constrain_pcms)
hdmi_pcm_add_constraints(hinfo, substream, NULL);

snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
return 0;
Expand Down Expand Up @@ -957,6 +986,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
runtime->hw.formats = hinfo->formats;
runtime->hw.rates = hinfo->rates;

if (codec->constrain_pcms) {
if (static_hdmi_pcm || !eld->eld_valid)
eld = NULL;
hdmi_pcm_add_constraints(hinfo, substream, eld);
}

snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
return 0;
Expand Down
9 changes: 9 additions & 0 deletions sound/soc/sof/intel/hda-codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
hda_priv->dev_index = address;
dev_set_drvdata(&codec->core.dev, hda_priv);

/*
* Every codec here is exposed as a dynamic PCM backend, and the ASoC
* core overwrites the runtime->hw of those with what topology says,
* after the codec has set it up. Ask for hw_constraints instead, which
* survive, so that a restriction only the codec knows about reaches the
* frontend that userspace negotiates against.
*/
codec->constrain_pcms = 1;

if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) {
if (!hbus->core.audio_component) {
dev_dbg(sdev->dev,
Expand Down
Loading