Commit a686632f authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Split out Intel-specific codes from patch_generic_hdmi()

We have too many Intel-specific codes in patch_hdmi_generic() despite
its function name.  And this makes it difficult to adjust per chipset,
e.g. for allowing the audio notifier on an old chipset, one would need
to add an explicit if() check.

This patch attempts some code refactoring and cleanups in this regard;
the Intel-specific codes are moved out of patch_generic_hdmi() into
the new functions, patch_i915_hsw_hdmi() and patch_i915_byt_hdmi(),
depending on the chipset.  The other old Intel chipsets keep using
patch_generic_hdmi() without Intel hacks.  The existing
patch_generic_hdmi() is also split to a few components so that they
can be called from the Intel codec parsers.

There are still many is_haswell*() and is_valleyview*() macro usages
in the code.  They will be cleaned up later.  For the time being, only
the entry are concerned.

Along with this change, the i915_bound flag and the on-demand i915
component binding have been removed as a cleanup, since there is no
user at this moment.  This will be added back later once when Cougar
Point and else start using the i915 eld notifier.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 5c5daf91
...@@ -154,7 +154,6 @@ struct hdmi_spec { ...@@ -154,7 +154,6 @@ struct hdmi_spec {
/* i915/powerwell (Haswell+/Valleyview+) specific */ /* i915/powerwell (Haswell+/Valleyview+) specific */
bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */ bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */
struct i915_audio_component_audio_ops i915_audio_ops; struct i915_audio_component_audio_ops i915_audio_ops;
bool i915_bound; /* was i915 bound in this driver? */
struct hdac_chmap chmap; struct hdac_chmap chmap;
}; };
...@@ -2074,6 +2073,18 @@ static void hdmi_array_free(struct hdmi_spec *spec) ...@@ -2074,6 +2073,18 @@ static void hdmi_array_free(struct hdmi_spec *spec)
snd_array_free(&spec->cvts); snd_array_free(&spec->cvts);
} }
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;
}
static void generic_hdmi_free(struct hda_codec *codec) static void generic_hdmi_free(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
...@@ -2098,10 +2109,7 @@ static void generic_hdmi_free(struct hda_codec *codec) ...@@ -2098,10 +2109,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
spec->pcm_rec[pcm_idx].jack = NULL; spec->pcm_rec[pcm_idx].jack = NULL;
} }
if (spec->i915_bound) generic_spec_free(codec);
snd_hdac_i915_exit(&codec->bus->core);
hdmi_array_free(spec);
kfree(spec);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -2139,6 +2147,54 @@ static const struct hdmi_ops generic_standard_hdmi_ops = { ...@@ -2139,6 +2147,54 @@ static const struct hdmi_ops generic_standard_hdmi_ops = {
.setup_stream = hdmi_setup_stream, .setup_stream = hdmi_setup_stream,
}; };
/* 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;
spec->ops = generic_standard_hdmi_ops;
mutex_init(&spec->pcm_lock);
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;
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;
}
/*
* Intel codec parsers and helpers
*/
static void intel_haswell_fixup_connect_list(struct hda_codec *codec, static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid) hda_nid_t nid)
{ {
...@@ -2234,92 +2290,96 @@ static void intel_pin_eld_notify(void *audio_ptr, int port) ...@@ -2234,92 +2290,96 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
check_presence_and_report(codec, pin_nid); check_presence_and_report(codec, pin_nid);
} }
static int patch_generic_hdmi(struct hda_codec *codec) /* register i915 component pin_eld_notify callback */
static void register_i915_notifier(struct hda_codec *codec)
{ {
struct hdmi_spec *spec; struct hdmi_spec *spec = codec->spec;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
spec->ops = generic_standard_hdmi_ops;
mutex_init(&spec->pcm_lock);
snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
spec->chmap.ops.get_chmap = hdmi_get_chmap; spec->use_acomp_notifier = true;
spec->chmap.ops.set_chmap = hdmi_set_chmap; spec->i915_audio_ops.audio_ptr = codec;
spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; /* 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->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
}
codec->spec = spec; /* Intel Haswell and onwards; audio component with eld notifier */
hdmi_array_init(spec, 4); static int patch_i915_hsw_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
int err;
#ifdef CONFIG_SND_HDA_I915 /* HSW+ requires i915 binding */
/* Try to bind with i915 for Intel HSW+ codecs (if not done yet) */ if (!codec->bus->core.audio_component) {
if ((codec->core.vendor_id >> 16) == 0x8086 && codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
is_haswell_plus(codec)) { return -ENODEV;
#if 0
/* on-demand binding leads to an unbalanced refcount when
* both i915 and hda drivers are probed concurrently;
* disabled temporarily for now
*/
if (!codec->bus->core.audio_component)
if (!snd_hdac_i915_init(&codec->bus->core))
spec->i915_bound = true;
#endif
/* use i915 audio component notifier for hotplug */
if (codec->bus->core.audio_component)
spec->use_acomp_notifier = true;
} }
#endif
if (is_haswell_plus(codec)) { err = alloc_generic_hdmi(codec);
intel_haswell_enable_all_pins(codec, true); if (err < 0)
intel_haswell_fixup_enable_dp12(codec); return err;
} spec = codec->spec;
/* For Valleyview/Cherryview, only the display codec is in the display intel_haswell_enable_all_pins(codec, true);
* power well and can use link_power ops to request/release the power. intel_haswell_fixup_enable_dp12(codec);
* For Haswell/Broadwell, the controller is also in the power well and
/* For Haswell/Broadwell, the controller is also in the power well and
* can cover the codec power request, and so need not set this flag. * can cover the codec power request, and so need not set this flag.
* For previous platforms, there is no such power well feature.
*/ */
if (is_valleyview_plus(codec) || is_skylake(codec) || if (!is_haswell(codec) && !is_broadwell(codec))
is_broxton(codec))
codec->core.link_power_control = 1; codec->core.link_power_control = 1;
if (hdmi_parse_codec(codec) < 0) { codec->patch_ops.set_power_state = haswell_set_power_state;
if (spec->i915_bound) codec->dp_mst = true;
snd_hdac_i915_exit(&codec->bus->core); codec->depop_delay = 0;
codec->spec = NULL; codec->auto_runtime_pm = 1;
kfree(spec);
return -EINVAL; err = hdmi_parse_codec(codec);
if (err < 0) {
generic_spec_free(codec);
return err;
} }
codec->patch_ops = generic_hdmi_patch_ops;
if (is_haswell_plus(codec)) { generic_hdmi_init_per_pins(codec);
codec->patch_ops.set_power_state = haswell_set_power_state; register_i915_notifier(codec);
codec->dp_mst = true; return 0;
}
/* Intel Baytrail and Braswell; without get_eld notifier */
static int patch_i915_byt_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
int err;
/* requires i915 binding */
if (!codec->bus->core.audio_component) {
codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
return -ENODEV;
} }
/* Enable runtime pm for HDMI audio codec of HSW/BDW/SKL/BYT/BSW */ err = alloc_generic_hdmi(codec);
if (is_haswell_plus(codec) || is_valleyview_plus(codec)) if (err < 0)
codec->auto_runtime_pm = 1; return err;
spec = codec->spec;
generic_hdmi_init_per_pins(codec); /* For Valleyview/Cherryview, only the display codec is in the display
* power well and can use link_power ops to request/release the power.
*/
codec->core.link_power_control = 1;
codec->depop_delay = 0;
codec->auto_runtime_pm = 1;
if (codec_has_acomp(codec)) { err = hdmi_parse_codec(codec);
codec->depop_delay = 0; if (err < 0) {
spec->i915_audio_ops.audio_ptr = codec; generic_spec_free(codec);
/* intel_audio_codec_enable() or intel_audio_codec_disable() return err;
* will call pin_eld_notify with using audio_ptr pointer
* We need make sure audio_ptr is really setup
*/
wmb();
spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
} }
WARN_ON(spec->dyn_pcm_assign && !codec_has_acomp(codec)); generic_hdmi_init_per_pins(codec);
return 0; return 0;
} }
...@@ -3498,14 +3558,14 @@ HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi), ...@@ -3498,14 +3558,14 @@ HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi),
/* special ID for generic HDMI */ /* special ID for generic HDMI */
HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
......
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