Commit 4846a67e authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Introduce pin_cvt_fixup() ops to hdmi parser

For reducing the splat of is_haswell_plus() or such macros, this patch
introduces pin_cvt_fixup() ops to hdmi_spec.  For HSW+ and VLV+
codecs, set this ops so that the driver can call the Intel-specific
workarounds appropriately.

A gratis bonus that we can remove the mux_id argument from
hdmi_choose_cvt(), too, since the fixup function always refers the
mux_idx from the given per_pin object.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2c1c9b86
...@@ -114,6 +114,9 @@ struct hdmi_ops { ...@@ -114,6 +114,9 @@ struct hdmi_ops {
int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
hda_nid_t pin_nid, u32 stream_tag, int format); hda_nid_t pin_nid, u32 stream_tag, int format);
void (*pin_cvt_fixup)(struct hda_codec *codec,
struct hdmi_spec_per_pin *per_pin,
hda_nid_t cvt_nid);
}; };
struct hdmi_pcm { struct hdmi_pcm {
...@@ -881,7 +884,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, ...@@ -881,7 +884,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
* of the pin. * of the pin.
*/ */
static int hdmi_choose_cvt(struct hda_codec *codec, static int hdmi_choose_cvt(struct hda_codec *codec,
int pin_idx, int *cvt_id, int *mux_id) int pin_idx, int *cvt_id)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin; struct hdmi_spec_per_pin *per_pin;
...@@ -922,8 +925,6 @@ static int hdmi_choose_cvt(struct hda_codec *codec, ...@@ -922,8 +925,6 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
if (cvt_id) if (cvt_id)
*cvt_id = cvt_idx; *cvt_id = cvt_idx;
if (mux_id)
*mux_id = mux_idx;
return 0; return 0;
} }
...@@ -1016,9 +1017,6 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec, ...@@ -1016,9 +1017,6 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
int mux_idx; int mux_idx;
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
if (!is_haswell_plus(codec) && !is_valleyview_plus(codec))
return;
/* On Intel platform, the mapping of converter nid to /* On Intel platform, the mapping of converter nid to
* mux index of the pins are always the same. * mux index of the pins are always the same.
* The pin nid may be 0, this means all pins will not * The pin nid may be 0, this means all pins will not
...@@ -1029,6 +1027,17 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec, ...@@ -1029,6 +1027,17 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
intel_not_share_assigned_cvt(codec, pin_nid, mux_idx); intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
} }
/* 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);
}
/* called in hdmi_pcm_open when no pin is assigned to the PCM /* called in hdmi_pcm_open when no pin is assigned to the PCM
* in dyn_pcm_assign mode. * in dyn_pcm_assign mode.
*/ */
...@@ -1046,7 +1055,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, ...@@ -1046,7 +1055,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
if (pcm_idx < 0) if (pcm_idx < 0)
return -EINVAL; return -EINVAL;
err = hdmi_choose_cvt(codec, -1, &cvt_idx, NULL); err = hdmi_choose_cvt(codec, -1, &cvt_idx);
if (err) if (err)
return err; return err;
...@@ -1054,7 +1063,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo, ...@@ -1054,7 +1063,7 @@ static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
per_cvt->assigned = 1; per_cvt->assigned = 1;
hinfo->nid = per_cvt->cvt_nid; hinfo->nid = per_cvt->cvt_nid;
intel_not_share_assigned_cvt_nid(codec, 0, per_cvt->cvt_nid); pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
set_bit(pcm_idx, &spec->pcm_in_use); set_bit(pcm_idx, &spec->pcm_in_use);
/* todo: setup spdif ctls assign */ /* todo: setup spdif ctls assign */
...@@ -1086,7 +1095,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -1086,7 +1095,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
int pin_idx, cvt_idx, pcm_idx, mux_idx = 0; int pin_idx, cvt_idx, pcm_idx;
struct hdmi_spec_per_pin *per_pin; struct hdmi_spec_per_pin *per_pin;
struct hdmi_eld *eld; struct hdmi_eld *eld;
struct hdmi_spec_per_cvt *per_cvt = NULL; struct hdmi_spec_per_cvt *per_cvt = NULL;
...@@ -1115,7 +1124,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -1115,7 +1124,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
} }
} }
err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx); err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx);
if (err < 0) { if (err < 0) {
mutex_unlock(&spec->pcm_lock); mutex_unlock(&spec->pcm_lock);
return err; return err;
...@@ -1132,11 +1141,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -1132,11 +1141,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,
mux_idx); per_pin->mux_idx);
/* configure unused pins to choose other converters */ /* configure unused pins to choose other converters */
if (is_haswell_plus(codec) || is_valleyview_plus(codec)) pin_cvt_fixup(codec, per_pin, 0);
intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx);
snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid); snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
...@@ -1369,12 +1377,7 @@ static void update_eld(struct hda_codec *codec, ...@@ -1369,12 +1377,7 @@ static void update_eld(struct hda_codec *codec,
* and this can make HW reset converter selection on a pin. * and this can make HW reset converter selection on a pin.
*/ */
if (eld->eld_valid && !old_eld_valid && per_pin->setup) { if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { pin_cvt_fixup(codec, per_pin, 0);
intel_verify_pin_cvt_connect(codec, per_pin);
intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
per_pin->mux_idx);
}
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
} }
...@@ -1709,7 +1712,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -1709,7 +1712,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
* skip pin setup and return 0 to make audio playback * skip pin setup and return 0 to make audio playback
* be ongoing * be ongoing
*/ */
intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid); pin_cvt_fixup(codec, NULL, cvt_nid);
snd_hda_codec_setup_stream(codec, cvt_nid, snd_hda_codec_setup_stream(codec, cvt_nid,
stream_tag, 0, format); stream_tag, 0, format);
mutex_unlock(&spec->pcm_lock); mutex_unlock(&spec->pcm_lock);
...@@ -1722,18 +1725,16 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -1722,18 +1725,16 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
} }
per_pin = get_pin(spec, pin_idx); per_pin = get_pin(spec, pin_idx);
pin_nid = per_pin->pin_nid; pin_nid = per_pin->pin_nid;
if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
/* Verify pin:cvt selections to avoid silent audio after S3. /* Verify pin:cvt selections to avoid silent audio after S3.
* After S3, the audio driver restores pin:cvt selections * After S3, the audio driver restores pin:cvt selections
* but this can happen before gfx is ready and such selection * but this can happen before gfx is ready and such selection
* is overlooked by HW. Thus multiple pins can share a same * is overlooked by HW. Thus multiple pins can share a same
* default convertor and mute control will affect each other, * default convertor and mute control will affect each other,
* which can cause a resumed audio playback become silent * which can cause a resumed audio playback become silent
* after S3. * after S3.
*/ */
intel_verify_pin_cvt_connect(codec, per_pin); pin_cvt_fixup(codec, per_pin, 0);
intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx);
}
/* Call sync_audio_rate to set the N/CTS/M manually if necessary */ /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
/* Todo: add DP1.2 MST audio support later */ /* Todo: add DP1.2 MST audio support later */
...@@ -2312,6 +2313,20 @@ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, ...@@ -2312,6 +2313,20 @@ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
} }
/* 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) {
intel_verify_pin_cvt_connect(codec, per_pin);
intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
per_pin->mux_idx);
} else {
intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
}
}
/* Intel Haswell and onwards; audio component with eld notifier */ /* Intel Haswell and onwards; audio component with eld notifier */
static int patch_i915_hsw_hdmi(struct hda_codec *codec) static int patch_i915_hsw_hdmi(struct hda_codec *codec)
{ {
...@@ -2344,6 +2359,7 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec) ...@@ -2344,6 +2359,7 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
codec->auto_runtime_pm = 1; codec->auto_runtime_pm = 1;
spec->ops.setup_stream = i915_hsw_setup_stream; spec->ops.setup_stream = i915_hsw_setup_stream;
spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
err = hdmi_parse_codec(codec); err = hdmi_parse_codec(codec);
if (err < 0) { if (err < 0) {
...@@ -2381,6 +2397,8 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) ...@@ -2381,6 +2397,8 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
codec->depop_delay = 0; codec->depop_delay = 0;
codec->auto_runtime_pm = 1; codec->auto_runtime_pm = 1;
spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
err = hdmi_parse_codec(codec); err = hdmi_parse_codec(codec);
if (err < 0) { if (err < 0) {
generic_spec_free(codec); generic_spec_free(codec);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment