Skip to content

Commit 15175a4

Browse files
kv2019itiwai
authored andcommitted
ALSA: hda/hdmi: add keep-alive support for ADL-P and DG2
Implement HDA keep alive (KAE) support for Intel display codecs. When no audio stream is active, the display codec will provide a continuous clock and a valid but silent audio stream to any connected HDMI/DP receiver. Without this, upon starting a new playback stream, initial samples may be lost as many receivers require time to initialize for new clock. This is a new feature in Intel AlderLake-P display codec implementation and replaces the Intel i915 silent-stream extension that has been used on older hardware. Main benefit of the new method is that codec no longer needs to be kept in D0 power state. This patch depends on commit 112a87c ("drm/i915/display: program audio CDCLK-TS for keepalives"). [ a minor coding-style fix by tiwai ] Signed-off-by: Kai Vehmanen <[email protected]> Reviewed-by: Pierre-Louis Bossart <[email protected]> Reviewed-by: Jyri Sarha <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent a9f73b0 commit 15175a4

File tree

2 files changed

+126
-49
lines changed

2 files changed

+126
-49
lines changed

sound/pci/hda/Kconfig

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -285,15 +285,16 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
285285
bool "Enable Silent Stream always for HDMI"
286286
depends on SND_HDA_INTEL
287287
help
288-
Intel hardware has a feature called 'silent stream', that
289-
keeps external HDMI receiver's analog circuitry powered on
290-
avoiding 2-3 sec silence during playback start. This mechanism
291-
relies on setting channel_id as 0xf, sending info packet and
292-
preventing codec D3 entry (increasing platform static power
293-
consumption when HDMI receiver is plugged-in). 2-3 sec silence
294-
at the playback start is expected whenever there is format change.
295-
(default is 2 channel format).
296-
Say Y to enable Silent Stream feature.
288+
Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
289+
for HDMI on hardware that supports the feature.
290+
291+
When enabled, the HDMI/DisplayPort codec will continue to provide
292+
a continuous clock and a valid but silent data stream to
293+
any connected external receiver. This allows to avoid gaps
294+
at start of playback. Many receivers require multiple seconds
295+
to start playing audio after the clock has been stopped.
296+
This feature can impact power consumption as resources
297+
are kept reserved both at transmitter and receiver.
297298

298299
endif
299300

sound/pci/hda/patch_hdmi.c

Lines changed: 116 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ struct hdmi_pcm {
120120
struct snd_kcontrol *eld_ctl;
121121
};
122122

123+
enum {
124+
SILENT_STREAM_OFF = 0,
125+
SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */
126+
SILENT_STREAM_I915, /* Intel i915 extension */
127+
};
128+
123129
struct hdmi_spec {
124130
struct hda_codec *codec;
125131
int num_cvts;
@@ -179,7 +185,7 @@ struct hdmi_spec {
179185
hda_nid_t vendor_nid;
180186
const int *port_map;
181187
int port_num;
182-
bool send_silent_stream; /* Flag to enable silent stream feature */
188+
int silent_stream_type;
183189
};
184190

185191
#ifdef CONFIG_SND_HDA_COMPONENT
@@ -1665,18 +1671,71 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
16651671
#define I915_SILENT_FORMAT_BITS 16
16661672
#define I915_SILENT_FMT_MASK 0xf
16671673

1674+
static void silent_stream_enable_i915(struct hda_codec *codec,
1675+
struct hdmi_spec_per_pin *per_pin)
1676+
{
1677+
unsigned int format;
1678+
1679+
snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
1680+
per_pin->dev_id, I915_SILENT_RATE);
1681+
1682+
/* trigger silent stream generation in hw */
1683+
format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS,
1684+
I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0);
1685+
snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
1686+
I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
1687+
usleep_range(100, 200);
1688+
snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
1689+
1690+
per_pin->channels = I915_SILENT_CHANNELS;
1691+
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
1692+
}
1693+
1694+
static void silent_stream_set_kae(struct hda_codec *codec,
1695+
struct hdmi_spec_per_pin *per_pin,
1696+
bool enable)
1697+
{
1698+
unsigned int param;
1699+
1700+
codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
1701+
1702+
param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
1703+
param = (param >> 16) & 0xff;
1704+
1705+
if (enable)
1706+
param |= AC_DIG3_KAE;
1707+
else
1708+
param &= ~AC_DIG3_KAE;
1709+
1710+
snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
1711+
}
1712+
16681713
static void silent_stream_enable(struct hda_codec *codec,
16691714
struct hdmi_spec_per_pin *per_pin)
16701715
{
16711716
struct hdmi_spec *spec = codec->spec;
16721717
struct hdmi_spec_per_cvt *per_cvt;
16731718
int cvt_idx, pin_idx, err;
1674-
unsigned int format;
1719+
int keep_power = 0;
1720+
1721+
/*
1722+
* Power-up will call hdmi_present_sense, so the PM calls
1723+
* have to be done without mutex held.
1724+
*/
1725+
1726+
err = snd_hda_power_up_pm(codec);
1727+
if (err < 0 && err != -EACCES) {
1728+
codec_err(codec,
1729+
"Failed to power up codec for silent stream enable ret=[%d]\n", err);
1730+
snd_hda_power_down_pm(codec);
1731+
return;
1732+
}
16751733

16761734
mutex_lock(&per_pin->lock);
16771735

16781736
if (per_pin->setup) {
16791737
codec_dbg(codec, "hdmi: PCM already open, no silent stream\n");
1738+
err = -EBUSY;
16801739
goto unlock_out;
16811740
}
16821741

@@ -1703,30 +1762,40 @@ static void silent_stream_enable(struct hda_codec *codec,
17031762
/* configure unused pins to choose other converters */
17041763
pin_cvt_fixup(codec, per_pin, 0);
17051764

1706-
snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
1707-
per_pin->dev_id, I915_SILENT_RATE);
1708-
1709-
/* trigger silent stream generation in hw */
1710-
format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS,
1711-
I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0);
1712-
snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
1713-
I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
1714-
usleep_range(100, 200);
1715-
snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
1716-
1717-
per_pin->channels = I915_SILENT_CHANNELS;
1718-
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
1765+
switch (spec->silent_stream_type) {
1766+
case SILENT_STREAM_KAE:
1767+
silent_stream_set_kae(codec, per_pin, true);
1768+
break;
1769+
case SILENT_STREAM_I915:
1770+
silent_stream_enable_i915(codec, per_pin);
1771+
keep_power = 1;
1772+
break;
1773+
default:
1774+
break;
1775+
}
17191776

