[alsa-devel] [PATCH 3/3] ALSA: hda - delay resuming Haswell HDMI codec in system resume
Takashi Iwai
tiwai at suse.de
Mon Apr 8 16:27:07 CEST 2013
At Mon, 8 Apr 2013 13:54:55 -0400,
mengdong.lin at intel.com wrote:
>
> From: Mengdong Lin <mengdong.lin at intel.com>
>
> In system resume, Haswell codec cannot be programmed to D0 before Gfx driver
> initializes the display pipeline and audio, which will trigger an unsol event
> on the pin with HDMI/DP cable connected. Otherwise, the connected pin will
> stay in D3 with right channel muted and thus no sound can be heard.
>
> In this patch, Haswell codec will claim it needs "delaying resume" by setting
> flag "support_delay_resume", so system resume will skip it and mark it as
> "delay_resumed". On later codec access, Haswell codec will be resumed and
> hda_call_codec_resume() will call its set_power_states ops intel_haswell_set_
> power_state(). For a delayed resume, this ops will enable and wait for the
> unsol event, and then resume the codec. A 300ms timeout is set in case unsol
> event is lost.
>
> Signed-off-by: Mengdong Lin <mengdong.lin at intel.com>
>
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index ede8215..f39e374 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -89,6 +89,14 @@ struct hdmi_spec {
> */
> struct hda_multi_out multiout;
> struct hda_pcm_stream pcm_playback;
> +
> +#ifdef CONFIG_PM
> + /*
> + * Non-generic Intel Haswell specific
> + */
> + unsigned int ready_to_resume:1;
> + wait_queue_head_t resume_wq;
> +#endif
> };
>
>
> @@ -975,6 +983,13 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
> if (pin_idx < 0)
> return;
>
> +#ifdef CONFIG_PM
> + if (codec->resume_delayed) {
> + spec->ready_to_resume = 1;
> + wake_up(&spec->resume_wq);
> + }
> +#endif
> +
> hdmi_present_sense(get_pin(spec, pin_idx), 1);
> snd_hda_jack_report_sync(codec);
> }
> @@ -1725,6 +1740,11 @@ static int generic_hdmi_init(struct hda_codec *codec)
> hdmi_init_pin(codec, pin_nid);
> snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
> }
> +
> +#ifdef CONFIG_PM
> + spec->ready_to_resume = 0;
> +#endif
> +
> return 0;
> }
>
> @@ -1855,6 +1875,61 @@ static const struct hda_fixup hdmi_fixups[] = {
> };
>
>
> +#ifdef CONFIG_PM
> +static void intel_haswell_wait_ready_to_resume(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;
> + hda_nid_t pin_nid;
> + struct hda_jack_tbl *jack;
> +
> + per_pin = get_pin(spec, pin_idx);
> + pin_nid = per_pin->pin_nid;
> + jack = snd_hda_jack_tbl_get(codec, pin_nid);
> + if (jack)
> + snd_hda_codec_write(codec, pin_nid, 0,
> + AC_VERB_SET_UNSOLICITED_ENABLE,
> + AC_USRSP_EN | jack->tag);
> + }
> +
> + wait_event_timeout(spec->resume_wq,
> + spec->ready_to_resume, msecs_to_jiffies(300));
> + if (!spec->ready_to_resume)
> + snd_printd(KERN_WARNING "HDMI: Haswell not ready to resume\n");
> +}
IMO, this should be shown no matter whether with or w/o debug option,
i.e. use snd_printk().
> +}
> +
> +static void intel_haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
> + unsigned int power_state)
> +{
> + if (codec->resume_delayed && power_state == AC_PWRST_D0) {
A superfluous space after '=='
> + intel_haswell_wait_ready_to_resume(codec);
> + codec->resume_delayed = 0;
> + }
> +
> + 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);
> +}
> +
> +static inline void intel_haswell_allow_delay_resume(struct hda_codec *codec)
You don't have to put inline for such a case.
Rely more on the compiler. It shall do that anyway.
> +{
> + struct hdmi_spec *spec = codec->spec;
> +
> + init_waitqueue_head(&spec->resume_wq);
> + codec->support_delay_resume = 1;
> +
> + codec->patch_ops.set_power_state =
> + intel_haswell_set_power_state;
No need for a new line...
> +}
> +#else
> +define intel_haswell_allow_delay_resume NULL
This should be an empty function instead
#define intel_haswell_allow_delay_resume() do { } while (0)
Takashi
> +#endif
> +
> static int patch_generic_hdmi(struct hda_codec *codec)
> {
> struct hdmi_spec *spec;
> @@ -1878,6 +1953,10 @@ static int patch_generic_hdmi(struct hda_codec *codec)
> return -EINVAL;
> }
> codec->patch_ops = generic_hdmi_patch_ops;
> +
> + if (codec->vendor_id == 0x80862807)
> + intel_haswell_allow_delay_resume(codec);
> +
> generic_hdmi_init_per_pins(codec);
>
> init_channel_allocations();
> --
> 1.7.10.4
>
More information about the Alsa-devel
mailing list