Skip to content

Commit ee0b089

Browse files
kv2019itiwai
authored andcommitted
ALSA: hda/hdmi: fix stream-id config keep-alive for rt suspend
When the new style KAE keep-alive implementation is used on compatible Intel hardware, the clocks are maintained when codec is in D3. The generic code in hda_cleanup_all_streams() can however interfere with generation of audio samples in this mode, by setting the stream and channel ids to zero. To get full benefit of the keepalive, set the new no_stream_clean_at_suspend quirk bit on affected Intel hardware. When this bit is set, stream cleanup is skipped in hda_call_codec_suspend(). Special handling is needed for the case when system goes to suspend. The stream id programming can be lost in this case. This will also cause codec->cvt_setups to be out of sync. Handle this by implementing custom suspend/resume handlers. If keep-alive is active for any converter, set the quirk flags no_stream_clean_at_suspend and forced_resume. Upon resume, keepalive programming is restored if needed. Fixes: 15175a4 ("ALSA: hda/hdmi: add keep-alive support for ADL-P and DG2") Signed-off-by: Kai Vehmanen <[email protected]> Reviewed-by: Pierre-Louis Bossart <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent b17e7ea commit ee0b089

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

include/sound/hda_codec.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ struct hda_codec {
258258
unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
259259
unsigned int relaxed_resume:1; /* don't resume forcibly for jack */
260260
unsigned int forced_resume:1; /* forced resume for jack */
261+
unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */
261262

262263
#ifdef CONFIG_PM
263264
unsigned long power_on_acct;

sound/pci/hda/hda_codec.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2886,7 +2886,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
28862886
snd_hdac_enter_pm(&codec->core);
28872887
if (codec->patch_ops.suspend)
28882888
codec->patch_ops.suspend(codec);
2889-
hda_cleanup_all_streams(codec);
2889+
if (!codec->no_stream_clean_at_suspend)
2890+
hda_cleanup_all_streams(codec);
28902891
state = hda_set_power_state(codec, AC_PWRST_D3);
28912892
update_power_acct(codec, true);
28922893
snd_hdac_leave_pm(&codec->core);

sound/pci/hda/patch_hdmi.c

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2926,6 +2926,88 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
29262926
}
29272927
}
29282928

2929+
#ifdef CONFIG_PM
2930+
static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
2931+
{
2932+
struct hdmi_spec *spec = codec->spec;
2933+
bool silent_streams = false;
2934+
int pin_idx, res;
2935+
2936+
res = generic_hdmi_suspend(codec);
2937+
2938+
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
2939+
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
2940+
2941+
if (per_pin->silent_stream) {
2942+
silent_streams = true;
2943+
break;
2944+
}
2945+
}
2946+
2947+
if (silent_streams && spec->silent_stream_type == SILENT_STREAM_KAE) {
2948+
/*
2949+
* stream-id should remain programmed when codec goes
2950+
* to runtime suspend
2951+
*/
2952+
codec->no_stream_clean_at_suspend = 1;
2953+
2954+
/*
2955+
* the system might go to S3, in which case keep-alive
2956+
* must be reprogrammed upon resume
2957+
*/
2958+
codec->forced_resume = 1;
2959+
2960+
codec_dbg(codec, "HDMI: KAE active at suspend\n");
2961+
} else {
2962+
codec->no_stream_clean_at_suspend = 0;
2963+
codec->forced_resume = 0;
2964+
}
2965+
2966+
return res;
2967+
}
2968+
2969+
static int i915_adlp_hdmi_resume(struct hda_codec *codec)
2970+
{
2971+
struct hdmi_spec *spec = codec->spec;
2972+
int pin_idx, res;
2973+
2974+
res = generic_hdmi_resume(codec);
2975+
2976+
/* KAE not programmed at suspend, nothing to do here */
2977+
if (!codec->no_stream_clean_at_suspend)
2978+
return res;
2979+
2980+
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
2981+
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
2982+
2983+
/*
2984+
* If system was in suspend with monitor connected,
2985+
* the codec setting may have been lost. Re-enable
2986+
* keep-alive.
2987+
*/
2988+
if (per_pin->silent_stream) {
2989+
unsigned int param;
2990+
2991+
param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
2992+
AC_VERB_GET_CONV, 0);
2993+
if (!param) {
2994+
codec_dbg(codec, "HDMI: KAE: restore stream id\n");
2995+
silent_stream_enable_i915(codec, per_pin);
2996+
}
2997+
2998+
param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
2999+
AC_VERB_GET_DIGI_CONVERT_1, 0);
3000+
if (!(param & (AC_DIG3_KAE << 16))) {
3001+
codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
3002+
silent_stream_set_kae(codec, per_pin, true);
3003+
}
3004+
}
3005+
}
3006+
3007+
return res;
3008+
}
3009+
#endif
3010+
29293011
/* precondition and allocation for Intel codecs */
29303012
static int alloc_intel_hdmi(struct hda_codec *codec)
29313013
{
@@ -3056,8 +3138,14 @@ static int patch_i915_adlp_hdmi(struct hda_codec *codec)
30563138
if (!res) {
30573139
spec = codec->spec;
30583140

3059-
if (spec->silent_stream_type)
3141+
if (spec->silent_stream_type) {
30603142
spec->silent_stream_type = SILENT_STREAM_KAE;
3143+
3144+
#ifdef CONFIG_PM
3145+
codec->patch_ops.resume = i915_adlp_hdmi_resume;
3146+
codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
3147+
#endif
3148+
}
30613149
}
30623150

30633151
return res;

0 commit comments

Comments
 (0)