17201777
unlock_out:
17211778
mutex_unlock(&per_pin->lock);
1779+
1780+
if (err || !keep_power)
1781+
snd_hda_power_down_pm(codec);
17221782
}
17231783

17241784
static void silent_stream_disable(struct hda_codec *codec,
17251785
struct hdmi_spec_per_pin *per_pin)
17261786
{
17271787
struct hdmi_spec *spec = codec->spec;
17281788
struct hdmi_spec_per_cvt *per_cvt;
1729-
int cvt_idx;
1789+
int cvt_idx, err;
1790+
1791+
err = snd_hda_power_up_pm(codec);
1792+
if (err < 0 && err != -EACCES) {
1793+
codec_err(codec,
1794+
"Failed to power up codec for silent stream disable ret=[%d]\n",
1795+
err);
1796+
snd_hda_power_down_pm(codec);
1797+
return;
1798+
}
17301799

17311800
mutex_lock(&per_pin->lock);
17321801
if (!per_pin->silent_stream)
@@ -1741,11 +1810,20 @@ static void silent_stream_disable(struct hda_codec *codec,
17411810
per_cvt->assigned = 0;
17421811
}
17431812

1813+
if (spec->silent_stream_type == SILENT_STREAM_I915) {
1814+
/* release ref taken in silent_stream_enable() */
1815+
snd_hda_power_down_pm(codec);
1816+
} else if (spec->silent_stream_type == SILENT_STREAM_KAE) {
1817+
silent_stream_set_kae(codec, per_pin, false);
1818+
}
1819+
17441820
per_pin->cvt_nid = 0;
17451821
per_pin->silent_stream = false;
17461822

17471823
unlock_out:
17481824
mutex_unlock(&per_pin->lock);
1825+
1826+
snd_hda_power_down_pm(codec);
17491827
}
17501828

17511829
/* update ELD and jack state via audio component */
@@ -1767,29 +1845,11 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
17671845
monitor_next = per_pin->sink_eld.monitor_present;
17681846
mutex_unlock(&per_pin->lock);
17691847

1770-
/*
1771-
* Power-up will call hdmi_present_sense, so the PM calls
1772-
* have to be done without mutex held.
1773-
*/
1774-
1775-
if (spec->send_silent_stream) {
1776-
int pm_ret;
1777-
1778-
if (!monitor_prev && monitor_next) {
1779-
pm_ret = snd_hda_power_up_pm(codec);
1780-
if (pm_ret < 0)
1781-
codec_err(codec,
1782-
"Monitor plugged-in, Failed to power up codec ret=[%d]\n",
1783-
pm_ret);
1848+
if (spec->silent_stream_type) {
1849+
if (!monitor_prev && monitor_next)
17841850
silent_stream_enable(codec, per_pin);
1785-
} else if (monitor_prev && !monitor_next) {
1851+
else if (monitor_prev && !monitor_next)
17861852
silent_stream_disable(codec, per_pin);
1787-
pm_ret = snd_hda_power_down_pm(codec);
1788-
if (pm_ret < 0)
1789-
codec_err(codec,
1790-
"Monitor plugged-out, Failed to power down codec ret=[%d]\n",
1791-
pm_ret);
1792-
}
17931853
}
17941854
}
17951855

@@ -2982,7 +3042,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
29823042
* module param or Kconfig option
29833043
*/
29843044
if (send_silent_stream)
2985-
spec->send_silent_stream = true;
3045+
spec->silent_stream_type = SILENT_STREAM_I915;
29863046

29873047
return parse_intel_hdmi(codec);
29883048
}
@@ -3035,6 +3095,22 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec)
30353095
return ret;
30363096
}
30373097

3098+
static int patch_i915_adlp_hdmi(struct hda_codec *codec)
3099+
{
3100+
struct hdmi_spec *spec;
3101+
int res;
3102+
3103+
res = patch_i915_tgl_hdmi(codec);
3104+
if (!res) {
3105+
spec = codec->spec;
3106+
3107+
if (spec->silent_stream_type)
3108+
spec->silent_stream_type = SILENT_STREAM_KAE;
3109+
}
3110+
3111+
return res;
3112+
}
3113+
30383114
/* Intel Baytrail and Braswell; with eld notifier */
30393115
static int patch_i915_byt_hdmi(struct hda_codec *codec)
30403116
{
@@ -4391,10 +4467,10 @@ HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi),
43914467
HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi),
43924468
HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
43934469
HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi),
4394-
HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi),
4470+
HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_adlp_hdmi),
43954471
HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
43964472
HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
4397-
HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
4473+
HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
43984474
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
43994475
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
44004476
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),

0 commit comments

Comments
 (0)